Syntax Highlighing:
comments, key words, predefined symbols, class members & methods, functions & classes
#LincolnSchools Demonstration Control Script.
#
#Requirements:
# - TNTmips 7.0 (or later)
# - LincolnSchools layout
# - Lincoln Property Viewer Atlas DVD
#
#This script can only be run as a control script. To use this script, open the LincolnSchools
#layout. In the Layout Controls of Spatial Data Display, click Layout / Edit Control Script.
numeric schoolPrclScl = 50000;
numeric mouselocPrclScl = 15000;
numeric labelOffset = 30;
numeric schoolSymOffset = 25;
class GEOREF vecGeoref;
class POINT2D offset;
#FindPointInPoly
#
#pre:
#takes mouse location in map coordinates.
#vPoints and vPolys assumed to have same georef and be in same projection as point.
#
#post:
#returns 1 if point found in poly and places point in pointloc
#returns 0 if point not found in poly, and pointloc is unmodified.
func FindPointInPoly(
class POINT2D pointloc,
class VECTOR vPoints,
class VECTOR vPolys,
class POINT2D cursorpos)
{
numeric closepoly = FindClosestPoly(vPolys, cursorpos.x, cursorpos.y);
numeric i;
for(i=1; i<=vPoints.$info.NumPoints; i++) {
numeric polyForPoint = FindClosestPoly(vPolys, vPoints.Point[i].Internal.x, vPoints.Point[i].Internal.y);
if(polyForPoint == closepoly) {
pointloc.x = vPoints.Point[i].Internal.x;
pointloc.y = vPoints.Point[i].Internal.y;
return 1;
}
}
return 0;
}
func FindPointInPolyElemNum(
class VECTOR vPoints,
class VECTOR vPolys,
class POINT2D cursorpos)
{
numeric closepoly = FindClosestPoly(vPolys, cursorpos.x, cursorpos.y);
numeric i;
for(i=1; i<vPoints.$info.NumPoints; i++) {
numeric polyForPoint = FindClosestPoly(vPolys, vPoints.Point[i].Internal.x, vPoints.Point[i].Internal.y);
if(polyForPoint == closepoly) {
return i;
}
}
return -1;
}
proc OnInitialize ()
{
numeric SZ=5;
}
#getTriOppositeLength
#
#given a triangle with adjacent side length adj, opposite side length opp, finds
#the subtriangle whose adjacent side is adjLength and returns the length
#of the opposite side of that triangle.
func getTriOppositeLength(numeric adj, numeric opp, numeric outAdj) {
if(adj==0) return 0;
return outAdj * opp / adj;
}
#getBinaryOutcode
#
#returns the binary outcode of point p relative to rectangle r, as
#defined in the Cohen-Sutherland clipping algorithm.
func getBinaryOutcode(class POINT2D p, class RECT r) {
numeric opcode = 0;
if(p.x < r.x1) opcode = opcode | 1;
if(p.x > r.x2) opcode = opcode | 2;
if(p.y > r.y2) opcode = opcode | 4;
if(p.y < r.y1) opcode = opcode | 8;
return opcode;
}
#clipPoint
#
#For point a outside the view window, finds the intersection of the view
#window's extents with the line from the mouse pointer location to a.
#For a point inside the view window, returns the point location.
#
#pre: all input parameters are in screen coordinates. ext is the view window's
#extents in screen coordinates
#
#post: returned POINT2D is the location on the edge of the extents of
#the view window (or just the location of the point if already inside the view).
func class POINT2D clipPoint(class POINT2D p, class POINT2D mouseloc, class RECT ext) {
class POINT2D out = p;
numeric outcode = getBinaryOutcode(out, ext);
while(outcode != 0) {
class POINT2D temp = out;
if(outcode & 1 == 1) {
#clip left
temp.x = ext.x1;
temp.y = mouseloc.y + getTriOppositeLength(mouseloc.x - out.x, mouseloc.y - out.y, ext.x1 - mouseloc.x);
} else if(outcode & 2 == 2) {
#clip right
temp.x = ext.x2;
temp.y = mouseloc.y + getTriOppositeLength(mouseloc.x - out.x, mouseloc.y - out.y, ext.x2 - mouseloc.x);
} else if(outcode & 4 == 4) {
#clip bottom
temp.x = mouseloc.x + getTriOppositeLength(mouseloc.y - out.y, mouseloc.x - out.x, ext.y2 - mouseloc.y);
temp.y = ext.y2;
} else if(outcode & 8 == 8) {
#clip top
temp.x = mouseloc.x + getTriOppositeLength(mouseloc.y - out.y, mouseloc.x - out.x, ext.y1 - mouseloc.y);
temp.y = ext.y1;
}
out = temp;
outcode = getBinaryOutcode(out, ext);
}
return out;
}
func calcAngle(class POINT2D a, class POINT2D b) {
numeric x = b.x - a.x;
numeric y = b.y - a.y;
numeric angle = acos(x / sqrt(x^2 + y^2));
if(y < 0) return PI - angle;
return angle - PI;
}
proc drawAngledLine(class GC gc, numeric x, numeric y, numeric angle, numeric len) {
numeric a = len * cos(angle);
numeric b = len * sin(angle);
gc.MoveTo(x, y);
gc.DrawTo(x-a, y-b);
}
proc drawAngledPoint(class GC gc, numeric x, numeric y, numeric angle, numeric len) {
numeric a = len * cos(angle);
numeric b = len * sin(angle);
gc.DrawPoint(x-a, y-b);
}
func class POINT2D getAngledPoint(numeric x, numeric y, numeric angle, numeric len) {
class POINT2D pt;
pt.x = x - len * cos(angle);
pt.y = y - len * sin(angle);
return pt;
}
#drawParcel
#draw a parcel polygon and returns its extents.
#
#pre: tp is the transparm from layer to screen, and parcelPolyID is the polygon number of the
#parcel to draw.
func class RECT drawParcel(
class GC gc,
class TRANSPARM tp,
class VECTOR parcelVec,
numeric parcelPolyID)
{
array polyLines[2048]; #arbitrarily large-sized array
numeric numPolyLines = GetVectorPolyLineList(parcelVec, polyLines, parcelPolyID);
numeric i;
class RECT parcelExtents;
for(i = 1; i <= numPolyLines; i++) {
class POLYLINE curLine = GetVectorLine(parcelVec, polyLines[i]);
curLine.ConvertForward(tp);
parcelExtents.ExtendRect(curLine.ComputeExtents());
gc.DrawPolyLine2(curLine);
}
return parcelExtents;
}
# Function called when the cursor pauses triggering a datatip action event
func OnViewDataTipShowRequest(class GRE_VIEW view, class POINT2D mouseScrn, class TOOLTIP datatip)
{
view.RestoreAll();
class GC gc = CreateGCForDrawingArea(view.DrawingArea);
ActivateGC(gc);
gc.SetColor("white");
class STRING name = "Schools";
class GRE_LAYER_VECTOR curPtLayer = MainLayout.GetGroupByName("Schools").FirstLayer;
class GRE_LAYER_VECTOR curDistLayer = MainLayout.GetGroupByName("School Districts").FirstLayer;
class GRE_LAYER_VECTOR parcels = MainLayout.GetGroupByName("Overlays").GetLayerByName("Parcels");
class VECTOR parcelVec;
VectorLayerGetObject(parcels, parcelVec);
class TRANSPARM tpPrclToScrn = ViewGetTransLayerToScreen(view, parcels);
class POINT2D mousepoint;
#draw parcel underneath mouse pointer
mousepoint = TransPoint2D(mouseScrn, ViewGetTransViewToScreen(view, 1));
mousepoint = TransPoint2D(mousepoint, ViewGetTransMapToView(view, parcels.Projection, 1));
numeric closeParcel = FindClosestPoly(parcelVec, mousepoint.x, mousepoint.y);
if(closeParcel != 0 && view.CurrentMapScale < mouselocPrclScl) {
gc.SetLineWidth(2);
class RECT parcelExtents = drawParcel(
gc,
tpPrclToScrn,
parcelVec,
closeParcel);
class string parcelAddress = parcelVec.Poly[closeParcel].CA032904.SITUS_ADDR$;
gc.DrawTextSetHeightPixels(12);
numeric addressLen = gc.TextGetWidth(parcelAddress);
gc.SetColor("Lemon Chiffon");
gc.FillRect(parcelExtents.x2 + 10, parcelExtents.y2, addressLen, 12);
gc.DrawTextSetFont("Arial");
gc.DrawTextSimple(parcelAddress, parcelExtents.x2 + 10, parcelExtents.y2 + 11);
}
#draw school locations and parcels
class STRINGLIST parcelColors;
numeric iterNum=1;
for(iterNum = 1; curPtLayer != 0 && curDistLayer != 0; iterNum++) {
class VECTOR ptsVect, distVect;
VectorLayerGetObject(curPtLayer, ptsVect);
VectorLayerGetObject(curDistLayer, distVect);
class string styleObj = "STYLE";
gc.DrawUseStyleSubObject(_context.Filename, ptsVect.$info.Name, styleObj);
class POINT2D schoolLoc, mousepoint;
numeric pointElemNum;
mousepoint = TransPoint2D(mouseScrn, ViewGetTransViewToScreen(view, 1));
mousepoint = TransPoint2D(mousepoint, ViewGetTransMapToView(view, curDistLayer.Projection, 1));
if((pointElemNum = FindPointInPolyElemNum(ptsVect, distVect, mousepoint)) != -1) {
schoolLoc.x = ptsVect.Point[pointElemNum].Internal.x;
schoolLoc.y = ptsVect.Point[pointElemNum].Internal.y;
schoolLoc = TransPoint2D(schoolLoc, ViewGetTransMapToView(view, curDistLayer.Projection));
schoolLoc = TransPoint2D(schoolLoc, ViewGetTransViewToScreen(view));
class RECT extents;
numeric buf=5;
extents.x1 = buf; extents.y1 = buf; extents.x2 = view.width-buf; extents.y2 = view.height-buf;
class POINT2D newLocation = clipPoint(schoolLoc, mouseScrn, extents);
class TEXTSTYLE textStyle;
textStyle.Shadow = 1;
gc.TextStyle = textStyle;
gc.DrawTextSetColors("white", "black");
gc.DrawTextSetFont("Arial Black");
gc.DrawTextSetHeightPixels(12);
class string schoolName = ptsVect.Point[pointElemNum].SchoolName.Name$;
schoolName = schoolName.toUppercase();
numeric textWidth = gc.TextGetWidth(schoolName);
gc.DrawSetPointStyle("School");
if(newLocation.x != schoolLoc.x || newLocation.y != schoolLoc.y) {
gc.SetColor("white");
numeric angle = calcAngle(schoolLoc, mouseScrn);
gc.DrawArrow(newLocation.x, newLocation.y, angle * 180 / PI, 20, 20);
gc.SetLineWidth(3);
drawAngledLine(gc, newLocation.x, newLocation.y, angle, 40);
gc.SetLineWidth(1);
drawAngledPoint(gc, newLocation.x, newLocation.y, angle, 70);
class POINT2D textpos = getAngledPoint(newLocation.x, newLocation.y, angle, 70);
gc.DrawTextSimple(schoolName, textpos.x - textWidth/2, textpos.y + labelOffset);
} else {
if(view.CurrentMapScale < schoolPrclScl) {
class POINT2D schoolLocParcel = TransPoint2D(schoolLoc, ViewGetTransViewToScreen(view, 1));
schoolLocParcel = TransPoint2D(schoolLocParcel, ViewGetTransMapToView(view, parcels.Projection, 1));
numeric schoolPolyID = FindClosestPoly(parcelVec, schoolLocParcel.x, schoolLocParcel.y);
gc.DrawSetLineStyle("Parcel");
class RECT parcelExtents = drawParcel(gc, tpPrclToScrn, parcelVec, schoolPolyID);
class POINT2D screenCenter;
screenCenter.x = view.Width/2;
screenCenter.y = view.Height/2;
numeric yPointPos = parcelExtents.y2 + schoolSymOffset;
#gc.DrawSetPointStyle("School");
gc.DrawPoint(newLocation.x, yPointPos);
gc.DrawTextSimple(schoolName, newLocation.x - textWidth/2, yPointPos + labelOffset);
} else {
gc.DrawPoint(newLocation.x, newLocation.y);
gc.DrawTextSimple(schoolName, newLocation.x - textWidth / 2, newLocation.y + labelOffset);
}
}
}
curPtLayer = curPtLayer.NextLayer;
curDistLayer = curDistLayer.NextLayer;
}
return 1;
}