-
Notifications
You must be signed in to change notification settings - Fork 29
/
Copy pathparser.js
138 lines (120 loc) · 3.93 KB
/
parser.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
// Polyhédronisme
//===================================================================================================
//
// A toy for constructing and manipulating polyhedra and other meshes
//
// Copyright 2019, Anselm Levskaya
// Released under the MIT License
// Parser Routines
//===================================================================================================
// fairly straightforward Parser Expression Grammar spec for simple
// operator-chain-on-base-polyhedra recipes
const PEG_parser_spec = `\
/* series of opspecs */
start = opspec+
/* opspec one of:
A - single letter
A3 - single letter and float
B(5,4.3,3) - function call format w. float args
*/
opspec =
let:opcode args:opargs {return {"op":let,"args":args};}
/ let:opcode float:float {return {"op":let,"args":[float]};}
/ let:opcode {return {"op":let,"args":[]};}
/*
parentheses surrounding comma-delimited list of floats i.e.
( 1 , 3.2, 4 ) or (1) or (2,3)
*/
opargs = "("
num:( float:float ","? {return float} )+
")" {return num;}
/* just a letter */
opcode = op:[a-zA-Z] {return op;}
/* standard numerical types */
int = digits:[0-9-]+ { return parseInt(digits.join(""), 10); }
float = digits:[0-9.-]+ { return parseFloat(digits.join(""), 10); }\
`;
const op_parser = PEG.buildParser(PEG_parser_spec);
//applies func fn to array args i.e. f, [1,2,3] -> f(1,2,3)
const dispatch = function(fn, args) { return fn.apply(this, args || []); };
const basemap = {
"T": tetrahedron,
"O": octahedron,
"C": cube,
"I": icosahedron,
"D": dodecahedron,
"P": prism, //takes integer arg
"A": antiprism, //takes integer arg
"Y": pyramid, //takes integer arg
"J": johnson, //takes integer arg
"U": cupola, //takes integer arg
"V": anticupola, //takes integer arg
};
const opmap = {
"d": dual,
"a": ambo,
"k": kisN,
"g": gyro,
"p": propellor,
"r": reflect,
"c": chamfer,
"w": whirl,
"n": insetN, //-->needle
"x": extrudeN,
"l": loft,
"P": perspectiva1,
"q": quinto,
"u": trisub,
//z --> zip
"H": hollow,
"Z": triangulate,
"C": canonicalize,
"A": adjustXYZ,
};
//unclaimed: yihfzv
// list of basic equivalences, easier to replace before parsing
const specreplacements = [
[/e/g, "aa"], // e --> aa (abbr. for explode)
[/b/g, "ta"], // b --> ta (abbr. for bevel)
[/o/g, "jj"], // o --> jj (abbr. for ortho)
[/m/g, "kj"], // m --> kj (abbr. for meta)
[/t(\d*)/g, "dk$1d"], // t(n) --> dk(n)d (dual operations)
[/j/g, "dad"], // j --> dad (dual operations) # Why not j --> da ?
[/s/g, "dgd"], // s --> dgd (dual operations) # Why not s --> dg ?
[/dd/g, ""], // dd --> null (order 2)
[/ad/g, "a"], // ad --> a (a_ = ad_)
[/gd/g, "g"], // gd --> g (g_ = gd_)
[/aO/g, "aC"], // aO --> aC (for uniqueness)
[/aI/g, "aD"], // aI --> aD (for uniqueness)
[/gO/g, "gC"], // gO --> gC (for uniqueness)
[/gI/g, "gD"]]; // gI --> gD (for uniqueness)
const getOps = function(notation) {
let expanded = notation;
for (let [orig,equiv] of specreplacements) {
expanded = expanded.replace(orig,equiv);
}
console.log(`${notation} executed as ${expanded}`);
return expanded;
};
// create polyhedron from notation
const newgeneratePoly = function(notation) {
//poly = new polyhedron()
const ops_spec = getOps(notation);
const oplist = op_parser.parse(ops_spec).reverse();
let op = oplist.shift();
const basefunc = basemap[op["op"]];
const baseargs = op["args"];
let poly = dispatch(basefunc, baseargs);
for (op of oplist) {
const opfunc = opmap[op["op"]];
const opargs = [poly].concat(op["args"]);
poly = dispatch(opfunc, opargs);
}
// Recenter polyhedra at origin (rarely needed)
poly.vertices = recenter(poly.vertices, poly.edges());
poly.vertices = rescale(poly.vertices);
// Color the faces of the polyhedra for display
poly = paintPolyhedron(poly);
// return the poly object
return poly;
};