omdl  v1.0
OpenSCAD Mechanical Design Library
Polygons

Polygon mathematical functions; 2-polytope. More...

+ Collaboration diagram for Polygons:

Files

file  polygon.scad
 Polygon shapes, conversions, properties, and tests functions.
 

Shapes

function polygon_regular_p (n, r, a, o=origin2d, ao=0, vr, cw=true)
 Compute coordinates for an n-sided regular polygon in 2D. More...
 
function polygon_line_p (p1=origin2d, p2=x_axis2d_uv, l, x, y, r, fs, ft, fn=1)
 Compute coordinates along a line in 2D. More...
 
function polygon_arc_sweep_p (r=1, o=origin2d, v1=x_axis2d_uv, v2=x_axis2d_uv, fn, cw=true)
 Compute coordinates of an arc with constant radius between two vectors in 2D. More...
 
function polygon_arc_fillet_p (r=1, o=origin2d, v1=x_axis2d_uv, v2=y_axis2d_uv, fn, cw=true)
 Compute coordinates for a circular fillet arc between two rays in 2D. More...
 
function polygon_arc_blend_p (p1, p2, p3, r=1, fn, cw=true)
 Compute coordinates for a circular arc blend between two line segments in 2D. More...
 
function polygon_elliptical_sector_p (r=1, o=origin2d, v1=x_axis2d_uv, v2=x_axis2d_uv, s=true, fn, cw=true)
 Compute coordinates for an elliptical sector in 2D. More...
 
function polygon_trapezoid_p (b=1, h, l=1, a=90, o=origin2d, cw=true)
 Compute the coordinates for a rounded trapezoid in 2D space. More...
 

Curves

function polygon_bezier_p (c, fn, cw=true)
 Compute coordinates for a degree-n Bézier curve in 2D. More...
 
function polygon_spline_p (c, fn, closed=false, cw=true)
 Compute coordinates for a Catmull-Rom spline through a list of knot points in 2D. More...
 

Properties

function polygon_regular_perimeter (n, r, a)
 Compute the perimeter of an n-sided regular polygon in 2D. More...
 
function polygon_regular_area (n, r, a)
 Compute the area of an n-sided regular polygon in 2D. More...
 
function polygon_perimeter (c, p)
 Calculate the perimeter length of a polygon in 2d. More...
 
function polygon_area (c, p, s=false)
 Compute the signed area of a polygon in a Euclidean 2d-space. More...
 
function polygon3d_area (c, p, n)
 Compute the area of a polygon in a Euclidean 3d-space. More...
 
function polygon_centroid (c, p)
 Compute the center of mass of a polygon in a Euclidean 2d-space. More...
 
function polygon_winding (c, p, t)
 Compute the winding number of a polygon about a point in a Euclidean 2d-space. More...
 

Tests

function polygon_is_clockwise (c, p)
 Test the vertex ordering of a polygon in a Euclidean 2d-space. More...
 
function polygon_is_convex (c, p)
 Test the convexity of a polygon in a Euclidean 2d-space. More...
 
function polygon_wn_is_p_inside (c, p, t)
 Test if a point is inside a polygon in a Euclidean 2d-space using winding number. More...
 
function polygon_as_is_p_inside (c, p, t)
 Test if a point is inside a polygon in a Euclidean 2d-space using angle summation. More...
 

Transforms

function polygon_linear_extrude_pf (c, p, h=1, centroid=false, center=false)
 Convert a polygon in 2D to a polyhedron by adding a height dimension. More...
 

Profiles

function polygon_round_eve_p (r=1, m=1, o=origin2d, v1=x_axis2d_uv, v2=y_axis2d_uv, fn, cw=true)
 Compute coordinates for a constant radius vertex round between two edge vectors in 2D. More...
 
function polygon_round_eve_all_p (c, vr=0, vrm=1, vfn, w=true, cw=true)
 Compute coordinates that round all of the vertices between each adjacent edges in 2D. More...
 
function polygon_line_wave_p (p1=origin2d, p2=x_axis2d_uv, p=1, a=1, w=1, m=0, t, fn)
 Generate 2D coordinate points along a line with periodic waveform lateral displacement. More...
 

Usage Details

Polygon mathematical functions; 2-polytope.

Validation Summary

filegroupscriptresultsno testskippedpassedfailedwarning
math/polygon.scadPolygonsScriptResults240000

No Failures

See complete validation results.

Requires:
include <omdl-base.scad>;

Conventions

All functions in this group operate on polygons defined by a list of 2d cartesian coordinates c and an optional list of paths p, following OpenSCAD's native polygon() convention:

Function and/or Module Documentation

◆ polygon_regular_p()

function polygon_regular_p ( ,
,
,
= origin2d,
ao  = 0,
vr  ,
cw  = true 
)

Compute coordinates for an n-sided regular polygon in 2D.

Parameters
n<integer> The number of sides.
r<decimal> The circumradius of the circumcircle.
a<decimal> The inradius of the incircle.
o<point-2d> The center coordinate [x, y].
ao<decimal> The rotational angular offset in degrees.
vr<decimal> The vertex rounding radius. Each computed vertex is offset inward by vr / cos(180/n) along the radial direction from o to the vertex. This is correct for any value of o.
cw<boolean> Vertex ordering. When true vertices are generated clockwise (decreasing angle from ao); when false they are generated counter-clockwise (increasing angle from ao). Always produces exactly n vertices.
Returns
<points-2d> A list of exactly n coordinate points [[x, y], ...], one per polygon vertex.

Both n and at least one of r or a must be provided. When neither r nor a is defined, the circumradius defaults to 0 and an n-pointed degenerate polygon at o is returned.

The radius can be specified by either the circumradius r or the inradius a. If both are specified, r is used.

Vertex angles are computed as ao ± i × (360/n) for i in [0, n-1], giving exact uniform angular spacing with no floating-point accumulation across the range. The closing vertex at 0° is always included.

Example

vr=5;
hull()
{
for ( p = polygon_regular_p( r=20, n=5, vr=vr ) )
translate( p )
circle( r=vr );
}
function polygon_regular_p(n, r, a, o=origin2d, ao=0, vr, cw=true)
Compute coordinates for an n-sided regular polygon in 2D.

See Wikipedia for more information.

+ Here is the caller graph for this function:

◆ polygon_line_p()

function polygon_line_p ( p1  = origin2d,
p2  = x_axis2d_uv,
,
,
,
,
fs  ,
ft  ,
fn  = 1 
)

Compute coordinates along a line in 2D.

Parameters
p1<point-2d> The line initial coordinate [x, y].
p2<point-2d> The line terminal coordinate [x, y].
l<line-2d> The line or vector.
x<decimal-list | decimal> A list of x coordinates [x1, x2, ...] or a single x coordinate at which to interpolate along the line.
y<decimal-list | decimal> A list of y coordinates [y1, y2, ...] or a single y coordinate at which to interpolate along the line.
r<decimal-list | decimal> A list of ratios [r1, r2, ...] or a single ratio r. The position ratio along line p1 (r=0) to p2 (r=1).
fs<decimal> A fixed segment size between each point along the line.
ft<decimal> A fixed segment size between each point, centered, beginning at p1 and terminating at p2.
fn<integer> A fixed number of equally spaced points.
Returns
<points-2d> A list of coordinates points [[x, y], ...]. Returns undef when the requested interpolation axis is degenerate for the given line orientation (see

).

Linear interpolation is used to compute each point along the line. The order of precedence for line specification is: l then p1 and p2. The order of precedence for interpolation is: x, y, r, fs, ft, fn.

When the line is vertical (delta-x ≈ 0), the interpolation axis switches to y. Querying by x on a vertical line returns undef. Querying by y on a horizontal line (zero delta-y) also returns undef. In all other cases a list of interpolated coordinates is returned.

◆ polygon_arc_sweep_p()

function polygon_arc_sweep_p ( = 1,
= origin2d,
v1  = x_axis2d_uv,
v2  = x_axis2d_uv,
fn  ,
cw  = true 
)

Compute coordinates of an arc with constant radius between two vectors in 2D.

Parameters
r<decimal> The arc radius.
o<point-2d> The arc center coordinate [x, y].
v1<line-2d | decimal> The arc start angle. A 2d line, vector, or decimal angle 1.
v2<line-2d | decimal> The arc end angle. A 2d line, vector, or decimal angle 2.
fn<integer> The number of facets (optional).
cw<boolean> Sweep direction. When true the arc sweeps clockwise from the head of v1 to the head of v2; when false it sweeps counter-clockwise. The returned list always contains fn + 1 points (both endpoints included).
Returns
<points-2d> A list of coordinates points [[x, y], ...].

The arc coordinates will have radius r centered about o contained within the heads of vectors v1 and v2. The arc will start at the point coincident to v1 and will end at the point coincident to v2. When vectors v1 and v2 are parallel, or when the positive sweep angle is within the almost_eq_nv() tolerance of zero (nearly parallel), the sweep angle is forced to 360° and a full circle is returned. When fn is undefined, its value is determined by get_fn().

Note
To round a polygon corner with a tangent arc whose center is derived automatically from the corner geometry, use polygon_arc_fillet_p().
+ Here is the caller graph for this function:

◆ polygon_arc_fillet_p()

function polygon_arc_fillet_p ( = 1,
= origin2d,
v1  = x_axis2d_uv,
v2  = y_axis2d_uv,
fn  ,
cw  = true 
)

Compute coordinates for a circular fillet arc between two rays in 2D.

Parameters
r<decimal> The fillet radius. Must be greater than zero.
o<point-2d> The corner coordinate [x, y] — the vertex where the two rays v1 and v2 meet.
v1<line-2d | decimal> The first ray direction (incoming edge). A 2d line, vector, or decimal angle in degrees. The fillet begins at the tangent point on this ray.
v2<line-2d | decimal> The second ray direction (outgoing edge). A 2d line, vector, or decimal angle in degrees. The fillet ends at the tangent point on this ray.
fn<integer> The number of facets (optional). When undefined, its value is determined by get_fn() evaluated at the fillet radius r.
cw<boolean> Point ordering. When true the returned list runs from the tangent point on v1 to the tangent point on v2 in the clockwise direction; when false the list is reversed to run counter-clockwise. Defaults to true, consistent with polygon_arc_sweep_p() and the other shape-generation functions in this group.
Returns
<points-2d> A list of coordinates points [[x, y], ...] tracing the fillet arc from the tangent point on v1 to the tangent point on v2. Returns empty_lst when the two rays are (anti-)parallel within the almost_eq_nv() tolerance.

A circular fillet of radius r is tangent to both rays v1 and v2 that originate at the corner vertex o. The function computes and returns only the arc of the fillet circle that lies between the two tangent points; it does not include the corner vertex o or the tangent points' projections back along the rays. The resulting point list can be spliced directly into a polygon path in place of the sharp corner at o to round it.

◆ polygon_arc_blend_p()

function polygon_arc_blend_p ( p1  ,
p2  ,
p3  ,
= 1,
fn  ,
cw  = true 
)

Compute coordinates for a circular arc blend between two line segments in 2D.

Parameters
p1<point-2d> The start point of the incoming segment [x, y].
p2<point-2d> The corner vertex coordinate [x, y] — the point where the two segments meet.
p3<point-2d> The end point of the outgoing segment [x, y].
r<decimal> The blend radius. Must be greater than zero.
fn<integer> The number of facets (optional). When undefined, its value is determined by get_fn() evaluated at the blend radius r.
cw<boolean> Point ordering. When true the returned list runs from the tangent point on the incoming segment to the tangent point on the outgoing segment in the clockwise direction; when false the list is reversed to run counter-clockwise. Defaults to true, consistent with polygon_arc_fillet_p() and the other shape-generation functions in this group.
Returns
<points-2d> A list of coordinate points [[x, y], ...] tracing the blend arc from the tangent point on the incoming segment to the tangent point on the outgoing segment. Returns empty_lst when the two segments are (anti-)parallel within the almost_eq_nv() tolerance.

Computes a circular fillet arc of radius r that is tangent to both the incoming segment p1 to p2 and the outgoing segment p2 to p3. The returned arc replaces the sharp corner at p2 and can be spliced directly into a polygon path to produce a rounded vertex.

The function derives the incoming and outgoing ray directions from the three supplied points and delegates to polygon_arc_fillet_p(). The corner vertex p2 is not included in the returned list; only the arc points between the two tangent points are returned.

Example

$fn = 32;
c = [[0,0], [10,0], [10,10], [0,10]];
// replace the corner at c[1] with a blend arc of radius 3
blend = polygon_arc_blend_p( p1=c[0], p2=c[1], p3=c[2], r=3 );
polygon( concat( [c[0]], blend, [c[2]], [c[3]] ) );
function polygon_arc_blend_p(p1, p2, p3, r=1, fn, cw=true)
Compute coordinates for a circular arc blend between two line segments in 2D.

◆ polygon_elliptical_sector_p()

function polygon_elliptical_sector_p ( = 1,
= origin2d,
v1  = x_axis2d_uv,
v2  = x_axis2d_uv,
= true,
fn  ,
cw  = true 
)

Compute coordinates for an elliptical sector in 2D.

Parameters
r<decimal-list-2 | decimal> The elliptical radius. A list [rx, ry] of decimals where rx is the x-axis radius and ry is the y-axis radius, or a single decimal for (rx=ry).
o<point-2d> The center coordinate [x, y].
v1<line-2d | decimal> The sector angle 1. A 2d line, vector, or decimal.
v2<line-2d | decimal> The sector angle 2. A 2d line, vector, or decimal.
s<boolean> Use signed vector angle conversions. When false, positive angle conversion will be used.
fn<integer> The number of facets (optional).
cw<boolean> Coordinate point ordering. When true the returned list is in the natural computed order; when false the list is reversed.
Returns
<points-2d> A list of coordinates points [[x, y], ...].

The coordinates sweep from angle v1 to angle v2. When v1 and v2 are equal, a full ellipse is returned. The sweep direction is determined by the signs of the angles; a positive delta sweeps counter-clockwise and a negative delta sweeps clockwise, regardless of the cw ordering parameter (which only controls whether the returned list is reversed).

When v1 and v2 are not equal, the origin point o is prepended to the coordinate list, forming a closed pie-sector shape when passed directly to polygon(). For a full ellipse, o is omitted and the result is a closed ring of perimeter points.

The parameter s controls how vector angles are converted to decimal degrees. When s = true (default), signed angle conversion is used, so vectors below the x-axis yield negative angles. When s = false, all angles are mapped to [0, 360). This affects sector orientation when v1 or v2 are given as 2d lines or vectors rather than explicit decimal angles.

When fn is undefined, its value is determined by get_fn().

+ Here is the caller graph for this function:

◆ polygon_trapezoid_p()

function polygon_trapezoid_p ( = 1,
,
= 1,
= 90,
= origin2d,
cw  = true 
)

Compute the coordinates for a rounded trapezoid in 2D space.

Parameters
b<decimal-list-2 | decimal> The base lengths. A list [b1, b2] of 2 decimals or a single decimal for (b1=b2).
h<decimal> The perpendicular height between bases. Takes precedence over l when both are specified. When neither h nor l is specified, l defaults to 1.
l<decimal> The left side leg length. Used only when h is not specified; the resulting height is l × sin(a).
a<decimal> The angle in degrees between the lower base and the left leg. When h is specified, restricted to [45, 135] to keep the upper-left vertex above the lower base.
o<point-2d> The origin offset coordinate [x, y].
cw<boolean> Polygon vertex ordering.
Returns
<points-2d> A list of exactly 4 coordinate points [[x, y], ...] defining the trapezoid vertices.

The four vertices are computed from the origin o as follows: p1 = o (lower-left), p2 = upper-left leg endpoint, p3 = p2 + [b2, 0] (upper-right), p4 = o + [b1, 0] (lower-right). The lower base has length b1 and the upper base has length b2.

When both h and l are specified, h takes precedence and the actual leg length is derived from h and a. When only l is given, the perpendicular height is l × sin(a). If h is specified, the angle a is restricted to the range [45, 135] to keep the upper-left vertex above the lower base.

Special cases: when b is a single decimal (b1 = b2) and a = 90 the result is a rectangle; when additionally b1 = h the result is a square. When a ≠ 90 and b1 = b2 the result is a parallelogram.

See Wikipedia for more general information on trapezoids.

+ Here is the caller graph for this function:

◆ polygon_bezier_p()

function polygon_bezier_p ( ,
fn  ,
cw  = true 
)

Compute coordinates for a degree-n Bézier curve in 2D.

Parameters
c<points-2d> A list of 2d control point coordinates [[x, y], ...]. The curve interpolates c[0] and c[last] and approximates the interior control points. Minimum 2 points required (degree 1, linear).
fn<integer> The number of facets (optional). When undefined, its value is determined by get_fn() using the chord length of the control polygon as a proxy radius.
cw<boolean> Point ordering. When true the returned list is in the natural computed order (t = 0 to 1); when false the list is reversed. Defaults to true.
Returns
<points-2d> A list of fn + 1 coordinate points [[x, y], ...] sampled uniformly in the parameter t member of [0, 1], including both endpoints.

Evaluates the Bézier curve defined by the control polygon c using the de Casteljau algorithm. The degree of the curve is len(c) - 1. Common cases:

  • Degree 1 (2 points): straight line segment.
  • Degree 2 (3 points): quadratic Bézier.
  • Degree 3 (4 points): cubic Bézier.
  • Higher degrees are supported but may exhibit Runge-like oscillation.

The de Casteljau algorithm is used for its numerical stability. At each parameter value t it performs degree rounds of linear interpolation on the current level's point list until a single point remains. No external helper functions are required.

Example

$fn = 32;
ctrl = [ [0,0], [5,20], [15,20], [20,0] ];
polygon( polygon_bezier_p( c=ctrl ) );
function polygon_bezier_p(c, fn, cw=true)
Compute coordinates for a degree-n Bézier curve in 2D.

◆ polygon_spline_p()

function polygon_spline_p ( ,
fn  ,
closed  = false,
cw  = true 
)

Compute coordinates for a Catmull-Rom spline through a list of knot points in 2D.

Parameters
c<points-2d> A list of 2d knot coordinates [[x, y], ...]. The curve passes through every knot. Minimum 2 points required. When closed is false the curve runs from c[0] to c[last]; when closed is true it also returns from c[last] back to c[0].
fn<integer> The number of facets per segment (optional). Each segment is the span between two consecutive knot points. When undefined, the per-segment value is determined by get_fn() evaluated at the segment chord length divided by .
closed<boolean> When true the spline is closed: a segment is added from the last knot back to the first, and the phantom knots at both ends are wrapped accordingly. Defaults to false.
cw<boolean> Point ordering. When true the returned list is in the natural computed order; when false the list is reversed. Defaults to true.
Returns
<points-2d> A list of coordinate points [[x, y], ...] tracing the spline. For an open spline with n knots and fn facets per segment the list contains (n-1) × fn + 1 points. For a closed spline it contains n × fn points (the closing knot is not duplicated).

Implements the centripetal Catmull-Rom spline. Each interior segment i (from knot i to knot i+1) uses the four control points c[i-1], c[i], c[i+1], c[i+2] to form a smooth cubic. Phantom knots at the ends of an open spline are synthesised by reflecting: the phantom before c[0] mirrors c[1], and the phantom after c[last] mirrors c[last-1].

Example

$fn = 32;
knots = [ [0,0], [5,10], [15,10], [20,0], [15,-10], [5,-10] ];
polygon( polygon_spline_p( c=knots, closed=true ) );
function polygon_spline_p(c, fn, closed=false, cw=true)
Compute coordinates for a Catmull-Rom spline through a list of knot points in 2D.

◆ polygon_regular_perimeter()

function polygon_regular_perimeter ( ,
,
 
)

Compute the perimeter of an n-sided regular polygon in 2D.

Parameters
n<integer> The number of sides.
r<decimal> The vertex circumradius of the circumcircle.
a<decimal> The inradius of the incircle.
Returns
<decimal> Perimeter length of the n-sided regular polygon.

The radius can be specified by either the circumradius r or the inradius a. If both are specified, r is used. Returns 0 when neither is defined.

Formulae used:

P = 2 × n × r × sin(180/n) (from circumradius r)
P = 2 × n × a × tan(180/n) (from inradius a)
+ Here is the caller graph for this function:

◆ polygon_regular_area()

function polygon_regular_area ( ,
,
 
)

Compute the area of an n-sided regular polygon in 2D.

Parameters
n<integer> The number of sides.
r<decimal> The vertex circumradius of the circumcircle.
a<decimal> The inradius of the incircle.
Returns
<decimal> Area of the n-sided regular polygon.

The radius can be specified by either the circumradius r or the inradius a. If both are specified, r is used. Returns 0 when neither is defined.

Formulae used:

A = r² × n × sin(360/n) / 2 (from circumradius r)
A = a² × n × tan(180/n) (from inradius a)

◆ polygon_perimeter()

function polygon_perimeter ( ,
 
)

Calculate the perimeter length of a polygon in 2d.

Parameters
c<points-2d> A list of 2d cartesian coordinates [[x, y], ...].
p<integer-list-list> An optional list of paths that define one or more closed shapes where each is a list of coordinate indexes.
Returns
<decimal> The sum of all polygon primary and secondary perimeter lengths.

Computes the total perimeter by summing the Euclidean distance between each consecutive pair of vertices in every path, including the closing edge from the last vertex back to the first. Uses _polygon_edge_indices() to enumerate edge pairs.

Note
When p is not defined, the listed order of the coordinates will be used.

◆ polygon_area()

function polygon_area ( ,
,
= false 
)

Compute the signed area of a polygon in a Euclidean 2d-space.

Parameters
c<points-2d> A list of 2d cartesian coordinates [[x, y], ...].
p<integer-list-list> An optional list of paths that define one or more closed shapes where each is a list of coordinate indexes.
s<boolean> Return the signed area. When true the raw signed value is returned: negative for clockwise vertex ordering and positive for counter-clockwise. When false (default) the absolute area is returned.
Returns
<decimal> The area of the given polygon.

Uses the shoelace formula applied to all edge pairs enumerated by _polygon_edge_indices(). See Wikipedia for more information.

Note
When p is not defined, the listed order of the coordinates will be used.
Warning
This function does not track secondary shapes subtraction as implemented by the polygon() function.

◆ polygon3d_area()

function polygon3d_area ( ,
,
 
)

Compute the area of a polygon in a Euclidean 3d-space.

Parameters
c<points-3d> A list of 3d cartesian coordinates [[x, y, z], ...].
p<integer-list-list> An optional list of paths that define one or more closed shapes where each is a list of coordinate indexes.
n<vector-3d> An optional normal vector, [x, y, z], to the polygon plane. When not given, a normal vector is constructed from the first three points of the primary path.
Returns
<decimal> The area of the given polygon.

Computes the area using a coordinate-projection method: the dominant axis of the polygon's normal vector is identified, the polygon is projected onto the perpendicular plane, and the 2D shoelace formula is applied with a correction factor derived from the normal vector magnitude. Function patterned after Dan Sunday, 2012.

When n is not supplied the normal is derived from the first three vertices of the primary path. An assertion is raised if those three vertices are collinear (i.e. the derived normal is the zero vector), because no valid projection axis exists in that case. Supply an explicit n to override when the first three vertices are known to be collinear but the polygon as a whole is non-degenerate.

Note
When p is not defined, the listed order of the coordinates will be used.
Warning
This function does not track secondary shapes subtraction as implemented by the polygon() function.

◆ polygon_centroid()

function polygon_centroid ( ,
 
)

Compute the center of mass of a polygon in a Euclidean 2d-space.

Parameters
c<points-2d> A list of 2d cartesian coordinates [[x, y], ...].
p<integer-list-list> An optional list of paths that define one or more closed shapes where each is a list of coordinate indexes.
Returns
<point-2d> The center of mass of the given polygon.

Uses the shoelace-derived centroid formula applied to all edge pairs enumerated by _polygon_edge_indices(). See Wikipedia for more information.

Note
When p is not defined, the listed order of the coordinates will be used.
Warning
This function does not track secondary shapes subtraction as implemented by the polygon() function.
Returns undef (division by zero) for degenerate polygons with zero signed area, such as collinear point sets or self-intersecting shapes whose positive and negative areas cancel.
+ Here is the caller graph for this function:

◆ polygon_winding()

function polygon_winding ( ,
,
 
)

Compute the winding number of a polygon about a point in a Euclidean 2d-space.

Parameters
c<points-2d> A list of 2d cartesian coordinates [[x, y], ...].
p<integer-list-list> An optional list of paths that define one or more closed shapes where each is a list of coordinate indexes.
t<point-2d> A test point coordinate [x, y].
Returns
<integer> The winding number. Positive values indicate the point is enclosed by net counter-clockwise turns; negative values indicate net clockwise turns; zero means the point is outside the polygon.

Computes the winding number, the total number of counterclockwise turns that the polygon paths makes around the test point in a Euclidean 2d-space. Will be 0 iff the point is outside of the polygon. The result for a test point exactly on a polygon edge is implementation-defined. Uses _polygon_edge_indices() to enumerate edge pairs. Function patterned after Dan Sunday, 2012.

Note

Copyright 2000 softSurfer, 2012 Dan Sunday This code may be freely used and modified for any purpose providing that this copyright notice is included with it. iSurfer.org makes no warranty for this code, and cannot be held liable for any real or imagined damage resulting from its use. Users of this code must verify correctness for their application.

Note
When p is not defined, the listed order of the coordinates will be used.
Warning
Where there are secondary paths, the vertex ordering of each must be the same as the primary path.

◆ polygon_is_clockwise()

function polygon_is_clockwise ( ,
 
)

Test the vertex ordering of a polygon in a Euclidean 2d-space.

Parameters
c<points-2d> A list of 2d cartesian coordinates [[x, y], ...].
p<integer-list-list> An optional list of paths that define one or more closed shapes where each is a list of coordinate indexes.
Returns
<boolean> true if the vertex are ordered clockwise, false if the vertex are counterclockwise ordered, and undef if the ordering can not be determined.

Uses the sign of the polygon's signed area (shoelace formula). A negative signed area indicates clockwise vertex ordering in the standard 2d coordinate system (y-up). Returns undef for degenerate polygons with zero signed area (e.g. collinear vertices).

Note
Two separate winding conventions coexist in this library. Shape-generation functions (polygon_regular_p(), polygon_trapezoid_p(), polygon_elliptical_sector_p(), etc.) all default to cw = true, producing clockwise output. OpenSCAD's polygon() and linear_extrude() treat the primary path as counter-clockwise and hole paths as clockwise. Callers that bridge the two layers must reverse the coordinate list (or pass cw = false) as appropriate. Functions in this library that require a specific winding — such as polygon_linear_extrude_pf() — call polygon_is_clockwise() and normalise internally; callers are not required to pre-normalise their input.
When p is not defined, the listed order of the coordinates will be used.

◆ polygon_is_convex()

function polygon_is_convex ( ,
 
)

Test the convexity of a polygon in a Euclidean 2d-space.

Parameters
c<points-2d> A list of 2d cartesian coordinates [[x, y], ...].
p<integer-list-list> An optional list of paths that define one or more closed shapes where each is a list of coordinate indexes.
Returns
<boolean> true if the polygon is convex, false otherwise.

Tests convexity by computing the cross product sign of each consecutive edge pair using _polygon_vertex_indices() to enumerate vertex triples. A polygon is convex when all cross products have the same sign (all left-turns or all right-turns). Collinear edges produce a cross product of zero, which counts as a distinct sign value and will cause the function to return false even for otherwise convex polygons with collinear points on an edge. Returns undef when c is undefined, has fewer than 3 points, or contains non-2d coordinates.

Note
When p is not defined, the listed order of the coordinates will be used.

◆ polygon_wn_is_p_inside()

function polygon_wn_is_p_inside ( ,
,
 
)

Test if a point is inside a polygon in a Euclidean 2d-space using winding number.

Parameters
c<points-2d> A list of 2d cartesian coordinates [[x, y], ...].
p<integer-list-list> An optional list of paths that define one or more closed shapes where each is a list of coordinate indexes.
t<point-2d> A test point coordinate [x, y].
Returns
<boolean> true when the point is inside the polygon and false otherwise.

Delegates to polygon_winding() and returns true when the winding number is non-zero. A winding number of zero indicates the point is outside all enclosed regions. The result for a test point exactly on a polygon edge is implementation-defined (see polygon_winding()).

Note
When p is not defined, the listed order of the coordinates will be used.
See also
polygon_winding for warning about secondary Shapes.

◆ polygon_as_is_p_inside()

function polygon_as_is_p_inside ( ,
,
 
)

Test if a point is inside a polygon in a Euclidean 2d-space using angle summation.

Parameters
c<points-2d> A list of 2d cartesian coordinates [[x, y], ...].
p<integer-list-list> An optional list of paths that define one or more closed shapes where each is a list of coordinate indexes.
t<point-2d> A test point coordinate [x, y].
Returns
<boolean> true when the point is inside the polygon and false otherwise.

Tests point inclusion by summing the signed angles subtended by each polygon edge as seen from the test point t. For a point strictly inside a simple polygon the absolute sum approximates 360°; for a point outside it approximates 0°. The threshold used is 180° to distinguish the two cases, which is reliable for non-degenerate simple polygons. Points exactly on an edge produce an undefined result.

See Wikipedia for more information.

Note
When p is not defined, the listed order of the coordinates will be used.
Warning
This function does not track secondary shapes subtraction as implemented by the polygon() function.

◆ polygon_linear_extrude_pf()

function polygon_linear_extrude_pf ( ,
,
= 1,
centroid  = false,
center  = false 
)

Convert a polygon in 2D to a polyhedron by adding a height dimension.

Parameters
c<points-2d> A list of 2d cartesian coordinates [[x, y], ...].
p<integer-list-list> An optional list of paths that define one or more closed shapes where each is a list of coordinate indexes.
h<decimal> The polyhedron height.
centroid<boolean> Center polygon centroid at z-axis.
center<boolean> Center polyhedron height about xy-plane.
Returns
<datastruct> A structure [points, faces], where points are <points-3d> and faces are a <integer-list-list>, suitable for use with polyhedron().

Extrudes the 2D polygon into a closed 3D polyhedron by duplicating the coordinate list at two z-levels and constructing bottom, top, and side faces.

Each path in p produces its own set of triangulated cap faces (bottom and top) via ear-clipping triangulation, and its own band of quad side faces. This correctly handles multi-path polygons with holes, provided hole paths carry winding opposite to the primary path, matching the convention used by polygon() and linear_extrude().

Bottom cap triangles follow each path's own vertex winding; top cap triangles are reversed so that all face normals point outward. Side face quad winding is determined per-path by calling polygon_is_clockwise() on each path's coordinates and signed area.

Warning
Triangulation uses ear clipping, which is correct for simple (non-self-intersecting) polygons only. If a path is self-intersecting, a warning is emitted via echo and the triangulation for that path will be incomplete, producing a non-manifold solid.
An assertion is raised if any path is degenerate (zero signed area), because the winding direction cannot be determined and the resulting polyhedron faces would be incorrect. Degenerate paths include collinear vertex sets and self-intersecting shapes whose positive and negative areas cancel exactly.
Note
Hole correctness depends on the caller providing hole paths with winding opposite to the primary path, matching the polygon() convention.

When centroid is true, the polygon centroid is computed and subtracted from all x/y coordinates before extrusion, centering the shape on the z-axis.

When center is true the z-range is [-h/2, h/2]; otherwise it is [0, h].

Note
When p is not defined, the listed order of the coordinates will be used.

◆ polygon_round_eve_p()

function polygon_round_eve_p ( = 1,
= 1,
= origin2d,
v1  = x_axis2d_uv,
v2  = y_axis2d_uv,
fn  ,
cw  = true 
)

Compute coordinates for a constant radius vertex round between two edge vectors in 2D.

Parameters
r<decimal> The round radius.
m<integer> The round mode.
o<point-2d> The vertex coordinate [x, y] at which the two edge vectors meet (the corner being rounded).
v1<line-2d | decimal> The first edge direction. A 2d line, vector, or decimal angle.
v2<line-2d | decimal> The second edge direction. A 2d line, vector, or decimal angle.
fn<integer> The number of facets (optional).
cw<boolean> Coordinate point ordering. When true the list runs from the inflection point on edge 1 toward the inflection point on edge 2; when false the order is reversed.
Returns
<points-2d> A list of coordinates points [[x, y], ...] beginning at the inflection point on v1, followed by the arc (or chamfer) segment, and ending at the inflection point on v2. These points replace the original corner vertex in a polygon path.

Computes the replacement coordinate sequence for a single polygon corner at o between edges v1 and v2. Normally, edge angle 1 should be less than edge angle 2.

The round mode may be one of the following:

mode name description
1 fillet concave arc (inward, tangent to both edges)
2 round convex arc (outward, tangent to both edges)
3 chamfer straight bevel between the two inflection points
+ Here is the caller graph for this function:

◆ polygon_round_eve_all_p()

function polygon_round_eve_all_p ( ,
vr  = 0,
vrm  = 1,
vfn  ,
= true,
cw  = true 
)

Compute coordinates that round all of the vertices between each adjacent edges in 2D.

Parameters
c<points-2d> A list of n 2d cartesian coordinates [[x1, y1], [x2, y2], ..., [xn, yn]].
vr<decimal-list-n | decimal> The vertices rounding radius. A list [v1r, v2r, v3r, ... vnr] of n decimals or a single decimal for (v1r=v2r=v3r= ... =vnr). Undefined vertices are not rounded.
vrm<integer-list-n | integer> The vertices rounding mode. A list [v1rm, v2rm, v3rm, ... vnrm] of n integers or a single integer for (v1rm=v2rm=v3rm= ... =vnrm). Mode 0 returns the vertex coordinate unchanged and disables rounding for that vertex regardless of vr. Undefined vertices are not rounded.
vfn<integer-list-n> The vertices arc fragment number. A list [v1fn, v2fn, v3fn, ... vnfn] of n integers or a single integer for (v1fn=v2fn=v3fn= ... =vnfn). When any vfn entry is undef, the special variables $fa, $fs, and $fn control facet generation for that vertex.
w<boolean> Wrap-at-end during 3-point coordinate selection. When true (default), the first and last vertices are included in the rounding sequence, connecting the polygon end back to its start. When false, the first and last vertices are returned unmodified, which is useful for open paths where the endpoints should remain fixed.
cw<boolean> Polygon vertex ordering.
Returns
<points-2d> A new list of coordinates points [[x, y], ...] that define the polygon with rounded vertices.

Assumes polygon is defined in 2D space on the x-y plane. There should be no repeating adjacent vertices along the polygon path (ie: no adjacent vertex with identical coordinates). Any vertex determined to be collinear with its adjacent previous and next vertex is returned unmodified.

Each vertex may be individually rounded using one of the following modes:

mode name description
0 none return vertex unchanged
1 round previous to next edge round
2 e-hollow / i-circle previous to next edge inverse round
3 n-fillet next edge pass return fillet
4 p-fillet previous edge pass return fillet
5 chamfer previous to next edge bevel
6 e-circle / i-hollow previous to next edge inverse round
7 n-round next edge pass return round
8 p-round previous edge pass return round
9 n-chamfer next edge pass return bevel
10 p-chamfer previous edge pass return bevel

The following diagrams demonstrate each rounding mode by on the upper right vertex of a rectangular polygon.

Rounding modes diagram
top_1top_2top_3top_4top_5
expand top_1expand top_2expand top_3expand top_4expand top_5
top_6top_7top_8top_9top_10
expand top_6expand top_7expand top_8expand top_9expand top_10

Vertex arc fragments can be specified using vfn. When any vfn entry is undef, the special variables $fa, $fs, and $fn control facet generation. Each vertex is processed using 3-point selection (the previous and following vertex). Collinear vertices (where the previous, current, and next points are co-linear) are automatically detected and returned unmodified regardless of the specified vr and vrm values. The resulting triangle incircles and excircles are used to create the round and fillet arc segments. All arcs and chamfers use constant radius.

Rounding example script

include <omdl-base.scad>;
$fn=36;
c = [[1,1], [1,10], [10,12], [18,2]];
r = [1, 1, 5, 8];
m = [2, 3, 4, 3];
n = [3, 8, undef, undef];
p = polygon_round_eve_all_p(c=c, vr=r, vrm=m, vfn=n);
polygon( p );
// end_include
function polygon_round_eve_all_p(c, vr=0, vrm=1, vfn, w=true, cw=true)
Compute coordinates that round all of the vertices between each adjacent edges in 2D.

Rounding example diagram
top
expand top

+ Here is the caller graph for this function:

◆ polygon_line_wave_p()

function polygon_line_wave_p ( p1  = origin2d,
p2  = x_axis2d_uv,
= 1,
= 1,
= 1,
= 0,
,
fn   
)

Generate 2D coordinate points along a line with periodic waveform lateral displacement.

Parameters
p1<point-2d> The line initial coordinate [x, y].
p2<point-2d> The line terminal coordinate [x, y].
p<decimal> Period length; One full waveform cycle spans this distance along the line arc length.
a<decimal-list-3 | decimal> Amplitude configuration; a list [ma, na, oa] or a single decimal for (ma) (see below).
w<datastruct | integer> Waveform shape configuration; a list [shape, ...] or a single integer for (shape) (see below).
m<datastruct | integer> Time-axis remapping mode configuration; a list [remap, ...] or a single integer for (remap) (see below).
t<decimal-list-2 | decimal> Sampling range configuration; a list [t_min, t_max] or a single decimal for (t_min) (see below).
fn<integer> Period fragment count; overrides the automatically computed step count (see below).
Returns
<points-2d> A list of coordinate points [[x, y], ...] representing the waveform-displaced line, suitable for direct use with polygon().

Computes a sequence of 2D points by walking arc-length steps along the line defined by p1 and p2, displacing each point laterally (perpendicular to the line direction) by a shaped periodic waveform. The unit normal direction is 90° CCW from the line tangent.

The displacement formula applied at each point is:

offset = oa + ma × sign(wave) × |wave|^(1/na)

where wave is the waveform value at the remapped period position u member of [0, 1).

Packed parameters a, w, m, and t each accept either a single scalar (selecting only the primary value) or a list where each index corresponds to a sub-parameter as described in the sections below.

Multi-value and structured parameters

a

e data type default value parameter description
0 decimal 1 ma : maximum amplitude; peak perpendicular displacement from the line
1 decimal 1 na : nonlinear amplitude exponent; applied after waveform evaluation
2 decimal 0 oa : perpendicular offset; shifts the entire waveform baseline

a[1]:na

v description
<1 peaks flatten, waveform widens
=1 linear, no reshaping
>1 peaks sharpen, waveform narrows

w

Shape selection

v shape sub-parameters
0 none (no displacement)
1 sine -
2 triangle -
3 square -
4 sawtooth -
5 sawtooth reverse -
6 pulse duty
7 trapezoid rise, hold, fall
8 sine abs -
9 sine half -
10 lookup table lut

All waveforms are normalized to [-1, 1] before amplitude scaling, so ma always represents the true peak displacement regardless of shape.

Sub-parameters: pulse (shape=6)

e data type default value parameter description
1 decimal 1/2 duty : fraction of the period spent at +1; range (0, 1)

Sub-parameters: trapezoid (shape=7)

e data type default value parameter description
1 decimal 1/4 rise : fraction of the period ramping from -1 to +1
2 decimal rise hold : fraction of the period at +1 (top hold)
3 decimal hold fall : fraction of the period ramping from +1 to -1
Warning
w_rise + w_hold + w_fall must be <= 1.0. The remainder is the implicit bottom-hold duration.

Sub-parameters: lookup table (shape=10)

e data type default value parameter description
1 decimal-list [0, 1] lut : list of amplitude values defining one period

The values should be in [-1, 1] with a minimum 2 entries. The table is treated as periodic with interpolation between the last and first entry handles smooth looping

m

Mode selection

v mode description sub-parameters
0 none no remapping; waveform evaluated at natural u -
1 phase shifts peak and zero-crossings by a period fraction shift
2 skew warps time axis; peak repositioned, zero-crossings fixed at boundaries shift
3 blend interpolates in u-space between phase and skew before waveform evaluation phase, skew, blend

Sub-parameters: phase (mode=1)

e data type default value parameter description
1 decimal 1/2 shift : fraction of the period to shift

The range is [0, 1] where 0.0 = no shift, 0.5 = half-period shift (waveform inverts), 1.0 = full shift identical to 0.0.

Sub-parameters: skew (mode=2)

e data type default value parameter description
1 decimal 1/2 shift : fractional position within the period where the peak lands

The range is (0, 1), clamped internally at grid_fine with 0.25 = fast rise / slow fall, 0.5 = symmetric no skew, 0.75 = slow rise / fast fall.

Sub-parameters: blend (mode=3)

e data type default value parameter description
1 decimal 1/2 phase : phase-shift amount
2 decimal 1/2 skew : skew target position
3 decimal 1/2 blend : interpolation weight

In blend mode, three sub-parameters work together to shape the waveform. phase shifts the peak and zero-crossings together by a fraction of the period, range [0, 1]. skew warps the time axis to reposition the peak at a fractional position within the period while the zero-crossings remain fixed at the period boundaries, range (0, 1). blend controls the interpolation weight between the two axes; 0.0 yields pure phase shift, 1.0 yields pure skew, and 0.5 applies an equal mix of both.

t

e data type default value parameter description
0 decimal 0 t_min : start of the sampling range;
1 decimal t_min + 1 t_max : end of the sampling range;

The arc length at t_min = t_min × |p2 - p1|; 0.0 = starts at p1; negative values extend behind p1. The arc length at t_max = t_max × |p2 - p1|; 1.0 = ends at p2; values above 1.0 extend beyond p2.

The waveform phase is continuous across both boundaries. Period counting begins at p1 (t=0) and extends in both directions. Setting t_min < 0 or t_max > 1 does not clamp; the line direction and waveform extend naturally and indefinitely in either direction. The segment p1 to p2 defines orientation and scale only; it is not a hard boundary.

fn

When undefined, the fragment count is derived from get_fn(ma). See get_fn() for more information.

The total number of sampled points is:

steps = ceil( (len × (t_max - t_min) / p) × fn ) + 1

where len = |p2 - p1|. Choosing an appropriate value:

  • Period: at minimum 20 fragments per period for smooth sine curves; sawtooth and triangle need fewer.
  • Nonlinearity: for na > 3, consider doubling the base fragment count to resolve sharp peaks.
  • Waveform: square and pulse have hard transitions that no fragment count can perfectly resolve; fragment count affects only the flat regions for these shapes.

Line wave example script

include <omdl-base.scad>;
(
p2 = [200, 0],
p = 40,
a = [15, 1]
);
polygon(p);
// end_include
function polygon_line_wave_p(p1=origin2d, p2=x_axis2d_uv, p=1, a=1, w=1, m=0, t, fn)
Generate 2D coordinate points along a line with periodic waveform lateral displacement.

Line wave example diagram
top
expand top