DIRECTORY AtomButtonsTypes, Feedback, FunctionCache, GGBoundBox, Imager, ImagerColor, ImagerColorPrivate, PriorityQueue, Real, Rope, SV2d, SV3d, SVArtwork, SVAssembly, SVBasicTypes, SVBoundBox, SVCoordSys, SVGraphics, SVMasterObject, SVMatrix3d, SVMatrixOps, SVModelTypes, SVScene, SVSceneTypes, SVToolObject, SVTransforms, SVUtility, ViewerClasses; SVAssemblyImpl: CEDAR PROGRAM IMPORTS Feedback, FunctionCache, GGBoundBox, Imager, ImagerColor, ImagerColorPrivate, PriorityQueue, Rope, SVArtwork, SVBoundBox, SVCoordSys, SVGraphics, SVMasterObject, SVMatrix3d, SVMatrixOps, SVScene, SVToolObject, SVTransforms, SVUtility EXPORTS SVAssembly = BEGIN Artwork: TYPE = SVModelTypes.Artwork; BoundBlock: TYPE = REF BoundBlockObj; BoundBlockObj: TYPE = SVBasicTypes.BoundBlockObj; BoundBox: TYPE = SVBasicTypes.BoundBox; BoundHedron: TYPE = SVBasicTypes.BoundHedron; Camera: TYPE = SVModelTypes.Camera; Classification: TYPE = SVSceneTypes.Classification; 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; PointPairAndDone: TYPE = SVSceneTypes.PointPairAndDone; PointGenerator: TYPE = SVSceneTypes.PointGenerator; PointPairGenerator: TYPE = SVSceneTypes.PointPairGenerator; PointSetOp: TYPE = SVSceneTypes.PointSetOp; -- {union, intersection, difference} Primitive: TYPE = SVSceneTypes.Primitive; Ray: TYPE = SVSceneTypes.Ray; Scene: TYPE = SVSceneTypes.Scene; SelectionClass: TYPE = SVSceneTypes.SelectionClass; SelectMode: TYPE = SVSceneTypes.SelectMode; Shape: TYPE = SVSceneTypes.Shape; ShapeObj: TYPE = SVSceneTypes.ShapeObj; ShowAsType: TYPE = SVSceneTypes.ShowAsType; Slice: TYPE = SVSceneTypes.Slice; SliceList: TYPE = SVSceneTypes.SliceList; SliceListObj: TYPE = SVSceneTypes.SliceListObj; SliceObj: TYPE = SVSceneTypes.SliceObj; SliceDescriptor: TYPE = SVSceneTypes.SliceDescriptor; SliceDescriptorObj: TYPE = SVSceneTypes.SliceDescriptorObj; SliceParts: TYPE = SVSceneTypes.SliceParts; ToolData: TYPE = SVSceneTypes.ToolData; Vector3d: TYPE = SV3d.Vector3d; Viewer: TYPE = ViewerClasses.Viewer; SurfaceSeq: TYPE = REF SurfaceSeqObj; SurfaceSeqObj: TYPE = RECORD [ surfs: SEQUENCE len: NAT OF PlanarSurface ]; SurfaceGenerator: TYPE = REF SurfaceGeneratorObj; SurfaceGeneratorObj: TYPE = RECORD [ surfs: SurfaceSeq ]; 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 _ SVCoordSys.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 _ SVCoordSys.CreateCoordSysInTree[prim.name, mat, parent.coordSys, scene.coordSysRoot]; prim.coordSys _ cs; scalarName _ SVCoordSys.NameWithSuffix[prim.name, "$$Scalars", scene.coordSysRoot]; scalarCS _ SVCoordSys.CreateScalarsOnlyCoordSysInTree[scalarName, size, cs, scene.coordSysRoot]; 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 _ SVCoordSys.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 _ SVCoordSys.NameWithSuffix[assembly.name, "$$Scalars", scene.coordSysRoot]; scalarCS _ SVCoordSys.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 _ SVCoordSys.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 _ SVCoordSys.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 _ SVCoordSys.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]; }; GetBoundBlock: PUBLIC PROC [slice: Slice, parts: SliceParts _ NIL] RETURNS [bBlock: BoundBlock] = { mo: MasterObject _ NARROW[slice.shape, Shape].mo; hedron: BoundHedron _ GetHedron[mo]; point: Point3d; shape: Shape _ NARROW[slice.shape]; shapeWorld: Matrix4by4 _ SVCoordSys.WRTWorld[shape.coordSys]; bBlock _ NEW[BoundBlockObj]; point _ hedron[0]; point _ SVMatrix3d.Update[point, shapeWorld]; bBlock.loX _ bBlock.hiX _ point[1]; bBlock.loY _ bBlock.hiY _ point[2]; bBlock.loZ _ bBlock.hiZ _ point[3]; bBlock.null _ bBlock.infinite _ FALSE; FOR i: NAT IN [1..hedron.len) DO point _ hedron[i]; point _ SVMatrix3d.Update[point, shapeWorld]; bBlock.loX _ MIN[bBlock.loX, point[1]]; bBlock.loY _ MIN[bBlock.loY, point[2]]; bBlock.loZ _ MIN[bBlock.loZ, point[3]]; bBlock.hiX _ MAX[bBlock.hiX, point[1]]; bBlock.hiY _ MAX[bBlock.hiY, point[2]]; bBlock.hiZ _ MAX[bBlock.hiZ, point[3]]; ENDLOOP; }; 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 _ GGBoundBox.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, hiddenLine => ERROR; -- use AddPolygonsToBufferTransform normals => { assem: Slice _ sliceD.slice; oldAssemblyWORLD: Matrix4by4 _ SVCoordSys.WRTWorld[assem.coordSys]; newAssemblyWORLD: Matrix4by4 _ SVMatrix3d.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, SVMatrix3d.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, eyeWorld: Point3d] = { PutAssemblyOnQueue[assembly, surfaceQueue, camera.coordSys, eyeWorld]; }; AddPolygonsToBufferTransform: PUBLIC PROC [surfaceQueue: PriorityQueue.Ref, sliceD: SliceDescriptor, scene: Scene, camera: Camera, eyeWorld: Point3d, transform: Matrix4by4] = { PutAssemblyOnQueueTransform[sliceD, surfaceQueue, camera.coordSys, eyeWorld, transform]; }; DrawBuffer: PUBLIC PROC [dc: Imager.Context, surfaceQueue: PriorityQueue.Ref, scene: Scene, camera: Camera, hiddenLine: BOOL] = { 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, eyeWorld, hiddenLine]; ENDLOOP; }; eyeWorld: Point3d _ SVGraphics.LocalToWorld[[0,0,camera.focalLength], camera.coordSys]; 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; }; RayCast: PUBLIC PROC [cameraPoint: Point2d, localRay: Ray, sliceD: SliceDescriptor, prim: Primitive] RETURNS [class: Classification] = { shape: Shape _ NARROW[sliceD.slice.shape]; mo: MasterObject _ shape.mo; class _ mo.class.rayCast[cameraPoint, localRay, sliceD, prim]; }; RayCastNoBBoxes: PUBLIC PROC [localRay: Ray, sliceD: SliceDescriptor, prim: Primitive, positiveTOnly: BOOL _ TRUE] RETURNS [class: Classification] = { shape: Shape _ NARROW[sliceD.slice.shape]; mo: MasterObject _ shape.mo; class _ mo.class.rayCastNoBBoxes[localRay, sliceD, prim, positiveTOnly]; }; RayCastBoundingSpheres: PUBLIC PROC [localRay: Ray, sliceD: SliceDescriptor, prim: Primitive, positiveTOnly: BOOL _ TRUE] RETURNS [class: Classification] = { shape: Shape _ NARROW[sliceD.slice.shape]; mo: MasterObject _ shape.mo; class _ mo.class.rayCastBoundingSpheres[localRay, sliceD, prim, positiveTOnly]; }; DrawSelectionFeedback: PUBLIC PROC [slice: Slice, selectedParts: SliceParts, hotParts: SliceParts, dc: Imager.Context, camera: Camera, dragInProgress, caretIsMoving, hideHot, quick: BOOL] = { shape: Shape _ NARROW[slice.shape]; mo: MasterObject _ shape.mo; mo.class.drawSelectionFeedback[slice, selectedParts, hotParts, dc, camera, dragInProgress, caretIsMoving, hideHot, quick]; }; DrawAttractorFeedback: PUBLIC PROC [sliceD: SliceDescriptor, selectedParts: SliceParts, dragInProgress: BOOL, dc: Imager.Context, camera: Camera] = { shape: Shape _ NARROW[sliceD.slice.shape]; mo: MasterObject _ shape.mo; mo.class.drawAttractorFeedback[sliceD, selectedParts, dragInProgress, dc, camera]; }; 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, eyeWorld: Point3d] = { surfList: PlanarSurfaceList; SELECT assembly.showAs FROM tool => { toolMasterObject: MasterObject _ assembly.toolMasterObject; surfList _ toolMasterObject.class.getSurf[assembly, cameraCS, eyeWorld]; FOR surfList _ surfList, surfList.rest UNTIL surfList = NIL DO PriorityQueue.Insert[q, surfList.first]; 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, eyeWorld]; ENDLOOP; }; shape: Shape => { cameraShape: Matrix4by4; cameraShape _ SVCoordSys.FindCameraInTermsOf[shape.coordSys, cameraCS]; surfList _ shape.mo.class.getSurf[assembly, cameraCS, eyeWorld]; FOR surfList _ surfList, surfList.rest UNTIL surfList = NIL DO PriorityQueue.Insert[q, surfList.first]; 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, eyeWorld: Point3d, transform: Matrix4by4] = { 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, eyeWorld]; ENDLOOP; }; shape: Shape => { surfList _ shape.mo.class.getSurfTransform[sliceD, cameraCS, eyeWorld, transform]; FOR surfList _ surfList, surfList.rest UNTIL surfList = NIL DO PriorityQueue.Insert[q, surfList.first]; 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]; }; IncTransfMatrix: PUBLIC PROC [c: Slice, dWorld: Matrix4by4, m: Matrix4by4, cameraList: LIST OF Camera _ NIL] = { p: CoordSystem; cWorld, pWorld: Matrix4by4; assemCS: CoordSystem _ c.coordSys; p _ SVCoordSys.Parent[assemCS]; IF p = NIL THEN ERROR; -- cannot translate WORLD for now cWorld _ SVCoordSys.WRTWorld[assemCS]; pWorld _ SVCoordSys.WRTWorld[p]; SVCoordSys.SetMat[assemCS, SVMatrixOps.IncTransf[cWorld, pWorld, dWorld, m]]; UpdateBoundBoxes[c, cameraList]; }; IncTransfCS: PUBLIC PROC [c: CoordSystem, d: CoordSystem, m: Matrix4by4, dFixed: BOOL _ FALSE] = { p: CoordSystem; cWorld, dWorld, pWorld: Matrix4by4; p _ SVCoordSys.Parent[c]; IF p = NIL THEN ERROR; -- cannot translate WORLD for now IF d = NIL THEN ERROR; cWorld _ SVCoordSys.WRTWorld[c]; pWorld _ SVCoordSys.WRTWorld[p]; dWorld _ SVCoordSys.WRTWorld[d]; SVCoordSys.SetMat[c, SVMatrixOps.IncTransf[cWorld, pWorld, dWorld, m]]; IF dFixed THEN SVTransforms.AbsTransfMatrix[d, SVMatrix3d.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[SVCoordSys.Name[c], "SCREEN", TRUE] THEN {SVCoordSys.SetMat[c, n]; RETURN}; p _ SVCoordSys.Parent[c]; IF p = NIL THEN ERROR; -- cannot transform WORLD. IF d = NIL THEN ERROR; dWorld _ SVCoordSys.WRTWorld[d]; pWorld _ SVCoordSys.WRTWorld[p]; SVCoordSys.SetMat[c, SVMatrixOps.AbsTransf[pWorld, dWorld, n]]; IF dFixed THEN SVTransforms.AbsTransfMatrix[d, SVMatrix3d.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 _ SVCoordSys.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 _ SVCoordSys.GetMat[tugBoat]; F _ SVCoordSys.FindAInTermsOfB[C, tugBoat]; AbsTransfCS[tugBoat, D, N]; AbsTransfCS[C, tugBoat, F]; SVCoordSys.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 _ SVCoordSys.GetScalars[scalarCS]; scalars[1] _ scalars[1]*sx; scalars[2] _ scalars[2]*sy; scalars[3] _ scalars[3]*sz; SVCoordSys.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] _ SVMatrix3d.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]]; }; IsEmptyParts: 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.isEmptyParts[sliceD]]; }; IsCompleteParts: 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.isCompleteParts[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, centroids: BOOL] RETURNS [PointGenerator] = { assembly: Slice; mo: MasterObject; shape: Shape; assembly _ sliceD.slice; shape _ NARROW[assembly.shape]; mo _ shape.mo; RETURN[mo.class.pointsInDescriptor[sliceD, centroids]]; }; 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 _ SVCoordSys.WRTWorld[shape.coordSys]; pointAndDone.point _ SVMatrix3d.Update[ptBlockandDone.point, blockWORLD]; pointAndDone.done _ FALSE; }; PointPairsInDescriptor: PUBLIC PROC [sliceD: SliceDescriptor] RETURNS [pointPairGen: PointPairGenerator] = { assembly: Slice; mo: MasterObject; shape: Shape; assembly _ sliceD.slice; shape _ NARROW[assembly.shape]; mo _ shape.mo; RETURN[mo.class.pointPairsInDescriptor[sliceD]]; }; NextPointPair: PUBLIC PROC [pointPairGen: PointPairGenerator] RETURNS [pointPairAndDone: PointPairAndDone] = { assembly: Slice; mo: MasterObject; shape: Shape; pointPairShapeandDone: PointPairAndDone; shapeWorld: Matrix4by4; assembly _ pointPairGen.sliceD.slice; shape _ NARROW[assembly.shape]; mo _ shape.mo; pointPairShapeandDone _ mo.class.nextPointPair[pointPairGen]; IF pointPairShapeandDone.done THEN RETURN[[[0,0,0], [0,0,0], TRUE]]; shapeWorld _ SVCoordSys.WRTWorld[shape.coordSys]; pointPairAndDone.lo _ SVMatrix3d.Update[pointPairShapeandDone.lo, shapeWorld]; pointPairAndDone.hi _ SVMatrix3d.Update[pointPairShapeandDone.hi, shapeWorld]; pointPairAndDone.done _ FALSE; }; ClosestPointToPoint: PUBLIC PROC [sliceD: SliceDescriptor, testPoint: Point3d, t: REAL, centroids: BOOL] RETURNS [bestDist: REAL, pointWorld: Point3d, normalWorld: Vector3d, hitData: REF ANY, success: BOOL] = { mo: MasterObject; mo _ NARROW[sliceD.slice.shape, Shape].mo; [bestDist, pointWorld, normalWorld, hitData, success] _ mo.class.closestPointToPoint[sliceD, testPoint, t, centroids]; }; ClosestPointToLine: PUBLIC PROC [sliceD: SliceDescriptor, cameraPoint: Point2d, line3d: Line3d, t: REAL, camera: Camera, centroids: BOOL] RETURNS [bestDist: REAL, pointWorld: Point3d, normalWorld: Vector3d, hitData: REF ANY, success: BOOL] = { mo: MasterObject; mo _ NARROW[sliceD.slice.shape, Shape].mo; [bestDist, pointWorld, normalWorld, hitData, success] _ mo.class.closestPointToLine[sliceD, cameraPoint, line3d, t, camera, centroids]; }; ClosestSegmentToLine: PUBLIC PROC [sliceD: SliceDescriptor, cameraPoint: Point2d, line3d: Line3d, t: REAL, camera: Camera] RETURNS [bestDist: REAL, pointWorld: Point3d, normalWorld: Vector3d, hitData: REF ANY, success: BOOL] = { mo: MasterObject; mo _ NARROW[sliceD.slice.shape, Shape].mo; [bestDist, pointWorld, normalWorld, hitData, success] _ mo.class.closestSegmentToLine[sliceD, cameraPoint, line3d, t, 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, jointNormal, newHitData, success] _ ClosestPointToPoint[sliceD, worldPt, Real.LargestNumber, FALSE]; IF NOT success THEN ERROR; }; WithinBoundBlock: PUBLIC PROC [slice: Slice, boundBlockWorld: BoundBlock, parts: SliceParts _ NIL] RETURNS [withinParts: SliceDescriptor] = { mo: MasterObject; mo _ NARROW[slice.shape, Shape].mo; withinParts _ mo.class.withinBoundBlock[slice, boundBlockWorld, parts]; }; SetStrokeColor: PUBLIC PROC [slice: Slice, parts: SliceParts, color: Color _ NIL] = { mo: MasterObject; mo _ NARROW[slice.shape, Shape].mo; mo.class.setStrokeColor[slice, parts, color]; }; GetStrokeColor: PUBLIC PROC [slice: Slice, parts: SliceParts] RETURNS [color: Color _ NIL] = { mo: MasterObject; mo _ NARROW[slice.shape, Shape].mo; color _ mo.class.getStrokeColor[slice, parts]; }; SetFillColor: PUBLIC PROC [slice: Slice, parts: SliceParts, artwork: Artwork] = { mo: MasterObject; mo _ NARROW[slice.shape, Shape].mo; mo.class.setFillColor[slice, parts, artwork]; }; GetFillColor: PUBLIC PROC [slice: Slice, parts: SliceParts] RETURNS [artwork: Artwork] = { mo: MasterObject; mo _ NARROW[slice.shape, Shape].mo; artwork _ mo.class.getFillColor[slice, parts]; }; MakeBlockSlice: PUBLIC PROC [loX, loY, loZ, hiX, hiY, hiZ: REAL, corner: [0..7], transform: Matrix4by4, scene: Scene, feedback: FeedbackData] RETURNS [sliceD: SliceDescriptor] = { sliceParts: SliceParts; slice: Slice; mo: MasterObject; masterObjectFound, success: BOOL _ TRUE; name: Rope.ROPE _ SVScene.UniqueAssemblyNameFrom["Block", scene]; [sliceParts, mo] _ SVMasterObject.MakeBlockSlice[name, loX, loY, loZ, hiX, hiY, hiZ, corner]; BEGIN moFound: BOOL _ TRUE; addSucceeds: BOOL _ TRUE; SVScene.AddMasterObjectToScene[mo, scene ! SVScene.NameAlreadyPresent => { Feedback.PutF[feedback, oneLiner, "%g name %g is already registered. Try another.", [rope[mo.class.name]], [rope[mo.name]]]; Feedback.Blink[feedback]; addSucceeds _ FALSE; CONTINUE} ]; IF NOT addSucceeds THEN RETURN; END; [slice, masterObjectFound, success] _ CreatePrimitive[name, name, scene]; IF NOT masterObjectFound OR NOT success THEN ERROR; sliceD _ DescriptorFromParts[slice, sliceParts]; }; 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. Hidden Surface 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 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. IF MatrixHasScaling[m] THEN... 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. jointNormal _ normal; Style ส*ท˜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šœ˜Jšœฯbœ6˜ZJšœ˜JšœS˜SJšœขœ+˜`Jšœžœ ˜Jšœ˜Jšœ;˜;Jšœ žœ˜J˜—šžœ˜IprocšœV˜VNšœ˜Jšžœžœ˜J˜—J˜J– "Cedar" style™—– "Cedar" styleš !œžœžœ žœžœJžœ žœžœžœžœ&žœ˜‡Jšœ˜Jšœ˜J˜ Jšœ˜Jšœžœ˜ J˜Jšžœ žœžœž˜-šžœ˜JšœI˜IJšœ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šœW˜WJšœขœ1˜fJšœ˜Jšœ˜J˜—J˜– "Cedar" styleš  œžœžœ žœ8žœžœžœžœžœ˜ทJ– "Cedar" stylešœc™cJšœHŸ˜PJšœ˜Jšœžœ˜J˜šž˜Jšœ žœ˜Jšžœ,žœžœ ˜BJšžœ žœžœž˜-šžœ˜JšœI˜IJšœ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šœk˜kJšœ>˜>J˜—šžœ˜JšœV˜VJšœ˜Jšžœžœ˜J˜—J– "Cedar" style˜J– "Cedar" style˜—– "Cedar" styleš 'œžœžœ žœGžœžœžœžœ˜ัJšœHŸ˜PJšœ˜Jšœžœ˜Jšžœ žœžœž˜-šžœ˜JšœI˜IJšœ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˜—š   œžœžœ$žœžœ˜cKšœžœ˜1Kšœ$˜$Kšœ˜Kšœžœ˜#Kšœกœ3˜=Kšœ žœ˜Jšœ˜Jšœ&กœ˜-Kšœ#˜#Kšœ#˜#Kšœ#˜#Kšœ žœ˜&šžœžœžœž˜ Jšœ˜Jšœ&กœ˜-Jšœ žœ˜'Jšœ žœ˜'Jšœ žœ˜'Jšœ žœ˜'Jšœ žœ˜'Jšœ žœ˜'Jšžœ˜—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šœžœŸ#˜@šœ ˜ Jšœ˜Jšœ กœ3˜CJšœ กœ*กœ ˜LJšœ#กœ˜*Jšœ.˜.Jšœ#กœ˜*J˜—Jšžœžœ˜$—K˜K˜—š  œžœ!žœžœžœžœ˜WJšœžœ˜Jšœžœ˜Jšžœ˜Jšœ˜J˜—š   œžœžœ$žœ;žœ˜Jšžœ žœžœ ˜3J˜—š œžœžœE˜VJšœ*žœ˜?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กœ˜zJšœ?กœ˜FJšœ˜J˜—š œžœžœ]กœ%˜ฐJšœFกœ ˜XJ˜J˜—š  œžœžœažœ˜š  œžœ˜Jšœ˜Jšœ˜šžœžœžœ&ž˜5Jšœžœ%˜˜>N˜—š  œžœžœJžœžœžœ˜–Kšœžœ˜*Kšœ˜KšœH˜HN˜—š  œžœžœJžœžœžœ˜Kšœžœ˜*Kšœ˜KšœO˜ON˜—š œžœžœ”žœ˜ฟKšœžœ˜#Kšœ˜Kšœz˜zK˜—J˜šะbnœžœžœFžœ)˜•Kšœžœ˜*Kšœ˜KšœR˜RK˜K˜—š œžœžœ žœ˜Lšžœžœž˜JšœE˜EJšœ?˜?Jšžœžœ˜—Jšœ˜J˜—š œžœžœ žœ˜OJšœ˜š žœžœžœžœžœž˜AJšœ<˜Jšœ(˜(Jšžœ˜—J˜—šœ ˜ šžœžœž˜šœ˜š žœžœžœ žœžœž˜DJšœ/กœ˜6Jšžœ˜—J˜—šœ˜Jšœกœ ˜Jšœกœ<˜GJšœ9กœ˜@šžœ$žœ žœž˜>Jšœ(˜(Jšžœ˜—Jšœ˜—Jšžœžœ˜—J˜—Jšœ˜Jšœžœ+˜8Jšžœžœ˜—JšœŸ˜J˜—š œžœKกœ%˜–Jšœ˜Jšœ˜J˜šžœž˜Jšœ ˜ šœ ˜ šžœžœž˜šœ˜š žœžœžœ žœžœž˜DJšœ/กœ˜6Jšžœ˜—J˜—šœ˜Jšœ@กœ ˜Ršžœ$žœ žœž˜>Jšœ(˜(Jšžœ˜—Jšœ˜—Jšžœžœ˜—J˜—Jšœ˜Jšœžœ+˜8Jšžœžœ˜—JšœŸ˜J˜J˜—š œžœ7˜EJšžœžœ˜3šžœ˜Nšœ žœ)žœ ˜GNšœ?˜?—Jšœ˜—Jšขœžœžœžœ˜)K™ š  œžœžœC˜YJ˜Jšœžœ˜*Jšœ˜Jšœ-˜-Kšœ˜K˜K˜—K™Qš  œžœžœ:žœ žœžœžœžœ žœ˜Jšœœžœ.™ฮKšœ"˜"Kšžœžœžœ˜'Kšœ#˜#Kšœ ˜ K˜K˜—š œžœžœ กœ)žœžœ žœ˜pNšœ˜Nšœกœกœ ˜Kšœ"˜"N˜Nšœ˜Nš žœžœžœžœŸ!˜8N˜Nšœกœ ˜&Nšœกœžœ˜ Nš œขœกœกœžะkuœ˜MKšœ ˜ Nšœ˜N˜—š   œžœžœ9žœžœ˜bJšœœžœ.™ฮNšœ˜Nšœกœกœกœ ˜#N˜Jšžœžœ™Nšœ˜Nš žœžœžœžœŸ!˜8Nšžœžœžœžœ˜N˜Nšœกœ˜ Nšœกœ˜ Nšœกœ˜ Nšœ,กœกœกœ˜GN˜Nšžœžœ9กœ˜NNšœ˜N˜—š  œžœžœ:žœ žœžœžœžœ žœ˜Jšœžœžœžœžœžœžœ8žœžœ™หKšœ"˜"Kšžœžœžœ˜'Kš  œ˜#Kšœ ˜ K˜J™—š   œžœžœ9žœžœ˜bJšœžœžœžœžœžœžœ8žœžœ™หNšœ˜Nšœกœกœ ˜N˜Nšžœ*žœžœžœ˜YNšœ˜Nš žœžœžœžœŸ˜1Nš žœžœžœžœžœ˜šžœžœ™JšžœN™TJšžœ:™@—N˜Nšœกœ˜ Nšœกœ˜ Nšœ,กœกœ˜?Nšžœžœ9กœ˜NNšœ˜N˜—š  œžœžœPžœžœžœ žœ˜Jšœ.žœ$™SKšœ"˜"Kšžœžœžœ˜'Kšœ$˜$Kšœ ˜ J˜J˜—š   œžœžœžœ%žœžœ˜bJšžœ*žœ ˜7Jšœžœžœ˜Jšœ žœ žœ˜J˜J˜—š œžœžœPžœžœžœ žœ˜˜Jšœ=™=Kšœ"˜"Kšžœžœžœ˜'Kšœ,˜,Kšœ ˜ J˜J˜—š ฃœž œžœ%žœžœ˜jJ™AJšžœ ˜Jšœ4˜4J˜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™š ฃ œžœžœžœžœ˜FKšœžœ˜*Kšœ˜Kš žœžœžœžœžœ˜(Kšžœ ˜&K˜—š ฃœžœžœžœžœ˜IKšœžœ˜*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˜Kšœ™š  œžœžœ&žœžœ˜gKšœ˜K˜K˜ Kšœ˜Kšœžœ˜Kšœ˜Kšžœ1˜7K˜—– "Cedar" styleš  œžœžœžœ!˜ZKšœ˜K˜K˜ Kšœกœ˜Kšœกœ ˜Kšœ!˜!Kšœžœ˜Kšœ˜Kšœกœ'˜.Kšžœžœžœ žœ˜4Kšœกœ'˜1Kšœ)กœกœ˜IKšœžœ˜J– "Cedar" stylešœ˜—K˜– "Cedar" styleš œžœžœžœ'˜lKšœ˜K˜K˜ Kšœ˜Kšœžœ˜Kšœ˜Kšžœ*˜0J– "Cedar" style˜J– "Cedar" style˜—– "Cedar" styleš  œžœžœ$žœ)˜nKšœ˜K˜K˜ Kšœ กœ˜(Kšœกœ ˜Kšœ%˜%Kšœžœ˜Kšœ˜Kšœ กœ/˜=Kš žœ กœ žœžœžœ˜DKšœกœ'˜1Kšœ1กœกœ˜NKšœ1กœกœ˜NKšœžœ˜J– "Cedar" style˜J– "Cedar" style˜—Kšœ ™ š œžœžœ2žœ žœžœ žœกœกœžœžœ žœ˜าK˜Kšœžœ˜*KšœกœกœT˜vK˜K˜—š œžœžœDžœžœžœ žœกœกœžœžœ žœ˜๓K˜Kšœžœ˜*Kšœกœกœe˜‡K˜—K˜š œžœžœDžœžœ žœกœกœžœžœ žœ˜ไK˜Kšœžœ˜*Kšœกœกœ\˜~K˜—K˜š  œžœžœHžœžœžœH˜ยK™AKšœ žœžœ˜Kšœ žœ˜Kšœžœ˜ Kšœ˜Kšœnžœ˜uKšžœžœ žœžœ˜Kšœ™K˜K˜—K™š  œžœžœกœ"žœžœ#˜K˜Kšœžœ˜#Kšœ9กœ ˜GK˜K˜—Kšœ™K˜š œžœžœ2žœ˜UK˜Kšœžœ˜#Kšœ-˜-K˜K˜—š  œžœžœ#žœžœ˜^K˜Kšœžœ˜#Kšœ.˜.K˜K˜—š  œžœžœ8˜QK˜Kšœžœ˜#Kšœ-˜-K˜K˜—š  œžœžœ#žœ˜ZK˜Kšœžœ˜#Kšœ.˜.K˜—K˜š  œžœžœ žœOžœ˜ณKšœ˜K˜ K˜Kšœžœžœ˜(K˜Kšœ žœ2˜AKšœ]˜]šž˜Nšœ žœžœ˜Nšœ žœžœ˜šœ(˜(šœ!˜!Nšœ}˜}Nšœ(žœžœ˜8Nšœ˜——Nšžœžœ žœžœ˜Kšžœ˜—KšœI˜IKš žœžœžœžœ žœžœ˜3Kšœ0˜0K˜—K˜Kšžœ˜K˜Jšก˜—…—„Fผ