ORIGAMI MATH

The mathematics of ancient Greece, linear algebra, and graph data structures come together in origami math.

RabbitEar.math

Contents

RabbitEar
┃
┣━ Vector
┣━ Matrix2
┣━ Line
┣━ Ray
┣━ Edge
┣━ Junction
┣━ Sector
┣━ Rectangle
┣━ Circle
┣━ Polygon
┣━ ConvexPolygon
┗━ math

Point / Vector

Consider this object from two perspectives:

• a point in space, as measured from the origin (0,0)
• a translation away from another point in space

We call this object a vector.

let point = Vector(0.5, 0.666)point.normalize()

Notice the y axis is positive in the downwards direction. I didn't make this decision, it's a computer graphics standard. The SVG is simply drawing in its coordinate frame. If you want to flip the +Y axis is not difficult, but it's on you.

This vector object works in N-dimensions, not limited to 2D.

blue1 = red1.lerp(red2, t)blue2 = red2.lerp(red3, t)yellow = blue1.lerp(blue2, t)

This vector object is immutable. Each vector operation returns a new, transformed vector.

This immutability pattern is generally reflected throughout the entire library.

// return a bool
function isEquivalent(vector)
function isParallel(vector)
// return a number
function dot(vector)
function cross(vector) // vector, in 3D+
function magnitude()
function distanceTo(vector)
// return a vector
function subtract(vector)

function normalize()
function scale(magnitude)
function midpoint(vector)
function lerp(vector, magnitude)

function transform(matrix)
function reflect(line)          // 2D
function rotateZ(angle, origin) // 2D
function bisect(vector)         // 2D

Remember point and vector; two ways of looking at the same object. Ask yourself which one you are dealing with. A point might rarely use magnitude() but often uses distanceTo(), and a vector would be the opposite.

MATRIX

Matrices are powerful representations of geometric transformations. Inside of one matrix can contain instructions for any number of rotations, translations, reflections, scaling, shearing; and it can tell you things like whether a polygon has been flipped over.

One transform in particular is especially useful to origami: reflection. Folding an origami is two steps:

1. Along the crease line, divide the polygon into two.
2. reflect one face across the crease line and lie it on top of the other.

Reflection

A 2x2 matrix is sufficient to represent a reflection. However a problem arises: all the lines of reflection must pass through the origin. There are two solutions:

• translate your geometry to the origin, perform the reflection, translate it back.
• append a 1x2 column to the reflection matrix, encoding the translation: (tx, ty)

Any line type (Line, Ray, Edge) can be turned into a reflection matrix.

let matrix = edge.reflection()

Lines, Rays, Segments

Lines extend infinitely in both directions, rays extend infinitely in one direction, and line segments, or edges are bound by two endpoints.

let line = Line()let ray = Ray()let segment = Edge()

Line and Ray are initialized with a point and a direction, Edge is initialized with two endpoints:

Line(point, vector)Ray(point, vector)Edge(point_a, point_b)

All three types contain a point and a vector (even the Edge). Uniquely, an Edges's endpoints can be accessed with array syntax:

// line, ray, edgeline.pointline.vector// edge onlyedgeedge

We can ask two lines to bisect. In the unique case these lines are parallel, there is only one solution. Otherwise, this method returns an array of two lines and always sorts one first: the bisection of the smaller interior angle when the dot product is > 0.

This operation is analogous to origami axiom #3.

lineA.bisect(lineB)

The nearest point on a line can be located by projecting the point down to the line, along the line's normal.

In the case of rays and segments, the projection might lie beyond the endpoints. The nearest point is set to that endpoint.

let point = edge.nearestPoint()

Circle

These circles are constrained to a square space and maintain relative radii as they grow to best fit.

a preliminary step in circle-river origami design is circle-packing.

Polygon

A Polygon is a ordered set of points which defines the boundary. This ConvexPolygon is built using the convex hull algorithm, and it can clip lines, rays, and edges.

The convex hull algorithm performed on a collection of points

let polygon = Polygon(pointA, pointB, ...)

Intersections

The intersection between a line and a convex polygon can result in:

• 0: no intersection
• 1: collinear to a point
• 2: intersects the polygon
• Infinity: collinear to an edge
 = poly.clipline(line)

Edges and rays can result in a similar set, but one difference:

• 1: it's possible one point is inside and one outside

A non-convex polygon cannot make such guarantees.

A straight skeleton is a Voronoi diagram of the edges of the polygon. Both the fold-and-one-cut algorithm and the origami universal molecule employ the straight skeleton.

straight skeleton code is under construction

let clipped = polygon.clipEdge( Edge(0.5, 0, 0.5, 1) )

Clipping functions return an edge with a new set of endpoints.

ANGLES

The space between two vectors creates two interior angles. It's important to distinguish between vectors a and b the clockwise or the counter-clockwise interior angle.

Bisect

Two vectors bisected results in two answers. This function will return the bisection of the smaller interior angle first.

bisect(vec1, vec2)

APPENDIX

This math library is a free and open-source independent module.

Core

The core is where the computation occurs, everything above is calling methods in here.

RabbitEar
┃
┣━ Circle
┣━ ConvexPolygon
┣━ ...
┗━ math

The core was built for speed; there is no type checking. Things will be more reliable if you avoid this section.