MODULE Vertex; IMPORT LR3x3, LR3, LR3Extras, Text, Math; CONST OO = LAST(LONGREAL); PROCEDURE Find(READONLY vertex: List; name: Name): Num = BEGIN WITH n = NUMBER(vertex) DO FOR i := 0 TO n-1 DO IF Text.Equal(vertex[i].name, name) THEN RETURN i END END; RETURN None END END Find; PROCEDURE Copy(READONLY vertex: List; extra: CARDINAL := 0): REF List = BEGIN WITH n = NUMBER(vertex), r = NEW(REF List, n + extra) DO SUBARRAY(r^, 0, n) := vertex; RETURN r END END Copy; PROCEDURE GetNames(READONLY vertex: List; READONLY num: ARRAY OF Num): REF ARRAY OF Name = BEGIN WITH r = NEW(REF ARRAY OF Name, NUMBER(num)), name = r^ DO FOR i := 0 TO LAST(num) DO name[i] := vertex[num[i]].name END; RETURN r END END GetNames; PROCEDURE GetNums( READONLY vertex: List; prefix: TEXT; READONLY name: ARRAY OF Name; ): REF ARRAY OF Num = BEGIN WITH r = NEW(REF ARRAY OF Num, NUMBER(name)), num = r^ DO FOR i := 0 TO LAST(name) DO num[i] := Find(vertex, QualifyName(prefix, name[i])) END; RETURN r END END GetNums; PROCEDURE BoundingBox(READONLY vertex: List): ARRAY [0..1] OF LR3.T = VAR lo := LR3.T{+OO, +OO, +OO}; VAR hi := LR3.T{-OO, -OO, -OO}; BEGIN FOR k := 0 TO LAST(vertex) DO WITH p = vertex[k].c DO FOR i := 0 TO 2 DO lo[i] := MIN(lo[i], p[i]); hi[i] := MAX(hi[i], p[i]) END END END; RETURN ARRAY [0..1] OF LR3.T{lo, hi} END BoundingBox; PROCEDURE RingCurl(READONLY vertex: List; READONLY s: ARRAY OF Num): LR3.T = VAR u, v, d: LR3.T; BEGIN WITH n = NUMBER(s), o = vertex[s[0]].c DO IF n = 2 THEN RETURN LR3.T{0.0d0, ..} END; u := LR3.Sub(vertex[s[1]].c, o); v := LR3.Sub(vertex[s[2]].c, o); d := LR3Extras.Cross(u, v); FOR k := 3 TO LAST(s) DO u := v; v := LR3.Sub(vertex[s[k]].c, o); d := LR3.Add(d, LR3Extras.Cross(u, v)); END; END; RETURN d END RingCurl; PROCEDURE Center(READONLY vertex: List; READONLY num: ARRAY OF Num): LR3.T = VAR c: LR3.T; BEGIN WITH n = NUMBER(num) DO IF n = 0 THEN RETURN LR3.T{0.0d0, ..} END; c := vertex[num[0]].c; FOR k := 1 TO LAST(num) DO c := LR3.Add(c, vertex[num[k]].c); END; IF n > 1 THEN WITH f = FLOAT(n, LONGREAL) DO c[0] := c[0]/f; c[1] := c[1]/f; c[2] := c[2]/f; END; END; RETURN c END END Center; PROCEDURE Map(VAR vertex: List; READONLY R: LR3x3.T; READONLY t: LR3.T) = BEGIN FOR i := 0 TO LAST(vertex) DO WITH c = vertex[i].c DO c := LR3.Add(LR3x3.MapRow(c, R), t) END END END Map; PROCEDURE Scale(VAR vertex: List; sx, sy, sz: LONGREAL) = BEGIN FOR i := 0 TO LAST(vertex) DO WITH c = vertex[i].c DO c := LR3.T{sx * c[0], sy * c[1], sz * c[2]} END END END Scale; PROCEDURE Translate(VAR vertex: List; READONLY t: LR3.T) = BEGIN FOR i := 0 TO LAST(vertex) DO WITH c = vertex[i].c DO c := LR3.Add(c, t) END END END Translate; PROCEDURE Bend(VAR vertex: List; radius: LONGREAL) = BEGIN FOR i := 0 TO LAST(vertex) DO WITH c = vertex[i].c, theta = c[2]/radius, r = radius - c[0] DO c[0] := radius - r * Math.cos(theta); c[2] := r * Math.sin(theta) END; END END Bend; PROCEDURE Twist(VAR vertex: List; rate: LONGREAL) = BEGIN FOR i := 0 TO LAST(vertex) DO WITH c = vertex[i].c, theta = c[2]*rate, cos = Math.cos(theta), sin = Math.sin(theta), x = c[0]*cos - c[1]*sin, y = c[0]*sin + c[1]*cos DO c[0] := x; c[1] := y END; END END Twist; PROCEDURE Taper(VAR vertex: List; zLim: LONGREAL) = BEGIN FOR i := 0 TO LAST(vertex) DO WITH c = vertex[i].c, f = 1.0d0 - c[2]/zLim DO c[0] := f * c[0]; c[1] := f * c[1] END END END Taper; PROCEDURE Bloat(VAR vertex: List; height, factor: LONGREAL) = BEGIN FOR i := 0 TO LAST(vertex) DO WITH c = vertex[i].c, r = c[2]/height, r2 = r*r, alpha = Math.exp(factor*(1.0d0 - r2)/(1.0d0 + r2)) DO c[0] := alpha * c[0]; c[1] := alpha * c[1]; END END END Bloat; PROCEDURE Sag(VAR vertex: List; height, factor: LONGREAL) = BEGIN FOR i := 0 TO LAST(vertex) DO WITH c = vertex[i].c, r = c[2]/height, r2 = r*r, delta = factor * height * (1.0d0 - r2)/(1.0d0 + r2) DO c[0] := c[0] + delta END END END Sag; PROCEDURE Wiggle(VAR vertex: List; height, slope: LONGREAL) = BEGIN FOR i := 0 TO LAST(vertex) DO WITH c = vertex[i].c, r = c[2]/height, r2 = r*r, delta = slope * c[2] * (1.0d0 - r2)/(1.0d0 + r2) DO c[0] := c[0] + delta END END END Wiggle; PROCEDURE Det(READONLY p, q, r, s: LR3.T): LONGREAL = BEGIN WITH M = LR3x3.T{ LR3.T{q[0] - p[0], q[1] - p[1], q[2] - p[2]}, LR3.T{r[0] - p[0], r[1] - p[1], r[2] - p[2]}, LR3.T{s[0] - p[0], s[1] - p[1], s[2] - p[2]} } DO RETURN LR3x3.Det(M) END END Det; PROCEDURE QualifyName(prefix, name: TEXT): TEXT = BEGIN IF Text.Empty(prefix) THEN RETURN name ELSE RETURN prefix & "." & name END END QualifyName; BEGIN END Vertex.