schools.sml

  Download

More scripts: Enhanced Data Tip

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;
}