DIRECTORY Draw2d, G2dBasic, G2dVector, G3dBasic, G3dDraw, G3dMatrix, G3dModel, G3dPlane, G3dPolygon, G3dShape, G3dSpline, G3dVector, Imager, Real, RefTab, Rope, RuntimeError; G3dModelImpl: CEDAR MONITOR IMPORTS G2dBasic, G2dVector, G3dBasic, G3dDraw, G3dMatrix, G3dPlane, G3dPolygon, G3dShape, G3dSpline, G3dVector, RefTab, RuntimeError EXPORTS G3dModel ~ BEGIN DrawType: TYPE ~ Draw2d.DrawType; Border: TYPE ~ G3dBasic.Border; Box: TYPE ~ G3dBasic.Box; Pair: TYPE ~ G3dBasic.Pair; Triple: TYPE ~ G3dBasic.Triple; Plane: TYPE ~ G3dPlane.Plane; Ray: TYPE ~ G3dBasic.Ray; Segment: TYPE ~ G3dBasic.Segment; NatSequence: TYPE ~ G3dBasic.NatSequence; NatSequenceRep: TYPE ~ G3dBasic.NatSequenceRep; IntegerPair: TYPE ~ G3dBasic.IntegerPair; IntSequence: TYPE ~ G3dBasic.IntSequence; IntSequenceRep: TYPE ~ G3dBasic.IntSequenceRep; SurfaceSequence: TYPE ~ G3dBasic.SurfaceSequence; SurfaceSequenceRep: TYPE ~ G3dBasic.SurfaceSequenceRep; PairSequence: TYPE ~ G3dBasic.PairSequence; PairSequenceRep: TYPE ~ G3dBasic.PairSequenceRep; TripleSequence: TYPE ~ G3dBasic.TripleSequence; TripleSequenceRep: TYPE ~ G3dBasic.TripleSequenceRep; Matrix: TYPE ~ G3dMatrix.Matrix; Viewport: TYPE ~ G3dMatrix.Viewport; Model: TYPE ~ G3dModel.Model; ModelRep: TYPE ~ G3dModel.ModelRep; NearModel: TYPE ~ G3dModel.NearModel; Polygon: TYPE ~ G3dPolygon.Polygon; PolygonSequenceRep: TYPE ~ G3dPolygon.PolygonSequenceRep; Edge: TYPE ~ G3dShape.Edge; EdgeRep: TYPE ~ G3dShape.EdgeRep; EdgeSequence: TYPE ~ G3dShape.EdgeSequence; Face: TYPE ~ G3dShape.Face; FaceRep: TYPE ~ G3dShape.FaceRep; FaceSequence: TYPE ~ G3dShape.FaceSequence; FaceSequenceRep: TYPE ~ G3dShape.FaceSequenceRep; ScreenSequence: TYPE ~ G3dShape.ScreenSequence; Shape: TYPE ~ G3dShape.Shape; ShapeRep: TYPE ~ G3dShape.ShapeRep; ShapeSequence: TYPE ~ G3dShape.ShapeSequence; SurfaceProc: TYPE ~ G3dShape.SurfaceProc; Vertex: TYPE ~ G3dShape.Vertex; VertexRep: TYPE ~ G3dShape.VertexRep; VertexSequence: TYPE ~ G3dShape.VertexSequence; VertexSequenceRep: TYPE ~ G3dShape.VertexSequenceRep; SplineSequence: TYPE ~ G3dSpline.SplineSequence; SplineSequenceRep: TYPE ~ G3dSpline.SplineSequenceRep; Context: TYPE ~ Imager.Context; ROPE: TYPE ~ Rope.ROPE; BoundsFault: ERROR ~ RuntimeError.BoundsFault; Error: PUBLIC SIGNAL [code: ATOM, reason: ROPE] = CODE; ShapeFromFile: PUBLIC PROC [ fileName: ROPE, points: BOOL ¬ TRUE, polygons: BOOL ¬ FALSE, faceCenters: BOOL ¬ TRUE, faceNormals: BOOL ¬ TRUE, edges: BOOL ¬ TRUE, curves: BOOL ¬ FALSE, normal: BOOL ¬ FALSE, center: BOOL ¬ FALSE, lines: BOOL ¬ FALSE, accs: BOOL ¬ FALSE, area: BOOL ¬ FALSE] RETURNS [s: Shape] ~ { s ¬ G3dShape.ShapeFromFile[fileName]; SetShape[s, points, polygons, faceCenters, faceNormals, edges, curves, normal, center, lines, accs, area]; }; GetModel: PUBLIC PROC [shape: Shape] RETURNS [m: Model] ~ { m ¬ SELECT TRUE FROM shape = NIL => NIL, shape.modelData # NIL => NARROW[shape.modelData], ENDCASE => (shape.modelData ¬ NEW[ModelRep]); }; SetShape: PUBLIC PROC [ shape: Shape, points: BOOL ¬ TRUE, polygons: BOOL ¬ FALSE, faceCenters: BOOL ¬ TRUE, faceNormals: BOOL ¬ TRUE, edges: BOOL ¬ TRUE, curves: BOOL ¬ FALSE, normal: BOOL ¬ FALSE, center: BOOL ¬ FALSE, lines: BOOL ¬ FALSE, accs: BOOL ¬ FALSE, area: BOOL ¬ FALSE] ~ { IF points THEN SetPoints[shape]; IF faceCenters THEN G3dShape.SetFaceCenters[shape]; IF faceNormals AND NOT G3dShape.FaceValid[shape, normal] THEN G3dShape.SetFaceNormals[shape, FALSE]; IF polygons THEN SetPolygons[shape, normal, center, area, accs, lines]; IF edges THEN shape.edges ¬ G3dShape.MakeEdges[shape ! BoundsFault => CONTINUE]; IF curves THEN SetCurves[shape]; }; SetPoints: PUBLIC PROC [shape: Shape] ~ { m: Model ¬ GetModel[shape]; m.points ¬ G3dShape.PointsFromShape[shape, m.points]; }; IsolateVertices: PUBLIC PROC [shape: Shape] ~ { model: Model ¬ GetModel[shape]; nvert, vertno: NAT ¬ 0; old: VertexSequence ¬ shape.vertices; FOR i: NAT IN [0..shape.surfaces.length) DO nvert ¬ nvert+shape.surfaces[i].vertices.length; ENDLOOP; shape.vertices ¬ NEW[VertexSequenceRep[nvert]]; -- allocate new vertices shape.vertices.valid ¬ old.valid; shape.vertices.length ¬ nvert; shape.verticesIsolated ¬ TRUE; FOR i: NAT IN [0..shape.surfaces.length) DO -- for each polygon poly: NatSequence ¬ shape.surfaces[i].vertices; -- this polygon FOR j: NAT IN [0..poly.length) DO -- for each vertex of poly shape.vertices[vertno] ¬ NEW[VertexRep ¬ old[poly[j]]^]; -- new vertex poly[j] ¬ vertno; -- modify index list vertno ¬ vertno+1; ENDLOOP; ENDLOOP; }; DeleteVertices: PUBLIC PROC [shape: Shape, vId0, vId1: NAT] ~ { nPoly: NAT ¬ 0; nDeleted: NAT ¬ ABS[vId1-vId0]+1; FOR n: NAT IN [MIN[vId0, vId1]..shape.vertices.length-nDeleted) DO shape.vertices[n] ¬ shape.vertices[n] ¬ shape.vertices[n+nDeleted]; ENDLOOP; WHILE nPoly < shape.surfaces.length DO poly: NatSequence ¬ shape.surfaces[nPoly].vertices; FOR p: NAT IN [0..poly.length) DO SELECT poly[p] FROM IN [vId0..vId1] => { -- this polygon now bogus FOR n: NAT IN [nPoly..shape.surfaces.length-1) DO shape.surfaces[n] ¬ shape.surfaces[n-1]; ENDLOOP; shape.surfaces.length ¬ shape.surfaces.length-1; LOOP; }; > vId1 => poly[p] ¬ poly[p]-nDeleted; ENDCASE; nPoly ¬ nPoly+1; ENDLOOP; ENDLOOP; }; SetPolygons: PUBLIC PROC [ shape: Shape, normal, center, area, accs, lines: BOOL, complyWithVertices: BOOL ¬ TRUE] ~ { model: Model ¬ GetModel[shape]; normalFromFace: BOOL ¬ normal AND G3dShape.FaceValid[shape, normal]; IF normalFromFace THEN normal ¬ FALSE; -- we'll get from shape.faces IF shape.vertices = NIL AND shape.surfaces = NIL THEN RETURN; IF model.polygons = NIL OR model.polygons.maxLength < shape.surfaces.length THEN model.polygons ¬ NEW[PolygonSequenceRep[shape.surfaces.length]]; model.polygons.length ¬ shape.surfaces.length; FOR n: NAT IN [0..shape.surfaces.length) DO poly: NatSequence ¬ shape.surfaces[n].vertices; polygon: Polygon ¬ model.polygons[n] ¬ NEW[G3dPolygon.PolygonRep]; polygon.points ¬ NEW[TripleSequenceRep[poly.length]]; polygon.points.length ¬ poly.length; polygon.indices ¬ poly; FOR n: NAT IN [0..poly.length) DO polygon.points[n] ¬ shape.vertices[poly[n]].point; ENDLOOP; IF normalFromFace THEN { -- if complyWithVertices, assume faces[n].normal complies v: Triple ¬ shape.faces[n].normal; polygon.plane ¬ [v.x, v.y, v.z, G3dPlane.DFromNormalAndPoints[v, polygon.points]]; IF normalFromFace THEN polygon.normal ¬ v; }; G3dPolygon.SetPolygon[polygon, polygon.points, normal, center, area, accs, lines]; ENDLOOP; IF complyWithVertices AND shape.vertices # NIL AND normal THEN FOR n: NAT IN [0..shape.surfaces.length) DO p: Polygon ¬ model.polygons[n]; v: Triple ¬ IF normal THEN p.normal ELSE [p.plane.x, p.plane.y, p.plane.z]; IF G3dVector.Dot[v, shape.vertices[p.indices[0]].normal] < 0.0 THEN { p.plane ¬ [-p.plane.x, -p.plane.y, -p.plane.z, -p.plane.w]; IF normal THEN p.normal ¬ [-p.plane.x, -p.plane.y, -p.plane.z]; }; ENDLOOP; }; CullBadPolygons: PUBLIC PROC [polygons: SurfaceSequence, maxNVertices: NAT] ~ { n: NAT ¬ 0; DO poly: NatSequence ¬ polygons[n].vertices; FOR nn: NAT IN [0..poly.length) DO IF poly[nn] >= maxNVertices THEN { -- overwrite this polygon polygons.length ¬ polygons.length-1; IF n # polygons.length THEN polygons[n] ¬ polygons[polygons.length]; EXIT; }; REPEAT FINISHED => n ¬ n+1; ENDLOOP; IF n >= polygons.length THEN RETURN; ENDLOOP; }; EnsureModelPolygons: PROC [s: Shape] RETURNS [m: Model] ~ { IF (m ¬ GetModel[s]) # NIL THEN { ok: BOOL ¬ m.polygons # NIL AND m.polygons.length # 0; IF ok THEN { p: Polygon ¬ m.polygons[0]; ok ¬ p.plane # [] AND p.accs # NIL AND p.lines # NIL; }; IF NOT ok THEN SetPolygons[s, TRUE, TRUE, FALSE, TRUE, TRUE]; }; }; IntersectWithRay: PUBLIC PROC [shape: Shape, ray: Ray] RETURNS [near: NearModel] ~ { model: Model ¬ EnsureModelPolygons[shape]; minSqDistance: REAL ¬ Real.LargestNumber; IF model = NIL THEN RETURN; FOR n: NAT IN [0..model.polygons.length) DO polygon: Polygon ¬ model.polygons[n]; pdDot: REAL ¬ G3dVector.Dot[polygon.normal, ray.axis]; -- see G3dPlaneImpl IF pdDot # 0.0 THEN { alpha: REAL ¬ (-polygon.plane.w-G3dVector.Dot[polygon.normal, ray.base])/pdDot; IF alpha >= 0.0 THEN { -- if < 0.0 then no intersection in direction of ray intersection: Triple ¬ G3dVector.ScaleRay[ray, alpha]; sqDistance: REAL ¬ G3dVector.SquareDistance[intersection, ray.base]; IF sqDistance < minSqDistance THEN { IF G3dPolygon.InsidePolygon[intersection, polygon] # outside THEN { minSqDistance ¬ sqDistance; near ¬ [intersection, FALSE, n]; }; }; }; }; ENDLOOP; }; ClosestPoint: PUBLIC PROC [shape: Shape, point: Triple] RETURNS [near: NearModel] ~ { model: Model ¬ EnsureModelPolygons[shape]; minDistance: REAL ¬ Real.LargestNumber; IF model # NIL THEN FOR n: NAT IN [0..model.polygons.length) DO polygon: Polygon ¬ model.polygons[n]; nearPolygon: G3dPolygon.NearPolygon ¬ G3dPolygon.NearestToPolygon[polygon, point]; IF nearPolygon.distance < minDistance THEN { near ¬ [nearPolygon.point, FALSE, n]; minDistance ¬ nearPolygon.distance; }; ENDLOOP; }; ShapeFromRevolvedCurve: PUBLIC PROC [ curve: PairSequence, axis: Ray, res: NAT, start: NAT ¬ 0, stop: NAT ¬ LAST[NAT]] RETURNS [s: Shape] ~ { newStop: NAT ¬ MIN[res, stop]; nStrips: NAT ¬ IF start < newStop THEN newStop-start ELSE res-start+newStop; mat: G3dMatrix.Matrix ¬ G3dMatrix.ObtainMatrix[]; nthVertex, nthPolygon: CARD ¬ 0; nPolygons: CARD ¬ nStrips*(curve.length-1); nVertices: CARD ¬ (IF nStrips = res THEN nStrips ELSE nStrips+1)*curve.length; curveNormals: PairSequence ¬ NormalsFromCurve[curve]; s ¬ NEW[ShapeRep]; s.surfaces ¬ NEW[SurfaceSequenceRep[nPolygons]]; s.vertices ¬ NEW[VertexSequenceRep[nVertices]]; s.surfaces.length ¬ nPolygons; s.vertices.length ¬ nVertices; s.vertices.valid[normal] ¬ TRUE; FOR n: NAT IN [0..IF nStrips = res THEN nStrips-1 ELSE nStrips] DO a: NAT ¬ (n+start) MOD res; theta: REAL ¬ 2.0*G3dBasic.PI*REAL[a]/REAL[res]; mat ¬ G3dMatrix.MakeRotateAbout[axis.axis, theta, FALSE, axis.base, mat]; FOR i: NAT IN [0..curve.length) DO p: Pair ¬ curve[i]; pn: Pair ¬ curveNormals[i]; v: Vertex ¬ s.vertices[nthVertex] ¬ NEW[VertexRep]; v.point ¬ G3dMatrix.Transform[[p.x, 0.0, p.y], mat]; v.normal ¬ G3dMatrix.TransformVec[[pn.x, 0.0, pn.y], mat]; nthVertex ¬ nthVertex+1; ENDLOOP; ENDLOOP; FOR n: NAT IN [0..nStrips) DO FOR i: NAT IN [0..curve.length-1) DO p: NatSequence ¬ s.surfaces[nthPolygon].vertices ¬ NEW[NatSequenceRep[4]]; p.length ¬ 4; p[0] ¬ n*curve.length+i; p[1] ¬ p[0]+1; p[2] ¬ (p[1]+curve.length) MOD nVertices; p[3] ¬ (p[0]+curve.length) MOD nVertices; nthPolygon ¬ nthPolygon+1; ENDLOOP; ENDLOOP; G3dMatrix.ReleaseMatrix[mat]; }; ShapeFromPointsPolys: PUBLIC PROC [ name: ROPE, points: TripleSequence, polys: SurfaceSequence] RETURNS [s: Shape] ~ { s ¬ NEW[ShapeRep ¬ [name: name, surfaces: polys, matrix: G3dMatrix.Identity[]]]; s.vertices ¬ NEW[VertexSequenceRep[points.length]]; s.vertices.length ¬ points.length; FOR n: NAT IN [0..points.length) DO s.vertices[n] ¬ NEW[VertexRep ¬ [point: points[n]]]; ENDLOOP; s.objectExtent ¬ G3dShape.BoundingBox[s]; }; PolyFromTwoPoints: PROC [n0, n1: NAT] RETURNS [poly: NatSequence] ~ { poly ¬ NEW[NatSequenceRep[2]]; poly[0] ¬ n0; poly[1] ¬ n1; poly.length ¬ 2; }; ShapeFrom2dCurve: PUBLIC PROC [name: ROPE, curve: PairSequence] RETURNS [s: Shape] ~ { IF curve # NIL AND curve.length > 1 THEN { triples: TripleSequence ¬ NEW[TripleSequenceRep[curve.length]]; triples.length ¬ curve.length; FOR n: NAT IN [0..curve.length) DO p: Pair ¬ curve[n]; triples[n] ¬ [p.x, 0.0, p.y]; ENDLOOP; s ¬ ShapeFrom3dCurve[name, triples]; }; }; ShapeFrom3dCurve: PUBLIC PROC [name: ROPE, curve: TripleSequence] RETURNS [s: Shape] ~ { IF curve # NIL AND curve.length > 1 THEN { polys: SurfaceSequence ¬ NEW[SurfaceSequenceRep[curve.length-1]]; polys.length ¬ curve.length-1; FOR n: NAT IN [0..curve.length-1) DO polys[n].vertices ¬ PolyFromTwoPoints[n, n+1]; ENDLOOP; s ¬ ShapeFromPointsPolys[name, curve, polys]; }; }; ShapeFromSegments: PUBLIC PROC [name: ROPE, segments: LIST OF Segment] RETURNS [s: Shape] ~ { nPoints, nPolys: NAT ¬ 0; FOR l: LIST OF Segment ¬ segments, l.rest WHILE l # NIL DO nPolys ¬ nPolys+1; nPoints ¬ nPoints+2; ENDLOOP; IF nPoints > 1 THEN { AddVertex: PROC [p: Triple] ~ { s.vertices[s.vertices.length] ¬ NEW[VertexRep ¬ [point: p]]; s.vertices.length ¬ s.vertices.length+1; }; s ¬ NEW[ShapeRep ¬ [name: name, matrix: G3dMatrix.Identity[]]]; s.surfaces ¬ NEW[SurfaceSequenceRep[nPolys]]; s.vertices ¬ NEW[VertexSequenceRep[nPoints]]; FOR l: LIST OF Segment ¬ segments, l.rest WHILE l # NIL DO AddVertex[l.first.p0]; AddVertex[l.first.p1]; s.surfaces[s.surfaces.length].vertices ¬ PolyFromTwoPoints[s.vertices.length-2,s.vertices.length-1]; s.surfaces.length ¬ s.surfaces.length+1; ENDLOOP; s.objectExtent ¬ G3dShape.BoundingBox[s]; }; }; ShapeFromPoints: PUBLIC PROC [name: ROPE, points: TripleSequence] RETURNS [Shape] ~ { ERROR; }; SkipNPolys: PUBLIC PROC [shape: Shape, nPolys: NAT] ~ { FOR n: NAT IN [nPolys..shape.surfaces.length) DO shape.surfaces[n-nPolys] ¬ shape.surfaces[n]; ENDLOOP; shape.surfaces.length ¬ shape.surfaces.length-nPolys; }; Hash: PROC [key: REF ANY] RETURNS [CARD] ~ { i: REF IntegerPair ~ NARROW[key]; RETURN[i.x+i.y]; }; Equal: PROC [key1, key2: REF ANY] RETURNS [BOOL] ~ { RETURN[NARROW[key1, REF IntegerPair]^ = NARROW[key2, REF IntegerPair]^]; }; Cleave: PUBLIC PROC [shape: Shape, plane: Plane, cap: BOOL ¬ FALSE] RETURNS [neg, pos: Shape ¬ NIL] ~ { CapInfo: TYPE ~ RECORD [vID, pID0, pID1: INTEGER ¬ -1]; Caps: TYPE ~ RECORD [len: CARD ¬ 0, s: SEQUENCE max: CARD OF REF CapInfo]; VertexState: TYPE ~ RECORD [v: Vertex, dist: REAL, sign: Border, old, pos, neg: INTEGER]; VertexStates: TYPE ~ RECORD [element: SEQUENCE max: CARD OF VertexState]; IF shape # NIL AND shape.vertices # NIL AND shape.vertices.length > 2 THEN { Init: PROC RETURNS [s: Shape] ~ { s ¬ NEW[ShapeRep]; s.vertices ¬ NEW[VertexSequenceRep[10]]; s.surfaces ¬ NEW[SurfaceSequenceRep[10]]; s.faces ¬ NEW[FaceSequenceRep[10]]; }; AddVertex: PROC [s: Shape, v: Vertex] ~ { s.vertices ¬ G3dShape.AddToVertexSequence[s.vertices, NEW[VertexRep ¬ v^]]; }; AddPoly: PROC [s: Shape, poly: NatSequence, old: NAT] ~ { s.surfaces ¬ G3dBasic.AddToSurfaceSequence[s.surfaces, [NIL, poly]]; IF shape.faces # NIL AND shape.faces.length > old THEN s.faces ¬ G3dShape.AddToFaceSequence[s.faces, NEW[FaceRep ¬ shape.faces[old]^]]; }; AllInPlane: PROC [poly: NatSequence] RETURNS [b: BOOL ¬ TRUE] ~ { FOR i: INTEGER IN [0..poly.length) DO IF vertexStates[poly[i]].sign # edge THEN RETURN[FALSE]; ENDLOOP; }; ToCaps: PROC [caps: REF Caps, vID, pID: INTEGER] RETURNS [ret: REF Caps] ~ { IF (ret ¬ caps) = NIL THEN ret ¬ NEW[Caps[1]]; FOR i: INTEGER IN [0..ret.len) DO IF ret[i].vID = vID THEN {ret[i].pID1 ¬ pID; RETURN}; ENDLOOP; IF ret.len = ret.max THEN { old: REF Caps ¬ ret; ret ¬ NEW[Caps[MAX[2*old.max, 3]]]; FOR i: INTEGER IN [0..(ret.len ¬ old.len)) DO ret[i] ¬ old[i]; ENDLOOP; }; ret[ret.len] ¬ NEW[CapInfo ¬ [vID, pID, -1]]; ret.len ¬ ret.len+1; }; PosNegToCaps: PROC [posVid, negVid, posPid, negPid: INTEGER] ~ { posCaps ¬ ToCaps[posCaps, posVid, posPid]; negCaps ¬ ToCaps[negCaps, negVid, negPid]; }; Cap: PROC [s: Shape, caps: REF Caps] ~ { GetAny: PROC RETURNS [r: REF CapInfo] ~ { FOR i: INTEGER IN [0..caps.len) DO IF (r ¬ caps[i]) # NIL THEN EXIT; ENDLOOP; }; GetForIDAndDelete: PROC [pID: INTEGER] RETURNS [r: REF CapInfo] ~ { FOR i: INTEGER IN [0..caps.len) DO IF (r¬caps[i]) # NIL AND (r.pID0=pID OR r.pID1=pID) THEN {caps[i]¬NIL; RETURN}; ENDLOOP; RETURN[NIL]; }; a, b: REF CapInfo; WHILE (a ¬ GetAny[]) # NIL DO poly: NatSequence ¬ NIL; start, id: INTEGER ¬ a.pID0; WHILE (b ¬ GetForIDAndDelete[id]) # NIL DO poly ¬ G2dBasic.AddToNatSequence[poly, b.vID]; id ¬ IF b.pID0 = id THEN b.pID1 ELSE b.pID0; ENDLOOP; IF id = start THEN s.surfaces ¬ G3dBasic.AddToSurfaceSequence[s.surfaces, [, poly]]; ENDLOOP; }; posCaps, negCaps: REF Caps ¬ NIL; hash: RefTab.Ref ¬ RefTab.Create[equal: Equal, hash: Hash]; vertexStates: REF VertexStates ¬ NEW[VertexStates[shape.vertices.length]]; pos ¬ Init[]; neg ¬ Init[]; FOR i: INTEGER IN [0..shape.vertices.length) DO v: Vertex ¬ shape.vertices[i]; dist: REAL ¬ G3dPlane.DistanceToPoint[v.point, plane, FALSE]; sign: Border ¬ SELECT dist FROM > 0.01 => inside, < -0.01 => outside, ENDCASE => edge; vertexStates[i] ¬ [v, dist, sign, i, pos.vertices.length, neg.vertices.length]; IF sign = outside OR sign = edge THEN AddVertex[neg, v]; IF sign = inside OR sign = edge THEN AddVertex[pos, v]; ENDLOOP; FOR n: INTEGER IN [0..shape.surfaces.length) DO oldPoly: NatSequence ¬ shape.surfaces[n].vertices; posPoly, negPoly: NatSequence ¬ NIL; IF AllInPlane[oldPoly] THEN { -- case 1 IF cap THEN FOR i: INTEGER IN [0..oldPoly.length) DO vs: VertexState ¬ vertexStates[oldPoly[i]]; posPoly ¬ G2dBasic.AddToNatSequence[posPoly, vs.pos]; negPoly ¬ G2dBasic.AddToNatSequence[negPoly, vs.neg]; ENDLOOP; } ELSE { -- case 2, 3, 4, or 5 nInside, nOutside, nEdge: INTEGER ¬ 0; s1: VertexState ¬ vertexStates[oldPoly[oldPoly.length-1]]; FOR i: INTEGER IN [0..oldPoly.length) DO SELECT vertexStates[oldPoly[i]].sign FROM inside => nInside ¬ nInside+1; outside => nOutside ¬ nOutside+1; ENDCASE => nEdge ¬ nEdge+1; ENDLOOP; FOR i: INTEGER IN [0..oldPoly.length) DO s0: VertexState ¬ s1; s1 ¬ vertexStates[oldPoly[i]]; IF s0.sign # s1.sign AND s0.sign # edge AND s1.sign # edge THEN { -- interp. indices: IntegerPair; -- pos and neg indices for interpolated vertex key: REF IntegerPair ¬NEW[IntegerPair¬[MIN[s0.old,s1.old],MAX[s0.old,s1.old]]]; ref: REF ¬ RefTab.Fetch[hash, key].val; IF ref # NIL THEN indices ¬ NARROW[ref, REF IntegerPair]^ -- previously stored ELSE { -- interpolate and store v: Vertex ¬ G3dShape.InterpolateVertex[s0.dist/(s0.dist-s1.dist), s0.v, s1.v]; indices ¬ [pos.vertices.length, neg.vertices.length]; [] ¬ RefTab.Store[hash, key, NEW[IntegerPair ¬ indices]]; AddVertex[pos, v]; AddVertex[neg, v]; }; IF cap THEN PosNegToCaps[indices.x, indices.y, pos.surfaces.length, neg.surfaces.length]; posPoly ¬ G2dBasic.AddToNatSequence[posPoly, indices.x]; -- case 2 negPoly ¬ G2dBasic.AddToNatSequence[negPoly, indices.y]; -- case 2 }; IF cap AND s1.sign = edge THEN SELECT TRUE FROM nInside > 0 AND nOutside > 0 => -- case 4 (rightmost poly in fig) PosNegToCaps[s1.pos, s1.neg, pos.surfaces.length, neg.surfaces.length]; nInside > 0 AND nEdge >= 2 => -- case 5 (leftmost poly in fig) posCaps ¬ ToCaps[posCaps, s1.pos, pos.surfaces.length]; nOutside > 0 AND nEdge >= 2 => -- case 5 (leftmost poly in fig) negCaps ¬ ToCaps[negCaps, s1.neg, neg.surfaces.length]; ENDCASE; -- case 3 IF nInside > 0 AND s1.sign # outside THEN posPoly ¬ G2dBasic.AddToNatSequence[posPoly, s1.pos]; IF nOutside > 0 AND s1.sign # inside THEN negPoly ¬ G2dBasic.AddToNatSequence[negPoly, s1.neg]; ENDLOOP; }; IF posPoly # NIL THEN AddPoly[pos, posPoly, n]; -- add poly if not fully clipped IF negPoly # NIL THEN AddPoly[neg, G3dPolygon.PolygonReverse[negPoly], n]; ENDLOOP; IF posCaps # NIL THEN Cap[pos, posCaps]; IF negCaps # NIL THEN Cap[neg, negCaps]; pos.edges ¬ G3dShape.MakeEdges[pos ! BoundsFault => CONTINUE]; neg.edges ¬ G3dShape.MakeEdges[neg ! BoundsFault => CONTINUE]; }; }; DrawCurves: PUBLIC PROC [ context: Context, shape: Shape, view: Matrix, viewport: Viewport ¬ [], type: DrawType ¬ solid, backFaces: BOOL ¬ TRUE, screens: ScreenSequence ¬ NIL, forceTransform: BOOL ¬ FALSE, forInterpress: BOOL ¬ FALSE] RETURNS [ScreenSequence] ~ { FrontFacingAction: SurfaceProc ~ { i0: CARD ¬ surface[surface.length-1]; FOR n: INTEGER IN [0..surface.length) DO i1: CARD ¬ surface[n]; index: INT ¬ G3dShape.FindEdge[shape.edges, i0, i1]; i0 ¬ i1; IF index = -1 THEN LOOP; IF type # solid THEN G3dDraw.DotCurve[context, model.curves[index], x, viewport] ELSE G3dDraw.Curve[context, model.curves[index], x, viewport,, forInterpress]; ENDLOOP; }; model: Model ¬ GetModel[shape]; mat: Matrix ¬ IF shape.matrix # NIL THEN shape.matrix ELSE G3dMatrix.Identity[]; x: Matrix ¬ G3dMatrix.Mul[shape.matrix ¬ mat, view, G3dMatrix.ObtainMatrix[]]; IF model = NIL THEN RETURN[NIL]; IF forceTransform OR screens = NIL OR NOT screens.screensValid THEN screens ¬ G3dDraw.SetScreenCoords[context, shape, x, viewport, screens]; IF shape.edges = NIL THEN shape.edges ¬ G3dShape.MakeEdges[shape]; IF backFaces THEN G3dDraw.Curves[context, model.curves, x, viewport, type # solid, forInterpress] ELSE G3dShape.DoWithFacingPolygons[shape, x, FrontFacingAction]; RETURN[screens]; }; SetCurves: PUBLIC PROC [shape: Shape] ~ { model: Model ¬ GetModel[shape]; IF G3dShape.VertexValid[shape, normal] AND shape.edges # NIL THEN { IF model.curves = NIL OR model.curves.maxLength < shape.edges.length THEN model.curves ¬ NEW[SplineSequenceRep[shape.edges.length]]; model.curves.length ¬ shape.edges.length; FOR n: NAT IN [0..shape.edges.length) DO e: Edge ¬ shape.edges[n]; v0: Vertex ¬ shape.vertices[e.v0]; v1: Vertex ¬ shape.vertices[e.v1]; model.curves[n] ¬ G3dSpline.SplineFromPointsAndNormals[ v0.point, v1.point, v0.normal, v1.normal,, model.curves[n]]; ENDLOOP; }; }; MakeCurves: PUBLIC PROC [ vertices, normals: TripleSequence, edges: EdgeSequence, curves: SplineSequence ¬ NIL] RETURNS [SplineSequence] ~ { IF vertices # NIL AND normals # NIL AND edges # NIL THEN { IF curves = NIL OR curves.maxLength < edges.length THEN curves ¬ NEW[SplineSequenceRep[edges.length]]; curves.length ¬ edges.length; FOR n: NAT IN [0..edges.length) DO e: Edge ¬ edges[n]; curves[n] ¬ G3dSpline.SplineFromPointsAndNormals[ vertices[e.v0], vertices[e.v1], normals[e.v0], normals[e.v1], , curves[n]]; ENDLOOP; }; RETURN[curves]; }; NormalsFromCurve: PUBLIC PROC [curve: PairSequence] RETURNS [curveNormals: PairSequence] ~ { curveNormals ¬ NEW[PairSequenceRep[curve.length]]; curveNormals.length ¬ curve.length; SELECT curve.length FROM = 2 => { tangent: Pair ¬ G2dVector.Unit[G2dVector.Sub[curve[1], curve[0]]]; curveNormals[0] ¬ curveNormals[1] ¬ [-tangent.y, tangent.x]; }; > 2 => { dm, dp, tangent: Pair; delm, delp, delSum: REAL; FOR i: NAT IN [1..curve.length-1) DO dm ¬ G2dVector.Sub[curve[i], curve[i-1]]; dp ¬ G2dVector.Sub[curve[i+1], curve[i]]; delm ¬ ABS[dm.x] + ABS[dm.y]; delp ¬ ABS[dp.x] + ABS[dp.y]; delSum ¬ delm+delp; tangent ¬ G2dVector.Combine[G2dVector.Unit[dm], delp/delSum, G2dVector.Unit[dp], delm/delSum]; curveNormals[i] ¬ G2dVector.Unit[[-tangent.y, tangent.x]]; ENDLOOP; tangent ¬ G2dVector.Combine[G2dVector.Unit[dp], 2.0*delSum, G2dVector.Unit[tangent], -1]; curveNormals[curve.length-1] ¬ G2dVector.Unit[[-tangent.y, tangent.x]]; dm ¬ G2dVector.Sub[curve[1], curve[0]]; dp ¬ G2dVector.Sub[curve[2], curve[1]]; delm ¬ ABS[dm.x] + ABS[dm.y]; delp ¬ ABS[dp.x] + ABS[dp.y]; delSum ¬ delm+delp; tangent ¬ G2dVector.Combine[G2dVector.Unit[dm], 2.0*delSum, [curveNormals[1].y, -curveNormals[1].x], -1]; curveNormals[0] ¬ G2dVector.Unit[[-tangent.y, tangent.x]]; }; ENDCASE; }; END. .. MakeEdges: PUBLIC PROC [polygons: SurfaceSequence, edges: EdgeSequence ¬ NIL] RETURNS [EdgeSequence] ~ { n0, n1, min, max: CARD; IF vertices = NIL OR polygons = NIL THEN RETURN[NIL]; IF edges = NIL OR edges.maxLength < vertices.length THEN edges ¬ NEW[EdgeSequence[vertices.length]]; FOR i: NAT IN [0..polygons.length) DO polygon: NatSequence ~ polygons[i]; n0 ¬ polygon[polygon.length-1]; FOR ii: NAT IN [0..polygon.length) DO n1 ¬ polygon[ii]; IF n0 < n1 THEN {min ¬ n0; max ¬ n1} ELSE {min ¬ n1; max ¬ n0}; IF min+1 > edges.length THEN edges.length ¬ min+1; FOR l: LIST OF NAT ¬ edges[min], l.rest WHILE l # NIL DO IF l.first = max THEN EXIT; REPEAT FINISHED => edges[min] ¬ CONS[max, edges[min]]; ENDLOOP; n0 ¬ n1; ENDLOOP; ENDLOOP; RETURN[edges]; }; * G3dModelImpl.mesa Copyright c 1985 by Xerox Corporation. All rights reserved. Bloomenthal, October 21, 1992 5:51 pm PDT Heckbert, June 22, 1988 4:54:42 pm PDT Glassner, March 2, 1990 9:41:41 am PST Shoemake, November 20, 1989 8:29:31 pm PST Types and Constants File IO Shape Specification Vertex Procedures compute nvert, the number of new vertices: one per polygon per vertex, and allocate them modify polygon indices and build new vertex list Polygon Procedures we didn't have face normals, so comply with vertices by testing polygon plane or normal Nearness Procedures Creation Cleaving This will fail for concave polygons (ie, a polygon cut more than once by the plane). [Artwork node; type 'Artwork on' to command tool] Curve Procedures Unit normals are created by rotating estimated tangents left 90" as we follow curve. If data is specified in the opposite order, the normals may be 180" out of phase. For evenly spaced data points tangent estimation is no problem; irregularly spaced points require more care. The intent here is to average the (normalized) incoming and outgoing vectors at an interior point when their magnitudes are the same, so simple data works as expected. However when one of the vectors is small compared to the other, it gets more weight (after normalization)--on the assumption that the curve is parameterized by arc length so nearly incident points provide a better tangent estimate. Estimate tangent from chord length parameterized parabola Estimate tangent at trailing end using left-over values Estimate tangent at leading end Êd¯•NewlineDelimiter ™™Jšœ Ïmœ1™J™Wšžœžœžœž˜+J˜Jšœ žœžœ žœ#˜Kšžœ=žœ˜EJ˜;Jšžœžœ1˜?J˜—Jšžœ˜——J˜J˜—š¡œžœžœ+žœ˜OJšœžœ˜ šž˜J˜)šžœžœžœž˜"šžœžœ¢˜Í4Äu¤¡£¡¡¨¢¯“¢°“¢·“ÄÄ?54™Ä ›Ž˜ k é k x jÅxeroxÅxc1-2-2Å helvetica£¡ “ •  —¡¡¨Äèo ¤Ä€ù¹ÄµÇ ¢ ¥ ¨  Š¡²“ÁCase 1– k x jÅxeroxÅxc1-2-2Å helvetica£¡ “ •  —¡¡¨Äèo ¤Ä¶"›ÄµÇ ¢ ¥ ¨  Š¡²“ÁCase 2– k x jÅxeroxÅxc1-2-2Å helvetica£¡ “ •  —¡¡¨Äèo ¤Ä“ýgĵǠ¢ ¥ ¨  Š¡²“ÁCase 3– k x jÅxeroxÅxc1-2-2Å helvetica£¡ “ •  —¡¡¨Äèo ¤Ä¿qgĵǠ¢ ¥ ¨  Š¡²“ÁCase 4– k x jÅxeroxÅxc1-2-2Å helvetica£¡ “ •  —¡¡¨Äèo ¤ÄìgĵǠ¢ ¥ ¨  Š¡²“ÁCase 5– kÄ¡¨ ¡ ¡™ x j r j— Š ªiÄám–Ä+8›ÄF7¡£¡¡¨¢¯“¢°“¢·“IJ°aÄâ™–™k6—˜ k é k k k g•Artwork Interpress•Bounds:0.0 mm xmin 0.0 mm ymin 185.7738 mm xmax 31.78033 mm ymax –é34.60255 mm bigger topLeading 34.60255 mm bigger topIndent 1.411111 mm bigger bottomLeading 0.5 0.3 0.95 backgroundColor the topLeading 6 pt .sub backgroundAscent 3 pt backgroundDescent 4 pt outlineBoxThickness 1 pt outlineBoxBearoff•GGFile¹UGargoyle file for scene: stuffed from Gargoyle at April 10, 1992 9:44:30 pm PDT Produced by version 9106.27 Scripts: Slope: [F 150.0] [F 135.0] [F 120.0] [T 90.0] [F 60.0] [F 45.0] [F 30.0] [T 0.0] Angle: [F 90.0] [F 60.0] [F 45.0] [F 30.0] [F 0.0] [F -30.0] [F -45.0] [F -60.0] [F -90.0] Radius: [F 5.555556e-2 1/18] [F 0.1111111 1/9] [F 0.125 1/8] [F 0.25 1/4] [F 0.3333334 1/3] [F 0.5 1/2] [F 0.6666668 2/3] [F 0.75 3/4] [F 1.0 1] [F 2.0 2] [F 4.0 4] LineDistance: [F 0.0 0] [F 5.555556e-2 1/18] [F 0.1111111 1/9] [F 0.5 1/2] [F 1.0 1] Midpoints: F Heuristics: F ShowAlignments: T ScaleUnit: 72.0 DisplayStyle: print Gravity: T GravityExtent: 8.680556e-2 GravityType: pointsPreferred DefaultFont: xerox/xc1-2-2/helvetica [r1: 0.0 s: [18.53268 18.53268] r2: 0.0] 1.0 1.0 Defaults: [1 0.5] [1 1.0] 2.0 round round Dashed: F Shadows: [1 1.0]F Anchor: F Palette: F Entities: [56]: Outline fillColor: [1 0.5] ow: T fillText: T 0 Children: [1] Traj (open) [1] arrows: 0 j: round e: T round w: 3.0 c: T [1 0.5] d: T F [254.96,425.173] (Line ) [345.5224,425.173] fwd: T pList: ( ) Outline fillColor: [1 0.5] ow: T fillText: T 0 Children: [1] Traj (open) [5] arrows: 0 j: round e: T round w: 2.0 c: T [1 1.0] d: T F [285.68,445.423] (Line ) [268.2425,411.673] (Line ) [292.9925,387.4856] (Line ) [323.93,404.923] (Line ) [319.9925,439.2355] (Line ) [285.68,445.423] fwd: T pList: ( ) Circle [2.999147 0.0 321.6062 0.0 2.999147 425.173] strokeWidth: 2.0 strokeColor: [] fillColor: [0 0.8 0.0 0.0] dashes: ( F ) props: ( F ) fwd: T pList: ( ) Circle [2.999147 0.0 275.2175 0.0 2.999147 425.173] strokeWidth: 2.0 strokeColor: [] fillColor: [0 0.8 0.0 0.0] dashes: ( F ) props: ( F ) fwd: T pList: ( ) Circle [1.999431 0.0 323.93 0.0 1.999431 404.923] strokeWidth: 2.0 strokeColor: [] fillColor: [1 1.0] dashes: ( F ) props: ( F ) fwd: T pList: ( ) Circle [1.999431 0.0 319.9925 0.0 1.999431 439.2355] strokeWidth: 2.0 strokeColor: [] fillColor: [1 1.0] dashes: ( F ) props: ( F ) fwd: T pList: ( ) Circle [1.999431 0.0 292.9925 0.0 1.999431 387.4856] strokeWidth: 2.0 strokeColor: [] fillColor: [1 1.0] dashes: ( F ) props: ( F ) fwd: T pList: ( ) Circle [1.999431 0.0 285.68 0.0 1.999431 445.423] strokeWidth: 2.0 strokeColor: [] fillColor: [1 1.0] dashes: ( F ) props: ( F ) fwd: T pList: ( ) Circle [1.999431 0.0 268.2425 0.0 1.999431 411.673] strokeWidth: 2.0 strokeColor: [] fillColor: [1 1.0] dashes: ( F ) props: ( F ) fwd: T pList: ( ) Outline fillColor: [1 0.5] ow: T fillText: T 0 Children: [1] Traj (open) [5] arrows: 0 j: round e: T round w: 2.0 c: T [1 1.0] d: T F [192.0625,418.3105] (Line ) [174.625,408.1855] (Line ) [199.375,400.9292] (Line ) [230.3125,406.1605] (Line ) [226.375,416.4543] (Line ) [192.0625,418.3105] fwd: T pList: ( ) Circle [1.999431 0.0 174.625 0.0 1.999431 408.1855] strokeWidth: 2.0 strokeColor: [] fillColor: [1 1.0] dashes: ( F ) props: ( F ) fwd: T pList: ( ) Circle [1.999431 0.0 199.375 0.0 1.999431 400.9292] strokeWidth: 2.0 strokeColor: [] fillColor: [1 1.0] dashes: ( F ) props: ( F ) fwd: T pList: ( ) Circle [1.999431 0.0 230.3125 0.0 1.999431 406.1605] strokeWidth: 2.0 strokeColor: [] fillColor: [1 1.0] dashes: ( F ) props: ( F ) fwd: T pList: ( ) Circle [1.999431 0.0 226.375 0.0 1.999431 416.4543] strokeWidth: 2.0 strokeColor: [] fillColor: [1 1.0] dashes: ( F ) props: ( F ) fwd: T pList: ( ) Circle [1.999431 0.0 192.0625 0.0 1.999431 418.3105] strokeWidth: 2.0 strokeColor: [] fillColor: [1 1.0] dashes: ( F ) props: ( F ) fwd: T pList: ( ) Outline fillColor: [1 0.5] ow: T fillText: T 0 Children: [1] Traj (open) [4] arrows: 0 j: round e: T round w: 3.0 c: T [1 0.5] d: T F [260.4062,387.4856] (Line ) [138.625,387.4856] (Line ) [178.2812,426.298] (Line ) [233.4062,426.298] (Line ) [260.4062,387.4856] fwd: T pList: ( ) Outline fillColor: [1 0.5] ow: T fillText: T 0 Children: [1] Traj (open) [1] arrows: 0 j: round e: T round w: 3.0 c: T [1 0.5] d: T F [349.9078,387.4856] (Line ) [440.4703,387.4856] fwd: T pList: ( ) Outline fillColor: [1 0.5] ow: T fillText: T 0 Children: [1] Traj (open) [5] arrows: 0 j: round e: T round w: 2.0 c: T [1 1.0] d: T F [373.3453,445.423] (Line ) [355.9078,411.673] (Line ) [380.6578,387.4856] (Line ) [411.5953,404.923] (Line ) [407.6578,439.2355] (Line ) [373.3453,445.423] fwd: T pList: ( ) Circle [1.999431 0.0 411.5953 0.0 1.999431 404.923] strokeWidth: 2.0 strokeColor: [] fillColor: [1 1.0] dashes: ( F ) props: ( F ) fwd: T pList: ( ) Circle [1.999431 0.0 407.6578 0.0 1.999431 439.2355] strokeWidth: 2.0 strokeColor: [] fillColor: [1 1.0] dashes: ( F ) props: ( F ) fwd: T pList: ( ) Circle [1.999431 0.0 373.3453 0.0 1.999431 445.423] strokeWidth: 2.0 strokeColor: [] fillColor: [1 1.0] dashes: ( F ) props: ( F ) fwd: T pList: ( ) Circle [1.999431 0.0 355.9078 0.0 1.999431 411.673] strokeWidth: 2.0 strokeColor: [] fillColor: [1 1.0] dashes: ( F ) props: ( F ) fwd: T pList: ( ) Outline fillColor: [1 0.5] ow: T fillText: T 0 Children: [1] Traj (open) [1] arrows: 0 j: round e: T round w: 3.0 c: T [1 0.5] d: T F [437.0,415.9766] (Line ) [549.0,415.9766] fwd: T pList: ( ) Outline fillColor: [1 0.5] ow: T fillText: T 0 Children: [1] Traj (open) [5] arrows: 0 j: round e: T round w: 2.0 c: T [1 1.0] d: T F [501.5876,449.7266] (Line ) [484.1502,415.9766] (Line ) [508.9002,391.7892] (Line ) [539.8377,409.2267] (Line ) [535.9002,443.5391] (Line ) [501.5876,449.7266] fwd: T pList: ( ) Circle [2.999147 0.0 539.063 0.0 2.999147 415.9766] strokeWidth: 2.0 strokeColor: [] fillColor: [0 0.8 0.0 0.0] dashes: ( F ) props: ( F ) fwd: T pList: ( ) Circle [1.999431 0.0 539.8377 0.0 1.999431 409.2267] strokeWidth: 2.0 strokeColor: [] fillColor: [1 1.0] dashes: ( F ) props: ( F ) fwd: T pList: ( ) Circle [1.999431 0.0 535.9002 0.0 1.999431 443.5391] strokeWidth: 2.0 strokeColor: [] fillColor: [1 1.0] dashes: ( F ) props: ( F ) fwd: T pList: ( ) Circle [1.999431 0.0 508.9002 0.0 1.999431 391.7892] strokeWidth: 2.0 strokeColor: [] fillColor: [1 1.0] dashes: ( F ) props: ( F ) fwd: T pList: ( ) Circle [1.999431 0.0 501.5876 0.0 1.999431 449.7266] strokeWidth: 2.0 strokeColor: [] fillColor: [1 1.0] dashes: ( F ) props: ( F ) fwd: T pList: ( ) Circle [1.999431 0.0 484.1502 0.0 1.999431 415.9766] strokeWidth: 2.0 strokeColor: [] fillColor: [1 1.0] dashes: ( F ) props: ( F ) fwd: T pList: ( ) Circle [1.999431 0.0 380.6578 0.0 1.999431 387.4856] strokeWidth: 2.0 strokeColor: [] fillColor: [1 1.0] dashes: ( F ) props: ( F ) fwd: T pList: ( ) Outline fillColor: [1 0.5] ow: T fillText: T 0 Children: [1] Traj (open) [1] arrows: 0 j: round e: T round w: 2.0 c: T [1 1.0] d: T F [462.5877,386.7267] (Line ) [484.1502,415.9766] fwd: T pList: ( ) Outline fillColor: [1 0.5] ow: T fillText: T 0 Children: [1] Traj (open) [2] arrows: 0 j: round e: T round w: 2.0 c: T [1 1.0] d: T F [484.1502,415.9766] (Line ) [463.3377,444.4766] (Line ) [445.0,425.0] fwd: T pList: ( ) Outline fillColor: [1 0.5] ow: T fillText: T 0 Children: [1] Traj (open) [1] arrows: 0 j: round e: T round w: 2.0 c: T [1 1.0] d: T F [463.3377,444.4766] (Line ) [501.5876,449.7266] fwd: T pList: ( ) Outline fillColor: [1 0.5] ow: T fillText: T 0 Children: [1] Traj (open) [1] arrows: 0 j: round e: T round w: 2.0 c: T [1 1.0] d: T F [462.5877,386.7267] (Line ) [508.9002,391.7892] fwd: T pList: ( ) Circle [1.999431 0.0 462.5877 0.0 1.999431 386.7267] strokeWidth: 2.0 strokeColor: [] fillColor: [1 1.0] dashes: ( F ) props: ( F ) fwd: T pList: ( ) Circle [1.999431 0.0 463.3377 0.0 1.999431 444.4766] strokeWidth: 2.0 strokeColor: [] fillColor: [1 1.0] dashes: ( F ) props: ( F ) fwd: T pList: ( ) Outline fillColor: [1 0.5] ow: T fillText: T 0 Children: [1] Traj (open) [1] arrows: 0 j: round e: T round w: 3.0 c: T [1 0.5] d: T F [563.0,415.9766] (Line ) [660.2278,415.9766] fwd: T pList: ( ) Outline fillColor: [1 0.5] ow: T fillText: T 0 Children: [1] Traj (open) [4] arrows: 0 j: round e: T round w: 2.0 c: T [1 1.0] d: T F [615.9777,449.7266] (Line ) [598.5402,415.9766] (Line ) [623.2902,391.7892] (Line ) [646.7277,405.4767] (Line ) [615.9777,449.7266] fwd: T pList: ( ) Circle [2.999147 0.0 639.4312 0.0 2.999147 415.9766] strokeWidth: 2.0 strokeColor: [] fillColor: [0 0.8 0.0 0.0] dashes: ( F ) props: ( F ) fwd: T pList: ( ) Circle [1.999431 0.0 623.2902 0.0 1.999431 391.7892] strokeWidth: 2.0 strokeColor: [] fillColor: [1 1.0] dashes: ( F ) props: ( F ) fwd: T pList: ( ) Circle [1.999431 0.0 615.9777 0.0 1.999431 449.7266] strokeWidth: 2.0 strokeColor: [] fillColor: [1 1.0] dashes: ( F ) props: ( F ) fwd: T pList: ( ) Circle [1.999431 0.0 598.5402 0.0 1.999431 415.9766] strokeWidth: 2.0 strokeColor: [] fillColor: [1 1.0] dashes: ( F ) props: ( F ) fwd: T pList: ( ) Outline fillColor: [1 0.5] ow: T fillText: T 0 Children: [1] Traj (open) [3] arrows: 0 j: round e: T round w: 2.0 c: T [1 1.0] d: T F [576.9778,386.7267] (Line ) [579.2278,415.9766] (Line ) [564.9778,451.2266] (Line ) [615.9777,449.7266] fwd: T pList: ( ) Outline fillColor: [1 0.5] ow: T fillText: T 0 Children: [1] Traj (open) [1] arrows: 0 j: round e: T round w: 2.0 c: T [1 1.0] d: T F [576.9778,386.7267] (Line ) [623.2902,391.7892] fwd: T pList: ( ) Circle [1.999431 0.0 576.9778 0.0 1.999431 386.7267] strokeWidth: 2.0 strokeColor: [] fillColor: [1 1.0] dashes: ( F ) props: ( F ) fwd: T pList: ( ) Circle [1.999431 0.0 579.2278 0.0 1.999431 415.9766] strokeWidth: 2.0 strokeColor: [] fillColor: [1 1.0] dashes: ( F ) props: ( F ) fwd: T pList: ( ) Circle [1.999431 0.0 646.7277 0.0 1.999431 405.4767] strokeWidth: 2.0 strokeColor: [] fillColor: [1 1.0] dashes: ( F ) props: ( F ) fwd: T pList: ( ) Circle [1.999431 0.0 564.9778 0.0 1.999431 451.2266] strokeWidth: 2.0 strokeColor: [] fillColor: [1 1.0] dashes: ( F ) props: ( F ) fwd: T pList: ( ) Outline fillColor: [1 0.5] ow: T fillText: T 0 Children: [1] Traj (open) [1] arrows: 0 j: round e: T round w: 2.0 c: T [1 1.0] d: T F [579.2278,415.9766] (Line ) [598.5402,415.9766] fwd: T pList: ( ) Text T "Case 1" xerox/xc1-2-2/helvetica [11.4671 0.0 178.4703 0.0 11.4671 366.4172][1 1.0] F 1.0 props: ( F ) ls: 1.2 pList: ( ) Text T "Case 2" xerox/xc1-2-2/helvetica [11.4671 0.0 272.9002 0.0 11.4671 366.4172][1 1.0] F 1.0 props: ( F ) ls: 1.2 pList: ( ) Text T "Case 3" xerox/xc1-2-2/helvetica [11.4671 0.0 367.8156 0.0 11.4671 366.4172][1 1.0] F 1.0 props: ( F ) ls: 1.2 pList: ( ) Text T "Case 4" xerox/xc1-2-2/helvetica [11.4671 0.0 475.8155 0.0 11.4671 366.4172][1 1.0] F 1.0 props: ( F ) ls: 1.2 pList: ( ) Text T "Case 5" xerox/xc1-2-2/helvetica [11.4671 0.0 586.8156 0.0 11.4671 366.4172][1 1.0] F 1.0 props: ( F ) ls: 1.2 pList: ( ) Outline fillColor: [1 0.5] ow: T fillText: T 0 Children: [1] Traj (open) [1] arrows: 0 j: round e: T round w: 2.0 c: T [1 1.0] d: T F [462.5877,386.7267] (Line ) [450.0,406.0] fwd: T pList: ( ) š¡3™3˜J˜2Jšœ žœ˜$šžœ˜šžœ¢ ˜š žœžœžœžœžœž˜4J˜+J˜5J˜5Jšžœ˜—J˜—šžœ¢˜Jšœžœ˜&J˜:šžœžœžœž˜(šžœž˜)J˜J˜!Jšžœ˜—Jšžœ˜—šžœžœžœž˜(J˜J˜š žœžœžœžœ¢ ˜LJšœ¢.˜DJš œ¤ž¤œ ¤œžœžœžœ˜OJšœžœ˜'šžœž˜ Jšžœ žœžœ¢˜Ašžœ¢˜Jš œ¤œ¤œ¤œ5¤œ¤œ˜NJ˜5Jšœ¤œ¤œ¤œ¤žœ ¤œ¤œ ˜9J˜J˜J˜——šžœž˜ JšœM˜M—Jšœ9¢ ˜BJšœ9¢ ˜BJ˜—š žœžœžœžœžœž˜/šœ žœ¢!˜AJšœG˜G—šœ žœ¢ ˜>J˜7—šœ žœ¢ ˜?J˜7—Jšžœ¢ ˜—šžœ žœ˜$Jšžœ6˜:—šžœžœ˜%Jšžœ6˜:—Jšžœ˜—J˜——Jšžœ žœžœ¢ ˜PJšžœ žœžœ5˜JJšžœ˜—Jšžœ žœžœ˜(Jšžœ žœžœ˜(Jšœ4žœ˜>Jšœ4žœ˜>J˜—J˜——š ™š¡ œž œ˜J˜J˜ J˜ J˜J˜Jšœ žœžœ˜Jšœžœ˜Jšœžœžœ˜Jšœžœžœ˜Jšžœ˜J˜š¡œ˜"Jšœžœ˜%šžœžœžœž˜(Jšœžœ˜Jšœžœ*˜4J˜Jšžœ žœžœ˜šžœ ˜Jšžœ<˜@JšžœJ˜N—Jšžœ˜—J˜—J˜Jš œžœžœžœžœ˜PJ˜NJš žœ žœžœžœžœ˜ š žœžœ žœžœžœ˜>JšžœI˜M—Jšžœžœžœ)˜Bšžœ ˜ JšžœP˜TJšžœ<˜@—Jšžœ ˜J˜J™—š¡ œž œ˜)J˜šžœ%žœžœžœ˜Cšžœžœžœ,˜DJšžœžœ(˜?—J˜)šžœžœžœž˜(J˜J˜"J˜"˜7J˜<—Jšžœ˜—J˜—˜J˜——š¡ œž œ˜J˜"J˜Jšœžœ˜Jšžœ˜J˜šžœ žœžœ žœžœ žœžœ˜:šžœ žœžœ ˜2Jšžœ žœ"˜3—J˜šžœžœžœž˜"J˜˜1J˜K—Jšžœ˜—J˜—Jšžœ ˜J˜J˜—š ¡œ¤ž¤ž¤œ¤œ ˜3Jšž¤œ¤œ ˜$Jšœ?œ™TJšœBœ™QIblockšÏiþ™þJ˜Jšœžœ ˜2J˜#šžœž˜šœ˜J˜BJ˜