From ecbd0eab09a5ba646257fe9db2a69e846cdbe196 Mon Sep 17 00:00:00 2001 From: Dogukan Karatas Date: Fri, 13 Dec 2024 15:34:10 +0100 Subject: [PATCH 1/5] adds qgis essentials --- src/specklepy/objects/geometry.py | 182 +++++++++++++++++- src/specklepy/objects/instances.py | 28 +++ src/specklepy/objects/interfaces.py | 45 ++++- src/specklepy/objects/primitive.py | 6 +- src/specklepy/objects/proxies.py | 25 +++ .../{v3_test.py => tests/line_test.py} | 24 +-- src/specklepy/objects/tests/mesh_test.py | 96 +++++++++ src/specklepy/objects/tests/point_test.py | 20 ++ src/specklepy/objects/tests/polyline_test.py | 61 ++++++ 9 files changed, 453 insertions(+), 34 deletions(-) create mode 100644 src/specklepy/objects/instances.py create mode 100644 src/specklepy/objects/proxies.py rename src/specklepy/objects/{v3_test.py => tests/line_test.py} (56%) create mode 100644 src/specklepy/objects/tests/mesh_test.py create mode 100644 src/specklepy/objects/tests/point_test.py create mode 100644 src/specklepy/objects/tests/polyline_test.py diff --git a/src/specklepy/objects/geometry.py b/src/specklepy/objects/geometry.py index 4767d4e..8497342 100644 --- a/src/specklepy/objects/geometry.py +++ b/src/specklepy/objects/geometry.py @@ -1,8 +1,7 @@ from dataclasses import dataclass, field -from typing import List - +from typing import List, Tuple from specklepy.objects.base import Base -from specklepy.objects.interfaces import ICurve, IHasUnits +from specklepy.objects.interfaces import ICurve, IHasArea, IHasUnits, IHasVolume from specklepy.objects.models.units import Units from specklepy.objects.primitive import Interval @@ -72,7 +71,8 @@ def to_list(self) -> List[float]: @classmethod def from_list(cls, coords: List[float], units: str) -> "Line": if len(coords) < 6: - raise ValueError("Line from coordinate array requires 6 coordinates.") + raise ValueError( + "Line from coordinate array requires 6 coordinates.") start = Point(x=coords[0], y=coords[1], z=coords[2], units=units) end = Point(x=coords[3], y=coords[4], z=coords[5], units=units) @@ -93,3 +93,177 @@ def from_coords( start = Point(x=start_x, y=start_y, z=start_z, units=units) end = Point(x=end_x, y=end_y, z=end_z, units=units) return cls(start=start, end=end, units=units) + + +@dataclass(kw_only=True) +class Polyline(Base, IHasUnits, ICurve, speckle_type="Objects.Geometry.Polyline"): + """ + a polyline curve, defined by a set of vertices. + """ + + value: List[float] = field(default_factory=list) + closed: bool = False + domain: Interval = field(default_factory=Interval.unit_interval) + + @property + def length(self) -> float: + points = self.get_points() + total_length = 0.0 + for i in range(len(points) - 1): + total_length += points[i].distance_to(points[i + 1]) + if self.closed and points: + total_length += points[-1].distance_to(points[0]) + return total_length + + @property + def _domain(self) -> Interval: + """ + internal domain property for ICurve interface + """ + return self.domain + + def get_points(self) -> List[Point]: + """ + converts the raw coordinate list into Point objects + """ + if len(self.value) % 3 != 0: + raise ValueError( + "Polyline value list is malformed: expected length to be multiple of 3") + + points = [] + for i in range(0, len(self.value), 3): + points.append( + Point( + x=self.value[i], + y=self.value[i + 1], + z=self.value[i + 2], + units=self.units + ) + ) + return points + + def to_list(self) -> List[float]: + """ + returns the values of this Polyline as a list of numbers + """ + result = [] + result.append(len(self.value) + 6) # total list length + # type indicator for polyline ?? not sure about this + result.append("Objects.Geometry.Polyline") + result.append(1 if self.closed else 0) + result.append(self.domain.start) + result.append(self.domain.end) + result.append(len(self.value)) + result.extend(self.value) + result.append(Units.get_encoding_from_unit(self.units)) + return result + + @classmethod + def from_list(cls, coords: List[float], units: str | Units) -> "Polyline": + """ + creates a new Polyline based on a list of coordinates + """ + point_count = int(coords[5]) + return cls( + closed=(int(coords[2]) == 1), + domain=Interval(start=coords[3], end=coords[4]), + value=coords[6:6 + point_count], + units=units + ) + + +@dataclass(kw_only=True) +class Mesh(Base, IHasArea, IHasVolume, IHasUnits, + speckle_type="Objects.Geometry.Mesh", + detachable={"vertices", "faces", "colors", "textureCoordinates"}, + chunkable={"vertices": 31250, "faces": 62500, "colors": 62500, "textureCoordinates": 31250}): + + vertices: List[float] = field(default_factory=list) + faces: List[int] = field(default_factory=list) + colors: List[int] = field(default_factory=list) + textureCoordinates: List[float] = field(default_factory=list) + + @property + def vertices_count(self) -> int: + return len(self.vertices) // 3 + + @property + def texture_coordinates_count(self) -> int: + return len(self.textureCoordinates) // 2 + + def get_point(self, index: int) -> Point: + + index *= 3 + return Point( + x=self.vertices[index], + y=self.vertices[index + 1], + z=self.vertices[index + 2], + units=self.units + ) + + def get_points(self) -> List[Point]: + + if len(self.vertices) % 3 != 0: + raise ValueError( + "Mesh vertices list is malformed: expected length to be multiple of 3" + ) + + points = [] + for i in range(0, len(self.vertices), 3): + points.append( + Point( + x=self.vertices[i], + y=self.vertices[i + 1], + z=self.vertices[i + 2], + units=self.units + ) + ) + return points + + def get_texture_coordinate(self, index: int) -> Tuple[float, float]: + + index *= 2 + return ( + self.textureCoordinates[index], + self.textureCoordinates[index + 1] + ) + + def align_vertices_with_texcoords_by_index(self) -> None: + + if not self.textureCoordinates: + return + + if self.texture_coordinates_count == self.vertices_count: + return + + faces_unique = [] + vertices_unique = [] + has_colors = len(self.colors) > 0 + colors_unique = [] if has_colors else None + + n_index = 0 + while n_index < len(self.faces): + n = self.faces[n_index] + if n < 3: + n += 3 + + if n_index + n >= len(self.faces): + break + + faces_unique.append(n) + for i in range(1, n + 1): + vert_index = self.faces[n_index + i] + new_vert_index = len(vertices_unique) // 3 + + point = self.get_point(vert_index) + vertices_unique.extend([point.x, point.y, point.z]) + + if colors_unique is not None: + colors_unique.append(self.colors[vert_index]) + faces_unique.append(new_vert_index) + + n_index += n + 1 + + self.vertices = vertices_unique + self.colors = colors_unique if colors_unique is not None else self.colors + self.faces = faces_unique diff --git a/src/specklepy/objects/instances.py b/src/specklepy/objects/instances.py new file mode 100644 index 0000000..6ec056e --- /dev/null +++ b/src/specklepy/objects/instances.py @@ -0,0 +1,28 @@ +from dataclasses import dataclass, field +from typing import List +from specklepy.objects.base import Base +from specklepy.objects.interfaces import IHasUnits + + +@dataclass(kw_only=True) +class InstanceProxy( + Base, + IHasUnits, + speckle_type="Models.Instances.InstanceProxy", +): + + definition_id: str + transform: List[float] = field(default_factory=list) + max_depth: int = 50 + + +@dataclass(kw_only=True) +class InstanceDefinitionProxy( + Base, + speckle_type="Models.Instances.InstanceDefinitionProxy", + detachable={"objects"}, +): + + objects: List[str] = field(default_factory=list) + max_depth: int = 50 + name: str = field(default="Unnamed Instance") diff --git a/src/specklepy/objects/interfaces.py b/src/specklepy/objects/interfaces.py index 28f6f40..843b061 100644 --- a/src/specklepy/objects/interfaces.py +++ b/src/specklepy/objects/interfaces.py @@ -1,7 +1,6 @@ from abc import ABCMeta, abstractmethod from dataclasses import dataclass, field -from typing import Generic, TypeVar - +from typing import Generic, TypeVar, List from specklepy.logging.exceptions import SpeckleInvalidUnitException from specklepy.objects.base import Base from specklepy.objects.models.units import Units @@ -37,22 +36,16 @@ def display_value(self) -> T: @dataclass(kw_only=True) class IHasUnits(metaclass=ABCMeta): - """Interface for objects that have units.""" units: str | Units _units: str = field(repr=False, init=False) @property def units(self) -> str: - """Get the units of the object""" return self._units @units.setter def units(self, value: str | Units): - """ - While this property accepts any string value, geometry expects units - to be specific strings (see Units enum) - """ if isinstance(value, str): self._units = value elif isinstance(value, Units): @@ -63,6 +56,40 @@ def units(self, value: str | Units): ) +@dataclass(kw_only=True) +class IHasArea(metaclass=ABCMeta): + + area: float + _area: float = field(init=False, repr=False) + + @property + def area(self) -> float: + return self._area + + @area.setter + def area(self, value: float): + if not isinstance(value, (int, float)): + raise ValueError(f"Area must be a number, got {type(value)}") + self._area = float(value) + + +@dataclass(kw_only=True) +class IHasVolume(metaclass=ABCMeta): + + volume: float + _volume: float = field(init=False, repr=False) + + @property + def volume(self) -> float: + return self._volume + + @volume.setter + def volume(self, value: float): + if not isinstance(value, (int, float)): + raise ValueError(f"Volume must be a number, got {type(value)}") + self._volume = float(value) + + # data object interfaces class IProperties(metaclass=ABCMeta): @property @@ -71,7 +98,7 @@ def properties(self) -> dict[str, object]: pass -class IDataObject(IProperties, IDisplayValue[list[Base]], metaclass=ABCMeta): +class IDataObject(IProperties, IDisplayValue[List[Base]], metaclass=ABCMeta): @property @abstractmethod def name(self) -> str: diff --git a/src/specklepy/objects/primitive.py b/src/specklepy/objects/primitive.py index 267401e..689a656 100644 --- a/src/specklepy/objects/primitive.py +++ b/src/specklepy/objects/primitive.py @@ -1,5 +1,5 @@ from dataclasses import dataclass - +from typing import List from specklepy.objects.base import Base @@ -19,9 +19,9 @@ def __str__(self) -> str: def unit_interval(cls) -> "Interval": return cls(start=0, end=1) - def to_list(self) -> list[float]: + def to_list(self) -> List[float]: return [self.start, self.end] @classmethod - def from_list(cls, args: list[float]) -> "Interval": + def from_list(cls, args: List[float]) -> "Interval": return cls(start=args[0], end=args[1]) diff --git a/src/specklepy/objects/proxies.py b/src/specklepy/objects/proxies.py new file mode 100644 index 0000000..e59e349 --- /dev/null +++ b/src/specklepy/objects/proxies.py @@ -0,0 +1,25 @@ +from dataclasses import dataclass, field +from typing import List, Optional +from specklepy.objects.base import Base + + +@dataclass(kw_only=True) +class ColorProxy( + Base, + speckle_type="Models.Proxies.ColorProxy", + detachable={"objects"}, +): + objects: List[str] = field(default_factory=list) + value: int + name: Optional[str] = None + + +@dataclass(kw_only=True) +class GroupProxy( + Base, + speckle_type="Models.Proxies.GroupProxy", + detachable={"objects"}, +): + + objects: List[str] = field(default_factory=list) + name: str = field(default="Unnamed Group") diff --git a/src/specklepy/objects/v3_test.py b/src/specklepy/objects/tests/line_test.py similarity index 56% rename from src/specklepy/objects/v3_test.py rename to src/specklepy/objects/tests/line_test.py index 264b6b9..fec552f 100644 --- a/src/specklepy/objects/v3_test.py +++ b/src/specklepy/objects/tests/line_test.py @@ -1,32 +1,20 @@ from devtools import debug - from specklepy.api.operations import deserialize, serialize from specklepy.objects.geometry import Line, Point from specklepy.objects.models.units import Units from specklepy.objects.primitive import Interval -# test points + +# points p1 = Point(x=1.0, y=2.0, z=3.0, units=Units.m) p2 = Point(x=4.0, y=6.0, z=8.0, units=Units.m, applicationId="asdf") -p3 = Point(units="m", x=0, y=0, z=0) - -print("Distance between points:", p1.distance_to(p2)) - -ser_p1 = serialize(p1) -p1_again = deserialize(ser_p1) - -print("\nOriginal point:") -debug(p1) -print("\nSerialized point:") -debug(ser_p1) -print("\nDeserialized point:") -debug(p1_again) -# # test Line -line = Line(start=p1, end=p2, units=Units.m, domain=Interval(start=0.0, end=1.0)) +# test Line +line = Line(start=p1, end=p2, units=Units.m, + domain=Interval(start=0.0, end=1.0)) -# print(f"\nLine length: {line.length}") +print(f"\nLine length: {line.length}") ser_line = serialize(line) line_again = deserialize(ser_line) diff --git a/src/specklepy/objects/tests/mesh_test.py b/src/specklepy/objects/tests/mesh_test.py new file mode 100644 index 0000000..38b8d71 --- /dev/null +++ b/src/specklepy/objects/tests/mesh_test.py @@ -0,0 +1,96 @@ +from devtools import debug +from specklepy.api.operations import deserialize, serialize +from specklepy.objects.geometry import Mesh + + +# create a speckle cube mesh (but more colorful) +vertices = [ + 0.0, 0.0, 0.0, + 1.0, 0.0, 0.0, + 1.0, 1.0, 0.0, + 0.0, 1.0, 0.0, + 0.0, 0.0, 1.0, + 1.0, 0.0, 1.0, + 1.0, 1.0, 1.0, + 0.0, 1.0, 1.0 +] + +# define faces (triangles) +faces = [ + 3, 0, 1, 2, + 3, 0, 2, 3, + 3, 4, 5, 6, + 3, 4, 6, 7, + 3, 0, 4, 7, + 3, 0, 7, 3, + 3, 1, 5, 6, + 3, 1, 6, 2, + 3, 3, 2, 6, + 3, 3, 6, 7, + 3, 0, 1, 5, + 3, 0, 5, 4 +] + +# create colors (one per vertex) +colors = [ + 255, 0, 0, 255, + 0, 255, 0, 255, + 0, 0, 255, 255, + 255, 255, 0, 255, + 255, 0, 255, 255, + 0, 255, 255, 255, + 255, 255, 255, 255, + 0, 0, 0, 255 +] + +texture_coordinates = [ + 0.0, 0.0, + 1.0, 0.0, + 1.0, 1.0, + 0.0, 1.0, + 0.0, 0.0, + 1.0, 0.0, + 1.0, 1.0, + 0.0, 1.0 +] + +# create the mesh +cube_mesh = Mesh( + vertices=vertices, + faces=faces, + colors=colors, + textureCoordinates=texture_coordinates, + units="mm", + area=0.0, + volume=0.0) + +print(f"\nMesh Details:") +print(f"Number of vertices: {cube_mesh.vertices_count}") +print(f"Number of texture coordinates: {cube_mesh.texture_coordinates_count}") + +print("\nSome vertex points:") +for i in range(4): + point = cube_mesh.get_point(i) + print(f"Vertex {i}: ({point.x}, {point.y}, {point.z})") + +print("\nSome texture coordinates:") +for i in range(4): + u, v = cube_mesh.get_texture_coordinate(i) + print(f"Texture coordinate {i}: ({u}, {v})") + +print("\nTesting serialization...") +ser_mesh = serialize(cube_mesh) +mesh_again = deserialize(ser_mesh) + +print("\nOriginal mesh:") +debug(cube_mesh) +print("\nDeserialized mesh:") +debug(mesh_again) + +print("\nTesting vertex-texture coordinate alignment...") +cube_mesh.align_vertices_with_texcoords_by_index() +print("Alignment complete.") + +print(f"Vertices count after alignment: {cube_mesh.vertices_count}") +print(f"Texture coordinates count after alignment: { + cube_mesh.texture_coordinates_count}") diff --git a/src/specklepy/objects/tests/point_test.py b/src/specklepy/objects/tests/point_test.py new file mode 100644 index 0000000..a8892ae --- /dev/null +++ b/src/specklepy/objects/tests/point_test.py @@ -0,0 +1,20 @@ +from devtools import debug +from specklepy.api.operations import deserialize, serialize +from specklepy.objects.geometry import Point +from specklepy.objects.models.units import Units + +# test points +p1 = Point(x=1.0, y=2.0, z=3.0, units=Units.m) +p2 = Point(x=4.0, y=6.0, z=8.0, units=Units.m, applicationId="asdf") + +print("Distance between points:", p1.distance_to(p2)) + +ser_p1 = serialize(p1) +p1_again = deserialize(ser_p1) + +print("\nOriginal point:") +debug(p1) +print("\nSerialized point:") +debug(ser_p1) +print("\nDeserialized point:") +debug(p1_again) diff --git a/src/specklepy/objects/tests/polyline_test.py b/src/specklepy/objects/tests/polyline_test.py new file mode 100644 index 0000000..0667736 --- /dev/null +++ b/src/specklepy/objects/tests/polyline_test.py @@ -0,0 +1,61 @@ +from devtools import debug +from specklepy.api.operations import deserialize, serialize +from specklepy.objects.geometry import Polyline +from specklepy.objects.models.units import Units +from specklepy.objects.primitive import Interval + + +# create points for first polyline - not closed, in meters +points1_coords = [ + 1.0, 1.0, 0.0, + 2.0, 1.0, 0.0, + 2.0, 2.0, 0.0, + 1.0, 2.0, 0.0 +] + +# Create points for second polyline - closed, in ft +points2_coords = [ + 0.0, 0.0, 0.0, + 3.0, 0.0, 0.0, + 3.0, 3.0, 0.0, + 0.0, 3.0, 0.0 +] + +# create polylines +polyline1 = Polyline( + value=points1_coords, + closed=False, + units=Units.m, + domain=Interval(start=0.0, end=1.0) +) + +polyline2 = Polyline( + value=points2_coords, + closed=True, + units=Units.feet, + domain=Interval(start=0.0, end=1.0), + applicationId="polyllllineeee" +) + +print("Polyline 1 length (meters):", polyline1.length) +print("Polyline 2 length (feet):", polyline2.length) + +ser_poly1 = serialize(polyline1) +poly1_again = deserialize(ser_poly1) + +print("\nOriginal polyline 1:") +debug(polyline1) +print("\nSerialized polyline 1:") +debug(ser_poly1) +print("\nDeserialized polyline 1:") +debug(poly1_again) + +ser_poly2 = serialize(polyline2) +poly2_again = deserialize(ser_poly2) + +print("\nOriginal polyline 2:") +debug(polyline2) +print("\nSerialized polyline 2:") +debug(ser_poly2) +print("\nDeserialized polyline 2:") +debug(poly2_again) From edce76491f90e3ea038290a6303a0ff60efff708 Mon Sep 17 00:00:00 2001 From: Dogukan Karatas Date: Fri, 13 Dec 2024 15:44:56 +0100 Subject: [PATCH 2/5] moves intances under proxies --- src/specklepy/objects/instances.py | 28 ---------------------------- src/specklepy/objects/proxies.py | 25 +++++++++++++++++++++++++ 2 files changed, 25 insertions(+), 28 deletions(-) delete mode 100644 src/specklepy/objects/instances.py diff --git a/src/specklepy/objects/instances.py b/src/specklepy/objects/instances.py deleted file mode 100644 index 6ec056e..0000000 --- a/src/specklepy/objects/instances.py +++ /dev/null @@ -1,28 +0,0 @@ -from dataclasses import dataclass, field -from typing import List -from specklepy.objects.base import Base -from specklepy.objects.interfaces import IHasUnits - - -@dataclass(kw_only=True) -class InstanceProxy( - Base, - IHasUnits, - speckle_type="Models.Instances.InstanceProxy", -): - - definition_id: str - transform: List[float] = field(default_factory=list) - max_depth: int = 50 - - -@dataclass(kw_only=True) -class InstanceDefinitionProxy( - Base, - speckle_type="Models.Instances.InstanceDefinitionProxy", - detachable={"objects"}, -): - - objects: List[str] = field(default_factory=list) - max_depth: int = 50 - name: str = field(default="Unnamed Instance") diff --git a/src/specklepy/objects/proxies.py b/src/specklepy/objects/proxies.py index e59e349..b98dc7e 100644 --- a/src/specklepy/objects/proxies.py +++ b/src/specklepy/objects/proxies.py @@ -1,6 +1,7 @@ from dataclasses import dataclass, field from typing import List, Optional from specklepy.objects.base import Base +from specklepy.objects.interfaces import IHasUnits @dataclass(kw_only=True) @@ -23,3 +24,27 @@ class GroupProxy( objects: List[str] = field(default_factory=list) name: str = field(default="Unnamed Group") + + +@dataclass(kw_only=True) +class InstanceProxy( + Base, + IHasUnits, + speckle_type="Models.Proxies.InstanceProxy", +): + + definition_id: str + transform: List[float] = field(default_factory=list) + max_depth: int = 50 + + +@dataclass(kw_only=True) +class InstanceDefinitionProxy( + Base, + speckle_type="Models.Proxies.InstanceDefinitionProxy", + detachable={"objects"}, +): + + objects: List[str] = field(default_factory=list) + max_depth: int = 50 + name: str = field(default="Unnamed Instance") From 2e44a891e8cb697a2e2233cbca4ed7f36e5eb40f Mon Sep 17 00:00:00 2001 From: KatKatKateryna Date: Sun, 15 Dec 2024 17:06:06 +0000 Subject: [PATCH 3/5] formatting to pass tests --- src/speckle_automate/runner.py | 12 +++-- .../resources/current/active_user_resource.py | 6 ++- .../resources/current/active_user_resource.py | 6 ++- src/specklepy/objects/geometry.py | 45 ++++++++++--------- src/specklepy/objects/interfaces.py | 6 +-- src/specklepy/objects/primitive.py | 1 + src/specklepy/objects/proxies.py | 4 +- src/specklepy/objects/tests/line_test.py | 5 +-- src/specklepy/objects/tests/mesh_test.py | 4 +- src/specklepy/objects/tests/point_test.py | 1 + src/specklepy/objects/tests/polyline_test.py | 20 +++------ src/specklepy/objects_v2/other.py | 6 +-- 12 files changed, 57 insertions(+), 59 deletions(-) diff --git a/src/speckle_automate/runner.py b/src/speckle_automate/runner.py index dcac239..71a27aa 100644 --- a/src/speckle_automate/runner.py +++ b/src/speckle_automate/runner.py @@ -61,13 +61,15 @@ class FunctionRunData(AutomateBase): def execute_automate_function( automate_function: AutomateFunction[T], input_schema: type[T], -) -> None: ... +) -> None: + ... @overload def execute_automate_function( automate_function: AutomateFunctionWithoutInputs, -) -> None: ... +) -> None: + ... class AutomateGenerateJsonSchema(GenerateJsonSchema): @@ -144,14 +146,16 @@ def run_function( automation_context: AutomationContext, automate_function: AutomateFunction[T], inputs: T, -) -> AutomationContext: ... +) -> AutomationContext: + ... @overload def run_function( automation_context: AutomationContext, automate_function: AutomateFunctionWithoutInputs, -) -> AutomationContext: ... +) -> AutomationContext: + ... def run_function( diff --git a/src/specklepy/api/resources/current/active_user_resource.py b/src/specklepy/api/resources/current/active_user_resource.py index ed16eb0..1240808 100644 --- a/src/specklepy/api/resources/current/active_user_resource.py +++ b/src/specklepy/api/resources/current/active_user_resource.py @@ -43,10 +43,12 @@ def update( company: Optional[str] = None, bio: Optional[str] = None, avatar: Optional[str] = None, - ) -> User: ... + ) -> User: + ... @overload - def update(self, *, input: UserUpdateInput) -> User: ... + def update(self, *, input: UserUpdateInput) -> User: + ... def update( self, diff --git a/src/specklepy/core/api/resources/current/active_user_resource.py b/src/specklepy/core/api/resources/current/active_user_resource.py index e7ce1e8..37ebdae 100644 --- a/src/specklepy/core/api/resources/current/active_user_resource.py +++ b/src/specklepy/core/api/resources/current/active_user_resource.py @@ -99,10 +99,12 @@ def update( company: Optional[str] = None, bio: Optional[str] = None, avatar: Optional[str] = None, - ) -> User: ... + ) -> User: + ... @overload - def update(self, *, input: UserUpdateInput) -> User: ... + def update(self, *, input: UserUpdateInput) -> User: + ... def update( self, diff --git a/src/specklepy/objects/geometry.py b/src/specklepy/objects/geometry.py index 8497342..09a0214 100644 --- a/src/specklepy/objects/geometry.py +++ b/src/specklepy/objects/geometry.py @@ -1,5 +1,6 @@ from dataclasses import dataclass, field from typing import List, Tuple + from specklepy.objects.base import Base from specklepy.objects.interfaces import ICurve, IHasArea, IHasUnits, IHasVolume from specklepy.objects.models.units import Units @@ -71,8 +72,7 @@ def to_list(self) -> List[float]: @classmethod def from_list(cls, coords: List[float], units: str) -> "Line": if len(coords) < 6: - raise ValueError( - "Line from coordinate array requires 6 coordinates.") + raise ValueError("Line from coordinate array requires 6 coordinates.") start = Point(x=coords[0], y=coords[1], z=coords[2], units=units) end = Point(x=coords[3], y=coords[4], z=coords[5], units=units) @@ -128,7 +128,8 @@ def get_points(self) -> List[Point]: """ if len(self.value) % 3 != 0: raise ValueError( - "Polyline value list is malformed: expected length to be multiple of 3") + "Polyline value list is malformed: expected length to be multiple of 3" + ) points = [] for i in range(0, len(self.value), 3): @@ -137,7 +138,7 @@ def get_points(self) -> List[Point]: x=self.value[i], y=self.value[i + 1], z=self.value[i + 2], - units=self.units + units=self.units, ) ) return points @@ -167,17 +168,26 @@ def from_list(cls, coords: List[float], units: str | Units) -> "Polyline": return cls( closed=(int(coords[2]) == 1), domain=Interval(start=coords[3], end=coords[4]), - value=coords[6:6 + point_count], - units=units + value=coords[6 : 6 + point_count], + units=units, ) @dataclass(kw_only=True) -class Mesh(Base, IHasArea, IHasVolume, IHasUnits, - speckle_type="Objects.Geometry.Mesh", - detachable={"vertices", "faces", "colors", "textureCoordinates"}, - chunkable={"vertices": 31250, "faces": 62500, "colors": 62500, "textureCoordinates": 31250}): - +class Mesh( + Base, + IHasArea, + IHasVolume, + IHasUnits, + speckle_type="Objects.Geometry.Mesh", + detachable={"vertices", "faces", "colors", "textureCoordinates"}, + chunkable={ + "vertices": 31250, + "faces": 62500, + "colors": 62500, + "textureCoordinates": 31250, + }, +): vertices: List[float] = field(default_factory=list) faces: List[int] = field(default_factory=list) colors: List[int] = field(default_factory=list) @@ -192,17 +202,15 @@ def texture_coordinates_count(self) -> int: return len(self.textureCoordinates) // 2 def get_point(self, index: int) -> Point: - index *= 3 return Point( x=self.vertices[index], y=self.vertices[index + 1], z=self.vertices[index + 2], - units=self.units + units=self.units, ) def get_points(self) -> List[Point]: - if len(self.vertices) % 3 != 0: raise ValueError( "Mesh vertices list is malformed: expected length to be multiple of 3" @@ -215,21 +223,16 @@ def get_points(self) -> List[Point]: x=self.vertices[i], y=self.vertices[i + 1], z=self.vertices[i + 2], - units=self.units + units=self.units, ) ) return points def get_texture_coordinate(self, index: int) -> Tuple[float, float]: - index *= 2 - return ( - self.textureCoordinates[index], - self.textureCoordinates[index + 1] - ) + return (self.textureCoordinates[index], self.textureCoordinates[index + 1]) def align_vertices_with_texcoords_by_index(self) -> None: - if not self.textureCoordinates: return diff --git a/src/specklepy/objects/interfaces.py b/src/specklepy/objects/interfaces.py index 843b061..ad91a7c 100644 --- a/src/specklepy/objects/interfaces.py +++ b/src/specklepy/objects/interfaces.py @@ -1,6 +1,7 @@ from abc import ABCMeta, abstractmethod from dataclasses import dataclass, field -from typing import Generic, TypeVar, List +from typing import Generic, List, TypeVar + from specklepy.logging.exceptions import SpeckleInvalidUnitException from specklepy.objects.base import Base from specklepy.objects.models.units import Units @@ -36,7 +37,6 @@ def display_value(self) -> T: @dataclass(kw_only=True) class IHasUnits(metaclass=ABCMeta): - units: str | Units _units: str = field(repr=False, init=False) @@ -58,7 +58,6 @@ def units(self, value: str | Units): @dataclass(kw_only=True) class IHasArea(metaclass=ABCMeta): - area: float _area: float = field(init=False, repr=False) @@ -75,7 +74,6 @@ def area(self, value: float): @dataclass(kw_only=True) class IHasVolume(metaclass=ABCMeta): - volume: float _volume: float = field(init=False, repr=False) diff --git a/src/specklepy/objects/primitive.py b/src/specklepy/objects/primitive.py index 689a656..1fcd87d 100644 --- a/src/specklepy/objects/primitive.py +++ b/src/specklepy/objects/primitive.py @@ -1,5 +1,6 @@ from dataclasses import dataclass from typing import List + from specklepy.objects.base import Base diff --git a/src/specklepy/objects/proxies.py b/src/specklepy/objects/proxies.py index b98dc7e..0defdee 100644 --- a/src/specklepy/objects/proxies.py +++ b/src/specklepy/objects/proxies.py @@ -1,5 +1,6 @@ from dataclasses import dataclass, field from typing import List, Optional + from specklepy.objects.base import Base from specklepy.objects.interfaces import IHasUnits @@ -21,7 +22,6 @@ class GroupProxy( speckle_type="Models.Proxies.GroupProxy", detachable={"objects"}, ): - objects: List[str] = field(default_factory=list) name: str = field(default="Unnamed Group") @@ -32,7 +32,6 @@ class InstanceProxy( IHasUnits, speckle_type="Models.Proxies.InstanceProxy", ): - definition_id: str transform: List[float] = field(default_factory=list) max_depth: int = 50 @@ -44,7 +43,6 @@ class InstanceDefinitionProxy( speckle_type="Models.Proxies.InstanceDefinitionProxy", detachable={"objects"}, ): - objects: List[str] = field(default_factory=list) max_depth: int = 50 name: str = field(default="Unnamed Instance") diff --git a/src/specklepy/objects/tests/line_test.py b/src/specklepy/objects/tests/line_test.py index fec552f..a9db15b 100644 --- a/src/specklepy/objects/tests/line_test.py +++ b/src/specklepy/objects/tests/line_test.py @@ -1,18 +1,17 @@ from devtools import debug + from specklepy.api.operations import deserialize, serialize from specklepy.objects.geometry import Line, Point from specklepy.objects.models.units import Units from specklepy.objects.primitive import Interval - # points p1 = Point(x=1.0, y=2.0, z=3.0, units=Units.m) p2 = Point(x=4.0, y=6.0, z=8.0, units=Units.m, applicationId="asdf") # test Line -line = Line(start=p1, end=p2, units=Units.m, - domain=Interval(start=0.0, end=1.0)) +line = Line(start=p1, end=p2, units=Units.m, domain=Interval(start=0.0, end=1.0)) print(f"\nLine length: {line.length}") diff --git a/src/specklepy/objects/tests/mesh_test.py b/src/specklepy/objects/tests/mesh_test.py index 38b8d71..89fc1c1 100644 --- a/src/specklepy/objects/tests/mesh_test.py +++ b/src/specklepy/objects/tests/mesh_test.py @@ -1,8 +1,8 @@ from devtools import debug + from specklepy.api.operations import deserialize, serialize from specklepy.objects.geometry import Mesh - # create a speckle cube mesh (but more colorful) vertices = [ 0.0, 0.0, 0.0, @@ -64,7 +64,7 @@ area=0.0, volume=0.0) -print(f"\nMesh Details:") +print("\nMesh Details:") print(f"Number of vertices: {cube_mesh.vertices_count}") print(f"Number of texture coordinates: {cube_mesh.texture_coordinates_count}") diff --git a/src/specklepy/objects/tests/point_test.py b/src/specklepy/objects/tests/point_test.py index a8892ae..247ea50 100644 --- a/src/specklepy/objects/tests/point_test.py +++ b/src/specklepy/objects/tests/point_test.py @@ -1,4 +1,5 @@ from devtools import debug + from specklepy.api.operations import deserialize, serialize from specklepy.objects.geometry import Point from specklepy.objects.models.units import Units diff --git a/src/specklepy/objects/tests/polyline_test.py b/src/specklepy/objects/tests/polyline_test.py index 0667736..76367cf 100644 --- a/src/specklepy/objects/tests/polyline_test.py +++ b/src/specklepy/objects/tests/polyline_test.py @@ -1,32 +1,22 @@ from devtools import debug + from specklepy.api.operations import deserialize, serialize from specklepy.objects.geometry import Polyline from specklepy.objects.models.units import Units from specklepy.objects.primitive import Interval - # create points for first polyline - not closed, in meters -points1_coords = [ - 1.0, 1.0, 0.0, - 2.0, 1.0, 0.0, - 2.0, 2.0, 0.0, - 1.0, 2.0, 0.0 -] +points1_coords = [1.0, 1.0, 0.0, 2.0, 1.0, 0.0, 2.0, 2.0, 0.0, 1.0, 2.0, 0.0] # Create points for second polyline - closed, in ft -points2_coords = [ - 0.0, 0.0, 0.0, - 3.0, 0.0, 0.0, - 3.0, 3.0, 0.0, - 0.0, 3.0, 0.0 -] +points2_coords = [0.0, 0.0, 0.0, 3.0, 0.0, 0.0, 3.0, 3.0, 0.0, 0.0, 3.0, 0.0] # create polylines polyline1 = Polyline( value=points1_coords, closed=False, units=Units.m, - domain=Interval(start=0.0, end=1.0) + domain=Interval(start=0.0, end=1.0), ) polyline2 = Polyline( @@ -34,7 +24,7 @@ closed=True, units=Units.feet, domain=Interval(start=0.0, end=1.0), - applicationId="polyllllineeee" + applicationId="polyllllineeee", ) print("Polyline 1 length (meters):", polyline1.length) diff --git a/src/specklepy/objects_v2/other.py b/src/specklepy/objects_v2/other.py index fbf4d43..5a2576e 100644 --- a/src/specklepy/objects_v2/other.py +++ b/src/specklepy/objects_v2/other.py @@ -295,9 +295,9 @@ class RevitParameter(Base, speckle_type="Objects.BuiltElements.Revit.Parameter") value: Any = None applicationUnitType: Optional[str] = None # eg UnitType UT_Length applicationUnit: Optional[str] = None # DisplayUnitType eg DUT_MILLIMITERS - applicationInternalName: Optional[str] = ( - None # BuiltInParameterName or GUID for shared parameter - ) + applicationInternalName: Optional[ + str + ] = None # BuiltInParameterName or GUID for shared parameter isShared: bool = False isReadOnly: bool = False isTypeParameter: bool = False From d20f7ea82ae767525ab7696478aa599476886a7b Mon Sep 17 00:00:00 2001 From: KatKatKateryna Date: Sun, 15 Dec 2024 22:07:41 +0000 Subject: [PATCH 4/5] fix --- src/specklepy/objects/tests/mesh_test.py | 164 +++++++++++++++++------ 1 file changed, 125 insertions(+), 39 deletions(-) diff --git a/src/specklepy/objects/tests/mesh_test.py b/src/specklepy/objects/tests/mesh_test.py index 89fc1c1..81ab991 100644 --- a/src/specklepy/objects/tests/mesh_test.py +++ b/src/specklepy/objects/tests/mesh_test.py @@ -5,53 +5,137 @@ # create a speckle cube mesh (but more colorful) vertices = [ - 0.0, 0.0, 0.0, - 1.0, 0.0, 0.0, - 1.0, 1.0, 0.0, - 0.0, 1.0, 0.0, - 0.0, 0.0, 1.0, - 1.0, 0.0, 1.0, - 1.0, 1.0, 1.0, - 0.0, 1.0, 1.0 + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 1.0, + 1.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 1.0, + 1.0, + 0.0, + 1.0, + 1.0, + 1.0, + 1.0, + 0.0, + 1.0, + 1.0, ] # define faces (triangles) faces = [ - 3, 0, 1, 2, - 3, 0, 2, 3, - 3, 4, 5, 6, - 3, 4, 6, 7, - 3, 0, 4, 7, - 3, 0, 7, 3, - 3, 1, 5, 6, - 3, 1, 6, 2, - 3, 3, 2, 6, - 3, 3, 6, 7, - 3, 0, 1, 5, - 3, 0, 5, 4 + 3, + 0, + 1, + 2, + 3, + 0, + 2, + 3, + 3, + 4, + 5, + 6, + 3, + 4, + 6, + 7, + 3, + 0, + 4, + 7, + 3, + 0, + 7, + 3, + 3, + 1, + 5, + 6, + 3, + 1, + 6, + 2, + 3, + 3, + 2, + 6, + 3, + 3, + 6, + 7, + 3, + 0, + 1, + 5, + 3, + 0, + 5, + 4, ] # create colors (one per vertex) colors = [ - 255, 0, 0, 255, - 0, 255, 0, 255, - 0, 0, 255, 255, - 255, 255, 0, 255, - 255, 0, 255, 255, - 0, 255, 255, 255, - 255, 255, 255, 255, - 0, 0, 0, 255 + 255, + 0, + 0, + 255, + 0, + 255, + 0, + 255, + 0, + 0, + 255, + 255, + 255, + 255, + 0, + 255, + 255, + 0, + 255, + 255, + 0, + 255, + 255, + 255, + 255, + 255, + 255, + 255, + 0, + 0, + 0, + 255, ] texture_coordinates = [ - 0.0, 0.0, - 1.0, 0.0, - 1.0, 1.0, - 0.0, 1.0, - 0.0, 0.0, - 1.0, 0.0, - 1.0, 1.0, - 0.0, 1.0 + 0.0, + 0.0, + 1.0, + 0.0, + 1.0, + 1.0, + 0.0, + 1.0, + 0.0, + 0.0, + 1.0, + 0.0, + 1.0, + 1.0, + 0.0, + 1.0, ] # create the mesh @@ -62,7 +146,8 @@ textureCoordinates=texture_coordinates, units="mm", area=0.0, - volume=0.0) + volume=0.0, +) print("\nMesh Details:") print(f"Number of vertices: {cube_mesh.vertices_count}") @@ -92,5 +177,6 @@ print("Alignment complete.") print(f"Vertices count after alignment: {cube_mesh.vertices_count}") -print(f"Texture coordinates count after alignment: { - cube_mesh.texture_coordinates_count}") +print( + f"Texture coordinates count after alignment: {cube_mesh.texture_coordinates_count}" +) From 89f4c75cc94aadd5743e09e9d78492959091e32e Mon Sep 17 00:00:00 2001 From: KatKatKateryna Date: Sun, 15 Dec 2024 22:36:08 +0000 Subject: [PATCH 5/5] formatting by save --- src/speckle_automate/runner.py | 12 ++++-------- .../api/resources/current/active_user_resource.py | 6 ++---- .../api/resources/current/active_user_resource.py | 6 ++---- src/specklepy/objects_v2/other.py | 6 +++--- 4 files changed, 11 insertions(+), 19 deletions(-) diff --git a/src/speckle_automate/runner.py b/src/speckle_automate/runner.py index 71a27aa..dcac239 100644 --- a/src/speckle_automate/runner.py +++ b/src/speckle_automate/runner.py @@ -61,15 +61,13 @@ class FunctionRunData(AutomateBase): def execute_automate_function( automate_function: AutomateFunction[T], input_schema: type[T], -) -> None: - ... +) -> None: ... @overload def execute_automate_function( automate_function: AutomateFunctionWithoutInputs, -) -> None: - ... +) -> None: ... class AutomateGenerateJsonSchema(GenerateJsonSchema): @@ -146,16 +144,14 @@ def run_function( automation_context: AutomationContext, automate_function: AutomateFunction[T], inputs: T, -) -> AutomationContext: - ... +) -> AutomationContext: ... @overload def run_function( automation_context: AutomationContext, automate_function: AutomateFunctionWithoutInputs, -) -> AutomationContext: - ... +) -> AutomationContext: ... def run_function( diff --git a/src/specklepy/api/resources/current/active_user_resource.py b/src/specklepy/api/resources/current/active_user_resource.py index 1240808..ed16eb0 100644 --- a/src/specklepy/api/resources/current/active_user_resource.py +++ b/src/specklepy/api/resources/current/active_user_resource.py @@ -43,12 +43,10 @@ def update( company: Optional[str] = None, bio: Optional[str] = None, avatar: Optional[str] = None, - ) -> User: - ... + ) -> User: ... @overload - def update(self, *, input: UserUpdateInput) -> User: - ... + def update(self, *, input: UserUpdateInput) -> User: ... def update( self, diff --git a/src/specklepy/core/api/resources/current/active_user_resource.py b/src/specklepy/core/api/resources/current/active_user_resource.py index 37ebdae..e7ce1e8 100644 --- a/src/specklepy/core/api/resources/current/active_user_resource.py +++ b/src/specklepy/core/api/resources/current/active_user_resource.py @@ -99,12 +99,10 @@ def update( company: Optional[str] = None, bio: Optional[str] = None, avatar: Optional[str] = None, - ) -> User: - ... + ) -> User: ... @overload - def update(self, *, input: UserUpdateInput) -> User: - ... + def update(self, *, input: UserUpdateInput) -> User: ... def update( self, diff --git a/src/specklepy/objects_v2/other.py b/src/specklepy/objects_v2/other.py index 5a2576e..fbf4d43 100644 --- a/src/specklepy/objects_v2/other.py +++ b/src/specklepy/objects_v2/other.py @@ -295,9 +295,9 @@ class RevitParameter(Base, speckle_type="Objects.BuiltElements.Revit.Parameter") value: Any = None applicationUnitType: Optional[str] = None # eg UnitType UT_Length applicationUnit: Optional[str] = None # DisplayUnitType eg DUT_MILLIMITERS - applicationInternalName: Optional[ - str - ] = None # BuiltInParameterName or GUID for shared parameter + applicationInternalName: Optional[str] = ( + None # BuiltInParameterName or GUID for shared parameter + ) isShared: bool = False isReadOnly: bool = False isTypeParameter: bool = False