Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add the arc shape. #81

Merged
merged 15 commits into from
Sep 12, 2022
144 changes: 144 additions & 0 deletions src/ansys/geometry/core/shapes/arc.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
"""``ArcSketch`` class module."""
from typing import List, Optional

import numpy as np

from ansys.geometry.core.math import Point, vector
Maxjrey marked this conversation as resolved.
Show resolved Hide resolved
from ansys.geometry.core.shapes.base import BaseShape
from ansys.geometry.core.typing import Real


class Arc(BaseShape):
"""A class for modelling arcs."""
Maxjrey marked this conversation as resolved.
Show resolved Hide resolved

def __init__(
Maxjrey marked this conversation as resolved.
Show resolved Hide resolved
self,
origin: Point,
start_point: Point,
end_point: Point,
):
Maxjrey marked this conversation as resolved.
Show resolved Hide resolved
"""Initializes the arc shape.

Parameters
----------
origin : Point
A :class:``Point`` representing the center of the arc.
start_point : Point
A :class:``Point`` representing the start of the arc.
end_points : Point
A :class:``Point`` representing the end of the arc.

"""
# Verify both points are not the same
Maxjrey marked this conversation as resolved.
Show resolved Hide resolved
if start_point == end_point:
raise ValueError("Start and end points must be different.")
if origin == start_point:
raise ValueError("Center and start points must be different.")
if origin == end_point:
raise ValueError("Center and end points must be different.")

Maxjrey marked this conversation as resolved.
Show resolved Hide resolved
self._origin, self._start_point, self._end_point = (origin, start_point, end_point)

self._start_vector = vector.Vector.from_points(self._origin, self._start_point)
self._end_vector = vector.Vector.from_points(self._origin, self._end_point)
self._radius = self._start_vector.norm

@property
def start_point(self) -> Point:
"""Return the start of the arc line.

Returns
-------
Point
Starting point of the arc line.

"""
return self._start_point

@property
def end_point(self) -> Point:
"""Return the end of the arc line.

Returns
-------
Point
Ending point of the arc line.

"""
return self._end_point

@property
def radius(self) -> Real:
"""The radius of the circle.

Returns
-------
Real
The radius of the circle.
Maxjrey marked this conversation as resolved.
Show resolved Hide resolved

"""
return self._radius
Maxjrey marked this conversation as resolved.
Show resolved Hide resolved

@property
def angle(self) -> Real:
"""The angle of the circle.

Returns
-------
Real
The angle of the circle.

"""
Maxjrey marked this conversation as resolved.
Show resolved Hide resolved

self._angle = np.arccos(self._start_vector * self._end_vector / self.radius**2)
return self._angle

@property
def length(self) -> Real:
"""Return the length of the arc.

Returns
-------
Real
The length of the arc.

"""
return 2 * np.pi * self.radius * self.angle

@property
def sector_area(self) -> Real:
"""Return the area of the sector of the arc.

Returns
-------
Real
The area of the sector of the arc.

"""
return self.radius**2 * self.angle / 2

def local_points(self, num_points: Optional[int] = 100) -> List[Point]:
"""Returns al list containing all the points belonging to the shape.

Parameters
----------
num_points : int
Desired number of points belonging to the shape.

Returns
-------
List[Point]
A list of points representing the shape.

"""
theta = np.linspace(0, self.angle, num_points)
return [
Point(
[
self.radius * np.cos(ang) + self.origin[0],
self.radius * np.sin(ang) + self.origin[1],
self.origin[2],
Maxjrey marked this conversation as resolved.
Show resolved Hide resolved
]
)
for ang in theta
]
28 changes: 28 additions & 0 deletions src/ansys/geometry/core/sketch.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from ansys.geometry.core.math import UNIT_VECTOR_X, UNIT_VECTOR_Y, ZERO_VECTOR3D
from ansys.geometry.core.math.point import Point
from ansys.geometry.core.math.vector import UnitVector, Vector
from ansys.geometry.core.shapes.arc import Arc
from ansys.geometry.core.shapes.base import BaseShape
from ansys.geometry.core.shapes.circle import Circle
from ansys.geometry.core.shapes.ellipse import Ellipse
Expand Down Expand Up @@ -232,3 +233,30 @@ def draw_polygon(
polygon = Polygon(radius, sides, origin, dir_1=dir_1, dir_2=dir_2)
self.append_shape(polygon)
return polygon

def draw_arc(
self,
center: Point,
start_point: Point,
end_point: Point,
):
"""Create an arc shape on the sketch.

Parameters
----------
center : Point
A :class:``Point`` representing the center of the arc.
start_point : Point
A :class:``Point`` representing the start of the shape.
end_points : Point
A :class:``Point`` representing the end of the shape.

Returns
-------
Arc
An object representing the arc added to the sketch.

"""
arc = Arc(center, start_point, end_point)
self.append_shape(arc)
return arc
24 changes: 24 additions & 0 deletions tests/test_shapes.py
Original file line number Diff line number Diff line change
Expand Up @@ -249,3 +249,27 @@ def test_errors_segment():
match="Parameters 'origin' and 'end' have the same values. No segment can be created.",
):
Segment(Point([10, 20, 30]), Point([10, 20, 30]))


def test_create_arc():
"""Test arc shape creation in a sketch."""

# Create a Sketch instance
sketch = Sketch()

# Draw an arc in previous sketch
origin = Point([1, 1, 0], unit=UNITS.meter)
start_point = Point([1, 3, 0], unit=UNITS.meter)
end_point = Point([3, 1, 0], unit=UNITS.meter)
arc = sketch.draw_arc(origin, start_point, end_point)

# Check attributes are expected ones
assert_allclose(arc.radius, 2)
assert_allclose(arc.sector_area, np.pi)
assert_allclose(arc.length, 2 * np.pi**2)

# Check points are expected ones
local_points = arc.local_points(num_points=5)
assert abs(all(local_points[0] - Point([3, 1, 0]))) <= DOUBLE_EPS
assert abs(all(local_points[1] - Point([2.8477, 1.7653, 0]))) <= DOUBLE_EPS
assert abs(all(local_points[4] - Point([1, 3, 0]))) <= DOUBLE_EPS