|
22 | 22 | """Provides for creating and managing an arc.""" |
23 | 23 |
|
24 | 24 | from beartype import beartype as check_input_types |
25 | | -from beartype.typing import Optional |
| 25 | +from beartype.typing import Optional, Union |
26 | 26 | import numpy as np |
27 | 27 | from pint import Quantity |
28 | 28 | import pyvista as pv |
29 | 29 |
|
| 30 | +from ansys.geometry.core.math.matrix import Matrix |
30 | 31 | from ansys.geometry.core.math.point import Point2D |
31 | 32 | from ansys.geometry.core.math.vector import Vector2D |
32 | | -from ansys.geometry.core.misc.measurements import DEFAULT_UNITS |
| 33 | +from ansys.geometry.core.misc.measurements import DEFAULT_UNITS, Angle, Distance |
33 | 34 | from ansys.geometry.core.misc.units import UNITS |
34 | 35 | from ansys.geometry.core.sketch.edge import SketchEdge |
| 36 | +from ansys.geometry.core.typing import Real |
35 | 37 |
|
36 | 38 |
|
37 | 39 | class Arc(SketchEdge): |
@@ -270,6 +272,7 @@ def __arc_pyvista_hack(self): |
270 | 272 | return arc_sub1 + arc_sub2 |
271 | 273 |
|
272 | 274 | @classmethod |
| 275 | + @check_input_types |
273 | 276 | def from_three_points(cls, start: Point2D, inter: Point2D, end: Point2D): |
274 | 277 | """ |
275 | 278 | Create an arc from three given points. |
@@ -342,3 +345,122 @@ def from_three_points(cls, start: Point2D, inter: Point2D, end: Point2D): |
342 | 345 |
|
343 | 346 | # Finally... you can create the arc |
344 | 347 | return Arc(start=start, end=end, center=center, clockwise=is_clockwise) |
| 348 | + |
| 349 | + @classmethod |
| 350 | + @check_input_types |
| 351 | + def from_start_end_and_radius( |
| 352 | + cls, |
| 353 | + start: Point2D, |
| 354 | + end: Point2D, |
| 355 | + radius: Union[Quantity, Distance, Real], |
| 356 | + convex_arc: Optional[bool] = False, |
| 357 | + clockwise: Optional[bool] = False, |
| 358 | + ): |
| 359 | + """ |
| 360 | + Create an arc from a starting point, an ending point, and a radius. |
| 361 | +
|
| 362 | + Parameters |
| 363 | + ---------- |
| 364 | + start : Point2D |
| 365 | + Starting point of the arc. |
| 366 | + end : Point2D |
| 367 | + Ending point of the arc. |
| 368 | + radius : Union[Quantity, Distance, Real] |
| 369 | + Radius of the arc. |
| 370 | + convex_arc : bool, default: False |
| 371 | + Whether the arc is convex. The default is ``False``. |
| 372 | + When ``False``, the arc is concave. When ``True``, the arc is convex. |
| 373 | + clockwise : bool, default: False |
| 374 | + Whether the arc spans the clockwise angle between the start and end points. |
| 375 | + When ``False``, the arc spans the counter-clockwise angle. |
| 376 | + When ``True``, the arc spands the clockwise angle. |
| 377 | +
|
| 378 | + Returns |
| 379 | + ------- |
| 380 | + Arc |
| 381 | + Arc generated from the three points. |
| 382 | + """ |
| 383 | + # Compute the potential centers of the circle |
| 384 | + # that could generate the arc |
| 385 | + from ansys.geometry.core.math.misc import get_two_circle_intersections |
| 386 | + |
| 387 | + # Sanitize the radius |
| 388 | + radius = radius if isinstance(radius, Distance) else Distance(radius) |
| 389 | + if radius.value <= 0: |
| 390 | + raise ValueError("Radius must be a real positive value.") |
| 391 | + |
| 392 | + # Unpack the points into its coordinates (in DEFAULT_UNITS.LENGTH) |
| 393 | + x_s, y_s = start.tolist() |
| 394 | + x_e, y_e = end.tolist() |
| 395 | + r0 = r1 = radius.value.m_as(DEFAULT_UNITS.LENGTH) |
| 396 | + |
| 397 | + # Compute the potential centers of the circle |
| 398 | + centers = get_two_circle_intersections(x0=x_s, y0=y_s, r0=r0, x1=x_e, y1=y_e, r1=r1) |
| 399 | + if centers is None: |
| 400 | + raise ValueError("The provided points and radius do not yield a valid arc.") |
| 401 | + |
| 402 | + # Choose the center depending on if the arc is convex |
| 403 | + center = Point2D(centers[1] if convex_arc else centers[0]) |
| 404 | + |
| 405 | + # Create the arc |
| 406 | + return Arc(start=start, end=end, center=center, clockwise=clockwise) |
| 407 | + |
| 408 | + @classmethod |
| 409 | + @check_input_types |
| 410 | + def from_start_center_and_angle( |
| 411 | + cls, |
| 412 | + start: Point2D, |
| 413 | + center: Point2D, |
| 414 | + angle: Union[Angle, Quantity, Real], |
| 415 | + clockwise: Optional[bool] = False, |
| 416 | + ): |
| 417 | + """ |
| 418 | + Create an arc from a starting point, a center point, and an angle. |
| 419 | +
|
| 420 | + Parameters |
| 421 | + ---------- |
| 422 | + start : Point2D |
| 423 | + Starting point of the arc. |
| 424 | + center : Point2D |
| 425 | + Center point of the arc. |
| 426 | + angle : Union[Angle, Quantity, Real] |
| 427 | + Angle of the arc. |
| 428 | + clockwise : bool, default: False |
| 429 | + Whether the provided angle should be considered clockwise. |
| 430 | + When ``False``, the angle is considered counter-clockwise. |
| 431 | + When ``True``, the angle is considered clockwise. |
| 432 | +
|
| 433 | + Returns |
| 434 | + ------- |
| 435 | + Arc |
| 436 | + Arc generated from the three points. |
| 437 | + """ |
| 438 | + # Define a 2D vector from the center to the start point |
| 439 | + to_start_vector = Vector2D.from_points(center, start) |
| 440 | + |
| 441 | + # Perform sanity check for the angle |
| 442 | + angle = angle if isinstance(angle, Angle) else Angle(angle) |
| 443 | + rad_angle = angle.value.m_as(UNITS.radian) |
| 444 | + cang = np.cos(rad_angle) |
| 445 | + sang = np.sin(rad_angle) |
| 446 | + |
| 447 | + # Rotate the vector by the angle |
| 448 | + if clockwise: |
| 449 | + rot_matrix = Matrix([[cang, sang], [-sang, cang]]) |
| 450 | + else: |
| 451 | + rot_matrix = Matrix([[cang, -sang], [sang, cang]]) |
| 452 | + |
| 453 | + # Compute the end vector |
| 454 | + to_end_vector = rot_matrix @ to_start_vector |
| 455 | + |
| 456 | + # Define the end point |
| 457 | + end = Point2D( |
| 458 | + [ |
| 459 | + to_end_vector[0] + center.x.to_base_units().m, |
| 460 | + to_end_vector[1] + center.y.to_base_units().m, |
| 461 | + ], |
| 462 | + center.base_unit, |
| 463 | + ) |
| 464 | + |
| 465 | + # Create the arc |
| 466 | + return Arc(start=start, end=end, center=center, clockwise=clockwise) |
0 commit comments