Add custom nodes, Civitai loras (LFS), and vast.ai setup script
Some checks failed
Python Linting / Run Ruff (push) Has been cancelled
Python Linting / Run Pylint (push) Has been cancelled
Full Comfy CI Workflow Runs / test-stable (12.1, , linux, 3.10, [self-hosted Linux], stable) (push) Has been cancelled
Full Comfy CI Workflow Runs / test-stable (12.1, , linux, 3.11, [self-hosted Linux], stable) (push) Has been cancelled
Full Comfy CI Workflow Runs / test-stable (12.1, , linux, 3.12, [self-hosted Linux], stable) (push) Has been cancelled
Full Comfy CI Workflow Runs / test-unix-nightly (12.1, , linux, 3.11, [self-hosted Linux], nightly) (push) Has been cancelled
Execution Tests / test (macos-latest) (push) Has been cancelled
Execution Tests / test (ubuntu-latest) (push) Has been cancelled
Execution Tests / test (windows-latest) (push) Has been cancelled
Test server launches without errors / test (push) Has been cancelled
Unit Tests / test (macos-latest) (push) Has been cancelled
Unit Tests / test (ubuntu-latest) (push) Has been cancelled
Unit Tests / test (windows-2022) (push) Has been cancelled
Some checks failed
Python Linting / Run Ruff (push) Has been cancelled
Python Linting / Run Pylint (push) Has been cancelled
Full Comfy CI Workflow Runs / test-stable (12.1, , linux, 3.10, [self-hosted Linux], stable) (push) Has been cancelled
Full Comfy CI Workflow Runs / test-stable (12.1, , linux, 3.11, [self-hosted Linux], stable) (push) Has been cancelled
Full Comfy CI Workflow Runs / test-stable (12.1, , linux, 3.12, [self-hosted Linux], stable) (push) Has been cancelled
Full Comfy CI Workflow Runs / test-unix-nightly (12.1, , linux, 3.11, [self-hosted Linux], nightly) (push) Has been cancelled
Execution Tests / test (macos-latest) (push) Has been cancelled
Execution Tests / test (ubuntu-latest) (push) Has been cancelled
Execution Tests / test (windows-latest) (push) Has been cancelled
Test server launches without errors / test (push) Has been cancelled
Unit Tests / test (macos-latest) (push) Has been cancelled
Unit Tests / test (ubuntu-latest) (push) Has been cancelled
Unit Tests / test (windows-2022) (push) Has been cancelled
Includes 30 custom nodes committed directly, 7 Civitai-exclusive loras stored via Git LFS, and a setup script that installs all dependencies and downloads HuggingFace-hosted models on vast.ai. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
1
custom_nodes/ComfyMath/.gitignore
vendored
Normal file
1
custom_nodes/ComfyMath/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
**/__pycache__
|
||||
201
custom_nodes/ComfyMath/LICENSE
Normal file
201
custom_nodes/ComfyMath/LICENSE
Normal file
@@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
19
custom_nodes/ComfyMath/README.md
Normal file
19
custom_nodes/ComfyMath/README.md
Normal file
@@ -0,0 +1,19 @@
|
||||
# ComfyMath
|
||||
|
||||
Provides Math Nodes for [ComfyUI](https://github.com/comfyanonymous/ComfyUI)
|
||||
|
||||
## Features
|
||||
|
||||
Provides nodes for:
|
||||
* Boolean Logic
|
||||
* Integer Arithmetic
|
||||
* Floating Point Arithmetic and Functions
|
||||
* Vec2, Vec3, and Vec4 Arithmetic and Functions
|
||||
|
||||
## Installation
|
||||
|
||||
From the `custom_nodes` directory in your ComfyUI installation, run:
|
||||
|
||||
```sh
|
||||
git clone https://github.com/evanspearman/ComfyMath.git
|
||||
```
|
||||
29
custom_nodes/ComfyMath/__init__.py
Normal file
29
custom_nodes/ComfyMath/__init__.py
Normal file
@@ -0,0 +1,29 @@
|
||||
from .src.comfymath.convert import NODE_CLASS_MAPPINGS as convert_NCM
|
||||
from .src.comfymath.bool import NODE_CLASS_MAPPINGS as bool_NCM
|
||||
from .src.comfymath.int import NODE_CLASS_MAPPINGS as int_NCM
|
||||
from .src.comfymath.float import NODE_CLASS_MAPPINGS as float_NCM
|
||||
from .src.comfymath.number import NODE_CLASS_MAPPINGS as number_NCM
|
||||
from .src.comfymath.vec import NODE_CLASS_MAPPINGS as vec_NCM
|
||||
from .src.comfymath.control import NODE_CLASS_MAPPINGS as control_NCM
|
||||
from .src.comfymath.graphics import NODE_CLASS_MAPPINGS as graphics_NCM
|
||||
|
||||
|
||||
NODE_CLASS_MAPPINGS = {
|
||||
**convert_NCM,
|
||||
**bool_NCM,
|
||||
**int_NCM,
|
||||
**float_NCM,
|
||||
**number_NCM,
|
||||
**vec_NCM,
|
||||
**control_NCM,
|
||||
**graphics_NCM,
|
||||
}
|
||||
|
||||
|
||||
def remove_cm_prefix(node_mapping: str) -> str:
|
||||
if node_mapping.startswith("CM_"):
|
||||
return node_mapping[3:]
|
||||
return node_mapping
|
||||
|
||||
|
||||
NODE_DISPLAY_NAME_MAPPINGS = {key: remove_cm_prefix(key) for key in NODE_CLASS_MAPPINGS}
|
||||
19
custom_nodes/ComfyMath/pyproject.toml
Normal file
19
custom_nodes/ComfyMath/pyproject.toml
Normal file
@@ -0,0 +1,19 @@
|
||||
[tool.poetry]
|
||||
name = "comfymath"
|
||||
version = "0.1.0"
|
||||
description = "Math nodes for ComfyUI"
|
||||
authors = ["Evan Spearman <evan@spearman.mb.ca>"]
|
||||
license = { text = "Apache License 2.0" }
|
||||
readme = "README.md"
|
||||
|
||||
[tool.poetry.dependencies]
|
||||
python = "^3.10"
|
||||
numpy = "^1.25.1"
|
||||
|
||||
[tool.poetry.group.dev.dependencies]
|
||||
mypy = "^1.4.1"
|
||||
black = "^23.7.0"
|
||||
|
||||
[build-system]
|
||||
requires = ["poetry-core"]
|
||||
build-backend = "poetry.core.masonry.api"
|
||||
1
custom_nodes/ComfyMath/requirements.txt
Normal file
1
custom_nodes/ComfyMath/requirements.txt
Normal file
@@ -0,0 +1 @@
|
||||
numpy
|
||||
0
custom_nodes/ComfyMath/src/comfymath/__init__.py
Normal file
0
custom_nodes/ComfyMath/src/comfymath/__init__.py
Normal file
59
custom_nodes/ComfyMath/src/comfymath/bool.py
Normal file
59
custom_nodes/ComfyMath/src/comfymath/bool.py
Normal file
@@ -0,0 +1,59 @@
|
||||
from typing import Any, Callable, Mapping
|
||||
|
||||
DEFAULT_BOOL = ("BOOLEAN", {"default": False})
|
||||
|
||||
|
||||
BOOL_UNARY_OPERATIONS: Mapping[str, Callable[[bool], bool]] = {
|
||||
"Not": lambda a: not a,
|
||||
}
|
||||
|
||||
BOOL_BINARY_OPERATIONS: Mapping[str, Callable[[bool, bool], bool]] = {
|
||||
"Nor": lambda a, b: not (a or b),
|
||||
"Xor": lambda a, b: a ^ b,
|
||||
"Nand": lambda a, b: not (a and b),
|
||||
"And": lambda a, b: a and b,
|
||||
"Xnor": lambda a, b: not (a ^ b),
|
||||
"Or": lambda a, b: a or b,
|
||||
"Eq": lambda a, b: a == b,
|
||||
"Neq": lambda a, b: a != b,
|
||||
}
|
||||
|
||||
|
||||
class BoolUnaryOperation:
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls) -> Mapping[str, Any]:
|
||||
return {
|
||||
"required": {"op": (list(BOOL_UNARY_OPERATIONS.keys()),), "a": DEFAULT_BOOL}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("BOOLEAN",)
|
||||
FUNCTION = "op"
|
||||
CATEGORY = "math/bool"
|
||||
|
||||
def op(self, op: str, a: bool) -> tuple[bool]:
|
||||
return (BOOL_UNARY_OPERATIONS[op](a),)
|
||||
|
||||
|
||||
class BoolBinaryOperation:
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls) -> Mapping[str, Any]:
|
||||
return {
|
||||
"required": {
|
||||
"op": (list(BOOL_BINARY_OPERATIONS.keys()),),
|
||||
"a": DEFAULT_BOOL,
|
||||
"b": DEFAULT_BOOL,
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("BOOLEAN",)
|
||||
FUNCTION = "op"
|
||||
CATEGORY = "math/bool"
|
||||
|
||||
def op(self, op: str, a: bool, b: bool) -> tuple[bool]:
|
||||
return (BOOL_BINARY_OPERATIONS[op](a, b),)
|
||||
|
||||
|
||||
NODE_CLASS_MAPPINGS = {
|
||||
"CM_BoolUnaryOperation": BoolUnaryOperation,
|
||||
"CM_BoolBinaryOperation": BoolBinaryOperation,
|
||||
}
|
||||
3
custom_nodes/ComfyMath/src/comfymath/control.py
Normal file
3
custom_nodes/ComfyMath/src/comfymath/control.py
Normal file
@@ -0,0 +1,3 @@
|
||||
from typing import Any, Mapping
|
||||
|
||||
NODE_CLASS_MAPPINGS: Mapping[str, Any] = {}
|
||||
273
custom_nodes/ComfyMath/src/comfymath/convert.py
Normal file
273
custom_nodes/ComfyMath/src/comfymath/convert.py
Normal file
@@ -0,0 +1,273 @@
|
||||
from typing import Any, Mapping
|
||||
|
||||
from .vec import VEC2_ZERO, VEC3_ZERO, VEC4_ZERO
|
||||
from .types import Number, Vec2, Vec3, Vec4
|
||||
|
||||
|
||||
class BoolToInt:
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls) -> Mapping[str, Any]:
|
||||
return {"required": {"a": ("BOOLEAN", {"default": False})}}
|
||||
|
||||
RETURN_TYPES = ("INT",)
|
||||
FUNCTION = "op"
|
||||
CATEGORY = "math/conversion"
|
||||
|
||||
def op(self, a: bool) -> tuple[int]:
|
||||
return (int(a),)
|
||||
|
||||
|
||||
class IntToBool:
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls) -> Mapping[str, Any]:
|
||||
return {"required": {"a": ("INT", {"default": 0})}}
|
||||
|
||||
RETURN_TYPES = ("BOOLEAN",)
|
||||
FUNCTION = "op"
|
||||
CATEGORY = "math/conversion"
|
||||
|
||||
def op(self, a: int) -> tuple[bool]:
|
||||
return (a != 0,)
|
||||
|
||||
|
||||
class FloatToInt:
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls) -> Mapping[str, Any]:
|
||||
return {"required": {"a": ("FLOAT", {"default": 0.0, "round": False})}}
|
||||
|
||||
RETURN_TYPES = ("INT",)
|
||||
FUNCTION = "op"
|
||||
CATEGORY = "math/conversion"
|
||||
|
||||
def op(self, a: float) -> tuple[int]:
|
||||
return (int(a),)
|
||||
|
||||
|
||||
class IntToFloat:
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls) -> Mapping[str, Any]:
|
||||
return {"required": {"a": ("INT", {"default": 0})}}
|
||||
|
||||
RETURN_TYPES = ("FLOAT",)
|
||||
FUNCTION = "op"
|
||||
CATEGORY = "math/conversion"
|
||||
|
||||
def op(self, a: int) -> tuple[float]:
|
||||
return (float(a),)
|
||||
|
||||
|
||||
class IntToNumber:
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls) -> Mapping[str, Any]:
|
||||
return {"required": {"a": ("INT", {"default": 0})}}
|
||||
|
||||
RETURN_TYPES = ("NUMBER",)
|
||||
FUNCTION = "op"
|
||||
CATEGORY = "math/conversion"
|
||||
|
||||
def op(self, a: int) -> tuple[Number]:
|
||||
return (a,)
|
||||
|
||||
|
||||
class NumberToInt:
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls) -> Mapping[str, Any]:
|
||||
return {"required": {"a": ("NUMBER", {"default": 0.0})}}
|
||||
|
||||
RETURN_TYPES = ("INT",)
|
||||
FUNCTION = "op"
|
||||
CATEGORY = "math/conversion"
|
||||
|
||||
def op(self, a: Number) -> tuple[int]:
|
||||
return (int(a),)
|
||||
|
||||
|
||||
class FloatToNumber:
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls) -> Mapping[str, Any]:
|
||||
return {"required": {"a": ("FLOAT", {"default": 0.0, "round": False})}}
|
||||
|
||||
RETURN_TYPES = ("NUMBER",)
|
||||
FUNCTION = "op"
|
||||
CATEGORY = "math/conversion"
|
||||
|
||||
def op(self, a: float) -> tuple[Number]:
|
||||
return (a,)
|
||||
|
||||
|
||||
class NumberToFloat:
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls) -> Mapping[str, Any]:
|
||||
return {"required": {"a": ("NUMBER", {"default": 0.0})}}
|
||||
|
||||
RETURN_TYPES = ("FLOAT",)
|
||||
FUNCTION = "op"
|
||||
CATEGORY = "math/conversion"
|
||||
|
||||
def op(self, a: Number) -> tuple[float]:
|
||||
return (float(a),)
|
||||
|
||||
|
||||
class ComposeVec2:
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls) -> Mapping[str, Any]:
|
||||
return {
|
||||
"required": {
|
||||
"x": ("FLOAT", {"default": 0.0, "round": False}),
|
||||
"y": ("FLOAT", {"default": 0.0, "round": False}),
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("VEC2",)
|
||||
FUNCTION = "op"
|
||||
CATEGORY = "math/conversion"
|
||||
|
||||
def op(self, x: float, y: float) -> tuple[Vec2]:
|
||||
return ((x, y),)
|
||||
|
||||
|
||||
class FillVec2:
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls) -> Mapping[str, Any]:
|
||||
return {
|
||||
"required": {
|
||||
"a": ("FLOAT", {"default": 0.0, "round": False}),
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("VEC2",)
|
||||
FUNCTION = "op"
|
||||
CATEGORY = "math/conversion"
|
||||
|
||||
def op(self, a: float) -> tuple[Vec2]:
|
||||
return ((a, a),)
|
||||
|
||||
|
||||
class BreakoutVec2:
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls) -> Mapping[str, Any]:
|
||||
return {"required": {"a": ("VEC2", {"default": VEC2_ZERO})}}
|
||||
|
||||
RETURN_TYPES = ("FLOAT", "FLOAT")
|
||||
FUNCTION = "op"
|
||||
CATEGORY = "math/conversion"
|
||||
|
||||
def op(self, a: Vec2) -> tuple[float, float]:
|
||||
return (a[0], a[1])
|
||||
|
||||
|
||||
class ComposeVec3:
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls) -> Mapping[str, Any]:
|
||||
return {
|
||||
"required": {
|
||||
"x": ("FLOAT", {"default": 0.0}),
|
||||
"y": ("FLOAT", {"default": 0.0}),
|
||||
"z": ("FLOAT", {"default": 0.0}),
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("VEC3",)
|
||||
FUNCTION = "op"
|
||||
CATEGORY = "math/conversion"
|
||||
|
||||
def op(self, x: float, y: float, z: float) -> tuple[Vec3]:
|
||||
return ((x, y, z),)
|
||||
|
||||
|
||||
class FillVec3:
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls) -> Mapping[str, Any]:
|
||||
return {
|
||||
"required": {
|
||||
"a": ("FLOAT", {"default": 0.0}),
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("VEC3",)
|
||||
FUNCTION = "op"
|
||||
CATEGORY = "math/conversion"
|
||||
|
||||
def op(self, a: float) -> tuple[Vec3]:
|
||||
return ((a, a, a),)
|
||||
|
||||
|
||||
class BreakoutVec3:
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls) -> Mapping[str, Any]:
|
||||
return {"required": {"a": ("VEC3", {"default": VEC3_ZERO})}}
|
||||
|
||||
RETURN_TYPES = ("FLOAT", "FLOAT", "FLOAT")
|
||||
FUNCTION = "op"
|
||||
CATEGORY = "math/conversion"
|
||||
|
||||
def op(self, a: Vec3) -> tuple[float, float, float]:
|
||||
return (a[0], a[1], a[2])
|
||||
|
||||
|
||||
class ComposeVec4:
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls) -> Mapping[str, Any]:
|
||||
return {
|
||||
"required": {
|
||||
"x": ("FLOAT", {"default": 0.0}),
|
||||
"y": ("FLOAT", {"default": 0.0}),
|
||||
"z": ("FLOAT", {"default": 0.0}),
|
||||
"w": ("FLOAT", {"default": 0.0}),
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("VEC4",)
|
||||
FUNCTION = "op"
|
||||
CATEGORY = "math/conversion"
|
||||
|
||||
def op(self, x: float, y: float, z: float, w: float) -> tuple[Vec4]:
|
||||
return ((x, y, z, w),)
|
||||
|
||||
|
||||
class FillVec4:
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls) -> Mapping[str, Any]:
|
||||
return {
|
||||
"required": {
|
||||
"a": ("FLOAT", {"default": 0.0}),
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("VEC4",)
|
||||
FUNCTION = "op"
|
||||
CATEGORY = "math/conversion"
|
||||
|
||||
def op(self, a: float) -> tuple[Vec4]:
|
||||
return ((a, a, a, a),)
|
||||
|
||||
|
||||
class BreakoutVec4:
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls) -> Mapping[str, Any]:
|
||||
return {"required": {"a": ("VEC4", {"default": VEC4_ZERO})}}
|
||||
|
||||
RETURN_TYPES = ("FLOAT", "FLOAT", "FLOAT", "FLOAT")
|
||||
FUNCTION = "op"
|
||||
CATEGORY = "math/conversion"
|
||||
|
||||
def op(self, a: Vec4) -> tuple[float, float, float, float]:
|
||||
return (a[0], a[1], a[2], a[3])
|
||||
|
||||
|
||||
NODE_CLASS_MAPPINGS = {
|
||||
"CM_BoolToInt": BoolToInt,
|
||||
"CM_IntToBool": IntToBool,
|
||||
"CM_FloatToInt": FloatToInt,
|
||||
"CM_IntToFloat": IntToFloat,
|
||||
"CM_IntToNumber": IntToNumber,
|
||||
"CM_NumberToInt": NumberToInt,
|
||||
"CM_FloatToNumber": FloatToNumber,
|
||||
"CM_NumberToFloat": NumberToFloat,
|
||||
"CM_ComposeVec2": ComposeVec2,
|
||||
"CM_ComposeVec3": ComposeVec3,
|
||||
"CM_ComposeVec4": ComposeVec4,
|
||||
"CM_BreakoutVec2": BreakoutVec2,
|
||||
"CM_BreakoutVec3": BreakoutVec3,
|
||||
"CM_BreakoutVec4": BreakoutVec4,
|
||||
}
|
||||
159
custom_nodes/ComfyMath/src/comfymath/float.py
Normal file
159
custom_nodes/ComfyMath/src/comfymath/float.py
Normal file
@@ -0,0 +1,159 @@
|
||||
import math
|
||||
|
||||
from typing import Any, Callable, Mapping
|
||||
|
||||
DEFAULT_FLOAT = ("FLOAT", {"default": 0.0, "step": 0.001, "round": False})
|
||||
|
||||
FLOAT_UNARY_OPERATIONS: Mapping[str, Callable[[float], float]] = {
|
||||
"Neg": lambda a: -a,
|
||||
"Inc": lambda a: a + 1,
|
||||
"Dec": lambda a: a - 1,
|
||||
"Abs": lambda a: abs(a),
|
||||
"Sqr": lambda a: a * a,
|
||||
"Cube": lambda a: a * a * a,
|
||||
"Sqrt": lambda a: math.sqrt(a),
|
||||
"Exp": lambda a: math.exp(a),
|
||||
"Ln": lambda a: math.log(a),
|
||||
"Log10": lambda a: math.log10(a),
|
||||
"Log2": lambda a: math.log2(a),
|
||||
"Sin": lambda a: math.sin(a),
|
||||
"Cos": lambda a: math.cos(a),
|
||||
"Tan": lambda a: math.tan(a),
|
||||
"Asin": lambda a: math.asin(a),
|
||||
"Acos": lambda a: math.acos(a),
|
||||
"Atan": lambda a: math.atan(a),
|
||||
"Sinh": lambda a: math.sinh(a),
|
||||
"Cosh": lambda a: math.cosh(a),
|
||||
"Tanh": lambda a: math.tanh(a),
|
||||
"Asinh": lambda a: math.asinh(a),
|
||||
"Acosh": lambda a: math.acosh(a),
|
||||
"Atanh": lambda a: math.atanh(a),
|
||||
"Round": lambda a: round(a),
|
||||
"Floor": lambda a: math.floor(a),
|
||||
"Ceil": lambda a: math.ceil(a),
|
||||
"Trunc": lambda a: math.trunc(a),
|
||||
"Erf": lambda a: math.erf(a),
|
||||
"Erfc": lambda a: math.erfc(a),
|
||||
"Gamma": lambda a: math.gamma(a),
|
||||
"Radians": lambda a: math.radians(a),
|
||||
"Degrees": lambda a: math.degrees(a),
|
||||
}
|
||||
|
||||
FLOAT_UNARY_CONDITIONS: Mapping[str, Callable[[float], bool]] = {
|
||||
"IsZero": lambda a: a == 0.0,
|
||||
"IsPositive": lambda a: a > 0.0,
|
||||
"IsNegative": lambda a: a < 0.0,
|
||||
"IsNonZero": lambda a: a != 0.0,
|
||||
"IsPositiveInfinity": lambda a: math.isinf(a) and a > 0.0,
|
||||
"IsNegativeInfinity": lambda a: math.isinf(a) and a < 0.0,
|
||||
"IsNaN": lambda a: math.isnan(a),
|
||||
"IsFinite": lambda a: math.isfinite(a),
|
||||
"IsInfinite": lambda a: math.isinf(a),
|
||||
"IsEven": lambda a: a % 2 == 0.0,
|
||||
"IsOdd": lambda a: a % 2 != 0.0,
|
||||
}
|
||||
|
||||
FLOAT_BINARY_OPERATIONS: Mapping[str, Callable[[float, float], float]] = {
|
||||
"Add": lambda a, b: a + b,
|
||||
"Sub": lambda a, b: a - b,
|
||||
"Mul": lambda a, b: a * b,
|
||||
"Div": lambda a, b: a / b,
|
||||
"Mod": lambda a, b: a % b,
|
||||
"Pow": lambda a, b: a**b,
|
||||
"FloorDiv": lambda a, b: a // b,
|
||||
"Max": lambda a, b: max(a, b),
|
||||
"Min": lambda a, b: min(a, b),
|
||||
"Log": lambda a, b: math.log(a, b),
|
||||
"Atan2": lambda a, b: math.atan2(a, b),
|
||||
}
|
||||
|
||||
FLOAT_BINARY_CONDITIONS: Mapping[str, Callable[[float, float], bool]] = {
|
||||
"Eq": lambda a, b: a == b,
|
||||
"Neq": lambda a, b: a != b,
|
||||
"Gt": lambda a, b: a > b,
|
||||
"Gte": lambda a, b: a >= b,
|
||||
"Lt": lambda a, b: a < b,
|
||||
"Lte": lambda a, b: a <= b,
|
||||
}
|
||||
|
||||
|
||||
class FloatUnaryOperation:
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls) -> Mapping[str, Any]:
|
||||
return {
|
||||
"required": {
|
||||
"op": (list(FLOAT_UNARY_OPERATIONS.keys()),),
|
||||
"a": DEFAULT_FLOAT,
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("FLOAT",)
|
||||
FUNCTION = "op"
|
||||
CATEGORY = "math/float"
|
||||
|
||||
def op(self, op: str, a: float) -> tuple[float]:
|
||||
return (FLOAT_UNARY_OPERATIONS[op](a),)
|
||||
|
||||
|
||||
class FloatUnaryCondition:
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls) -> Mapping[str, Any]:
|
||||
return {
|
||||
"required": {
|
||||
"op": (list(FLOAT_UNARY_CONDITIONS.keys()),),
|
||||
"a": DEFAULT_FLOAT,
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("BOOLEAN",)
|
||||
FUNCTION = "op"
|
||||
CATEGORY = "math/float"
|
||||
|
||||
def op(self, op: str, a: float) -> tuple[bool]:
|
||||
return (FLOAT_UNARY_CONDITIONS[op](a),)
|
||||
|
||||
|
||||
class FloatBinaryOperation:
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls) -> Mapping[str, Any]:
|
||||
return {
|
||||
"required": {
|
||||
"op": (list(FLOAT_BINARY_OPERATIONS.keys()),),
|
||||
"a": DEFAULT_FLOAT,
|
||||
"b": DEFAULT_FLOAT,
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("FLOAT",)
|
||||
FUNCTION = "op"
|
||||
CATEGORY = "math/float"
|
||||
|
||||
def op(self, op: str, a: float, b: float) -> tuple[float]:
|
||||
return (FLOAT_BINARY_OPERATIONS[op](a, b),)
|
||||
|
||||
|
||||
class FloatBinaryCondition:
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls) -> Mapping[str, Any]:
|
||||
return {
|
||||
"required": {
|
||||
"op": (list(FLOAT_BINARY_CONDITIONS.keys()),),
|
||||
"a": DEFAULT_FLOAT,
|
||||
"b": DEFAULT_FLOAT,
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("BOOLEAN",)
|
||||
FUNCTION = "op"
|
||||
CATEGORY = "math/float"
|
||||
|
||||
def op(self, op: str, a: float, b: float) -> tuple[bool]:
|
||||
return (FLOAT_BINARY_CONDITIONS[op](a, b),)
|
||||
|
||||
|
||||
NODE_CLASS_MAPPINGS = {
|
||||
"CM_FloatUnaryOperation": FloatUnaryOperation,
|
||||
"CM_FloatUnaryCondition": FloatUnaryCondition,
|
||||
"CM_FloatBinaryOperation": FloatBinaryOperation,
|
||||
"CM_FloatBinaryCondition": FloatBinaryCondition,
|
||||
}
|
||||
153
custom_nodes/ComfyMath/src/comfymath/graphics.py
Normal file
153
custom_nodes/ComfyMath/src/comfymath/graphics.py
Normal file
@@ -0,0 +1,153 @@
|
||||
from abc import ABC, abstractmethod
|
||||
from typing import Any, Mapping, Sequence, Tuple
|
||||
|
||||
|
||||
SDXL_SUPPORTED_RESOLUTIONS = [
|
||||
(1024, 1024, 1.0),
|
||||
(1152, 896, 1.2857142857142858),
|
||||
(896, 1152, 0.7777777777777778),
|
||||
(1216, 832, 1.4615384615384615),
|
||||
(832, 1216, 0.6842105263157895),
|
||||
(1344, 768, 1.75),
|
||||
(768, 1344, 0.5714285714285714),
|
||||
(1536, 640, 2.4),
|
||||
(640, 1536, 0.4166666666666667),
|
||||
]
|
||||
|
||||
SDXL_EXTENDED_RESOLUTIONS = [
|
||||
(512, 2048, 0.25),
|
||||
(512, 1984, 0.26),
|
||||
(512, 1920, 0.27),
|
||||
(512, 1856, 0.28),
|
||||
(576, 1792, 0.32),
|
||||
(576, 1728, 0.33),
|
||||
(576, 1664, 0.35),
|
||||
(640, 1600, 0.4),
|
||||
(640, 1536, 0.42),
|
||||
(704, 1472, 0.48),
|
||||
(704, 1408, 0.5),
|
||||
(704, 1344, 0.52),
|
||||
(768, 1344, 0.57),
|
||||
(768, 1280, 0.6),
|
||||
(832, 1216, 0.68),
|
||||
(832, 1152, 0.72),
|
||||
(896, 1152, 0.78),
|
||||
(896, 1088, 0.82),
|
||||
(960, 1088, 0.88),
|
||||
(960, 1024, 0.94),
|
||||
(1024, 1024, 1.0),
|
||||
(1024, 960, 1.8),
|
||||
(1088, 960, 1.14),
|
||||
(1088, 896, 1.22),
|
||||
(1152, 896, 1.30),
|
||||
(1152, 832, 1.39),
|
||||
(1216, 832, 1.47),
|
||||
(1280, 768, 1.68),
|
||||
(1344, 768, 1.76),
|
||||
(1408, 704, 2.0),
|
||||
(1472, 704, 2.10),
|
||||
(1536, 640, 2.4),
|
||||
(1600, 640, 2.5),
|
||||
(1664, 576, 2.90),
|
||||
(1728, 576, 3.0),
|
||||
(1792, 576, 3.12),
|
||||
(1856, 512, 3.63),
|
||||
(1920, 512, 3.76),
|
||||
(1984, 512, 3.89),
|
||||
(2048, 512, 4.0),
|
||||
]
|
||||
|
||||
|
||||
class Resolution(ABC):
|
||||
@classmethod
|
||||
@abstractmethod
|
||||
def resolutions(cls) -> Sequence[Tuple[int, int, float]]: ...
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls) -> Mapping[str, Any]:
|
||||
return {
|
||||
"required": {
|
||||
"resolution": ([f"{res[0]}x{res[1]}" for res in cls.resolutions()],)
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("INT", "INT")
|
||||
RETURN_NAMES = ("width", "height")
|
||||
FUNCTION = "op"
|
||||
CATEGORY = "math/graphics"
|
||||
|
||||
def op(self, resolution: str) -> tuple[int, int]:
|
||||
width, height = resolution.split("x")
|
||||
return (int(width), int(height))
|
||||
|
||||
|
||||
class NearestResolution(ABC):
|
||||
@classmethod
|
||||
@abstractmethod
|
||||
def resolutions(cls) -> Sequence[Tuple[int, int, float]]: ...
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls) -> Mapping[str, Any]:
|
||||
return {"required": {"image": ("IMAGE",)}}
|
||||
|
||||
RETURN_TYPES = ("INT", "INT")
|
||||
RETURN_NAMES = ("width", "height")
|
||||
FUNCTION = "op"
|
||||
CATEGORY = "math/graphics"
|
||||
|
||||
def op(self, image) -> tuple[int, int]:
|
||||
image_width = image.size()[2]
|
||||
image_height = image.size()[1]
|
||||
print(f"Input image resolution: {image_width}x{image_height}")
|
||||
image_ratio = image_width / image_height
|
||||
differences = [
|
||||
(abs(image_ratio - resolution[2]), resolution)
|
||||
for resolution in self.resolutions()
|
||||
]
|
||||
smallest = None
|
||||
for difference in differences:
|
||||
if smallest is None:
|
||||
smallest = difference
|
||||
else:
|
||||
if difference[0] < smallest[0]:
|
||||
smallest = difference
|
||||
if smallest is not None:
|
||||
width = smallest[1][0]
|
||||
height = smallest[1][1]
|
||||
else:
|
||||
width = 1024
|
||||
height = 1024
|
||||
print(f"Selected resolution: {width}x{height}")
|
||||
return (width, height)
|
||||
|
||||
|
||||
class SDXLResolution(Resolution):
|
||||
@classmethod
|
||||
def resolutions(cls):
|
||||
return SDXL_SUPPORTED_RESOLUTIONS
|
||||
|
||||
|
||||
class SDXLExtendedResolution(Resolution):
|
||||
@classmethod
|
||||
def resolutions(cls):
|
||||
return SDXL_EXTENDED_RESOLUTIONS
|
||||
|
||||
|
||||
class NearestSDXLResolution(NearestResolution):
|
||||
@classmethod
|
||||
def resolutions(cls):
|
||||
return SDXL_SUPPORTED_RESOLUTIONS
|
||||
|
||||
|
||||
class NearestSDXLExtendedResolution(NearestResolution):
|
||||
@classmethod
|
||||
def resolutions(cls):
|
||||
return SDXL_EXTENDED_RESOLUTIONS
|
||||
|
||||
|
||||
NODE_CLASS_MAPPINGS = {
|
||||
"CM_SDXLResolution": SDXLResolution,
|
||||
"CM_NearestSDXLResolution": NearestSDXLResolution,
|
||||
"CM_SDXLExtendedResolution": SDXLExtendedResolution,
|
||||
"CM_NearestSDXLExtendedResolution": NearestSDXLExtendedResolution,
|
||||
}
|
||||
129
custom_nodes/ComfyMath/src/comfymath/int.py
Normal file
129
custom_nodes/ComfyMath/src/comfymath/int.py
Normal file
@@ -0,0 +1,129 @@
|
||||
import math
|
||||
|
||||
from typing import Any, Callable, Mapping
|
||||
|
||||
DEFAULT_INT = ("INT", {"default": 0})
|
||||
|
||||
INT_UNARY_OPERATIONS: Mapping[str, Callable[[int], int]] = {
|
||||
"Abs": lambda a: abs(a),
|
||||
"Neg": lambda a: -a,
|
||||
"Inc": lambda a: a + 1,
|
||||
"Dec": lambda a: a - 1,
|
||||
"Sqr": lambda a: a * a,
|
||||
"Cube": lambda a: a * a * a,
|
||||
"Not": lambda a: ~a,
|
||||
"Factorial": lambda a: math.factorial(a),
|
||||
}
|
||||
|
||||
INT_UNARY_CONDITIONS: Mapping[str, Callable[[int], bool]] = {
|
||||
"IsZero": lambda a: a == 0,
|
||||
"IsNonZero": lambda a: a != 0,
|
||||
"IsPositive": lambda a: a > 0,
|
||||
"IsNegative": lambda a: a < 0,
|
||||
"IsEven": lambda a: a % 2 == 0,
|
||||
"IsOdd": lambda a: a % 2 == 1,
|
||||
}
|
||||
|
||||
INT_BINARY_OPERATIONS: Mapping[str, Callable[[int, int], int]] = {
|
||||
"Add": lambda a, b: a + b,
|
||||
"Sub": lambda a, b: a - b,
|
||||
"Mul": lambda a, b: a * b,
|
||||
"Div": lambda a, b: a // b,
|
||||
"Mod": lambda a, b: a % b,
|
||||
"Pow": lambda a, b: a**b,
|
||||
"And": lambda a, b: a & b,
|
||||
"Nand": lambda a, b: ~a & b,
|
||||
"Or": lambda a, b: a | b,
|
||||
"Nor": lambda a, b: ~a & b,
|
||||
"Xor": lambda a, b: a ^ b,
|
||||
"Xnor": lambda a, b: ~a ^ b,
|
||||
"Shl": lambda a, b: a << b,
|
||||
"Shr": lambda a, b: a >> b,
|
||||
"Max": lambda a, b: max(a, b),
|
||||
"Min": lambda a, b: min(a, b),
|
||||
}
|
||||
|
||||
INT_BINARY_CONDITIONS: Mapping[str, Callable[[int, int], bool]] = {
|
||||
"Eq": lambda a, b: a == b,
|
||||
"Neq": lambda a, b: a != b,
|
||||
"Gt": lambda a, b: a > b,
|
||||
"Lt": lambda a, b: a < b,
|
||||
"Geq": lambda a, b: a >= b,
|
||||
"Leq": lambda a, b: a <= b,
|
||||
}
|
||||
|
||||
|
||||
class IntUnaryOperation:
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls) -> Mapping[str, Any]:
|
||||
return {
|
||||
"required": {"op": (list(INT_UNARY_OPERATIONS.keys()),), "a": DEFAULT_INT}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("INT",)
|
||||
FUNCTION = "op"
|
||||
CATEGORY = "math/int"
|
||||
|
||||
def op(self, op: str, a: int) -> tuple[int]:
|
||||
return (INT_UNARY_OPERATIONS[op](a),)
|
||||
|
||||
|
||||
class IntUnaryCondition:
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls) -> Mapping[str, Any]:
|
||||
return {
|
||||
"required": {"op": (list(INT_UNARY_CONDITIONS.keys()),), "a": DEFAULT_INT}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("BOOL",)
|
||||
FUNCTION = "op"
|
||||
CATEGORY = "math/int"
|
||||
|
||||
def op(self, op: str, a: int) -> tuple[bool]:
|
||||
return (INT_UNARY_CONDITIONS[op](a),)
|
||||
|
||||
|
||||
class IntBinaryOperation:
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls) -> Mapping[str, Any]:
|
||||
return {
|
||||
"required": {
|
||||
"op": (list(INT_BINARY_OPERATIONS.keys()),),
|
||||
"a": DEFAULT_INT,
|
||||
"b": DEFAULT_INT,
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("INT",)
|
||||
FUNCTION = "op"
|
||||
CATEGORY = "math/int"
|
||||
|
||||
def op(self, op: str, a: int, b: int) -> tuple[int]:
|
||||
return (INT_BINARY_OPERATIONS[op](a, b),)
|
||||
|
||||
|
||||
class IntBinaryCondition:
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls) -> Mapping[str, Any]:
|
||||
return {
|
||||
"required": {
|
||||
"op": (list(INT_BINARY_CONDITIONS.keys()),),
|
||||
"a": DEFAULT_INT,
|
||||
"b": DEFAULT_INT,
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("BOOL",)
|
||||
FUNCTION = "op"
|
||||
CATEGORY = "math/int"
|
||||
|
||||
def op(self, op: str, a: int, b: int) -> tuple[bool]:
|
||||
return (INT_BINARY_CONDITIONS[op](a, b),)
|
||||
|
||||
|
||||
NODE_CLASS_MAPPINGS = {
|
||||
"CM_IntUnaryOperation": IntUnaryOperation,
|
||||
"CM_IntUnaryCondition": IntUnaryCondition,
|
||||
"CM_IntBinaryOperation": IntBinaryOperation,
|
||||
"CM_IntBinaryCondition": IntBinaryCondition,
|
||||
}
|
||||
94
custom_nodes/ComfyMath/src/comfymath/number.py
Normal file
94
custom_nodes/ComfyMath/src/comfymath/number.py
Normal file
@@ -0,0 +1,94 @@
|
||||
from dataclasses import dataclass
|
||||
from typing import Any, Callable, Mapping
|
||||
|
||||
from .float import (
|
||||
FLOAT_UNARY_OPERATIONS,
|
||||
FLOAT_UNARY_CONDITIONS,
|
||||
FLOAT_BINARY_OPERATIONS,
|
||||
FLOAT_BINARY_CONDITIONS,
|
||||
)
|
||||
from .types import Number
|
||||
|
||||
DEFAULT_NUMBER = ("NUMBER", {"default": 0.0})
|
||||
|
||||
|
||||
class NumberUnaryOperation:
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls) -> Mapping[str, Any]:
|
||||
return {
|
||||
"required": {
|
||||
"op": (list(FLOAT_UNARY_OPERATIONS.keys()),),
|
||||
"a": DEFAULT_NUMBER,
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("NUMBER",)
|
||||
FUNCTION = "op"
|
||||
CATEGORY = "math/number"
|
||||
|
||||
def op(self, op: str, a: Number) -> tuple[float]:
|
||||
return (FLOAT_UNARY_OPERATIONS[op](float(a)),)
|
||||
|
||||
|
||||
class NumberUnaryCondition:
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls) -> Mapping[str, Any]:
|
||||
return {
|
||||
"required": {
|
||||
"op": (list(FLOAT_UNARY_CONDITIONS.keys()),),
|
||||
"a": DEFAULT_NUMBER,
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("BOOL",)
|
||||
FUNCTION = "op"
|
||||
CATEGORY = "math/Number"
|
||||
|
||||
def op(self, op: str, a: Number) -> tuple[bool]:
|
||||
return (FLOAT_UNARY_CONDITIONS[op](float(a)),)
|
||||
|
||||
|
||||
class NumberBinaryOperation:
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls) -> Mapping[str, Any]:
|
||||
return {
|
||||
"required": {
|
||||
"op": (list(FLOAT_BINARY_OPERATIONS.keys()),),
|
||||
"a": DEFAULT_NUMBER,
|
||||
"b": DEFAULT_NUMBER,
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("NUMBER",)
|
||||
FUNCTION = "op"
|
||||
CATEGORY = "math/number"
|
||||
|
||||
def op(self, op: str, a: Number, b: Number) -> tuple[float]:
|
||||
return (FLOAT_BINARY_OPERATIONS[op](float(a), float(b)),)
|
||||
|
||||
|
||||
class NumberBinaryCondition:
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls) -> Mapping[str, Any]:
|
||||
return {
|
||||
"required": {
|
||||
"op": (list(FLOAT_BINARY_CONDITIONS.keys()),),
|
||||
"a": DEFAULT_NUMBER,
|
||||
"b": DEFAULT_NUMBER,
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("BOOL",)
|
||||
FUNCTION = "op"
|
||||
CATEGORY = "math/float"
|
||||
|
||||
def op(self, op: str, a: Number, b: Number) -> tuple[bool]:
|
||||
return (FLOAT_BINARY_CONDITIONS[op](float(a), float(b)),)
|
||||
|
||||
|
||||
NODE_CLASS_MAPPINGS = {
|
||||
"CM_NumberUnaryOperation": NumberUnaryOperation,
|
||||
"CM_NumberUnaryCondition": NumberUnaryCondition,
|
||||
"CM_NumberBinaryOperation": NumberBinaryOperation,
|
||||
"CM_NumberBinaryCondition": NumberBinaryCondition,
|
||||
}
|
||||
0
custom_nodes/ComfyMath/src/comfymath/py.typed
Normal file
0
custom_nodes/ComfyMath/src/comfymath/py.typed
Normal file
16
custom_nodes/ComfyMath/src/comfymath/types.py
Normal file
16
custom_nodes/ComfyMath/src/comfymath/types.py
Normal file
@@ -0,0 +1,16 @@
|
||||
import sys
|
||||
|
||||
if sys.version_info[1] < 10:
|
||||
from typing import Tuple, Union
|
||||
|
||||
Number = Union[int, float]
|
||||
Vec2 = Tuple[float, float]
|
||||
Vec3 = Tuple[float, float, float]
|
||||
Vec4 = Tuple[float, float, float, float]
|
||||
else:
|
||||
from typing import TypeAlias
|
||||
|
||||
Number: TypeAlias = int | float
|
||||
Vec2: TypeAlias = tuple[float, float]
|
||||
Vec3: TypeAlias = tuple[float, float, float]
|
||||
Vec4: TypeAlias = tuple[float, float, float, float]
|
||||
500
custom_nodes/ComfyMath/src/comfymath/vec.py
Normal file
500
custom_nodes/ComfyMath/src/comfymath/vec.py
Normal file
@@ -0,0 +1,500 @@
|
||||
import numpy
|
||||
|
||||
from typing import Any, Callable, Mapping
|
||||
|
||||
from .types import Vec2, Vec3, Vec4
|
||||
|
||||
VEC2_ZERO = (0.0, 0.0)
|
||||
DEFAULT_VEC2 = ("VEC2", {"default": VEC2_ZERO})
|
||||
|
||||
VEC3_ZERO = (0.0, 0.0, 0.0)
|
||||
DEFAULT_VEC3 = ("VEC3", {"default": VEC3_ZERO})
|
||||
|
||||
VEC4_ZERO = (0.0, 0.0, 0.0, 0.0)
|
||||
DEFAULT_VEC4 = ("VEC4", {"default": VEC4_ZERO})
|
||||
|
||||
VEC_UNARY_OPERATIONS: Mapping[str, Callable[[numpy.ndarray], numpy.ndarray]] = {
|
||||
"Neg": lambda a: -a,
|
||||
"Normalize": lambda a: a / numpy.linalg.norm(a),
|
||||
}
|
||||
|
||||
VEC_TO_SCALAR_UNARY_OPERATION: Mapping[str, Callable[[numpy.ndarray], float]] = {
|
||||
"Norm": lambda a: numpy.linalg.norm(a).astype(float),
|
||||
}
|
||||
|
||||
VEC_UNARY_CONDITIONS: Mapping[str, Callable[[numpy.ndarray], bool]] = {
|
||||
"IsZero": lambda a: not numpy.any(a).astype(bool),
|
||||
"IsNotZero": lambda a: numpy.any(a).astype(bool),
|
||||
"IsNormalized": lambda a: numpy.allclose(a, a / numpy.linalg.norm(a)),
|
||||
"IsNotNormalized": lambda a: not numpy.allclose(a, a / numpy.linalg.norm(a)),
|
||||
}
|
||||
|
||||
VEC_BINARY_OPERATIONS: Mapping[
|
||||
str, Callable[[numpy.ndarray, numpy.ndarray], numpy.ndarray]
|
||||
] = {
|
||||
"Add": lambda a, b: a + b,
|
||||
"Sub": lambda a, b: a - b,
|
||||
"Cross": lambda a, b: numpy.cross(a, b),
|
||||
}
|
||||
|
||||
VEC_TO_SCALAR_BINARY_OPERATION: Mapping[
|
||||
str, Callable[[numpy.ndarray, numpy.ndarray], float]
|
||||
] = {
|
||||
"Dot": lambda a, b: numpy.dot(a, b),
|
||||
"Distance": lambda a, b: numpy.linalg.norm(a - b).astype(float),
|
||||
}
|
||||
|
||||
VEC_BINARY_CONDITIONS: Mapping[str, Callable[[numpy.ndarray, numpy.ndarray], bool]] = {
|
||||
"Eq": lambda a, b: numpy.allclose(a, b),
|
||||
"Neq": lambda a, b: not numpy.allclose(a, b),
|
||||
}
|
||||
|
||||
VEC_SCALAR_OPERATION: Mapping[str, Callable[[numpy.ndarray, float], numpy.ndarray]] = {
|
||||
"Mul": lambda a, b: a * b,
|
||||
"Div": lambda a, b: a / b,
|
||||
}
|
||||
|
||||
|
||||
def _vec2_from_numpy(a: numpy.ndarray) -> Vec2:
|
||||
return (
|
||||
float(a[0]),
|
||||
float(a[1]),
|
||||
)
|
||||
|
||||
|
||||
def _vec3_from_numpy(a: numpy.ndarray) -> Vec3:
|
||||
return (
|
||||
float(a[0]),
|
||||
float(a[1]),
|
||||
float(a[2]),
|
||||
)
|
||||
|
||||
|
||||
def _vec4_from_numpy(a: numpy.ndarray) -> Vec4:
|
||||
return (
|
||||
float(a[0]),
|
||||
float(a[1]),
|
||||
float(a[2]),
|
||||
float(a[3]),
|
||||
)
|
||||
|
||||
|
||||
class Vec2UnaryOperation:
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls) -> Mapping[str, Any]:
|
||||
return {
|
||||
"required": {
|
||||
"op": (list(VEC_UNARY_OPERATIONS.keys()),),
|
||||
"a": DEFAULT_VEC2,
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("VEC2",)
|
||||
FUNCTION = "op"
|
||||
CATEGORY = "math/vec2"
|
||||
|
||||
def op(self, op: str, a: Vec2) -> tuple[Vec2]:
|
||||
return (_vec2_from_numpy(VEC_UNARY_OPERATIONS[op](numpy.array(a))),)
|
||||
|
||||
|
||||
class Vec2ToScalarUnaryOperation:
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls) -> Mapping[str, Any]:
|
||||
return {
|
||||
"required": {
|
||||
"op": (list(VEC_TO_SCALAR_UNARY_OPERATION.keys()),),
|
||||
"a": DEFAULT_VEC2,
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("FLOAT",)
|
||||
FUNCTION = "op"
|
||||
CATEGORY = "math/vec2"
|
||||
|
||||
def op(self, op: str, a: Vec2) -> tuple[float]:
|
||||
return (VEC_TO_SCALAR_UNARY_OPERATION[op](numpy.array(a)),)
|
||||
|
||||
|
||||
class Vec2UnaryCondition:
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls) -> Mapping[str, Any]:
|
||||
return {
|
||||
"required": {
|
||||
"op": (list(VEC_UNARY_CONDITIONS.keys()),),
|
||||
"a": DEFAULT_VEC2,
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("BOOL",)
|
||||
FUNCTION = "op"
|
||||
CATEGORY = "math/vec2"
|
||||
|
||||
def op(self, op: str, a: Vec2) -> tuple[bool]:
|
||||
return (VEC_UNARY_CONDITIONS[op](numpy.array(a)),)
|
||||
|
||||
|
||||
class Vec2BinaryOperation:
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls) -> Mapping[str, Any]:
|
||||
return {
|
||||
"required": {
|
||||
"op": (list(VEC_BINARY_OPERATIONS.keys()),),
|
||||
"a": DEFAULT_VEC2,
|
||||
"b": DEFAULT_VEC2,
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("VEC2",)
|
||||
FUNCTION = "op"
|
||||
CATEGORY = "math/vec2"
|
||||
|
||||
def op(self, op: str, a: Vec2, b: Vec2) -> tuple[Vec2]:
|
||||
return (
|
||||
_vec2_from_numpy(VEC_BINARY_OPERATIONS[op](numpy.array(a), numpy.array(b))),
|
||||
)
|
||||
|
||||
|
||||
class Vec2ToScalarBinaryOperation:
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls) -> Mapping[str, Any]:
|
||||
return {
|
||||
"required": {
|
||||
"op": (list(VEC_TO_SCALAR_BINARY_OPERATION.keys()),),
|
||||
"a": DEFAULT_VEC2,
|
||||
"b": DEFAULT_VEC2,
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("FLOAT",)
|
||||
FUNCTION = "op"
|
||||
CATEGORY = "math/vec2"
|
||||
|
||||
def op(self, op: str, a: Vec2, b: Vec2) -> tuple[float]:
|
||||
return (VEC_TO_SCALAR_BINARY_OPERATION[op](numpy.array(a), numpy.array(b)),)
|
||||
|
||||
|
||||
class Vec2BinaryCondition:
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls) -> Mapping[str, Any]:
|
||||
return {
|
||||
"required": {
|
||||
"op": (list(VEC_BINARY_CONDITIONS.keys()),),
|
||||
"a": DEFAULT_VEC2,
|
||||
"b": DEFAULT_VEC2,
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("BOOL",)
|
||||
FUNCTION = "op"
|
||||
CATEGORY = "math/vec2"
|
||||
|
||||
def op(self, op: str, a: Vec2, b: Vec2) -> tuple[bool]:
|
||||
return (VEC_BINARY_CONDITIONS[op](numpy.array(a), numpy.array(b)),)
|
||||
|
||||
|
||||
class Vec2ScalarOperation:
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls) -> Mapping[str, Any]:
|
||||
return {
|
||||
"required": {
|
||||
"op": (list(VEC_SCALAR_OPERATION.keys()),),
|
||||
"a": DEFAULT_VEC2,
|
||||
"b": ("FLOAT",),
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("VEC2",)
|
||||
FUNCTION = "op"
|
||||
CATEGORY = "math/vec2"
|
||||
|
||||
def op(self, op: str, a: Vec2, b: float) -> tuple[Vec2]:
|
||||
return (_vec2_from_numpy(VEC_SCALAR_OPERATION[op](numpy.array(a), b)),)
|
||||
|
||||
|
||||
class Vec3UnaryOperation:
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls) -> Mapping[str, Any]:
|
||||
return {
|
||||
"required": {
|
||||
"op": (list(VEC_UNARY_OPERATIONS.keys()),),
|
||||
"a": DEFAULT_VEC3,
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("VEC3",)
|
||||
FUNCTION = "op"
|
||||
CATEGORY = "math/vec3"
|
||||
|
||||
def op(self, op: str, a: Vec3) -> tuple[Vec3]:
|
||||
return (_vec3_from_numpy(VEC_UNARY_OPERATIONS[op](numpy.array(a))),)
|
||||
|
||||
|
||||
class Vec3ToScalarUnaryOperation:
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls) -> Mapping[str, Any]:
|
||||
return {
|
||||
"required": {
|
||||
"op": (list(VEC_TO_SCALAR_UNARY_OPERATION.keys()),),
|
||||
"a": DEFAULT_VEC3,
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("FLOAT",)
|
||||
FUNCTION = "op"
|
||||
CATEGORY = "math/vec3"
|
||||
|
||||
def op(self, op: str, a: Vec3) -> tuple[float]:
|
||||
return (VEC_TO_SCALAR_UNARY_OPERATION[op](numpy.array(a)),)
|
||||
|
||||
|
||||
class Vec3UnaryCondition:
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls) -> Mapping[str, Any]:
|
||||
return {
|
||||
"required": {
|
||||
"op": (list(VEC_UNARY_CONDITIONS.keys()),),
|
||||
"a": DEFAULT_VEC3,
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("BOOL",)
|
||||
FUNCTION = "op"
|
||||
CATEGORY = "math/vec3"
|
||||
|
||||
def op(self, op: str, a: Vec3) -> tuple[bool]:
|
||||
return (VEC_UNARY_CONDITIONS[op](numpy.array(a)),)
|
||||
|
||||
|
||||
class Vec3BinaryOperation:
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls) -> Mapping[str, Any]:
|
||||
return {
|
||||
"required": {
|
||||
"op": (list(VEC_BINARY_OPERATIONS.keys()),),
|
||||
"a": DEFAULT_VEC3,
|
||||
"b": DEFAULT_VEC3,
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("VEC3",)
|
||||
FUNCTION = "op"
|
||||
CATEGORY = "math/vec3"
|
||||
|
||||
def op(self, op: str, a: Vec3, b: Vec3) -> tuple[Vec3]:
|
||||
return (
|
||||
_vec3_from_numpy(VEC_BINARY_OPERATIONS[op](numpy.array(a), numpy.array(b))),
|
||||
)
|
||||
|
||||
|
||||
class Vec3ToScalarBinaryOperation:
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls) -> Mapping[str, Any]:
|
||||
return {
|
||||
"required": {
|
||||
"op": (list(VEC_TO_SCALAR_BINARY_OPERATION.keys()),),
|
||||
"a": DEFAULT_VEC3,
|
||||
"b": DEFAULT_VEC3,
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("FLOAT",)
|
||||
FUNCTION = "op"
|
||||
CATEGORY = "math/vec3"
|
||||
|
||||
def op(self, op: str, a: Vec3, b: Vec3) -> tuple[float]:
|
||||
return (VEC_TO_SCALAR_BINARY_OPERATION[op](numpy.array(a), numpy.array(b)),)
|
||||
|
||||
|
||||
class Vec3BinaryCondition:
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls) -> Mapping[str, Any]:
|
||||
return {
|
||||
"required": {
|
||||
"op": (list(VEC_BINARY_CONDITIONS.keys()),),
|
||||
"a": DEFAULT_VEC3,
|
||||
"b": DEFAULT_VEC3,
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("BOOL",)
|
||||
FUNCTION = "op"
|
||||
CATEGORY = "math/vec3"
|
||||
|
||||
def op(self, op: str, a: Vec3, b: Vec3) -> tuple[bool]:
|
||||
return (VEC_BINARY_CONDITIONS[op](numpy.array(a), numpy.array(b)),)
|
||||
|
||||
|
||||
class Vec3ScalarOperation:
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls) -> Mapping[str, Any]:
|
||||
return {
|
||||
"required": {
|
||||
"op": (list(VEC_SCALAR_OPERATION.keys()),),
|
||||
"a": DEFAULT_VEC3,
|
||||
"b": ("FLOAT",),
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("VEC3",)
|
||||
FUNCTION = "op"
|
||||
CATEGORY = "math/vec3"
|
||||
|
||||
def op(self, op: str, a: Vec3, b: float) -> tuple[Vec3]:
|
||||
return (_vec3_from_numpy(VEC_SCALAR_OPERATION[op](numpy.array(a), b)),)
|
||||
|
||||
|
||||
class Vec4UnaryOperation:
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls) -> Mapping[str, Any]:
|
||||
return {
|
||||
"required": {
|
||||
"op": (list(VEC_UNARY_OPERATIONS.keys()),),
|
||||
"a": DEFAULT_VEC4,
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("VEC4",)
|
||||
FUNCTION = "op"
|
||||
CATEGORY = "math/vec4"
|
||||
|
||||
def op(self, op: str, a: Vec4) -> tuple[Vec4]:
|
||||
return (_vec4_from_numpy(VEC_UNARY_OPERATIONS[op](numpy.array(a))),)
|
||||
|
||||
|
||||
class Vec4ToScalarUnaryOperation:
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls) -> Mapping[str, Any]:
|
||||
return {
|
||||
"required": {
|
||||
"op": (list(VEC_TO_SCALAR_UNARY_OPERATION.keys()),),
|
||||
"a": DEFAULT_VEC4,
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("FLOAT",)
|
||||
FUNCTION = "op"
|
||||
CATEGORY = "math/vec4"
|
||||
|
||||
def op(self, op: str, a: Vec4) -> tuple[float]:
|
||||
return (VEC_TO_SCALAR_UNARY_OPERATION[op](numpy.array(a)),)
|
||||
|
||||
|
||||
class Vec4UnaryCondition:
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls) -> Mapping[str, Any]:
|
||||
return {
|
||||
"required": {
|
||||
"op": (list(VEC_UNARY_CONDITIONS.keys()),),
|
||||
"a": DEFAULT_VEC4,
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("BOOL",)
|
||||
FUNCTION = "op"
|
||||
CATEGORY = "math/vec4"
|
||||
|
||||
def op(self, op: str, a: Vec4) -> tuple[bool]:
|
||||
return (VEC_UNARY_CONDITIONS[op](numpy.array(a)),)
|
||||
|
||||
|
||||
class Vec4BinaryOperation:
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls) -> Mapping[str, Any]:
|
||||
return {
|
||||
"required": {
|
||||
"op": (list(VEC_BINARY_OPERATIONS.keys()),),
|
||||
"a": DEFAULT_VEC4,
|
||||
"b": DEFAULT_VEC4,
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("VEC4",)
|
||||
FUNCTION = "op"
|
||||
CATEGORY = "math/vec4"
|
||||
|
||||
def op(self, op: str, a: Vec4, b: Vec4) -> tuple[Vec4]:
|
||||
return (
|
||||
_vec4_from_numpy(VEC_BINARY_OPERATIONS[op](numpy.array(a), numpy.array(b))),
|
||||
)
|
||||
|
||||
|
||||
class Vec4ToScalarBinaryOperation:
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls) -> Mapping[str, Any]:
|
||||
return {
|
||||
"required": {
|
||||
"op": (list(VEC_TO_SCALAR_BINARY_OPERATION.keys()),),
|
||||
"a": DEFAULT_VEC4,
|
||||
"b": DEFAULT_VEC4,
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("FLOAT",)
|
||||
FUNCTION = "op"
|
||||
CATEGORY = "math/vec4"
|
||||
|
||||
def op(self, op: str, a: Vec4, b: Vec4) -> tuple[float]:
|
||||
return (VEC_TO_SCALAR_BINARY_OPERATION[op](numpy.array(a), numpy.array(b)),)
|
||||
|
||||
|
||||
class Vec4BinaryCondition:
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls) -> Mapping[str, Any]:
|
||||
return {
|
||||
"required": {
|
||||
"op": (list(VEC_BINARY_CONDITIONS.keys()),),
|
||||
"a": DEFAULT_VEC4,
|
||||
"b": DEFAULT_VEC4,
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("BOOL",)
|
||||
FUNCTION = "op"
|
||||
CATEGORY = "math/vec4"
|
||||
|
||||
def op(self, op: str, a: Vec4, b: Vec4) -> tuple[bool]:
|
||||
return (VEC_BINARY_CONDITIONS[op](numpy.array(a), numpy.array(b)),)
|
||||
|
||||
|
||||
class Vec4ScalarOperation:
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls) -> Mapping[str, Any]:
|
||||
return {
|
||||
"required": {
|
||||
"op": (list(VEC_SCALAR_OPERATION.keys()),),
|
||||
"a": DEFAULT_VEC4,
|
||||
"b": ("FLOAT",),
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("VEC4",)
|
||||
FUNCTION = "op"
|
||||
CATEGORY = "math/vec4"
|
||||
|
||||
def op(self, op: str, a: Vec4, b: float) -> tuple[Vec4]:
|
||||
return (_vec4_from_numpy(VEC_SCALAR_OPERATION[op](numpy.array(a), b)),)
|
||||
|
||||
|
||||
NODE_CLASS_MAPPINGS = {
|
||||
"CM_Vec2UnaryOperation": Vec2UnaryOperation,
|
||||
"CM_Vec2UnaryCondition": Vec2UnaryCondition,
|
||||
"CM_Vec2ToScalarUnaryOperation": Vec2ToScalarUnaryOperation,
|
||||
"CM_Vec2BinaryOperation": Vec2BinaryOperation,
|
||||
"CM_Vec2BinaryCondition": Vec2BinaryCondition,
|
||||
"CM_Vec2ToScalarBinaryOperation": Vec2ToScalarBinaryOperation,
|
||||
"CM_Vec2ScalarOperation": Vec2ScalarOperation,
|
||||
"CM_Vec3UnaryOperation": Vec3UnaryOperation,
|
||||
"CM_Vec3UnaryCondition": Vec3UnaryCondition,
|
||||
"CM_Vec3ToScalarUnaryOperation": Vec3ToScalarUnaryOperation,
|
||||
"CM_Vec3BinaryOperation": Vec3BinaryOperation,
|
||||
"CM_Vec3BinaryCondition": Vec3BinaryCondition,
|
||||
"CM_Vec3ToScalarBinaryOperation": Vec3ToScalarBinaryOperation,
|
||||
"CM_Vec3ScalarOperation": Vec3ScalarOperation,
|
||||
"CM_Vec4UnaryOperation": Vec4UnaryOperation,
|
||||
"CM_Vec4UnaryCondition": Vec4UnaryCondition,
|
||||
"CM_Vec4ToScalarUnaryOperation": Vec4ToScalarUnaryOperation,
|
||||
"CM_Vec4BinaryOperation": Vec4BinaryOperation,
|
||||
"CM_Vec4BinaryCondition": Vec4BinaryCondition,
|
||||
"CM_Vec4ToScalarBinaryOperation": Vec4ToScalarBinaryOperation,
|
||||
"CM_Vec4ScalarOperation": Vec4ScalarOperation,
|
||||
}
|
||||
Reference in New Issue
Block a user