DIRECTORY Real USING [ FixC ], Rope USING [ ROPE ], CedarProcess USING [ DoWithPriority ], ImagerColor USING [ RGB ], Vector3d USING [ Sub, Length ], Matrix3d USING [ Transform ], ThreeDBasics USING [ Context, PairSequence, Quad, ShadingSequence, ShapeInstance, ShapeSequence, ShadingValue, Triple, TripleSequence, Vertex, VertexSequence ], ThreeDScenes USING [ Error, FindShape, NewShape, PutShading, SetPosition ], ThreeDSurfaces USING [ PtrPatchSequence ], ShapeTwiddle USING [ NatPair ]; ShapeTwiddleImpl: CEDAR PROGRAM IMPORTS Real, Vector3d, ThreeDScenes, CedarProcess, Matrix3d EXPORTS ShapeTwiddle ~ BEGIN Context: TYPE ~ ThreeDBasics.Context; ShapeTwiddleError: PUBLIC SIGNAL [reason: ATOM] = CODE; NatPair: TYPE ~ ShapeTwiddle.NatPair; -- RECORD [x, y: NAT]; PairSequence: TYPE ~ ThreeDBasics.PairSequence; Triple: TYPE ~ ThreeDBasics.Triple; TripleSequence: TYPE ~ ThreeDBasics.TripleSequence; RGB: TYPE ~ ImagerColor.RGB; NatSequence: TYPE ~ RECORD [SEQUENCE length: NAT OF NAT]; ScaleShape: PUBLIC PROC [context: REF Context, name: Rope.ROPE, scale: REAL, xRatio, yRatio, zRatio: REAL _ 1.0] ~ { shape: REF ThreeDBasics.ShapeInstance _ ThreeDScenes.FindShape[ context.shapes, name ]; IF shape.positionInValid THEN ThreeDScenes.SetPosition[shape]; -- set position matrix FOR i: NAT IN [0..shape.vertex.length) DO OPEN shape.vertex[i]; tx, ty, tz: REAL; [ [tx, ty, tz] ] _ Matrix3d.Transform[ [x, y, z], shape.position]; x _ tx * scale * xRatio; y _ ty * scale * yRatio; z _ tz * scale * zRatio; ENDLOOP; shape.boundingRadius _ shape.boundingRadius * scale * MAX[xRatio, yRatio, zRatio]; ThreeDScenes.PutShading[ shape, $Scale, NEW[ ThreeDBasics.Quad _ [scale, xRatio, yRatio, zRatio] ] ]; }; ScaleTexture: PUBLIC PROC [context: REF Context, name: Rope.ROPE, scale: REAL, xRatio, yRatio, zRatio: REAL _ 1.0] ~ { shape: REF ThreeDBasics.ShapeInstance _ ThreeDScenes.FindShape[ context.shapes, name ]; IF shape.positionInValid THEN ThreeDScenes.SetPosition[shape]; -- set position matrix WITH shape.auxInfo SELECT FROM pair: REF PairSequence => FOR i: NAT IN [0..pair.length) DO pair[i].x _ pair[i].x * scale * xRatio; pair[i].y _ pair[i].y * scale * yRatio; ENDLOOP; triple: REF TripleSequence => FOR i: NAT IN [0..triple.length) DO triple[i].x _ triple[i].x * scale * xRatio; triple[i].y _ triple[i].y * scale * yRatio; triple[i].z _ triple[i].z * scale * zRatio; ENDLOOP; ENDCASE => SIGNAL ThreeDScenes.Error[[$Unimplemented, "Unknown texture type"]]; ThreeDScenes.PutShading[ shape, $TextureScale, NEW[ ThreeDBasics.Quad _ [scale, xRatio, yRatio, zRatio] ] ]; }; SortPair: TYPE ~ RECORD [vtx, next: NAT]; SortSequence: TYPE ~ RECORD[SEQUENCE length: NAT OF REF SortPair]; CleanUp: PUBLIC PROC [context: REF Context, name: Rope.ROPE, deSeam: BOOLEAN _ FALSE, tolerance: REAL _ 0.0] ~ { currPos: NAT _ 0; shape: REF ThreeDBasics.ShapeInstance _ ThreeDScenes.FindShape[ context.shapes, name ]; surface: REF ThreeDSurfaces.PtrPatchSequence _ NARROW[shape.surface]; table: REF NatSequence _ NEW[ NatSequence[shape.vertex.length] ]; buckets: REF SortSequence _ NEW[SortSequence[5 * shape.vertex.length / 4]]; nextBucket: NAT _ (shape.vertex.length / 4) + 1; newVtx: REF ThreeDBasics.VertexSequence; newShade: REF ThreeDBasics.ShadingSequence; Action: PROC ~ { IF deSeam THEN { minX, maxX, scale: REAL; [minX, maxX] _ Bounds[context, name]; scale _ (shape.vertex.length / 4) / (maxX - minX); IF 1.0 / scale < tolerance THEN SIGNAL ShapeTwiddleError[$ToleranceTooLarge]; FOR i: NAT IN [0..shape.vertex.length) DO -- bucket sort vertices index: NAT _ Real.FixC[ (shape.vertex[i].x - minX) * scale ]; IF buckets[index] # NIL THEN { buckets[nextBucket] _ NEW[SortPair]; buckets[nextBucket].next _ buckets[index].next; -- put on next-to-head of list buckets[index].next _ nextBucket; -- reset first pointer index _ nextBucket; nextBucket _ nextBucket + 1; } ELSE { buckets[index] _ NEW[SortPair]; -- bucket hit for first time buckets[index].next _ 0; }; buckets[index].vtx _ i; -- store vertex pointer ENDLOOP; FOR i: NAT IN [1..table.length) DO -- Coalesce nearby vertices vtx: REF ThreeDBasics.Vertex _ shape.vertex[i]; xBucket: NAT _ MAX[1, MIN[shape.vertex.length-1, Real.FixC[ (vtx.x - minX)*scale]]]; table[i] _ i; -- set to identity value FOR j: NAT IN [xBucket-1 .. xBucket+1] DO -- search this and last and next buckets index: NAT _ j; WHILE buckets[index] # NIL DO k: NAT _ buckets[index].vtx; diff: REAL _ Vector3d.Length[ Vector3d.Sub[ -- check distance [vtx.x, vtx.y, vtx.z], [shape.vertex[k].x, shape.vertex[k].y, shape.vertex[k].z] ] ]; IF diff <= tolerance THEN IF k < table[i] THEN table[i] _ k; -- reset if smaller index _ buckets[index].next; IF index = 0 THEN EXIT; ENDLOOP; ENDLOOP; ENDLOOP; FOR i: NAT IN [0..shape.numSurfaces) DO -- retarget vertex pointers IF surface[i] # NIL THEN FOR j: NAT IN [0..surface[i].nVtces) DO surface[i].vtxPtr[j] _ table[surface[i].vtxPtr[j]]; ENDLOOP; ENDLOOP; IF shape.type = $ConvexPolygon THEN { FOR i: NAT IN [0..shape.numSurfaces) DO -- eliminate duplicated polygon vertices vtx: NAT _ 0; IF surface[i] # NIL THEN FOR j: NAT IN [0..surface[i].nVtces) DO k: NAT _ (j-1 + surface[i].nVtces) MOD surface[i].nVtces; IF surface[i].vtxPtr[j] # surface[i].vtxPtr[k] THEN { surface[i].vtxPtr[vtx] _ surface[i].vtxPtr[j]; vtx _ vtx + 1; }; ENDLOOP; surface[i].nVtces _ vtx; ENDLOOP; }; }; -- end deSeaming block FOR i: NAT IN [0..table.length) DO table[i] _ 0; ENDLOOP; FOR i: NAT IN [0..shape.numSurfaces) DO -- build vertex reference count IF surface[i] # NIL THEN FOR j: NAT IN [0..surface[i].nVtces) DO table[surface[i].vtxPtr[j]] _ table[surface[i].vtxPtr[j]] + 1; ENDLOOP; ENDLOOP; currPos _ 0; FOR i: NAT IN [0..table.length) DO -- collapse vertex array and keep audit trail IF table[i] # 0 THEN { shape.vertex[currPos] _ shape.vertex[i]; shape.shade[currPos] _ shape.shade[i]; table[i] _ currPos; currPos _ currPos + 1; }; ENDLOOP; newVtx _ NEW[ ThreeDBasics.VertexSequence[currPos] ]; newShade _ NEW[ ThreeDBasics.ShadingSequence[currPos] ]; FOR i: NAT IN [0..currPos) DO -- copy into new sequences of proper length newVtx[i] _ shape.vertex[i]; newShade[i] _ shape.shade[i]; ENDLOOP; shape.vertex _ newVtx; shape.shade _ newShade; FOR i: NAT IN [0..shape.numSurfaces) DO -- retarget vertex pointers FOR j: NAT IN [0..surface[i].nVtces) DO surface[i].vtxPtr[j] _ table[surface[i].vtxPtr[j]]; ENDLOOP; ENDLOOP; }; CedarProcess.DoWithPriority[background, Action]; }; CopyShape: PUBLIC PROC [context: REF Context, dstName, srcName: Rope.ROPE] RETURNS[REF ThreeDBasics.ShapeInstance] ~ { dstShape: REF ThreeDBasics.ShapeInstance _ ThreeDScenes.NewShape[dstName]; srcShape: REF ThreeDBasics.ShapeInstance _ ThreeDScenes.FindShape[ context.shapes, srcName ]; srcSurface: REF ThreeDSurfaces.PtrPatchSequence _ NARROW[srcShape.surface]; dstSurface: REF ThreeDSurfaces.PtrPatchSequence; currPos: NAT _ 0; shape: REF ThreeDBasics.ShapeInstance _ ThreeDScenes.NewShape[dstName]; dstShape.orientation _ srcShape.orientation; dstShape.location _ srcShape.location; dstShape.rotation _ srcShape.rotation; dstShape.axisBase _ srcShape.axisBase; dstShape.axisEnd _ srcShape.axisEnd; dstShape.centroid _ srcShape.centroid; dstShape.boundingRadius _ srcShape.boundingRadius; dstShape.vertex _ NEW[ThreeDBasics.VertexSequence[srcShape.vertex.length] ]; FOR i: NAT IN [0..srcShape.vertex.length) DO dstShape.vertex[i] _ srcShape.vertex[i]; ENDLOOP; dstShape.shade _ NEW[ ThreeDBasics.ShadingSequence[srcShape.shade.length] ]; FOR i: NAT IN [0..srcShape.shade.length) DO dstShape.shade[i] _ srcShape.shade[i]; ENDLOOP; dstShape.surface _ NEW[ ThreeDSurfaces.PtrPatchSequence[srcShape.numSurfaces] ]; dstSurface _ NARROW[dstShape.surface, REF ThreeDSurfaces.PtrPatchSequence]; FOR i: NAT IN [0..srcShape.numSurfaces) DO dstSurface[i] _ srcSurface[i]; ENDLOOP; dstShape.numSurfaces _ srcShape.numSurfaces; dstShape.shadingProps _ srcShape.shadingProps; dstShape.props _ srcShape.props; RETURN[dstShape]; }; Combine: PUBLIC PROC [context: REF Context, dstName, src1, src2: Rope.ROPE] RETURNS[REF ThreeDBasics.ShapeInstance] ~ { shape: REF ThreeDBasics.ShapeInstance _ ThreeDScenes.NewShape[dstName]; shape1: REF ThreeDBasics.ShapeInstance _ ThreeDScenes.FindShape[ context.shapes, src1 ]; shape2: REF ThreeDBasics.ShapeInstance _ ThreeDScenes.FindShape[ context.shapes, src2 ]; surface1: REF ThreeDSurfaces.PtrPatchSequence _ NARROW[shape1.surface]; surface2: REF ThreeDSurfaces.PtrPatchSequence _ NARROW[shape2.surface]; surface: REF ThreeDSurfaces.PtrPatchSequence; shape.vertex _ NEW[ -- copy vertices ThreeDBasics.VertexSequence[shape1.vertex.length + shape2.vertex.length] ]; FOR i: NAT IN [0..shape1.vertex.length) DO shape.vertex[i] _ shape1.vertex[i]; [[shape.vertex[i].x, shape.vertex[i].y, shape.vertex[i].z]] _ Matrix3d.Transform[ [shape.vertex[i].x, shape.vertex[i].y, shape.vertex[i].z], shape1.position ]; ENDLOOP; FOR i: NAT IN [0..shape2.vertex.length) DO shape.vertex[i+shape1.vertex.length] _ shape2.vertex[i]; [[shape.vertex[i].x, shape.vertex[i].y, shape.vertex[i].z]] _ Matrix3d.Transform[ [shape.vertex[i].x, shape.vertex[i].y, shape.vertex[i].z], shape2.position ]; ENDLOOP; shape.shade _ NEW[ -- copy shading values ThreeDBasics.ShadingSequence[shape1.shade.length + shape2.shade.length] ]; FOR i: NAT IN [0..shape1.shade.length) DO shape.shade[i] _ shape1.shade[i]; ENDLOOP; FOR i: NAT IN [0..shape2.shade.length) DO shape.shade[i+shape1.shade.length] _ shape2.shade[i]; ENDLOOP; shape.numSurfaces _ shape1.numSurfaces + shape2.numSurfaces; shape.surface _ NEW[ -- copy surfaces ThreeDSurfaces.PtrPatchSequence[shape1.numSurfaces + shape2.numSurfaces] ]; surface _ NARROW[shape.surface, REF ThreeDSurfaces.PtrPatchSequence]; FOR i: NAT IN [0..shape1.numSurfaces) DO surface[i] _ surface1[i]; ENDLOOP; FOR i: NAT IN [0..shape2.numSurfaces) DO base: NAT _ shape1.numSurfaces; surface[i+base] _ surface2[i]; FOR j: NAT IN [0..surface[i+base].nVtces) DO -- redirect vertex pointers surface[i+base].vtxPtr[j] _ surface[i+base].vtxPtr[j] + shape1.vertex.length ENDLOOP; ENDLOOP; shape.shadingProps _ shape1.shadingProps; shape.props _ shape1.props; RETURN[shape]; }; DeletePatches: PUBLIC PROC [context: REF Context, dstName, srcName: Rope.ROPE, patchList: LIST OF NatPair] RETURNS[REF ThreeDBasics.ShapeInstance] ~ { currPos: NAT _ 0; oldShape: REF ThreeDBasics.ShapeInstance _ ThreeDScenes.FindShape[ context.shapes, srcName ]; shape: REF ThreeDBasics.ShapeInstance _ CopyShape[context, dstName, srcName]; surface: REF ThreeDSurfaces.PtrPatchSequence; surface _ NARROW[shape.surface, REF ThreeDSurfaces.PtrPatchSequence]; FOR list: LIST OF NatPair _ patchList, list.rest UNTIL list = NIL DO FOR i: NAT IN [list.first.x..list.first.y] DO surface[i] _ NIL; ENDLOOP; ENDLOOP; FOR i: NAT IN [0..shape.numSurfaces) DO -- collapse array IF surface[i] # NIL THEN { surface[currPos] _ surface[i]; currPos _ currPos + 1; }; ENDLOOP; shape.numSurfaces _ currPos; RETURN[ shape ]; }; Bounds: PUBLIC PROC [context: REF Context, name: Rope.ROPE] RETURNS[xMin, xMax, yMin, yMax, zMin, zMax: REAL] ~ { shape: REF ThreeDBasics.ShapeInstance _ ThreeDScenes.FindShape[ context.shapes, name ]; xMin _ xMax _ shape.vertex[0].x; yMin _ yMax _ shape.vertex[0].y; zMin _ zMax _ shape.vertex[0].z; FOR i: NAT IN (0..shape.vertex.length) DO -- get min and max in x, y, and z IF shape.vertex[i].x < xMin THEN xMin _ shape.vertex[i].x ELSE IF shape.vertex[i].x > xMax THEN xMax _ shape.vertex[i].x; IF shape.vertex[i].y < yMin THEN yMin _ shape.vertex[i].y ELSE IF shape.vertex[i].y > yMax THEN yMax _ shape.vertex[i].y; IF shape.vertex[i].z < zMin THEN zMin _ shape.vertex[i].z ELSE IF shape.vertex[i].z > zMax THEN zMax _ shape.vertex[i].z; ENDLOOP; }; END. ฌShapeTwiddleImpl.mesa Last Edited by: Crow, October 2, 1986 5:24:58 pm PDT Types Global Variables Shape Manipulations WriteOutShape: PUBLIC PROC [context: REF Context, name, ext: Rope.ROPE _ NIL, numbered: BOOLEAN _ FALSE] ~ { Caution!!! Writes old format!!! shape: REF ThreeDBasics.ShapeInstance _ ThreeDScenes.FindShape[ context.shapes, name ]; surface: REF ThreeDSurfaces.PtrPatchSequence _ NARROW[shape.surface]; pInfo: REF ThreeDBasics.ShadingSequence _ NARROW[ ThreeDScenes.GetShading[ shape, $PatchColors ] ]; vtxNormals: BOOLEAN _ ThreeDScenes.GetShading[ shape, $VertexNormalsInFile ] # NIL; vtxColors: BOOLEAN _ ThreeDScenes.GetShading[ shape, $VertexColorsInFile ] # NIL; vtxTexture: BOOLEAN _ ThreeDScenes.GetShading[ shape, $VertexTextureInFile ] # NIL; vtxTrans: BOOLEAN _ ThreeDScenes.GetShading[ shape, $VertexTransInFile ] # NIL; ptchNormals: BOOLEAN _ ThreeDScenes.GetShading[ shape, $PatchNormalsInFile ] # NIL; ptchColors: BOOLEAN _ ThreeDScenes.GetShading[ shape, $PatchColorsInFile ] # NIL; ptchTrans: BOOLEAN _ ThreeDScenes.GetShading[ shape, $PatchTransInFile ] # NIL; out: IO.STREAM; IF name = NIL THEN SIGNAL ShapeTwiddleError[$UnNamedObject]; IF ext = NIL THEN ext _ "shape"; out _ FS.StreamOpen[ fileName: Rope.Cat[name, ".", ext], accessOptions: create, wDir: NARROW[ Atom.GetPropFromList[context.props, $WDir] ] ]; out.PutF[" %g - Created by: %g at %g\n\n", IO.rope[name], IO.rope[UserCredentials.Get[].name], IO.time[] ]; out.PutRope["SurfaceType ~ "]; out.PutRope[Atom.GetPName[shape.type]]; IF shape.insideVisible THEN out.PutRope[", InsideVisible"]; out.PutRope["\n\n"]; out.PutRope["Vertices ~ "]; IF numbered THEN out.PutRope["index: integer, "]; out.PutRope["xyz: triple"]; IF vtxNormals THEN out.PutRope[", normal: triple"]; IF vtxColors THEN out.PutRope[", color: triple"]; IF vtxTrans THEN out.PutRope[", trans: real"]; IF vtxTexture THEN out.PutRope[", texture: triple"]; out.PutF[" -- %g Vertices %g Patches\n\n", IO.int[shape.vertex.length], IO.int[shape.numSurfaces] ]; IF shape.positionInValid THEN ThreeDScenes.SetPosition[shape]; -- set position matrix FOR i: NAT IN [0..shape.vertex.length) DO OPEN shape.vertex[i]; s: REF ThreeDBasics.ShadingValue _ shape.shade[i]; tx, ty, tz: REAL; [ [tx, ty, tz] ] _ Matrix3d.Transform[ [x, y, z], shape.position]; IF numbered THEN out.PutF["%g ", IO.int[i] ]; out.PutF["\t%g %g %g", IO.real[tx], IO.real[ty], IO.real[tz] ]; IF vtxNormals THEN out.PutF["\t%g %g %g", IO.real[s.xn], IO.real[s.yn], IO.real[s.zn] ]; IF vtxColors THEN out.PutF["\t%g %g %g", IO.real[s.r], IO.real[s.g], IO.real[s.b] ]; IF vtxTrans THEN out.PutF["\t%g", IO.real[s.t] ]; IF vtxTexture THEN out.PutF["\t%g %g %g", IO.real[s.txtrX], IO.real[s.txtrY], IO.real[s.txtrZ] ]; out.PutRope["\n"]; ENDLOOP; out.PutRope["\n"]; IF shape.type = $ConvexPolygon THEN out.PutRope["Polygons ~ "] ELSE out.PutRope["Patches ~ "]; IF numbered THEN out.PutRope["index: integer, "]; IF ptchNormals THEN out.PutRope["normal: triple, "]; IF ptchColors THEN out.PutRope["color: triple, "]; IF ptchTrans THEN out.PutRope["trans: real, "]; out.PutRope["vertices: nats\n\n"]; FOR i: NAT IN [0..shape.numSurfaces) DO IF numbered THEN out.PutF["%g ", IO.int[i] ]; IF ptchNormals THEN out.PutF["\t%g %g %g", IO.real[pInfo[i].xn], IO.real[pInfo[i].yn], IO.real[pInfo[i].zn] ]; IF ptchColors THEN out.PutF["\t%g %g %g", IO.real[pInfo[i].r], IO.real[pInfo[i].g], IO.real[pInfo[i].b] ]; IF ptchTrans THEN out.PutF["\t%g", IO.real[pInfo[i].t] ]; out.PutRope["\t"]; FOR j: NAT IN [0..surface[i].nVtces) DO out.PutF[" %g", IO.int[ surface[i][j] ] ]; ENDLOOP; out.PutF["\n"]; ENDLOOP; IO.Close[out]; }; delete excess vertices, join identical ones, etc. ส.˜headšœ™Jšœ4™4defaultšฯk ˜ Jšœ œ ˜Jšœ œœ˜Jšœœ˜(Jšœœœ˜Jšœ œ˜"Jšœ œ˜ Jšœœก˜ดJšœœ:˜MJšœœ˜+Jšœœ ˜ ——head2šœœ˜Jšœ6˜=Jšœ ˜J˜Jšœ˜J˜—head3šะbi™Iašœ œ˜%Oš œœœ œœ˜7Icodešœ œฯc˜>Pšœœ˜/Iunitšœœ˜#Pšœœ˜3Jšœœœ˜Pš œ œœœ œœœ˜9P˜—Nšฯb™š ™šฯn œœœ œœœœœ™wJš  ™ JšœœM™WLšœ œ#œ™Ešœœ œ™1Jšœ.™.Jšœ™—Lšœ œ<œ™SLšœ œ;œ™QLšœ œ<œ™SLšœ œ:œ™OLšœ œ;œ™SLšœ œ:œ™QLšœ œ9œ™OLšœ™Lšœœœœ#™=Lšœœœ™ šœ™Lšœ#™#Lšœ™Lšœœ/™;Lšœ™—šœ,™,Lšœ ™Lšœ"™$Lšœ™ L™—Lšœ™Lšœ'™'Lšœœ ™;Lšœ™Lšœ™Lšœ œ!™1Lšœ™Lšœ œ!™3Lšœ œ ™1Lšœ œ™.Lšœ œ"™4Lšœ.œœ™qJšœœ!Ÿ™Wšœœœœ™*Lšœ™Lšœœ,™2Lšœ œ™LšœB™BLšœ œœ ™.Lšœœ œ œ ™ALš œ œœ œ œ™ZLš œ œœ œ œ ™VLšœ œœ ™1šœ ™Lšœœœœ™U—Lšœ™Lšœ™ —Lšœ™Lšœœ&œ™kLšœ œ!™1Lšœ œ!™4Lšœ œ ™2Lšœ œ™/Lšœ#™#šœœœœ™(Lšœ œœ ™/šœ œ™Lšœœœœ™\—šœ œ™Lšœœœœ™Y—Lšœ œœ™9Lšœ™šœœœ™'Lšœœ™+Lšœ™Lšœ™—Lšœ™—Lšœ ™L™—š ก œ œ œœ œœ ˜wJšœœM˜WJšœœ!Ÿ˜Wšœœœœ˜*Lšœ˜Lšœ œ˜LšœB˜BJšœ˜Jšœ˜Jšœ˜Lšœ˜—Pšœ6œ˜Ršœ˜Pšœ˜Pšœ˜Pšœ7˜:P˜—P˜—š ก œ œ œœ œœ ˜{JšœœM˜WJšœœ!Ÿ˜Wšœœ˜š œœœœœœ˜=Jšœ'˜'Jšœ'˜'Lšœ˜—š œœœœœœ˜CJšœ+˜+Jšœ+˜+Jšœ+˜+Lšœ˜—Lšœœ>˜O—šœ˜Pšœ˜Pšœ˜Pšœ7˜:P˜—L˜—˜Jšœ œœ œ˜)Jš œœœœ œœœ ˜B—šกœ œ œœ œœœ ˜{PšŸ1™1Jšœ œ˜JšœœM˜WLšœ œ#œ˜ELšœœœ%˜ALšœ œœ,˜KLšœ œ!˜0Lšœœ˜)Lšœ œ˜+šกœœ˜šœœ˜Lšœœ˜Jšœ%˜%Jšœ3˜3Jšœœœ'˜Mš œœœœŸ˜EJšœœ5˜?šœœ˜šœ˜Jšœœ ˜$Jšœ/Ÿ"˜QJšœ&Ÿ˜J˜J˜9J˜—Jš œœœœŸ˜PJšœ œ œœ˜7Jšœ˜—Jšœ˜—Jšœ˜—š œœœœ Ÿ˜Kš œœœœœœ˜@Jšœ3˜3Jšœ˜—Jšœ˜—šœœ˜%š œœœœŸ)˜QJšœœ˜ š œœœœœœ˜@Jšœœœ˜9šœ-œ˜5Jšœ.˜.J˜J˜—Jšœ˜—J˜Jšœ˜—J˜—LšœŸ˜—Lš œœœœœ˜;š œœœœŸ˜Iš œœœœœœ˜@Lšœ>˜>Lšœ˜—Lšœ˜—Lšœ ˜ š œœœœŸ-˜Sšœœœ˜Lšœ(˜(Lšœ&˜&Lšœ˜Lšœ˜Lšœ˜—Lšœ˜—Lšœ œ)˜5Lšœ œ*˜8š œœœœŸ+˜LLšœ˜Lšœ˜Lšœ˜—Lšœ œ˜Lšœ˜š œœœœŸ˜Ešœœœ˜'Lšœ3˜3Lšœ˜—Lšœ˜—L˜—Pšœ0˜0P˜—š ก œ œ œ!œœœ ˜ƒJšœ œ=˜JPšœ œ\˜iLšœ œ#œ˜KJšœ œ!˜0Jšœ œ˜Jšœœ=˜GPšœ,˜,Pšœ&˜&Pšœ&˜&Pšœ&˜&Pšœ$˜$Pšœ&˜&Pšœ2˜2Pšœœ7˜Lšœœœœ˜-Pšœ*˜*Pšœ˜—Pšœœ8˜Lš œœœœŸ˜-Pšœ(˜(Pšœ˜—Pšœœ:˜PPšœ œœ"˜Kšœœœœ˜,Pšœ ˜ Pšœ˜—Pšœ,˜,Pšœ.˜.Pšœ ˜ Pšœ ˜Pšœ˜—š กœ œ œ$œ œœ ˜€Jšœœ=˜GPšœœM˜XPšœœM˜XLšœ œ#œ˜GLšœ œ#œ˜GLšœ œ!˜-P˜PšœœŸœV˜€šœœœ˜*Pšœ%˜%šœR˜RPšœ;˜;Pšœ˜Pšœ˜—Pšœ˜—šœœœœ˜,Pšœ:˜:šœR˜RPšœ;˜;Pšœ˜Pšœ˜—Pšœ˜—PšœœŸœU˜‚š œœœœŸ˜+Pšœ#˜#Pšœ˜—šœœœœ˜+Pšœ7˜7Pšœ˜—Pšœ<˜