DIRECTORY AtomButtonsTypes, CoordSys, Feedback, FunctionCache, Imager, ImagerColor, ImagerColorPrivate, Matrix3d, PriorityQueue, Real, Rope, SV2d, SV3d, SVArtwork, SVAssembly, SVBasicTypes, SVBoundBox, SVDraw3d, SVMatrixOps, SVModelTypes, SVRayTypes, SVScene, SVSceneTypes, SVToolObject, SVTransforms, SVUtility, ViewerClasses; SVAssemblyImpl: CEDAR PROGRAM IMPORTS CoordSys, Feedback, FunctionCache, Imager, ImagerColor, ImagerColorPrivate, Matrix3d, PriorityQueue, Rope, SVArtwork, SVBoundBox, SVDraw3d, SVMatrixOps, SVScene, SVToolObject, SVTransforms, SVUtility EXPORTS SVAssembly = BEGIN Artwork: TYPE = SVModelTypes.Artwork; Slice: TYPE = SVSceneTypes.Slice; SliceList: TYPE = SVSceneTypes.SliceList; SliceListObj: TYPE = SVSceneTypes.SliceListObj; SliceObj: TYPE = SVSceneTypes.SliceObj; BoundBox: TYPE = SVBasicTypes.BoundBox; BoundHedron: TYPE = SVBasicTypes.BoundHedron; Camera: TYPE = SVModelTypes.Camera; Color: TYPE = Imager.Color; CoordSystem: TYPE = SVModelTypes.CoordSystem; FeedbackData: TYPE = AtomButtonsTypes.FeedbackData; LightSourceList: TYPE = SVSceneTypes.LightSourceList; Line3d: TYPE = SV3d.Line3d; MasterObject: TYPE = SVSceneTypes.MasterObject; Matrix4by4: TYPE = SV3d.Matrix4by4; PlanarSurface: TYPE = SVSceneTypes.PlanarSurface; PlanarSurfaceList: TYPE = SVSceneTypes.PlanarSurfaceList; Point2d: TYPE = SV2d.Point2d; Point3d: TYPE = SV3d.Point3d; PointAndDone: TYPE = SVSceneTypes.PointAndDone; PointGenerator: TYPE = SVSceneTypes.PointGenerator; PointSetOp: TYPE = SVRayTypes.PointSetOp; -- {union, intersection, difference} Scene: TYPE = SVSceneTypes.Scene; SelectionClass: TYPE = SVSceneTypes.SelectionClass; SelectMode: TYPE = SVSceneTypes.SelectMode; Shape: TYPE = SVSceneTypes.Shape; ShapeObj: TYPE = SVSceneTypes.ShapeObj; ShowAsType: TYPE = SVSceneTypes.ShowAsType; SliceDescriptor: TYPE = SVSceneTypes.SliceDescriptor; SliceDescriptorObj: TYPE = SVSceneTypes.SliceDescriptorObj; SliceParts: TYPE = SVSceneTypes.SliceParts; ToolData: TYPE = SVSceneTypes.ToolData; Vector3d: TYPE = SV3d.Vector3d; Viewer: TYPE = ViewerClasses.Viewer; Problem: SIGNAL [msg: Rope.ROPE] = Feedback.Problem; bBoxCacheSize: NAT = 3; CreatePrimitive: PUBLIC PROC [name: Rope.ROPE, object: Rope.ROPE, scene: Scene, artwork: Artwork _ NIL, isTool: BOOL _ FALSE, toolData: ToolData _ NIL] RETURNS [prim: Slice, masterObjectFound: BOOL, success: BOOL] = { masterObject: MasterObject; toolMasterObject: MasterObject; shape: Shape; toolName: Rope.ROPE; BEGIN success _ TRUE; IF SVScene.AssemblyNameIsPresent[name, scene] THEN GOTO NameAlreadyPresent; IF toolData = NIL THEN toolMasterObject _ NIL ELSE { toolName _ CoordSys.NameWithSuffix[name, "$$tool", scene.coordSysRoot]; toolMasterObject _ SVToolObject.ToolMakeMasterObject[toolName, toolData]; }; [masterObject, masterObjectFound] _ SVScene.FindObjectFromName[object, scene]; IF NOT masterObjectFound THEN RETURN; IF artwork = NIL THEN artwork _ SVArtwork.CreateColorArtwork[ImagerColor.ColorFromRGB[[.6,.6,.8]], plastic]; -- light blue shape _ NEW[ShapeObj]; shape.mo _ masterObject; prim _ NEW[SliceObj _ [ name: name, coordSys: NIL, shape: shape, bBoxCache: FunctionCache.Create[maxEntries: bBoxCacheSize], artwork: artwork, showAs: normal, isTool: isTool, toolMasterObject: toolMasterObject ]]; EXITS NameAlreadyPresent => { Feedback.AppendRaw[$Solidviews, Rope.Cat["Slice ", name, " already present."], oneLiner]; Feedback.BlinkRaw[$Solidviews]; RETURN[NIL, TRUE, FALSE]; }; END; }; AddPrimitive: PUBLIC PROC [prim: Slice, size: Vector3d, parent: Slice, mat: Matrix4by4, scene: Scene] RETURNS [success: BOOL] = { scalarName: Rope.ROPE; shape: Shape; IF ISTYPE[parent.shape, SliceList] THEN { -- add to old SliceList alist: SliceList _ NARROW[parent.shape]; cs: CoordSystem; scalarCS: CoordSystem; cs _ CoordSys.CreateCoordSysInTree[prim.name, mat, parent.coordSys, scene.coordSysRoot !CoordSys.NameAlreadyExists => ERROR]; prim.coordSys _ cs; scalarName _ CoordSys.NameWithSuffix[prim.name, "$$Scalars", scene.coordSysRoot]; scalarCS _ CoordSys.CreateScalarsOnlyCoordSysInTree[scalarName, size, cs, scene.coordSysRoot !CoordSys.NameAlreadyExists => ERROR]; shape _ NARROW[prim.shape]; shape.coordSys _ scalarCS; parent.shape _ SVUtility.AppendToAssemblyList[prim, alist]; success _ TRUE; } ELSE { Feedback.AppendRaw[$Solidviews, "Attempt to add subassembly to primitive.", oneLiner]; Feedback.BlinkRaw[$Solidviews]; RETURN[FALSE]; }; }; CreatePrimitiveAtExistingCoordSys: PUBLIC PROC [name: Rope.ROPE, object: Rope.ROPE, size: Vector3d, scene: Scene, coordSys: CoordSystem, artwork: Artwork _ NIL, isTool: BOOL _ FALSE, toolData: ToolData _ NIL] RETURNS [assembly: Slice, masterObjectFound: BOOL] = { masterObject: MasterObject; toolMasterObject: MasterObject; shape: Shape; scalarCS: CoordSystem; toolName, scalarName: Rope.ROPE; IF toolData = NIL THEN toolMasterObject _ NIL ELSE { toolName _ CoordSys.NameWithSuffix[name, "$$tool", scene.coordSysRoot]; toolMasterObject _ SVToolObject.ToolMakeMasterObject[toolName, toolData]; }; [masterObject, masterObjectFound] _ SVScene.FindObjectFromName[object, scene]; IF NOT masterObjectFound THEN { Feedback.AppendRaw[$Solidviews, Rope.Cat["Couldn't add assembly ", name, ". Master object ", object, " not found."], oneLiner]; Feedback.BlinkRaw[$Solidviews]; }; IF artwork = NIL THEN artwork _ SVArtwork.CreateColorArtwork[ImagerColor.ColorFromRGB[[.6,.6,.8]], plastic]; -- light blue shape _ NEW[ShapeObj]; shape.mo _ masterObject; assembly _ NEW[SliceObj _ [ name: name, coordSys: NIL, shape: shape, bBoxCache: FunctionCache.Create[maxEntries: bBoxCacheSize], artwork: artwork, showAs: normal, isTool: isTool, toolMasterObject: toolMasterObject ]]; assembly.coordSys _ coordSys; scalarName _ CoordSys.NameWithSuffix[assembly.name, "$$Scalars", scene.coordSysRoot]; scalarCS _ CoordSys.CreateScalarsOnlyCoordSysInTree[scalarName, size, coordSys, scene.coordSysRoot]; shape.coordSys _ scalarCS; }; CreateCluster: PUBLIC PROC [name: Rope.ROPE, pointSetOp: PointSetOp _ union, scene: Scene, isTool: BOOL _ FALSE, toolData: ToolData _ NIL] RETURNS [assembly: Slice, success: BOOL] = { artwork: Artwork _ SVArtwork.CreateColorArtwork[Imager.white, plastic]; -- white toolMasterObject: MasterObject; toolName: Rope.ROPE; BEGIN success _ TRUE; IF SVScene.AssemblyNameIsPresent[name, scene] THEN GOTO NameInUse; IF toolData = NIL THEN toolMasterObject _ NIL ELSE { toolName _ CoordSys.NameWithSuffix[name, "$$tool", scene.coordSysRoot]; toolMasterObject _ SVToolObject.ToolMakeMasterObject[toolName, toolData]; }; assembly _ NEW[SliceObj _ [ name: name, coordSys: NIL, shape: NEW[SliceListObj _ [NIL, pointSetOp]], bBoxCache: FunctionCache.Create[maxEntries: bBoxCacheSize], artwork: artwork, showAs: normal, isTool: isTool, toolMasterObject: toolMasterObject ]]; EXITS NameInUse => { Feedback.AppendRaw[$Solidviews, Rope.Cat["Composite name ", name, " is already registered. Try another."], oneLiner]; Feedback.BlinkRaw[$Solidviews]; RETURN[NIL, FALSE]; }; END; }; AddCluster: PUBLIC PROC [cluster: Slice, parent: Slice, mat: Matrix4by4, scene: Scene] RETURNS [success: BOOL] = { IF IsComposite[parent] THEN{ -- add to old SliceList alist: SliceList _ NARROW[parent.shape]; cluster.coordSys _ CoordSys.CreateCoordSysInTree[cluster.name, mat, parent.coordSys, scene.coordSysRoot]; parent.shape _ SVUtility.AppendToAssemblyList[cluster, alist]; } ELSE { Feedback.AppendRaw[$Solidviews, "Attempt to add subassembly to primitive.", oneLiner]; Feedback.BlinkRaw[$Solidviews]; RETURN[FALSE]; }; }; CreateClusterAssemblyAtExistingCoordSys: PUBLIC PROC [name: Rope.ROPE, pointSetOp: PointSetOp, scene: Scene, coordSys: CoordSystem, isTool: BOOL _ FALSE, toolData: ToolData _ NIL] RETURNS [assembly: Slice] = { artwork: Artwork _ SVArtwork.CreateColorArtwork[Imager.white, plastic]; -- white toolMasterObject: MasterObject; toolName: Rope.ROPE; IF toolData = NIL THEN toolMasterObject _ NIL ELSE { toolName _ CoordSys.NameWithSuffix[name, "$$tool", scene.coordSysRoot]; toolMasterObject _ SVToolObject.ToolMakeMasterObject[toolName, toolData]; }; assembly _ NEW[SliceObj _ [ name: name, coordSys: NIL, shape: NEW[SliceListObj _ [NIL, pointSetOp]], bBoxCache: FunctionCache.Create[maxEntries: bBoxCacheSize], artwork: artwork, showAs: normal, isTool: isTool, toolMasterObject: toolMasterObject ]]; assembly.coordSys _ coordSys; }; AttemptToAddSubassemblyToPrimitive: PUBLIC SIGNAL = CODE; ConnectAssemblyToParent: PUBLIC PROC [assembly: Slice, parent: Slice] = { IF IsComposite[parent] THEN { -- add to old SliceList alist: SliceList _ NARROW[parent.shape]; parent.shape _ SVUtility.AppendToAssemblyList[assembly, alist]; } ELSE SIGNAL AttemptToAddSubassemblyToPrimitive; }; IsComposite: PUBLIC PROC [assem: Slice] RETURNS [BOOL] = { RETURN[ISTYPE [assem.shape, SliceList] OR assem.shape = NIL]; }; GetHedron: PUBLIC PROC [mo: MasterObject] RETURNS [hedron: BoundHedron] = { hedron _ mo.class.getHedron[mo]; }; BoundBoxEntry: TYPE = REF BoundBoxEntryObj; BoundBoxEntryObj: TYPE = RECORD [ bBox: BoundBox, ok: BOOL _ FALSE ]; GetBoundBox: PUBLIC PROC [assem: Slice, parts: SliceParts, camera: Camera] RETURNS [bBox: BoundBox] = { CompareEntries2: PROC [argument: FunctionCache.Domain] RETURNS [good: BOOL] = { thisName: Rope.ROPE _ NARROW[argument]; good _ Rope.Equal[thisName, camera.viewName, FALSE]; }; bBoxCache: FunctionCache.Cache _ assem.bBoxCache; oldEntryAny: REF ANY; oldEntry: BoundBoxEntry; ok: BOOL; BEGIN [oldEntryAny, ok] _ FunctionCache.Lookup[bBoxCache, CompareEntries2]; IF NOT ok THEN GOTO UpdateTheCache -- not in cache ELSE { oldEntry _ NARROW[oldEntryAny]; IF NOT oldEntry.ok THEN GOTO UpdateTheCache -- cache out of date ELSE bBox _ oldEntry.bBox; }; EXITS UpdateTheCache => { UpdateBoundBoxForCamera[assem, camera]; bBox _ GetBoundBox[assem, parts, camera]; -- recursive call }; END; }; UpdateBoundBoxForCamera: PUBLIC PROC [assem: Slice, camera: Camera] = { CompareEntries: PROC [argument: FunctionCache.Domain] RETURNS [good: BOOL] = { thisName: Rope.ROPE _ NARROW[argument]; good _ Rope.Equal[thisName, camera.viewName, FALSE]; }; bBoxCache: FunctionCache.Cache _ assem.bBoxCache; oldEntryAny: REF ANY; oldEntry: BoundBoxEntry; ok: BOOL _ FALSE; [oldEntryAny, ok] _ FunctionCache.Lookup[bBoxCache, CompareEntries]; IF ok THEN { oldEntry _ NARROW[oldEntryAny]; FillBox[oldEntry.bBox, assem, camera]; oldEntry.ok _ TRUE; } ELSE { newEntry: BoundBoxEntry _ NEW[BoundBoxEntryObj]; newEntry.bBox _ SVBoundBox.NullBoundBox[]; FillBox[newEntry.bBox, assem, camera]; newEntry.ok _ TRUE; FunctionCache.Insert[bBoxCache, camera.viewName, newEntry, 0]; }; }; FillBox: PROC [bBox: BoundBox, slice: Slice, camera: Camera] = { shape: Shape _ NARROW[slice.shape]; hedron: BoundHedron; mo: MasterObject _ shape.mo; hedron _ GetHedron[mo]; SVBoundBox.FillBoundBoxFromBoundHedron[hedron, camera, shape.coordSys, bBox]; EnlargeByOffset[bBox, 2.0]; -- allow for stroke width }; EnlargeByOffset: PROC [bBox: BoundBox, offset: REAL] = { IF bBox.null OR bBox.infinite THEN RETURN; bBox.loX _ bBox.loX - offset; bBox.hiX _ bBox.hiX + offset; bBox.loY _ bBox.loY - offset; bBox.hiY _ bBox.hiY + offset; }; UpdateBoundBoxes: PROC [slice: Slice, cameraList: LIST OF Camera _ NIL] = { oldEntry: BoundBoxEntry; bBoxCache: FunctionCache.Cache _ slice.bBoxCache; allCache: LIST OF FunctionCache.CacheEntry _ FunctionCache.GetList[bBoxCache]; FOR list: LIST OF FunctionCache.CacheEntry _ allCache, list.rest UNTIL list = NIL DO oldEntry _ NARROW[list.first.value]; IF oldEntry # NIL THEN oldEntry.ok _ FALSE; ENDLOOP; FOR list: LIST OF Camera _ cameraList, list.rest UNTIL list = NIL DO UpdateBoundBoxForCamera[slice, list.first]; ENDLOOP; }; DrawTransform: PUBLIC PROC [sliceD: SliceDescriptor, dc: Imager.Context, scene: Scene, camera: Camera, transform: Matrix4by4] = { SELECT camera.style FROM wire => DrawWireAssemblyTransform[sliceD, dc, camera, transform]; shaded => ERROR; -- use AddPolygonsToBufferTransform normals => { assem: Slice _ sliceD.slice; oldAssemblyWORLD: Matrix4by4 _ CoordSys.WRTWorld[assem.coordSys]; newAssemblyWORLD: Matrix4by4 _ Matrix3d.Mult[oldAssemblyWORLD, transform]; AbsTransf[assem, scene, newAssemblyWORLD]; DrawNormalsAssembly[dc, assem, scene, camera]; AbsTransf[assem, scene, oldAssemblyWORLD]; }; ENDCASE => SIGNAL NotYetImplemented; }; DeeperPlanarPolygon: PROC [x,y: PriorityQueue.Item, data: REF _ NIL] RETURNS [BOOL] = { xS: PlanarSurface _ NARROW[x]; yS: PlanarSurface _ NARROW[y]; RETURN[xS.depth < yS.depth]; }; DrawParts: PUBLIC PROC [slice: Slice, parts: SliceParts _ NIL, dc: Imager.Context, scene: Scene, camera: Camera, quick: BOOL] = { IF parts = NIL THEN Draw[slice, dc, scene, camera]; }; Draw: PUBLIC PROC [assem: Slice, dc: Imager.Context, scene: Scene, camera: Camera] = { sliceD: SliceDescriptor _ NewParts[assem, NIL, [0,0,0], slice]; DrawTransform[sliceD, dc, scene, camera, Matrix3d.Identity[]]; }; DrawWireAssembly: PROC [assembly: Slice, dc: Imager.Context, camera: Camera] = { SetColor[dc, camera, Imager.black]; SELECT assembly.showAs FROM tool => { toolMasterObject: MasterObject _ assembly.toolMasterObject; IF toolMasterObject = NIL THEN { Feedback.AppendTypescriptRaw[$Solidviews, Rope.Cat["Slice ", assembly.name, " is a tool but has no tool data. Contact implementor."], oneLiner]; RETURN; }; toolMasterObject.class.lineDraw[assembly, dc, camera]; }; normal => { WITH assembly.shape SELECT FROM assems: SliceList => { FOR subassemblies: LIST OF Slice _ assems.list, subassemblies.rest UNTIL subassemblies = NIL DO DrawWireAssembly[subassemblies.first, dc, camera]; ENDLOOP; }; shape: Shape => { shape.mo.class.lineDraw[assembly, dc, camera]; }; ENDCASE => ERROR; }; invisible => {}; both => ERROR Feedback.Problem[msg: "Can't have both"]; ENDCASE => ERROR; }; DrawWireAssemblyTransform: PROC [sliceD: SliceDescriptor, dc: Imager.Context, camera: Camera, transform: Matrix4by4] = { assembly: Slice _ sliceD.slice; SetColor[dc, camera, Imager.black]; SELECT assembly.showAs FROM normal => { WITH assembly.shape SELECT FROM assems: SliceList => { SIGNAL Problem[msg: "LineDraw not implemented for composite assemblies"]; }; shape: Shape => { shape.mo.class.lineDrawTransform[sliceD, dc, camera, transform]; }; ENDCASE => ERROR; }; invisible, tool => {}; both => ERROR Feedback.Problem[msg: "Can't have both"]; ENDCASE => ERROR; }; AddPolygonsToBuffer: PUBLIC PROC [surfaceQueue: PriorityQueue.Ref, assembly: Slice, camera: Camera] = { PutAssemblyOnQueue[assembly, surfaceQueue, camera.coordSys]; }; AddPolygonsToBufferTransform: PUBLIC PROC [surfaceQueue: PriorityQueue.Ref, sliceD: SliceDescriptor, scene: Scene, camera: Camera, transform: Matrix4by4] = { PutAssemblyOnQueueTransform[sliceD, surfaceQueue, camera.coordSys, transform]; }; DrawBuffer: PUBLIC PROC [dc: Imager.Context, surfaceQueue: PriorityQueue.Ref, scene: Scene, camera: Camera] = { DoDrawBuffer: PROC = { thisPlanarSurf: PlanarSurface; mo: MasterObject; FOR i: INT IN[1..PriorityQueue.Size[surfaceQueue]] DO thisPlanarSurf _ NARROW[PriorityQueue.Remove[surfaceQueue]]; mo _ thisPlanarSurf.mo; mo.class.drawSurf[dc, thisPlanarSurf, scene.lightSources, camera]; ENDLOOP; }; Imager.DoSaveAll[dc, DoDrawBuffer]; }; DrawNormalsAssembly: PROC [dc: Imager.Context, assembly: Slice, scene: Scene, camera: Camera] = { lightSources: LightSourceList _ scene.lightSources; SetColor[dc, camera, Imager.black]; WITH assembly.shape SELECT FROM assems: SliceList => { FOR subassemblies: LIST OF Slice _ assems.list, subassemblies.rest UNTIL subassemblies = NIL DO DrawNormalsAssembly[dc, subassemblies.first, scene, camera]; ENDLOOP; }; shape: Shape => { shape.mo.class.normalsDraw[dc, shape.mo.shadeBody, camera, shape.coordSys]; }; ENDCASE => ERROR; }; DrawSelectionFeedback: PUBLIC PROC [slice: Slice, selectedParts: SliceParts, hotParts: SliceParts, dc: Imager.Context, camera: Camera, dragInProgress, caretIsMoving, hideHot, quick: BOOL] = { pointGen: SVSceneTypes.PointGenerator; selectedD: SliceDescriptor _ DescriptorFromParts[slice, selectedParts]; pointGen _ PointsInDescriptor[selectedD]; FOR pointAndDone: SVSceneTypes.PointAndDone _ NextPoint[pointGen], NextPoint[pointGen] UNTIL pointAndDone.done DO SVDraw3d.DrawSelectedJoint[dc, pointAndDone.point, camera]; ENDLOOP; }; CountSurfacesInAssembly: PROC [assembly: Slice] RETURNS [surfCount: NAT] = { WITH assembly.shape SELECT FROM assems: SliceList => surfCount _ CountSurfacesInAssemblyList[assems]; shape: Shape => surfCount _ shape.mo.class.countSurf[shape.mo]; ENDCASE => ERROR; }; CountSurfacesInAssemblyList: PROC [asl: SliceList] RETURNS [surfCount: NAT] = { surfCount _ 0; FOR list: LIST OF Slice _ asl.list, list.rest UNTIL list = NIL DO surfCount _ surfCount + CountSurfacesInAssembly[list.first]; ENDLOOP; }; PutAssemblyOnQueue: PROC [assembly: Slice, q: PriorityQueue.Ref, cameraCS: CoordSystem] = { thisSurf: PlanarSurface; cameraNormal: Vector3d; surfList: PlanarSurfaceList; SELECT assembly.showAs FROM tool => { toolMasterObject: MasterObject _ assembly.toolMasterObject; surfList _ toolMasterObject.class.getSurf[assembly, cameraCS]; FOR surfList _ surfList, surfList.rest UNTIL surfList = NIL DO thisSurf _ surfList.first; cameraNormal _ Matrix3d.UpdateVectorWithInverse[CoordSys.FindCameraInTermsOf[assembly.coordSys, cameraCS], thisSurf.normal]; thisSurf.normal _ cameraNormal; PriorityQueue.Insert[q, thisSurf]; ENDLOOP; }; normal => { WITH assembly.shape SELECT FROM assems: SliceList => { FOR list: LIST OF Slice _ assems.list, list.rest UNTIL list = NIL DO PutAssemblyOnQueue[list.first, q, cameraCS]; ENDLOOP; }; shape: Shape => { surfList _ shape.mo.class.getSurf[assembly, cameraCS]; FOR surfList _ surfList, surfList.rest UNTIL surfList = NIL DO thisSurf _ surfList.first; cameraNormal _ Matrix3d.UpdateVectorWithInverse[CoordSys.FindCameraInTermsOf[shape.coordSys, cameraCS], thisSurf.normal]; thisSurf.normal _ cameraNormal; IF thisSurf.normal[3] >0 THEN PriorityQueue.Insert[q,thisSurf]; ENDLOOP; }; ENDCASE => ERROR; }; invisible => {}; both => ERROR Feedback.Problem[msg: "Can't have both."]; ENDCASE => ERROR; }; -- end of PutAssemblyOnQueue PutAssemblyOnQueueTransform: PROC [sliceD: SliceDescriptor, q: PriorityQueue.Ref, cameraCS: CoordSystem, transform: Matrix4by4] = { thisSurf: PlanarSurface; cameraNormal: Vector3d; surfList: PlanarSurfaceList; assembly: Slice _ sliceD.slice; SELECT assembly.showAs FROM tool => {}; normal => { WITH assembly.shape SELECT FROM assems: SliceList => { FOR list: LIST OF Slice _ assems.list, list.rest UNTIL list = NIL DO PutAssemblyOnQueue[list.first, q, cameraCS]; ENDLOOP; }; shape: Shape => { surfList _ shape.mo.class.getSurfTransform[sliceD, cameraCS, transform]; FOR surfList _ surfList, surfList.rest UNTIL surfList = NIL DO thisSurf _ surfList.first; cameraNormal _ Matrix3d.UpdateVectorWithInverse[CoordSys.FindCameraInTermsOf[shape.coordSys, cameraCS], thisSurf.normal]; thisSurf.normal _ cameraNormal; IF thisSurf.normal[3] >0 THEN PriorityQueue.Insert[q,thisSurf]; ENDLOOP; }; ENDCASE => ERROR; }; invisible => {}; both => ERROR Feedback.Problem[msg: "Can't have both."]; ENDCASE => ERROR; }; -- end of PutAssemblyOnQueue SetColor: PROC [dc: Imager.Context, camera: Camera, color: Color] = { IF camera.colorFilm THEN Imager.SetColor[dc, color] ELSE { intensity: REAL _ ImagerColorPrivate.IntensityFromColor[NARROW[color]]; Imager.SetColor[dc, ImagerColor.ColorFromGray[1.0-intensity]]}; }; NotYetImplemented: PUBLIC SIGNAL = CODE; Transform: PUBLIC PROC [sliceD: SliceDescriptor, scene: Scene, transform: Matrix4by4] = { shape: Shape _ NARROW[sliceD.slice.shape]; mo: MasterObject _ shape.mo; mo.class.transform[sliceD, scene, transform]; UpdateBoundBoxes[sliceD.slice]; }; IncTransf: PUBLIC PROC [c: Slice, scene: Scene, m: Matrix4by4, d: CoordSystem _ NIL, dFixed: BOOL _ FALSE, cameraList: LIST OF Camera _ NIL] = { assemCS: CoordSystem _ c.coordSys; IF d = NIL THEN d _ scene.coordSysRoot; IncTransfCS[assemCS, d, m, dFixed]; UpdateBoundBoxes[c, cameraList]; }; IncTransfCS: PUBLIC PROC [c: CoordSystem, d: CoordSystem, m: Matrix4by4, dFixed: BOOL _ FALSE] = { p: CoordSystem; cWorld, dWorld, pWorld: Matrix4by4; IF MatrixHasScaling[m] THEN { SIGNAL Feedback.Problem[msg: "SVTransform.IncTransf got illegal matrix. Ignored."]; RETURN}; p _ CoordSys.Parent[c]; IF p = NIL THEN ERROR; -- cannot translate WORLD for now IF d = NIL THEN ERROR; cWorld _ CoordSys.WRTWorld[c]; pWorld _ CoordSys.WRTWorld[p]; dWorld _ CoordSys.WRTWorld[d]; CoordSys.SetMat[c, SVMatrixOps.IncTransf[cWorld, pWorld, dWorld, m]]; IF dFixed THEN SVTransforms.AbsTransfMatrix[d, Matrix3d.Identity[], dWorld]; }; AbsTransf: PUBLIC PROC [c: Slice, scene: Scene, n: Matrix4by4, d: CoordSystem _ NIL, dFixed: BOOL _ FALSE, cameraList: LIST OF Camera _ NIL] = { assemCS: CoordSystem _ c.coordSys; IF d = NIL THEN d _ scene.coordSysRoot; AbsTransfCS[assemCS, d, n, dFixed]; UpdateBoundBoxes[c, cameraList]; }; AbsTransfCS: PUBLIC PROC [c: CoordSystem, d: CoordSystem, n: Matrix4by4, dFixed: BOOL _ FALSE] = { p: CoordSystem; dWorld, pWorld: Matrix4by4; IF Rope.Equal[CoordSys.Name[c], "SCREEN", TRUE] THEN {CoordSys.SetMat[c, n]; RETURN}; p _ CoordSys.Parent[c]; IF p = NIL THEN ERROR; -- cannot transform WORLD. IF d = NIL THEN ERROR; dWorld _ CoordSys.WRTWorld[d]; pWorld _ CoordSys.WRTWorld[p]; CoordSys.SetMat[c, SVMatrixOps.AbsTransf[pWorld, dWorld, n]]; IF dFixed THEN SVTransforms.AbsTransfMatrix[d, Matrix3d.Identity[], dWorld]; }; TugTransf: PUBLIC PROC [c: Slice, scene: Scene, tugBoat: CoordSystem, n: Matrix4by4, d: CoordSystem _ NIL, cameraList: LIST OF Camera _ NIL] = { assemCS: CoordSystem _ c.coordSys; IF d = NIL THEN d _ scene.coordSysRoot; TugTransfCS[assemCS, tugBoat, d, n]; UpdateBoundBoxes[c, cameraList]; }; TugTransfCS: PUBLIC PROC [C: CoordSystem, tugBoat: CoordSystem, D: CoordSystem, N: Matrix4by4] = { F: Matrix4by4 _ CoordSys.FindAInTermsOfB[C, tugBoat]; AbsTransfCS[tugBoat, D, N]; AbsTransfCS[C, tugBoat, F]; }; TugTransfLeaveTug: PUBLIC PROC [c: Slice, scene: Scene, tugBoat: CoordSystem, n: Matrix4by4, d: CoordSystem _ NIL, cameraList: LIST OF Camera _ NIL] = { assemCS: CoordSystem _ c.coordSys; IF d = NIL THEN d _ scene.coordSysRoot; TugTransfLeaveTugCS[assemCS, tugBoat, d, n]; UpdateBoundBoxes[c, cameraList]; }; TugTransfLeaveTugCS: PUBLIC PROC [C: CoordSystem, tugBoat: CoordSystem, D: CoordSystem, N: Matrix4by4] = { F: Matrix4by4; saveTugMat: Matrix4by4 _ CoordSys.GetMat[tugBoat]; F _ CoordSys.FindAInTermsOfB[C, tugBoat]; AbsTransfCS[tugBoat, D, N]; AbsTransfCS[C, tugBoat, F]; CoordSys.SetMat[tugBoat, saveTugMat]; }; ScalePrimitive: PUBLIC PROC [c: Slice, sx, sy, sz: REAL, cameraList: LIST OF Camera _ NIL] = { shape: Shape; scalarCS: CoordSystem; scalars: Vector3d; IF NOT ISTYPE[c.shape, Shape] THEN ERROR; shape _ NARROW[c.shape]; scalarCS _ shape.coordSys; scalars _ CoordSys.GetScalars[scalarCS]; scalars[1] _ scalars[1]*sx; scalars[2] _ scalars[2]*sy; scalars[3] _ scalars[3]*sz; CoordSys.SetScalars[scalarCS, scalars]; UpdateBoundBoxes[c, cameraList]; }; MatrixHasScaling: PRIVATE PROC [mat: Matrix4by4] RETURNS [BOOL] = { sx, sy, sz: REAL; almostZero: REAL _ 1.0e-4; [sx, sy, sz] _ Matrix3d.ScaleFromMatrix[mat]; IF ABS[sx - 1.0] > almostZero OR ABS[sy-1.0] > almostZero OR ABS[sz - 1.0] > almostZero THEN RETURN[TRUE] ELSE RETURN [FALSE]; }; Describe: PUBLIC PROC [sliceD: SliceDescriptor] RETURNS [rope: Rope.ROPE] = { shape: Shape _ NARROW[sliceD.slice.shape]; mo: MasterObject _ shape.mo; RETURN[mo.class.describe[sliceD]]; }; DescribeHit: PUBLIC PROC [slice: Slice, hitData: REF ANY] RETURNS [rope: Rope.ROPE] = { shape: Shape _ NARROW[slice.shape]; mo: MasterObject _ shape.mo; RETURN[mo.class.describeHit[mo, hitData]]; }; EmptyParts: PUBLIC PROC [sliceD: SliceDescriptor] RETURNS [BOOL] = { shape: Shape _ NARROW[sliceD.slice.shape]; mo: MasterObject _ shape.mo; IF sliceD.parts = NIL THEN RETURN[TRUE]; RETURN[mo.class.emptyParts[sliceD]]; }; NewParts: PUBLIC PROC [slice: Slice, hitData: REF ANY, hitPoint: Point3d, mode: SelectMode] RETURNS [sliceD: SliceDescriptor] = { shape: Shape _ NARROW[slice.shape]; mo: MasterObject _ shape.mo; RETURN[mo.class.newParts[slice, hitData, hitPoint, mode]]; }; DescriptorFromParts: PUBLIC PROC [slice: Slice, parts: SliceParts] RETURNS [sliceD: SliceDescriptor] = { sliceD _ NEW[SliceDescriptorObj _ [slice, parts]]; }; UnionParts: PUBLIC PROC [partsA: SliceDescriptor, partsB: SliceDescriptor] RETURNS [aPlusB: SliceDescriptor] = { shape: Shape; mo: MasterObject; IF partsA = NIL AND partsB = NIL THEN RETURN[NIL]; IF partsA = NIL THEN shape _ NARROW[partsB.slice.shape] ELSE shape _ NARROW[partsA.slice.shape]; mo _ shape.mo; RETURN[mo.class.unionParts[partsA, partsB]]; }; DifferenceParts: PUBLIC PROC [partsA: SliceDescriptor, partsB: SliceDescriptor] RETURNS [aMinusB: SliceDescriptor] = { shape: Shape; mo: MasterObject; IF partsA = NIL AND partsB = NIL THEN RETURN[NIL]; IF partsA = NIL THEN shape _ NARROW[partsB.slice.shape] ELSE shape _ NARROW[partsA.slice.shape]; mo _ shape.mo; RETURN[mo.class.differenceParts[partsA, partsB]]; }; MovingParts: PUBLIC PROC [slice: Slice, selectedParts: SliceParts] RETURNS [background, overlay, rubber, drag: SliceDescriptor] = { shape: Shape _ NARROW[slice.shape]; mo: MasterObject _ shape.mo; [background, overlay, rubber, drag] _ mo.class.movingParts[slice, selectedParts]; }; AugmentParts: PUBLIC PROC [sliceD: SliceDescriptor, selectClass: SelectionClass] RETURNS [more: SliceDescriptor] = { mo: MasterObject; mo _ NARROW[sliceD.slice.shape, Shape].mo; more _ mo.class.augmentParts[sliceD, selectClass]; }; PointsInDescriptor: PUBLIC PROC [sliceD: SliceDescriptor] RETURNS [PointGenerator] = { assembly: Slice; mo: MasterObject; shape: Shape; assembly _ sliceD.slice; shape _ NARROW[assembly.shape]; mo _ shape.mo; RETURN[mo.class.pointsInDescriptor[sliceD]]; }; NextPoint: PUBLIC PROC [pointGen: PointGenerator] RETURNS [pointAndDone: PointAndDone] = { assembly: Slice; mo: MasterObject; shape: Shape; ptBlockandDone: PointAndDone; blockWORLD: Matrix4by4; assembly _ pointGen.sliceD.slice; shape _ NARROW[assembly.shape]; mo _ shape.mo; ptBlockandDone _ mo.class.nextPoint[pointGen]; IF ptBlockandDone.done THEN RETURN[[[0,0,0], TRUE]]; blockWORLD _ CoordSys.WRTWorld[shape.coordSys]; pointAndDone.point _ Matrix3d.Update[ptBlockandDone.point, blockWORLD]; pointAndDone.done _ FALSE; }; ClosestPointToPoint: PUBLIC PROC [sliceD: SliceDescriptor, testPoint: Point3d, criticalR: REAL] RETURNS [bestDist: REAL, pointWORLD: Point3d, hitData: REF ANY, success: BOOL] = { mo: MasterObject; mo _ NARROW[sliceD.slice.shape, Shape].mo; [bestDist, pointWORLD, hitData, success] _ mo.class.closestPointToPoint[sliceD, testPoint, criticalR]; }; ClosestPointToLine: PUBLIC PROC [sliceD: SliceDescriptor, cameraPoint: Point2d, line3d: Line3d, criticalR: REAL, camera: Camera] RETURNS [bestDist: REAL, pointWORLD: Point3d, hitData: REF ANY, success: BOOL] = { mo: MasterObject; mo _ NARROW[sliceD.slice.shape, Shape].mo; [bestDist, pointWORLD, hitData, success] _ mo.class.closestPointToLine[sliceD, cameraPoint, line3d, criticalR, camera]; }; ClosestSegmentToLine: PUBLIC PROC [sliceD: SliceDescriptor, cameraPoint: Point2d, line3d: Line3d, criticalR: REAL, camera: Camera] RETURNS [bestDist: REAL, pointWORLD: Point3d, hitData: REF ANY, success: BOOL] = { mo: MasterObject; mo _ NARROW[sliceD.slice.shape, Shape].mo; [bestDist, pointWORLD, hitData, success] _ mo.class.closestSegmentToLine[sliceD, cameraPoint, line3d, criticalR, camera]; }; ClosestJointToHitData: PUBLIC PROC [sliceD: SliceDescriptor, worldPt: Point3d, normal: Vector3d, hitData: REF ANY] RETURNS [jointD: SliceDescriptor, jointPos: Point3d, jointNormal: Vector3d] = { newHitData: REF ANY; success: BOOL; dist: REAL; jointD _ sliceD; [dist, jointPos, newHitData, success] _ ClosestPointToPoint[sliceD, worldPt, Real.LargestNumber]; IF NOT success THEN ERROR; jointNormal _ normal; }; END. ขSVAssemblyImpl.mesa Copyright c 1986 by Xerox Corporation. All rights reserved. Last edited by Bier on February 24, 1987 2:11:06 pm PST Contents: Solidviews assemblies are like Gargoyle slices. They draw themselves as a unit. They update their bounding boxes. Their parts can be selected. This module is to Solidviews what GGSlice is to Gargoyle. We will wire up the shape to a scalars coordinate frame below. Create a primitive assembly, based on the master object named object, in scene. Its surface looks are described by artwork. It will look normal to start with (as opposed to as a "Tool" or invisible). If toolData is not provided, a close-fitting tool will be computed when needed. Object must be on the master object list of scene. Use AddMasterObjectToScene below. If success is FALSE, a message is written to the message window and nothing is done (NameAlreadyPresent and AttemptToAddSubassemblyToPrimitive are failure reasons). Scale the primitive assembly by size and add it as a child of parent, so that assemblyparent will be mat. We will wire up the shape to a scalars coordinate frame below. Now wire up the assembly to its parent. Like CreatePrimitive but adds an assembly which can have children (can be passed as "parent" later. Now wire up the assembly to its parent. Not for general use. Used in conjunction with Create*AtExistingCoordSys to wire up children to parents. Text filein uses this. Fundamentals Returns a bounding polyhedron in master object coordinates. A camera has moved, or we are using this camera for the first time. Update the entry for this camera (adding an entry if needed). We have moved assembly, so its bounding boxes have changed in all views. For each camera in cameraList, update its entry to be correct (add an entry if necessary). Mark all other entries as incorrect. Drawing DrawShadedAssembly: PROC [dc: Imager.Context, assembly: Slice, scene: Scene, camera: Camera] = { Count the total number of surfaces and make a priority queue of the appropriate size. predictedQueueSize: NAT _ CountSurfacesInAssembly[assembly]; surfaceQueue: PriorityQueue.Ref _ PriorityQueue.Predict[predictedQueueSize, DeeperPlanarPolygon]; mo: MasterObject; thisPlanarSurf: PlanarSurface; DrawShadedAssemblyAux: PROC = { Now put the surfaces on the queue PutAssemblyOnQueue[assembly, surfaceQueue, camera.coordSys]; Take the surfaces off the queue in order and draw them FOR i: INT IN[1..PriorityQueue.Size[surfaceQueue]] DO thisPlanarSurf _ NARROW[PriorityQueue.Remove[surfaceQueue]]; mo _ thisPlanarSurf.mo; mo.class.drawSurf[dc, thisPlanarSurf, scene.lightSources, camera]; ENDLOOP; }; Imager.DoSaveAll[dc, DrawShadedAssemblyAux]; }; oldAssemblyWORLD: Matrix4by4 _ CoordSys.WRTWorld[assembly.coordSys]; newAssemblyWORLD: Matrix4by4 _ Matrix3d.Mult[oldAssemblyWORLD, transform]; AbsTransf[assembly, scene, newAssemblyWORLD]; AbsTransf[assembly, scene, oldAssemblyWORLD]; IF assembly = except THEN RETURN; Eliminate most back-facing surfaces at this point by a simple test. Eliminate most back-facing surfaces at this point by a simple test. Transforming Four ways to move an assembly C. If d is NIL, the anchor is assumed to be WORLD. Incrementally transform C with respect to D by M. If D is a descendent of C, this could result in D moving as well. If this is not desired, set DFixed to TRUE and IncTransf makes sure that D doesn't move. Incrementally transform C with respect to D by M. If D is a descendent of C, this could result in D moving as well. If this is not desired, set DFixed to TRUE and IncTransf makes sure that D doesn't move. Absolutely transform C with respect to D by M. If D is a descendent of C, this could result in D moving as well. If this is not desired, set DFixed to TRUE and AbsTransf makes sure that D doesn't move. Absolutely transform C with respect to D by M. If D is a descendent of C, this could result in D moving as well. If this is not desired, set DFixed to TRUE and AbsTransf makes sure that D doesn't move. IF MatrixHasScaling[n] THEN { SIGNAL Feedback.Problem[msg: "SVTransform.AbsTransf got illegal matrix. Ignored."]; RETURN}; -- commented out by Bier on May 27, 1987 3:27:32 pm PDT Absolutely transforms tugBoat with respect to D and then C with respect to tugBoat. Like TugTransf, but returns tugBoat to its original location. Like TugTransf, but returns the Tugboat to its original position. Parts Part Generators Hit Testing This is an incomplete implementation, just to get off the ground. ส$*˜J˜Icodešœ™Kšœ ฯmœ1™—šœžœ ˜Jšœ ˜ Jšœ žœ˜Jšœ ˜ J•StartOfExpansion:[maxEntries: INT _ 10, maxTotalSize: INT _ 2147483647]šœ;˜;Jšœ˜Jšœ˜Jšœ˜Jšœ"˜"Jšœ˜—šž˜šœ˜JšœY˜YJšœ˜Jšžœžœžœžœ˜J˜——Jšžœ˜—J˜J– "Cedar" stylešœš™šJ– "Cedar" stylešœU™UJ– "Cedar" stylešœค™คJ– "Cedar" style™—š   œžœžœMžœ žœ˜J– "Cedar" stylešœVฯuœ ™iJšœžœ˜J˜ šžœžœžœŸ˜AJšœžœ˜(Jšœ˜Jšœ˜šœฯbœ4˜VJšœžœ˜&—Jšœ˜JšœQ˜Qšœขœ)˜\Jšœžœ˜&—Jšœžœ ˜Jšœ˜Jšœ;˜;Jšœ žœ˜J˜—šžœ˜IprocšœV˜VLšœ˜Jšžœžœ˜J˜—J˜J– "Cedar" style™—– "Cedar" styleš !œžœžœ žœžœJžœ žœžœžœžœ&žœ˜‡Jšœ˜Jšœ˜J˜ Jšœ˜Jšœžœ˜ J˜Jšžœ žœžœž˜-šžœ˜JšœG˜GJšœI˜IJ˜—JšœN˜Nšžœžœžœ˜Jšœ˜Jšœ˜J˜—šžœ žœžœ ˜JšœMŸ ˜Z—Jšœžœ ˜šœ˜J™>—šœ žœ ˜Jšœ ˜ Jšœ žœ˜Jšœ ˜ J–:[maxEntries: INT _ 10, maxTotalSize: INT _ 2147483647]šœ;˜;Jšœ˜Jšœ˜Jšœ˜Jšœ"˜"Jšœ˜J™'—Jšœ˜JšœU˜UJšœขœ1˜dJšœ˜Jšœ˜J˜—J˜– "Cedar" styleš  œžœžœ žœ8žœžœžœžœžœ˜ทJ– "Cedar" stylešœc™cJšœHŸ˜PJšœ˜Jšœžœ˜J˜šž˜Jšœ žœ˜Jšžœ,žœžœ ˜BJšžœ žœžœž˜-šžœ˜JšœG˜GJšœI˜IJ˜—šœ žœ ˜Jšœ ˜ Jšœ žœ˜Jšœžœžœ˜-J–:[maxEntries: INT _ 10, maxTotalSize: INT _ 2147483647]šœ;˜;Jšœ˜Jšœ˜Jšœ˜Jšœ"˜"Jšœ˜—– "Cedar" stylešž˜– "Cedar" stylešœ˜Jšœv˜vJšœ˜Jšžœžœžœ˜Jšœ˜——J– "Cedar" stylešžœ˜—J– "Cedar" style˜J– "Cedar" style˜—– "Cedar" styleš   œžœžœ@žœ žœ˜rJšข'™'šžœžœŸ˜4Jšœžœ˜(Jšœi˜iJšœ>˜>J˜—šžœ˜JšœV˜VJšœ˜Jšžœžœ˜J˜—J– "Cedar" style˜J– "Cedar" style˜—– "Cedar" styleš 'œžœžœ žœGžœžœžœžœ˜ัJšœHŸ˜PJšœ˜Jšœžœ˜Jšžœ žœžœž˜-šžœ˜JšœG˜GJšœI˜IJ˜—šœ žœ ˜Jšœ ˜ Jšœ žœ˜Jšœžœžœ˜-J–:[maxEntries: INT _ 10, maxTotalSize: INT _ 2147483647]˜;Jšœ˜Jšœ˜Jšœ˜Jšœ"˜"Jšœ˜—Jšœ˜Jšœ˜J– "Cedar" style˜J˜—J˜Jšข"œžœžœžœ˜9– "Cedar" styleš œžœžœ%˜IšžœžœŸ˜5Jšœžœ˜(Jšœ?˜?J˜—Jšžœžœ$˜/J˜J– "Cedar" style˜J– "Cedar" stylešœ€™€—K˜š  œž œžœžœ˜:Jšžœžœžœžœ˜=J˜J˜—J™ š  œžœžœžœ˜KK™;Kšœ ˜ K˜K˜—Kšœžœžœ˜+šœžœžœ˜!K˜Kšœž ˜K˜K˜—š  œžœžœ3žœ˜gš œžœ"žœžœ˜OKšœžœžœ ˜'Kšœ-žœ˜4K˜—Kšœ1˜1Kšœ žœžœ˜Kšœ˜Kšœžœ˜ šž˜KšœE˜EKš žœžœžœžœŸ˜2šžœ˜Kšœ žœ˜Kš žœžœ žœžœŸ˜@Kšžœ˜K˜—šž˜˜Kšœ'˜'Kšœ*Ÿ˜;K˜——Kšžœ˜—K˜K˜—š œž œ#˜GK™‚š œžœ"žœžœ˜NKšœžœžœ ˜'Kšœ-žœ˜4K˜—Kšœ1˜1Kšœ žœžœ˜Kšœ˜Kšœžœžœ˜K˜KšœD˜Dšžœžœ˜ Kšœ žœ˜Kšœ&˜&Kšœžœ˜K˜—šžœ˜Kšœžœ˜0Kšœ*˜*Kšœ&˜&Kšœžœ˜Kšœ>˜>K˜—K˜K˜—š œžœ3˜@Kšœžœ˜#Kšœ˜Kšœ˜Kšœ˜KšœM˜MKšœŸ˜5K˜K˜—š œžœžœ˜8Kšžœ žœžœžœ˜*Kšœ˜Kšœ˜Kšœ˜Kšœ˜K˜K˜—š  œžœžœžœ žœ˜KKšœส™สKšœ˜Kšœ1˜1Kšœ žœžœ=˜Nš žœžœžœ0žœžœž˜TKšœ žœ˜$Kšžœ žœžœžœ˜+Kšžœ˜—š žœžœžœ žœžœž˜DJšœ+˜+Jšžœ˜—K˜—J™J™š  œžœžœg˜J˜šžœž˜JšœA˜AJšœ žœŸ#˜4šœ ˜ Jšœ˜Jšœ กœ1˜AJšœ กœ(กœ ˜JJšœ#กœ˜*Jšœ.˜.Jšœ#กœ˜*J˜—Jšžœžœ˜$—K˜K˜—š œžœH™`JšœU™UJšœžœ%™<šœ!™!Jšœ?™?—Jšœ™Jšœ™š œžœ™Jšœ!™!Jšœ<™˜>Jšœ˜J˜—š œžœ:˜PJšœ#˜#šžœž˜šœ ˜ Jšœ;˜;šžœžœžœ˜ Jšœ‘˜‘Jšžœ˜J˜—Jšœ6˜6J˜—šœ ˜ Jšžœžœž˜šœ˜Jšžœžœžœ(˜Bšžœžœž˜Jšœ2˜2Jšžœ˜—Jšœ˜—šœ˜Jšœ.˜.Jšœ˜—Jšžœžœ˜J˜—Jšœ˜Jšœžœ*˜7Jšžœžœ˜—Jšœ˜J˜—š œžœY˜xJšœ˜Jšœ#˜#šžœž˜šœ ˜ Jšžœžœž˜šœ˜JšžœC˜IJšœ˜—šœ˜Jšœ@˜@Jšœ˜—Jšžœžœ˜J˜—Jšœ˜Jšœžœ*˜7Jšžœžœ˜—Jšœ˜J˜J˜—š œž œG˜gJšœ<˜˜>šžœ$žœ žœž˜>Jšœ˜Jšœ|˜|Jšœ˜Jšœ"˜"Jšžœ˜—J˜—šœ ˜ šžœžœž˜šœ˜š žœžœžœ žœžœž˜DJšœ,˜,Jšžœ˜—J˜—šœ˜Jšžœžœžœ™!Jšœ6˜6šžœ$žœ žœž˜>Jšœ˜Jšœy˜yšœ˜JšขC™C—Jšžœžœ"˜?Jšžœ˜—Jšœ˜—Jšžœžœ˜—J˜—Jšœ˜Jšœžœ+˜8Jšžœžœ˜—JšœŸ˜J˜—š œžœb˜ƒJšœ˜Jšœ˜Jšœ˜Jšœ˜J˜šžœž˜Jšœ ˜ šœ ˜ šžœžœž˜šœ˜š žœžœžœ žœžœž˜DJšœ,˜,Jšžœ˜—J˜—šœ˜JšœH˜Hšžœ$žœ žœž˜>Jšœ˜Jšœy˜yšœ˜JšขC™C—Jšžœžœ"˜?Jšžœ˜—Jšœ˜—Jšžœžœ˜—J˜—Jšœ˜Jšœžœ+˜8Jšžœžœ˜—JšœŸ˜J˜J˜—š œžœ7˜EJšžœžœ˜3šžœ˜Lšœ žœ)žœ ˜GLšœ?˜?—Jšœ˜—Jšขœžœžœžœ˜)K™ š  œžœžœC˜YJ˜Jšœžœ˜*Jšœ˜Jšœ-˜-Kšœ˜K˜K˜—K™Qš  œžœžœ:žœ žœžœžœžœ žœ˜Jšœœžœ.™ฮKšœ"˜"Kšžœžœžœ˜'Kšœ#˜#Kšœ ˜ K˜K˜—š   œžœžœ9žœžœ˜bJšœœžœ.™ฮLšœ˜Lšœกœกœกœ ˜#L˜šžœžœ˜JšžœN˜TJšžœ˜—Lšœ˜Lš žœžœžœžœŸ!˜8Lšžœžœžœžœ˜L˜Lšœกœ˜Lšœกœ˜Lšœกœ˜Lšœ*กœกœกœ˜EL˜Lšžœžœ7กœ˜LLšœ˜L˜—š  œžœžœ:žœ žœžœžœžœ žœ˜Jšœžœžœžœžœžœžœ8žœžœ™หKšœ"˜"Kšžœžœžœ˜'Kš  œ˜#Kšœ ˜ K˜J™—š   œžœžœ9žœžœ˜bJšœžœžœžœžœžœžœ8žœžœ™หLšœ˜Lšœกœกœ ˜L˜Lšžœ(žœžœžœ˜ULšœ˜Lš žœžœžœžœŸ˜1Lš žœžœžœžœžœ˜šžœžœ™JšžœN™TJšžœ:™@—L˜Lšœกœ˜Lšœกœ˜Lšœ*กœกœ˜=Lšžœžœ7กœ˜LLšœ˜L˜—š  œžœžœPžœžœžœ žœ˜Jšœ.žœ$™SKšœ"˜"Kšžœžœžœ˜'Kšœ$˜$Kšœ ˜ J˜J˜—š   œžœžœžœ%žœžœ˜bJšžœ(žœ ˜5Jšœžœžœ˜Jšœ žœ žœ˜J˜J˜—š œžœžœPžœžœžœ žœ˜˜Jšœ=™=Kšœ"˜"Kšžœžœžœ˜'Kšœ,˜,Kšœ ˜ J˜J˜—š ะbnœž œžœ%žœžœ˜jJ™AJšžœ ˜Jšœ2˜2J˜Jšžœžœ ˜)Jšœžœžœ˜Jšœ žœ žœ˜Jšœ%˜%J˜J˜—š œžœžœžœžœžœ žœ˜^Jšœ ˜ J˜Jšœ˜Jš žœžœžœžœžœ˜)Jšœžœ ˜Jšœ˜Jšœ(˜(Jšœ˜Jšœ˜Jšœ˜Jšœ'˜'Kšœ ˜ Jšœ˜J˜—š  œžœžœžœžœ˜CJšœ žœ˜Jšœ žœ ˜Jšœ-˜-Jš žœžœžœžœžœžœ˜WJšžœžœžœ˜Jšžœžœžœ˜Jšœ˜J˜—š  œžœžœžœ žœ˜MKšœžœ˜*Kšœ˜Kšžœ˜"K˜—š  œžœžœžœžœžœ žœ˜WKšœžœ˜#Kšœ˜Kšžœ$˜*K˜—K™K™š ฃ œžœžœžœžœ˜DKšœžœ˜*Kšœ˜Kš žœžœžœžœžœ˜(Kšžœ˜$K˜—š  œžœžœžœžœ'žœ˜Kšœžœ˜#Kšœ˜Kšžœ4˜:K˜K˜—š œžœžœ#žœ˜hKšœ žœ&˜2K˜—K™š  œžœžœ4žœ˜pKšœ ˜ Kšœ˜Kšžœ žœžœ žœžœžœžœ˜2Kšžœ žœžœ žœ˜7Kšžœ žœ˜(Kšœ˜Kšžœ&˜,K˜—š ฃขœžœžœ4žœ˜vKšœ ˜ Kšœ˜Kšžœ žœžœ žœžœžœžœ˜2Kšžœ žœžœ žœ˜7Kšžœ žœ˜(Kšœ˜Kšžœ+˜1K˜—š  œžœžœ+žœ9˜ƒKšœžœ˜#Kšœ˜KšœQ˜QK˜K˜—šฃ œžœžœ8žœ˜tK˜Kšœžœ˜*Kšœ2˜2K˜—Kšœ™š œžœžœžœ˜VKšœ˜K˜K˜ Kšœ˜Kšœžœ˜Kšœ˜Kšžœ&˜,K˜—– "Cedar" styleš  œžœžœžœ!˜ZKšœ˜K˜K˜ Kšœกœ˜Kšœกœ ˜Kšœ!˜!Kšœžœ˜Kšœ˜Kšœกœ'˜.Kšžœžœžœ žœ˜4Kšœกœ%˜/Kšœ'กœกœ˜GKšœžœ˜J– "Cedar" stylešœ˜—K˜Kšœ ™ š œžœžœ:žœžœ žœกœžœžœ žœ˜ฒK˜Kšœžœ˜*KšœกœQ˜fK˜K˜—š œžœžœLžœžœ žœกœžœžœ žœ˜ำK˜Kšœžœ˜*Kšœกœb˜wK˜—K˜š œžœžœLžœžœ žœกœžœžœ žœ˜ีK˜Kšœžœ˜*Kšœกœd˜yK˜—K˜š  œžœžœHžœžœžœH˜ยK™AKšœ žœžœ˜Kšœ žœ˜Kšœžœ˜ Kšœ˜Kšœa˜aKšžœžœ žœžœ˜Kšœ˜K˜K˜—Kšžœ˜K˜J˜—…—mขา