Planar Shape Construction¶
Basic representations of common two-dimensional shapes:
Also contains convenience methods for creating complex polygons:
-
class
petrify.shape.Circle(origin, radius, segments)[source]¶ Bases:
petrify.plane.Polygon2Approximates a perfect circle with a finite number of line segments:
>>> circle = Circle(Point2.origin, 1, 5)
-
clockwise()¶ Returns True if the points in this polygon are in clockwise order:
>>> Polygon2([Point2(2, 0), Point2(0, 0), Point2(1, 1)]).clockwise() True >>> Polygon2([Point2(1, 1), Point2(0, 0), Point2(2, 0)]).clockwise() False
-
contains(p)¶ Tests whether a point lies within this polygon:
>>> tri = Polygon2([Point2(2, 0), Point2(0, 0), Point2(1, 1)]) >>> tri.contains(Point2(1.0, 0.5)) True >>> tri.contains(Point2(0.5, 1.5)) False
-
inverted()¶ Reverse the points in this polygon:
>>> tri = Polygon2([Point2(2, 0), Point2(0, 0), Point2(1, 1)]) >>> tri.inverted() Polygon2([Point2(1, 1), Point2(0, 0), Point2(2, 0)])
-
inwards(edge)¶ Finds the normalized
Ray2facing inwards for a given edge:>>> tri = Polygon2([Point2(2, 0), Point2(0, 0), Point2(1, 1)]) >>> tri.inwards(tri.segments()[0]) Vector2(0.0, 1.0)
-
is_convex()¶ Return True if the polynomial defined by the sequence of 2D points is ‘strictly convex’:
>>> tri = Polygon2([Point2(2, 0), Point2(0, 0), Point2(1, 1)]) >>> tri.is_convex() True >>> indent = Polygon2([ Point2(0, 0), Point2(10, 0), Point2(5, 5), Point2(10, 10), Point2(0, 10) ]) >>> indent.is_convex() False
Note
“strictly convex” is defined as follows:
- points are valid
- side lengths are non-zero
- interior angles are strictly between zero and a straight angle
- the polygon does not intersect itself
-
offset(amount, tolerance=0.0001)¶ Finds the dynamic offset of a polygon by moving all edges by a given amount perpendicular to their direction:
>>> square = Polygon2([Point2(0, 0), Point2(0, 1), Point2(1, 1), Point2(1, 0)]) >>> square.offset(-0.1) Polygon2([Point2(0.1, 0.1), Point2(0.1, 0.9), Point2(0.9, 0.9), Point2(0.9, 0.1)]) >>> square.offset(0.1) Polygon2([Point2(-0.1, -0.1), Point2(-0.1, 1.1), Point2(1.1, 1.1), Point2(1.1, -0.1)]) >>> square.offset(10) is None True
Note
This is currently a naive implementation that does not properly handle non-local intersections that can split the polygon.
-
simplify(tolerance=0.0001)¶ Remove any duplicate points, within a certain tolerance:
>>> Polygon2([Point2(1, 1), Point2(2, 0), Point2(0, 0), Point2(1, 1)]).simplify() Polygon2([Point2(2, 0), Point2(0, 0), Point2(1, 1)])
Returns None if the resulting simplification would create a point:
>>> Polygon2([Point2(1, 1), Point2(2, 0), Point2(0, 0), Point2(1, 1)]).simplify(100) is None True
-
to_clockwise()¶ Converts this polygon to a clockwise one if necessary:
>>> Polygon2([Point2(2, 0), Point2(0, 0), Point2(1, 1)]).to_clockwise() Polygon2([Point2(2, 0), Point2(0, 0), Point2(1, 1)]) >>> Polygon2([Point2(1, 1), Point2(0, 0), Point2(2, 0)]).to_clockwise() Polygon2([Point2(2, 0), Point2(0, 0), Point2(1, 1)])
-
to_counterclockwise()¶ Converts this polygon to a clockwise one if necessary:
>>> Polygon2([Point2(2, 0), Point2(0, 0), Point2(1, 1)]).to_counterclockwise() Polygon2([Point2(1, 1), Point2(0, 0), Point2(2, 0)]) >>> Polygon2([Point2(1, 1), Point2(0, 0), Point2(2, 0)]).to_counterclockwise() Polygon2([Point2(1, 1), Point2(0, 0), Point2(2, 0)])
-
-
class
petrify.shape.Rectangle(origin, size)[source]¶ Bases:
petrify.plane.Polygon2An axis-aligned rectangle with a point of origin and a vector size:
>>> square = Rectangle(Point2.origin, Vector2(1, 1))
-
clockwise()¶ Returns True if the points in this polygon are in clockwise order:
>>> Polygon2([Point2(2, 0), Point2(0, 0), Point2(1, 1)]).clockwise() True >>> Polygon2([Point2(1, 1), Point2(0, 0), Point2(2, 0)]).clockwise() False
-
contains(p)¶ Tests whether a point lies within this polygon:
>>> tri = Polygon2([Point2(2, 0), Point2(0, 0), Point2(1, 1)]) >>> tri.contains(Point2(1.0, 0.5)) True >>> tri.contains(Point2(0.5, 1.5)) False
-
inverted()¶ Reverse the points in this polygon:
>>> tri = Polygon2([Point2(2, 0), Point2(0, 0), Point2(1, 1)]) >>> tri.inverted() Polygon2([Point2(1, 1), Point2(0, 0), Point2(2, 0)])
-
inwards(edge)¶ Finds the normalized
Ray2facing inwards for a given edge:>>> tri = Polygon2([Point2(2, 0), Point2(0, 0), Point2(1, 1)]) >>> tri.inwards(tri.segments()[0]) Vector2(0.0, 1.0)
-
is_convex()¶ Return True if the polynomial defined by the sequence of 2D points is ‘strictly convex’:
>>> tri = Polygon2([Point2(2, 0), Point2(0, 0), Point2(1, 1)]) >>> tri.is_convex() True >>> indent = Polygon2([ Point2(0, 0), Point2(10, 0), Point2(5, 5), Point2(10, 10), Point2(0, 10) ]) >>> indent.is_convex() False
Note
“strictly convex” is defined as follows:
- points are valid
- side lengths are non-zero
- interior angles are strictly between zero and a straight angle
- the polygon does not intersect itself
-
offset(amount, tolerance=0.0001)¶ Finds the dynamic offset of a polygon by moving all edges by a given amount perpendicular to their direction:
>>> square = Polygon2([Point2(0, 0), Point2(0, 1), Point2(1, 1), Point2(1, 0)]) >>> square.offset(-0.1) Polygon2([Point2(0.1, 0.1), Point2(0.1, 0.9), Point2(0.9, 0.9), Point2(0.9, 0.1)]) >>> square.offset(0.1) Polygon2([Point2(-0.1, -0.1), Point2(-0.1, 1.1), Point2(1.1, 1.1), Point2(1.1, -0.1)]) >>> square.offset(10) is None True
Note
This is currently a naive implementation that does not properly handle non-local intersections that can split the polygon.
-
simplify(tolerance=0.0001)¶ Remove any duplicate points, within a certain tolerance:
>>> Polygon2([Point2(1, 1), Point2(2, 0), Point2(0, 0), Point2(1, 1)]).simplify() Polygon2([Point2(2, 0), Point2(0, 0), Point2(1, 1)])
Returns None if the resulting simplification would create a point:
>>> Polygon2([Point2(1, 1), Point2(2, 0), Point2(0, 0), Point2(1, 1)]).simplify(100) is None True
-
to_clockwise()¶ Converts this polygon to a clockwise one if necessary:
>>> Polygon2([Point2(2, 0), Point2(0, 0), Point2(1, 1)]).to_clockwise() Polygon2([Point2(2, 0), Point2(0, 0), Point2(1, 1)]) >>> Polygon2([Point2(1, 1), Point2(0, 0), Point2(2, 0)]).to_clockwise() Polygon2([Point2(2, 0), Point2(0, 0), Point2(1, 1)])
-
to_counterclockwise()¶ Converts this polygon to a clockwise one if necessary:
>>> Polygon2([Point2(2, 0), Point2(0, 0), Point2(1, 1)]).to_counterclockwise() Polygon2([Point2(1, 1), Point2(0, 0), Point2(2, 0)]) >>> Polygon2([Point2(1, 1), Point2(0, 0), Point2(2, 0)]).to_counterclockwise() Polygon2([Point2(1, 1), Point2(0, 0), Point2(2, 0)])
-
-
petrify.shape.arc(center, radius, start, end, segments=10)[source]¶ Creates an arc of points around the given center with a specified radius and start and end angles, approximated with a fixed number of segments:
>>> points = arc(Point2(5, 0), 5, 0, tau / 2, segments = 3) >>> [p.snap(0.1) for p in points] [Point2(10.0, 0.0), Point2(5.0, 5.0), Point2(0.0, 0.0)]
-
petrify.shape.bezier(a, b, c, d, segments=10)[source]¶ Creates a bezier curve between the given control points, approximated with a given number of segments:
>>> points = bezier(Point2(0, 0), Point2(5, 0), Point2(5, 5), Point2(10, 5), 4) >>> [p.snap(1.0) for p in points] [Point2(0.0, 0.0), Point2(4.0, 1.0), Point2(6.0, 4.0), Point2(10.0, 5.0)]