DIRECTORY Containers, CoordSys, Graphics, Icons, Imager, ImagerBridge, Interminal, IO, Menus, PadGraphics, Rope, Scratchpad2d, Scratchpad2dUser, SV2d, SVError, SVInterfaceTypes, SVModelTypes, SVLines2d, SVPolygon2d, SVScratchpadMonitor, SVVector2d, SweepGeometry, TIPUser, ViewerClasses, ViewerOps; Scratchpad2dImpl: CEDAR PROGRAM IMPORTS Containers, CoordSys, Imager, ImagerBridge, Icons, IO, Menus, PadGraphics, Scratchpad2dUser, SVLines2d, SVScratchpadMonitor, SVPolygon2d, TIPUser, SVError, SVVector2d, ViewerOps EXPORTS Scratchpad2d SHARES ViewerClasses = BEGIN CoordSystem: TYPE = SVModelTypes.CoordSystem; EditToolData: TYPE = SVInterfaceTypes.EditToolData; 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: Graphics.Context, whatChanged: REF ANY, clear: BOOL] = TRUSTED { scratchpadData: ScratchpadData; scratchViewerState: ScratchViewerData; IF whatChanged = NIL THEN {--we are being called by Window Manager scratchpadData _ NARROW[self.data]; Scratchpad2dUser.PlaceOrigin[self]; Scratchpad2dUser.DrawSceneButton[self, scratchpadData.scratchViewerData, red, FALSE, FALSE]; } ELSE { proc: ImagerProc; scratchViewerState _ NARROW[whatChanged]; scratchpadData _ NARROW[scratchViewerState.scratchpad.data]; proc _ scratchpadData.proc; ImagerBridge.SetViewFromGraphicsContext[scratchpadData.imager, context]; proc[scratchpadData.imager]; RETURN}; }; Init: PROC = { scratchpadClass: ViewerClasses.ViewerClass; scratchpadClass _ NEW[ViewerClasses.ViewerClassRec _ [ paint: ScratchpadPaint, notify: InputNotify, tipTable: TIPUser.InstantiateNewTIPTable["Scratchpad2d.TIP"] ]]; ViewerOps.RegisterViewerClass[$Scratchpad2d, 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 { 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: Scratchpad2dUser.EraseButton, clientData: scratchViewerData, documentation: "erase the scratchpad" ], line: 0 ]; Menus.AppendMenuEntry[ menu: padMenu, entry: Menus.CreateEntry[ name: "Normals", proc: Scratchpad2dUser.NormalsButton, clientData: scratchViewerData, documentation: "show normals to all current segments" ], line: 0 ]; Menus.AppendMenuEntry[ menu: padMenu, entry: Menus.CreateEntry[ name: "CrossHairs", proc: Scratchpad2dUser.CrossHairsButton, clientData: scratchViewerData, documentation: "draw crosshairs to show current origin" ], line: 0 ]; Menus.AppendMenuEntry[ menu: padMenu, entry: Menus.CreateEntry[ name: "NewLin", proc: Scratchpad2dUser.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: Scratchpad2dUser.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: Scratchpad2dUser.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: Scratchpad2dUser.CircleButton, clientData: scratchViewerData, documentation: "draw a circle centered on the origin" ], line: 0 ]; Menus.AppendMenuEntry[ menu: padMenu, entry: Menus.CreateEntry[ name: "Slice", proc: Scratchpad2dUser.DrawSliceButton, clientData: scratchViewerData, documentation: "Draw the current slice from the selected viewer" ], line: 1 ]; Menus.AppendMenuEntry[ menu: padMenu, entry: Menus.CreateEntry[ name: "Interpress", proc: Scratchpad2dUser.HardcopyButton, clientData: scratchViewerData, documentation: "Make an interpress document of this scene" ], line: 1 ]; Menus.AppendMenuEntry[ menu: padMenu, entry: Menus.CreateEntry[ name: "SliceRepeat", proc: Scratchpad2dUser.SliceRepeatButton, clientData: scratchViewerData, documentation: "Draw the current slice. Don't recompute tree" ], line: 1 ]; scratchViewerData.outer _ Containers.Create[[ name: "Scratchpad2d", 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 _ CoordSys.CreateRoot["WORLD"]; scratchpadData.origin _ [200, 200]; -- will be updated every window manager paint scratchpadData.path _ SVPolygon2d.CreatePath[IntMax[SweepGeometry.maxMeshLen, SweepGeometry.maxLinesOfLat]]; scratchpadData.mode _ off; scratchpadData.scratchViewerData _ scratchViewerData; scratchpadData.imager _ Imager.Create[$LFDisplay]; Imager.ScaleT[scratchpadData.imager, 3.527778e-4]; -- units in screen dots scratchViewerData.scratchpad _ ViewerOps.CreateViewer[ flavor: $Scratchpad2d, 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; p: Imager.Pair; p _ Imager.Transform[Imager.Invert[context.state.T], [mousePlace.mouseX, mousePlace.mouseY]]; controlPoint[1] _ p.x; controlPoint[2] _ p.y; 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]; Scratchpad2dUser.DrawSceneButton[self, scratchpadData.scratchViewerData, red, FALSE, FALSE]; }; drawRevo =>{ AddRevoPoint[controlPoint, scratchpadData]; Scratchpad2dUser.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]; Scratchpad2dUser.DrawSceneButton[self, scratchpadData.scratchViewerData, red, FALSE, FALSE]}; drawRevo =>{DeleteRevoPoint[controlPoint, scratchpadData]; Scratchpad2dUser.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]; Scratchpad2dUser.DrawSceneButton[self, scratchpadData.scratchViewerData, red, FALSE, FALSE]}; drawRevo =>{SpliceRevoPoint[controlPoint, scratchpadData]; Scratchpad2dUser.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 _ PadGraphics.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]]]; SVError.Append[testRope, TRUE, TRUE]; }; -- end of TestPoint AddLinPoint: PROC [screenPoint2d: Point2d, scratchpadData: ScratchpadData] = TRUSTED { area: REAL; poly: Polygon; areaRope: Rope.ROPE; IF scratchpadData.path.len = SweepGeometry.maxMeshLen THEN {ComplainTooManyLinPoints[]; RETURN}; scratchpadData.path _ SVPolygon2d.AddPathPoint[scratchpadData.path, PadGraphics.ScreenToPad[screenPoint2d, scratchpadData.origin]]; poly _ SVPolygon2d.PathToPolygon[scratchpadData.path]; area _ SVPolygon2d.SignedArea[poly]; areaRope _ IO.PutFR["Poly has area: %g",[real[area]]]; SVError.Append[areaRope, TRUE, TRUE]; }; -- end of AddLinPoint AddRevoPoint: PROC [screenPoint2d: Point2d, scratchpadData: ScratchpadData] = TRUSTED { area: REAL; poly: Polygon; areaRope: Rope.ROPE; p: Point2d; p _ PadGraphics.ScreenToPad[screenPoint2d, scratchpadData.origin]; IF p[1] < 0 THEN p[1] _ -p[1]; IF scratchpadData.path.len = SweepGeometry.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]]]; SVError.Append[areaRope, TRUE, TRUE]; }; -- end of AddRevoPoint MoveLinStart: PUBLIC PROC [screenPoint2d: Point2d, scratchpadData: ScratchpadData] = TRUSTED { newPoint, oldPoint: Point2d; index: NAT; success: BOOL; newPoint _ PadGraphics.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 _ PadGraphics.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]; PadGraphics.DrawPolyNeighborHood[dc, oldPoly, scratchpadData.index, scratchpadData.origin]; Imager.SetColor[dc, Imager.black]; PadGraphics.DrawPolyNeighborHood[dc, newPoly, scratchpadData.index, scratchpadData.origin]; }; IF scratchpadData.path.len = 0 THEN RETURN;-- no points to move newPoint _ PadGraphics.ScreenToPad[screenPoint2d, scratchpadData.origin]; oldPoly _ SVPolygon2d.PathToPolygon[scratchpadData.path]; scratchpadData.path[scratchpadData.index] _ newPoint; newPoly _ SVPolygon2d.PathToPolygon[scratchpadData.path]; Scratchpad2dUser.Painter[DoDrawNeighborHood, scratchpadData.scratchViewerData]; area _ SVPolygon2d.SignedArea[newPoly]; areaRope _ IO.PutFR["Poly has area: %g",[real[area]]]; SVError.Append[areaRope, TRUE, TRUE]; }; -- 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]; PadGraphics.DrawPathNeighborHood[dc, oldPath, scratchpadData.index+1, scratchpadData.origin]; PadGraphics.MirrorDrawPathNeighborHood[dc, oldPath, scratchpadData.index+1, scratchpadData.origin]; Imager.SetColor[dc, Imager.black]; PadGraphics.DrawPathNeighborHood[dc, newPath, scratchpadData.index+1, scratchpadData.origin]; PadGraphics.MirrorDrawPathNeighborHood[dc, newPath, scratchpadData.index+1, scratchpadData.origin]; }; IF scratchpadData.path.len = 0 THEN RETURN; -- no points to move newPoint _ PadGraphics.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]]]; Scratchpad2dUser.Painter[DoDrawNeighborHood, scratchpadData.scratchViewerData]; }; -- end of MoveRevoPoint DeleteLinPoint: PROC [screenPoint2d: Point2d, scratchpadData: ScratchpadData] = TRUSTED { newPoint, oldPoint: Point2d; index: NAT; success: BOOL; newPoint _ PadGraphics.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 _ PadGraphics.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 [] = TRUSTED { errorRope: Rope.ROPE; errorRope _ IO.PutFR["Can't have more than %g points in a linear sweep", [integer[SweepGeometry.maxMeshLen]]]; SVError.Append[errorRope, TRUE, TRUE]; }; ComplainTooManyRevoPoints: PRIVATE PROC [] = TRUSTED { errorRope: Rope.ROPE; errorRope _ IO.PutFR["Can't have more than %g points in a revolute sweep", [integer[SweepGeometry.maxLinesOfLat]]]; SVError.Append[errorRope, TRUE, TRUE]; }; SpliceLinPoint: PROC [screenPoint2d: Point2d, scratchpadData: ScratchpadData] = TRUSTED { index: NAT; newPoint: Point2d; success: BOOL; poly: Polygon; IF scratchpadData.path.len = SweepGeometry.maxMeshLen THEN {ComplainTooManyLinPoints[]; RETURN}; newPoint _ PadGraphics.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 = SweepGeometry.maxLinesOfLat THEN {ComplainTooManyRevoPoints[]; RETURN}; newPoint _ PadGraphics.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. ΦFile: Scratchpad2dImpl.mesa Author: Eric Bier on July 2, 1983 1:44 pm Copyright c 1984 by Xerox Corporation. All rights reserved. Last edited by Bier on July 30, 1984 10:41:41 pm PDT Contents: Definitions for a new type of viewer designed to support 2d editting. Most (or perhaps all) three dimensional shapes in the SolidViews three dimensional illustrator will be constructable from a set of 2d entities, hence, the Scratchpad2d window may be a principle source of shape creation until that time when shapes can be drawn on planes which are in the 3d scene. whatChanged is a ScratchViewerData self is a Scratchpad I register the new Scratchpad class. Parent is the SolidViewer tool. Here we create the Container and the top menu which looks like this: CLOSE GROW <-> DESTROY SAVE NEWLINE ERASE Erase Normals CrossHairs NewLin NewRevo TestPoints Circle construct the menu CrossHairs NewLin NewRevo TestPoints now make the outer container Now build the draw section. Self is a scratchpad Self is a Scratchpad2d this was a fix to float conversion Scratchpad2dUser.DrawLin[self, scratchpadData.scratchViewerData, red, FALSE, FALSE]; Scratchpad2dUser.DrawRevo[self, scratchpadData.scratchViewerData, red, FALSE, FALSE]; Revo points must have positive x in scratchpad coords. Print current poly area. Print out current poly area revo points must have positive x in scratchpad coords area: REAL; poly: Polygon; areaRope: Rope.ROPE; Print out current poly area poly _ SVPolygon2d.CreatePoly[scratchpadData.path.len+2]; poly[0] _ [0, scratchpadData.path[0][2]]; poly[scratchpadData.path.len + 1] _ [0, scratchpadData.path[scratchpadData.path.len -1][2]]; poly _ SVPolygon2d.PartPolyGetsPartPath[scratchpadData.path, 0, poly, 1, scratchpadData.path.len]; area _ SVPolygon2d.SignedArea[poly]; areaRope _ IO.PutFR["Poly has area: %g",[real[area]]]; SVError.Append[areaRope, TRUE, TRUE]; Returns success _ FALSE if there are no points. Use distance squared to midpoint as a heuristic for being close to an edge. Index will be 0 if edge between 0 and 1 is closest and poly.len - 2 if edge between poly.len - 2 and poly.len - 1 is closest, etc. Index will be 0 if edge between 0 and 1 is closest and poly.len - 1 if edge between poly.len - 1 and 0 is closest, etc. Κ – "cedar" style˜Iheadšœ™Iprocšœ)™)Jšœ Οmœ1™˜>Lšœ˜—Lšœ˜š  œžœžœžœžœžœ˜?Lšžœžœžœžœ˜Lšœ˜—L˜š  œžœžœ=žœ+žœ˜•Lšœ™LšœD™DLšœ)™)Lšœ9™9L˜Lšœ˜Lšœ˜Lšœ'žœ˜ALšœ!žœŸ,˜eL˜Lšœ™L˜Lšœ˜L˜šœ˜Lšœ˜šœ˜Lšœ˜Lšœ#˜#Lšœ˜Lšœ%˜%Lšœ˜—Lšœ˜Lšœ˜——L˜˜šœ˜Lšœ˜šœ˜Lšœ˜Lšœ%˜%Lšœ˜Lšœ5˜5Lšœ˜—Lšœ˜Lšœ˜L˜—Lšœ$™$L˜šœ˜Lšœ˜šœ˜Lšœ˜Lšœ(˜(Lšœ˜Lšœ7˜7Lšœ˜—L˜Lšœ˜—L˜šœ˜Lšœ˜šœ˜Lšœ˜Lšœ$˜$Lšœ˜Lšœ>˜>Lšœ˜—L˜Lšœ˜—L˜šœ˜Lšœ˜šœ˜Lšœ˜Lšœ%˜%Lšœ˜Lšœ@˜@Lšœ˜—L˜Lšœ˜—L˜šœ˜Lšœ˜šœ˜Lšœ˜Lšœ(˜(Lšœ˜LšœB˜BLšœ˜—L˜Lšœ˜—L˜šœ˜Lšœ˜šœ˜Lšœ˜Lšœ$˜$Lšœ˜Lšœ5˜5Lšœ˜—L˜Lšœ˜L˜—šœ˜Lšœ˜šœ˜Lšœ˜Lšœ'˜'Lšœ˜Lšœ@˜@Lšœ˜—L˜Lšœ˜L˜—šœ˜Lšœ˜šœ˜Lšœ˜Lšœ&˜&Lšœ˜Lšœ:˜:Lšœ˜—L˜Lšœ˜L˜—šœ˜Lšœ˜šœ˜Lšœ˜Lšœ)˜)Lšœ˜Lšœ>˜>Lšœ˜—L˜Lšœ˜—L˜Lšœ™L˜šœ-˜-Lšœ˜Lšœ˜Lšœžœ˜ LšœŸ(˜6Lšœ žœ˜Lšœ2˜2Lšœ˜—Lšœ.˜.L˜Lšœ%˜%Lšœ$Ÿ-˜QLšœl˜lLšœ˜Lšœ5˜5Lšœ2˜2LšœK˜KL˜Lšœ™L˜šœ6˜6Lšœ˜šœ˜Lšœ ˜ Lšœ$˜$Lšœ˜LšœŸA˜`LšœŸ˜2Lšœ ž˜Lšœ˜—Lšœ˜—LšœN˜NLšœN˜NLšœV˜VL˜Lšœ4˜4Lšœ$˜$Lšœ*˜*LšœŸ˜—L˜š œžœžœžœ˜Lšœ žœ˜Lšœ"˜"Lšœ2˜2šžœžœžœž˜.Lšœ@˜@Lšžœžœ˜&Lšœ˜Lšœ"˜"Lšœ ˜ —Lšžœ˜Lšœ˜—Lšœ˜š  œžœžœžœžœ˜ELšœ>˜>LšœŸ˜—Lšœ˜š œžœžœžœžœžœžœ˜6Lšžœžœžœžœ˜ LšœŸ ˜—Lšœ˜š  œžœžœ%žœžœžœ˜bLšœK™KLšœ˜Lšœ˜LšœG˜GLšœ,˜,Lšœ.˜.LšœŸ˜—Lšœ˜š  œžœžœ%žœžœžœ˜^LšœE˜ELšœ9˜9Lšœ˜—Lšœ˜š  œžœžœ žœ žœžœ˜gLšœ‚™‚Lšœžœ˜"Lšœ˜Lš žœžœ žœžœŸ ˜;Lšœ žœ˜Lšœ˜Lšœ˜Lšœ ˜ Lšœ;˜;Lšœ˜šžœžœžœž˜Lšœ˜Lšœ;˜;Lšžœžœ˜&Lšœ˜Lšœ˜Lšœ˜—Lšžœ˜Lšœ˜—Lšœ˜š  œžœ"žœ žœ žœžœ˜jLšœw™wLšœžœ˜"Lšœ˜Lšœ žœ˜Lš žœžœ žœžœŸ ˜;Lšœ žœ˜Lšœ˜Lšœ˜Lšœ ˜ Lšœ;˜;Lšœ˜šžœžœžœžŸ˜>Lšœ žœžœžœ˜/Lšœ˜Lšœ;˜;šžœžœ˜&Lšœ˜Lšœ ˜ —Lšœ˜—Lšžœ˜Lšœ˜—Lšœ˜Lšœ˜L˜Lšžœ˜—…—R\r;