Comparing version 0.11.6 to 0.12.0
@@ -64,3 +64,3 @@ # FOLD API | ||
second array is empty. | ||
* `FOLD.filter.cutEdges(fold, es)`: | ||
* `FOLD.filter.splitCuts(fold, [es])`: | ||
Given a FOLD object with `edges_vertices`, `edges_assignment`, and | ||
@@ -76,2 +76,5 @@ counterclockwise-sorted `vertices_edges` | ||
but ignores face properties. | ||
If `es` is unspecified, cuts all edges with an assignment of `"C"`, | ||
effectively switching from FOLD 1.2's `"C"` assignments to | ||
FOLD 1.1's `"B"` assignments. | ||
* `FOLD.filter.transform(fold, matrix)`: | ||
@@ -78,0 +81,0 @@ Transforms a FOLD object by a given transformation `matrix` (generated by |
@@ -7,2 +7,17 @@ # History of FOLD Specifications | ||
## Version 1.1 | ||
* Rename `edges_foldAngles` -> `edges_foldAngle` and `edges_lengths` -> `edges_length` for consistent pluralization with the rest of the spec. | ||
* Rename `edges_foldAngles` → `edges_foldAngle` and | ||
`edges_lengths` → `edges_length` | ||
for consistent pluralization with the rest of the spec. | ||
## Version 1.2 | ||
* Add join edge (`"J"`) option to `edges_assignment`. | ||
* Add cut/slit edge (`"C"`) option to `edges_assignment` (optional). | ||
* Add `joins`/`noJoins` and `cuts`/`noCuts` to `frame_attributes`. | ||
* Add `convexFaces`/`nonconvexFaces` to `frame_attributes`. | ||
* Define `vertices_edges` and `faces_faces`. | ||
* Extend definition of `vertices_faces`, `edges_faces`, and `faces_faces` | ||
to allow `null` values, allowing for consistent ordering of all arrays and | ||
consistent orientation. | ||
* Specify correspondence between "faces" and "material", to clarify that the | ||
exterior (unbounded) face of a planar graph is not typically a face. | ||
* Clarify that support for multiple frames is optional. |
188
doc/spec.md
@@ -1,2 +0,2 @@ | ||
# [FOLD](https://github.com/edemaine/fold/) Specification (version 1.1) | ||
# [FOLD](https://github.com/edemaine/fold/) Specification (version 1.2) | ||
@@ -89,3 +89,4 @@ This specification is still considered a rough draft, with everything subject | ||
* `file_spec`: The version of the FOLD spec that the file assumes | ||
(a number). See the top of this spec for the current value. | ||
(a number). See the top of this spec for the current value, | ||
and [history](history.md) for differences between versions. | ||
**Strongly recommended**, in case we ever have to make | ||
@@ -142,17 +143,20 @@ backward-incompatible changes. | ||
--> | ||
* `"manifold"`: the polyhedral complex is a manifold | ||
* `"manifold"` / `"nonManifold"`: | ||
whether the polyhedral complex is a manifold | ||
(has at most two faces incident to each edge) | ||
* `"nonManifold"`: the polyhedral complex is *not* a manifold | ||
(has more than two faces incident to an edge) | ||
* `"orientable"`: the polyhedral complex is orientable, meaning it can be | ||
* `"orientable"` / `"nonOrientable"`: | ||
whether the polyhedral complex is orientable, meaning it can be | ||
assigned a consistent normal direction (and hence it is also manifold) | ||
* `"nonOrientable"`: the polyhedral complex is not orientable, meaning it | ||
cannot be assigned a consistent normal direction | ||
* `"selfTouching"`: the polyhedral complex has faces that touch in their | ||
relative interiors, so you probably want a face ordering | ||
* `"nonSelfTouching"`: the polyhedral complex has no touching faces, | ||
so face ordering isn't needed | ||
* `"selfIntersecting"`: the polyhedral complex has properly intersecting faces | ||
* `"nonSelfIntersecting"`: the polyhedral complex has no properly | ||
intersecting faces | ||
* `"selfTouching"` / `"nonSelfTouching"`: | ||
whether the polyhedral complex has faces that touch in their | ||
relative interiors, in which case you probably want a face ordering | ||
* `"selfIntersecting"` / `"nonSelfIntersecting"`: | ||
whether the polyhedral complex has properly intersecting faces | ||
* `"cuts"` / `"noCuts"`: | ||
whether any edges have an assignment of `"C"` | ||
(cut/slit representing multiple `"B"` edges) | ||
* `"joins"` / `"noJoins"`: | ||
whether any edges have an assignment of `"J"` (join) | ||
* `"convexFaces"` / `"nonConvexFaces"`: | ||
whether all faces are convex polygons, or some are nonconvex | ||
* Custom attributes should have a colon in them; | ||
@@ -179,3 +183,3 @@ see [Custom Properties](#custom-properties) below. | ||
such as `[x, y, z]` or `[x, y]` (where `z` is implicitly zero). | ||
In higher dimensions, all unspecified coordinates are implicitly zero. | ||
In higher dimensions, all trailing unspecified coordinates are implicitly zero. | ||
**Recommended** except for frames with attribute `"abstract"`. | ||
@@ -187,3 +191,3 @@ <!--**Required** for frames with attribute `"concrete"`.--> | ||
around the vertex (possibly repeating a vertex more than once). | ||
If the frame is a nonorientable manifold, this list should be cyclicly | ||
If the frame is a nonorientable manifold, this list should be cyclically | ||
ordered around the vertex (possibly repeating a vertex). | ||
@@ -194,13 +198,28 @@ Otherwise, the order is arbitrary. | ||
`edges_vertices` as needed). | ||
* `vertices_edges`: For each vertex, an array of edge IDs for the edges | ||
incident to the vertex. If the frame represents an orientable manifold, | ||
this list should be ordered counterclockwise around the vertex. | ||
If the frame is a nonorientable manifold, this list should be cyclically | ||
ordered around the vertex. | ||
In all cases, the linear order should match `vertices_vertices` if both | ||
are specified: `vertices_edges[v][i]` should be an edge connecting vertices | ||
`v` and `vertices_vertices[v][i]`. | ||
* `vertices_faces`: For each vertex, an array of face IDs for the faces | ||
incident to the vertex. If the frame represents an orientable manifold, | ||
incident to the vertex, possibly including `null`s. | ||
If the frame represents a manifold, `vertices_faces` should align with | ||
`vertices_vertices` and/or `vertices_edges`: | ||
`vertices_faces[v][i]` should be either | ||
* the face containing vertices | ||
`vertices_vertices[v][i]` and `vertices_vertices[v][(i+1)%d]` and | ||
containing edges `vertices_edges[v][i]` and `vertices_edges[v][(i+1)%d]`, | ||
where `d` is the degree of vertex `v`; or | ||
* `null` if such a face doesn't exist. | ||
If the frame represents an orientable manifold, | ||
this list should be ordered counterclockwise around the vertex | ||
(possibly repeating a face more than once). If the frame is a nonorientable | ||
manifold, this list shoudl be cyclicly ordered around the vertex | ||
manifold, this list should be cyclically ordered around the vertex | ||
(possibly repeating a vertex), and matching the cyclic order of | ||
`vertices_vertices` (if both are specified). | ||
In addition to the matching cyclic order, `vertices_vertices` and | ||
`vertices_faces` should align in start so that | ||
`vertices_faces[v][i]` contains vertices `vertices_vertices[v][i]` and | ||
`vertices_vertices[v][(i+1)%d]` where `d` is the degree of vertex `v`. | ||
`vertices_vertices` and/or `vertices_edges` (if either is specified). | ||
@@ -217,15 +236,32 @@ ## Edge information: `edges_...` | ||
(e.g., to represent mountain-valley assignment). | ||
<!-- | ||
* `edges_edges`: For each edge, an array of edge IDs for the edges incident | ||
to (either endpoint of) the edge. If the frame is a manifold, | ||
the edges should be listed in cyclic order around the edge (concatenating | ||
some cyclic shift of `vertices_edges` for the two endpoints); and if the | ||
frame is an oriented manifold, the order should be counterclockwise. | ||
(This property is defined for completeness, but may not be particularly useful.) | ||
--> | ||
* `edges_faces`: For each edge, an array of face IDs for the faces incident | ||
to the edge. The faces should be listed in counterclockwise order around | ||
the edge. For manifolds, this array has length 1 (for boundary edges) | ||
or 2 (for nonboundary edges). When the array has length 2, the canonical | ||
ordering is to start with the face locally to the left of the edge | ||
(as defined by its orientation in `edges_vertices`). | ||
to the edge, possibly including `null`s. | ||
For nonmanifolds in particular, the (nonnull) faces should be listed in | ||
counterclockwise order around the edge, | ||
relative to the orientation of the edge. | ||
For manifolds, the array for each edge should be an array of length 2, | ||
where the first entry is the face locally to the "left" of | ||
the edge (or `null` if there is no such face) and the second entry is the | ||
face locally to the "right" of the edge (or `null` if there is no such face); | ||
for orientable manifolds, "left" and "right" must be consistent with the | ||
manifold orientation given by the counterclockwise orientation of faces. | ||
However, a boundary edge may also be represented by a length-1 array, with | ||
the `null` omitted, to be consistent with the nonmanifold representation. | ||
* `edges_assignment`: For each edge, a string representing its fold | ||
direction assignment: | ||
* `"B"`: border/boundary edge (only one incident face) | ||
* `"M"`: mountain fold | ||
* `"V"`: valley fold | ||
* `"F"`: flat (unfolded) fold | ||
* `"U"`: unassigned/unknown | ||
* `"M"`: mountain crease | ||
* `"V"`: valley crease | ||
* `"F"`: flat (unfolded) crease | ||
* `"U"`: unassigned/unknown crease | ||
* `"C"`: cut/slit edge (should be treated as multiple `"B"` edges) | ||
* `"J"`: join edge (incident faces should be treated as a single face) | ||
@@ -236,8 +272,44 @@ For example, this property can be used to specify a full mountain-valley | ||
For orientable manifolds, a valley fold points the two face normals into | ||
each other, while a mountain fold makes them point away from each other. | ||
For nonorientable manifolds, a valley fold is defined as bringing the normal | ||
of the face to the left of the edge (listed first in `edges_faces`) to point | ||
into the adjacent face (when fully folded), while a mountain fold has the | ||
same normal point away from the adjacent face. | ||
* **Folded edges** | ||
* For orientable manifolds, a valley crease (`"V"`) points the two | ||
face normals into each other, | ||
while a mountain crease (`"M"`) makes them point away from each other. | ||
For nonorientable manifolds, a valley fold is defined as bringing the | ||
normal of the face to the left of the edge | ||
(listed first in `edges_faces`) | ||
to point into the adjacent face (when fully folded), | ||
while a mountain fold has the | ||
same normal point away from the adjacent face. | ||
* An unassigned/unknown crease (`"U"`) is a crease that could be mountain | ||
or valley or (in some cases) flat, but it is unknown which. | ||
* **Unfolded edges** | ||
* Flat creases (`"F"`) represent creases that are present but not folded | ||
(not mountain or valley). | ||
* Join edges (`"J"`) represent edges that are present only for modeling | ||
purposes, and are insignificant from an origami perspective: | ||
the incident faces should in fact be treated as a single effective face. | ||
Join edges enable the modeling of one effective face that is both above | ||
and below another effective face, and effective faces with holes. | ||
Join edges are also appropriate for triangulation edges used in | ||
simulation but which are not meaningful otherwise. | ||
If you use join edges, we recommend including | ||
`"joins"` in [`frame_attributes`](#frame-metadata-frame_). | ||
*Added in version 1.2.* | ||
* **Boundary edges** | ||
* A boundary edge (`"B"`) has only one incident face. | ||
* A cut/slit edge (`"C"`) is shorthand for two (or more for nonmanifold) | ||
boundary edges at the same location. | ||
This is useful for e.g. drawing programs to enable | ||
simple toggling of slits in a crease pattern without having to | ||
convert back and forth from a multiple-`"B"`-edge representation. | ||
Mechanical modeling should treat such edges as separate boundary (`"B"`) | ||
edges, one per face, with incident `"C"` edges connecting together into | ||
larger slits/holes. | ||
Support for `"C"` edges is **optional**, so is not expected to be | ||
implemented by all software supporting the FOLD format. | ||
Implement only for applications where it is useful, | ||
limited to locally nonoverlapping, locally manifold surfaces. | ||
If you use cut edges, we recommend including | ||
`"cuts"` in [`frame_attributes`](#frame-metadata-frame_). | ||
*Added in version 1.2.* | ||
* `edges_foldAngle`: For each edge, the fold angle (deviation from flatness) | ||
@@ -249,2 +321,3 @@ along each edge of the pattern. The fold angle is a number in degrees | ||
`edges_assignment` if both are specified. | ||
*Renamed from `edges_foldAngles` in version 1.1.* | ||
* `edges_length`: For each edge, the length of the edge (a number). | ||
@@ -254,5 +327,10 @@ This is mainly useful for defining the intrinsic geometry of | ||
otherwise, `edges_length` can be computed from `vertices_coords`. | ||
*Renamed from `edges_lengths` in version 1.1.* | ||
## Face information: `faces_...` | ||
Faces in a FOLD file should correspond to the "material" being folded. | ||
In particular, they do not typically include the exterior (unbounded) face | ||
of a planar graph such as a crease pattern. | ||
The values of the following properties are zero-indexed arrays by face ID. | ||
@@ -269,2 +347,9 @@ | ||
`faces_vertices[f][(i+1)%d]` where `d` is the degree of face `f`. | ||
* `faces_faces`: For each face, an array of face IDs for the faces *sharing | ||
edges* around the face, possibly including `null`s. | ||
If the frame is a manifold, the faces should be listed in counterclockwise | ||
order and in the same linear order as `faces_edges` (if it is specified): | ||
`f` and `faces_faces[f][i]` should be the faces incident to the edge | ||
`faces_edges[f][i]`, unless that edge has no face on the other side, | ||
in which case `faces_faces[f][i]` should be `null`. | ||
@@ -276,2 +361,13 @@ The counterclockwise ordering of each face defines the side/sign of its | ||
The layer ordering of a folded state is normally defined pointwise | ||
(λ(*p*, *q*) for two noncrease points *p* and *q* of paper | ||
that fold to the same point). FOLD does not directly represent such points, | ||
and instead works with entire faces (or edges for the case of linkages). | ||
Two faces have a consistent "above" or "below" relationship only if | ||
they overlap in a single connected region. For example, this property | ||
is guaranteed by convex faces. If your faces overlap in multiple regions, | ||
you should subdivide them (via `"J"` join edges) so that they do not. | ||
We recommend specifying either `"convexFaces"` or `"nonConvexFaces"` | ||
in [`frame_attributes`](#frame-metadata-frame_). | ||
* `faceOrders`: An array of triples `[f, g, s]` where `f` and `g` are face IDs | ||
@@ -297,2 +393,7 @@ and `s` is an integer between −1 and 1: | ||
Note that the specified ordering on faces may have cycles (e.g., | ||
in a square twist). For visualization purposes, you may want to | ||
subdivide faces (e.g., at overlapping face boundaries) | ||
so that the face ordering is a partial order. | ||
**Recommended** for frames with interior-overlapping faces. | ||
@@ -316,3 +417,3 @@ | ||
which are about the entire file) can appear in the top-level dictionary | ||
*or* within an individiaul frame. Properties in the top-level dictionary | ||
*or* within an individual frame. Properties in the top-level dictionary | ||
describes the **key frame** (frame 0). | ||
@@ -323,3 +424,3 @@ If your file consists of just one frame, that's all you need to know. | ||
to store all frames beyond the key frame. The value of the | ||
`file_frames` property is an array of dictonaries, where | ||
`file_frames` property is an array of dictionaries, where | ||
`file_frames[i]` represents frame `i+1` (because frame 0 is the key frame). | ||
@@ -341,2 +442,7 @@ Each frame dictionary can have any of the properties described above | ||
Support for multiple frames is **optional**, so is not expected to be | ||
implemented by all software supporting the FOLD format. | ||
Software not implementing support for multiple frames should ignore all | ||
`frames` properties and use only the key frame. | ||
## Custom Properties | ||
@@ -343,0 +449,0 @@ |
@@ -310,2 +310,4 @@ /* FOLD FORMAT MANIPULATORS */ | ||
(indicating which edges are boundary with 'B'). | ||
This code currently assumes an orientable manifold, and uses nulls to | ||
represent missing neighbor faces in `edges_faces` (for boundary edges). | ||
*/ | ||
@@ -312,0 +314,0 @@ mesh.edges_vertices = []; |
@@ -41,2 +41,10 @@ var RepeatedPointsDS, filter, geom, | ||
filter.cutEdges = function(fold) { | ||
return filter.edgesAssigned(fold, 'C'); | ||
}; | ||
filter.joinEdges = function(fold) { | ||
return filter.edgesAssigned(fold, 'J'); | ||
}; | ||
filter.keysStartingWith = function(fold, prefix) { | ||
@@ -672,3 +680,3 @@ var key, results; | ||
filter.cutEdges = function(fold, es) { | ||
filter.splitCuts = function(fold, es = filter.cutEdges(fold)) { | ||
var b, b1, b2, boundaries, e, e1, e2, ev, i, i1, i2, ie, ie1, ie2, k, l, len, len1, len2, len3, len4, len5, len6, len7, len8, m, n, neighbor, neighbors, o, q, r, ref, ref1, ref10, ref2, ref3, ref4, ref5, ref6, ref7, ref8, ref9, t, u1, u2, v, v1, v2, ve, vertices_boundaries, z; | ||
@@ -687,2 +695,5 @@ if (!es.length) { | ||
but ignores face properties. | ||
`es` is unspecified, cuts all edges with an assignment of `"C"`, | ||
effectively switching from FOLD 1.2's `"C"` assignments to | ||
FOLD 1.1's `"B"` assignments. | ||
*/ | ||
@@ -689,0 +700,0 @@ return fold; |
{ | ||
"name": "fold", | ||
"version": "0.11.6", | ||
"version": "0.12.0", | ||
"description": "FOLD file format for origami models, crease patterns, etc.", | ||
@@ -5,0 +5,0 @@ "main": "lib/index.js", |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
361483
6793