<> <> <> <> <> DIRECTORY AtomButtonsTypes, Containers, SVCoordSys, Feedback, Icons, Imager, Interminal, IO, Menus, SVPadGraphics, Rope, SV2d, SVInterfaceTypes, SVLines2d, SVModelTypes, SVPolygon2d, SVScratchpad, SVScratchpadMonitor, SVScratchpadUser, SVVector2d, SVSweepGeometry, TIPUser, ViewerClasses, ViewerOps; SVScratchpadImpl: CEDAR PROGRAM IMPORTS Containers, SVCoordSys, Feedback, Icons, Imager, IO, Menus, SVPadGraphics, SVLines2d, SVPolygon2d, SVScratchpadMonitor, SVScratchpadUser, SVVector2d, TIPUser, ViewerOps EXPORTS SVScratchpad SHARES ViewerClasses = BEGIN CoordSystem: TYPE = SVModelTypes.CoordSystem; EditToolData: TYPE = SVInterfaceTypes.EditToolData; FeedbackData: TYPE = AtomButtonsTypes.FeedbackData; ImagerProc: TYPE = SVInterfaceTypes.ImagerProc; Path: TYPE = SV2d.Path; Point2d: TYPE = SV2d.Point2d; PointPolyClass: TYPE = SVPolygon2d.PointPolyClass; Polygon: TYPE = SV2d.Polygon; TrigLineSeg: TYPE = SV2d.TrigLineSeg; Vector2d: TYPE = SV2d.Vector2d; Viewer: TYPE = ViewerClasses.Viewer; entryHeight: CARDINAL = 15; -- height of a line of items entryVSpace: CARDINAL = 3; -- vertical leading between lines entryHSpace: CARDINAL = 10; -- horizontal space between items on a line ScratchViewerData: TYPE = REF ScratchViewerDataObj; ScratchViewerDataObj: TYPE = SVInterfaceTypes.ScratchViewerDataObj; ScratchpadData: TYPE = REF ScratchpadDataObj; ScratchpadDataObj: TYPE = SVInterfaceTypes.ScratchpadDataObj; ScratchpadPaint: SAFE PROC [self: Viewer, context: Imager.Context, whatChanged: REF ANY, clear: BOOL] RETURNS [quit: BOOL _ FALSE] = TRUSTED { <> <> scratchpadData: ScratchpadData; scratchViewerState: ScratchViewerData; IF whatChanged = NIL THEN {--we are being called by Window Manager scratchpadData _ NARROW[self.data]; SVScratchpadUser.PlaceOrigin[self]; SVScratchpadUser.DrawSceneButton[self, scratchpadData.scratchViewerData, red, FALSE, FALSE]; } ELSE { proc: ImagerProc; scratchViewerState _ NARROW[whatChanged]; scratchpadData _ NARROW[scratchViewerState.scratchpad.data]; proc _ scratchpadData.proc; proc[context]; }; }; Init: PROC = { scratchpadClass: ViewerClasses.ViewerClass; <> scratchpadClass _ NEW[ViewerClasses.ViewerClassRec _ [ paint: ScratchpadPaint, notify: InputNotify, tipTable: TIPUser.InstantiateNewTIPTable["SVScratchpad.tip"] ]]; ViewerOps.RegisterViewerClass[$SVScratchpad, scratchpadClass]; }; IntMax: PRIVATE PROC [a, b: INTEGER] RETURNS [max: INTEGER] = { RETURN[IF a>= b THEN a ELSE b]; }; CreateScratchpad: PUBLIC PROC [parent: ViewerClasses.Viewer, editToolData: EditToolData] RETURNS [container: Viewer, scratchpad: Viewer] = TRUSTED { <> <> < DESTROY SAVE NEWLINE ERASE>> <> world: CoordSystem; padMenu: Menus.Menu; scratchViewerData: ScratchViewerData _ NEW[ScratchViewerDataObj]; scratchpadData: ScratchpadData _ NEW[ScratchpadDataObj]; -- make the data object for the solid window <> padMenu _ Menus.CreateMenu[2]; Menus.AppendMenuEntry[ menu: padMenu, entry: Menus.CreateEntry[ name: "Erase", proc: SVScratchpadUser.EraseButton, clientData: scratchViewerData, documentation: "erase the scratchpad" ], line: 0 ]; Menus.AppendMenuEntry[ menu: padMenu, entry: Menus.CreateEntry[ name: "Normals", proc: SVScratchpadUser.NormalsButton, clientData: scratchViewerData, documentation: "show normals to all current segments" ], line: 0 ]; <> Menus.AppendMenuEntry[ menu: padMenu, entry: Menus.CreateEntry[ name: "CrossHairs", proc: SVScratchpadUser.CrossHairsButton, clientData: scratchViewerData, documentation: "draw crosshairs to show current origin" ], line: 0 ]; Menus.AppendMenuEntry[ menu: padMenu, entry: Menus.CreateEntry[ name: "NewLin", proc: SVScratchpadUser.NewLinButton, clientData: scratchViewerData, documentation: "prepare to draw the outline of a linear sweep" ], line: 0 ]; Menus.AppendMenuEntry[ menu: padMenu, entry: Menus.CreateEntry[ name: "NewRevo", proc: SVScratchpadUser.NewRevoButton, clientData: scratchViewerData, documentation: "prepare to draw the outline of a revolute sweep" ], line: 0 ]; Menus.AppendMenuEntry[ menu: padMenu, entry: Menus.CreateEntry[ name: "TestPoints", proc: SVScratchpadUser.TestPointsButton, clientData: scratchViewerData, documentation: "prepare to perform in-on-out test on mouse points" ], line: 0 ]; Menus.AppendMenuEntry[ menu: padMenu, entry: Menus.CreateEntry[ name: "Circle", proc: SVScratchpadUser.CircleButton, clientData: scratchViewerData, documentation: "draw a circle centered on the origin" ], line: 0 ]; Menus.AppendMenuEntry[ menu: padMenu, entry: Menus.CreateEntry[ name: "CatScan", proc: SVScratchpadUser.DrawCatScanButton, clientData: scratchViewerData, documentation: "Draw the current slice from the selected viewer" ], line: 1 ]; Menus.AppendMenuEntry[ menu: padMenu, entry: Menus.CreateEntry[ name: "Interpress", proc: SVScratchpadUser.HardcopyButton, clientData: scratchViewerData, documentation: "Make an interpress document of this scene" ], line: 1 ]; Menus.AppendMenuEntry[ menu: padMenu, entry: Menus.CreateEntry[ name: "CatScanRepeat", proc: SVScratchpadUser.CatScanRepeatButton, clientData: scratchViewerData, documentation: "Draw the current slice. Don't recompute tree" ], line: 1 ]; <> scratchViewerData.outer _ Containers.Create[[ name: "SVScratchpad", menu: padMenu, iconic: TRUE, column: right,-- data is set by the Containers package scrollable: TRUE, icon: Icons.NewIconFromFile["SolidViews.icons", 1] ]]; scratchViewerData.editToolData _ editToolData; world _ SVCoordSys.CreateRoot["WORLD"]; scratchpadData.origin _ [200, 200]; -- will be updated every window manager paint scratchpadData.path _ SVPolygon2d.CreatePath[IntMax[SVSweepGeometry.maxMeshLen, SVSweepGeometry.maxLinesOfLat]]; scratchpadData.mode _ off; scratchpadData.scratchViewerData _ scratchViewerData; <> scratchViewerData.scratchpad _ ViewerOps.CreateViewer[ flavor: $SVScratchpad, info: [ parent: scratchViewerData.outer, wx: 0, wy: scratchViewerData.height, ww: scratchViewerData.outer.ww, wh: scratchViewerData.outer.wh,-- only initial values for ww and wh. They are constrained below data: scratchpadData,-- contains the current scene scrollable: FALSE ] ]; Containers.ChildXBound[scratchViewerData.outer, scratchViewerData.scratchpad]; Containers.ChildYBound[scratchViewerData.outer, scratchViewerData.scratchpad]; scratchViewerData.height _ scratchViewerData.height + scratchViewerData.scratchpad.wh; ViewerOps.PaintViewer[scratchViewerData.outer, all]; container _ scratchViewerData.outer; scratchpad _ scratchViewerData.scratchpad; }; -- end of CreateScratchpad GetPath: PUBLIC PROC [self: Viewer] RETURNS [path: Path] = { <> scratchpadData: ScratchpadData _ NARROW[self.data]; path _ scratchpadData.path; }; InputNotify: PUBLIC SAFE PROCEDURE [self: ViewerClasses.Viewer, input: LIST OF REF ANY] = TRUSTED { <> IF ISTYPE[input.first, TIPUser.TIPScreenCoords] THEN { controlPoint: Point2d; mousePlace: TIPUser.TIPScreenCoords _ NARROW[input.first]; scratchpadData: ScratchpadData _ NARROW[self.data]; context: Imager.Context _ scratchpadData.imager; <

> controlPoint[1] _ mousePlace.mouseX; controlPoint[2] _ mousePlace.mouseY; <> IF ISTYPE[input.rest.first, ATOM] THEN SELECT input.rest.first FROM $DRAW => { scratchpadData: ScratchpadData _ NARROW[self.data]; SELECT scratchpadData.mode FROM off => RETURN; pointAt => TestPoint[controlPoint, scratchpadData]; drawLin =>{ AddLinPoint[controlPoint, scratchpadData]; SVScratchpadUser.DrawSceneButton[self, scratchpadData.scratchViewerData, red, FALSE, FALSE]; }; drawRevo =>{ AddRevoPoint[controlPoint, scratchpadData]; SVScratchpadUser.DrawSceneButton[self, scratchpadData.scratchViewerData, red, FALSE, FALSE]; }; ENDCASE => ERROR; }; $MOVE => { scratchpadData: ScratchpadData _ NARROW[self.data]; SELECT scratchpadData.mode FROM off => RETURN; pointAt => RETURN; drawLin =>{SVScratchpadMonitor.NewMotion[controlPoint, NARROW[input.rest.first], scratchpadData]; }; drawRevo =>{SVScratchpadMonitor.NewMotion[controlPoint, NARROW[input.rest.first], scratchpadData]; }; ENDCASE => ERROR; }; $MOVESTART => { scratchpadData: ScratchpadData _ NARROW[self.data]; SELECT scratchpadData.mode FROM off => RETURN; pointAt => RETURN; drawLin =>{SVScratchpadMonitor.NewMotion[controlPoint, NARROW[input.rest.first], scratchpadData]}; drawRevo =>{SVScratchpadMonitor.NewMotion[controlPoint, NARROW[input.rest.first], scratchpadData]}; ENDCASE => ERROR; }; $MOVEEND => { scratchpadData: ScratchpadData _ NARROW[self.data]; SELECT scratchpadData.mode FROM off => RETURN; pointAt => RETURN; drawLin =>{ SVScratchpadMonitor.NewMotion[controlPoint, NARROW[input.rest.first], scratchpadData]; }; drawRevo =>{ SVScratchpadMonitor.NewMotion[controlPoint, NARROW[input.rest.first], scratchpadData]; }; ENDCASE => ERROR; }; $ERASE => { scratchpadData: ScratchpadData _ NARROW[self.data]; SELECT scratchpadData.mode FROM off => RETURN; pointAt => RETURN; drawLin =>{DeleteLinPoint[controlPoint, scratchpadData]; SVScratchpadUser.DrawSceneButton[self, scratchpadData.scratchViewerData, red, FALSE, FALSE]}; drawRevo =>{DeleteRevoPoint[controlPoint, scratchpadData]; SVScratchpadUser.DrawSceneButton[self, scratchpadData.scratchViewerData, red, FALSE, FALSE]}; ENDCASE => ERROR; }; $SPLICE => { scratchpadData: ScratchpadData _ NARROW[self.data]; SELECT scratchpadData.mode FROM off => RETURN; pointAt => RETURN; drawLin =>{SpliceLinPoint[controlPoint, scratchpadData]; SVScratchpadUser.DrawSceneButton[self, scratchpadData.scratchViewerData, red, FALSE, FALSE]}; drawRevo =>{SpliceRevoPoint[controlPoint, scratchpadData]; SVScratchpadUser.DrawSceneButton[self, scratchpadData.scratchViewerData, red, FALSE, FALSE]}; ENDCASE => ERROR; }; ENDCASE => ERROR; }; -- end is a mouse point }; -- end of InputNotify TestPoint: PROC [screenPoint2d: Point2d, scratchpadData: ScratchpadData] = TRUSTED { poly: Polygon; inOnOut: PointPolyClass; inOnOutRope: Rope.ROPE; testRope: Rope.ROPE; padPoint: Point2d; poly _ SVPolygon2d.PathToPolygon[scratchpadData.path]; padPoint _ SVPadGraphics.ScreenToPad[screenPoint2d, scratchpadData.origin]; inOnOut _ SVPolygon2d.BoysePointInPoly[padPoint, poly]; SELECT inOnOut FROM in => inOnOutRope _ "in"; on => inOnOutRope _ "on"; out => inOnOutRope _ "out"; ENDCASE => ERROR; testRope _ IO.PutFR["Point: [%g, %g] is %g poly.",[real[padPoint[1]]], [real[padPoint[2]]], [rope[inOnOutRope]]]; Feedback.AppendRaw[$Solidviews, testRope, oneLiner]; }; -- end of TestPoint AddLinPoint: PROC [screenPoint2d: Point2d, scratchpadData: ScratchpadData] = TRUSTED { area: REAL; poly: Polygon; areaRope: Rope.ROPE; IF scratchpadData.path.len = SVSweepGeometry.maxMeshLen THEN {ComplainTooManyLinPoints[]; RETURN}; scratchpadData.path _ SVPolygon2d.AddPathPoint[scratchpadData.path, SVPadGraphics.ScreenToPad[screenPoint2d, scratchpadData.origin]]; poly _ SVPolygon2d.PathToPolygon[scratchpadData.path]; area _ SVPolygon2d.SignedArea[poly]; areaRope _ IO.PutFR["Poly has area: %g",[real[area]]]; Feedback.AppendRaw[$Solidviews, areaRope, oneLiner]; }; -- end of AddLinPoint AddRevoPoint: PROC [screenPoint2d: Point2d, scratchpadData: ScratchpadData] = TRUSTED { <> area: REAL; poly: Polygon; areaRope: Rope.ROPE; p: Point2d; p _ SVPadGraphics.ScreenToPad[screenPoint2d, scratchpadData.origin]; IF p[1] < 0 THEN p[1] _ -p[1]; IF scratchpadData.path.len = SVSweepGeometry.maxLinesOfLat THEN {ComplainTooManyRevoPoints[]; RETURN}; scratchpadData.path _ SVPolygon2d.AddPathPoint[scratchpadData.path, p]; poly _ SVPolygon2d.PathToPolygon[scratchpadData.path]; <> area _ SVPolygon2d.SignedArea[poly]; areaRope _ IO.PutFR["Poly has area: %g",[real[area]]]; Feedback.AppendRaw[$Solidviews, areaRope, oneLiner]; }; -- end of AddRevoPoint MoveLinStart: PUBLIC PROC [screenPoint2d: Point2d, scratchpadData: ScratchpadData] = TRUSTED { newPoint, oldPoint: Point2d; index: NAT; success: BOOL; newPoint _ SVPadGraphics.ScreenToPad[screenPoint2d, scratchpadData.origin]; [oldPoint, index, success] _ PointClosestTo[newPoint, scratchpadData]; IF NOT success THEN RETURN; scratchpadData.index _ index; MoveLinPoint[screenPoint2d, scratchpadData]; }; MoveRevoStart: PUBLIC PROC [screenPoint2d: Point2d, scratchpadData: ScratchpadData] = TRUSTED { newPoint, oldPoint: Point2d; index: NAT; success: BOOL; newPoint _ SVPadGraphics.ScreenToPad[screenPoint2d, scratchpadData.origin]; IF newPoint[1] < 0 THEN newPoint[1] _ -newPoint[1]; [oldPoint, index, success] _ PointClosestTo[newPoint, scratchpadData]; IF NOT success THEN RETURN; scratchpadData.index _ index; MoveRevoPoint[screenPoint2d, scratchpadData]; }; MoveLinPoint: PUBLIC PROC [screenPoint2d: Point2d, scratchpadData: ScratchpadData] = TRUSTED { oldPoly, newPoly: Polygon; area: REAL; areaRope: Rope.ROPE; newPoint: Point2d; DoDrawNeighborHood: PROC [dc: Imager.Context] = TRUSTED { Imager.SetColor[dc, Imager.white]; SVPadGraphics.DrawPolyNeighborHood[dc, oldPoly, scratchpadData.index, scratchpadData.origin]; Imager.SetColor[dc, Imager.black]; SVPadGraphics.DrawPolyNeighborHood[dc, newPoly, scratchpadData.index, scratchpadData.origin]; }; IF scratchpadData.path.len = 0 THEN RETURN;-- no points to move newPoint _ SVPadGraphics.ScreenToPad[screenPoint2d, scratchpadData.origin]; oldPoly _ SVPolygon2d.PathToPolygon[scratchpadData.path]; scratchpadData.path[scratchpadData.index] _ newPoint; newPoly _ SVPolygon2d.PathToPolygon[scratchpadData.path]; SVScratchpadUser.Painter[DoDrawNeighborHood, scratchpadData.scratchViewerData]; <> area _ SVPolygon2d.SignedArea[newPoly]; areaRope _ IO.PutFR["Poly has area: %g",[real[area]]]; Feedback.AppendRaw[$Solidviews, areaRope, oneLiner]; }; -- end of MoveLinPoint MoveRevoPoint: PUBLIC PROC [screenPoint2d: Point2d, scratchpadData: ScratchpadData] = TRUSTED { <> oldPath, newPath: Path; <> <> <> newPoint: Point2d; DoDrawNeighborHood: PROC [dc: Imager.Context] = TRUSTED { Imager.SetColor[dc, Imager.white]; SVPadGraphics.DrawPathNeighborHood[dc, oldPath, scratchpadData.index+1, scratchpadData.origin]; SVPadGraphics.MirrorDrawPathNeighborHood[dc, oldPath, scratchpadData.index+1, scratchpadData.origin]; Imager.SetColor[dc, Imager.black]; SVPadGraphics.DrawPathNeighborHood[dc, newPath, scratchpadData.index+1, scratchpadData.origin]; SVPadGraphics.MirrorDrawPathNeighborHood[dc, newPath, scratchpadData.index+1, scratchpadData.origin]; }; IF scratchpadData.path.len = 0 THEN RETURN; -- no points to move newPoint _ SVPadGraphics.ScreenToPad[screenPoint2d, scratchpadData.origin]; IF newPoint[1] < 0 THEN newPoint[1] _ -newPoint[1]; oldPath _ SVPolygon2d.CreatePath[scratchpadData.path.len+2]; SVPolygon2d.PutPathPoint[oldPath, 0, [0, scratchpadData.path[0][2]]]; oldPath _ SVPolygon2d.PartPathGetsPartPath[scratchpadData.path, 0, oldPath, 1, scratchpadData.path.len]; SVPolygon2d.PutPathPoint[oldPath, scratchpadData.path.len+1, [0, scratchpadData.path[scratchpadData.path.len-1][2]]]; scratchpadData.path[scratchpadData.index] _ newPoint; newPath _ SVPolygon2d.CreatePath[scratchpadData.path.len+2]; SVPolygon2d.PutPathPoint[newPath, 0, [0, scratchpadData.path[0][2]]]; newPath _ SVPolygon2d.PartPathGetsPartPath[scratchpadData.path, 0, newPath, 1, scratchpadData.path.len]; SVPolygon2d.PutPathPoint[newPath, scratchpadData.path.len+1, [0, scratchpadData.path[scratchpadData.path.len-1][2]]]; SVScratchpadUser.Painter[DoDrawNeighborHood, scratchpadData.scratchViewerData]; <> <> <> <> <> <> <> <> }; -- end of MoveRevoPoint DeleteLinPoint: PROC [screenPoint2d: Point2d, scratchpadData: ScratchpadData] = TRUSTED { newPoint, oldPoint: Point2d; index: NAT; success: BOOL; newPoint _ SVPadGraphics.ScreenToPad[screenPoint2d, scratchpadData.origin]; [oldPoint, index, success] _ PointClosestTo[newPoint, scratchpadData]; IF NOT success THEN RETURN; scratchpadData.path _ SVPolygon2d.DeletePathPoint[scratchpadData.path, index]; }; DeleteRevoPoint: PROC [screenPoint2d: Point2d, scratchpadData: ScratchpadData] = TRUSTED { newPoint, oldPoint: Point2d; index: NAT; success: BOOL; newPoint _ SVPadGraphics.ScreenToPad[screenPoint2d, scratchpadData.origin]; IF newPoint[1] < 0 THEN newPoint[1] _ -newPoint[1]; [oldPoint, index, success] _ PointClosestTo[newPoint, scratchpadData]; IF NOT success THEN RETURN; scratchpadData.path _ SVPolygon2d.DeletePathPoint[scratchpadData.path, index]; }; ComplainTooManyLinPoints: PRIVATE PROC [] = { errorRope: Rope.ROPE; errorRope _ IO.PutFR["Can't have more than %g points in a linear sweep", [integer[SVSweepGeometry.maxMeshLen]]]; Feedback.AppendRaw[$Solidviews, errorRope, oneLiner]; }; ComplainTooManyRevoPoints: PRIVATE PROC [] = { errorRope: Rope.ROPE; errorRope _ IO.PutFR["Can't have more than %g points in a revolute sweep", [integer[SVSweepGeometry.maxLinesOfLat]]]; Feedback.AppendRaw[$Solidviews, errorRope, oneLiner]; }; SpliceLinPoint: PROC [screenPoint2d: Point2d, scratchpadData: ScratchpadData] = { index: NAT; newPoint: Point2d; success: BOOL; poly: Polygon; IF scratchpadData.path.len = SVSweepGeometry.maxMeshLen THEN {ComplainTooManyLinPoints[]; RETURN}; newPoint _ SVPadGraphics.ScreenToPad[screenPoint2d, scratchpadData.origin]; poly _ SVPolygon2d.PathToPolygon[scratchpadData.path]; [index, success] _ EdgeClosestToInPoly[newPoint, poly]; IF NOT success THEN RETURN;-- less than 2 points in path scratchpadData.path _ SVPolygon2d.SplicePathPoint[scratchpadData.path, newPoint, index]; }; -- end of SpliceLinPoint SpliceRevoPoint: PROC [screenPoint2d: Point2d, scratchpadData: ScratchpadData] = TRUSTED { index: INTEGER; newPoint: Point2d; success: BOOL; newPath: Path; IF scratchpadData.path.len = SVSweepGeometry.maxLinesOfLat THEN {ComplainTooManyRevoPoints[]; RETURN}; newPoint _ SVPadGraphics.ScreenToPad[screenPoint2d, scratchpadData.origin]; IF newPoint[1] < 0 THEN newPoint[1] _ -newPoint[1]; newPath _ SVPolygon2d.CreatePath[scratchpadData.path.len+2]; SVPolygon2d.PutPathPoint[newPath, 0, [0, scratchpadData.path[0][2]]]; newPath _ SVPolygon2d.PartPathGetsPartPath[scratchpadData.path, 0, newPath, 1, scratchpadData.path.len]; SVPolygon2d.PutPathPoint[newPath, scratchpadData.path.len+1, [0, scratchpadData.path[scratchpadData.path.len - 1][2]]]; [index, success] _ EdgeClosestToInPath[newPoint, newPath]; index _ index - 1; -- since we have added a point onto the path IF NOT success THEN RETURN; -- less than 2 points in path scratchpadData.path _ SVPolygon2d.SplicePathPoint[scratchpadData.path, newPoint, index]; }; -- end of SplicePoint PointClosestTo: PROC [target: Point2d, scratchpadData: ScratchpadData] RETURNS [oldPoint: Point2d, index: NAT, success: BOOL] = TRUSTED { <> leastDistance, thisDistance: REAL; index _ 0; IF scratchpadData.path.len = 0 THEN {success _ FALSE; RETURN}; success _ TRUE; oldPoint _ scratchpadData.path[0]; leastDistance _ DistanceSquared[target, oldPoint]; FOR i: NAT IN[1..scratchpadData.path.len-1] DO thisDistance _ DistanceSquared[scratchpadData.path[i], target]; IF thisDistance < leastDistance THEN { leastDistance _ thisDistance; oldPoint _ scratchpadData.path[i]; index _ i;}; ENDLOOP; }; DistanceSquared: PROC [p1, p2: Point2d] RETURNS [d: REAL] = TRUSTED { d _ (p1[1]-p2[1])*(p1[1]-p2[1]) + (p1[2]-p2[2])*(p1[2]-p2[2]); }; -- end of DistanceSquared Abs: PRIVATE PROC [r: REAL] RETURNS [REAL] = TRUSTED { RETURN[IF r >=0 THEN r ELSE -r]; }; -- end of Abs DistanceToMidpoint: PRIVATE PROC [pt, edgeVert1, edgeVert2: Point2d] RETURNS [d: REAL] = TRUSTED { <> midpoint: Point2d; midpointToPt: Vector2d; midpoint _ SVVector2d.Scale[SVVector2d.Add[edgeVert2, edgeVert1], 0.5]; midpointToPt _ SVVector2d.Sub[pt, midpoint]; d _ SVVector2d.MagnitudeSquared[midpointToPt]; }; -- end of DistanceToEdge DistanceToEdge: PRIVATE PROC [pt, edgeVert1, edgeVert2: Point2d] RETURNS [d: REAL] = TRUSTED { seg: TrigLineSeg _ SVLines2d.CreateTrigLineSeg[edgeVert1, edgeVert2]; d _ SVLines2d.DistanceSquaredPointToTrigLineSeg[pt, seg]; }; EdgeClosestToInPath: PROC [target: Point2d, path: Path] RETURNS [index: NAT, success: BOOL] = TRUSTED { <> leastDistance, thisDistance: REAL; fromPoint, toPoint: Point2d; IF path.len < 2 THEN {success _ FALSE; RETURN}; -- no edges success _ TRUE; fromPoint _ path[0]; toPoint _ path[1]; index _ 0; leastDistance _ DistanceToEdge[target, fromPoint, toPoint]; fromPoint _ toPoint; FOR i: NAT IN[2..path.len) DO toPoint _ path[i]; thisDistance _ DistanceToEdge[target, fromPoint, toPoint]; IF thisDistance < leastDistance THEN { leastDistance _ thisDistance; index _ i-1;}; fromPoint _ toPoint; ENDLOOP; }; EdgeClosestToInPoly: PROC [target: Point2d, poly: Polygon] RETURNS [index: NAT, success: BOOL] = TRUSTED { <> leastDistance, thisDistance: REAL; fromPoint, toPoint: Point2d; iPlusOne: NAT; IF poly.len < 2 THEN {success _ FALSE; RETURN}; -- no edges success _ TRUE; fromPoint _ poly[0]; toPoint _ poly[1]; index _ 0; leastDistance _ DistanceToEdge[target, fromPoint, toPoint]; fromPoint _ toPoint; FOR i: NAT IN[1..poly.len-1] DO-- i is the number of fromPoint iPlusOne _ IF i = poly.len - 1 THEN 0 ELSE i+1; toPoint _ poly[iPlusOne]; thisDistance _ DistanceToEdge[target, fromPoint, toPoint]; IF thisDistance < leastDistance THEN { leastDistance _ thisDistance; index _ i;}; fromPoint _ toPoint; ENDLOOP; }; Init[]; END.