DIRECTORY Containers, CoordSys, Graphics, GraphicsColor, Icons, Interminal, IO, Matrix3d, Menus, MessageWindow, PadGraphics, Rope, Scratchpad2d, Scratchpad2dUser, SV2d, SVLines2d, SVPolygon2d, SVScratchpadMonitor, SVVector2d, SweepGeometry, TIPUser, ViewerClasses, ViewerOps; Scratchpad2dImpl: CEDAR PROGRAM IMPORTS Containers, CoordSys, Graphics, Icons, IO, Matrix3d, Menus, MessageWindow, PadGraphics, Scratchpad2dUser, SVLines2d, SVScratchpadMonitor, SVPolygon2d, TIPUser, SVVector2d, ViewerOps EXPORTS Scratchpad2d SHARES ViewerClasses = BEGIN CoordSystem: TYPE = REF CoordSysObj; CoordSysObj: TYPE = CoordSys.CoordSysObj; Path: TYPE = REF PathObj; PathObj: TYPE = SV2d.PathObj; PointPolyClass: TYPE = SVPolygon2d.PointPolyClass; Polygon: TYPE = REF PolygonObj; PolygonObj: TYPE = SV2d.PolygonObj; TrigLineSeg: TYPE = SV2d.TrigLineSeg; Vector2d: TYPE = SVVector2d.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 = Scratchpad2dUser.ScratchViewerDataObj; TextSectionData: TYPE = REF TextSectionDataObj; TextSectionDataObj: TYPE = Scratchpad2dUser.TextSectionDataObj; ScratchpadData: TYPE = REF ScratchpadDataObj; ScratchpadDataObj: TYPE = Scratchpad2dUser.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.DrawScene[self, scratchpadData.scratchViewerData, red, FALSE, FALSE]; } ELSE { proc: PROC [Graphics.Context]; scratchViewerState _ NARROW[whatChanged]; scratchpadData _ NARROW[scratchViewerState.scratchpad.data]; proc _ scratchpadData.proc; proc[context]; 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] 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[1]; Menus.AppendMenuEntry[ menu: padMenu, entry: Menus.CreateEntry[ name: "Erase", proc: Scratchpad2dUser.Erase, clientData: scratchViewerData, documentation: "erase the scratchpad" ] ]; Menus.AppendMenuEntry[ menu: padMenu, entry: Menus.CreateEntry[ name: "Normals", proc: Scratchpad2dUser.Normals, clientData: scratchViewerData, documentation: "show normals to all current segments" ] ]; Menus.AppendMenuEntry[ menu: padMenu, entry: Menus.CreateEntry[ name: "CrossHairs", proc: Scratchpad2dUser.CrossHairs, clientData: scratchViewerData, documentation: "draw crosshairs to show current origin" ] ]; Menus.AppendMenuEntry[ menu: padMenu, entry: Menus.CreateEntry[ name: "NewLin", proc: Scratchpad2dUser.NewLin, clientData: scratchViewerData, documentation: "prepare to draw the outline of a linear sweep" ] ]; Menus.AppendMenuEntry[ menu: padMenu, entry: Menus.CreateEntry[ name: "NewRevo", proc: Scratchpad2dUser.NewRevo, clientData: scratchViewerData, documentation: "prepare to draw the outline of a revolute sweep" ] ]; Menus.AppendMenuEntry[ menu: padMenu, entry: Menus.CreateEntry[ name: "TestPoints", proc: Scratchpad2dUser.TestPoints, clientData: scratchViewerData, documentation: "prepare to perform in-on-out test on mouse points" ] ]; Menus.AppendMenuEntry[ menu: padMenu, entry: Menus.CreateEntry[ name: "Circle", proc: Scratchpad2dUser.Circle, clientData: scratchViewerData, documentation: "draw a circle centered on the origin" ] ]; 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] ]]; world _ CoordSys.CreateCoordSys["WORLD", Matrix3d.Identity[],NIL]; 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; 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; }; Point2d: TYPE = Matrix3d.Point2d; 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]; controlPoint[1] _ mousePlace.mouseX; -- this is a fix to float conversion 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]; Scratchpad2dUser.DrawLin[self, scratchpadData.scratchViewerData, red, FALSE, FALSE]; }; drawRevo =>{ AddRevoPoint[controlPoint, scratchpadData]; Scratchpad2dUser.DrawRevo[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 =>{Scratchpad2dUser.DrawLin[self, scratchpadData.scratchViewerData, red, FALSE, FALSE]}; drawRevo =>{Scratchpad2dUser.DrawRevo[self, scratchpadData.scratchViewerData, red, FALSE, FALSE]}; ENDCASE => ERROR; }; $ERASE => { scratchpadData: ScratchpadData _ NARROW[self.data]; SELECT scratchpadData.mode FROM off => RETURN; pointAt => RETURN; drawLin =>{DeleteLinPoint[controlPoint, scratchpadData]; Scratchpad2dUser.DrawLin[self, scratchpadData.scratchViewerData, red, FALSE, FALSE]}; drawRevo =>{DeleteRevoPoint[controlPoint, scratchpadData]; Scratchpad2dUser.DrawRevo[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.DrawLin[self, scratchpadData.scratchViewerData, red, FALSE, FALSE]}; drawRevo =>{SpliceRevoPoint[controlPoint, scratchpadData]; Scratchpad2dUser.DrawRevo[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; testStream: IO.STREAM; 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; testStream _ IO.CreateOutputStreamToRope[]; testStream.PutF["Point: [%g, %g] is %g poly.",[real[padPoint[1]]], [real[padPoint[2]]], [rope[inOnOutRope]]]; testRope _ IO.GetOutputStreamRope[testStream]; MessageWindow.Append[testRope, TRUE]; }; -- end of TestPoint AddLinPoint: PROC [screenPoint2d: Point2d, scratchpadData: ScratchpadData] = TRUSTED { area: REAL; poly: Polygon; areaRope: Rope.ROPE; areaStream: IO.STREAM; 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]; areaStream _ IO.CreateOutputStreamToRope[]; areaStream.PutF["Poly has area: %g",[real[area]]]; areaRope _ IO.GetOutputStreamRope[areaStream]; MessageWindow.Append[areaRope, TRUE]; }; -- end of AddLinPoint AddRevoPoint: PROC [screenPoint2d: Point2d, scratchpadData: ScratchpadData] = TRUSTED { area: REAL; poly: Polygon; areaRope: Rope.ROPE; areaStream: IO.STREAM; 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]; areaStream _ IO.CreateOutputStreamToRope[]; areaStream.PutF["Poly has area: %g",[real[area]]]; areaRope _ IO.GetOutputStreamRope[areaStream]; MessageWindow.Append[areaRope, 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; areaStream: IO.STREAM; newPoint: Point2d; DoDrawNeighborHood: PROC [dc: Graphics.Context] = TRUSTED { Graphics.SetColor[dc, GraphicsColor.white]; PadGraphics.DrawPolyNeighborHood[dc, oldPoly, scratchpadData.index, scratchpadData.origin]; Graphics.SetColor[dc, GraphicsColor.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]; areaStream _ IO.CreateOutputStreamToRope[]; areaStream.PutF["Poly has area: %g",[real[area]]]; areaRope _ IO.GetOutputStreamRope[areaStream]; MessageWindow.Append[areaRope, TRUE]; }; -- end of MoveLinPoint MoveRevoPoint: PUBLIC PROC [screenPoint2d: Point2d, scratchpadData: ScratchpadData] = TRUSTED { oldPath, newPath: Path; newPoint: Point2d; DoDrawNeighborHood: PROC [dc: Graphics.Context] = TRUSTED { Graphics.SetColor[dc, GraphicsColor.white]; PadGraphics.DrawPathNeighborHood[dc, oldPath, scratchpadData.index+1, scratchpadData.origin]; PadGraphics.MirrorDrawPathNeighborHood[dc, oldPath, scratchpadData.index+1, scratchpadData.origin]; Graphics.SetColor[dc, GraphicsColor.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 { errorStream: IO.STREAM; errorRope: Rope.ROPE; errorStream _ IO.CreateOutputStreamToRope[]; errorStream.PutF["Can't have more than %g points in a linear sweep", [integer[SweepGeometry.maxMeshLen]]]; errorRope _ IO.GetOutputStreamRope[errorStream]; MessageWindow.Append[errorRope, TRUE]; }; ComplainTooManyRevoPoints: PRIVATE PROC [] = TRUSTED { errorStream: IO.STREAM; errorRope: Rope.ROPE; errorStream _ IO.CreateOutputStreamToRope[]; errorStream.PutF["Can't have more than %g points in a revolute sweep", [integer[SweepGeometry.maxLinesOfLat]]]; errorRope _ IO.GetOutputStreamRope[errorStream]; MessageWindow.Append[errorRope, 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.Sum[edgeVert2, edgeVert1], 0.5]; midpointToPt _ SVVector2d.Difference[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 Last edited by Bier on July 2, 1983 2:53 pm 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 NewLin NewRevo TestPoints 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 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; areaStream: IO.STREAM; 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]; areaStream _ IO.CreateOutputStreamToRope[]; areaStream.PutF["Poly has area: %g",[real[area]]]; areaRope _ IO.GetOutputStreamRope[areaStream]; MessageWindow.Append[areaRope, 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šœ)™)Lšœ+™+Lšœϊ™ϊL˜šΟk ˜ 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šœœ˜2Lšœ œœ ˜Lšœ œ˜#Lšœ œ˜%Lšœ œ˜%Lšœœ˜$L˜Lšœ œΟc˜7Lšœ œž!˜;Lšœ œž+˜GL˜L˜Lšœœœ˜3Lšœœ)˜CLšœœœ˜/Lšœœ'˜?L˜Lšœœœ˜-Lšœœ&˜=L˜šΟnœœœ*˜DLš œ œœ œœ˜.Lšœ"™"Lšœ™Lšœ˜Lšœ'˜'šœœœž'˜BLšœœ ˜#Lšœ#˜#LšœHœœ˜VLšœ˜—šœ˜Lšœœ˜Lšœœ˜)Lšœœ%˜˜>Lšœ˜—Lšœ˜š Ÿœœœœœœ˜?Lšœœœœ˜Lšœ˜—L˜š Ÿœœœ!œ+œ˜yLšœ™LšœD™DLšœ)™)Lšœ™L˜Lšœ˜Lšœ˜Lšœ'œ˜ALšœ!œž,˜eL˜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šœ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šœB˜BLšœ˜—Lšœ˜—L˜šœ˜Lšœ˜šœ˜Lšœ˜Lšœ˜Lšœ˜Lšœ5˜5Lšœ˜—Lšœ˜—L˜Lšœ™L˜šœ-˜-Lšœ˜Lšœ˜Lšœœ˜ Lšœž(˜6Lšœ œ˜Lšœ2˜2Lšœ˜—L˜Lšœ=œ˜BLšœ$ž-˜QLšœl˜lLšœ˜Lšœ5˜5L˜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šœ3˜3Lšœ.˜.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šœ˜—…—Pͺo—