<<>> <> <> <> <> DIRECTORY ApproxSymTab, Ascii, Atom, Browser2D, Buttons, Commander, CommanderOps, Containers, Convert, Draw2d, FileNames, FS, IO, Icons, Imager, ImagerColor, ImagerPath, Menus, MessageWindow, Process, Real, Rope, Rules, TEditDocument, TEditSelectionOps, TiogaMenuOps, CensusFileReader, Vector, ViewerClasses, ViewerEvents, ViewerTools, ViewerOps; CensusMapImpl: CEDAR MONITOR LOCKS common USING common: Common IMPORTS ApproxSymTab, Ascii, Atom, Browser2D, Buttons, Containers, Convert, Commander, CommanderOps, Draw2d, FileNames, FS, IO, Icons, Imager, ImagerPath, ImagerColor, Menus, MessageWindow, Process, Rope, Rules, TEditSelectionOps, TiogaMenuOps, CensusFileReader, Vector, ViewerEvents, ViewerTools, ViewerOps = BEGIN mA: CARD ¬ 10; mS: CARD ¬ 10000; showOriginalRecord: BOOL ¬ FALSE; nameIndex: BOOL ¬ TRUE; ItemData: TYPE = REF ItemDataRec; ItemDataRec: TYPE = RECORD [ fileName: Rope.ROPE, filePosition: INT, fromX: REAL, fromY: REAL, toX: REAL, toY: REAL, color: ImagerColor.Color, name: REF TEXT ]; Common: TYPE = REF CommonRec; CommonRec: TYPE = MONITORED RECORD [ banner: Rope.ROPE ¬ NIL, streetNames: ApproxSymTab.Ref, browser: Browser2D.BrowserHandle, outer: Containers.Container, menu: Menus.Menu, nameInput, addressInput, showChoice: ViewerClasses.Viewer, lastNameInput: Rope.ROPE, guardMapDestroy: BOOL ¬ TRUE, --changes from TRUE to FALSE once after initial load matches: EntryDoubleList, matchesCurrent: EntryDoubleList, matchesTail: EntryDoubleList, statusChange: CONDITION, matcherStatus: MatcherStatus ¬ notRunning, alwaysButton, ifNecessaryButton, neverButton: Buttons.Button, always: BOOL ¬ FALSE, ifNecessary: BOOL ¬ TRUE, never: BOOL ¬ FALSE ]; EntryDoubleList: TYPE = REF EntryDoubleListRec; EntryDoubleListRec: TYPE = RECORD[ entry: ApproxSymTab.Entry, next, prev: EntryDoubleList ¬ NIL ]; MatcherStatus: TYPE = {notRunning, computing, matchDelivered, computeNextMatch, abort}; BoundingBox: Browser2D.ItemBoundingBoxProc = { data: ItemData ¬ NARROW[self.data]; {OPEN data; box.lowerLeft.x ¬ MIN[fromX, toX]; box.upperRight.x ¬ MAX[fromX, toX]; box.lowerLeft.y ¬ MIN[fromY, toY]; box.upperRight.y ¬ MAX[fromY, toY]; }; }; DistanceTo: Browser2D.ItemDistanceToProc = { id: ItemData ¬ NARROW[self.data]; o: Vector.VEC ¬ [id.fromX, id.fromY]; b: Vector.VEC ¬ [id.toX - id.fromX, id.toY - id.fromY]; p: Vector.VEC ¬ Vector.Sub[location, o]; bb: REAL ¬ Vector.Dot[b,b]; t: REAL; IF bb = 0.0 THEN RETURN[Vector.Mag[p]]; t ¬ Vector.Dot[p,b]/bb; IF t <= 0.0 THEN RETURN[Vector.Mag[p]]; IF t >= 1.0 THEN RETURN[Vector.Mag[Vector.Sub[p,b]]]; RETURN[Vector.Mag[Vector.Sub[p, Vector.Mul[b,t]]]]; }; SelectionNotify: Browser2D.ItemSelectionNotifyProc = { data: ItemData ¬ NARROW[self.data]; common: Common ¬ NARROW[commonData]; scanItems: LIST OF Browser2D.Item; viewer: ViewerClasses.Viewer; IF how = userSelected THEN { IF common.streetNames # NIL THEN { scanItems ¬ NARROW[common.streetNames.FetchBest[Rope.FromRefText[data.name], NIL, 0].entry.value]; UNTIL scanItems = NIL DO common.browser.SelectItem[scanItems.first]; scanItems ¬ scanItems.rest; ENDLOOP; }; IF data.name # NIL THEN common.browser.SetMessageWindow[Rope.FromRefText[data.name], 1, 100]; IF showOriginalRecord THEN { viewer ¬ TiogaMenuOps.Open[data.fileName]; TEditSelectionOps.ShowGivenPositionRange[viewer, feedback, data.filePosition, data.filePosition + 300, TRUE, FALSE]; }; }; }; Paint: Browser2D.ItemPaintProc = { data: ItemData ¬ NARROW[self.data]; traj: Imager.Trajectory; context.SetStrokeEnd[square]; IF how # normal THEN { traj ¬ ImagerPath.MoveTo[ [data.fromX, data.fromY] ]; traj ¬ traj.LineTo[ [data.toX, data.toY] ]; SELECT how FROM userSelected, clientSelected =>{context.SetStrokeWidth[2.4]; context.SetColor[data.color]}; deSelect => {context.SetStrokeWidth[2.4]; context.SetColor[Imager.white]}; ENDCASE; context.MaskStrokeTrajectory[traj]; }; SELECT how FROM normal, deSelect => { context.SetStrokeWidth[0.0]; context.SetColor[data.color]; --context.MaskStrokeTrajectory[traj]; Draw2d.Line[context, [data.fromX, data.fromY], [data.toX, data.toY], solid, zip] }; userSelected, clientSelected =>{ context.SetStrokeWidth[.7]; context.SetColor[red]; context.MaskStrokeTrajectory[traj]; }; ENDCASE; }; mapFeatures: Browser2D.ItemClass ¬ NEW[Browser2D.ItemClassRec ¬ [ paint: Paint, selectionNotify: SelectionNotify, boundingBox: BoundingBox, distanceTo: DistanceTo ]]; <> Strip: PROC [in: Rope.ROPE] RETURNS [out: Rope.ROPE] ~ { start: INT ¬ Rope.SkipOver[in, 0, " "]; end: INT ¬ Rope.Length[in] - 1; IF start > end THEN RETURN[NIL]; DO IF in.Fetch[end] # ' THEN RETURN[Rope.Substr[in, start, end-start+1]]; end ¬ end - 1; ENDLOOP; }; CensusMap: Commander.CommandProc = { argv: CommanderOps.ArgumentVector ¬ CommanderOps.Parse[cmd ! CommanderOps.Failed => {msg ¬ errorMsg; GO TO errorExit}]; common: Common ¬ NEW[CommonRec]; {OPEN common; fileName: Rope.ROPE ¬ NIL; item: Browser2D.Item; items: LIST OF Browser2D.Item ¬ NIL; enclosingBox: Browser2D.BoundingBox ¬ [[Real.LargestNumber, Real.LargestNumber], [- Real.LargestNumber, - Real.LargestNumber]]; tB: Buttons.Button; rule: Rules.Rule; PerLine: CensusFileReader.PerLineProc ~ { itemData: ItemData ¬ NEW[ItemDataRec ¬ [ fileName: fileName, filePosition: filePosition[], fromX: - fromLong[], fromY: fromLat[], toX: - toLong[], toY: toLat[], color: ColorCode[nonStCo[]] ]]; FindName: PROC [a, b, c, d: Rope.ROPE] RETURNS [REF TEXT] ~ { found: BOOL; entry: ApproxSymTab.Entry; already: LIST OF Browser2D.Item; sa: Rope.ROPE ¬ Strip[a]; root: Rope.ROPE ¬ Strip[b]; sc: Rope.ROPE ¬ Strip[c]; sd: Rope.ROPE ¬ Strip[d]; full: Rope.ROPE ¬ IF sa # NIL THEN Rope.Concat[sa, " "] ELSE NIL; full ¬ Rope.Concat[full, root]; full ¬ IF sc # NIL THEN Rope.Cat[full, " ", sc] ELSE full; full ¬ IF sd # NIL THEN Rope.Cat[full, " ", sd] ELSE full; [found, entry] ¬ streetNames.FetchBest[full, NIL, 0]; IF found THEN { already ¬ NARROW[entry.value]; already.rest ¬ CONS[item, already.rest]; RETURN[entry.key]; }; already ¬ LIST[item]; [ , entry] ¬ streetNames.Insert[full, already]; RETURN[entry.key]; }; IF (itemData.toX # 0) OR (itemData.toY # 0) OR (itemData.fromX # 0) OR (itemData.fromY # 0) THEN { item ¬ NEW[Browser2D.ItemRec ¬ [class: mapFeatures, data: itemData]]; IF (itemData.toX = 0) AND (itemData.toY = 0) THEN {itemData.toX ¬ itemData.fromX - 1.0; itemData.toY ¬ itemData.fromY - 1.0}; IF (itemData.fromX = 0) AND (itemData.fromY = 0) THEN {itemData.fromX ¬ itemData.toX - 1.0; itemData.fromY ¬ itemData.toY - 1.0}; IF nameIndex THEN itemData.name ¬ FindName[stPreDir[], stName[], stType[], stSufDir[]]; items ¬ CONS[item, items]; enclosingBox ¬ Browser2D.LeastCommonBoundingBox[enclosingBox, BoundingBox[item, NIL]]; }; }; IF nameIndex THEN streetNames ¬ ApproxSymTab.Create[]; IF argv.argc <= 1 THEN {msg ¬ "Usage: CensusMap map1 map2 . . ."; GO TO errorExit}; FOR i: NAT IN [1..argv.argc) DO shortName: Rope.ROPE ¬ argv[i]; longName: Rope.ROPE; IF NOT Rope.Match["*.cmap*", shortName] THEN shortName ¬ Rope.Concat[shortName, ".cmap"]; longName ¬ Rope.Concat["/censusmaps/", shortName]; fileName ¬ FileNames.FileWithSearchRules[ root: longName, defaultExtension: "cmap", searchRules: NIL].fullPath; IF fileName = NIL THEN {msg ¬ Rope.Cat["Could not find: ", longName, "\n Try: pma /censusmaps/ -vux:/net/eich/noir/greene/cmaps/"]; GO TO errorExit}; banner ¬ Rope.Cat[banner, ", ", argv[i]]; CensusFileReader.GetDIME[fileName, PerLine]; ENDLOOP; browser ¬ Browser2D.Create[enclosingBox, 50.0, mapIcon, Rope.Concat["Map: ", Rope.Substr[banner,2]], common, BrowserDestroyed]; UNTIL items = NIL DO browser.AddItem[items.first]; items ¬ items.rest; ENDLOOP; browser.CenterEverything[]; UnguardMapDestroy[common]; IF NOT nameIndex THEN RETURN; common.menu ¬ Menus.CreateMenu[]; Menus.AppendMenuEntry[common.menu, Menus.CreateEntry["BestMatch", BestMatch, common]]; Menus.AppendMenuEntry[common.menu, Menus.CreateEntry["NextMatch", NextMatch, common]]; Menus.AppendMenuEntry[common.menu, Menus.CreateEntry["PrevMatch", PrevMatch, common]]; Menus.AppendMenuEntry[common.menu, Menus.CreateEntry["ShowStreetOnMap", ShowStreetOnMap, common]]; Menus.AppendMenuEntry[common.menu, Menus.CreateEntry["ShowAddressOnStreet", ShowAddressOnStreet, common]]; common.outer ¬ Containers.Create[[ name: Rope.Concat["Index: ", Rope.Substr[banner, 2]], openHeight: 105, icon: indexIcon, menu: common.menu, scrollable: FALSE ]]; common.outer.props ¬ Atom.PutPropOnList[common.outer.props, $common, common]; common.showChoice ¬ ViewerTools.MakeNewTextViewer[[ data: "> Punch 'BestMatch' and street name will appear here. Punch 'NextMatch' for more streets. <", parent: common.outer, wx: 20, wy: 5, wh: 15, ww: 600, scrollable: FALSE, border: FALSE]]; rule ¬ Rules.Create[ info: [ wx: 0, wy: 25, wh: 2, ww: common.outer.cw, parent: common.outer ] ]; Containers.ChildXBound[common.outer, rule]; tB ¬ Buttons.Create[ info: [name: "Street Name:", wx: 10, wy: 30, wh: 15, parent: common.outer, border: FALSE], proc: ForceName, clientData: common]; common.nameInput ¬ ViewerTools.MakeNewTextViewer[[ data: "> Misspell a substring of the desired street here. <", parent: common.outer, wx: tB.wx + tB.ww + 5, wy: tB.wy, wh: 15, ww: 310, scrollable: FALSE, border: FALSE]]; tB ¬ Buttons.Create[ info: [name: "Address:", wx: common.nameInput.wx + common.nameInput.ww + 5, wy: common.nameInput.wy, wh: 15, parent: common.outer, border: FALSE], proc: ForceAddress, clientData: common]; common.addressInput ¬ ViewerTools.MakeNewTextViewer[[ data: "> Enter an integer here. <", parent: common.outer, wx: tB.wx + tB.ww + 5, wy: tB.wy, wh: 15, ww: 200, scrollable: FALSE, border: FALSE]]; tB ¬ Buttons.Create[ info: [name: "Selection Centering on Map:", wx: 10, wy: 55, wh: 15, parent: common.outer, border: FALSE], proc: ToggleCentering, clientData: common]; tB ¬ common.alwaysButton ¬ Buttons.Create[ info: [ name: "Always", parent: common.outer, wx: tB.wx + tB.ww + 10, wy: tB.wy, wh: 15, scrollable: FALSE, border: TRUE], proc: SetAlways, clientData: common]; tB ¬ common.ifNecessaryButton ¬ Buttons.Create[ info: [ name: "If Necessary", parent: common.outer, wx: tB.wx + tB.ww + 10, wy: tB.wy, wh: 15, scrollable: FALSE, border: TRUE], proc: SetIfNecessary, clientData: common]; tB ¬ common.neverButton ¬ Buttons.Create[ info: [ name: "Never", parent: common.outer, wx: tB.wx + tB.ww + 10, wy: tB.wy, wh: 15, scrollable: FALSE, border: TRUE], proc: SetNever, clientData: common]; ColorCenteringButtons[common]; [] ¬ ViewerEvents.RegisterEventProc[IndexDestroyed, destroy, common.outer]; } EXITS errorExit => result ¬ $Failure; }; ColorCenteringButtons: PROC [common: Common] ~ { OPEN common; Buttons.SetDisplayStyle[alwaysButton, IF always THEN $WhiteOnBlack ELSE $BlackOnWhite]; Buttons.SetDisplayStyle[ifNecessaryButton, IF ifNecessary THEN $WhiteOnBlack ELSE $BlackOnWhite]; Buttons.SetDisplayStyle[neverButton, IF never THEN $WhiteOnBlack ELSE $BlackOnWhite]; }; IndexDestroyed: ViewerEvents.EventProc ~ { common: Common; IF event # destroy THEN RETURN; common ¬ NARROW[Atom.GetPropFromList[viewer.props, $common]]; IF common # NIL THEN IndexDestroyedLocked[common]; }; IndexDestroyedLocked: ENTRY PROC [common: Common] ~ { OPEN common; ENABLE UNWIND => NULL; UNTIL matcherStatus = notRunning DO matcherStatus ¬ abort; BROADCAST statusChange; WAIT statusChange; ENDLOOP; ApproxSymTab.Destroy[streetNames]; streetNames ¬ NIL; outer ¬ NIL; menu ¬ NIL; nameInput ¬ NIL; addressInput ¬ NIL; showChoice ¬ NIL; }; BrowserDestroyed: Browser2D.DestroyProc ~ { IF commonData = NIL THEN RETURN; BrowserDestroyedLocked[NARROW[commonData]]; }; BrowserDestroyedLocked: ENTRY PROC [common: Common] ~ { ENABLE UNWIND => NULL; UNTIL NOT common.guardMapDestroy DO WAIT common.statusChange ENDLOOP; common.browser ¬ NIL; }; UnguardMapDestroy: ENTRY PROC [common: Common] ~ { common.guardMapDestroy ¬ FALSE; BROADCAST common.statusChange; }; ForceName: Buttons.ButtonProc ~ { common: Common ¬ NARROW[clientData]; ViewerTools.SetSelection[common.nameInput]; }; ForceAddress: Buttons.ButtonProc ~ { common: Common ¬ NARROW[clientData]; ViewerTools.SetSelection[common.addressInput]; }; ToggleCentering: Buttons.ButtonProc ~ { common: Common ¬ NARROW[clientData]; ToggleCenteringLocked[common, mouseButton]; }; ToggleCenteringLocked: ENTRY PROC[common: Common, mouseButton: ViewerClasses.MouseButton] ~ { OPEN common; save: BOOL; IF mouseButton = blue THEN { save ¬ never; never ¬ ifNecessary; ifNecessary ¬ always; always ¬ save; } ELSE IF mouseButton = red THEN { save ¬ always; always ¬ ifNecessary; ifNecessary ¬ never; never ¬ save }; ColorCenteringButtons[common]; }; SetAlways: Buttons.ButtonProc ~ { common: Common ¬ NARROW[clientData]; SetAlwaysLocked[common]; }; SetAlwaysLocked: ENTRY PROC[common: Common] ~ { OPEN common; always ¬ TRUE; ifNecessary¬ FALSE; never ¬ FALSE; ColorCenteringButtons[common]; }; SetIfNecessary: Buttons.ButtonProc ~ { common: Common ¬ NARROW[clientData]; SetIfNecessaryLocked[common]; }; SetIfNecessaryLocked: ENTRY PROC[common: Common] ~ { OPEN common; always ¬ FALSE; ifNecessary¬ TRUE; never ¬ FALSE; ColorCenteringButtons[common]; }; SetNever: Buttons.ButtonProc ~ { common: Common ¬ NARROW[clientData]; SetNeverLocked[common]; }; SetNeverLocked: ENTRY PROC[common: Common] ~ { OPEN common; always ¬ FALSE; ifNecessary¬ FALSE; never ¬ TRUE; ColorCenteringButtons[common]; }; HasNameChanged: PROC [common: Common] RETURNS [changed: BOOL] ~ { new: Rope.ROPE ¬ ForceRopeUpper[ViewerTools.GetContents[common.nameInput]]; RETURN[Rope.Compare[new, common.lastNameInput] # equal]; }; BestMatch: Menus.ClickProc ~ { common: Common ¬ NARROW[clientData]; BestMatchLocked[common]; }; BestMatchLocked: ENTRY PROC [common: Common] ~ { ENABLE UNWIND => NULL; BestMatchCore[common]; }; BestMatchCore: INTERNAL PROC [common: Common] ~ { OPEN common; IF NOT HasNameChanged[common] THEN { matchesCurrent ¬ matches; UpdateShowChoice[common]; } ELSE { lastNameInput ¬ ForceRopeUpper[ViewerTools.GetContents[common.nameInput]]; matches ¬ matchesCurrent ¬ matchesTail ¬ NIL; UNTIL matcherStatus = notRunning DO matcherStatus ¬ abort; BROADCAST statusChange; WAIT statusChange ENDLOOP; matcherStatus ¬ computeNextMatch; TRUSTED{Process.Detach[FORK NearMatch[common]]}; UNTIL (matcherStatus = matchDelivered) OR (matcherStatus = notRunning) DO WAIT statusChange ENDLOOP; IF matcherStatus = matchDelivered THEN { matchesCurrent ¬ matches; UpdateShowChoice[common]; }; }; }; ForceRopeUpper: PROC [in: Rope.ROPE] RETURNS [out: Rope.ROPE] ~ { ForceCharUpper: Rope.TranslatorType ~ {RETURN[Ascii.Upper[old]]}; out ¬ Rope.Translate[base: in, translator: ForceCharUpper]; }; NextMatch: Menus.ClickProc ~ { common: Common ¬ NARROW[clientData]; NextMatchLocked[common]; }; NextMatchLocked: ENTRY PROC [common: Common] ~ { OPEN common; ENABLE UNWIND => NULL; possibleNext: EntryDoubleList; IF HasNameChanged[common] THEN {BestMatchCore[common]; RETURN}; possibleNext ¬ matchesCurrent.next; IF possibleNext # NIL THEN { matchesCurrent ¬ possibleNext; UpdateShowChoice[common]; } ELSE { IF matcherStatus = notRunning THEN RETURN; matcherStatus ¬ computeNextMatch; BROADCAST statusChange; UNTIL (matcherStatus = matchDelivered) OR (matcherStatus = notRunning) DO WAIT statusChange ENDLOOP; IF matcherStatus = matchDelivered THEN { matchesCurrent ¬ matchesCurrent.next; UpdateShowChoice[common]; }; }; }; PrevMatch: Menus.ClickProc ~ { common: Common ¬ NARROW[clientData]; PrevMatchLocked[common]; }; PrevMatchLocked: ENTRY PROC [common: Common] ~ { OPEN common; ENABLE UNWIND => NULL; IF matchesCurrent.prev # NIL THEN { matchesCurrent ¬ matchesCurrent.prev; UpdateShowChoice[common]; }; }; NearMatch: ENTRY PROC [common: Common] ~ { OPEN common; DeliverMatchAction: INTERNAL ApproxSymTab.EachEntryAction ~ { newNode: EntryDoubleList ¬ NEW[EntryDoubleListRec ¬ [entry: entry, next: NIL]]; IF matchesTail = NIL THEN { matches ¬ newNode; newNode.prev ¬ NIL; } ELSE { matchesTail.next ¬ newNode; newNode.prev ¬ matchesTail; }; matchesTail ¬ newNode; matcherStatus ¬ matchDelivered; BROADCAST statusChange; UNTIL (matcherStatus = computeNextMatch) OR (matcherStatus = abort) DO LanguageDeficiencyWait[common]; ENDLOOP; RETURN[matcherStatus = abort] --quit? }; LanguageDeficiencyWait: INTERNAL PROC [common: Common] ~ { WAIT common.statusChange; }; streetNames.FetchAll[lastNameInput, DeliverMatchAction, mA, NIL, mS]; matcherStatus ¬ notRunning; BROADCAST statusChange; }; UpdateShowChoice: PROC [common: Common] ~ { OPEN common; IF matchesCurrent = NIL THEN RETURN; ViewerTools.SetContents[showChoice, Rope.FromRefText[matchesCurrent.entry.key]]; ViewerOps.BlinkViewer[showChoice]; }; ShowStreetOnMap: Menus.ClickProc ~ { IF clientData = NIL THEN RETURN; ShowStreetOnMapLocked[NARROW[clientData]]; }; ShowStreetOnMapLocked: ENTRY PROC [common: Common] ~ { scanItems: LIST OF Browser2D.Item; moved: BOOL ¬ FALSE; IF common.browser = NIL THEN RETURN; IF HasNameChanged[common] THEN BestMatchCore[common]; IF common.matchesCurrent # NIL THEN { common.browser.ClearAllSelections[]; scanItems ¬ NARROW[common.matchesCurrent.entry.value]; UNTIL scanItems = NIL DO common.browser.SelectItem[scanItems.first]; scanItems ¬ scanItems.rest; ENDLOOP; common.browser.SetMessageWindow[Rope.FromRefText[common.matchesCurrent.entry.key], 1, 100]; IF NOT common.never THEN { moved ¬ common.browser.CenterSelections[[120.0, 120.0], [0.0, 0.0], common.always]; }; IF NOT moved THEN common.browser.BlinkSelections[3, 200]; }; }; ShowAddressOnStreet: Menus.ClickProc ~ { IF clientData = NIL THEN RETURN; ShowAddressOnStreetLocked[NARROW[clientData]]; }; ShowAddressOnStreetLocked: ENTRY PROC [common: Common] ~ { failureMessage: Rope.ROPE; { moved: BOOLEAN ¬ FALSE; addressRequested: Rope.ROPE ¬ ViewerTools.GetContents[common.addressInput]; addressInt: INT ¬ Convert.IntFromRope[addressRequested ! Convert.Error => {failureMessage ¬ Rope.Cat["Could not interpret ", addressRequested, " as an integer"]; GOTO Failure; }]; scanItems: LIST OF Browser2D.Item; currentFileName: Rope.ROPE; currentFileStream: IO.STREAM ¬ NIL; rightSide: BOOLEAN ¬ FALSE; segment: ItemData; distanceOnSegment: REAL ¬ 0; readyToShow: BOOL ¬ FALSE; CheckForHit: CensusFileReader.PerLineProc ~ { leftLow: INT ¬ Convert.IntFromRope[leftAdd1[] ! Convert.Error => GOTO Flush]; leftHigh: INT ¬ Convert.IntFromRope[leftAdd2[] ! Convert.Error => GOTO Flush]; rightLow: INT ¬ Convert.IntFromRope[rgtAdd1[] ! Convert.Error => GOTO Flush]; rightHigh: INT ¬ Convert.IntFromRope[rgtAdd2[] ! Convert.Error => GOTO Flush]; leftValid: BOOL ¬ (leftLow # 0) OR (rightLow # 0); rightValid: BOOL ¬ (rightLow # 0) OR (rightHigh # 0); low, high: INT; IF NOT (leftValid OR rightValid) THEN RETURN; IF leftValid AND NOT rightValid THEN { rightSide ¬ FALSE; low ¬ leftLow; high ¬ leftHigh; }; IF rightValid AND NOT leftValid THEN { rightSide ¬ TRUE; low ¬ rightLow; high ¬ rightHigh; }; IF rightValid AND leftValid THEN { rightSide ¬ (addressInt MOD 2) = (rightHigh MOD 2); IF rightSide THEN { low ¬ rightLow; high ¬ rightHigh; } ELSE { low ¬ leftLow; high ¬ leftHigh; }; }; IF addressInt < low OR addressInt > high THEN RETURN; distanceOnSegment ¬ IF high = low THEN 0 ELSE (addressInt - low*1.0) / (high - low); readyToShow ¬ TRUE; EXITS Flush => NULL; }; IF common.browser = NIL THEN RETURN; IF HasNameChanged[common] THEN BestMatchCore[common]; IF common.matchesCurrent = NIL THEN {failureMessage ¬ "Street not found"; GOTO Failure}; scanItems ¬ NARROW[common.matchesCurrent.entry.value]; UNTIL scanItems = NIL DO segment ¬ NARROW[scanItems.first.data]; IF Rope.Compare[segment.fileName, currentFileName] # equal THEN { currentFileName ¬ segment.fileName; IF currentFileStream # NIL THEN IO.Close[currentFileStream]; currentFileStream ¬ FS.StreamOpen[fileName: currentFileName, streamOptions: options]; }; CensusFileReader.GetDIMERecord[currentFileStream, segment.filePosition, CheckForHit]; IF readyToShow THEN { o: Vector.VEC ¬ [segment.fromX, segment.fromY]; b: Vector.VEC ¬ [segment.toX - segment.fromX, segment.toY - segment.fromY]; onTheStreet: Vector.VEC ¬ Vector.Add[o, Vector.Mul[b, distanceOnSegment]]; justOffTheStreet: Vector.VEC ¬ Vector.Add[onTheStreet, Vector.Mul[Vector.Unit[Vector.Normal[b]], IF rightSide THEN -2.5 ELSE 2.5] ]; newItemData: LocateItemData ¬ NEW[LocateItemDataRec ¬ [x: justOffTheStreet.x , y: justOffTheStreet.y]]; newItem: Browser2D.Item ¬ NEW[Browser2D.ItemRec ¬ [data: newItemData, class: locatedPoints]]; common.browser.ClearAllSelections[]; common.browser.AddItem[newItem, TRUE]; common.browser.SelectItem[newItem]; IF NOT common.never THEN { moved ¬ common.browser.CenterSelections[[120.0, 120.0], [0.0, 0.0], common.always]; }; common.browser.BlinkSelections[IF moved THEN 3 ELSE 20, 200]; common.browser.SelectItem[scanItems.first]; RETURN; }; scanItems ¬ scanItems.rest; ENDLOOP; failureMessage ¬ "Could not interpolate number on street"; GOTO Failure; EXITS Failure => { MessageWindow.Clear[]; MessageWindow.Append[failureMessage]; MessageWindow.Blink[] }; }}; LocateItemData: TYPE = REF LocateItemDataRec; LocateItemDataRec: TYPE = RECORD [x, y: REAL]; LocateBoundingBox: Browser2D.ItemBoundingBoxProc = { data: LocateItemData ¬ NARROW[self.data]; {OPEN data; box.lowerLeft.x ¬ x; box.upperRight.x ¬ x; box.lowerLeft.y ¬ y; box.upperRight.y ¬ y; }; }; LocatePaint: Browser2D.ItemPaintProc = { data: LocateItemData ¬ NARROW[self.data]; traj: Imager.Trajectory; traj ¬ ImagerPath.MoveTo[ [data.x, data.y] ]; traj ¬ traj.LineTo[ [data.x, data.y] ]; context.SetStrokeEnd[round]; SELECT how FROM normal => {context.SetStrokeWidth[.8]; context.SetColor[Imager.black]}; userSelected, clientSelected =>{context.SetStrokeWidth[3.0]; context.SetColor[red]}; deSelect => {context.SetStrokeWidth[3.0]; context.SetColor[Imager.white]}; ENDCASE; context.MaskStrokeTrajectory[traj]; IF how = deSelect THEN { context.SetStrokeWidth[.8]; context.SetColor[Imager.black]; context.MaskStrokeTrajectory[traj]}; }; locatedPoints: Browser2D.ItemClass ¬ NEW[Browser2D.ItemClassRec ¬ [ paint: LocatePaint, boundingBox: LocateBoundingBox ]]; ColorCode: PROC [code: Rope.ROPE] RETURNS [color: ImagerColor.Color] ~ { c: CHAR ¬ code.Fetch[0]; RETURN[SELECT c FROM '1 => table[1], '2 => table[2], '3 => table[3], '4 => table[4], ENDCASE => Imager.black]; --roads and walkways }; options: FS.StreamOptions ¬ FS.defaultStreamOptions; mapIcon: Icons.IconFlavor = Icons.NewIconFromFile["CensusMap.icons", 1]; indexIcon: Icons.IconFlavor = Icons.NewIconFromFile["CensusMap.icons", 0]; red: Imager.Color ¬ ImagerColor.ColorFromHSV[.75, 1.0, 1.0]; table: ARRAY [1..4] OF Imager.Color; table[1] ¬ ImagerColor.ColorFromHSV[.05, 1.0, 1.0]; --orange table[2] ¬ ImagerColor.ColorFromHSV[.65, .75, 1.0]; --blue table[3] ¬ ImagerColor.ColorFromHSV[.15 ,1.0, 1.0]; --yellow table[4] ¬ ImagerColor.ColorFromHSV[.32 ,1.0, 1.0]; --green Commander.Register[key: "CensusMap", proc: CensusMap, doc: "Show/Search Census Dime/GBF File"]; options[tiogaRead] ¬ FALSE; END.