TNTmips

HOME

FREE PRODUCTS
  TNTlite
  TNTatlas
  TNTsim3D

DOWNLOADS
  Release Version
  Development Version
  FTP
  Language Kits
  Sample Geodata
  Reseller Resources
  Promotional

DOCUMENTATION
  Tutorials
  Technical Guides
  Quick Guides

SITE MAP


roads_Profile.sml

See other examples and scripts with DataTips and GraphTips ...


#
# This script is meant to be run as a Display control script
#
# Assumptions:
# In the group there are two layers:
# Layer 1: DEM
# Layer 2: Overlaying vector lines
#
# Purpose:
# The script generates graphical image tip displaying a plotted
# profile of the nearest line, using the DEM values for elevation.
#
# TODO:
# If the extents of the nearest line (for which the graph tip is 
# generated) is beyond the extents of the view window, then the
# offset value must be adjusted.
#
class GRDEVICE_MEM_RGB24 imagedev;
class GRDEVICE_MEM_BINARY maskdev;
class GC gc;

class GRE_GROUP group;
class GRE_LAYER_VECTOR vectorLayer;
class GRE_LAYER_RASTER rasterLayer;
class VECTOR lineVector;
class RASTER dem;
class GEOREF vecGeoref;
class TRANSPARM objToMap;

numeric minz, maxz;
numeric leftGraphOffset, bottomGraphOffset=20, rightGraphOffset=5, topGraphOffset=15;
numeric fontHeight = 12;
string message$;

# Initialize the image device
proc OnInitialize ()
{
	imagedev.Create(192, 256);
	maskdev.Create(192, 256);
	maskdev.ClearAll();
}

proc OnLayoutDrawEnd (
   class GRE_LAYOUT layout,
   class GRE_VIEW view
   ) {
	group = layout.GetGroupByName("ImageMaps");
	rasterLayer = group.FirstLayer;
	DispGetRasterFromLayer(dem, rasterLayer);

	vectorLayer = group.LastLayer;
	DispGetVectorFromLayer(lineVector, vectorLayer);
	vecGeoref = GetLastUsedGeorefObject(lineVector);

	class TRANSPARM mapTrans;
	mapTrans.InputProjection = vectorLayer.Projection;
	mapTrans.OutputProjection = rasterLayer.Projection;

#	message$ = "RasterLayer: " + rasterLayer.Name + " \n" + "VectorLayer: " + vectorLayer.Name;
#	PopupMessage(message$);
   }

# Compute the distance between two points
func computeDistance(class POINT2D p1, class POINT2D p2)
{
	return sqrt((p2.x-p1.x)^2 + (p2.y-p1.y)^2);
}

# Determine if the given lin, col is within the raster extents
func isPointInRaster(numeric lin, numeric col)
{
	if (lin<1 || col<1 || lin>NumLins(dem) || col>NumCols(dem)) return 0;
	return 1;
}

# Get the z value
func computeElevation(class POINT2D p)
{
	p = mapTrans.ConvertPoint2DFwd(p);  # convert from vector map coordinates to raster map coordinates

	local class POINT2D obj = MapToObject(GetLastUsedGeorefObject(dem), p.x, p.y, dem);
	obj.x = obj.x + .5; # center of cell
	obj.y = obj.y + .5; # center of cell


	local numeric demValue;
	if(isPointInRaster(obj.y, obj.x)) demValue = dem[obj.y, obj.x];	# y for line, x for column
	else	demValue = null;
	return demValue;
}

# Construct the graph line, x dimension is line distance y is elevation
func class POLYLINE constructGraphLine(class POLYLINE origLine)
{
	local class POLYLINE newLine;
	local class POINT2D tmp;

#	origLine.ConvertForward(mapTrans);

	local numeric i;
	local numeric distance=0;
	local numeric elevation = computeElevation(origLine.GetVertex(0));
	tmp.x = distance;
	tmp.y = elevation;
	newLine.AppendVertex(tmp);

	for i=1 to origLine.GetNumPoints()-1
	{
		distance += computeDistance(origLine.GetVertex(i-1), origLine.GetVertex(i));
		elevation = computeElevation(origLine.GetVertex(i));

		tmp.x = distance;
		tmp.y = elevation;
		newLine.AppendVertex(tmp);
	}
	return newLine;
}

# Determine if the value given is a null value
func isNull(numeric value)
{
	if (IsNull(value)) return 1;
	return value == NullValue(dem);
}

# Get the width from the appropriate drawing device
func getHeight()
{
	return imagedev.GetHeight();
}

# Get the width from the appropriate drawing device
func getWidth()
{
	return imagedev.GetWidth();
}

# Create the GC here using the appropriate drawing device (gc is global)
proc createGC()
{
	if (gc == 0) gc = imagedev.CreateGC();
}

# draw the axes for the graph
proc drawGraphAxes(class POLYLINE graphLine)
{
	# make a greyish-blue background
	local class COLOR textColor;
	gc.DrawTextSetColors(textColor);
	gc.SetColorRGB(255, 255, 255);
	gc.FillRect(0, 0, getWidth(), getHeight());
	gc.SetColorRGB(0, 0, 0);
   gc.DrawRect(0,0, getWidth() - 1, getHeight() - 1);

	# Get the minimum and maximum z values
	minz=9999999; maxz=-9999999;
	local numeric i=0;
	for i=0 to graphLine.GetNumPoints()-1
	{
		local numeric z = graphLine.GetVertex(i).y;
		if (z < minz) minz = z;
		if (z > maxz) maxz = z;
	}

	local string min$ = sprintf("%d", minz);
	local string max$ = sprintf("%d", maxz);
	if (maxz==-9999999) max$ = "null";
	if (minz==9999999) min$ = "null";

	# Draw graph axes
	local numeric size = gc.TextGetWidth(max$);
	leftGraphOffset = size + 5;
	if (maxz == minz) max$ = "";
	local array numeric graphx[3], graphy[3];
	graphx[1] = leftGraphOffset;
	graphy[1] = topGraphOffset;
	graphx[2] = leftGraphOffset;
	graphy[2] = getHeight() - bottomGraphOffset;
	graphx[3] = getWidth() - rightGraphOffset;
	graphy[3] = graphy[2];
	gc.DrawPolyLine(graphx, graphy, 3);

	# Draw text for coordinate and elevation axis labels
	gc.DrawTextSetFont("ARIAL");
	gc.DrawTextSetHeightPixels(fontHeight);

	# draw y axis labels
	gc.DrawTextSimple(max$, 3, graphy[1]+fontHeight/2);
	gc.DrawTextSimple(min$, 3, graphy[2]+fontHeight/2);
	local string ylabel = "elevation (m)";
	gc.DrawTextSimple(ylabel, graphx[1]-4, (graphy[3]-graphy[1])/2+gc.TextGetWidth(ylabel)*3/4, 90);

	# draw x axis labels
	gc.DrawTextSimple("0", graphx[1] - gc.TextGetWidth("0")/2, getHeight()-4);
	local string str$ = sprintf("%d", graphLine.GetVertex(graphLine.GetNumPoints()-1).x);
	gc.DrawTextSimple(str$, getWidth() - gc.TextGetWidth(str$) - 3, getHeight()-4);
	local string xlabel = "distance (m)";
	gc.DrawTextSimple(xlabel, (graphx[3]-graphx[1])/2-gc.TextGetWidth(xlabel)/4, getHeight()-bottomGraphOffset+fontHeight+1);
}

# translate a point on the graphline to image device coordinates for drawing
func class POINT2D transPointToGraph(class POINT2D point, class POLYLINE graphLine)
{
	# get graph extents
	local numeric minx, maxx, miny, maxy;
	minx = leftGraphOffset;
	miny = topGraphOffset;
	maxx = getWidth() - rightGraphOffset;
	maxy = getHeight() - bottomGraphOffset;

	# Get the drawing scale
	local numeric xscale = 0, yscale = 0;
	xscale = (maxx - minx) / abs(graphLine.GetVertex(graphLine.GetNumPoints()-1).x - graphLine.GetVertex(0).x);
	if (maxz != minz) yscale = (maxy - miny) / (maxz - minz);

	point.x = point.x * xscale + leftGraphOffset;
#	if (IsNull(point.y)) point.y=0;
	if (yscale!=0) point.y = getHeight() - ((point.y-minz) * yscale + bottomGraphOffset);
	else point.y = getHeight() - bottomGraphOffset;
	return point;
}

# draw the graph with the given polyline
proc drawGraph(class POLYLINE graphLine, numeric vertexNum)
{
	# Plot out the axes first
	drawGraphAxes(graphLine);

	# Draw the profile
	gc.SetColorRGB(200, 50, 50);
	local class POINT2D linePoint = graphLine.GetVertex(0);

	# Plot point zero
	local class POINT2D graphPoint = transPointToGraph(linePoint, graphLine);
	gc.DrawPoint(graphPoint.x, graphPoint.y);

	# Plot the rest of the points
	local numeric i;
	for i=1 to graphLine.GetNumPoints()-1
	{
		linePoint = graphLine.GetVertex(i);
		graphPoint = transPointToGraph(linePoint, graphLine);

		if (isNull(linePoint.y))
		{
			# if null skip point and move to next
			i++;
#			linePoint = graphLine.GetVertex(i+1);
			while (i (getWidth() - rightGraphOffset - leftGraphOffset)/2)
		{
			gc.DrawTextSimple(elev, leftGraphOffset+1, graphCircle.y-1);	# draw on left
		}
		else
		{
			gc.DrawTextSimple(elev, getWidth() - rightGraphOffset - gc.TextGetWidth(elev)-1, graphCircle.y-1);	# draw on right
		}
	}
}

# Computes the offset to use to prevent graph from obscuring element
func class POINT2D computeOffset(class POLYLINE line, class GRE_VIEW view, class POINT2D cursor)
{
	local class POINT2D offset, imageOffset, extentsOffset, center;
	local class RECT extents = line.ComputeExtents();
	local numeric isUpper = 0, isLeft = 0;
	local numeric pixelOffset = 5;

	center = view.Center;
	center = TransPoint2D(center, ViewGetTransViewToScreen(view));

	if (cursor.y < center.y) isUpper = 1;
	if (cursor.x < center.x) isLeft = 1;

	if (isUpper)	# isUpper half of view, get min y
	{
		if (extents.pt1.y < extents.pt2.y) offset.y = extents.pt1.y;
		else offset.y = extents.pt2.y;
		extentsOffset.y = pixelOffset;
	}
	else	# isLower half of view, get max y
	{
		if (extents.pt1.y > extents.pt2.y) offset.y = extents.pt1.y;
		else offset.y = extents.pt2.y;
		imageOffset.y = -getHeight();
		extentsOffset.y = -pixelOffset;
	}
	if (isLeft)	# isLeft half of view, get max x
	{
		if (extents.pt1.x > extents.pt2.x) offset.x = extents.pt1.x;
		else offset.x = extents.pt2.x;
		extentsOffset.x = pixelOffset;
	}
	else	# isRight half of view, get min y
	{
		if (extents.pt1.x < extents.pt2.x) offset.x = extents.pt1.x;
		else offset.x = extents.pt2.x;
		imageOffset.x = -getWidth();
		extentsOffset.x = -pixelOffset;
	}

	# Get screen pixels
	offset = TransPoint2D(offset, ViewGetTransMapToView(view, vectorLayer.Projection));
	offset = TransPoint2D(offset, ViewGetTransViewToScreen(view));

	# Adjust by cursor position
	offset = offset - cursor;

	# Offset accounting for the size of the image
	offset = offset + imageOffset;

	# Offset from line extents
	offset = offset + extentsOffset;

	return offset;
}

# Convert the polyline from obj to map coordinates
func class POLYLINE convertObjectToMap(class POLYLINE line)
{
	local class POLYLINE ret;
	local class POINT2D obj, map;

	local numeric i;
	for i=0 to line.GetNumPoints()-1
	{
		obj = line.GetVertex(i);
		map = ObjectToMap(lineVector, obj.x, obj.y, vecGeoref);
		ret.AppendVertex(map);
	}

	return ret;
}

# Predefined function called when the cursor pauses triggering a datatip action event
func OnViewDataTipShowRequest(class GRE_VIEW view, class POINT2D point, class TOOLTIP datatip)
{
	datatip.Delay = 500;

	numeric scale = view.CurrentMapScale;
	if (!vectorLayer.IsVisibleAtScale(scale)) return -1;
#	if (scale > 4000000) return -1;

	# Store the cursor position
	local class POINT2D cursor = point;

	# Get the cursor position in map coords
	local class TRANSPARM screenToView = ViewGetTransViewToScreen(view, 1);
	local class TRANSPARM viewToMap = ViewGetTransMapToView(view, vectorLayer.Projection, 1);
	point = TransPoint2D(point, screenToView);
	point = TransPoint2D(point, viewToMap);

	# Translate 16 pixel distance to map projected distance
	local class POINT2D tmppoint0;
	tmppoint0.x = 0; tmppoint0.y = 0;
	tmppoint0 = TransPoint2D(tmppoint0, screenToView);
	tmppoint0 = TransPoint2D(tmppoint0, viewToMap);

	local class POINT2D tmppoint;
	tmppoint.x = sqrt(128); tmppoint.y = sqrt(128);
	tmppoint = TransPoint2D(tmppoint, screenToView);
	tmppoint = TransPoint2D(tmppoint, viewToMap);

	local numeric dist = computeDistance(tmppoint0, tmppoint);

	# Get the line from the cursor position
	local numeric lineNum = FindClosestLine(lineVector, point.x, point.y, vecGeoref, dist);
	if (lineNum == 0) return -1;	# if we are not close enough, don't display graph
	local class POLYLINE line = GetVectorLine(lineVector, lineNum);
	line = convertObjectToMap(line);

	# Highlight the line
	vectorLayer.line.HighlightSingle(lineNum);
#	view.RedrawLayer(vectorLayer); ## demir

	# Get the closest vertex for display
	local numeric vertexNum = line.FindClosestVertex(point);
	# Get the line to graph - x-dimension is distance, y is elevation
	local class POLYLINE graphLine = constructGraphLine(line);

	# Create the graphics context to draw the graph to
	createGC();

	# Draw the graph
	drawGraph(graphLine, vertexNum);

	# Compute Image tip offset and display
	local class POINT2D offset;
	offset = computeOffset(line, view, cursor);
	datatip.SetImageTip(imagedev, maskdev, offset);
	return 1;
}










Back Home ©MicroImages, Inc. 2008 Published in the United States of America
11th Floor - Sharp Tower, 206 South 13th Street, Lincoln NE 68508-2010   USA
Business & Sales: (402)477-9554  Support: (402)477-9562  Fax: (402)477-9559
Business info@microimages.com  Support support@microimages.com  Web webmaster@microimages.com

13 May 2008

page update: 14 Aug 07