[mapserver-commits] r9167 - sandbox/davidK

svn at osgeo.org svn at osgeo.org
Sat Jul 11 16:51:03 EDT 2009


Author: davidK
Date: 2009-07-11 16:51:02 -0400 (Sat, 11 Jul 2009)
New Revision: 9167

Added:
   sandbox/davidK/mapkml.cpp
   sandbox/davidK/mapkml.h
   sandbox/davidK/mapkmlrenderer.cpp
   sandbox/davidK/mapkmlrenderer.h
Log:
Added KML renderer files mapkml.c and mapkmlrenderer.cpp

Added: sandbox/davidK/mapkml.cpp
===================================================================
--- sandbox/davidK/mapkml.cpp	                        (rev 0)
+++ sandbox/davidK/mapkml.cpp	2009-07-11 20:51:02 UTC (rev 9167)
@@ -0,0 +1,211 @@
+#include "mapserver.h"
+#include "mapkmlrenderer.h"
+
+#include "mapkml.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+KmlRenderer* getKmlRenderer(imageObj* img)
+{
+	return (KmlRenderer*) img->img.plugin;
+}
+
+imageObj* msCreateImageKml(int width, int height, outputFormatObj *format, colorObj* bg)
+{
+	imageObj *image = NULL;
+
+	image = (imageObj*)malloc(sizeof(imageObj));
+	memset(image, 0, sizeof(imageObj));
+
+	KmlRenderer *ren = new KmlRenderer(width, height, bg);
+	image->img.plugin = (void *) ren;
+
+	return image;
+}
+
+int msSaveImageKml(imageObj *img, FILE *fp, outputFormatObj *format)
+{
+	KmlRenderer* renderer = getKmlRenderer(img);
+	return renderer->saveImage(img, fp, format);
+}
+
+void msRenderLineKml(imageObj *img, shapeObj *p, strokeStyleObj *style)
+{
+	KmlRenderer* renderer = getKmlRenderer(img);
+	renderer->renderLine(img, p, style);
+}
+
+void msRenderPolygonKml(imageObj *img, shapeObj *p, colorObj *color)
+{
+	KmlRenderer* renderer = getKmlRenderer(img);
+	renderer->renderPolygon(img, p, color);
+}
+
+void msRenderPolygonTiledKml(imageObj *img, shapeObj *p,  imageObj *tile)
+{
+	KmlRenderer* renderer = getKmlRenderer(img);
+}
+
+void msRenderLineTiledKml(imageObj *img, shapeObj *p, imageObj *tile)
+{
+}
+
+void msRenderGlyphsKml(imageObj *img, double x, double y,
+            labelStyleObj *style, char *text)
+{
+	KmlRenderer* renderer = getKmlRenderer(img);
+	renderer->renderGlyphs(img, x, y, style, text);
+}
+
+void msRenderGlyphsLineKml(imageObj *img,labelPathObj *labelpath,
+      labelStyleObj *style, char *text)
+{
+}
+
+void msRenderVectorSymbolKml(imageObj *img, double x, double y,
+		symbolObj *symbol, symbolStyleObj *style)
+{
+}
+
+void* msCreateVectorSymbolTileKml(int width, int height,
+        symbolObj *symbol, symbolStyleObj *style)
+{
+	return NULL;
+}
+
+void msRenderPixmapSymbolKml(imageObj *img, double x, double y,
+    	symbolObj *symbol, symbolStyleObj *style)
+{
+	KmlRenderer* renderer = getKmlRenderer(img);
+	renderer->renderPixmapSymbol(img, x, y, symbol, style);
+}
+
+void* msCreatePixmapSymbolTileKml(int width, int height,
+        symbolObj *symbol, symbolStyleObj *style)
+{
+	return NULL;
+}
+
+void msRenderEllipseSymbolKml(imageObj *image, double x, double y, 
+		symbolObj *symbol, symbolStyleObj *style)
+{
+}
+
+void* msCreateEllipseSymbolTileKml(int width, int height,
+        symbolObj *symbol, symbolStyleObj *style)
+{
+	return NULL;
+}
+
+void msRenderTruetypeSymbolKml(imageObj *img, double x, double y,
+        symbolObj *symbol, symbolStyleObj *style)
+{
+}
+
+void* msCreateTruetypeSymbolTileKml(int width, int height,
+        symbolObj *symbol, symbolStyleObj *style)
+{
+	return NULL;
+}
+
+void msRenderTileKml(imageObj *img, imageObj *tile, double x, double y)
+{
+}
+
+void msGetRasterBufferKml(imageObj *img,rasterBufferObj *rb)
+{
+}
+
+void msMergeRasterBufferKml(imageObj *dest, rasterBufferObj *overlay, double opacity, int dstX, int dstY)
+{
+}
+
+int msGetTruetypeTextBBoxKml(imageObj *img,char *font, double size, char *string,
+		rectObj *rect, double **advances)
+{
+	KmlRenderer* renderer = getKmlRenderer(img);
+	return renderer->getTruetypeTextBBox(img, font, size, string, rect, advances);
+}
+
+void msStartNewLayerKml(imageObj *img, layerObj *layer)
+{
+	KmlRenderer* renderer = getKmlRenderer(img);
+	renderer->startNewLayer(img, layer);
+}
+
+void msCloseNewLayerKml(imageObj *img, layerObj *layer)
+{
+	KmlRenderer* renderer = getKmlRenderer(img);
+	renderer->closeNewLayer(img, layer);
+}
+
+void msTransformShapeKml(shapeObj *shape, rectObj extend, double cellsize)
+{
+}
+
+void msFreeImageKml(imageObj *image)
+{
+	KmlRenderer* renderer = getKmlRenderer(image);
+	if (renderer)
+	{
+		delete renderer;
+	}
+	image->img.plugin=NULL;
+}
+
+void msFreeTileKml(imageObj *tile)
+{
+}
+
+void msFreeSymbolKml(symbolObj *symbol)
+{
+}
+
+int msPopulateRendererVTableKML( rendererVTableObj *renderer )
+{
+#ifdef USE_KML
+
+	renderer->supports_transparent_layers = 1;
+	renderer->supports_pixel_buffer = 0;
+	renderer->supports_imagecache = 0;
+
+	renderer->startNewLayer = msStartNewLayerKml;
+	renderer->closeNewLayer = msCloseNewLayerKml;
+    renderer->renderLine=&msRenderLineKml;
+    renderer->createImage=&msCreateImageKml;
+    renderer->saveImage=&msSaveImageKml;
+    renderer->transformShape=&msTransformShapeKml;
+    renderer->renderPolygon=&msRenderPolygonKml;
+    renderer->renderGlyphs=&msRenderGlyphsKml;
+	renderer->renderGlyphsLine = &msRenderGlyphsLineKml;
+    renderer->renderEllipseSymbol = &msRenderEllipseSymbolKml;
+    renderer->renderVectorSymbol = &msRenderVectorSymbolKml;
+    renderer->renderPixmapSymbol = &msRenderPixmapSymbolKml;
+	renderer->renderTruetypeSymbol = &msRenderTruetypeSymbolKml;
+	renderer->getRasterBuffer = &msGetRasterBufferKml;
+    renderer->mergeRasterBuffer = &msMergeRasterBufferKml;
+    renderer->getTruetypeTextBBox = &msGetTruetypeTextBBoxKml;
+    renderer->createPixmapSymbolTile = &msCreatePixmapSymbolTileKml;
+    renderer->createVectorSymbolTile = &msCreateVectorSymbolTileKml;
+    renderer->createEllipseSymbolTile = &msCreateEllipseSymbolTileKml;
+    renderer->createTruetypeSymbolTile = &msCreateTruetypeSymbolTileKml;
+    renderer->renderTile = &msRenderTileKml;
+    renderer->renderPolygonTiled = &msRenderPolygonTiledKml;
+    renderer->renderLineTiled = &msRenderLineTiledKml;
+    renderer->freeTile = &msFreeTileKml;
+    renderer->freeSymbol = &msFreeSymbolKml;
+    renderer->freeImage=&msFreeImageKml;
+
+    return MS_SUCCESS;
+#else
+    msSetError(MS_MISCERR, "KML Driver requested but is not built in", 
+            "msPopulateRendererVTableKML()");
+    return MS_FAILURE;
+#endif
+}
+
+#ifdef __cplusplus
+}
+#endif
\ No newline at end of file

Added: sandbox/davidK/mapkml.h
===================================================================
--- sandbox/davidK/mapkml.h	                        (rev 0)
+++ sandbox/davidK/mapkml.h	2009-07-11 20:51:02 UTC (rev 9167)
@@ -0,0 +1,64 @@
+#ifndef MAPKML_H
+#define MAPKML_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "mapserver.h"
+
+imageObj* msCreateImageKml(int width, int height, outputFormatObj *format, colorObj* bg);
+int msSaveImageKml(imageObj *img, FILE *fp, outputFormatObj *format);
+void msRenderLineKml(imageObj *img, shapeObj *p, strokeStyleObj *style);
+void msRenderPolygonKml(imageObj *img, shapeObj *p, colorObj *color);
+void msRenderPolygonTiledKml(imageObj *img, shapeObj *p,  imageObj *tile);
+void msRenderLineTiledKml(imageObj *img, shapeObj *p, imageObj *tile);
+void msRenderGlyphsKml(imageObj *img, double x, double y,
+            labelStyleObj *style, char *text);
+
+void msRenderGlyphsLineKml(imageObj *img,labelPathObj *labelpath,
+      labelStyleObj *style, char *text);
+
+void msRenderVectorSymbolKml(imageObj *img, double x, double y,
+		symbolObj *symbol, symbolStyleObj *style);
+
+void* msCreateVectorSymbolTileKml(int width, int height,
+        symbolObj *symbol, symbolStyleObj *style);
+
+void msRenderPixmapSymbolKml(imageObj *img, double x, double y,
+    	symbolObj *symbol, symbolStyleObj *style);
+
+void* msCreatePixmapSymbolTileKml(int width, int height,
+        symbolObj *symbol, symbolStyleObj *style);
+
+void msRenderEllipseSymbolKml(imageObj *image, double x, double y, 
+		symbolObj *symbol, symbolStyleObj *style);
+
+void* msCreateEllipseSymbolTileKml(int width, int height,
+        symbolObj *symbol, symbolStyleObj *style);
+
+void msRenderTruetypeSymbolKml(imageObj *img, double x, double y,
+        symbolObj *symbol, symbolStyleObj *style);
+
+void* msCreateTruetypeSymbolTileKml(int width, int height,
+        symbolObj *symbol, symbolStyleObj *style);
+
+void msRenderTileKml(imageObj *img, imageObj *tile, double x, double y);
+void msGetRasterBufferKml(imageObj *img,rasterBufferObj *rb);
+
+void msMergeRasterBufferKml(imageObj *dest, rasterBufferObj *overlay, double opacity, int dstX, int dstY);
+int msGetTruetypeTextBBoxKml(imageObj *img,char *font, double size, char *string,
+		rectObj *rect, double **advances);
+
+void msStartNewLayerKml(imageObj *img, layerObj *layer);
+void msCloseNewLayerKml(imageObj *img, layerObj *layer);
+void msTransformShapeKml(shapeObj *shape, rectObj extend, double cellsize);
+void msFreeImageKml(imageObj *image);
+void msFreeTileKml(imageObj *tile);
+void msFreeSymbolKml(symbolObj *symbol);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MAPKML_H */
\ No newline at end of file

Added: sandbox/davidK/mapkmlrenderer.cpp
===================================================================
--- sandbox/davidK/mapkmlrenderer.cpp	                        (rev 0)
+++ sandbox/davidK/mapkmlrenderer.cpp	2009-07-11 20:51:02 UTC (rev 9167)
@@ -0,0 +1,733 @@
+#ifdef USE_KML
+
+#include "mapserver.h"
+#include "maperror.h"
+#include "mapkmlrenderer.h"
+#include "mapio.h"
+
+#define	LAYER_FOLDER_STYLE		"LayerFolder"
+#define	LAYER_FOLDER_STYLE_URL	"#LayerFolder"
+
+KmlRenderer::KmlRenderer(int width, int height, colorObj* color/*=NULL*/) 
+	:	XmlDoc(NULL), LayerNode(NULL), Width(width), Height(height),
+		FirstLayer(true), RasterizerOutputFormat(NULL),
+		VectorMode(true), RasterMode(false), MapCellsize(1.0)
+{
+	//	Create document.
+    XmlDoc = xmlNewDoc(BAD_CAST "1.0");
+
+    xmlNodePtr rootNode = xmlNewNode(NULL, BAD_CAST "kml");
+
+	//	Name spaces
+    xmlSetNs(rootNode, xmlNewNs(rootNode, BAD_CAST "http://www.opengis.net/kml/2.2", NULL));
+
+    xmlDocSetRootElement(XmlDoc, rootNode);
+
+	DocNode = xmlNewChild(rootNode, NULL, BAD_CAST "Document", NULL);
+
+	xmlNodePtr styleNode = xmlNewChild(DocNode, NULL, BAD_CAST "Style", NULL);
+	xmlNewProp(styleNode, BAD_CAST "id", BAD_CAST LAYER_FOLDER_STYLE);
+	xmlNodePtr listStyleNode = xmlNewChild(styleNode, NULL, BAD_CAST "ListStyle", NULL);
+	xmlNewChild(listStyleNode, NULL, BAD_CAST "listItemType", BAD_CAST "checkHideChildren");
+
+	StyleHashTable = msCreateHashTable();
+}
+
+KmlRenderer::~KmlRenderer()
+{
+	if (XmlDoc)
+		xmlFreeDoc(XmlDoc);
+
+	if (StyleHashTable)
+		msFreeHashTable(StyleHashTable);
+
+	xmlCleanupParser();
+
+	if (RasterizerOutputFormat)
+		msFreeOutputFormat(RasterizerOutputFormat);
+}
+
+imageObj* KmlRenderer::createInternalImage()
+{
+	rendererVTableObj *r = RasterizerOutputFormat->vtable;
+	imageObj *img = r->createImage(Width, Height, RasterizerOutputFormat, NULL);
+
+	return img;
+}
+
+imageObj* KmlRenderer::createImage(int width, int height, outputFormatObj *format, colorObj* bg)
+{
+	return NULL;
+}
+
+int KmlRenderer::saveImage(imageObj *img, FILE *fp, outputFormatObj *format)
+{
+	// 
+	if (InternalImg)
+	{
+		char fileName[512];
+
+		rendererVTableObj *r = RasterizerOutputFormat->vtable;
+
+		//FILE *stream = fopen(msBuildPath(szPath, map->mappath, filename), "wb");
+
+		sprintf(fileName, "kml_ground_overlay_%ld%d.%s", (long)time(NULL), (int)getpid(), MS_IMAGE_EXTENSION(RasterizerOutputFormat)); // __TODO__ add WEB IMAGEURL path;
+		FILE *stream = fopen(fileName, "wb");
+
+		if(r->supports_pixel_buffer)
+		{
+			rasterBufferObj data;
+			r->getRasterBuffer(InternalImg,&data);
+			msSaveRasterBuffer(&data, stream, RasterizerOutputFormat );
+		}
+		else
+		{
+			r->saveImage(InternalImg, stream, RasterizerOutputFormat);
+		}
+		fclose(stream);
+
+		createGroundOverlayNode(fileName);
+	}
+
+	/* -------------------------------------------------------------------- */
+	/*      Write out the document.                                         */
+	/* -------------------------------------------------------------------- */
+
+	int bufSize = 0;
+	xmlChar *buf = NULL;
+	msIOContext *context = NULL;
+
+	if( msIO_needBinaryStdout() == MS_FAILURE )
+		return MS_FAILURE;
+
+	xmlDocDumpFormatMemoryEnc(XmlDoc, &buf, &bufSize, "ISO-8859-1", 1);
+
+	context = msIO_getHandler(fp);
+	if (context)
+		msIO_printf("Content-type: %s%c%c",format->mimetype,10,10);
+
+
+	int chunkSize = 4096;
+	for (int i=0; i<bufSize; i+=chunkSize)
+	{
+		int size = chunkSize;
+		if (i + size > bufSize)
+			size = bufSize - i;
+
+		if (context)
+			msIO_contextWrite(context, buf+i, size);
+		else
+			msIO_fwrite(buf+i, 1, size, fp);
+	}
+
+	//msIO_fprintf(fp, "%s", buffer);
+
+	xmlFree(buf);
+
+	return(MS_SUCCESS);
+}
+
+void KmlRenderer::freeImage(imageObj *image)
+{
+}
+
+void KmlRenderer::setupRenderingParams(hashTableObj *layerMetadata)
+{
+	AltitudeMode = 0;
+	Extrude = 0;
+	Tessellate = 0;
+
+	char *altitudeModeVal = msLookupHashTable(layerMetadata, "kml_altitudeMode");
+	if (altitudeModeVal)
+	{
+		if(strcasecmp(altitudeModeVal, "absolute") == 0)
+			AltitudeMode = absolute;
+		else if(strcasecmp(altitudeModeVal, "relativeToGround") == 0)
+			AltitudeMode = relativeToGround;
+		else if(strcasecmp(altitudeModeVal, "clampToGround") == 0)
+			AltitudeMode = clampToGround;
+	}
+
+	char *extrudeVal = msLookupHashTable(layerMetadata, "kml_extrude");
+	if (altitudeModeVal)
+	{
+		Extrude = atoi(extrudeVal);
+	}
+
+	char *tessellateVal = msLookupHashTable(layerMetadata, "kml_tessellate");
+	if (tessellateVal)
+	{
+		Tessellate = atoi(tessellateVal);
+	}
+}
+
+int KmlRenderer::checkProjection(projectionObj *projection)
+{
+#ifdef USE_PROJ
+	if (projection && projection->numargs > 0 && pj_is_latlong(projection->proj))
+	{
+		char *projStr = msGetProjectionString(projection);
+
+		/* is ellipsoid WGS84 or projection code epsg:4326 */
+		if (strcasestr(projStr, "WGS84") || strcasestr(projStr,"epsg:4326"))
+		{
+			return MS_SUCCESS;
+		}
+	}
+
+	msSetError(MS_PROJERR, "Mapfile projection not defined, KML output driver requires projection WGS84 (epsg:4326)", "KmlRenderer::checkProjection()" );
+	return MS_FAILURE;
+
+#else
+	msSetError(MS_MISCERR, "Projection support not enabled", "KmlRenderer::checkProjection" );
+	return MS_FAILURE;
+#endif
+}
+
+void KmlRenderer::startNewLayer(imageObj *img, layerObj *layer)
+{
+	LayerNode = xmlNewChild(DocNode, NULL, BAD_CAST "Folder", NULL);
+	
+	xmlNewChild(LayerNode, NULL, BAD_CAST "name", BAD_CAST layer->name);
+
+	char *layerVisibility = layer->status != MS_OFF ? "1" : "0";
+	xmlNewChild(LayerNode, NULL, BAD_CAST "visibility", BAD_CAST layerVisibility);
+
+	xmlNewChild(LayerNode, NULL, BAD_CAST "styleUrl", BAD_CAST LAYER_FOLDER_STYLE_URL);
+
+	setupRenderingParams(&layer->metadata);
+
+	if (FirstLayer)
+	{
+		FirstLayer = false;
+
+		// map rect for ground overlay
+		MapExtent = layer->map->extent;
+		MapCellsize = layer->map->cellsize;
+
+		if (layer->map->name)
+			xmlNewChild(DocNode, NULL, BAD_CAST "name", BAD_CAST layer->map->name);
+
+		// First rendered layer - check mapfile projection
+		checkProjection(&layer->map->projection);
+
+		for (int i=0; i<layer->map->numoutputformats; i++)
+		{
+			outputFormatObj *iFormat = layer->map->outputformatlist[i];
+			if(!strcasecmp(iFormat->driver,"cairo/png"))
+			{
+				RasterizerOutputFormat = msCloneOutputFormat(iFormat);
+				InternalImg = createInternalImage();
+			}
+		}
+	}
+}
+
+void KmlRenderer::closeNewLayer(imageObj *img, layerObj *layer)
+{
+
+}
+
+xmlNodePtr KmlRenderer::createPlacemarkNode(xmlNodePtr parentNode, char *styleUrl)
+{
+	xmlNodePtr placemarkNode = xmlNewChild(parentNode, NULL, BAD_CAST "Placemark", NULL);
+
+	if (styleUrl)
+		xmlNewChild(placemarkNode, NULL, BAD_CAST "styleUrl", BAD_CAST styleUrl);
+
+	return placemarkNode;
+}
+
+void KmlRenderer::renderLineVector(imageObj *img, shapeObj *p, strokeStyleObj *style)
+{
+	xmlNodePtr placemarkNode = createPlacemarkNode(LayerNode, lookupLineStyle(style));
+
+	if (p->numlines == 1)
+	{
+		xmlNodePtr geomNode = xmlNewChild(placemarkNode, NULL, BAD_CAST "LineString", NULL);
+		addAddRenderingSpecifications(geomNode);
+		addCoordsNode(geomNode, p->line[0].point, p->line[0].numpoints);
+	}
+	else
+	{
+		xmlNodePtr multiGeomNode = xmlNewChild(placemarkNode, NULL, BAD_CAST "MultiGeometry", NULL);
+		for (int i=0; i<p->numlines; i++)
+		{
+			xmlNodePtr lineStringNode = xmlNewChild(multiGeomNode, NULL, BAD_CAST "LineString", NULL);
+			addAddRenderingSpecifications(lineStringNode);
+			addCoordsNode(lineStringNode, p->line[i].point, p->line[i].numpoints);
+		}
+	}
+}
+
+void KmlRenderer::renderLine(imageObj *img, shapeObj *p, strokeStyleObj *style)
+{
+	if (VectorMode)
+		renderLineVector(img, p, style);
+
+	if (RasterMode)
+	{
+		shapeObj rasShape;
+
+		// internal renderer used for rasterizing
+		rendererVTableObj *r = RasterizerOutputFormat->vtable;
+
+		msInitShape(&rasShape);
+		msCopyShape(p,&rasShape);
+
+		r->transformShape(&rasShape, MapExtent, MapCellsize);
+
+		r->renderLine(InternalImg, &rasShape, style);
+		msFreeShape(&rasShape);
+	}
+}
+
+void KmlRenderer::renderPolygonVector(imageObj *img, shapeObj *p, colorObj *color)
+{
+	xmlNodePtr placemarkNode = createPlacemarkNode(LayerNode, lookupPolyStyle(color));
+	xmlNodePtr polygonNode = xmlNewChild(placemarkNode, NULL, BAD_CAST "Polygon", NULL);
+
+	for (int i=0; i<p->numlines; i++)
+	{
+		xmlNodePtr bdryNode = NULL;
+
+		if (i==0) // __TODO__ check ring order
+			bdryNode = xmlNewChild(polygonNode, NULL, BAD_CAST "outerBoundaryIs", NULL);
+		else
+			bdryNode = xmlNewChild(polygonNode, NULL, BAD_CAST "innerBoundaryIs", NULL);
+
+		xmlNodePtr ringNode = xmlNewChild(bdryNode, NULL, BAD_CAST "LinearRing", NULL);
+		addAddRenderingSpecifications(ringNode);
+		addCoordsNode(ringNode, p->line[i].point, p->line[i].numpoints);
+	}
+}
+
+void KmlRenderer::renderPolygon(imageObj *img, shapeObj *p, colorObj *color)
+{
+	if (VectorMode)
+		renderPolygonVector(img, p, color);
+
+	if (RasterMode)
+	{
+		shapeObj rasShape;
+
+		// internal renderer used for rasterizing
+		rendererVTableObj *r = RasterizerOutputFormat->vtable;
+
+		msInitShape(&rasShape);
+		msCopyShape(p,&rasShape);
+
+		r->transformShape(&rasShape, MapExtent, MapCellsize);
+
+		r->renderPolygon(InternalImg, &rasShape, color);
+		msFreeShape(&rasShape);
+	}
+}
+
+void KmlRenderer::addCoordsNode(xmlNodePtr parentNode, pointObj *pts, int numPts)
+{
+	char lineBuf[128];
+
+	xmlNodePtr coordsNode = xmlNewChild(parentNode, NULL, BAD_CAST "coordinates", NULL);
+	xmlNodeAddContent(coordsNode, BAD_CAST "\n");
+
+	for (int i=0; i<numPts; i++)
+	{
+		if (AltitudeMode == relativeToGround || AltitudeMode == absolute)
+		{
+#ifdef USE_POINT_Z_M
+			sprintf(lineBuf, "\t%.8f,%.8f,%.8f\n", pts[i].x, pts[i].y, pts[i].z);
+#else
+			msSetError(MS_MISCERR, "Z coordinates support not available  (mapserver not compiled with USE_POINT_Z_M option)", "KmlRenderer::addCoordsNode()");
+#endif
+		}
+		else
+			sprintf(lineBuf, "\t%.8f,%.8f\n", pts[i].x, pts[i].y);
+
+		xmlNodeAddContent(coordsNode, BAD_CAST lineBuf);
+	}
+	xmlNodeAddContent(coordsNode, BAD_CAST "\t");
+}
+
+char* KmlRenderer::lookupLineStyle(strokeStyleObj *strokeStyle)
+{
+	/*
+	<LineStyle id="ID">
+	  <!-- inherited from ColorStyle -->
+	  <color>ffffffff</color>            <!-- kml:color -->
+	  <colorMode>normal</colorMode>      <!-- colorModeEnum: normal or random -->
+
+	  <!-- specific to LineStyle -->
+	  <width>1</width>                   <!-- float -->
+	</LineStyle>
+	*/
+
+	char hexColor[16];
+	sprintf(hexColor,"%02x%02x%02x%02x", strokeStyle->color.alpha, strokeStyle->color.blue,
+											strokeStyle->color.green, strokeStyle->color.red);
+
+	char styleName[32];
+	sprintf(styleName, "lineStyle%s_w%.1f", hexColor, strokeStyle->width);
+
+	char *styleUrl = msLookupHashTable(StyleHashTable, styleName);
+	if (!styleUrl)
+	{
+		char styleValue[32];
+		sprintf(styleValue, "#%s", styleName);
+
+		hashObj *hash = msInsertHashTable(StyleHashTable, styleName, styleValue);
+		styleUrl = hash->data;
+
+		// Insert new PolyStyle node into Document node
+		xmlNodePtr styleNode = xmlNewChild(DocNode, NULL, BAD_CAST "Style", NULL);
+		xmlNewProp(styleNode, BAD_CAST "id", BAD_CAST styleName);
+
+		xmlNodePtr lineStyleNode = xmlNewChild(styleNode, NULL, BAD_CAST "LineStyle", NULL);
+		xmlNewChild(lineStyleNode, NULL, BAD_CAST "color", BAD_CAST hexColor);
+
+		char width[16];
+		sprintf(width, "%.1f", strokeStyle->width);
+		xmlNewChild(lineStyleNode, NULL, BAD_CAST "width", BAD_CAST width);
+	}
+
+	return styleUrl;
+}
+
+char* KmlRenderer::lookupPolyStyle(colorObj *color)
+{
+	/*
+	<PolyStyle id="ID">
+	  <!-- inherited from ColorStyle -->
+	  <color>ffffffff</color>            <!-- kml:color -->
+	  <colorMode>normal</colorMode>      <!-- kml:colorModeEnum: normal or random -->
+
+	  <!-- specific to PolyStyle -->
+	  <fill>1</fill>                     <!-- boolean -->
+	  <outline>1</outline>               <!-- boolean -->
+	</PolyStyle>
+	*/
+
+	char hexColor[16];
+	sprintf(hexColor,"%02x%02x%02x%02x", color->alpha, color->blue, color->green, color->red);
+
+	char styleName[32];
+	sprintf(styleName, "polyStyle%s", hexColor);
+
+	char *styleUrl = msLookupHashTable(StyleHashTable, styleName);
+	if (!styleUrl)
+	{
+		char styleValue[32];
+		sprintf(styleValue, "#%s", styleName);
+
+		hashObj *hash = msInsertHashTable(StyleHashTable, styleName, styleValue);
+		styleUrl = hash->data;
+
+		// Insert new PolyStyle node into Document node
+		xmlNodePtr styleNode = xmlNewChild(DocNode, NULL, BAD_CAST "Style", NULL);
+		xmlNewProp(styleNode, BAD_CAST "id", BAD_CAST styleName);
+
+		xmlNodePtr polyStyleNode = xmlNewChild(styleNode, NULL, BAD_CAST "PolyStyle", NULL);
+		xmlNewChild(polyStyleNode, NULL, BAD_CAST "color", BAD_CAST hexColor);
+	}
+
+	return styleUrl;
+}
+
+char* KmlRenderer::lookupPointStyle(colorObj *color)
+{
+	return NULL;
+}
+
+void KmlRenderer::renderGlyphsVector(imageObj *img, double x, double y, labelStyleObj *style, char *text)
+{
+	xmlNodePtr placemarkNode = createPlacemarkNode(LayerNode, lookupPointStyle(&style->color));
+	xmlNewChild(placemarkNode, NULL, BAD_CAST "name", BAD_CAST text);
+	xmlNodePtr pointNode = xmlNewChild(placemarkNode, NULL, BAD_CAST "Point", NULL);
+
+	addAddRenderingSpecifications(pointNode);
+
+	pointObj pt;
+	pt.x = x; pt.y = y;
+	addCoordsNode(pointNode, &pt, 1);
+}
+
+void KmlRenderer::renderGlyphs(imageObj *img, double x, double y, labelStyleObj *style, char *text)
+{
+	if (VectorMode)
+		renderGlyphsVector(img, x, y, style, text);
+
+	if (RasterMode)
+	{
+		// internal renderer used for rasterizing
+		rendererVTableObj *r = RasterizerOutputFormat->vtable;
+		r->renderGlyphs(InternalImg, x, y, style, text);
+	}
+}
+
+int KmlRenderer::getTruetypeTextBBox(imageObj *img,char *font, double size, char *string,
+		rectObj *rect, double **advances)
+{
+	if (VectorMode)
+	{
+		// TODO
+		rect->minx=0.0;
+		rect->maxx=0.0;
+		rect->miny=0.0;
+		rect->maxy=0.0;
+	}
+
+	if (RasterMode)
+	{
+		rendererVTableObj *r = RasterizerOutputFormat->vtable;
+		r->getTruetypeTextBBox(InternalImg, font, size, string, rect, advances);
+	}
+
+	return true;
+}
+
+void KmlRenderer::addAddRenderingSpecifications(xmlNodePtr node)
+{
+	/*
+	<extrude>0</extrude>                   <!-- boolean -->
+	<tessellate>0</tessellate>             <!-- boolean -->
+	<altitudeMode>clampToGround</altitudeMode> 
+	*/
+
+	if (Extrude)
+		xmlNewChild(node, NULL, BAD_CAST "extrude", BAD_CAST "1");
+
+	if (Tessellate)
+		xmlNewChild(node, NULL, BAD_CAST "tessellate", BAD_CAST "1");
+
+	if (AltitudeMode == absolute)
+		xmlNewChild(node, NULL, BAD_CAST "altitudeMode", BAD_CAST "absolute");
+	else if (AltitudeMode == relativeToGround)
+		xmlNewChild(node, NULL, BAD_CAST "altitudeMode", BAD_CAST "relativeToGround");
+	else if (AltitudeMode == clampToGround)
+		xmlNewChild(node, NULL, BAD_CAST "altitudeMode", BAD_CAST "clampToGround");
+}
+
+char* KmlRenderer::lookupSymbolStyle(symbolObj *symbol, symbolStyleObj *style)
+{
+	/*	
+	<Style id="randomColorIcon">
+	  <IconStyle>
+		 <color>ff00ff00</color>
+		 <colorMode>random</colorMode>
+		 <scale>1.1</scale>
+		 <Icon>
+			<href>http://maps.google.com/mapfiles/kml/pal3/icon21.png</href>
+		 </Icon>
+	  </IconStyle>
+	</Style>
+	*/
+
+	char styleName[128];
+	sprintf(styleName, "symbol_%s_%.1f", symbol->name, style->scale);
+
+	char *styleUrl = msLookupHashTable(StyleHashTable, styleName);
+	if (!styleUrl)
+	{
+		char styleValue[32];
+		sprintf(styleValue, "#%s", styleName);
+
+		hashObj *hash = msInsertHashTable(StyleHashTable, styleName, styleValue);
+		styleUrl = hash->data;
+
+		// Insert new IconStyle node into Document node
+		xmlNodePtr styleNode = xmlNewChild(DocNode, NULL, BAD_CAST "Style", NULL);
+		xmlNewProp(styleNode, BAD_CAST "id", BAD_CAST styleName);
+
+		xmlNodePtr iconStyleNode = xmlNewChild(styleNode, NULL, BAD_CAST "IconStyle", NULL);
+		char scale[16];
+		sprintf(scale, "%.1f", style->scale);
+		xmlNewChild(iconStyleNode, NULL, BAD_CAST "scale", BAD_CAST scale);
+
+		char iconFileName[512];
+		sprintf(iconFileName, "symbol_%s_%.1f.%s", symbol->name, style->scale, MS_IMAGE_EXTENSION(RasterizerOutputFormat)); // __TODO__ add WEB IMAGEURL path
+		if (createIconImage(iconFileName, symbol, style) != MS_SUCCESS)
+		{
+			char errMsg[512];
+			sprintf(errMsg, "Error creating icon file '%s'", iconFileName);
+			msSetError(MS_IOERR, errMsg, "KmlRenderer::lookupSymbolStyle()" );
+			return NULL;
+		}
+
+		xmlNodePtr iconNode = xmlNewChild(iconStyleNode, NULL, BAD_CAST "Icon", NULL);
+		xmlNewChild(iconNode, NULL, BAD_CAST "href", BAD_CAST iconFileName);
+	}
+
+	return styleUrl;
+}
+
+int KmlRenderer::createIconImage(char *fileName, symbolObj *symbol, symbolStyleObj *style)
+{
+	// internal renderer used for rasterizing
+	rendererVTableObj *r = RasterizerOutputFormat->vtable;
+
+	RasterizerOutputFormat->imagemode = MS_IMAGEMODE_RGBA;
+	imageObj *tmpImg = r->createImage(symbol->sizex, symbol->sizey, RasterizerOutputFormat, NULL);
+
+	double scale = style->scale; // save symbol scale
+	style->scale = 1.0; // render symbol in default size
+
+	double cx = symbol->sizex / 2;
+	double cy = symbol->sizey / 2;
+
+	switch(symbol->type)
+	{
+		case (MS_SYMBOL_TRUETYPE):
+			r->renderTruetypeSymbol(tmpImg, cx, cy, symbol, style);
+			break;
+		case (MS_SYMBOL_PIXMAP): 
+			r->renderPixmapSymbol(tmpImg, cx, cy, symbol, style);
+			break;
+		case (MS_SYMBOL_ELLIPSE): 
+			r->renderEllipseSymbol(tmpImg, cx, cy, symbol, style);
+			break;
+		case (MS_SYMBOL_VECTOR): 
+			r->renderVectorSymbol(tmpImg, cx, cy, symbol, style);
+			break;
+		default:
+			break;
+	}
+
+	style->scale = scale; // restore symbol scale
+
+	FILE *fOut = fopen(fileName, "wb");
+	if (!fOut)
+		return MS_FAILURE;
+
+	tmpImg->format = RasterizerOutputFormat;
+
+	int status = MS_FAILURE;
+    if(r->supports_pixel_buffer)
+	{
+        rasterBufferObj data;
+        r->getRasterBuffer(tmpImg,&data);
+        status = msSaveRasterBuffer(&data, fOut, RasterizerOutputFormat );
+    }
+	else
+	{
+        status = r->saveImage(tmpImg, fOut, RasterizerOutputFormat);
+    }
+
+	fclose(fOut);
+
+	return status;
+}
+
+void KmlRenderer::createSymbolPlacemark(imageObj *img, double x, double y, symbolObj *symbol, symbolStyleObj *style)
+{
+	char *symbolUrl = lookupSymbolStyle(symbol, style);
+
+	xmlNodePtr placemarkNode = createPlacemarkNode(LayerNode, symbolUrl);
+	xmlNewChild(placemarkNode, NULL, BAD_CAST "name", NULL);
+	xmlNodePtr pointNode = xmlNewChild(placemarkNode, NULL, BAD_CAST "Point", NULL);
+
+	addAddRenderingSpecifications(pointNode);
+
+	pointObj pt;
+	pt.x = x; pt.y = y;
+	addCoordsNode(pointNode, &pt, 1);
+}
+
+void KmlRenderer::renderPixmapSymbol(imageObj *img, double x, double y, symbolObj *symbol, symbolStyleObj *style)
+{
+	if (VectorMode)
+		createSymbolPlacemark(img, x, y, symbol, style);
+
+	if (RasterMode)
+	{
+		rendererVTableObj *r = RasterizerOutputFormat->vtable;
+		r->renderPixmapSymbol(InternalImg, x, y, symbol, style);
+	}
+}
+
+void KmlRenderer::renderVectorSymbol(imageObj *img, double x, double y, symbolObj *symbol, symbolStyleObj *style)
+{
+	if (VectorMode)
+		createSymbolPlacemark(img, x, y, symbol, style);
+
+	if (RasterMode)
+	{
+		rendererVTableObj *r = RasterizerOutputFormat->vtable;
+		r->renderVectorSymbol(InternalImg, x, y, symbol, style);
+	}
+}
+
+void KmlRenderer::renderEllipseSymbol(imageObj *img, double x, double y, symbolObj *symbol, symbolStyleObj *style)
+{
+	if (VectorMode)
+		createSymbolPlacemark(img, x, y, symbol, style);
+
+	if (RasterMode)
+	{
+		rendererVTableObj *r = RasterizerOutputFormat->vtable;
+		r->renderEllipseSymbol(InternalImg, x, y, symbol, style);
+	}
+}
+
+void KmlRenderer::renderTruetypeSymbol(imageObj *img, double x, double y, symbolObj *symbol, symbolStyleObj *style)
+{
+	if (VectorMode)
+		createSymbolPlacemark(img, x, y, symbol, style);
+
+	if (RasterMode)
+	{
+		rendererVTableObj *r = RasterizerOutputFormat->vtable;
+		r->renderTruetypeSymbol(InternalImg, x, y, symbol, style);
+	}
+}
+
+void KmlRenderer::createGroundOverlayNode(char *imageHref)
+{
+	/*
+	<?xml version="1.0" encoding="UTF-8"?>
+	<kml xmlns="http://www.opengis.net/kml/2.2">
+	<GroundOverlay>
+	   <name>GroundOverlay.kml</name>
+	   <color>7fffffff</color>
+	   <drawOrder>1</drawOrder>
+	   <Icon>
+		  <href>http://www.google.com/intl/en/images/logo.gif</href>
+		  <refreshMode>onInterval</refreshMode>
+		  <refreshInterval>86400</refreshInterval>
+		  <viewBoundScale>0.75</viewBoundScale>
+	   </Icon>
+	   <LatLonBox>
+		  <north>37.83234</north>
+		  <south>37.832122</south>
+		  <east>-122.373033</east>
+		  <west>-122.373724</west>
+		  <rotation>45</rotation>
+	   </LatLonBox>
+	</GroundOverlay>
+	</kml>
+	*/
+
+	xmlNodePtr groundOverlayNode = xmlNewChild(DocNode, NULL, BAD_CAST "GroundOverlay", NULL);
+	xmlNewChild(groundOverlayNode, NULL, BAD_CAST "color", BAD_CAST "ffffffff");
+	xmlNewChild(groundOverlayNode, NULL, BAD_CAST "drawOrder", BAD_CAST "1");
+
+	xmlNodePtr iconNode = xmlNewChild(groundOverlayNode, NULL, BAD_CAST "Icon", NULL);
+	xmlNewChild(iconNode, NULL, BAD_CAST "href", BAD_CAST imageHref);
+
+	char crdStr[64];
+	xmlNodePtr latLonBoxNode = xmlNewChild(groundOverlayNode, NULL, BAD_CAST "LatLonBox", NULL);
+	sprintf(crdStr, "%.8f", MapExtent.maxy);
+	xmlNewChild(latLonBoxNode, NULL, BAD_CAST "north", BAD_CAST crdStr);
+
+	sprintf(crdStr, "%.8f", MapExtent.miny);
+	xmlNewChild(latLonBoxNode, NULL, BAD_CAST "south", BAD_CAST crdStr);
+
+	sprintf(crdStr, "%.8f", MapExtent.minx);
+	xmlNewChild(latLonBoxNode, NULL, BAD_CAST "west", BAD_CAST crdStr);
+
+	sprintf(crdStr, "%.8f", MapExtent.maxx);
+	xmlNewChild(latLonBoxNode, NULL, BAD_CAST "east", BAD_CAST crdStr);
+
+	xmlNewChild(latLonBoxNode, NULL, BAD_CAST "rotation", BAD_CAST "0.0");
+}
+
+#endif
\ No newline at end of file

Added: sandbox/davidK/mapkmlrenderer.h
===================================================================
--- sandbox/davidK/mapkmlrenderer.h	                        (rev 0)
+++ sandbox/davidK/mapkmlrenderer.h	2009-07-11 20:51:02 UTC (rev 9167)
@@ -0,0 +1,99 @@
+#ifndef MAPKMLRENDERER_H
+#define MAPKMLRENDERER_H
+
+#if defined(USE_KML) && defined (USE_LIBXML2)
+
+#include "mapserver.h"
+#include "maplibxml2.h"
+
+
+class KmlRenderer
+{
+protected:
+
+    xmlDocPtr	XmlDoc;	/* document pointer */
+	xmlNodePtr	DocNode;
+	xmlNodePtr	LayerNode;
+
+	int			Width, Height;
+
+	hashTableObj *StyleHashTable;
+
+	int			AltitudeMode;
+	int			Tessellate;
+	int			Extrude;
+
+	int			FirstLayer;
+
+	// internal output format containing cairo renderer used for rasterizing and rendering symbols
+	outputFormatObj	*RasterizerOutputFormat;
+	imageObj		*InternalImg;
+
+	rectObj			MapExtent;
+	double			MapCellsize;
+
+	// if true - features are rasterized
+	int	VectorMode;
+
+	// if true - features are written directly in kml
+	int	RasterMode;
+
+	enum altitudeModeEnum { undefined, clampToGround, relativeToGround, absolute };
+
+protected:
+
+	imageObj* createInternalImage();
+	xmlNodePtr createPlacemarkNode(xmlNodePtr parentNode, char *styleUrl);
+	void createGroundOverlayNode(char *imageHref);
+
+	char* lookupPointStyle(colorObj *color);
+	char* lookupLineStyle(strokeStyleObj *strokeStyle);
+	char* lookupPolyStyle(colorObj *color);
+
+	char* lookupSymbolStyle(symbolObj *symbol, symbolStyleObj *style);
+
+	void addCoordsNode(xmlNodePtr parentNode, pointObj *pts, int numPts);
+
+	void setupRenderingParams(hashTableObj *layerMetadata);
+	void addAddRenderingSpecifications(xmlNodePtr node);
+
+	int checkProjection(projectionObj *projection);
+
+	int createIconImage(char *fileName, symbolObj *symbol, symbolStyleObj *style);
+
+	void createSymbolPlacemark(imageObj *img, double x, double y, symbolObj *symbol, symbolStyleObj *style);
+
+	//////////////////////////////////////////////////////////////////////////////
+
+	void renderLineVector(imageObj *img, shapeObj *p, strokeStyleObj *style);
+	void renderPolygonVector(imageObj *img, shapeObj *p, colorObj *color);
+	void renderGlyphsVector(imageObj *img, double x, double y, labelStyleObj *style, char *text);
+
+public:
+
+	KmlRenderer(int width, int height, colorObj* color = NULL);
+	virtual ~KmlRenderer();
+
+    imageObj* createImage(int width, int height, outputFormatObj *format, colorObj* bg);
+    int saveImage(imageObj *img, FILE *fp, outputFormatObj *format);
+    void freeImage(imageObj *image);
+    
+	void startNewLayer(imageObj *img, layerObj *layer);
+	void closeNewLayer(imageObj *img, layerObj *layer);
+
+	void renderLine(imageObj *img, shapeObj *p, strokeStyleObj *style);
+	void renderPolygon(imageObj *img, shapeObj *p, colorObj *color);
+
+	void renderGlyphs(imageObj *img, double x, double y, labelStyleObj *style, char *text);
+
+	// Symbols
+	void renderPixmapSymbol(imageObj *img, double x, double y, symbolObj *symbol, symbolStyleObj *style);
+	void renderVectorSymbol(imageObj *img, double x, double y, symbolObj *symbol, symbolStyleObj *style);
+	void renderEllipseSymbol(imageObj *img, double x, double y, symbolObj *symbol, symbolStyleObj *style);
+	void renderTruetypeSymbol(imageObj *img, double x, double y, symbolObj *symbol, symbolStyleObj *style);
+
+	int getTruetypeTextBBox(imageObj *img,char *font, double size, char *string, rectObj *rect, double **advances);
+};
+
+#endif /* USE_KML && USE_LIBXML2*/
+#endif
\ No newline at end of file



More information about the mapserver-commits mailing list