DIRECTORY Args, Ascii, Commander, Draw2d, FileNames, FS, G2dBasic, G2dVector, G3dBasic, G3dBuild, G3dCurve, G3dDraw, G3dMatrix, G3dPlane, G3dPolygon, G3dQuaternion, G3dRender, G3dScene, G3dShape, G3dSpline, G3dSweep, G3dTimeTrees, G3dVector, Imager, IO, MessageWindow, Process, Random, Real, RealFns, RefTab, Rope, RopeFile, RuntimeError, TiogaAccess, TiogaMenuOps, ViewerOps, ViewerTools; G3dBuildAImpl: CEDAR PROGRAM IMPORTS G2dBasic, G3dBasic, G3dRender, G3dScene, G3dShape, G3dSweep, G3dVector, IO, Real, RealFns, Random, Rope EXPORTS G3dBuild ~ BEGIN Arg: TYPE ~ Args.Arg; AxisAngle: TYPE ~ G3dQuaternion.AxisAngle; BlendType: TYPE ~ G3dSweep.BlendType; BoolSequence: TYPE ~ G3dBasic.BoolSequence; Context3d: TYPE ~ G3dRender.Context3d; Material: TYPE ~ G3dScene.Material; NatSequence: TYPE ~ G3dBasic.NatSequence; NatSequenceRep: TYPE ~ G3dBasic.NatSequenceRep; ParseState: TYPE ~ G3dScene.ParseState; RealSequence: TYPE ~ G3dBasic.RealSequence; RenderStyle: TYPE ~ G3dRender.RenderStyle; ROPE: TYPE ~ Rope.ROPE; SceneProc: TYPE ~ G3dScene.SceneProc; Shape: TYPE ~ G3dShape.Shape; ShapeRep: TYPE ~ G3dShape.ShapeRep; ShapeSequence: TYPE ~ G3dShape.ShapeSequence; SurfaceDescription: TYPE ~ G3dSweep.SurfaceDescription; SurfaceDescriptionRep: TYPE ~ G3dSweep.SurfaceDescriptionRep; TextureStyle: TYPE ~ G3dRender.TextureStyle; Triple: TYPE ~ G3dBasic.Triple; TripleSequence: TYPE ~ G3dBasic.TripleSequence; Vertex: TYPE ~ G3dShape.Vertex; VertexRep: TYPE ~ G3dShape.VertexRep; Error: PUBLIC SIGNAL [code: ATOM, reason: ROPE] = CODE; SweepPaths: TYPE ~ G3dBuild.SweepPaths; SweepPathsRep: TYPE ~ G3dBuild.SweepPathsRep; Field: TYPE ~ G3dBuild.Field; FieldRep: TYPE ~ G3dBuild.FieldRep; State: TYPE ~ G3dBuild.State; StateRep: TYPE ~ G3dBuild.StateRep; pi: REAL ~ 3.1415926535; piOver2: REAL ~ 0.5*pi; piTimes2: REAL ~ 2.0*pi; degToRad: REAL ~ 1.745329e-2; radToDeg: REAL ~ 57.29577; GetBuildState: PUBLIC PROC [ps: ParseState] RETURNS [State] ~ { state: State; IF ps.buildData = NIL THEN { state ¬ ps.buildData ¬ NEW[StateRep ¬ []]; state.field ¬ NEW[FieldRep ¬ []]; state.sweepPaths ¬ NEW[SweepPathsRep ¬ []]; state.randomStream ¬ Random.Create[]; } ELSE state ¬ NARROW[ps.buildData]; RETURN[state]; }; specialCaseSphere: BOOL ¬ TRUE; MakeSphere: PUBLIC SceneProc ~ { state: State ¬ GetBuildState[ps]; shape: Shape ¬ NEW[ShapeRep]; radius: REAL ¬ 1.0; uRes, vRes: NAT ¬ 10; minTheta: REAL ¬ 0.0; maxTheta: REAL ¬ piTimes2; minPsi: REAL ¬ 0.0; maxPsi: REAL ¬ pi; radiusA, uResA, vResA, minThetaA, maxThetaA, minPsiA, maxPsiA, nameA, radiansA: Arg; [radiusA, uResA, vResA, minThetaA, maxThetaA, minPsiA, maxPsiA, nameA, radiansA] ¬ G3dScene.GetArgs[ps, args, "-r%r-ures%i-vres%i-mintheta%r-maxtheta%r-minpsi%r-maxpsi%r-name%s-radians%b"]; IF radiusA.ok THEN radius ¬ radiusA.real; IF uResA.ok THEN uRes ¬ uResA.int; IF vResA.ok THEN vRes ¬ vResA.int; IF minThetaA.ok THEN minTheta ¬ IF radiansA.ok THEN minThetaA.real ELSE minThetaA.real*degToRad; IF maxThetaA.ok THEN maxTheta ¬ IF radiansA.ok THEN maxThetaA.real ELSE maxThetaA.real*degToRad; IF minPsiA.ok THEN minPsi ¬ IF radiansA.ok THEN minPsiA.real ELSE minPsiA.real*degToRad; IF maxPsiA.ok THEN maxPsi ¬ IF radiansA.ok THEN maxPsiA.real ELSE maxPsiA.real*degToRad; IF specialCaseSphere THEN { Surf: PROC [nVertices: NAT, i0, i1, i2, i3: NAT ¬ 0] RETURNS [s: G3dBasic.Surface] ~ { s.vertices ¬ NEW[NatSequenceRep[nVertices]]; s.vertices.length ¬ nVertices; s.vertices[0] ¬ i0; s.vertices[1] ¬ i1; s.vertices[2] ¬ i2; IF nVertices = 4 THEN s.vertices[3] ¬ i3; }; nVertices: NAT ¬ uRes*(vRes-2)+2; nSurfaces: NAT ¬ uRes*(vRes-1); lastRing: NAT ¬ 1+(vRes-3)*uRes; shape.vertices ¬ NEW[G3dShape.VertexSequenceRep[nVertices]]; shape.vertices.length ¬ nVertices; FOR n: NAT IN [0..nVertices) DO shape.vertices[n] ¬ NEW[VertexRep]; ENDLOOP; shape.surfaces ¬ NEW[G3dBasic.SurfaceSequenceRep[nSurfaces]]; shape.surfaces.length ¬ nSurfaces; shape.vertices[0].point ¬ [0.0, 0.0, radius]; -- north pole shape.vertices[nVertices-1].point ¬ [0.0, 0.0, -radius]; -- south pole FOR n: NAT IN [0..vRes-2) DO offset: NAT ¬ 1+n*uRes; a: REAL ¬ minPsi+REAL[n+1]*(maxPsi-minPsi)/REAL[vRes-1]; s: REAL ¬ radius*RealFns.Sin[a]; z: REAL ¬ radius*RealFns.Cos[a]; FOR nn: NAT IN [0..uRes) DO aa: REAL ¬ minTheta+REAL[nn]*(maxTheta-minTheta)/REAL[uRes]; x: REAL ¬ s*RealFns.Cos[aa]; y: REAL ¬ s*RealFns.Sin[aa]; shape.vertices[offset+nn].point ¬ [x, y, z]; ENDLOOP; ENDLOOP; FOR u: NAT IN [0..uRes) DO u0: NAT ¬ u; u1: NAT ¬ (u0+1) MOD uRes; shape.surfaces[u] ¬ Surf[3, 1+u1, 1+u0, 0]; shape.surfaces[shape.surfaces.length-u-1] ¬ Surf[3, lastRing+u0, lastRing+u1, nVertices-1]; ENDLOOP; FOR v: NAT IN [1..vRes-2) DO startRing1: NAT ¬ 1+v*uRes; startRing0: NAT ¬ startRing1-uRes; FOR u: NAT IN [0..uRes) DO u0: NAT ¬ u; u1: NAT ¬ (u+1) MOD uRes; shape.surfaces[u+v*uRes] ¬ Surf[4, startRing0+u0, startRing0+u1, startRing1+u1, startRing1+u0]; ENDLOOP; ENDLOOP; } ELSE shape ¬ ConstructSphere[uRes, vRes, minTheta, maxTheta, minPsi, maxPsi, radius]; shape.name ¬ IF nameA.ok THEN nameA.rope ELSE AutoName[ps.context3d, "AutoSphere"]; LoadShape[ps, state, shape]; }; MakeCylinder: PUBLIC SceneProc ~ { state: State ¬ GetBuildState[ps]; MakeConeShape[ps, args, state, FALSE]; }; MakeCone: PUBLIC SceneProc ~ { state: State ¬ GetBuildState[ps]; MakeConeShape[ps, args, state, TRUE]; }; MakeConeShape: PROC [ps: ParseState, args: ROPE, state: State, cone: BOOL ¬ TRUE] ~ { shape: Shape; steps: INT ¬ 10; zLo: REAL ¬ -1.0; zHi: REAL ¬ 1.0; rLo: REAL ¬ 1.0; rHi: REAL ¬ 1.0; minTheta: REAL ¬ 0.0; maxTheta: REAL ¬ piTimes2; name: ROPE; nameA, stepsA, lcapA, ucapA, radiusA, rLoA, rHiA, zLoA, zHiA, minThetaA, maxThetaA, radiansA: Arg; sd: SurfaceDescription ¬ NEW[SurfaceDescriptionRep ¬ []]; IF cone THEN { [nameA, stepsA, lcapA, ucapA, rLoA, rHiA, zLoA, zHiA, minThetaA, maxThetaA, radiansA] ¬ G3dScene.GetArgs[ps, args, "-name%s-steps%i-lcap%b-ucap%b-rlo%r-rhi%r-zlo%r-zhi%r-minTheta%r-maxTheta%r-radians%b"]; IF rLoA.ok THEN rLo ¬ rLoA.real; IF rHiA.ok THEN rHi ¬ rHiA.real; name ¬ AutoName[ps.context3d, "AutoCone"]; } ELSE { [nameA, stepsA, lcapA, ucapA, radiusA, zLoA, zHiA, minThetaA, maxThetaA, radiansA] ¬ G3dScene.GetArgs[ps, args, "-name%s-steps%i-lcap%b-ucap%b-r%r-zlo%r-zhi%r-minTheta%r-maxTheta%r-radians%b"]; IF radiusA.ok THEN rLo ¬ rHi ¬ radiusA.real; name ¬ AutoName[ps.context3d, "AutoCylinder"]; }; IF minThetaA.ok THEN { minTheta ¬ minThetaA.real; IF NOT radiansA.ok THEN minTheta ¬ minTheta * degToRad; }; IF maxThetaA.ok THEN { maxTheta ¬ maxThetaA.real; IF NOT radiansA.ok THEN maxTheta ¬ maxTheta * degToRad; }; IF nameA.ok THEN name ¬ nameA.rope; IF zLoA.ok THEN zLo ¬ zLoA.real; IF zHiA.ok THEN zHi ¬ zHiA.real; IF stepsA.ok THEN steps ¬ stepsA.int; shape ¬ ConstructCone[steps, rLo, rHi, zLo, zHi, lcapA.ok, ucapA.ok, minTheta, maxTheta]; shape.name ¬ name; LoadShape[ps, state, shape]; }; MakeTorus: PUBLIC SceneProc ~ { state: State ¬ GetBuildState[ps]; shape: Shape; sd: SurfaceDescription ¬ NEW[SurfaceDescriptionRep ¬ []]; majorRA, minorRA, uResA, vResA, minThetaA, maxThetaA, minPsiA, maxPsiA, nameA, radiansA, lcapA, ucapA: Arg; majorR: REAL ¬ 1.0; minorR: REAL ¬ 0.1; uRes, vRes: INT ¬ 10; minTheta: REAL ¬ 0.0; maxTheta: REAL ¬ piTimes2; minPsi: REAL ¬ 0.0; maxPsi: REAL ¬ piTimes2; [majorRA, minorRA, uResA, vResA, minThetaA, maxThetaA, minPsiA, maxPsiA, nameA, radiansA, lcapA, ucapA] ¬ G3dScene.GetArgs[ps, args, "-majorR%r-minorR%r-ures%i-vres%i-mintheta%r-maxtheta%r-minpsi%r-maxpsi%r-name%s-lcap%b-ucap%b"]; IF minorRA.ok THEN minorR ¬ minorRA.real; IF majorRA.ok THEN majorR ¬ majorRA.real; IF uResA.ok THEN uRes ¬ uResA.int; IF vResA.ok THEN vRes ¬ vResA.int; IF minThetaA.ok THEN minTheta ¬ IF radiansA.ok THEN minThetaA.real ELSE minThetaA.real*degToRad; IF maxThetaA.ok THEN maxTheta ¬ IF radiansA.ok THEN maxThetaA.real ELSE maxThetaA.real*degToRad; IF minPsiA.ok THEN minPsi ¬ IF radiansA.ok THEN minPsiA.real ELSE minPsiA.real*degToRad; IF maxPsiA.ok THEN maxPsi ¬ IF radiansA.ok THEN maxPsiA.real ELSE maxPsiA.real*degToRad; shape ¬ ConstructTorus[uRes, vRes, minorR, majorR, minTheta, maxTheta, minPsi, maxPsi, lcapA.ok, ucapA.ok]; shape.name ¬ IF nameA.ok THEN nameA.rope ELSE AutoName[ps.context3d, "AutoTorus"]; LoadShape[ps, state, shape]; }; MakeNGon: PUBLIC SceneProc ~ { shape: Shape; state: State ¬ GetBuildState[ps]; sidesA, radA, nameA, radialNormsA, zA, minThetaA, maxThetaA, radiansA: Arg; rad: REAL ¬ 1.0; z: REAL ¬ 0.0; sides: INT ¬ 10; radialNorms: BOOL ¬ FALSE; minTheta: REAL ¬ 0.0; maxTheta: REAL ¬ piTimes2; name: ROPE ¬ AutoName[ps.context3d, "AutoNGon"]; [sidesA, radA, zA, radialNormsA, nameA, minThetaA, maxThetaA, radiansA] ¬ G3dScene.GetArgs[ps, args, "%i-r%r-z%r-radial%b-name%s-minTheta%r-maxTheta%r-radians%b"]; sides ¬ sidesA.int; IF radA.ok THEN rad ¬ radA.real; IF zA.ok THEN z ¬ zA.real; IF nameA.ok THEN name ¬ nameA.rope; IF radialNormsA.ok THEN radialNorms ¬ TRUE; IF minThetaA.ok THEN { minTheta ¬ minThetaA.real; IF NOT radiansA.ok THEN minTheta ¬ minTheta * degToRad; }; IF maxThetaA.ok THEN { maxTheta ¬ maxThetaA.real; IF NOT radiansA.ok THEN maxTheta ¬ maxTheta * degToRad; }; shape ¬ ConstructNgonShape[rad, sides, z, radialNorms, TRUE, minTheta, maxTheta]; shape.name ¬ name; LoadShape[ps, state, shape]; G3dRender.SetRenderStyle[ps.currentShape, faceted]; }; MakeBox: PUBLIC SceneProc ~ { shape: Shape; state: State ¬ GetBuildState[ps]; dxA, dyA, dzA, nameA: Arg; dx, dy, dz: REAL ¬ -1.0; name: ROPE ¬ AutoName[ps.context3d, "AutoBox"]; [dxA, dyA, dzA, nameA] ¬ G3dScene.GetArgs[ps, args, "%rrr-name%s"]; IF nameA.ok THEN name ¬ nameA.rope; shape ¬ ConstructBox[dxA.real, dyA.real, dzA.real]; shape.name ¬ name; LoadShape[ps, state, shape]; G3dRender.SetRenderStyle[ps.currentShape, faceted]; }; MakeAnnulus: PUBLIC SceneProc ~ { shape: Shape; state: State ¬ GetBuildState[ps]; stepsA, smallRA, bigRA, nameA, radialNormsA, zA, minThetaA, maxThetaA, radiansA: Arg; smallR: REAL ¬ 0.5; bigR: REAL ¬ 1.0; z: REAL ¬ 0.0; radialNorms: BOOL ¬ FALSE; steps: INT ¬ 10; minTheta: REAL ¬ 0.0; maxTheta: REAL ¬ piTimes2; name: ROPE ¬ AutoName[ps.context3d, "AutoAnnulus"]; [stepsA, smallRA, bigRA, zA, radialNormsA, nameA, minThetaA, maxThetaA, radiansA] ¬ G3dScene.GetArgs[ps, args, "-steps%i-minorR%r-majorR%r-z%r-radial%b-name%s-minTheta%r-maxTheta%r-radians%b"]; IF stepsA.ok THEN steps ¬ stepsA.int; IF smallRA.ok THEN smallR ¬ smallRA.real; IF bigRA.ok THEN bigR ¬ bigRA.real; IF zA.ok THEN z ¬ zA.real; IF minThetaA.ok THEN { minTheta ¬ minThetaA.real; IF NOT radiansA.ok THEN minTheta ¬ minTheta * degToRad; }; IF maxThetaA.ok THEN { maxTheta ¬ maxThetaA.real; IF NOT radiansA.ok THEN maxTheta ¬ maxTheta * degToRad; }; IF nameA.ok THEN name ¬ nameA.rope; IF radialNormsA.ok THEN radialNorms ¬ TRUE; shape ¬ ConstructAnnulus[smallR, bigR, steps, z, radialNorms, TRUE, minTheta, maxTheta]; shape.name ¬ name; LoadShape[ps, state, shape]; G3dRender.SetRenderStyle[ps.currentShape, faceted]; }; ShapeFromTripleSequence: PUBLIC PROC [ts: TripleSequence] RETURNS [shape: Shape] ~ { ns: NatSequence ¬ NEW[NatSequenceRep[ts.length]]; shape ¬ NEW[ShapeRep ¬ []]; FOR i: INT IN [0..ts.length) DO v: Vertex ¬ NEW[VertexRep ¬ []]; v.point ¬ ts[i]; shape.vertices ¬ G3dShape.AddToVertexSequence[shape.vertices, v]; ENDLOOP; ns.length ¬ ts.length; FOR i: INT IN [0..ts.length) DO ns[i] ¬ i; ENDLOOP; shape.surfaces ¬ G3dBasic.AddToSurfaceSequence[shape.surfaces, [NIL, ns]]; G3dShape.SetFaceNormals[shape]; G3dShape.SetFaceCenters[shape]; G3dShape.SetVertexNormals[shape]; }; ShapeFromTripleList: PUBLIC PROC [tl: LIST OF Triple] RETURNS [shape: Shape] ~ { i: INT ¬ 0; ns: NatSequence ¬ NIL; shape ¬ NEW[ShapeRep ¬ []]; FOR t: LIST OF Triple ¬ tl, t.rest UNTIL t = NIL DO v: Vertex ¬ NEW[VertexRep ¬ []]; v.point ¬ t.first; shape.vertices ¬ G3dShape.AddToVertexSequence[shape.vertices, v]; ENDLOOP; FOR t: LIST OF Triple ¬ tl, t.rest UNTIL t = NIL DO ns ¬ G2dBasic.AddToNatSequence[ns, i]; i ¬ i+1; ENDLOOP; shape.surfaces ¬ G3dBasic.AddToSurfaceSequence[shape.surfaces, [NIL, ns]]; G3dShape.SetFaceNormals[shape]; G3dShape.SetFaceCenters[shape]; G3dShape.SetVertexNormals[shape]; }; ResampleTriples: PUBLIC PROC [ ts: TripleSequence, steps: INT, close: BOOL, curved: BOOL ¬ TRUE] RETURNS [TripleSequence] ~ { RETURN[LinearResampleTriples[ts, steps, close]]; }; LinearResampleTriples: PROC [ts: TripleSequence, steps: INT, close: BOOL] RETURNS [TripleSequence] ~ { arcLengths: RealSequence ¬ NIL; totalArcLength: REAL ¬ 0.0; newTriples: TripleSequence ¬ NIL; arcLengths ¬ G2dBasic.AddToRealSequence[arcLengths, 0.0]; FOR i: INT IN [0 .. ts.length-1) DO len: REAL ¬ G3dVector.Distance[ts[i], ts[i+1]]; totalArcLength ¬ totalArcLength + len; arcLengths ¬ G2dBasic.AddToRealSequence[arcLengths, totalArcLength]; ENDLOOP; IF close THEN { len: REAL ¬ G3dVector.Distance[ts[0], ts[ts.length-1]]; totalArcLength ¬ totalArcLength + len; arcLengths ¬ G2dBasic.AddToRealSequence[arcLengths, totalArcLength]; }; FOR i: INT IN [0 .. steps) DO alpha: REAL ¬ IF close THEN REAL[i]/REAL[steps] ELSE REAL[i]/REAL[steps-1]; position: REAL ¬ alpha * totalArcLength; segment: INT ¬ 0; lerp, d: REAL; newpt: Triple; WHILE position > arcLengths[segment+1] DO segment ¬ segment+1; ENDLOOP; d ¬ arcLengths[segment+1] - arcLengths[segment]; IF d = 0.0 THEN lerp ¬ 0.0 ELSE lerp ¬ (position - arcLengths[segment])/d; newpt ¬ G3dVector.Interp[lerp, ts[segment], ts[(segment+1) MOD ts.length]]; newTriples ¬ G3dBasic.AddToTripleSequence[newTriples, newpt]; ENDLOOP; RETURN[newTriples]; }; LoadShape: PUBLIC PROC [ps: ParseState, state: State, shape: Shape] ~ { G3dRender.AddShape[ps.context3d, shape]; UpdateShape[ps, state, shape]; }; UpdateShape: PUBLIC PROC [ps: ParseState, state: State, shape: Shape] ~ { SetTexture: PROC [name: ROPE, style: TextureStyle] ~ { IF name # NIL THEN [] ¬ G3dRender.SetTextureMap[shape, name, style]; }; shape.vertices.valid ¬ [TRUE, FALSE, TRUE, FALSE]; shape.type ¬ $ConvexPolygon; shape.fileName ¬ NIL; G3dScene.AssignCtmToShape[ps, shape]; ps.currentShape ¬ shape; G3dShape.UnitizeVertexNormals[shape]; G3dShape.SetFaceNormals[shape]; G3dShape.SetFaceCenters[shape]; G3dScene.InheritMaterial[ps]; }; AutoName: PUBLIC PROC [context3d: Context3d, type: ROPE] RETURNS [ROPE] ~ { shapes: ShapeSequence ¬ context3d.shapes; index: INT ¬ IF shapes = NIL THEN 0 ELSE shapes.length; RETURN[IO.PutFR["%g%g", IO.rope[type], IO.int[index]]]; }; AutoUTexture: PUBLIC PROC [shape: Shape] ~ { FOR i: INT IN [0 .. shape.vertices.length) DO alpha: REAL ¬ IF shape.vertices.length > 1 THEN REAL[i]/REAL[shape.vertices.length-1] ELSE 0.0; shape.vertices[i].texture.x ¬ alpha; ENDLOOP; }; ClearSweepPaths: PUBLIC SceneProc ~ { state: State ¬ GetBuildState[ps]; state.sweepPaths ¬ NEW[SweepPathsRep ¬ []]; }; ChangeSweepPaths: PUBLIC SceneProc ~ { state: State ¬ GetBuildState[ps]; shapeA, shapeBlendA, scaleA, scaleBlendA, pathA, pathBlendA, translateA, translateBlendA, rotateA, rotateBlendA: Arg; [shapeA, shapeBlendA, scaleA, scaleBlendA, pathA, pathBlendA, translateA, translateBlendA, rotateA, rotateBlendA] ¬ G3dScene.GetArgs[ps, args, "-shape%s-shapeBlend%s-scale%s-scaleBlend%s-path%s-pathBlend%s-translate%s-translateBlend%s-rotate%s-rotateBlend%s"]; IF shapeA.ok THEN state.sweepPaths.shapeFile ¬ shapeA.rope; IF shapeBlendA.ok THEN state.sweepPaths.shapeBlend ¬ BlendFromArg[shapeBlendA, smooth]; IF scaleA.ok THEN state.sweepPaths.scaleFile ¬ scaleA.rope; IF scaleBlendA.ok THEN state.sweepPaths.scaleBlend ¬ BlendFromArg[scaleBlendA, smooth]; IF pathA.ok THEN state.sweepPaths.pathFile ¬ pathA.rope; IF pathBlendA.ok THEN state.sweepPaths.pathBlend ¬ BlendFromArg[pathBlendA, smooth]; IF translateA.ok THEN state.sweepPaths.translateFile ¬ translateA.rope; IF translateBlendA.ok THEN state.sweepPaths.translateBlend ¬ BlendFromArg[translateBlendA, smooth]; IF rotateA.ok THEN state.sweepPaths.rotateFile ¬ rotateA.rope; IF rotateBlendA.ok THEN state.sweepPaths.rotateBlend ¬ BlendFromArg[rotateBlendA, smooth]; }; MakeSweep: PUBLIC SceneProc ~ { shape: Shape; state: State ¬ GetBuildState[ps]; tLo: REAL ¬ 0.0; tHi: REAL ¬ 1.0; steps: INT ¬ 10; sp: SweepPaths ¬ state.sweepPaths; onlyA, stepsA, anchorA, connectA, instanceA, localXSectionsA: Arg; tubeTextureA, closeA, nameA, tLoA, tHiA, activeA: Arg; [onlyA, activeA, stepsA, anchorA, connectA, instanceA, localXSectionsA, tubeTextureA, closeA, nameA, tLoA, tHiA] ¬ G3dScene.GetArgs[ps, args, "-onlyshape%s-activeShape%b-steps%i-anchor%s-connect%s-instance%s-localXSections%s-tubetexture%s-close%s-name%s-tlo%r-thi%r"]; shape ¬ G3dSweep.MakeSweepShape[ shapeProc: IF sp.shapeFile # NIL THEN G3dSweep.DefaultShapeBlendProc ELSE NIL, shapeData: IF sp.shapeFile # NIL THEN G3dSweep.SetupDefaultShapeBlendProc[sp.shapeFile, sp.shapeBlend] ELSE IF onlyA.ok THEN G3dShape.FindShape[ps.context3d.shapes, onlyA.rope] ELSE ps.currentShape, shapeBlend: sp.shapeBlend, pathProc: IF sp.pathFile # NIL THEN G3dSweep.DefaultPathProc ELSE NIL, pathData: IF sp.pathFile # NIL THEN G3dSweep.SetupDefaultPathProc[sp.pathFile, sp.pathBlend] ELSE NIL, pathBlend: sp.pathBlend, scaleProc: IF sp.scaleFile # NIL THEN G3dSweep.DefaultScaleProc ELSE NIL, scaleData: IF sp.scaleFile # NIL THEN G3dSweep.SetupDefaultScaleProc[sp.scaleFile, sp.scaleBlend] ELSE NIL, scaleBlend: sp.scaleBlend, rotateProc: IF sp.rotateFile # NIL THEN G3dSweep.DefaultRotateProc ELSE NIL, rotateData: IF sp.rotateFile # NIL THEN G3dSweep.SetupDefaultRotateProc[sp.rotateFile, sp.rotateBlend] ELSE NIL, rotateBlend: sp.rotateBlend, translateProc: IF sp.translateFile # NIL THEN G3dSweep.DefaultTranslateProc ELSE NIL, translateData: IF sp.translateFile # NIL THEN G3dSweep.SetupDefaultTranslateProc[sp.translateFile, sp.translateBlend] ELSE NIL, translateBlend: sp.translateBlend, xformProc: NIL, xformData: NIL, xformBlend: smooth, tLo: IF tLoA.ok THEN tLoA.real ELSE tLo, tHi: IF tHiA.ok THEN tHiA.real ELSE tHi, steps: IF stepsA.ok THEN stepsA.int ELSE steps, anchor: BoolFromArg[anchorA, FALSE], instance: BoolFromArg[instanceA, TRUE], connect: BoolFromArg[connectA, TRUE], localXSections: BoolFromArg[localXSectionsA, FALSE], tubeTexture: BoolFromArg[tubeTextureA, TRUE], close: BoolFromArg[closeA, TRUE] ]; shape.name ¬ IF nameA.ok THEN nameA.rope ELSE AutoName[ps.context3d, "AutoSweep"]; LoadShape[ps, state, shape]; }; ConstructCone: PROC [steps: INT, rLo, rHi, zLo, zHi: REAL, lcap, ucap: BOOL, minTheta, maxTheta: REAL] RETURNS [Shape] ~ { auxShape, shape: Shape; auxShape ¬ ConstructNgonShape[1.0, steps, 0.0, FALSE, TRUE, minTheta, maxTheta]; shape ¬ G3dSweep.MakeSweepShape[ shapeProc: NIL, shapeData: auxShape, shapeBlend: straight, scaleProc: G3dSweep.DefaultScaleProc, scaleData: G3dSweep.SimpleSetupScaleProc[[rLo, rLo, 1.0], [rHi, rHi, 1.0]], scaleBlend: straight, translateProc: G3dSweep.DefaultTranslateProc, translateData: G3dSweep.SimpleSetupTranslateProc[[0.0, 0.0, zLo], [0.0, 0.0, zHi]], translateBlend: straight, steps: 2, firstInstance: lcap, lastInstance: ucap, reverseFirstInstance: FALSE, reverseLastInstance: FALSE, anchor: TRUE, instance: FALSE, connect: TRUE, localXSections: FALSE, tubeTexture: TRUE, close: FALSE ]; RETURN[shape]; }; ConstructTorus: PROC [ uRes, vRes: INT, minorR, majorR: REAL, minTheta, maxTheta: REAL, minPsi, maxPsi: REAL, lcap, ucap: BOOL ] RETURNS [Shape] ~ { auxShape, shape: Shape; ts: TripleSequence; sd: SurfaceDescription ¬ NEW[SurfaceDescriptionRep ¬ []]; objClosed: BOOL; tmp: REAL; FOR step: INT IN [0 .. vRes) DO alpha: REAL ¬ REAL[step] / REAL[vRes]; theta: REAL ¬ LerpReal[alpha, minPsi, maxPsi]; t: Triple ¬ [minorR * RealFns.Cos[theta], 0.0, minorR * -RealFns.Sin[theta]]; t.x ¬ t.x + majorR; ts ¬ G3dBasic.AddToTripleSequence[ts, t]; ENDLOOP; auxShape ¬ ShapeFromTripleSequence[ts]; AutoUTexture[auxShape]; tmp ¬ maxPsi - minPsi; -- is the contour closed? sd.open ¬ NOT (Real.Floor[tmp/piTimes2] = (tmp/piTimes2)); auxShape.surfaces[0].clientData ¬ sd; tmp ¬ maxTheta - minTheta; -- is the torus itself closed? objClosed ¬ Real.Floor[tmp/piTimes2] = (tmp/piTimes2); shape ¬ G3dSweep.MakeSweepShape[ shapeProc: NIL, shapeData: auxShape, shapeBlend: straight, rotateProc: G3dSweep.DefaultRotateProc, rotateData: G3dSweep.SimpleSetupRotateProc[ [[0.0, 0.0, 1.0], minTheta], [[0.0, 0.0, 1.0], maxTheta] ], rotateBlend: straight, steps: uRes, anchor: FALSE, instance: FALSE, connect: TRUE, localXSections: FALSE, tubeTexture: TRUE, close: objClosed, firstInstance: lcap, lastInstance: ucap, reverseFirstInstance: FALSE, reverseLastInstance: FALSE ]; RETURN[shape]; }; ConstructSphere: PROC [ uRes, vRes: INT, minTheta, maxTheta: REAL, minPsi, maxPsi: REAL, radius: REAL ] RETURNS [Shape] ~ { shape, auxShape: Shape; ts: TripleSequence; sd: SurfaceDescription ¬ NEW[SurfaceDescriptionRep ¬ []]; bs: BoolSequence ¬ NIL; FOR step: INT IN [0 .. vRes) DO alpha: REAL ¬ REAL[step] / REAL[vRes-1]; psi: REAL ¬ LerpReal[alpha, minPsi, maxPsi]; t: Triple ¬ [radius * RealFns.Sin[psi], 0.0, radius * -RealFns.Cos[psi]]; ts ¬ G3dBasic.AddToTripleSequence[ts, t]; ENDLOOP; auxShape ¬ ShapeFromTripleSequence[ts]; AutoUTexture[auxShape]; IF minPsi = 0.0 OR maxPsi = pi THEN { FOR step: INT IN [0 .. vRes) DO bs ¬ G3dBasic.AddToBoolSequence[bs, FALSE]; ENDLOOP; IF minPsi = 0.0 THEN bs[0] ¬ TRUE; IF maxPsi = pi THEN bs[vRes-1] ¬ TRUE; }; auxShape.clientData ¬ bs; sd.open ¬ TRUE; auxShape.surfaces[0].clientData ¬ sd; shape ¬ RevolveShape[auxShape, uRes, minTheta, maxTheta, [0.0, 0.0, 1.0], FALSE, TRUE]; RETURN[shape]; }; ConstructNgonShape: PROC [r: REAL, n: INT, z: REAL, radialNorms: BOOL ¬ FALSE, positiveNormal: BOOL ¬ TRUE, loTheta: REAL ¬ 0.0, hiTheta: REAL ¬ piTimes2] RETURNS [shape: Shape] ~ { vSequence: NatSequence ¬ NIL; shape ¬ NEW[ShapeRep ¬ []]; FOR i: INT IN [0 .. n) DO alpha: REAL ¬ REAL[i] / REAL[n]; theta: REAL ¬ loTheta + ((hiTheta - loTheta) * alpha); vtx: Vertex ¬ NEW[VertexRep ¬ []]; cosTheta: REAL ¬ RealFns.Cos[theta]; sinTheta: REAL ¬ RealFns.Sin[theta]; vtx.point ¬ [r*cosTheta, -r*sinTheta, z]; IF radialNorms THEN vtx.normal ¬ [cosTheta, -sinTheta, 0.0] ELSE IF positiveNormal THEN vtx.normal ¬ [0.0, 0.0, 1.0] ELSE vtx.normal ¬ [0.0, 0.0, -1.0]; vtx.texture ¬ [alpha, alpha]; shape.vertices ¬ G3dShape.AddToVertexSequence[shape.vertices, vtx]; ENDLOOP; IF positiveNormal THEN { FOR i: INT IN [0 .. n) DO vSequence ¬ G2dBasic.AddToNatSequence[vSequence, i]; ENDLOOP; } ELSE { FOR i: INT DECREASING IN [0 .. n) DO vSequence ¬ G2dBasic.AddToNatSequence[vSequence, i]; ENDLOOP; }; shape.surfaces ¬ G3dBasic.AddToSurfaceSequence[shape.surfaces, [NIL, vSequence]]; }; ConstructBox: PROC [dx, dy, dz: REAL] RETURNS [shape: Shape] ~ { AddVert: PROC [x, y, z, u, v: REAL] ~ { vtx: Vertex ¬ NEW[VertexRep ¬ [point: [x, y, z], normal: norm, texture: [u, v]]]; shape.vertices ¬ G3dShape.AddToVertexSequence[shape.vertices, vtx]; }; norm: Triple; shape ¬ NEW[ShapeRep ¬ []]; norm ¬ [ 0.0, -1.0, 0.0]; AddVert[-dx, -dy, -dz, 0.0, 1.0]; -- near lower left AddVert[-dx, -dy, dz, 0.0, 0.0]; -- near upper left AddVert[ dx, -dy, dz, 1.0, 0.0]; -- near upper right AddVert[ dx, -dy, -dz, 1.0, 1.0]; -- near lower right norm ¬ [1.0, 0.0, 0.0]; AddVert[ dx, -dy, -dz, 0.0, 1.0]; -- near lower right AddVert[ dx, -dy, dz, 0.0, 0.0]; -- near upper right AddVert[ dx, dy, dz, 1.0, 0.0]; -- far upper right AddVert[ dx, dy, -dz, 1.0, 1.0]; -- far lower right norm ¬ [ 0.0, 0.0, 1.0]; AddVert[-dx, -dy, dz, 0.0, 1.0]; -- near upper left AddVert[-dx, dy, dz, 0.0, 0.0]; -- far upper left AddVert[ dx, dy, dz, 1.0, 0.0]; -- far upper right AddVert[ dx, -dy, dz, 1.0, 1.0]; -- near upper right norm ¬ [-1.0, 0.0, 0.0]; AddVert[-dx, dy, -dz, 0.0, 1.0]; -- far lower left AddVert[-dx, dy, dz, 0.0, 0.0]; -- far upper left AddVert[-dx, -dy, dz, 1.0, 0.0]; -- near upper left AddVert[-dx, -dy, -dz, 1.0, 1.0]; -- near lower left norm ¬ [ 0.0, 1.0, 0.0]; AddVert[ dx, dy, -dz, 0.0, 1.0]; -- far lower right AddVert[ dx, dy, dz, 0.0, 0.0]; -- far upper right AddVert[-dx, dy, dz, 1.0, 0.0]; -- far upper left AddVert[-dx, dy, -dz, 1.0, 1.0]; -- far lower left norm ¬ [ 0.0, 0.0, -1.0]; AddVert[-dx, dy, -dz, 0.0, 1.0]; -- far lower left AddVert[-dx, -dy, -dz, 0.0, 0.0]; -- near lower left AddVert[ dx, -dy, -dz, 1.0, 0.0]; -- near lower right AddVert[ dx, dy, -dz, 1.0, 1.0]; -- far lower right G3dSweep.AddGeneralQuadrilateralToShape[shape, 0, 1, 2, 3]; -- near G3dSweep.AddGeneralQuadrilateralToShape[shape, 4, 5, 6, 7]; -- right G3dSweep.AddGeneralQuadrilateralToShape[shape, 8, 9, 10, 11]; -- upper G3dSweep.AddGeneralQuadrilateralToShape[shape, 12, 13, 14, 15]; -- left G3dSweep.AddGeneralQuadrilateralToShape[shape, 16, 17, 18, 19]; -- far G3dSweep.AddGeneralQuadrilateralToShape[shape, 20, 21, 22, 23]; -- lower RETURN[shape]; }; ConstructAnnulus: PROC [smallR, bigR: REAL, steps: INT, z: REAL, radialNorms: BOOL ¬ FALSE, positiveNormal: BOOL ¬ TRUE, minTheta: REAL ¬ 0.0, maxTheta: REAL ¬ piTimes2] RETURNS [shape: Shape] ~ { shape ¬ NEW[ShapeRep ¬ []]; FOR i: INT IN [0 .. steps) DO alpha: REAL ¬ REAL[i] / REAL[steps]; theta: REAL ¬ minTheta + ((maxTheta - minTheta) * alpha); vtx: Vertex ¬ NEW[VertexRep ¬ []]; cosTheta: REAL ¬ RealFns.Cos[theta]; sinTheta: REAL ¬ RealFns.Sin[theta]; vtx.point ¬ [bigR*cosTheta, -bigR*sinTheta, z]; IF radialNorms THEN vtx.normal ¬ [cosTheta, -sinTheta, 0.0] ELSE IF positiveNormal THEN vtx.normal ¬ [0.0, 0.0, 1.0] ELSE vtx.normal ¬ [0.0, 0.0, -1.0]; vtx.texture ¬ [alpha, alpha]; shape.vertices ¬ G3dShape.AddToVertexSequence[shape.vertices, vtx]; ENDLOOP; FOR i: INT IN [0 .. steps) DO theta: REAL ¬ piTimes2 * i / REAL[steps]; vtx: Vertex ¬ NEW[VertexRep ¬ []]; cosTheta: REAL ¬ RealFns.Cos[theta]; sinTheta: REAL ¬ RealFns.Sin[theta]; vtx.point ¬ [smallR*cosTheta, -smallR*sinTheta, z]; IF radialNorms THEN vtx.normal ¬ [-cosTheta, sinTheta, 0.0] ELSE IF positiveNormal THEN vtx.normal ¬ [0.0, 0.0, 1.0] ELSE vtx.normal ¬ [0.0, 0.0, -1.0]; vtx.texture ¬ [cosTheta, -sinTheta]; shape.vertices ¬ G3dShape.AddToVertexSequence[shape.vertices, vtx]; ENDLOOP; FOR i: INT IN [0 .. steps) DO nexti: INT ¬ (i+1) MOD steps; iprime: INT ¬ i + steps; nextiprime: INT ¬ nexti + steps; G3dSweep.AddTriangleToShape[shape, i, nexti, iprime]; G3dSweep.AddTriangleToShape[shape, nexti, nextiprime, iprime]; ENDLOOP; IF NOT positiveNormal THEN G3dShape.ReversePolygons[shape]; RETURN[shape]; }; TranslateShapeAlongZ: PUBLIC PROC [ shape: Shape, distance: REAL ¬ 1.0, anchor: BOOL ¬ FALSE ] RETURNS [Shape] ~ { z: Triple ¬ [0.0, 0.0, 1.0]; RETURN[ TranslateShape[shape, [0.0, 0.0, 0.0], G3dVector.Mul[z, distance], anchor] ]; }; TranslateShape: PUBLIC PROC [ shape: Shape, lo, hi: Triple, anchor: BOOL ¬ FALSE ] RETURNS [Shape] ~ { RETURN[ G3dSweep.MakeSweepShape[ shapeProc: NIL, shapeData: shape, shapeBlend: straight, translateProc: G3dSweep.DefaultTranslateProc, translateData: G3dSweep.SimpleSetupTranslateProc[lo, hi], translateBlend: straight, steps: 2, anchor: anchor, instance: FALSE, connect: TRUE, localXSections: FALSE, tubeTexture: TRUE, close: FALSE ] ]; }; RevolveShape: PUBLIC PROC [ shape: Shape, steps: INT ¬ 10, loAngle: REAL ¬ 0.0, -- angle extreme in degrees hiAngle: REAL ¬ 360.0, -- angle extreme in degrees axis: Triple ¬ [0.0, 0.0, 1.0], -- z axis by default anchor: BOOL ¬ FALSE, objClosed: BOOL ¬ FALSE ] RETURNS [Shape] ~ { RETURN[ G3dSweep.MakeSweepShape[ shapeProc: NIL, shapeData: shape, shapeBlend: straight, rotateProc: G3dSweep.DefaultRotateProc, rotateData: G3dSweep.SimpleSetupRotateProc[[axis, loAngle], [axis, hiAngle]], rotateBlend: straight, steps: steps, anchor: anchor, instance: FALSE, connect: TRUE, localXSections: FALSE, tubeTexture: TRUE, close: objClosed ] ]; }; BlendFromArg: PUBLIC PROC [a: Arg, default: BlendType] RETURNS [BlendType] ~ { IF a.ok THEN RETURN[BlendFromRope[a.rope]] ELSE RETURN [default]; }; BlendFromRope: PUBLIC PROC [r: ROPE] RETURNS [BlendType] ~ { RE: PROC [a, b: ROPE] RETURNS [BOOL] ~ { RETURN[Rope.Equal[a, b, FALSE]]; }; IF RE[r, "straight"] OR RE[r, "linear"] THEN RETURN [straight]; IF RE[r, "smooth"] OR RE[r, "cubic"] THEN RETURN [smooth]; IF RE[r, "cyclic"] OR RE[r, "closed"] THEN RETURN [cyclic]; RETURN [smooth]; }; BoolFromArg: PUBLIC PROC [a: Arg, default: BOOL] RETURNS [BOOL] ~ { IF a.ok THEN RETURN[BoolFromRope[a.rope]] ELSE RETURN [default]; }; BoolFromRope: PUBLIC PROC [r: ROPE] RETURNS [BOOL] ~ { RETURN[Rope.Equal[r, "Yes", FALSE] OR Rope.Equal[r, "True", FALSE]]; }; RopeFromBool: PUBLIC PROC [b: BOOL] RETURNS [ROPE] ~ { IF b THEN RETURN["True"] ELSE RETURN["False"]; }; LerpReal: PROC [a, lo, hi: REAL] RETURNS [REAL] ~ { RETURN[lo + (a * (hi-lo))]; }; RegisterProcs: PROC ~ { G3dScene.RegisterProc["Sphere", MakeSphere]; G3dScene.RegisterProc["Cylinder", MakeCylinder]; G3dScene.RegisterProc["Cone", MakeCone]; G3dScene.RegisterProc["Torus", MakeTorus]; G3dScene.RegisterProc["NGon", MakeNGon]; G3dScene.RegisterProc["Annulus", MakeAnnulus]; G3dScene.RegisterProc["Box", MakeBox]; G3dScene.RegisterProc["ClearSweepPaths", ClearSweepPaths]; G3dScene.RegisterProc["ChangeSweepPaths", ChangeSweepPaths]; G3dScene.RegisterProc["Sweep", MakeSweep]; }; RegisterProcs[]; END. ˜ G3dBuildAImpl.mesa Copyright Σ 1985, 1992 by Xerox Corporation. All rights reserved. Glassner, November 17, 1989 12:38:07 pm PST Bloomenthal, July 15, 1992 11:31 pm PDT Imported Types Local Types Constants Get Build State Polygonal Surface Procedures sd: SurfaceDescription _ NEW[SurfaceDescriptionRep _ []]; -- unused Shape Saving and Book-keeping Procedures -- ignore curved flag, since curved interpolation is just too slow right now CurvedResampleTriples: PROC [ts: TripleSequence, steps: INT, close: BOOL] RETURNS [TripleSequence] ~ { -- yow! This is monstrously slow - don't use it yet! output: TripleSequence _ NIL; ss: G3dSpline.SplineSequence _ IF close THEN G3dSpline.InterpolateCyclic[ts] ELSE G3dSpline.Interpolate[ts]; c: G3dCurve.Curve _ G3dCurve.CurveFromSplines[ss]; FOR i: INT IN [0 .. steps) DO alpha: REAL _ REAL[i]/REAL[steps-1]; p: Triple _ G3dCurve.PositionA[c, alpha*c.totalLength]; output _ G3dBasic.AddToTripleSequence[output, p]; ENDLOOP; RETURN[output]; RETURN[ts]; }; Sweep Surface Procedures Shape Creation Procedures a regular n-gon in the xy plane, whose front face is towards +z the vertices the polygons we do each face individually to preserve unique texturing information for each face near face right face upper face left face far face lower face the vertices the polygons Primitive Sweep Convenience Procedures Utility Procedures Start Procedures primitive objects sweep objects Κ!΄•NewlineDelimiter –"cedarcode" style™™Jšœ Οeœ6™BJ™+J™'J™JšΟk œ,žœΓžœ‰˜…J˜—šΡbln œžœž˜JšžœIžœ˜pJšžœ ˜J˜—Jšœž˜headšΟl™Jšœ žœ ˜Jšœžœ˜-Jšœžœ˜(Jšœžœ˜-Jšœžœ˜)Jšœžœ˜'Jšœžœ˜,Jšœžœ˜1Jšœžœ˜*Jšœžœ˜-Jšœžœ˜-Jšžœžœžœ˜Jšœžœ˜(Jšœ žœ˜!Jšœ žœ˜&Jšœžœ˜/Jšœžœ˜8Jšœžœ"˜=Jšœžœ˜/Jšœ žœ˜#Jšœžœ˜1Jšœ žœ˜#Jšœžœ˜(J˜Jš Οnœžœžœžœ žœžœ˜;—š  ™ Jšœžœ˜*Jšœžœ˜/Jšœ žœ˜"Jšœžœ˜'Jšœ žœ˜"Jšœžœ˜'—š  ™ Jšœžœ˜Jšœ žœ ˜Jšœ žœ ˜Jšœ žœ˜Jšœ žœ ˜—š ™š Πbn œΟsž£ž£œžœ ˜?J˜ šžœž˜šžœ˜Jšœžœ˜*Jšœžœ˜!Jšœžœ˜+J˜%J˜—Jšžœ žœ˜"—Jšžœ˜J˜——š ™šœžœžœ˜J˜—š’ œžœ˜!J˜!Jšœžœ ˜Jšœžœ˜Jšœ žœ˜Jšœ žœ˜Jšœ žœ ˜Jšœžœ˜Jšœžœ˜J˜TJšœžœ'™C˜mJ˜OJ˜—Jšžœ žœ˜)Jšžœ žœ˜"Jšžœ žœ˜"šžœž˜Jšœ žœ žœžœ˜K—šžœž˜Jšœ žœ žœžœ˜K—šžœ ž˜Jšœ žœ žœžœ˜E—šžœ ž˜Jšœ žœ žœžœ˜EJ˜—šžœ˜šžœ˜š!‘œ£ž£œ £žœ£œ£œ£œ£œ£ž£œ£œ£ž£œ£œ£œ£œ˜VJšœ žœ˜,J˜J˜;Jšžœžœ˜)J˜—Jšœ žœ˜!Jšœ žœ˜Jšœ žœ˜ Jšœžœ(˜Jšœ9€ ˜Fšžœžœžœ ž˜Jšœžœ ˜Jšœžœ žœžœ ˜8Jšœžœ˜ Jšœžœ˜ šžœžœžœ ž˜Jšœžœ žœžœ˜žœ˜XJ˜J˜J˜3J˜——š (™(š’œžœžœžœ˜TJšœžœ˜1Jšœžœ˜šžœžœžœžœ˜ Jšœ žœ˜ J˜J˜AJšžœ˜—J˜šžœžœžœžœ˜ J˜ Jšžœ˜—Jšœ@žœ˜JJ˜J˜J˜!J˜J˜—š ’œžœžœžœžœ žœ˜PJšœžœ˜ Jšœžœ˜Jšœžœ˜š žœžœžœžœžœž˜3Jšœ žœ˜ J˜J˜AJšžœ˜—š žœžœžœžœžœž˜3J˜&J˜Jšžœ˜—Jšœ@žœ˜JJ˜J˜J˜!J˜J˜—š‘œžœžœ˜Jšœ˜Jšœžœ˜ Jšœžœ˜ Jšœžœžœ˜Jšžœ˜Jšœ˜J™LJšžœ*˜0J˜J˜—š‘œžœžœ žœ˜IJšžœ˜Jšœ˜Jšœžœ˜Jšœžœ˜Jšœžœ˜!J˜9šžœžœžœž˜#Jšœžœ&˜/J˜&J˜DJšžœ˜—šžœžœ˜Jšœžœ.˜7J˜&J˜DJ˜—šžœžœžœž˜Jšœžœžœžœžœžœžœžœžœ ˜KJšœ žœ˜(Jšœ žœ˜Jšœ žœ˜J˜šžœ"ž˜)J˜Jšžœ˜—J˜0šžœ˜ Jšžœ ˜Jšžœ+˜/—Jšœ;žœ ˜KJ˜=Jšžœ˜—Jšžœ ˜J˜J˜—š‘œžœžœ žœ™IJšžœ™Jšœ™J™5Jšœžœ™šœžœ™'Jšžœ ™$Jšžœ™—J™2šžœžœžœž™Jšœžœžœžœ ™$J™7J™1Jšžœ™—Jšžœ ™J™ J™J™—š‘ œžœžœ1˜GJ˜(J˜J˜J˜—š‘ œžœžœ1˜Iš‘ œžœžœ˜6Jšžœžœžœ3˜EJ˜—Jš œžœžœžœžœ˜2J˜Jšœžœ˜J˜%J˜J˜%J˜J˜J˜J˜J˜—š ‘œžœžœžœžœžœ˜KJ˜)Jš œžœžœ žœžœžœ˜7Jšžœžœžœ žœ˜7J˜J˜—š‘ œžœžœ˜,šžœžœžœž˜-šœžœžœ˜*Jšžœžœžœ˜*Jšžœ˜ J˜$—Jšžœ˜—J˜——š ™š‘œžœ˜%J˜!Jšœžœ˜+J˜J˜—š‘œžœ˜&J˜!J˜J˜J˜J˜J˜J˜J˜J˜„J˜Jšžœ žœ*˜;šžœž˜J˜@J˜—Jšžœ žœ*˜;šžœž˜J˜@J˜—Jšžœ žœ(˜8šžœž˜J˜>J˜—Jšžœžœ2˜Gšžœž˜J˜HJ˜—Jšžœ žœ,˜>šžœž˜J˜B—J˜J˜—š’ œžœ˜ J˜ J˜!Jšœžœ˜Jšœžœ˜Jšœžœ˜J˜"J˜J˜BJ˜6J˜J˜J˜˜ ˜ šžœž˜Jšžœ˜#Jšžœžœ˜ ——˜ šžœž˜JšžœA˜Ešžœžœ ˜Jšžœ4˜8Jšžœ˜———J˜J˜˜ šžœž˜Jšžœ˜Jšžœžœ˜ ——˜ šžœž˜Jšžœ9˜=Jšžœžœ˜ ——J˜J˜˜ šžœž˜Jšžœ˜Jšžœžœ˜ ——˜ šžœž˜Jšžœ<˜@Jšžœžœ˜ ——J˜J˜˜ šžœž˜Jšžœ˜Jšžœžœ˜ ——˜ šžœž˜Jšžœ?˜CJšžœžœ˜ ——J˜J˜˜šžœž˜Jšžœ˜"Jšžœžœ˜ ——˜šžœž˜JšžœH˜LJšžœžœ˜ ——J˜"J˜Jšœ žœ˜Jšœ žœ˜J˜J˜Jšœžœ žœ žœ˜(Jšœžœ žœ žœ˜(J˜Jšœžœ žœ žœ˜/Jšœžœ˜$Jšœ!žœ˜'Jšœžœ˜%Jšœ-žœ˜4Jšœ'žœ˜-Jšœžœ˜ J˜—Jšœ žœ žœ žœ%˜RJ˜J˜——š ™š’ œžœ žœžœžœžœžœ ˜zJ˜Jšœ/žœžœ˜P˜ Jšœ žœ˜J˜J˜J˜J˜%J˜KJ˜J˜J˜-J˜SJ˜J˜J˜ J˜J˜Jšœžœ˜Jšœžœ˜Jšœžœ˜ Jšœ žœ˜Jšœ žœ˜Jšœžœ˜Jšœ žœ˜Jšœž˜ J˜—Jšžœ˜J˜J˜—š’œžœ˜Jšœ žœ˜Jšœžœ˜Jšœžœ˜Jšœžœ˜Jšœ ž˜šœžœ ˜J˜J˜Jšœžœ˜9Jšœ žœ˜Jšœžœ˜ J˜šžœžœžœ ž˜Jšœžœžœ žœ˜&Jšœžœ#˜.J˜MJ˜J˜)Jšžœ˜—J˜'J˜J˜Jšœ€˜1Jšœ žœ-˜:J˜&J˜Jšœ€˜9J˜6J˜˜ Jšœ žœ˜J˜J˜J˜J˜'˜+J˜J˜J˜—J˜J˜J˜ Jšœžœ˜Jšœ žœ˜Jšœ žœ˜Jšœžœ˜Jšœ žœ˜J˜J˜J˜Jšœžœ˜Jšœž˜J˜—Jšžœ˜J˜—J˜—š’œžœ˜Jšœ žœ˜Jšœžœ˜Jšœžœ˜Jšœž˜ Jšœžœ ˜J˜J˜Jšœžœ˜9Jšœžœ˜J˜šžœžœžœ ž˜Jšœžœžœ žœ ˜(Jšœžœ#˜,J˜IJ˜)Jšžœ˜—J˜'J˜J˜šžœžœ žœ˜%šžœžœžœ ž˜Jšœ$žœ˜+Jšžœ˜—Jšžœžœ žœ˜"Jšžœ žœžœ˜&J˜—J˜J˜Jšœ žœ˜J˜%JšœJžœžœ˜WJšžœ˜J˜J˜J™—J™?š"‘œ£ž£œžœžœžœžœžœžœžœ žœžœ £ž£œ£œ£œ£œ˜ΆJšœžœ˜Jšœžœ˜J™ šžœžœžœ ž˜Jšœžœžœžœ˜ Jšœžœ+˜6Jšœžœ˜"Jšœ žœ˜$Jšœ žœ˜$J˜*šžœ ˜Jšžœ(˜,šžœžœ˜Jšžœ˜!Jšžœ˜#——J˜J˜CJšžœ˜—J™ šžœ˜šžœ˜šžœžœžœ ž˜J˜4Jšžœ˜—J˜—šžœ˜š žœžœž œžœ ž˜$J˜4Jšžœ˜——J˜—Jšœ@žœ˜QJ˜J˜—š‘ œ£ž£œ žœ£ž£œ£œ£œ£œ˜Aš‘œžœžœ˜'Jšœžœ@˜QJ˜CJ˜—J˜ Jšœžœ˜J˜J™SJ™ J˜Jšœ#€˜5Jšœ#€˜5Jšœ#€˜6Jšœ#€˜6J˜J™ J˜Jšœ#€˜6Jšœ#€˜6Jšœ#€˜5Jšœ#€˜5J˜Jš€œ™ J˜Jšœ#€˜5Jšœ#€˜4Jšœ#€˜5Jšœ#€˜6J˜Jš€œ™ J˜Jšœ#€˜4Jšœ#€˜4Jšœ#€˜5Jšœ#€˜5J˜Jš€œ™J˜Jšœ#€˜5Jšœ#€˜5Jšœ#€˜4Jšœ#€˜4J˜Jš€œ™ J˜Jšœ#€˜4Jšœ#€˜5Jšœ#€˜6Jšœ#€˜5J˜Jšœ@€˜GJšœ@€˜HJšœ@€˜HJšœ@€˜GJšœ@€˜FJšœ@€˜HJ˜Jšžœ˜J˜J˜—š"‘œ£ž£œžœ žœžœžœžœžœžœ žœžœ £ž£œ£œ£œ£œ˜ΕJšœžœ˜J™ šžœžœžœž˜Jšœžœžœžœ˜$Jšœžœ.˜9Jšœžœ˜"Jšœ žœ˜$Jšœ žœ˜$J˜0šžœ ˜Jšžœ(˜,šžœžœ˜Jšžœ˜!Jšžœ˜#——J˜J˜CJšžœ˜—šžœžœžœž˜Jšœžœžœ˜)Jšœžœ˜"Jšœ žœ˜$Jšœ žœ˜$J˜4šžœ ˜Jšžœ(˜,šžœžœ˜Jšžœ˜!Jšžœ˜#——J˜$J˜CJšžœ˜—J™ šžœžœžœž˜Jšœžœ žœ˜Jšœžœ ˜Jšœ žœ˜ J˜5J˜>Jšžœ˜—Jšžœžœžœ!˜;Jšžœ˜J˜——š &™&š ’‘œ£ž£ž£œ˜#Jšœ£œ˜ Jšœ £žœ ˜Jšœžœž˜š œ£ž£œ£œ£œ˜J˜šžœ˜J˜JJ˜—J˜—J˜—š’œ£ž£ž£œ˜Jšœ£œ˜ J˜Jšœžœž˜š œ£ž£œ£œ£œ˜šžœ˜˜Jšœ žœ˜J˜J˜J˜J˜-J˜9J˜J˜J˜ J˜Jšœ žœ˜Jšœ žœ˜Jšœžœ˜Jšœ žœ˜Jšœž˜ J˜—J˜——J˜J˜—š’ œ£ž£ž£œ˜Jšœ£œ˜ Jšœ£žœ˜Jšœ£žœ €˜2Jšœ£žœ €˜4Jšœ €˜4Jšœžœžœ˜Jšœ žœž˜š œ£ž£œ£œ£œ˜šžœ˜˜Jšœ žœ˜J˜J˜J˜J˜'J˜MJ˜J˜J˜ J˜Jšœ žœ˜Jšœ žœ˜Jšœžœ˜Jšœ žœ˜J˜J˜—J˜——J˜——š ™š‘ œžœžœžœ˜NJš žœžœžœžœžœ ˜AJ˜J˜—š ‘ œžœžœžœžœ˜