Skip to content

Commit 314801b

Browse files
authored
Merge branch 'blitz' into feat/run-script-core-service
2 parents 68d9e24 + 9389ba5 commit 314801b

File tree

12 files changed

+311
-467
lines changed

12 files changed

+311
-467
lines changed

.github/workflows/ci_cd.yml

Lines changed: 42 additions & 457 deletions
Large diffs are not rendered by default.

doc/changelog.d/1806.added.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
matrix helper methods

doc/changelog.d/1808.fixed.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
translating sketch issues when using a custom default unit

doc/changelog.d/1816.fixed.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
edge start and end were not being mapped correctly

src/ansys/geometry/core/designer/edge.py

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -128,8 +128,13 @@ def shape(self) -> TrimmedCurve:
128128
geometry = grpc_curve_to_curve(response)
129129

130130
response = self._edges_stub.GetStartAndEndPoints(self._grpc_id)
131-
start = Point3D([response.start.x, response.start.y, response.start.z])
132-
end = Point3D([response.end.x, response.end.y, response.end.z])
131+
start = Point3D(
132+
[response.start.x, response.start.y, response.start.z],
133+
unit=DEFAULT_UNITS.SERVER_LENGTH,
134+
)
135+
end = Point3D(
136+
[response.end.x, response.end.y, response.end.z], unit=DEFAULT_UNITS.SERVER_LENGTH
137+
)
133138

134139
response = self._edges_stub.GetLength(self._grpc_id)
135140
length = Quantity(response.length, DEFAULT_UNITS.SERVER_LENGTH)
@@ -193,7 +198,10 @@ def start(self) -> Point3D:
193198
# Only for versions earlier than 24.2.0 (before the introduction of the shape property)
194199
self._grpc_client.log.debug("Requesting edge start point from server.")
195200
response = self._edges_stub.GetStartAndEndPoints(self._grpc_id)
196-
return Point3D([response.start.x, response.start.y, response.start.z])
201+
return Point3D(
202+
[response.start.x, response.start.y, response.start.z],
203+
unit=DEFAULT_UNITS.SERVER_LENGTH,
204+
)
197205

198206
@property
199207
@protect_grpc

src/ansys/geometry/core/designer/face.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -554,8 +554,8 @@ def create_isoparametric_curves(
554554
trimmed_curves = []
555555
for c in curves:
556556
geometry = grpc_curve_to_curve(c.curve)
557-
start = Point3D([c.start.x, c.start.y, c.start.z])
558-
end = Point3D([c.end.x, c.end.y, c.end.z])
557+
start = Point3D([c.start.x, c.start.y, c.start.z], unit=DEFAULT_UNITS.SERVER_LENGTH)
558+
end = Point3D([c.end.x, c.end.y, c.end.z], unit=DEFAULT_UNITS.SERVER_LENGTH)
559559
interval = Interval(c.interval_start, c.interval_end)
560560
length = Quantity(c.length, DEFAULT_UNITS.SERVER_LENGTH)
561561

src/ansys/geometry/core/math/matrix.py

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
from ansys.geometry.core.typing import Real, RealSequence
3131

3232
if TYPE_CHECKING:
33+
from ansys.geometry.core.math.frame import Frame
3334
from ansys.geometry.core.math.vector import Vector3D # For type hints
3435

3536
DEFAULT_MATRIX33 = np.identity(3)
@@ -308,3 +309,61 @@ def create_rotation(
308309
]
309310
)
310311
return matrix
312+
313+
@classmethod
314+
def create_matrix_from_rotation_about_axis(cls, axis: "Vector3D", angle: float) -> "Matrix44":
315+
"""
316+
Create a matrix representing a rotation about a given axis.
317+
318+
Parameters
319+
----------
320+
axis : Vector3D
321+
The axis of rotation.
322+
angle : float
323+
The angle of rotation in radians.
324+
325+
Returns
326+
-------
327+
Matrix44
328+
A 4x4 matrix representing the rotation.
329+
"""
330+
axis_dir = axis.normalize()
331+
x, y, z = axis_dir[0], axis_dir[1], axis_dir[2]
332+
333+
k = np.array([[0, -z, y], [z, 0, -x], [-y, x, 0]])
334+
335+
identity = np.eye(3)
336+
cos_theta = np.cos(angle)
337+
sin_theta = np.sin(angle)
338+
339+
# Rodrigues' rotation formula
340+
rotation_3x3 = identity + sin_theta * k + (1 - cos_theta) * (k @ k)
341+
342+
# Convert to a 4x4 homogeneous matrix
343+
rotation_matrix = np.eye(4)
344+
rotation_matrix[:3, :3] = rotation_3x3
345+
346+
return cls(rotation_matrix)
347+
348+
@classmethod
349+
def create_matrix_from_mapping(cls, frame: "Frame") -> "Matrix44":
350+
"""
351+
Create a matrix representing the specified mapping.
352+
353+
Parameters
354+
----------
355+
frame : Frame
356+
The frame containing the origin and direction vectors.
357+
358+
Returns
359+
-------
360+
Matrix44
361+
A 4x4 matrix representing the translation and rotation defined by the frame.
362+
"""
363+
from ansys.geometry.core.math.vector import Vector3D
364+
365+
translation_matrix = Matrix44.create_translation(
366+
Vector3D([frame.origin[0], frame.origin[1], frame.origin[2]])
367+
)
368+
rotation_matrix = Matrix44.create_rotation(frame.direction_x, frame.direction_y)
369+
return translation_matrix * rotation_matrix

src/ansys/geometry/core/math/vector.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
from ansys.geometry.core.math.point import Point2D, Point3D
3333
from ansys.geometry.core.misc.accuracy import Accuracy
3434
from ansys.geometry.core.misc.checks import check_ndarray_is_float_int
35+
from ansys.geometry.core.misc.measurements import Angle
3536
from ansys.geometry.core.misc.units import UNITS
3637
from ansys.geometry.core.typing import Real, RealSequence
3738

@@ -163,6 +164,22 @@ def transform(self, matrix: "Matrix44") -> "Vector3D":
163164
result_vector = Vector3D(result_4x1[0:3])
164165
return result_vector
165166

167+
@check_input_types
168+
def rotate_vector(self, vector: "Vector3D", angle: Real | Quantity | Angle) -> "Vector3D":
169+
"""Rotate a vector around a given axis by a specified angle."""
170+
if self.is_zero:
171+
raise Exception("Invalid vector operation: rotation axis cannot be zero.")
172+
173+
# Convert angle to Angle object and get its value in radians
174+
angle = angle if isinstance(angle, Angle) else Angle(angle)
175+
angle_m = angle.value.m_as(UNITS.radian)
176+
177+
axis = self.normalize()
178+
parallel = axis * (vector.dot(axis))
179+
perpendicular1 = vector - parallel
180+
perpendicular2 = axis.cross(perpendicular1)
181+
return parallel + perpendicular1 * np.cos(angle_m) + perpendicular2 * np.sin(angle_m)
182+
166183
@check_input_types
167184
def get_angle_between(self, v: "Vector3D") -> Quantity:
168185
"""Get the angle between this 3D vector and another 3D vector.

src/ansys/geometry/core/shapes/curves/trimmed_curve.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
from ansys.geometry.core.connection.conversions import trimmed_curve_to_grpc_trimmed_curve
3030
from ansys.geometry.core.errors import protect_grpc
3131
from ansys.geometry.core.math.point import Point3D
32+
from ansys.geometry.core.misc.measurements import DEFAULT_UNITS
3233
from ansys.geometry.core.shapes.curves.curve import Curve
3334
from ansys.geometry.core.shapes.curves.curve_evaluation import CurveEvaluation
3435
from ansys.geometry.core.shapes.parameterization import Interval
@@ -148,7 +149,10 @@ def intersect_curve(self, other: "TrimmedCurve") -> list[Point3D]:
148149
)
149150
if res.intersect is False:
150151
return []
151-
return [Point3D([point.x, point.y, point.z]) for point in res.points]
152+
return [
153+
Point3D([point.x, point.y, point.z], unit=DEFAULT_UNITS.SERVER_LENGTH)
154+
for point in res.points
155+
]
152156

153157
def __repr__(self) -> str:
154158
"""Represent the trimmed curve as a string."""

src/ansys/geometry/core/sketch/sketch.py

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828

2929
from ansys.geometry.core.math.constants import ZERO_POINT2D
3030
from ansys.geometry.core.math.plane import Plane
31-
from ansys.geometry.core.math.point import Point2D
31+
from ansys.geometry.core.math.point import Point2D, Point3D
3232
from ansys.geometry.core.math.vector import UnitVector3D, Vector2D, Vector3D
3333
from ansys.geometry.core.misc.checks import graphics_required
3434
from ansys.geometry.core.misc.measurements import DEFAULT_UNITS, Angle, Distance
@@ -121,16 +121,24 @@ def translate_sketch_plane(self, translation: Vector3D) -> "Sketch":
121121
Parameters
122122
----------
123123
translation : Vector3D
124-
Vector defining the translation. Meters is the expected unit.
124+
Vector defining the translation. Default units are the expected
125+
units, otherwise it will be inconsistent.
125126
126127
Returns
127128
-------
128129
Sketch
129130
Revised sketch state ready for further sketch actions.
130131
"""
131-
self.plane = Plane(
132-
self.plane.origin + translation, self.plane.direction_x, self.plane.direction_y
132+
new_origin = Point3D(
133+
[
134+
self.plane.origin.x.m_as(DEFAULT_UNITS.LENGTH) + translation.x,
135+
self.plane.origin.y.m_as(DEFAULT_UNITS.LENGTH) + translation.y,
136+
self.plane.origin.z.m_as(DEFAULT_UNITS.LENGTH) + translation.z,
137+
]
133138
)
139+
# Set the same unit system as the plane origin
140+
new_origin.unit = self.plane.origin.unit
141+
self.plane = Plane(new_origin, self.plane.direction_x, self.plane.direction_y)
134142
return self
135143

136144
@check_input_types

0 commit comments

Comments
 (0)