[mapguide-commits] r1158 - in trunk/MgDev: Common/Stylization Server/src/Services/Kml Server/src/Services/Mapping Server/src/Services/Rendering

svn_mapguide at osgeo.org svn_mapguide at osgeo.org
Tue Mar 6 18:31:19 EST 2007


Author: waltweltonlair
Date: 2007-03-06 18:31:17 -0500 (Tue, 06 Mar 2007)
New Revision: 1158

Added:
   trunk/MgDev/Common/Stylization/RS_FontEngine.cpp
   trunk/MgDev/Common/Stylization/RS_FontEngine.h
   trunk/MgDev/Common/Stylization/SE_Bounds.cpp
   trunk/MgDev/Common/Stylization/SE_Bounds.h
   trunk/MgDev/Common/Stylization/SE_ConvexHull.h
   trunk/MgDev/Common/Stylization/SE_ExpressionBase.cpp
   trunk/MgDev/Common/Stylization/SE_ExpressionBase.h
   trunk/MgDev/Common/Stylization/SE_Include.h
   trunk/MgDev/Common/Stylization/SE_LineBuffer.cpp
   trunk/MgDev/Common/Stylization/SE_LineBuffer.h
   trunk/MgDev/Common/Stylization/SE_Matrix.h
   trunk/MgDev/Common/Stylization/SE_PositioningAlgorithms.cpp
   trunk/MgDev/Common/Stylization/SE_PositioningAlgorithms.h
   trunk/MgDev/Common/Stylization/SE_Renderer.cpp
   trunk/MgDev/Common/Stylization/SE_Renderer.h
   trunk/MgDev/Common/Stylization/SE_StyleVisitor.cpp
   trunk/MgDev/Common/Stylization/SE_StyleVisitor.h
   trunk/MgDev/Common/Stylization/SE_SymbolManager.h
   trunk/MgDev/Common/Stylization/StylizationEngine.cpp
   trunk/MgDev/Common/Stylization/StylizationEngine.h
   trunk/MgDev/Server/src/Services/Mapping/SEMgSymbolManager.cpp
   trunk/MgDev/Server/src/Services/Mapping/SEMgSymbolManager.h
Modified:
   trunk/MgDev/Common/Stylization/DefaultStylizer.cpp
   trunk/MgDev/Common/Stylization/DefaultStylizer.h
   trunk/MgDev/Common/Stylization/GDRenderer.cpp
   trunk/MgDev/Common/Stylization/GDRenderer.h
   trunk/MgDev/Common/Stylization/LabelRenderer.cpp
   trunk/MgDev/Common/Stylization/LabelRenderer.h
   trunk/MgDev/Common/Stylization/LabelRendererBase.cpp
   trunk/MgDev/Common/Stylization/LabelRendererBase.h
   trunk/MgDev/Common/Stylization/LabelRendererLocal.cpp
   trunk/MgDev/Common/Stylization/LabelRendererLocal.h
   trunk/MgDev/Common/Stylization/LineBuffer.cpp
   trunk/MgDev/Common/Stylization/LineBuffer.h
   trunk/MgDev/Common/Stylization/Makefile.am
   trunk/MgDev/Common/Stylization/RendererStyles.h
   trunk/MgDev/Common/Stylization/SimpleOverpost.cpp
   trunk/MgDev/Common/Stylization/SimpleOverpost.h
   trunk/MgDev/Common/Stylization/Stylization.h
   trunk/MgDev/Common/Stylization/Stylization.vcproj
   trunk/MgDev/Common/Stylization/Stylizer.h
   trunk/MgDev/Common/Stylization/SymbolVisitor.h
   trunk/MgDev/Common/Stylization/stdafx.h
   trunk/MgDev/Server/src/Services/Kml/ServerKmlService.cpp
   trunk/MgDev/Server/src/Services/Mapping/Makefile.am
   trunk/MgDev/Server/src/Services/Mapping/RSMgFeatureReader.cpp
   trunk/MgDev/Server/src/Services/Mapping/RSMgFeatureReader.h
   trunk/MgDev/Server/src/Services/Mapping/ServerMappingService.vcproj
   trunk/MgDev/Server/src/Services/Mapping/ServerMappingServiceBuild.cpp
   trunk/MgDev/Server/src/Services/Mapping/StylizationUtil.cpp
   trunk/MgDev/Server/src/Services/Mapping/StylizationUtil.h
   trunk/MgDev/Server/src/Services/Rendering/ServerRenderingService.cpp
Log:
Symbology submission - this merges in changes from the branched area we've
been working in.  This is a work-in-progress.  Some stylization functionality
may temporarily be broken.


Modified: trunk/MgDev/Common/Stylization/DefaultStylizer.cpp
===================================================================
--- trunk/MgDev/Common/Stylization/DefaultStylizer.cpp	2007-03-06 17:02:52 UTC (rev 1157)
+++ trunk/MgDev/Common/Stylization/DefaultStylizer.cpp	2007-03-06 23:31:17 UTC (rev 1158)
@@ -25,7 +25,9 @@
 #include "FilterExecutor.h"
 #include "Renderer.h"
 #include "LineBuffer.h"
+#include "StylizationEngine.h"
 #include "FeatureTypeStyleVisitor.h"
+#include "SE_Renderer.h"
 
 const RS_String s_Empty(L"");
 
@@ -34,6 +36,7 @@
     m_lbPool = new LineBufferPool;
     m_pRasterAdapter = NULL;
     m_renderer = NULL;
+    m_styleEngine = NULL;
 }
 
 DefaultStylizer::~DefaultStylizer()
@@ -44,6 +47,7 @@
     ClearAdapters();
 
     delete m_lbPool;
+    delete m_styleEngine;
 }
 
 
@@ -52,9 +56,13 @@
 //
 // Input: A pointer to a Renderer implementation instance
 //-----------------------------------------------------------------------------
-void DefaultStylizer::Initialize(Renderer* renderer)
+void DefaultStylizer::Initialize(Renderer* renderer, SE_SymbolManager* sman)
 {
     m_renderer = renderer;
+
+    if (m_styleEngine)
+        delete m_styleEngine;
+    m_styleEngine = new StylizationEngine(sman);
 }
 
 
@@ -106,7 +114,7 @@
     const RS_String& layerId = (layerInfo != NULL)? layerInfo->guid() : s_Empty;
     const RS_String& featCls = (featInfo != NULL)? featInfo->name() : s_Empty;
     exec->SetMapLayerInfo(session, mapName, layerId, featCls);
-    
+
     // find the FeatureTypeStyle
     MdfModel::FeatureTypeStyleCollection* ftsc = range->GetFeatureTypeStyles();
 
@@ -118,6 +126,17 @@
     if (lr_tooltip->empty()) lr_tooltip = NULL;
     if (lr_url->empty()) lr_url = NULL;
 
+    //TODO: //HACK: temporary code to detect whether we are using a new style
+    //composite symbolizations
+    bool use_style_engine = false;
+    SE_Renderer* se_renderer = NULL;
+
+    if (FeatureTypeStyleVisitor::DetermineFeatureTypeStyle(ftsc->GetAt(0)) == FeatureTypeStyleVisitor::ftsComposite)
+    {
+        use_style_engine = true;
+        se_renderer = dynamic_cast<SE_Renderer*>(m_renderer);
+    }
+
     //TODO:
     //*****************************************
     //* THIS CALL IS REALLY REALLY REALLY SLOW!!!
@@ -126,8 +145,6 @@
     //but is so horribly slow that in all other cases it needs to be optimized away
     //FdoPtr<FdoClassDefinition> concreteClass = features->GetClassDefinition();
 
-    FeatureTypeStyleVisitor visitor;
-
     bool bClip = m_renderer->RequiresClipping();
 
     #ifdef _DEBUG
@@ -179,15 +196,24 @@
         {
             MdfModel::FeatureTypeStyle* fts = ftsc->GetAt(i);
 
-            //TODO: future enhancement:
-            //If we have a stylizer that works on a specific feature class
-            //we should invoke it here, instead of invoking the
-            //generic stylizer for the particular type of geomtry
-            GeometryAdapter* adapter = FindGeomAdapter(lb->geom_type());
+            if (use_style_engine)
+            {
+                //we are hoping that the renderer is nice enough to be an SE_Renderer
+                if (se_renderer)
+                    m_styleEngine->Stylize(se_renderer, features, exec, lb, (CompositeTypeStyle*)fts);
+            }
+            else
+            {
+                //TODO: future enhancement:
+                //If we have a stylizer that works on a specific feature class
+                //we should invoke it here, instead of invoking the
+                //generic stylizer for the particular type of geomtry
+                GeometryAdapter* adapter = FindGeomAdapter(lb->geom_type());
 
-            //if we know how to stylize this type of geometry, then go ahead
-            if (adapter)
-                adapter->Stylize(m_renderer, features, exec, lb, fts, lr_tooltip, lr_url);
+                //if we know how to stylize this type of geometry, then go ahead
+                if (adapter)
+                    adapter->Stylize(m_renderer, features, exec, lb, fts, lr_tooltip, lr_url);
+            }
         }
 
         if (lb)
@@ -207,6 +233,7 @@
     //need to get rid of these since they cache per layer theming information
     //which may conflict with the next layer
     ClearAdapters();
+    m_styleEngine->ClearCache();
 }
 
 

Modified: trunk/MgDev/Common/Stylization/DefaultStylizer.h
===================================================================
--- trunk/MgDev/Common/Stylization/DefaultStylizer.h	2007-03-06 17:02:52 UTC (rev 1157)
+++ trunk/MgDev/Common/Stylization/DefaultStylizer.h	2007-03-06 23:31:17 UTC (rev 1158)
@@ -19,6 +19,7 @@
 
 class LineBufferPool;
 class RasterAdapter;
+class StylizationEngine;
 
 //-----------------------------------------------------------------------------
 // Stylizer used for all types of layers which do not have special
@@ -30,9 +31,8 @@
     STYLIZATION_API DefaultStylizer();
     STYLIZATION_API virtual ~DefaultStylizer();
 
-    STYLIZATION_API virtual void Initialize(Renderer* renderer);
+    STYLIZATION_API virtual void Initialize(Renderer* renderer, SE_SymbolManager* sman = NULL);
 
-
     STYLIZATION_API virtual void StylizeFeatures( const MdfModel::VectorLayerDefinition* layer,
                                                       RS_FeatureReader* features,
                                                       CSysTransformer*  xformer, //can be NULL
@@ -48,7 +48,6 @@
                                      void*                                userData
                                      );
 
-
     STYLIZATION_API virtual void StylizeDrawingLayer(   const MdfModel::DrawingLayerDefinition* layer,
                                                         RS_LayerUIInfo*         legendInfo,
                                                         RS_InputStream*         dwfin,
@@ -63,7 +62,6 @@
                                                      GeometryAdapter* sg);
 
 private:
-
     GeometryAdapter* FindGeomAdapter(int geomType);
     void ClearAdapters();
 
@@ -73,6 +71,9 @@
     //raster stylizer
     RasterAdapter* m_pRasterAdapter;
 
+    //composite stylizer
+    StylizationEngine* m_styleEngine;
+
     //TODO feature class stylizers
 
     Renderer* m_renderer;

Modified: trunk/MgDev/Common/Stylization/GDRenderer.cpp
===================================================================
--- trunk/MgDev/Common/Stylization/GDRenderer.cpp	2007-03-06 17:02:52 UTC (rev 1157)
+++ trunk/MgDev/Common/Stylization/GDRenderer.cpp	2007-03-06 23:31:17 UTC (rev 1158)
@@ -157,9 +157,9 @@
         gdImageColorTransparent(img, bgc);
 
     if (!m_bLocalOverposting)
-        m_labeler = new LabelRenderer(this);
+        m_labeler = new LabelRenderer(this, this);
     else
-        m_labeler = new LabelRendererLocal(this, tileExtentOffset);
+        m_labeler = new LabelRendererLocal(this, this, tileExtentOffset);
 
     m_polyrasterizer = new complex_polygon_gd();
 }
@@ -186,6 +186,7 @@
     Save(filename, format, m_width, m_height);
 }
 
+
 void GDRenderer::Save(const RS_String& filename, const RS_String& format, int width, int height)
 {
     //get the in-memory image stream
@@ -337,20 +338,10 @@
     if (arDisplay > arMap)
     {
         m_scale = (double)m_height / m_extents.height();
-
-    //    //compute margin required on the left and right
-    //    double pxwidth = arMap * (double)m_height;
-    //    double margin = 0.5 * (m_width - pxwidth);
-    //    proxy()->m_device.set_configure ("Window Origin", HT_Option_Value((int)margin, (int)0));
     }
     else
     {
         m_scale = (double)(m_width) / m_extents.width();
-
-    //    //compute margin required on top and bottom
-    //    double pxheight = arMap / (double)m_width;
-    //    double margin = 0.5 * (m_height - pxheight);
-    //    proxy()->m_device.set_configure ("Window Origin", HT_Option_Value((int)0, (int)margin));
     }
 
     m_offsetX = m_extents.minx;
@@ -368,6 +359,9 @@
 
     // remember the map info
     m_mapInfo = mapInfo;
+
+    // do it here, since we will need the renderer's map scales, which are computed above
+    InitFontEngine(this, this);
 }
 
 
@@ -400,7 +394,7 @@
 
 void GDRenderer::StartFeature(RS_FeatureReader* /*feature*/,
                               const RS_String* /*tooltip*/,
-                              const RS_String* /*url*/, 
+                              const RS_String* /*url*/,
                               const RS_String* /*theme*/ )
 {
 }
@@ -436,7 +430,7 @@
         }
 
         //call the new rasterizer
-        m_polyrasterizer->FillPolygon((Point*)m_wtPointBuffer, workbuffer->point_count(), workbuffer->cntrs(), workbuffer->cntr_count(), 
+        m_polyrasterizer->FillPolygon((Point*)m_wtPointBuffer, workbuffer->point_count(), workbuffer->cntrs(), workbuffer->cntr_count(),
             (fillpat) ? gdTiled : gdc, (gdImagePtr)m_imout);
 
         if (fillpat)
@@ -519,53 +513,13 @@
                                int width, int height,
                                RS_Bounds extents)
 {
-    int minx = _TX(extents.minx);
-    int maxx = _TX(extents.maxx);
+    double cx = (extents.minx + extents.maxx) * 0.5;
+    double cy = (extents.miny + extents.maxy) * 0.5;
+    WorldToScreenPoint(cx, cy, cx, cy);
 
-    //note reversal of min and max when going from mapping to screen space
-    int miny = _TY(extents.maxy);
-    int maxy = _TY(extents.miny);
-
-    if (format == RS_ImageFormat_RGBA)
-    {
-        gdImagePtr src = gdImageCreateTrueColor(width, height);
-
-        //TODO: figure out a way to do this without copying the whole thing
-        //in such a lame loop
-        //at least here we don't call gdImageSetPixel for every pixel
-        for (int j=0; j<height; j++)
-        {
-            for (int i=0; i<width; i++)
-            {
-                int srccol = ((int*)data)[i + j * width];
-                //compute GD alpha and reverse b and r
-                int col = gdImageColorAllocateAlpha(src,  srccol        & 0xFF,
-                                                         (srccol >> 8)  & 0XFF,
-                                                         (srccol >> 16) & 0xFF,
-                                                         127 - ((srccol >> 24) & 0xFF)/ 2);
-
-                src->tpixels[j][i] = col;
-            }
-        }
-
-        gdImageCopyResampled((gdImagePtr)m_imout, src,
-                             minx, miny, 0, 0,
-                             maxx-minx, maxy-miny, //TODO: do we need +1?
-                             gdImageSX(src), gdImageSY(src));
-
-        gdImageDestroy(src);
-    }
-    else if (format == RS_ImageFormat_PNG)
-    {
-        gdImagePtr src = gdImageCreateFromPngPtr(length, data);
-
-        gdImageCopyResampled((gdImagePtr)m_imout, src,
-                             minx, miny, 0, 0,
-                             maxx-minx, maxy-miny,
-                             gdImageSX(src), gdImageSY(src));
-
-        gdImageDestroy(src);
-    }
+    //pass to the screen space render function
+    DrawScreenRaster(data, length, format, width, height, 
+        cx, cy, extents.width() * m_scale, extents.height() * m_scale, 0.0);
 }
 
 
@@ -573,7 +527,6 @@
 {
     RS_MarkerDef use_mdef = mdef;
 
-
     //use the selection style to draw
     if (m_bSelectionMode)
            use_mdef = RS_MarkerDef( mdef.width(),
@@ -588,7 +541,7 @@
     {
         //if marker is processed from here it should be added to the
         //feature W2D, not the labeling W2D -- need the API to reflect that.
-		ProcessOneMarker(srclb->points()[2*i], srclb->points()[2*i+1], use_mdef, allowOverpost, (i==0) ? bounds : NULL);
+        ProcessOneMarker(srclb->points()[2*i], srclb->points()[2*i+1], use_mdef, allowOverpost, (i==0) ? bounds : NULL);
     }
 }
 
@@ -788,14 +741,14 @@
                     int superh = imsymh;
 
                     //if it is too small, make it bigger
-                    //so that we get an antialiased effect -- only 
+                    //so that we get an antialiased effect -- only
                     //do this for SLD symbols since DWF symbols are too
                     //varied and not all of them look good with smoothing applied
                     if (!symbol && superw < SYMBOL_BITMAP_SIZE/2 && superh < SYMBOL_BITMAP_SIZE/2)
                         superw = superh = SYMBOL_BITMAP_SIZE;
 
                     gdImagePtr tmp = gdImageCreateTrueColor(superw, superh);
-                    
+
                     //transform to coordinates of temporary image where we
                     //draw symbol before transfering to the map
                     EnsureBufferSize(npts);
@@ -823,7 +776,7 @@
                         RS_Color red(255, 0, 0, 255);
                         gdImagePtr brush1 = rs_gdImageThickLineBrush(rs_min(superw, superh) / 17, red);
                         gdImageSetBrush((gdImagePtr)tmp, brush1);
-                        
+
                         gdImageOpenPolygon((gdImagePtr)tmp, (gdPointPtr)pts, npts, gdBrushed);
 
                         gdImageSetBrush(tmp, NULL);
@@ -845,7 +798,6 @@
 
                         gdImageSetBrush(tmp, NULL);
                         gdImageDestroy(brush1);
-
                     }
 
                     // initialize the real cached symbol image to a transparent background
@@ -854,11 +806,10 @@
                     gdImageAlphaBlending((gdImagePtr)m_imsym, 1);
 
                     //resample the supersampled temporary image into the cached image
-                    gdImageCopyResampled((gdImagePtr)m_imsym, tmp, 0, 0, 0, 0, 
+                    gdImageCopyResampled((gdImagePtr)m_imsym, tmp, 0, 0, 0, 0,
                         imsymw, imsymh, superw, superh);
 
                     gdImageDestroy(tmp);
-
                 }
                 else
                 {
@@ -923,7 +874,7 @@
 
                     //we will use unrotated symbol bounding box
                     //since rotation will be done by the image copy
-                    //also we will use a slight boundary offset 
+                    //also we will use a slight boundary offset
                     //hardcoded to 1 pixel so that geometry exactly on the edge
                     //draws just inside the image
                     RS_Bounds dst1(1, 1, (double)(imsymw-1), (double)(imsymh-1));
@@ -955,7 +906,6 @@
                 m_bIsSymbolW2D = false;
                 m_imw2d = NULL;
             }
-
         }
 
         if (m_imsym)
@@ -987,8 +937,7 @@
                 trans.TransformPoint(b[i].x, b[i].y);
 
                 //world to screen space
-                b[i].x = _TXD(b[i].x);
-                b[i].y = _TYD(b[i].y);
+                WorldToScreenPoint(b[i].x, b[i].y, b[i].x, b[i].y);
             }
 
             //copy symbol image into destination image
@@ -1019,9 +968,7 @@
                 //straight copy without resampling since we are
                 //guaranteed for the source image size to equal the
                 //symbol pixel size
-                gdImageCopy(tmp, (gdImagePtr)m_imsym,
-                                     1, 1, 0, 0,
-                                     imsymw, imsymh);
+                gdImageCopy(tmp, (gdImagePtr)m_imsym, 1, 1, 0, 0, imsymw, imsymh);
 
                 //for rotated gd copy, we need the midpoint of
                 //the destination bounds
@@ -1080,16 +1027,17 @@
         m_labeler->AddExclusionRegion(pts, 4);
     }
 
-	//set actual (unrotated) bounds with new insertion point if a pointer was passed in
-	if (bounds)
-	{
-		bounds->minx = -refX * mdef.width();
-		bounds->maxx = (1.0 - refX) * mdef.width();
-		bounds->miny = -refY * mdef.height();
-		bounds->maxy = (1.0 - refY) * mdef.height();
-	}
+    //set actual (unrotated) bounds with new insertion point if a pointer was passed in
+    if (bounds)
+    {
+        bounds->minx = -refX * mdef.width();
+        bounds->maxx = (1.0 - refX) * mdef.width();
+        bounds->miny = -refY * mdef.height();
+        bounds->maxy = (1.0 - refY) * mdef.height();
+    }
 }
 
+
 void GDRenderer::ProcessLabel(double x, double y, const RS_String& text, RS_TextDef& tdef)
 {
     //check if we are rendering a selection -- bail if so
@@ -1247,31 +1195,7 @@
     return m_height-1 - (int)floor((y - m_offsetY) * m_scale);
 }
 
-//transforms an x coordinate from mapping to screen space
-double GDRenderer::_TXD(double x)
-{
-    return (x - m_offsetX) * m_scale;
-}
 
-//transforms a y coordinate from mapping to screen space
-double GDRenderer::_TYD(double y)
-{
-    return m_height - 1 - (y - m_offsetY) * m_scale;
-}
-
-//transforms an x coordinate from screen to mapping space
-double GDRenderer::_ITXD(double x)
-{
-    return x * m_invScale + m_offsetX;
-}
-
-//transforms a y coordinate from screen to mapping space
-double GDRenderer::_ITYD(double y)
-{
-    return m_offsetY - (y + 1.0 - m_height) * m_invScale;
-}
-
-
 //transforms an array of input mapping space points
 //into W2D coordinates and places them in the DWF
 //point buffer m_wtPointBuffer
@@ -1578,18 +1502,32 @@
 // Text drawing
 //////////////////////////////////////////////////////////////////////////////
 
+//////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////
+// RS_FontEngine implementation
+//////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////
+
 //////////////////////////////////////////////////////////////////////////////
-void GDRenderer::DrawString( const RS_String& s,
-                                int              x,
-                                int              y,
-                                double           height,
-                                const RS_Font*   font,
-                                const RS_Color&  color,
-                                double           angle)
+void GDRenderer::DrawString(const RS_String& s,
+                            int              x,
+                            int              y,
+                            double           height,
+                            const RS_Font*   font,
+                            const RS_Color&  color,
+                            double           angle)
 {
     if (font == NULL)
         return;
 
+    //gd likes height in points rather than pixels
+    height *= 72.0 / m_dpi;
+
+    // The computed height can have roundoff in it, and the rendering code is
+    // very sensitive to it.  Remove this roundoff by rounding the height to
+    // the nearest 1/65536ths of a point.
+    height = floor(height * 65536.0 + 0.5) / 65536.0;
+
     size_t len = s.length();
     size_t lenbytes = len*4+1;
     char* sutf8 = (char*)alloca(lenbytes);
@@ -1617,12 +1555,20 @@
 
 //////////////////////////////////////////////////////////////////////////////
 void GDRenderer::MeasureString(const RS_String&  s,
-                                  double            height,
-                                  const RS_Font*    font,
-                                  double            angle,
-                                  RS_F_Point*       res, //assumes 4 points in this array
-                                  float*            offsets) //assumes length equals 2 * length of string
+                               double            height,
+                               const RS_Font*    font,
+                               double            angle,
+                               RS_F_Point*       res, //assumes 4 points in this array
+                               float*            offsets) //assumes length equals 2 * length of string
 {
+    //gd likes height in points rather than pixels
+    height *= 72.0 / m_dpi;
+
+    // The computed height can have roundoff in it, and the rendering code is
+    // very sensitive to it.  Remove this roundoff by rounding the height to
+    // the nearest 1/65536ths of a point.
+    height = floor(height * 65536.0 + 0.5) / 65536.0;
+
     size_t len = s.length();
     size_t lenbytes = len*4+1;
     char* sutf8 = (char*)alloca(lenbytes);
@@ -1666,22 +1612,11 @@
 }
 
 
-//////////////////////////////////////////////////////////////////////////////
-const RS_Font* GDRenderer::FindFont(RS_FontDef& def)
-{
-    return FontManager::Instance()->FindFont(def.name().c_str(),
-                          (def.style() & RS_FontStyle_Bold) != 0,
-                          (def.style() & RS_FontStyle_Italic) != 0);
-}
-
-
 //////////////////////////////////////////////////////////////
 //////////////////////////////////////////////////////////////
 ////
-////
 ////             DWF Rewrite and related code
 ////
-////
 //////////////////////////////////////////////////////////////
 //////////////////////////////////////////////////////////////
 
@@ -2174,9 +2109,288 @@
 //////////////////////////////////////////////////////////////
 //////////////////////////////////////////////////////////////
 ////
-////
 ////      END of DWF Rewrite and related code
 ////
-////
 //////////////////////////////////////////////////////////////
 //////////////////////////////////////////////////////////////
+
+
+//////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////
+// SE_Renderer implementation
+/////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////
+
+
+void GDRenderer::_TransferPoints(double* src, int numpts)
+{
+    EnsureBufferSize(numpts);
+    int* pts = (int*)m_wtPointBuffer;
+    for (int i=0; i<numpts; i++)
+    {
+        *pts++ = (int)(*src);
+        src++;
+        *pts++ = (int)(*src);
+        src++;
+    }
+}
+
+
+//copied from WritePolylines, except it doesn't do to screen trasnform -- we should refactor.
+void GDRenderer::DrawScreenPolyline(SE_Geometry& geom, unsigned int color, double weightpx)
+{
+    RS_Color c((color >> 16) & 0xFF, (color >> 8) & 0xFF, color & 0xFF, (color >> 24) & 0xFF);
+
+    int gdc = ConvertColor((gdImagePtr)m_imout, c);
+    gdImageSetAntiAliased((gdImagePtr)m_imout, gdc);
+
+    //line width is always device space and units are meters.
+    //so convert to equivalent pixel width
+    int line_weight = (int)weightpx;
+
+    gdImagePtr brush1 = NULL;
+
+    if (line_weight > 1)
+    {
+        brush1 = rs_gdImageThickLineBrush(line_weight, c);
+    }
+
+    //draw the lines
+    int index = 0;
+
+    for (int i=0; i<geom.n_cntrs; i++)
+    {
+        int cntr_size = geom.contours[i];
+
+        //convert to integer coords
+        _TransferPoints(geom.points + index, cntr_size);
+
+        if (cntr_size > 1)
+        {
+            //draw antialiased only if thickness is single pixel
+            if (line_weight <= 1)
+                gdImageOpenPolygon((gdImagePtr)m_imout, (gdPointPtr)m_wtPointBuffer, cntr_size, gdAntiAliased/*gdc*/);
+            else
+            {
+                gdImageSetBrush((gdImagePtr)m_imout, brush1);
+                gdImageOpenPolygon((gdImagePtr)m_imout, (gdPointPtr)m_wtPointBuffer, cntr_size, brush1 ? gdBrushed : gdc);
+            }
+        }
+
+        index += 2*cntr_size;
+    }
+
+    //unset the stroke
+    gdImageSetBrush((gdImagePtr)m_imout, NULL);
+
+    if (brush1)
+        gdImageDestroy(brush1);
+}
+
+
+void GDRenderer::DrawScreenPolygon(SE_Geometry& geom, unsigned int color)
+{
+    RS_Color c((color >> 16) & 0xFF, (color >> 8) & 0xFF, color & 0xFF, (color >> 24) & 0xFF);
+
+    if (geom.n_pts == 0)
+        return;
+
+    if (c.alpha() != 0)
+    {
+        int gdc = ConvertColor((gdImagePtr)m_imout, c);
+
+        gdImagePtr fillpat = NULL;
+
+        //TODO: do the device space calls need fill pattern support?
+        /*
+        if (wcscmp(use_fill->pattern().c_str(), L"Solid") != 0)
+        {
+            fillpat = GDFillPatterns::CreatePatternBitmap(use_fill->pattern().c_str(), gdc, gdcbg);
+            gdImageSetTile((gdImagePtr)m_imout, fillpat);
+        }
+        */
+
+        _TransferPoints(geom.points, geom.n_pts);
+
+        //call the new rasterizer
+        m_polyrasterizer->FillPolygon((Point*)m_wtPointBuffer, geom.n_pts, geom.contours, geom.n_cntrs,
+            (fillpat) ? gdTiled : gdc, (gdImagePtr)m_imout);
+
+        /*
+        if (fillpat)
+        {
+            gdImageSetTile((gdImagePtr)m_imout, NULL);
+            gdImageDestroy(fillpat);
+        }
+        */
+    }
+}
+
+
+void GDRenderer::GetWorldToScreenTransform(SE_Matrix& xform)
+{
+    xform.x0 = m_scale;
+    xform.x1 = 0.0;
+    xform.x2 = - m_offsetX * m_scale;
+    xform.y0 = 0.0;
+    xform.y1 = - m_scale;
+    xform.y2 = m_height - 1 + m_offsetY * m_scale;
+}
+
+
+void GDRenderer::WorldToScreenPoint(double& inx, double& iny, double& ox, double& oy)
+{
+    //TODO: assumes no rotation of the viewport
+    ox = (inx - m_offsetX) * m_scale;
+    oy = m_height - 1 - (iny - m_offsetY) * m_scale;
+}
+
+
+void GDRenderer::ScreenToWorldPoint(double& inx, double& iny, double& ox, double& oy)
+{
+    //TODO: assumes no rotation of the viewport
+    ox = inx * m_invScale + m_offsetX;
+    oy = m_offsetY - (iny + 1.0 - m_height) * m_invScale;
+}
+
+
+double GDRenderer::GetPixelsPerMillimeterScreen()
+{
+    return m_dpi / 25.4;
+}
+
+
+double GDRenderer::GetPixelsPerMillimeterWorld()
+{
+    //TODO: check if this is right, could try
+    return m_dpi / 25.4 * m_mapScale;
+}
+
+RS_FontEngine* GDRenderer::GetFontEngine()
+{
+    return this;
+}
+
+//labeling -- this is the entry API for adding SE labels
+//to the label mananger
+void GDRenderer::ProcessLabelGroup(SE_LabelInfo*    labels,
+                                   int              nlabels,
+                                   RS_OverpostType  type,
+                                   bool             exclude,
+                                   SE_Geometry*      path)
+{
+    //pass labels to the label renderer here
+
+    //check if we are rendering a selection -- bail if so
+    if (m_bSelectionMode)
+        return;
+
+    //forward it to the label renderer
+    m_labeler->ProcessLabelGroup(labels, nlabels, type, exclude, path);
+}
+
+
+void GDRenderer::DrawScreenRaster(unsigned char* data, int length, RS_ImageFormat format, int native_width, int native_height, 
+        double x, double y, double w, double h, double angledeg)
+{
+    if (format == RS_ImageFormat_RGBA)
+    {
+        gdImagePtr src = gdImageCreateTrueColor(native_width, native_height);
+
+        //TODO: figure out a way to do this without copying the whole thing
+        //in such a lame loop
+        //at least here we don't call gdImageSetPixel for every pixel
+        for (int j=0; j<native_height; j++)
+        {
+            for (int i=0; i<native_width; i++)
+            {
+                int srccol = ((int*)data)[i + j * native_width];
+                //compute GD alpha and reverse b and r
+                int col = gdImageColorAllocateAlpha(src,  srccol        & 0xFF,
+                                                         (srccol >> 8)  & 0XFF,
+                                                         (srccol >> 16) & 0xFF,
+                                                         127 - ((srccol >> 24) & 0xFF)/ 2);
+
+                src->tpixels[j][i] = col;
+            }
+        }
+
+        if (angledeg == 0)
+        {
+            double w2 = w * 0.5;
+            double h2 = h * 0.5;
+
+            int minx = ROUND(x - w2);
+            int maxx = ROUND(x + w2);
+            int miny = ROUND(y - h2);
+            int maxy = ROUND(y + h2);
+
+            gdImageCopyResampled((gdImagePtr)m_imout, src,
+                                 minx, miny, 0, 0,
+                                 maxx-minx, maxy-miny, //TODO: do we need +1?
+                                 gdImageSX(src), gdImageSY(src));
+        }
+        else
+        {
+            //TODO: must scale from native width/height to requested width/height
+
+            gdImageCopyRotated((gdImagePtr)m_imout, src,
+                                   x, y, 0, 0, native_width, native_height, (int)angledeg);
+        }
+
+        gdImageDestroy(src);
+    }
+    else if (format == RS_ImageFormat_PNG)
+    {
+        //note width and height arguments are ignored for PNG, since they are encoded
+        //in the png data array
+
+        gdImagePtr src = gdImageCreateFromPngPtr(length, data);
+
+        if (angledeg == 0)
+        {
+            double w2 = w * 0.5;
+            double h2 = h * 0.5;
+
+            int minx = ROUND(x - w2);
+            int maxx = ROUND(x + w2);
+            int miny = ROUND(y - h2);
+            int maxy = ROUND(y + h2);
+
+            gdImageCopyResampled((gdImagePtr)m_imout, src,
+                                 minx, miny, 0, 0,
+                                 maxx-minx, maxy-miny,
+                                 gdImageSX(src), gdImageSY(src));
+        }
+        else
+        {
+            //TODO: must scale from native width/height to requested width/height
+
+            gdImageCopyRotated((gdImagePtr)m_imout, src,
+                                   x, y, 0, 0, gdImageSX(src), gdImageSY(src), (int)angledeg);
+        }
+
+        gdImageDestroy(src);
+    }
+    else
+        throw "Well implement this already!";
+}
+
+
+void GDRenderer::DrawScreenText(const RS_String& txt, RS_TextDef& tdef, double insx, double insy, double* path, int npts, double param_position)
+{
+    if (path)  //path text
+    {
+        RS_TextMetrics tm;
+        GetTextMetrics(txt, tdef, tm, true);
+        //TODO: need computed seglens rather than NULL to make things faster
+        LayoutPathText(tm, (RS_F_Point*)path, npts, NULL, param_position, tdef.valign(), 0);
+        DrawPathText(tm, tdef);
+    }
+    else //block text
+    {
+        RS_TextMetrics tm;
+        GetTextMetrics(txt, tdef, tm, false);
+        DrawBlockText(tm, tdef, insx, insy);
+    }
+}

Modified: trunk/MgDev/Common/Stylization/GDRenderer.h
===================================================================
--- trunk/MgDev/Common/Stylization/GDRenderer.h	2007-03-06 17:02:52 UTC (rev 1157)
+++ trunk/MgDev/Common/Stylization/GDRenderer.h	2007-03-06 23:31:17 UTC (rev 1158)
@@ -33,6 +33,9 @@
 #include "LabelRendererBase.h"
 #include "RS_ByteData.h"
 
+#include "SE_Renderer.h"
+#include "RS_FontEngine.h"
+
 class WT_File;
 class WT_Viewport;
 class WT_Logical_Point;
@@ -40,8 +43,9 @@
 struct RS_Font;
 
 class complex_polygon_gd;
+class FontEngine;
 
-class GDRenderer : public Renderer
+class GDRenderer : public Renderer, public SE_Renderer, public RS_FontEngine
 {
     friend class LabelRenderer;
     friend class LabelRendererBase;
@@ -75,7 +79,7 @@
 
     STYLIZATION_API virtual void StartFeature(RS_FeatureReader* feature,
                                               const RS_String*  tooltip = NULL,
-                                              const RS_String*  url = NULL, 
+                                              const RS_String*  url = NULL,
                                               const RS_String* theme = NULL);
 
     STYLIZATION_API virtual void ProcessPolygon(LineBuffer* lb, RS_FillStyle& fill);
@@ -138,8 +142,33 @@
 
     STYLIZATION_API void SetRenderSelectionMode(bool mode);
 
+    ////////////////////////////////////////////////
+    // SE_Renderer
+    //
+    virtual void DrawScreenPolyline(SE_Geometry& geom, unsigned int color, double weight); // px
+    virtual void DrawScreenPolygon(SE_Geometry& geom, unsigned int fill);
+    virtual void DrawScreenRaster(unsigned char* data, int length, RS_ImageFormat format, int native_width, int native_height, 
+        double x, double y, double w, double h, double angledeg);
+    virtual void DrawScreenText(const RS_String& txt, RS_TextDef& tdef, double insx, double insy, double* path, int npts, double param_position);
 
-    void DrawString(const RS_String& s,
+    virtual void GetWorldToScreenTransform(SE_Matrix& xform);
+    virtual void WorldToScreenPoint(double& inx, double& iny, double& ox, double& oy);
+    virtual void ScreenToWorldPoint(double& inx, double& iny, double& ox, double& oy);
+
+    virtual double GetPixelsPerMillimeterScreen();
+    virtual double GetPixelsPerMillimeterWorld();
+
+    virtual RS_FontEngine* GetFontEngine();
+
+    //labeling -- this is the entry API for adding SE labels
+    //to the label mananger
+    virtual void ProcessLabelGroup(SE_LabelInfo*    labels,
+                                   int              nlabels,
+                                   RS_OverpostType  type,
+                                   bool             exclude,
+                                   SE_Geometry*      path = NULL);
+
+    virtual void DrawString(const RS_String& s,
                     int              x,
                     int              y,
                     double           height,
@@ -147,18 +176,14 @@
                     const RS_Color&  color,
                     double           angle);
 
-    void MeasureString(const RS_String& s,
+    virtual void MeasureString(const RS_String& s,
                        double           height,
                        const RS_Font*   font,
                        double           angle,
                        RS_F_Point*      res,
                        float*           offsets);
 
-    const RS_Font* FindFont(RS_FontDef& def);
-
-
 private:
-
     double _MeterToMapSize(RS_Units unit, double number);
     double _PixelToMapSize(Renderer* renderer, int pixels);
 
@@ -171,12 +196,9 @@
     //transformation from mapping to W2D space
     inline int _TX(double x);
     inline int _TY(double y);
-    double _TXD(double x);
-    double _TYD(double y);
-    double _ITXD(double x);
-    double _ITYD(double y);
 
     void _TransformPointsNoClamp(double* inpts, int numpts);
+    void _TransferPoints(double* inpts, int numpts);
 
     RS_Color m_bgcolor;
     RS_Bounds m_extents;
@@ -210,6 +232,8 @@
 
     LabelRendererBase* m_labeler;
 
+    FontEngine* m_fe;
+
     /////////////////////////////////////////////////////////
     //
     // Functions and structures used during insertion of W2Ds
@@ -220,7 +244,6 @@
     // all of the W2D rewriting context
 
 public:
-
     /*Do not export from DLL*/ void* GetImage() { return m_imout; } //target map image
     /*Do not export from DLL*/ void* GetW2DTargetImage() { return m_imw2d; } //target image for W2D rewriter
     /*Do not export from DLL*/ bool IsViewportSet() { return m_bHaveViewport; }

Modified: trunk/MgDev/Common/Stylization/LabelRenderer.cpp
===================================================================
--- trunk/MgDev/Common/Stylization/LabelRenderer.cpp	2007-03-06 17:02:52 UTC (rev 1157)
+++ trunk/MgDev/Common/Stylization/LabelRenderer.cpp	2007-03-06 23:31:17 UTC (rev 1158)
@@ -21,6 +21,10 @@
 #include "GDRenderer.h"
 #include "GDUtils.h"
 #include "RS_Font.h"
+#include "SE_Include.h"
+#include "SE_Bounds.h"
+#include "SE_Renderer.h"
+#include "RS_FontEngine.h"
 
 #define M_PI 3.14159265358979323846
 #define ROUND(x) (int)((x) + 0.5)
@@ -31,8 +35,9 @@
 
 
 //////////////////////////////////////////////////////////////////////////////
-LabelRenderer::LabelRenderer(GDRenderer* renderer) 
-: LabelRendererBase(renderer),
+//TODO: this needs to be cleaned up -- all three arguments are the same object
+LabelRenderer::LabelRenderer(Renderer* renderer, SE_Renderer* serenderer)
+: LabelRendererBase(renderer, serenderer),
   m_bOverpostGroupOpen(false)
 {
 }
@@ -98,7 +103,7 @@
         // coming in on some tiles.
         RS_String stitch_key = text;
 
-        if (m_renderer->UseLocalOverposting())
+        if (false /*m_renderer->UseLocalOverposting()*/)  //LabelRenderer is not used in tiled mode so this is not needed
         {
             // TODO: stitch in subregions of tile
 //          const RS_Bounds& tileBounds = m_renderer->GetBounds();
@@ -135,10 +140,7 @@
             lblpath = new RS_F_Point[lblpathpts];
 
             for (int b=0; b<lblpathpts; b++)
-            {
-                lblpath[b].x = m_renderer->_TXD(lines[2*b]);
-                lblpath[b].y = m_renderer->_TYD(lines[2*b+1]);
-            }
+                m_serenderer->WorldToScreenPoint(lines[2*b], lines[2*b+1], lblpath[b].x, lblpath[b].y);
 
             _ASSERT(nlabels == 1);
             RS_LabelInfo* info = &labels[0];    // TODO: assumes one label
@@ -168,14 +170,16 @@
     }
     else
     {
+        RS_FontEngine* fe = m_serenderer->GetFontEngine();
+
         // case of a simple label
         for (int i=0; i<nlabels; i++)
         {
             RS_LabelInfo* info = &labels[i];
 
             // label is in device space
-            double offx = m_renderer->_MeterToMapSize(info->dunits(), info->dx());
-            double offy = m_renderer->_MeterToMapSize(info->dunits(), info->dy());
+            double offx = fe->MeterToMapSize(info->dunits(), info->dx());
+            double offy = fe->MeterToMapSize(info->dunits(), info->dy());
 
             LR_LabelInfo lrinfo(info->x() + offx, info->y() + offy, text, info->tdef());
 
@@ -188,6 +192,42 @@
 
 
 //////////////////////////////////////////////////////////////////////////////
+//SE symbol-labels
+void LabelRenderer::ProcessLabelGroup(SE_LabelInfo*    labels,
+                                      int              nlabels,
+                                      RS_OverpostType  type,
+                                      bool             exclude,
+                                      SE_Geometry*      path)
+{
+    BeginOverpostGroup(type, true, exclude);
+
+    //Add a new style SE label to the overpost groups.
+    //here we are processing the simlpe case (like labels at a given points,
+    //rather than labels along a line). The hard case is //TODO
+    m_labelGroups.back().m_algo = laSESymbol;
+    RS_FontEngine* fe = m_serenderer->GetFontEngine();
+
+    for (int i=0; i<nlabels; i++)
+    {
+        SE_LabelInfo* info = &labels[i];
+
+        // label is in device space
+        double offx = fe->MeterToMapSize(info->dunits, info->dx);
+        double offy = fe->MeterToMapSize(info->dunits, info->dy);
+
+        LR_LabelInfo lrinfo(info->x + offx, info->y + offy, info->symbol);
+
+        //TODO: HACK -- well somewhat of a hack -- store the angle in the tdef
+        lrinfo.m_tdef.rotation() = info->anglerad;
+
+        m_labelGroups.back().m_labels.push_back(lrinfo);
+    }
+
+    EndOverpostGroup();
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
 void LabelRenderer::BeginOverpostGroup(RS_OverpostType type, bool render, bool exclude)
 {
     m_bOverpostGroupOpen = true;
@@ -297,6 +337,9 @@
 bool LabelRenderer::ProcessLabelInternal(LR_LabelInfo& info,
                                          bool render, bool exclude, bool check)
 {
+    if (info.m_sestyle)
+        return DrawSELabel(info, render, exclude, check);
+
     //if it is path label, call our path text routine
     if (info.m_pts)
         return DrawPathLabel(info, render, exclude, check);
@@ -309,119 +352,66 @@
 //////////////////////////////////////////////////////////////////////////////
 void LabelRenderer::AddExclusionRegion(RS_F_Point* pts, int npts)
 {
-    //use axis aligned bounds for overposting
-    //TODO: can be improved to use the given polygon as is
-    //instead of taking its bounds
-    RS_Bounds axis_bounds;
-    ComputeBounds(pts, npts, axis_bounds);
+    RS_F_Point* tmp = (RS_F_Point*)alloca(npts * sizeof(RS_F_Point));
 
-    //convert to mapping space for overpost tracking
-    //this is needed so that we can do overposting
-    //across map tiles generated at different times
-    DeviceToMappingBounds(axis_bounds);
+    //convert back to mapping space since the overpost manager uses mapping space
+    //bounding boxes
+    for (int i=0; i<npts; i++)
+        m_serenderer->ScreenToWorldPoint(pts[i].x, pts[i].y, tmp[i].x, tmp[i].y);
 
-    m_overpost.AddRegion(axis_bounds);
+    m_overpost.AddRegion(tmp, npts);
 }
 
 
 //////////////////////////////////////////////////////////////////////////////
 bool LabelRenderer::OverlapsStuff(RS_F_Point* pts, int npts)
 {
-    //use axis aligned bounds for overposting
-    //TODO: can be improved to use the given polygon as is
-    //instead of taking its bounds
-    RS_Bounds axis_bounds;
-    ComputeBounds(pts, npts, axis_bounds);
+    RS_F_Point* tmp = (RS_F_Point*)alloca(npts * sizeof(RS_F_Point));
 
-    //convert to mapping space for overpost tracking
-    //this is needed so that we can do overposting
-    //across map tiles generated at different times
-    DeviceToMappingBounds(axis_bounds);
+    //convert back to mapping space since the overpost manager uses mapping space
+    //bounding boxes
+    for (int i=0; i<npts; i++)
+        m_serenderer->ScreenToWorldPoint(pts[i].x, pts[i].y, tmp[i].x, tmp[i].y);
 
-    return m_overpost.Overlaps(axis_bounds);
+    return m_overpost.Overlaps(tmp, npts);
 }
 
 
 //////////////////////////////////////////////////////////////////////////////
 bool LabelRenderer::DrawSimpleLabel(LR_LabelInfo& info, bool render, bool exclude, bool check)
 {
-    // font matching
-    const RS_Font* font = m_renderer->FindFont(info.m_tdef.font());
-    if (!font)
-        return false;
+    RS_TextMetrics tm;
+    RS_FontEngine* fe = m_serenderer->GetFontEngine();
 
-    //determine pixel space font height
-    double hgt = m_renderer->_MeterToMapSize(info.m_tdef.font().units(), info.m_tdef.font().height());
-    hgt *= m_renderer->GetMapToScreenScale() * 0.75;
+    //measure the text (this function will take into account newlines)
+    fe->GetTextMetrics(info.m_text, info.m_tdef, tm, false);
 
-    // The computed height can have roundoff in it, and the rendering code is
-    // very sensitive to it.  Remove this roundoff by rounding the height to
-    // the nearest 1/65536ths of a point.
-    hgt = floor(hgt * 65536.0 + 0.5) / 65536.0;
-
     //radian CCW rotation
     double rotation = info.m_tdef.rotation() * M_PI / 180.0;
     double cos_a = cos(rotation);
     double sin_a = sin(rotation);
 
-    // font height gives the distance from one baseline to the next
-    // increase this by a factor of 1.05 (what GD uses)
-    double font_height = font->m_height * hgt / font->m_units_per_EM;
-    double line_height = 1.05 * font_height;
-
     // transform insertion point into pixel space
-    RS_F_Point ins_point(m_renderer->_TXD(info.m_x), m_renderer->_TYD(info.m_y));
+    RS_F_Point ins_point;
+    m_serenderer->WorldToScreenPoint(info.m_x, info.m_y, ins_point.x, ins_point.y);
 
     //-------------------------------------------------------
-    // break up the string up into individual lines
-    //-------------------------------------------------------
-
-    // make a temporary copy
-    size_t len = wcslen(info.m_text.c_str());
-    wchar_t* cpy = (wchar_t*)alloca((len + 1) * sizeof(wchar_t));
-    wcscpy(cpy, info.m_text.c_str());
-
-    // break it up
-    std::vector<wchar_t*> line_breaks;
-    size_t num_lines = SplitLabel(cpy, line_breaks);
-
-    //-------------------------------------------------------
     // text extent and alignment computation
     //-------------------------------------------------------
 
     RS_F_Point fpts[4];
+
     RS_Bounds rotatedBounds(+DBL_MAX, +DBL_MAX, -DBL_MAX, -DBL_MAX);
     RS_Bounds unrotatedBounds(+DBL_MAX, +DBL_MAX, -DBL_MAX, -DBL_MAX);
 
-    double* hAlignOffsets = (double*)alloca(num_lines * sizeof(double));
-    double* vAlignOffsets = (double*)alloca(num_lines * sizeof(double));
-    double* textWidths    = (double*)alloca(num_lines * sizeof(double));
-
-    // base vertical offset is the same for each line of text
-    double vAlignBaseOffset = GetVerticalAlignmentOffset(info.m_tdef, font, hgt, line_height, num_lines);
-
-    for (size_t k=0; k<num_lines; ++k)
+    for (size_t k=0; k<tm.line_pos.size(); ++k)
     {
-        wchar_t* txt = line_breaks[k];
+        //convert the unrotated measured bounds for the current line to a local point array
+        memcpy(fpts, tm.line_pos[k].ext, sizeof(fpts));
 
-        // get the unrotated extent of this sub-string
-        m_renderer->MeasureString(txt, hgt, font, 0.0, fpts, NULL);
-
-        // horizontal offset depends on the sub-string width, while
-        // vertical offset depends on the line of text
-        hAlignOffsets[k] = GetHorizontalAlignmentOffset(info.m_tdef, fpts);
-        vAlignOffsets[k] = vAlignBaseOffset + k*line_height;
-
-        // remember the width
-        textWidths[k] = fpts[1].x - fpts[0].x;
-
         // process the extent points
         for (int j=0; j<4; ++j)
         {
-            // translate to account for the alignment
-            fpts[j].x += hAlignOffsets[k];
-            fpts[j].y += vAlignOffsets[k];
-
             // update the overall unrotated bounds
             unrotatedBounds.add_point(fpts[j]);
 
@@ -464,79 +454,76 @@
     //-------------------------------------------------------
 
     if (render)
-    {
-        // draw the opaque background first, if requested
-        if (info.m_tdef.textbg() == RS_TextBackground_Opaque)
-        {
-            // get the overall unrotated bounds
-            unrotatedBounds.get_points(fpts);
+        fe->DrawBlockText(tm, info.m_tdef, ins_point.x, ins_point.y);
 
-            // rotate and translate it
-            for (int j=0; j<4; ++j)
-            {
-                double tmpX = fpts[j].x;
-                double tmpY = fpts[j].y;
-                fpts[j].x = ins_point.x + tmpX * cos_a + tmpY * sin_a;
-                fpts[j].y = ins_point.y - tmpX * sin_a + tmpY * cos_a;
-            }
+    return true;
+}
 
-            // draw a filled rectangle
-            RS_D_Point dpts[4];
-            for (int j=0; j<4; j++)
-            {
-                dpts[j].x = ROUND(fpts[j].x);
-                dpts[j].y = ROUND(fpts[j].y);
-            }
 
-            gdImageFilledPolygon((gdImagePtr)m_renderer->GetImage(), (gdPointPtr)dpts, 4, ConvertColor((gdImagePtr)m_renderer->GetImage(), info.m_tdef.bgcolor()));
-        }
+//////////////////////////////////////////////////////////////////////////////
+bool LabelRenderer::DrawSELabel(LR_LabelInfo& info, bool render, bool exclude, bool check)
+{
+    //draws an SE symbol-label
+    //This needs to be improved to handle text along a path
 
-        for (size_t k=0; k<num_lines; ++k)
-        {
-            RS_String txt = line_breaks.at(k);
+    //get native symbol bounds (in pixels -- the render style is already scaled to pixels)
+    SE_Bounds* b;
+    b = info.m_sestyle->bounds;
 
-            // add the rotated original offset for this line to the insertion point
-            // to get the actual draw point
-            double insX = ins_point.x + hAlignOffsets[k] * cos_a + vAlignOffsets[k] * sin_a;
-            double insY = ins_point.y - hAlignOffsets[k] * sin_a + vAlignOffsets[k] * cos_a;
+    //now we will trnaslate and orient the bounds with the given angle and position of the symbol
+    RS_F_Point fpts[4];
 
-            int posx = (int)floor(insX + 0.5);
-            int posy = (int)floor(insY + 0.5);
+    fpts[0].x = b->min[0];
+    fpts[0].y = b->min[1];
+    fpts[1].x = b->max[0];
+    fpts[1].y = b->min[1];
+    fpts[2].x = b->max[0];
+    fpts[2].y = b->max[1];
+    fpts[3].x = b->min[0];
+    fpts[3].y = b->max[1];
 
-            // render the ghosted text, if requested
-            if (info.m_tdef.textbg() == RS_TextBackground_Ghosted)
-            {
-                m_renderer->DrawString(txt, posx-1, posy, hgt, font, info.m_tdef.bgcolor(), rotation);
-                m_renderer->DrawString(txt, posx+1, posy, hgt, font, info.m_tdef.bgcolor(), rotation);
-                m_renderer->DrawString(txt, posx, posy-1, hgt, font, info.m_tdef.bgcolor(), rotation);
-                m_renderer->DrawString(txt, posx, posy+1, hgt, font, info.m_tdef.bgcolor(), rotation);
-            }
+    //apply position and rotation to the native bounds of the symbol
+    double angle = m_serenderer->GetFontEngine()->_Yup() ? info.m_tdef.rotation() : -info.m_tdef.rotation();
+    SE_Matrix m;
+    m.setIdentity();
+    m.rotate(angle); //it is already in radians in there
+    m.translate(info.m_x, info.m_y);
 
-            // render the primary text
-            m_renderer->DrawString(txt, posx, posy, hgt, font, info.m_tdef.color(), rotation);
+    for (int i=0; i<4; i++)
+        m.transform(fpts[i].x, fpts[i].y);
 
-            // render the underline, if requested
-            if (info.m_tdef.font().style() & RS_FontStyle_Underline)
-            {
-                // estimate underline line width as % of font height
-                double line_width = (double)font->m_underline_thickness * hgt / (double)font->m_units_per_EM;
-                double line_pos = - (double)font->m_underline_position * hgt / (double)font->m_units_per_EM;
+    //check for overposting
+    if (check)
+    {
+        if (OverlapsStuff(fpts, 4))
+            return false;
+    }
 
-                // the line's start point is the insertion point, but shifted vertically by line_pos
-                double x0 = insX + line_pos * sin_a;
-                double y0 = insY + line_pos * cos_a;
+    //add bounds to exclusion regions if needed
+    if (exclude)
+    {
+        AddExclusionRegion(fpts, 4);
+    }
 
-                // the end point is a horizontal shift by the text width
-                double x1 = x0 + textWidths[k] * cos_a;
-                double y1 = y0 - textWidths[k] * sin_a;
+    //-------------------------------------------------------
+    // draw the label
+    //-------------------------------------------------------
 
-                // draw the thick line
-                gdImageSetThickness((gdImagePtr)m_renderer->GetImage(), ROUND(line_width));
-                gdImageSetAntiAliased((gdImagePtr)m_renderer->GetImage(), ConvertColor((gdImagePtr)m_renderer->GetImage(), info.m_tdef.color()));
-                gdImageLine((gdImagePtr)m_renderer->GetImage(), ROUND(x0), ROUND(y0), ROUND(x1), ROUND(y1), gdAntiAliased);
-                gdImageSetThickness((gdImagePtr)m_renderer->GetImage(), 0);
-            }
-        }
+    if (render)
+    {      
+        m_serenderer->DrawSymbol(info.m_sestyle->symbol, m, angle);
+
+#ifdef DEBUG_LABELS
+        //debug -- draw the bounds also
+        LineBuffer lb(5);
+        lb.MoveTo(fpts[0].x, fpts[0].y);
+        lb.LineTo(fpts[1].x, fpts[1].y);
+        lb.LineTo(fpts[2].x, fpts[2].y);
+        lb.LineTo(fpts[3].x, fpts[3].y);
+        lb.Close();
+        m_serenderer->DrawScreenPolyline(&lb, 0xff000000, 0.0);
+        //end debug
+#endif
     }
 
     return true;
@@ -546,34 +533,13 @@
 //////////////////////////////////////////////////////////////////////////////
 bool LabelRenderer::DrawPathLabel(LR_LabelInfo& info, bool render, bool exclude, bool check)
 {
-    // font matching
-    const RS_Font* font = m_renderer->FindFont(info.m_tdef.font());
-    if (!font)
+    RS_FontEngine* fe = m_serenderer->GetFontEngine();
+    RS_TextMetrics tm;
+
+    //match the font and measure the sizes of the characters
+    if (!fe->GetTextMetrics(info.m_text, info.m_tdef, tm, true))
         return false;
 
-    //determine pixel space font height
-    double hgt = m_renderer->_MeterToMapSize(info.m_tdef.font().units(), info.m_tdef.font().height());
-    hgt *= m_renderer->GetMapToScreenScale() * 0.75;
-
-    // The computed height can have roundoff in it, and the rendering code is
-    // very sensitive to it.  Remove this roundoff by rounding the height to
-    // the nearest 1/65536ths of a point.
-    hgt = floor(hgt * 65536.0 + 0.5) / 65536.0;
-
-    //-------------------------------------------------------
-    // text extent and alignment computation
-    //-------------------------------------------------------
-
-    //get overall extent and char spacing
-    RS_F_Point fpts[4];
-    float* spacing = (float*)alloca(info.m_text.length() * 2 * sizeof(float));
-    m_renderer->MeasureString(info.m_text, hgt, font, 0.0, fpts, spacing);
-
-    //the width and height of this particular string
-    //TODO: we can be more precise if we get height on per character basis
-    double texthgt = fabs(fpts[2].y - fpts[0].y);
-    double textwid = fabs(fpts[1].x - fpts[0].x);
-
     //find length of each segment in the screen space path
     //we will use it to position characters along the curve
     //This is precomputed here, rather than in ComputeCharacterPositions
@@ -591,9 +557,10 @@
 
     //how many times should we repeat the label along the polyline?
     //TODO: fine tune this formula
-    int numreps = (int)(seglens[info.m_numpts-1] / (200.0 + textwid));
+    int numreps = (int)(seglens[info.m_numpts-1] / (200.0 + tm.text_width));
     if (!numreps) numreps = 1;
 
+    int numchars = info.m_text.length();
     int labels_drawn = 0; //counter for how many of the repeated label were accepted
 
     for (int i=0; i<numreps; i++)
@@ -604,62 +571,12 @@
         double param_position = ((double)i + 0.5) / (double)numreps;
 
         //compute position and angle along the path for each character
-        size_t numchars = info.m_text.length();
-        CharPos* pos = (CharPos*)alloca(sizeof(CharPos) * numchars);
-        double font_scale = ComputeCharacterPositions(info, seglens, param_position, spacing, textwid, pos);
+        bool success = fe->LayoutPathText(tm, info.m_pts, info.m_numpts, seglens, param_position, info.m_tdef.valign(), 0);
 
-        //update font height to value that curve fitting suggested
-        if (font_scale != 1.0)
-        {
-            //don't bother measuring the string with the new height,
-            //scaling should work almost as good
-            hgt     *= font_scale;
-            texthgt *= font_scale;
-            textwid *= font_scale;
-        }
-
-        //take into account text vertical alignment
-        //horizontal alignment is ignored in this case
-        for (size_t i=0; i<numchars; i++)
-        {
-            //TODO:
-            double font_cap_height = hgt;
-            double font_ascent     = hgt;
-            double font_descent    = 0;
-
-            // get the height vector
-            double dyh = 0.0;
-
-            RS_VAlignment vAlign = info.m_tdef.valign();
-            switch (vAlign)
-            {
-                case RS_VAlignment_Descent: dyh = -font_descent;        break;
-                case RS_VAlignment_Base:                                break;
-                case RS_VAlignment_Half:    dyh =  font_cap_height/2.0; break;
-                case RS_VAlignment_Cap:     dyh =  font_cap_height;     break;
-                case RS_VAlignment_Ascent:  dyh =  font_ascent;         break;
-                default:                                                break;
-            }
-
-            // add in the rotated vertical alignment contribution
-            double angle = pos[i].anglerad;
-
-            //take into account that y axis goes down in our coordinate system
-            dyh = -dyh;
-
-            double cs = cos(angle);
-            double sn = sin(angle);
-            double hAlignOffset = -sn*dyh;
-            double vAlignOffset =  cs*dyh;
-
-            //adjust insertion point
-            pos[i].x += hAlignOffset;
-            pos[i].y -= vAlignOffset;
-        }
-
         //once we have position and angle for each character
         //compute oriented bounding box for each character
         RS_F_Point* oriented_bounds = (RS_F_Point*)alloca(4 * numchars * sizeof(RS_F_Point));
+        float* spacing = (float*)&tm.char_advances.front(); //bold assumption
 
         double total_advance = 0.0;
         for (size_t i=0; i<numchars; i++)
@@ -668,21 +585,21 @@
             //it takes kerning into account, but should be good enough
             //we could measure each character separately but that seems like
             //too many calls to FreeType
-            double advance = (i == numchars-1)? textwid - total_advance : spacing[i] * font_scale;
+            double advance = (i == numchars-1)? tm.text_width - total_advance : spacing[i];
             total_advance += advance;
 
             //compute rotated bounds of character
             RS_F_Point* b = &oriented_bounds[i * 4];
-            RotatedBounds(pos[i].x, pos[i].y, advance, texthgt, pos[i].anglerad, b);
+            RotatedBounds(tm.char_pos[i].x, tm.char_pos[i].y, advance, tm.text_height, tm.char_pos[i].anglerad, b);
 
     #ifdef DEBUG_LABELS
-            RS_D_Point dpts[4];
-            for (int j=0; j<4; j++)
-            {
-                dpts[j].x = (int)b[j].x;
-                dpts[j].y = (int)b[j].y;
-            }
-            gdImagePolygon((gdImagePtr)m_renderer->GetImage(), (gdPointPtr)dpts, 4, ConvertColor((gdImagePtr)m_renderer->GetImage(), info.m_tdef.color()));
+            LineBuffer lb(5);
+            lb.MoveTo(b[0].x, b[0].y);
+            lb.LineTo(b[1].x, b[1].y);
+            lb.LineTo(b[2].x, b[2].y);
+            lb.LineTo(b[3].x, b[3].y);
+            lb.Close();
+            m_serenderer->DrawScreenPolyline(&lb, info.m_tdef.color().argb(), 0.0);
     #endif
         }
 
@@ -716,84 +633,7 @@
 
         if (render)
         {
-            //draw the characters, each in its computed position
-            RS_String c;
-            for (size_t i=0; i<numchars; ++i)
-            {
-                c = info.m_text[i];
-
-                //compute screen position and round
-                int posx = ROUND(pos[i].x);
-                int posy = ROUND(pos[i].y);
-
-                if (info.m_tdef.textbg() == RS_TextBackground_Ghosted)
-                {
-                    m_renderer->DrawString(c, posx-1, posy, hgt, font, info.m_tdef.bgcolor(), pos[i].anglerad);
-                    m_renderer->DrawString(c, posx+1, posy, hgt, font, info.m_tdef.bgcolor(), pos[i].anglerad);
-                    m_renderer->DrawString(c, posx, posy-1, hgt, font, info.m_tdef.bgcolor(), pos[i].anglerad);
-                    m_renderer->DrawString(c, posx, posy+1, hgt, font, info.m_tdef.bgcolor(), pos[i].anglerad);
-                }
-
-                m_renderer->DrawString(c, posx, posy, hgt, font, info.m_tdef.color(), pos[i].anglerad);
-            }
-
-            //render underline
-            if (info.m_tdef.font().style() & RS_FontStyle_Underline)
-            {
-                //estimate underline line width as % of font height
-                double line_width = (double)font->m_underline_thickness * hgt / (double)font->m_units_per_EM;
-                //underline position w.r.t. baseline. Invert y while at it
-                double line_pos = - (double)font->m_underline_position * hgt / (double)font->m_units_per_EM;
-
-                //zero it out again, we will need the accumulator for
-                //underline purposes
-                total_advance = 0.0;
-
-                //used to keep track of last position of the underline, which is 
-                //drawn piecewise for each character
-                int last_x = ROUND(pos[0].x + sin(pos[0].anglerad) * line_pos);
-                int last_y = ROUND(pos[0].y + cos(pos[0].anglerad) * line_pos);
-                int sx, sy, ex, ey;
-
-                //draw the characters, each in its computed position
-                for (size_t i=0; i<numchars; i++)
-                {
-                    //width of character - not really exact width since
-                    //it takes kerning into account, but should be good enough
-                    //we could measure each character separately but that seems like
-                    //too many calls to FreeType
-                    double advance = (i == numchars-1)? textwid - total_advance : spacing[i] * font_scale;
-                    total_advance += advance;
-
-                    sx = last_x;
-                    sy = last_y;
-
-                    if (i == numchars - 1)
-                    {
-                        //estimate bottom right corner of last character
-                        double eex = pos[i].x + cos(pos[i].anglerad) * advance;
-                        double eey = pos[i].y - sin(pos[i].anglerad) * advance;
-
-                        //now take into account underline offset
-                        ex = ROUND(eex + sin(pos[i].anglerad) * line_pos);
-                        ey = ROUND(eey + cos(pos[i].anglerad) * line_pos);
-                    }
-                    else
-                    {
-                        //move position by underline offset
-                        ex = ROUND(pos[i+1].x + sin(pos[i+1].anglerad) * line_pos);
-                        ey = ROUND(pos[i+1].y + cos(pos[i+1].anglerad) * line_pos);
-                    }
-
-                    gdImageSetThickness((gdImagePtr)m_renderer->GetImage(), (int)(line_width+0.5));
-                    gdImageSetAntiAliased((gdImagePtr)m_renderer->GetImage(), ConvertColor((gdImagePtr)m_renderer->GetImage(), info.m_tdef.color()));
-                    gdImageLine((gdImagePtr)m_renderer->GetImage(), sx, sy, ex, ey, gdAntiAliased);
-                    gdImageSetThickness((gdImagePtr)m_renderer->GetImage(), 0);
-
-                    last_x = ex;
-                    last_y = ey;
-                }
-            }
+            fe->DrawPathText(tm, info.m_tdef);
         }
 
         labels_drawn ++; //increment count of how many labels we accepted
@@ -807,183 +647,6 @@
 
 
 //////////////////////////////////////////////////////////////////////////////
-//computes position and rotation of each character along the
-//feature to be labeled -- it may return a scale factor to be
-//applied to the font size to make the label fit better in the
-//allotted space
-double LabelRenderer::ComputeCharacterPositions(LR_LabelInfo& info, double* seglens, double position, float* kerned_spacing, double measured_width, CharPos* ret)
-{
-    //determine in which direction we should follow the polyline
-    //so that the label points up more likely than down
-    //find the length of polyline that requires inverting versus
-    //length that does not and see which one is bigger
-    //TODO: this loop should really be performed on the piece of the
-    //polyline where we will be labeling since otherwise features like
-    //circles can throw it off and so a label may still end up upside down
-    double inverted_len = 0.0;
-
-    for (int m=0; m<info.m_numpts - 1; m++)
-    {
-        RS_F_Point p0 = info.m_pts[m];
-        RS_F_Point p1 = info.m_pts[m+1];
-
-        double angle = -atan2(p1.y - p0.y, p1.x - p0.x);
-
-        if (angle > M_PI/2.0 || angle < -M_PI/2.0)
-            inverted_len += seglens[m+1] - seglens[m];
-        else
-            inverted_len -= seglens[m+1] - seglens[m];
-    }
-
-    bool reverse = (inverted_len > 0.0);
-
-    double pathlen = seglens[info.m_numpts - 1];
-
-    //compute font height that better fits the geometry
-    //but limit scaling to be in the range [0.5 - 1.0]
-    double font_scale = rs_min(1.0, rs_max(0.5, pathlen / (1.1 * measured_width)));
-
-    //distance of current character along current segment
-    //initialize to start position, based on given parametric position
-    //along the polyline
-    double dist_along_segment = position * pathlen - 0.5 * measured_width * font_scale;
-
-    //j indicates index of segment we are on with current character
-    int j;
-
-    //segment for current character
-    RS_F_Point start;
-    RS_F_Point end;
-
-    if (reverse)
-    {
-        //case where we want to walk along the polyline
-        //in reverse
-
-        //compute starting segment
-        for (j=info.m_numpts-2; j>=0; j--)
-            if (dist_along_segment < pathlen - seglens[j])
-                break;
-
-        if (j < 0) j=0;
-
-        start = info.m_pts[j+1];
-        end = info.m_pts[j];
-        dist_along_segment -= pathlen - seglens[j+1];
-    }
-    else
-    {
-        //case where we follow the polyline forwards
-
-        //compute starting segment
-        for (j=0; j<info.m_numpts-1; j++)
-            if (dist_along_segment < seglens[j+1])
-                break;
-
-        if (j >= info.m_numpts-1)
-            j=info.m_numpts-2;
-
-        start = info.m_pts[j];
-        end = info.m_pts[j+1];
-        dist_along_segment -= seglens[j];
-    }
-
-    //length of current segment
-    double seg_len = seglens[j+1] - seglens[j];
-
-    //position of current character relative to the left end of the string
-    double char_pos = 0;
-
-    int numchars = (int)info.m_text.length();
-
-    //The premise here is that we will compute three positions along the path
-    //for each character - one for the left corner, one for the right
-    //and one for the centerpoint
-    //We will compute a tangent vector based on the left and right points
-    //and then position the character relative to the point computed for its
-    //center with the normal comuted from the left and right points
-    //Note that the end position of one character equals the start position
-    //of the next, so in fact we need to compute 2 * n + 1 points
-    RS_F_Point* positions = (RS_F_Point*)alloca(sizeof(RS_F_Point) * (numchars * 2 + 1));
-
-    for (int i=0; i <= numchars * 2; i++)
-    {
-        //check if we need to move to next segment
-        while (dist_along_segment > seg_len)
-        {
-            if (reverse)
-            {
-                //case where we go in reverse direction of the path
-                if (j > 0)
-                {
-                    j--;
-                    dist_along_segment -= seg_len;
-                    seg_len = seglens[j+1] - seglens[j];
-                    start = info.m_pts[j+1];
-                    end = info.m_pts[j];
-                }
-                else
-                    break;
-            }
-            else
-            {
-                //case where we go forward along the path
-                if (j < info.m_numpts - 2)
-                {
-                    j++;
-                    dist_along_segment -= seg_len;
-                    seg_len = seglens[j+1] - seglens[j];
-                    start = info.m_pts[j];
-                    end = info.m_pts[j+1];
-                }
-                else
-                    break;
-            }
-        }
-
-        //compute position along current segment using weighted
-        //normalized end-start vector
-        double weight = dist_along_segment / seg_len;
-        double dx = end.x - start.x;
-        double dy = end.y - start.y;
-
-        positions[i].x = start.x + dx * weight;
-        positions[i].y = start.y + dy * weight;
-
-        //kerned width of current character
-        int index = i / 2; //which character are we working with -- 3 iterations for each one
-        double char_width = (index >= numchars - 1) ? measured_width - char_pos : kerned_spacing[index];
-
-        //advance cursor by half the width of the current character
-        dist_along_segment += char_width * 0.5 * font_scale;
-        char_pos += char_width * 0.5;
-    }
-
-    char_pos = 0.0;
-
-    //now compute character placement and angles based on the positioning points
-    for (int i=0; i<numchars; i++)
-    {
-        //find angle based on left and right of character
-        ret[i].anglerad = -atan2(positions[2*i+2].y - positions[2*i].y,positions[2*i+2].x - positions[2*i].x);
-
-        //kerned width of current character
-        double char_width = (i == numchars - 1) ? measured_width - char_pos : kerned_spacing[i];
-        double char_width_2 = 0.5 * char_width * font_scale;
-
-        //and now find a lower left insertion point
-        //based on the midpoint anchor and the angle
-        ret[i].x = positions[2*i+1].x - cos(ret[i].anglerad) * char_width_2;
-        ret[i].y = positions[2*i+1].y + sin(ret[i].anglerad) * char_width_2; //y down means + sin
-
-        char_pos += char_width;
-    }
-
-    return font_scale;
-}
-
-
-//////////////////////////////////////////////////////////////////////////////
 std::vector<LR_LabelInfo> LabelRenderer::StitchPolylines(std::vector<LR_LabelInfo>& labels)
 {
     std::vector<LR_LabelInfo> src = labels; //make a copy

Modified: trunk/MgDev/Common/Stylization/LabelRenderer.h
===================================================================
--- trunk/MgDev/Common/Stylization/LabelRenderer.h	2007-03-06 17:02:52 UTC (rev 1157)
+++ trunk/MgDev/Common/Stylization/LabelRenderer.h	2007-03-06 23:31:17 UTC (rev 1158)
@@ -21,6 +21,7 @@
 #include "LabelRendererBase.h"
 #include "SimpleOverpost.h"
 
+struct SE_RenderStyle;
 
 //////////////////////////////////////////////////////////////////////////////
 //used to accumulate labels
@@ -33,10 +34,20 @@
           m_text(text),
           m_tdef(tdef),
           m_pts(NULL),
-          m_numpts(0)
+          m_numpts(0),
+          m_sestyle(NULL)
     {
     }
 
+    LR_LabelInfo(double x, double y, SE_RenderStyle* style)
+        : m_x(x),
+          m_y(y),
+          m_pts(NULL),
+          m_numpts(0),
+          m_sestyle(style)
+    {
+    }
+
     double m_x;
     double m_y;
     RS_String m_text;
@@ -45,6 +56,9 @@
     // if set, defines the path which the label will follow
     RS_F_Point* m_pts;
     int m_numpts;
+
+    //new SE labels keep the symbol here rather than in the m_tdef/m_text combo
+    SE_RenderStyle* m_sestyle;
 };
 
 
@@ -70,9 +84,8 @@
 //////////////////////////////////////////////////////////////////////////////
 class LabelRenderer : public LabelRendererBase
 {
-
 public:
-    LabelRenderer(GDRenderer* renderer);
+    LabelRenderer(Renderer* renderer, SE_Renderer* serenderer); //TODO: clean this up -- they point to the same class
     virtual ~LabelRenderer();
 
     virtual void StartLabels();
@@ -87,6 +100,13 @@
                                    bool             exclude,
                                    LineBuffer*      path);
 
+    //SE symbol-labels
+    virtual void ProcessLabelGroup(SE_LabelInfo*    labels,
+                                   int              nlabels,
+                                   RS_OverpostType  type,
+                                   bool             exclude,
+                                   SE_Geometry*      path);
+
     virtual void BlastLabels();
 
     virtual void AddExclusionRegion(RS_F_Point* pts, int npts);
@@ -99,9 +119,8 @@
 
     bool DrawSimpleLabel(LR_LabelInfo& info, bool render, bool exclude, bool check);
     bool DrawPathLabel(LR_LabelInfo& info, bool render, bool exclude, bool check);
+    bool DrawSELabel(LR_LabelInfo& info, bool render, bool exclude, bool check);
 
-    double ComputeCharacterPositions(LR_LabelInfo& info, double* seglens, double position, float* kerned_spacing, double measured_width, CharPos* ret);
-
     bool OverlapsStuff(RS_F_Point* pts, int npts);
 
     std::vector<LR_LabelInfo> StitchPolylines(std::vector<LR_LabelInfo>& labels);

Modified: trunk/MgDev/Common/Stylization/LabelRendererBase.cpp
===================================================================
--- trunk/MgDev/Common/Stylization/LabelRendererBase.cpp	2007-03-06 17:02:52 UTC (rev 1157)
+++ trunk/MgDev/Common/Stylization/LabelRendererBase.cpp	2007-03-06 23:31:17 UTC (rev 1158)
@@ -24,248 +24,59 @@
 
 
 //////////////////////////////////////////////////////////////////////////////
-LabelRendererBase::LabelRendererBase(GDRenderer* renderer)
-: m_renderer(renderer)
+//TODO: clearly the arguments to this need cleanup
+LabelRendererBase::LabelRendererBase(Renderer* renderer, SE_Renderer* serenderer)
+:
+m_renderer(renderer),
+m_serenderer(serenderer)
 {
 }
 
 
 //////////////////////////////////////////////////////////////////////////////
-// Finds occurences of line breaks and adds the start pointer of each
-// line to the supplied array.  Line breaks can be any of the following:
-//   "\\n"                      // sequence currently used by MG OS / Enterprise
-//   \n\r  (char 13 + char 10)  // common in RDBMS like Oracle
-//   \r\n  (char 10 + char 13)
-//   \n    (char 13)            // used by MG 6.5
-//   \r    (char 10)            // common in Linux
-size_t LabelRendererBase::SplitLabel(wchar_t* label, std::vector<wchar_t*>& line_breaks)
+//Applies a given angle to an axis aligned bounding box.
+//Rotation point is lower left
+//TODO: move these transformations to the renderer
+void LabelRendererBase::RotatedBounds(double x, double y, double width, double height, double angle_cw_rad, RS_F_Point* b)
 {
-    _ASSERT(label != NULL);
-    if (label == NULL)
-        return 0;
-
-    // first line
-    line_breaks.push_back(label);
-
-    for (;;)
+    if (m_serenderer->GetFontEngine()->_Yup())
     {
-        // find the next line break - note that we must search
-        // for the 2-character sequences FIRST
-        wchar_t* found;
-        for (;;)
-        {
-            found = ::wcsstr(label, L"\\n");
-            if (found != NULL)
-            {
-                // null terminate line break (2 characters)
-                *found++ = 0;
-                *found++ = 0;
-                break;
-            }
+        double sina = sin(-angle_cw_rad);
+        double cosa = cos(-angle_cw_rad);
 
-            found = ::wcsstr(label, L"\n\r");
-            if (found != NULL)
-            {
-                // null terminate line break (2 characters)
-                *found++ = 0;
-                *found++ = 0;
-                break;
-            }
-
-            found = ::wcsstr(label, L"\r\n");
-            if (found != NULL)
-            {
-                // null terminate line break (2 characters)
-                *found++ = 0;
-                *found++ = 0;
-                break;
-            }
-
-            found = ::wcsstr(label, L"\n");
-            if (found != NULL)
-            {
-                // null terminate line break (1 character)
-                *found++ = 0;
-                break;
-            }
-
-            found = ::wcsstr(label, L"\r");
-            if (found != NULL)
-            {
-                // null terminate line break (1 character)
-                *found++ = 0;
-            }
-
-            break;
-        }
-
-        if (found == NULL)
-            break;
-
-        label = found;
-        line_breaks.push_back(label);
+        //apply rotation
+        //taking into account that y goes down (so subtract instead of adding for y)
+        b[0].x = x;
+        b[0].y = y;
+        b[1].x = b[0].x +  width * cosa;
+        b[1].y = b[0].y + (width * sina);
+        b[2].x = b[0].x +  width * cosa - height * sina;
+        b[2].y = b[0].y + (width * sina + height * cosa);
+        b[3].x = b[0].x                 - height * sina;
+        b[3].y = b[0].y + (               height * cosa);
     }
-
-    return line_breaks.size();
-}
-
-
-//////////////////////////////////////////////////////////////////////////////
-// Computes the X offset that must be applied to the unrotated text to
-// obtain the specified horizontal alignment.
-double LabelRendererBase::GetHorizontalAlignmentOffset(RS_TextDef& tdef, RS_F_Point* extent)
-{
-    double offsetX = 0.0;
-
-    RS_HAlignment hAlign = tdef.halign();
-    switch (hAlign)
+    else
     {
-    case RS_HAlignment_Left:
-        offsetX = -extent[0].x;
-        break;
+        //y goes down case
 
-    case RS_HAlignment_Center:
-        offsetX = -0.5*(extent[0].x + extent[1].x);
-        break;
+        double sina = sin(angle_cw_rad);
+        double cosa = cos(angle_cw_rad);
 
-    case RS_HAlignment_Right:
-        offsetX = -extent[1].x;
-        break;
+        //apply rotation
+        //taking into account that y goes down (so subtract instead of adding for y)
+        b[0].x = x;
+        b[0].y = y;
+        b[1].x = b[0].x +  width * cosa;
+        b[1].y = b[0].y - (width * sina);
+        b[2].x = b[0].x +  width * cosa - height * sina;
+        b[2].y = b[0].y - (width * sina + height * cosa);
+        b[3].x = b[0].x                 - height * sina;
+        b[3].y = b[0].y - (               height * cosa);
     }
-
-    return offsetX;
 }
 
 
 //////////////////////////////////////////////////////////////////////////////
-// Computes the Y offset that must be applied to the unrotated text to
-// obtain the specified vertical alignment.  Positive Y points down.
-double LabelRendererBase::GetVerticalAlignmentOffset(RS_TextDef& tdef, const RS_Font* font,
-                                                     double actual_height, double line_height,
-                                                     size_t numLines)
-{
-    double offsetY = 0.0;
-
-    // According to FreeType:
-    //
-    //   * The face's ascender is the vertical distance from the baseline
-    //     to the topmost point of any glyph in the face.  This field's
-    //     value is positive.
-    //
-    //   * The face's descender is the vertical distance from the baseline
-    //     to the bottommost point of any glyph in the face.  This field's
-    //     value is *negative* for values below the baseline.
-    //
-    //   * The face's height is the vertical distance from one baseline to
-    //     the next when writing several lines of text.  Its value is always
-    //     positive.  The value can be computed as `ascender+descender+line_gap'.
-
-    // FreeType doesn't provide the capline - for now just use the ascent.
-    double em_square_size = font->m_units_per_EM;
-    double font_ascent    = font->m_ascender * actual_height / em_square_size;
-    double font_descent   = font->m_descender * actual_height / em_square_size;
-    double font_capline   = font_ascent;
-
-    RS_VAlignment vAlign = tdef.valign();
-    switch (vAlign)
-    {
-    case RS_VAlignment_Descent:
-        // must also account for the total number of lines
-        offsetY = font_descent - line_height*(numLines - 1);
-        break;
-
-    case RS_VAlignment_Base:
-        // must also account for the total number of lines
-        offsetY = - line_height*(numLines - 1);
-        break;
-
-    case RS_VAlignment_Half:
-        // must also account for the total number of lines
-        offsetY = 0.5*(font_capline - line_height*(numLines - 1));
-        break;
-
-    case RS_VAlignment_Cap:
-        offsetY = font_capline;
-        break;
-
-    case RS_VAlignment_Ascent:
-        offsetY = font_ascent;
-        break;
-    }
-
-    return offsetY;
-}
-
-
-//////////////////////////////////////////////////////////////////////////////
-void LabelRendererBase::DeviceToMappingBounds(RS_Bounds& b)
-{
-    b.minx = m_renderer->_ITXD(b.minx);
-    b.maxx = m_renderer->_ITXD(b.maxx);
-
-    //y goes down in screen space, up in mapping space -- so reverse them
-    double swap = b.miny;
-    b.miny = m_renderer->_ITYD(b.maxy);
-    b.maxy = m_renderer->_ITYD(swap);
-}
-
-
-//////////////////////////////////////////////////////////////////////////////
-//computes axis aligned bounds of a point set
-void LabelRendererBase::ComputeBounds(RS_F_Point* RESTRICT pts, int npts, RS_Bounds& b)
-{
-    if (!npts) return;
-
-    b.minx = b.maxx = pts[0].x;
-    b.miny = b.maxy = pts[0].y;
-
-    for (int i=1; i<npts; i++)
-        b.add_point(pts[i]);
-}
-
-
-//////////////////////////////////////////////////////////////////////////////
-//Applies a given angle to an axis aligned bounding box.
-//Rotation point is lower left
-void LabelRendererBase::RotatedBounds(double x, double y, double width, double height, double angle_cw_rad, RS_F_Point* b)
-{
-#ifdef HEIDI
-    //HEIDI has y coordinate going up
-
-    double sina = sin(-angle_ccw_rad);
-    double cosa = cos(-angle_ccw_rad);
-
-    //apply rotation
-    //taking into account that y goes down (so subtract instead of adding for y)
-    b[0].x = x;
-    b[0].y = y;
-    b[1].x = b[0].x +  width * cosa;
-    b[1].y = b[0].y + (width * sina);
-    b[2].x = b[0].x +  width * cosa - height * sina;
-    b[2].y = b[0].y + (width * sina + height * cosa);
-    b[3].x = b[0].x                 - height * sina;
-    b[3].y = b[0].y + (               height * cosa);
-#else
-    //y goes down case
-
-    double sina = sin(angle_cw_rad);
-    double cosa = cos(angle_cw_rad);
-
-    //apply rotation
-    //taking into account that y goes down (so subtract instead of adding for y)
-    b[0].x = x;
-    b[0].y = y;
-    b[1].x = b[0].x +  width * cosa;
-    b[1].y = b[0].y - (width * sina);
-    b[2].x = b[0].x +  width * cosa - height * sina;
-    b[2].y = b[0].y - (width * sina + height * cosa);
-    b[3].x = b[0].x                 - height * sina;
-    b[3].y = b[0].y - (               height * cosa);
-#endif
-}
-
-
-//////////////////////////////////////////////////////////////////////////////
 bool LabelRendererBase::CloseEnough(RS_F_Point& p1, RS_F_Point& p2)
 {
     double delta = fabs(p2.y - p1.y) + fabs(p2.x - p1.x);

Modified: trunk/MgDev/Common/Stylization/LabelRendererBase.h
===================================================================
--- trunk/MgDev/Common/Stylization/LabelRendererBase.h	2007-03-06 17:02:52 UTC (rev 1157)
+++ trunk/MgDev/Common/Stylization/LabelRendererBase.h	2007-03-06 23:31:17 UTC (rev 1158)
@@ -19,19 +19,21 @@
 #define LABELRENDERERBASE_H
 
 #include "RendererStyles.h"
-#include "Bounds.h"
+#include "SE_LineBuffer.h"
 
-class GDRenderer;
+class Renderer;
 class LineBuffer;
 struct RS_Font;
+class SE_LabelInfo;
+class RS_FontEngine;
+class SE_Renderer;
 
 
 //////////////////////////////////////////////////////////////////////////////
 class LabelRendererBase
 {
-
 public:
-    LabelRendererBase(GDRenderer* renderer);
+    LabelRendererBase(Renderer* renderer, SE_Renderer* serenderer);
 
     virtual ~LabelRendererBase() {};
 
@@ -47,24 +49,25 @@
                                    bool             exclude,
                                    LineBuffer*      path) = 0;
 
+    //SE symbol-labels
+    virtual void ProcessLabelGroup(SE_LabelInfo*    labels,
+                                   int              nlabels,
+                                   RS_OverpostType  type,
+                                   bool             exclude,
+                                   SE_Geometry*      path) = 0;
+
     virtual void BlastLabels() = 0;
 
     virtual void AddExclusionRegion(RS_F_Point* pts, int npts) = 0;
 
 protected:
-    size_t SplitLabel(wchar_t* label, std::vector<wchar_t*>& line_breaks);
-
-    double GetHorizontalAlignmentOffset(RS_TextDef& tdef, RS_F_Point* extent);
-    double GetVerticalAlignmentOffset(RS_TextDef& tdef, const RS_Font* font, double actual_height, double line_height, size_t numLines);
-
-    void DeviceToMappingBounds(RS_Bounds& b);
-    void ComputeBounds(RS_F_Point* RESTRICT pts, int npts, RS_Bounds& b);
     void RotatedBounds(double x, double y, double width, double height, double angle_cw_rad, RS_F_Point* b);
 
     bool CloseEnough(RS_F_Point& p1, RS_F_Point& p2);
 
 protected:
-    GDRenderer* m_renderer;
+    Renderer* m_renderer;
+    SE_Renderer* m_serenderer;
 };
 
 #endif

Modified: trunk/MgDev/Common/Stylization/LabelRendererLocal.cpp
===================================================================
--- trunk/MgDev/Common/Stylization/LabelRendererLocal.cpp	2007-03-06 17:02:52 UTC (rev 1157)
+++ trunk/MgDev/Common/Stylization/LabelRendererLocal.cpp	2007-03-06 23:31:17 UTC (rev 1158)
@@ -31,8 +31,8 @@
 
 
 //////////////////////////////////////////////////////////////////////////////
-LabelRendererLocal::LabelRendererLocal(GDRenderer* renderer, double tileExtentOffset)
-: LabelRendererBase(renderer),
+LabelRendererLocal::LabelRendererLocal(Renderer* renderer, SE_Renderer* serenderer, double tileExtentOffset)
+: LabelRendererBase(renderer, serenderer),
   m_bOverpostGroupOpen(false),
   m_tileExtentOffset(tileExtentOffset)
 {
@@ -75,6 +75,8 @@
 {
     BeginOverpostGroup(type, true, exclude);
 
+    RS_FontEngine* fe = m_serenderer->GetFontEngine();
+
     // get the geometry type
     _ASSERT(path != NULL);
     int geomType = (path != NULL)? path->geom_type() : FdoGeometryType_None;
@@ -96,7 +98,7 @@
         // coming in on some tiles.
         RS_String stitch_key = text;
 
-        if (m_renderer->UseLocalOverposting())
+        if (true /*m_renderer->UseLocalOverposting()*/) //Local label renderer is only used for tiled mode
         {
             // TODO: stitch in subregions of tile
 //          const RS_Bounds& tileBounds = m_renderer->GetBounds();
@@ -133,10 +135,7 @@
             lblpath = new RS_F_Point[lblpathpts];
 
             for (int b=0; b<lblpathpts; b++)
-            {
-                lblpath[b].x = m_renderer->_TXD(lines[2*b]);
-                lblpath[b].y = m_renderer->_TYD(lines[2*b+1]);
-            }
+                m_serenderer->WorldToScreenPoint(lines[2*b], lines[2*b+1], lblpath[b].x, lblpath[b].y);
 
             _ASSERT(nlabels == 1);
             RS_LabelInfo* info = &labels[0];    // TODO: assumes one label
@@ -182,8 +181,8 @@
             RS_LabelInfo* info = &labels[i];
 
             // label is in device space
-            double offx = m_renderer->_MeterToMapSize(info->dunits(), info->dx());
-            double offy = m_renderer->_MeterToMapSize(info->dunits(), info->dy());
+            double offx = fe->MeterToMapSize(info->dunits(), info->dx());
+            double offy = fe->MeterToMapSize(info->dunits(), info->dy());
 
             LR_LabelInfoLocal lrinfo(info->x() + offx, info->y() + offy, text, info->tdef());
 
@@ -235,22 +234,21 @@
             double tileendx = (rejectBounds.maxx - b.minx) * invwidth;
             tileendx = rs_min(1.0, tileendx);
 
-
             double ypos = yoffset;
 
-            //move ypos up until we reach a relevant position that is likely to 
+            //move ypos up until we reach a relevant position that is likely to
             //draw a label that intersects the tile
             if (tilestarty != 0.0)
                 ypos += ceil((tilestarty - ypos) / yinc) * yinc;
 
             bool offset = false;
 
-            //loop to add labels 
+            //loop to add labels
             while (ypos <= tileendy)
             {
                 double xpos = xoffset + ((offset) ? 0.5 * xinc : 0.0);
 
-                //move to the right until we reach a relevant position that is likely to 
+                //move to the right until we reach a relevant position that is likely to
                 //draw a label that intersects the tile
                 if (tilestartx != 0.0)
                     xpos += ceil((tilestartx - xpos) / xinc) * xinc;
@@ -288,8 +286,8 @@
             RS_LabelInfo* info = &labels[i];
 
             // label is in device space
-            double offx = m_renderer->_MeterToMapSize(info->dunits(), info->dx());
-            double offy = m_renderer->_MeterToMapSize(info->dunits(), info->dy());
+            double offx = fe->MeterToMapSize(info->dunits(), info->dx());
+            double offy = fe->MeterToMapSize(info->dunits(), info->dy());
 
             LR_LabelInfoLocal lrinfo(info->x() + offx, info->y() + offy, text, info->tdef());
 
@@ -305,6 +303,17 @@
 
 
 //////////////////////////////////////////////////////////////////////////////
+//SE symbol-labels
+void LabelRendererLocal::ProcessLabelGroup(SE_LabelInfo*    labels,
+                                           int              nlabels,
+                                           RS_OverpostType  type,
+                                           bool             exclude,
+                                           SE_Geometry*      path)
+{
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
 void LabelRendererLocal::BeginOverpostGroup(RS_OverpostType type, bool render, bool exclude)
 {
     m_bOverpostGroupOpen = true;
@@ -500,8 +509,8 @@
             for (size_t k=0; k<info.m_numelems*4; k++)
             {
                 // don't need to worry about y-orientation in this case
-                double x = m_renderer->_ITXD(info.m_oriented_bounds[k].x);
-                double y = m_renderer->_ITYD(info.m_oriented_bounds[k].y);
+                double x, y;
+                m_serenderer->ScreenToWorldPoint(info.m_oriented_bounds[k].x, info.m_oriented_bounds[k].y, x, y);
 
                 minX = rs_min(minX, x);
                 maxX = rs_max(maxX, x);
@@ -722,24 +731,9 @@
         {
             LR_LabelInfoLocal& info = group.m_labels[j];
 
-            if (info.m_charpos)
-            {
-                delete [] info.m_charpos;
-                info.m_charpos = NULL;
-            }
+            delete [] info.m_oriented_bounds;
+            info.m_oriented_bounds = NULL;
 
-            if (info.m_oriented_bounds)
-            {
-                delete [] info.m_oriented_bounds;
-                info.m_oriented_bounds = NULL;
-            }
-
-            if (info.m_spacing)
-            {
-                delete [] info.m_spacing;
-                info.m_spacing = NULL;
-            }
-
             info.m_numpts = 0;
             info.m_numelems = 0;
         }
@@ -750,80 +744,40 @@
     m_overpost.Clear();
 }
 
+
 //////////////////////////////////////////////////////////////////////////////
 bool LabelRendererLocal::ComputeSimpleLabelBounds(LR_LabelInfoLocal& info)
 {
-    // font matching
-    info.m_font = m_renderer->FindFont(info.m_tdef.font());
-    if (!info.m_font)
+    //match the font and measure the sizes of the characters
+    if (!m_serenderer->GetFontEngine()->GetTextMetrics(info.m_text, info.m_tdef, info.m_tm, false))
         return false;
 
-    //determine pixel space font height
-    info.m_hgt = m_renderer->_MeterToMapSize(info.m_tdef.font().units(), info.m_tdef.font().height());
-    info.m_hgt *= m_renderer->GetMapToScreenScale() * 0.75;
-
-    // The computed height can have roundoff in it, and the rendering code is
-    // very sensitive to it.  Remove this roundoff by rounding the height to
-    // the nearest 1/65536ths of a point.
-    info.m_hgt = floor(info.m_hgt * 65536.0 + 0.5) / 65536.0;
-
     //radian CCW rotation
     double rotation = info.m_tdef.rotation() * M_PI / 180.0;
     double cos_a = cos(rotation);
     double sin_a = sin(rotation);
 
-    // font height gives the distance from one baseline to the next
-    // increase this by a factor of 1.05 (what GD uses)
-    double font_height = info.m_font->m_height * info.m_hgt / info.m_font->m_units_per_EM;
-    double line_height = 1.05 * font_height;
-
     // transform insertion point into pixel space
-    info.m_ins_point.x = m_renderer->_TXD(info.m_x);
-    info.m_ins_point.y = m_renderer->_TYD(info.m_y);
+    m_serenderer->WorldToScreenPoint(info.m_x, info.m_y, info.m_ins_point.x, info.m_ins_point.y);
 
     //-------------------------------------------------------
-    // break up the string into individual lines
-    //-------------------------------------------------------
-
-    // make a temporary copy
-    size_t len = wcslen(info.m_text.c_str());
-    wchar_t* cpy = (wchar_t*)alloca((len + 1) * sizeof(wchar_t));
-    wcscpy(cpy, info.m_text.c_str());
-
-    // break it up
-    std::vector<wchar_t*> line_breaks;
-    size_t num_lines = SplitLabel(cpy, line_breaks);
-
-    //-------------------------------------------------------
     // text extent and alignment computation
     //-------------------------------------------------------
 
     RS_F_Point fpts[4];
     RS_Bounds rotatedBounds(+DBL_MAX, +DBL_MAX, -DBL_MAX, -DBL_MAX);
 
-    // base vertical offset is the same for each line of text
-    double vAlignBaseOffset = GetVerticalAlignmentOffset(info.m_tdef, info.m_font, info.m_hgt, line_height, num_lines);
-
-    for (size_t k=0; k<num_lines; ++k)
+    for (size_t k=0; k<info.m_tm.line_pos.size(); ++k)
     {
-        wchar_t* txt = line_breaks.at(k);
+        //convert the unrotated measured bounds for the current line to a local point array
+        memcpy(fpts, info.m_tm.line_pos[k].ext, sizeof(fpts));
 
-        // get the unrotated extent of this sub-string
-        m_renderer->MeasureString(txt, info.m_hgt, info.m_font, 0.0, fpts, NULL);
-
-        // horizontal offset depends on the sub-string width, while
-        // vertical offset depends on the line of text
-        double hAlignOffset = GetHorizontalAlignmentOffset(info.m_tdef, fpts);
-        double vAlignOffset = vAlignBaseOffset + k*line_height;
-
         // process the extent points
         for (int j=0; j<4; ++j)
         {
-            // translate to account for the alignment
-            double tmpX = fpts[j].x + hAlignOffset;
-            double tmpY = fpts[j].y + vAlignOffset;
-
             // rotate and translate to the insertion point
+            double tmpX = fpts[j].x;
+            double tmpY = fpts[j].y;
             fpts[j].x = info.m_ins_point.x + tmpX * cos_a + tmpY * sin_a;
             fpts[j].y = info.m_ins_point.y - tmpX * sin_a + tmpY * cos_a;
 
@@ -886,34 +840,12 @@
 //////////////////////////////////////////////////////////////////////////////
 bool LabelRendererLocal::ComputePathLabelBounds(LR_LabelInfoLocal& info, std::vector<LR_LabelInfoLocal>& repeated_infos)
 {
-    // font matching
-    info.m_font = m_renderer->FindFont(info.m_tdef.font());
-    if (!info.m_font)
+    RS_FontEngine* fe = m_serenderer->GetFontEngine();
+
+    //match the font and measure the sizes of the characters
+    if (!fe->GetTextMetrics(info.m_text, info.m_tdef, info.m_tm, true))
         return false;
 
-    //determine pixel space font height
-    info.m_hgt = m_renderer->_MeterToMapSize(info.m_tdef.font().units(), info.m_tdef.font().height());
-    info.m_hgt *= m_renderer->GetMapToScreenScale() * 0.75;
-
-    // The computed height can have roundoff in it, and the rendering code is
-    // very sensitive to it.  Remove this roundoff by rounding the height to
-    // the nearest 1/65536ths of a point.
-    info.m_hgt = floor(info.m_hgt * 65536.0 + 0.5) / 65536.0;
-
-    //-------------------------------------------------------
-    // text extent and alignment computation
-    //-------------------------------------------------------
-
-    //get overall extent and char spacing
-    RS_F_Point fpts[4];
-    float* spacing = (float*)alloca(info.m_text.length() * 2 * sizeof(float));
-    m_renderer->MeasureString(info.m_text, info.m_hgt, info.m_font, 0.0, fpts, spacing);
-
-    //the width and height of this particular string
-    //TODO: we can be more precise if we get height on per character basis
-    info.m_texthgt = fabs(fpts[2].y - fpts[0].y);
-    info.m_textwid = fabs(fpts[1].x - fpts[0].x);
-
     //allocate the data we need
     info.m_numelems = info.m_text.length();
 
@@ -935,7 +867,7 @@
 
     //how many times should we repeat the label along the polyline?
     //TODO: fine tune this formula
-    int numreps = (int)(seglens[info.m_numpts-1] / (200.0 + info.m_textwid));
+    int numreps = (int)(seglens[info.m_numpts-1] / (200.0 + info.m_tm.text_width));
     if (!numreps) numreps = 1;
 
     for (int i=0; i<numreps; i++)
@@ -947,10 +879,7 @@
         LR_LabelInfoLocal copy_info = info;
         copy_info.m_pts = NULL;
         copy_info.m_numpts = 0;
-
-        copy_info.m_charpos = new CharPos[copy_info.m_numelems];
         copy_info.m_oriented_bounds = new RS_F_Point[4*copy_info.m_numelems];
-        copy_info.m_spacing = new double[copy_info.m_numelems - 1];
 
         //parametric position for current repeated label
         //positions are spaced in such a way that each label has
@@ -958,61 +887,8 @@
         double param_position = ((double)i + 0.5) / (double)numreps;
 
         //compute position and angle along the path for each character
-        double font_scale = ComputeCharacterPositions(info, seglens, param_position, spacing, copy_info.m_textwid, copy_info.m_charpos);
+        bool ret = fe->LayoutPathText(copy_info.m_tm, info.m_pts, info.m_numpts, seglens, param_position, info.m_tdef.valign(), 0);
 
-        //update font height to value that curve fitting suggested
-        if (font_scale != 1.0)
-        {
-            //don't bother measuring the string with the new height,
-            //scaling should work almost as good
-            copy_info.m_hgt     *= font_scale;
-            copy_info.m_texthgt *= font_scale;
-            copy_info.m_textwid *= font_scale;
-        }
-
-        //copy over scaled character advance
-        for (size_t i=0; i<copy_info.m_numelems - 1; i++)
-            copy_info.m_spacing[i] = spacing[i] * font_scale;
-
-        //take into account text vertical alignment
-        //horizontal alignment is ignored in this case
-        for (size_t i=0; i<copy_info.m_numelems; i++)
-        {
-            //TODO:
-            double font_cap_height = copy_info.m_hgt;
-            double font_ascent     = copy_info.m_hgt;
-            double font_descent    = 0;
-
-            // get the height vector
-            double dyh = 0.0;
-
-            RS_VAlignment vAlign = copy_info.m_tdef.valign();
-            switch (vAlign)
-            {
-                case RS_VAlignment_Descent: dyh = -font_descent;        break;
-                case RS_VAlignment_Base:                                break;
-                case RS_VAlignment_Half:    dyh =  font_cap_height/2.0; break;
-                case RS_VAlignment_Cap:     dyh =  font_cap_height;     break;
-                case RS_VAlignment_Ascent:  dyh =  font_ascent;         break;
-                default:                                                break;
-            }
-
-            // add in the rotated vertical alignment contribution
-            double angle = copy_info.m_charpos[i].anglerad;
-
-            //take into account that y axis goes down in our coordinate system
-            dyh = -dyh;
-
-            double cs = cos(angle);
-            double sn = sin(angle);
-            double hAlignOffset = -sn*dyh;
-            double vAlignOffset =  cs*dyh;
-
-            //adjust insertion point
-            copy_info.m_charpos[i].x += hAlignOffset;
-            copy_info.m_charpos[i].y -= vAlignOffset;
-        }
-
         //once we have position and angle for each character
         //compute oriented bounding box for each character
         double total_advance = 0.0;
@@ -1022,12 +898,12 @@
             //it takes kerning into account, but should be good enough
             //we could measure each character separately but that seems like
             //too many calls to FreeType
-            double advance = (i == copy_info.m_numelems-1)? copy_info.m_textwid - total_advance : spacing[i] * font_scale;
+            double advance = (i == copy_info.m_numelems-1)? copy_info.m_tm.text_width - total_advance : copy_info.m_tm.char_advances[i];
             total_advance += advance;
 
             //compute rotated bounds of character
             RS_F_Point* b = &copy_info.m_oriented_bounds[i * 4];
-            RotatedBounds(copy_info.m_charpos[i].x, copy_info.m_charpos[i].y, advance, copy_info.m_texthgt, copy_info.m_charpos[i].anglerad, b);
+            RotatedBounds(copy_info.m_tm.char_pos[i].x, copy_info.m_tm.char_pos[i].y, advance, copy_info.m_tm.text_height, copy_info.m_tm.char_pos[i].anglerad, b);
 
     #ifdef DEBUG_LABELS
             static int featIdP = -1;
@@ -1058,182 +934,7 @@
     return true;
 }
 
-//////////////////////////////////////////////////////////////////////////////
-//computes position and rotation of each character along the
-//feature to be labeled -- it may return a scale factor to be
-//applied to the font size to make the label fit better in the
-//allotted space
-double LabelRendererLocal::ComputeCharacterPositions(LR_LabelInfoLocal& info, double* seglens, double position, float* kerned_spacing, double measured_width, CharPos* ret)
-{
-    //determine in which direction we should follow the polyline
-    //so that the label points up more likely than down
-    //find the length of polyline that requires inverting versus
-    //length that does not and see which one is bigger
-    //TODO: this loop should really be performed on the piece of the
-    //polyline where we will be labeling since otherwise features like
-    //circles can throw it off and so a label may still end up upside down
-    double inverted_len = 0.0;
 
-    for (int m=0; m<info.m_numpts - 1; m++)
-    {
-        RS_F_Point p0 = info.m_pts[m];
-        RS_F_Point p1 = info.m_pts[m+1];
-
-        double angle = -atan2(p1.y - p0.y, p1.x - p0.x);
-
-        if (angle > M_PI/2.0 || angle < -M_PI/2.0)
-            inverted_len += seglens[m+1] - seglens[m];
-        else
-            inverted_len -= seglens[m+1] - seglens[m];
-    }
-
-    bool reverse = (inverted_len > 0.0);
-
-    double pathlen = seglens[info.m_numpts - 1];
-
-    //compute font height that better fits the geometry
-    //but limit scaling to be in the range [0.5 - 1.0]
-    double font_scale = rs_min(1.0, rs_max(0.5, pathlen / (1.1 * measured_width)));
-
-    //distance of current character along current segment
-    //initialize to start position
-    double dist_along_segment = position * pathlen - 0.5 * measured_width * font_scale;
-
-    //j indicates index of segment we are on with current character
-    int j;
-
-    //segment for current character
-    RS_F_Point start;
-    RS_F_Point end;
-
-    if (reverse)
-    {
-        //case where we want to walk along the polyline
-        //in reverse
-
-        //compute starting segment
-        for (j=info.m_numpts-2; j>=0; j--)
-            if (dist_along_segment < pathlen - seglens[j])
-                break;
-
-        if (j < 0) j=0;
-
-        start = info.m_pts[j+1];
-        end = info.m_pts[j];
-        dist_along_segment -= pathlen - seglens[j+1];
-    }
-    else
-    {
-        //case where we follow the polyline forwards
-
-        //compute starting segment
-        for (j=0; j<info.m_numpts-1; j++)
-            if (dist_along_segment < seglens[j+1])
-                break;
-
-        if (j >= info.m_numpts-1)
-            j=info.m_numpts-2;
-
-        start = info.m_pts[j];
-        end = info.m_pts[j+1];
-        dist_along_segment -= seglens[j];
-    }
-
-    //length of current segment
-    double seg_len = seglens[j+1] - seglens[j];
-
-    //position of current character relative to the left end of the string
-    double char_pos = 0;
-
-    int numchars = (int)info.m_text.length();
-
-    //The premise here is that we will compute three positions along the path
-    //for each character - one for the left corner, one for the right
-    //and one for the centerpoint
-    //We will compute a tangent vector based on the left and right points
-    //and then position the character relative to the point computed for its
-    //center with the normal comuted from the left and right points
-    //Note that the end position of one character equals the start position
-    //of the next, so in fact we need to compute 2 * n + 1 points
-    RS_F_Point* positions = (RS_F_Point*)alloca(sizeof(RS_F_Point) * (numchars * 2 + 1));
-
-    for (int i=0; i <= numchars * 2; i++)
-    {
-        //check if we need to move to next segment
-        while (dist_along_segment > seg_len)
-        {
-            if (reverse)
-            {
-                //case where we go in reverse direction of the path
-                if (j > 0)
-                {
-                    j--;
-                    dist_along_segment -= seg_len;
-                    seg_len = seglens[j+1] - seglens[j];
-                    start = info.m_pts[j+1];
-                    end = info.m_pts[j];
-                }
-                else
-                    break;
-            }
-            else
-            {
-                //case where we go forward along the path
-                if (j < info.m_numpts - 2)
-                {
-                    j++;
-                    dist_along_segment -= seg_len;
-                    seg_len = seglens[j+1] - seglens[j];
-                    start = info.m_pts[j];
-                    end = info.m_pts[j+1];
-                }
-                else
-                    break;
-            }
-        }
-
-        //compute position along current segment using weighted
-        //normalized end-start vector
-        double weight = dist_along_segment / seg_len;
-        double dx = end.x - start.x;
-        double dy = end.y - start.y;
-
-        positions[i].x = start.x + dx * weight;
-        positions[i].y = start.y + dy * weight;
-
-        //kerned width of current character
-        int index = i / 2; //which character are we working with -- 3 iterations for each one
-        double char_width = (index >= numchars - 1) ? measured_width - char_pos : kerned_spacing[index];
-
-        //advance cursor by half the width of the current character
-        dist_along_segment += char_width * 0.5 * font_scale;
-        char_pos += char_width * 0.5;
-    }
-
-    char_pos = 0.0;
-
-    //now compute character placement and angles based on the positioning points
-    for (int i=0; i<numchars; i++)
-    {
-        //find angle based on left and right of character
-        ret[i].anglerad = -atan2(positions[2*i+2].y - positions[2*i].y,positions[2*i+2].x - positions[2*i].x);
-
-        //kerned width of current character
-        double char_width = (i == numchars - 1) ? measured_width - char_pos : kerned_spacing[i];
-        double char_width_2 = 0.5 * char_width * font_scale;
-
-        //and now find a lower left insertion point
-        //based on the midpoint anchor and the angle
-        ret[i].x = positions[2*i+1].x - cos(ret[i].anglerad) * char_width_2;
-        ret[i].y = positions[2*i+1].y + sin(ret[i].anglerad) * char_width_2; //y down means + sin
-
-        char_pos += char_width;
-    }
-
-    return font_scale;
-}
-
-
 //////////////////////////////////////////////////////////////////////////////
 void LabelRendererLocal::ProcessLabelGroupsInternal(SimpleOverpost* pMgr, std::vector<LR_OverpostGroupLocal*>& groups)
 {
@@ -1295,14 +996,13 @@
     //-------------------------------------------------------
     // draw the label
     //-------------------------------------------------------
-
     if (render)
     {
         // call the appropriate routine
-        if (info.m_charpos != NULL)
-            DrawPathLabel(info);
+        if (info.m_tm.char_pos.size() > 0) //detect whether it's path text or not
+            m_serenderer->GetFontEngine()->DrawPathText(info.m_tm, info.m_tdef);
         else
-            DrawSimpleLabel(info);
+            m_serenderer->GetFontEngine()->DrawBlockText(info.m_tm, info.m_tdef, info.m_ins_point.x, info.m_ins_point.y);
     }
 
     return true;
@@ -1310,240 +1010,6 @@
 
 
 //////////////////////////////////////////////////////////////////////////////
-void LabelRendererLocal::DrawSimpleLabel(LR_LabelInfoLocal& info)
-{
-    //radian CCW rotation
-    double rotation = info.m_tdef.rotation() * M_PI / 180.0;
-    double cos_a = cos(rotation);
-    double sin_a = sin(rotation);
-
-    // font height gives the distance from one baseline to the next
-    // increase this by a factor of 1.05 (what GD uses)
-    double font_height = info.m_font->m_height * info.m_hgt / info.m_font->m_units_per_EM;
-    double line_height = 1.05 * font_height;
-
-    //-------------------------------------------------------
-    // break up the string into individual lines
-    //-------------------------------------------------------
-
-    // make a temporary copy
-    size_t len = wcslen(info.m_text.c_str());
-    wchar_t* cpy = (wchar_t*)alloca((len + 1) * sizeof(wchar_t));
-    wcscpy(cpy, info.m_text.c_str());
-
-    // break it up
-    std::vector<wchar_t*> line_breaks;
-    size_t num_lines = SplitLabel(cpy, line_breaks);
-
-    //-------------------------------------------------------
-    // text extent and alignment computation
-    //-------------------------------------------------------
-
-    RS_F_Point fpts[4];
-    RS_Bounds unrotatedBounds(+DBL_MAX, +DBL_MAX, -DBL_MAX, -DBL_MAX);
-
-    double* hAlignOffsets = (double*)alloca(num_lines * sizeof(double));
-    double* vAlignOffsets = (double*)alloca(num_lines * sizeof(double));
-    double* textWidths    = (double*)alloca(num_lines * sizeof(double));
-
-    // base vertical offset is the same for each line of text
-    double vAlignBaseOffset = GetVerticalAlignmentOffset(info.m_tdef, info.m_font, info.m_hgt, line_height, num_lines);
-
-    for (size_t k=0; k<num_lines; ++k)
-    {
-        wchar_t* txt = line_breaks.at(k);
-
-        // get the unrotated extent of this sub-string
-        m_renderer->MeasureString(txt, info.m_hgt, info.m_font, 0.0, fpts, NULL);
-
-        // horizontal offset depends on the sub-string width, while
-        // vertical offset depends on the line of text
-        hAlignOffsets[k] = GetHorizontalAlignmentOffset(info.m_tdef, fpts);
-        vAlignOffsets[k] = vAlignBaseOffset + k*line_height;
-
-        // remember the width
-        textWidths[k] = fpts[1].x - fpts[0].x;
-
-        // process the extent points
-        for (int j=0; j<4; ++j)
-        {
-            // translate to account for the alignment
-            fpts[j].x += hAlignOffsets[k];
-            fpts[j].y += vAlignOffsets[k];
-
-            // update the overall unrotated bounds
-            unrotatedBounds.add_point(fpts[j]);
-        }
-    }
-
-    //-------------------------------------------------------
-    // draw the text
-    //-------------------------------------------------------
-
-    // draw the opaque background first, if requested
-    if (info.m_tdef.textbg() == RS_TextBackground_Opaque)
-    {
-        // get the overall unrotated bounds
-        unrotatedBounds.get_points(fpts);
-
-        // rotate and translate it
-        for (int j=0; j<4; ++j)
-        {
-            double tmpX = fpts[j].x;
-            double tmpY = fpts[j].y;
-            fpts[j].x = info.m_ins_point.x + tmpX * cos_a + tmpY * sin_a;
-            fpts[j].y = info.m_ins_point.y - tmpX * sin_a + tmpY * cos_a;
-        }
-
-        // draw a filled rectangle
-        RS_D_Point dpts[4];
-        for (int j=0; j<4; j++)
-        {
-            dpts[j].x = ROUND(fpts[j].x);
-            dpts[j].y = ROUND(fpts[j].y);
-        }
-
-        gdImageFilledPolygon((gdImagePtr)m_renderer->GetImage(), (gdPointPtr)dpts, 4, ConvertColor((gdImagePtr)m_renderer->GetImage(), info.m_tdef.bgcolor()));
-    }
-
-    for (size_t k=0; k<num_lines; ++k)
-    {
-        RS_String txt = line_breaks.at(k);
-
-        // add the rotated original offset for this line to the insertion point
-        // to get the actual draw point
-        double insX = info.m_ins_point.x + hAlignOffsets[k] * cos_a + vAlignOffsets[k] * sin_a;
-        double insY = info.m_ins_point.y - hAlignOffsets[k] * sin_a + vAlignOffsets[k] * cos_a;
-
-        int posx = (int)floor(insX + 0.5);
-        int posy = (int)floor(insY + 0.5);
-
-        // render the ghosted text, if requested
-        if (info.m_tdef.textbg() == RS_TextBackground_Ghosted)
-        {
-            m_renderer->DrawString(txt, posx-1, posy, info.m_hgt, info.m_font, info.m_tdef.bgcolor(), rotation);
-            m_renderer->DrawString(txt, posx+1, posy, info.m_hgt, info.m_font, info.m_tdef.bgcolor(), rotation);
-            m_renderer->DrawString(txt, posx, posy-1, info.m_hgt, info.m_font, info.m_tdef.bgcolor(), rotation);
-            m_renderer->DrawString(txt, posx, posy+1, info.m_hgt, info.m_font, info.m_tdef.bgcolor(), rotation);
-        }
-
-        // render the primary text
-        m_renderer->DrawString(txt, posx, posy, info.m_hgt, info.m_font, info.m_tdef.color(), rotation);
-
-        // render the underline, if requested
-        if (info.m_tdef.font().style() & RS_FontStyle_Underline)
-        {
-            // estimate underline line width as % of font height
-            double line_width = (double)info.m_font->m_underline_thickness * info.m_hgt / (double)info.m_font->m_units_per_EM;
-            double line_pos = - (double)info.m_font->m_underline_position * info.m_hgt / (double)info.m_font->m_units_per_EM;
-
-            // the line's start point is the insertion point, but shifted vertically by line_pos
-            double x0 = insX + line_pos * sin_a;
-            double y0 = insY + line_pos * cos_a;
-
-            // the end point is a horizontal shift by the text width
-            double x1 = x0 + textWidths[k] * cos_a;
-            double y1 = y0 - textWidths[k] * sin_a;
-
-            // draw the thick line
-            gdImageSetThickness((gdImagePtr)m_renderer->GetImage(), ROUND(line_width));
-            gdImageSetAntiAliased((gdImagePtr)m_renderer->GetImage(), ConvertColor((gdImagePtr)m_renderer->GetImage(), info.m_tdef.color()));
-            gdImageLine((gdImagePtr)m_renderer->GetImage(), ROUND(x0), ROUND(y0), ROUND(x1), ROUND(y1), gdAntiAliased);
-            gdImageSetThickness((gdImagePtr)m_renderer->GetImage(), 0);
-        }
-    }
-}
-
-
-//////////////////////////////////////////////////////////////////////////////
-void LabelRendererLocal::DrawPathLabel(LR_LabelInfoLocal& info)
-{
-    //draw the characters, each in its computed position
-    RS_String c;
-    for (size_t i=0; i<info.m_numelems; ++i)
-    {
-        c = info.m_text[i], 1;
-
-        //compute screen position and round
-        int posx = ROUND(info.m_charpos[i].x);
-        int posy = ROUND(info.m_charpos[i].y);
-
-        if (info.m_tdef.textbg() == RS_TextBackground_Ghosted)
-        {
-            m_renderer->DrawString(c, posx-1, posy, info.m_hgt, info.m_font, info.m_tdef.bgcolor(), info.m_charpos[i].anglerad);
-            m_renderer->DrawString(c, posx+1, posy, info.m_hgt, info.m_font, info.m_tdef.bgcolor(), info.m_charpos[i].anglerad);
-            m_renderer->DrawString(c, posx, posy-1, info.m_hgt, info.m_font, info.m_tdef.bgcolor(), info.m_charpos[i].anglerad);
-            m_renderer->DrawString(c, posx, posy+1, info.m_hgt, info.m_font, info.m_tdef.bgcolor(), info.m_charpos[i].anglerad);
-        }
-
-        m_renderer->DrawString(c, posx, posy, info.m_hgt, info.m_font, info.m_tdef.color(), info.m_charpos[i].anglerad);
-    }
-
-    //render underline
-    if (info.m_tdef.font().style() & RS_FontStyle_Underline)
-    {
-        const RS_Font * font = info.m_font;
-
-        //estimate underline line width as % of font height
-        double line_width = (double)font->m_underline_thickness * info.m_hgt / (double)font->m_units_per_EM;
-        //underline position w.r.t. baseline. Invert y while at it
-        double line_pos = - (double)font->m_underline_position * info.m_hgt / (double)font->m_units_per_EM;
-
-        //accumulator for underline purposes
-        double total_advance = 0.0;
-
-        //used to keep track of last position of the underline, which is 
-        //drawn piecewise for each character
-        int last_x = ROUND(info.m_charpos[0].x + sin(info.m_charpos[0].anglerad) * line_pos);
-        int last_y = ROUND(info.m_charpos[0].y + cos(info.m_charpos[0].anglerad) * line_pos);
-        int sx, sy, ex, ey;
-
-        //draw the characters, each in its computed position
-        for (size_t i=0; i<info.m_numelems; i++)
-        {
-            //width of character - not really exact width since
-            //it takes kerning into account, but should be good enough
-            //we could measure each character separately but that seems like
-            //too many calls to FreeType
-            //note that unlike the regular label renderer, here the char spacing
-            //array is already scaled by the font scale so we don't have to do it here
-            double advance = (i == info.m_numelems-1)? info.m_textwid - total_advance : info.m_spacing[i];
-            total_advance += advance;
-
-            sx = last_x;
-            sy = last_y;
-
-            if (i == info.m_numelems - 1) //is it the last char -- needs special handling
-            {
-                //estimate bottom right corner of last character
-                double eex = info.m_charpos[i].x + cos(info.m_charpos[i].anglerad) * advance;
-                double eey = info.m_charpos[i].y - sin(info.m_charpos[i].anglerad) * advance;
-
-                //now take into account underline offset
-                ex = ROUND(eex + sin(info.m_charpos[i].anglerad) * line_pos);
-                ey = ROUND(eey + cos(info.m_charpos[i].anglerad) * line_pos);
-            }
-            else
-            {                
-                //move position by underline offset
-                ex = ROUND(info.m_charpos[i+1].x + sin(info.m_charpos[i+1].anglerad) * line_pos);
-                ey = ROUND(info.m_charpos[i+1].y + cos(info.m_charpos[i+1].anglerad) * line_pos);
-            }
-
-            gdImageSetThickness((gdImagePtr)m_renderer->GetImage(), ROUND(line_width));
-            gdImageSetAntiAliased((gdImagePtr)m_renderer->GetImage(), ConvertColor((gdImagePtr)m_renderer->GetImage(), info.m_tdef.color()));
-            gdImageLine((gdImagePtr)m_renderer->GetImage(), sx, sy, ex, ey, gdAntiAliased);
-            gdImageSetThickness((gdImagePtr)m_renderer->GetImage(), 0);
-
-            last_x = ex;
-            last_y = ey;
-        }
-    }
-
-}
-
-
-//////////////////////////////////////////////////////////////////////////////
 void LabelRendererLocal::AddExclusionRegion(RS_F_Point* pts, int npts)
 {
     AddExclusionRegion(&m_overpost, pts, npts);
@@ -1553,36 +1019,28 @@
 //////////////////////////////////////////////////////////////////////////////
 void LabelRendererLocal::AddExclusionRegion(SimpleOverpost* pMgr, RS_F_Point* pts, int npts)
 {
-    //use axis aligned bounds for overposting
-    //TODO: can be improved to use the given polygon as is
-    //instead of taking its bounds
-    RS_Bounds axis_bounds;
-    ComputeBounds(pts, npts, axis_bounds);
+    RS_F_Point* tmp = (RS_F_Point*)alloca(npts * sizeof(RS_F_Point));
 
-    //convert to mapping space for overpost tracking
-    //this is needed so that we can do overposting
-    //across map tiles generated at different times
-    DeviceToMappingBounds(axis_bounds);
+    //convert back to mapping space since the overpost manager uses mapping space
+    //bounding boxes
+    for (int i=0; i<npts; i++)
+        m_serenderer->ScreenToWorldPoint(pts[i].x, pts[i].y, tmp[i].x, tmp[i].y);
 
-    pMgr->AddRegion(axis_bounds);
+    pMgr->AddRegion(tmp, npts);
 }
 
 
 //////////////////////////////////////////////////////////////////////////////
 bool LabelRendererLocal::OverlapsStuff(SimpleOverpost* pMgr, RS_F_Point* pts, int npts)
 {
-    //use axis aligned bounds for overposting
-    //TODO: can be improved to use the given polygon as is
-    //instead of taking its bounds
-    RS_Bounds axis_bounds;
-    ComputeBounds(pts, npts, axis_bounds);
+    RS_F_Point* tmp = (RS_F_Point*)alloca(npts * sizeof(RS_F_Point));
 
-    //convert to mapping space for overpost tracking
-    //this is needed so that we can do overposting
-    //across map tiles generated at different times
-    DeviceToMappingBounds(axis_bounds);
+    //convert back to mapping space since the overpost manager uses mapping space
+    //bounding boxes
+    for (int i=0; i<npts; i++)
+        m_serenderer->ScreenToWorldPoint(pts[i].x, pts[i].y, tmp[i].x, tmp[i].y);
 
-    return pMgr->Overlaps(axis_bounds);
+    return pMgr->Overlaps(tmp, npts);
 }
 
 

Modified: trunk/MgDev/Common/Stylization/LabelRendererLocal.h
===================================================================
--- trunk/MgDev/Common/Stylization/LabelRendererLocal.h	2007-03-06 17:02:52 UTC (rev 1157)
+++ trunk/MgDev/Common/Stylization/LabelRendererLocal.h	2007-03-06 23:31:17 UTC (rev 1158)
@@ -15,11 +15,12 @@
 //  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 //
 
-#ifndef LABELRENDERER2_H
-#define LABELRENDERER2_H
+#ifndef LABELRENDERERLOCAL_H
+#define LABELRENDERERLOCAL_H
 
 #include "LabelRendererBase.h"
 #include "SimpleOverpost.h"
+#include "RS_FontEngine.h"
 
 
 //////////////////////////////////////////////////////////////////////////////
@@ -35,9 +36,7 @@
           m_pts(NULL),
           m_numpts(0),
           m_numelems(0),
-          m_oriented_bounds(NULL),
-          m_charpos(NULL),
-          m_spacing(NULL)
+          m_oriented_bounds(NULL)
     {
     }
 
@@ -50,10 +49,6 @@
     RS_F_Point* m_pts;
     int m_numpts;
 
-    const RS_Font* m_font;
-    double m_hgt;
-    double m_textwid;
-    double m_texthgt;
     RS_F_Point m_ins_point;
 
     // number of elements this label consists of
@@ -66,11 +61,9 @@
     // - there's one bounds per element
     RS_F_Point* m_oriented_bounds;
 
-    // stores data for individual characters of a path label
-    CharPos* m_charpos;
-
-    // stores horizontal advance per character (including kerning)
-    double* m_spacing;
+    // stores matched font, measured text size, kerned char spacings
+    // layout character positions
+    RS_TextMetrics m_tm;
 };
 
 
@@ -97,9 +90,8 @@
 //////////////////////////////////////////////////////////////////////////////
 class LabelRendererLocal : public LabelRendererBase
 {
-
 public:
-    LabelRendererLocal(GDRenderer* renderer, double tileExtentOffset);
+    LabelRendererLocal(Renderer* renderer, SE_Renderer* serenderer, double tileExtentOffset);
     virtual ~LabelRendererLocal();
 
     virtual void StartLabels();
@@ -114,6 +106,13 @@
                                    bool             exclude,
                                    LineBuffer*      path);
 
+    //SE symbol-labels
+    virtual void ProcessLabelGroup(SE_LabelInfo*    labels,
+                                   int              nlabels,
+                                   RS_OverpostType  type,
+                                   bool             exclude,
+                                   SE_Geometry*      path);
+
     virtual void BlastLabels();
 
     virtual void AddExclusionRegion(RS_F_Point* pts, int npts);
@@ -124,11 +123,7 @@
 
     bool ComputeSimpleLabelBounds(LR_LabelInfoLocal& info);
     bool ComputePathLabelBounds(LR_LabelInfoLocal& info, std::vector<LR_LabelInfoLocal>& repeated_infos);
-    double ComputeCharacterPositions(LR_LabelInfoLocal& info, double* seglens, double position, float* kerned_spacing, double measured_width, CharPos* ret);
 
-    void DrawSimpleLabel(LR_LabelInfoLocal& info);
-    void DrawPathLabel(LR_LabelInfoLocal& info);
-
     void ProcessLabelGroupsInternal(SimpleOverpost* pMgr, std::vector<LR_OverpostGroupLocal*>& groups);
     bool ProcessLabelInternal(SimpleOverpost* pMgr, LR_LabelInfoLocal& info, bool render, bool exclude, bool check);
 

Modified: trunk/MgDev/Common/Stylization/LineBuffer.cpp
===================================================================
--- trunk/MgDev/Common/Stylization/LineBuffer.cpp	2007-03-06 17:02:52 UTC (rev 1157)
+++ trunk/MgDev/Common/Stylization/LineBuffer.cpp	2007-03-06 23:31:17 UTC (rev 1158)
@@ -59,6 +59,12 @@
     m_xformbuf_len = 0;
 }
 
+
+LineBuffer::LineBuffer()
+{
+}
+
+
 LineBuffer::~LineBuffer()
 {
     delete[] m_types;
@@ -69,6 +75,7 @@
         delete [] m_xformbuf;
 }
 
+
 void LineBuffer::Reset()
 {
     m_bounds = RS_Bounds(DBL_MAX, DBL_MAX, -DBL_MAX, -DBL_MAX);
@@ -78,11 +85,13 @@
     m_cur_cntr = -1;//will increment with first MoveTo segment
 }
 
+
 void LineBuffer::SetGeometryType(int geomType)
 {
     m_geom_type = geomType;
 }
 
+
 void LineBuffer::MoveTo(double x, double y)
 {
     if (m_cur_types == m_types_len)
@@ -103,6 +112,7 @@
     AddToBounds(x, y);
 }
 
+
 void LineBuffer::LineTo(double x, double y)
 {
     if (m_cur_types == m_types_len)
@@ -133,6 +143,7 @@
     LineTo(m_last_x, m_last_y);
 }
 
+
 inline void LineBuffer::AddToBounds(double x, double y)
 {
     if (x < m_bounds.minx)
@@ -164,6 +175,7 @@
     m_types_len *= 2;
 }
 
+
 void LineBuffer::ResizeContours()
 {
     int* tempCntrs = new int[m_cntrs_len * 2];
@@ -174,7 +186,6 @@
 }
 
 
-
 ///////////////////////////////////////////////////////////////////////////////
 ///////////////////////////////////////////////////////////////////////////////
 ////
@@ -184,6 +195,8 @@
 ////
 ///////////////////////////////////////////////////////////////////////////////
 ///////////////////////////////////////////////////////////////////////////////
+
+
 void LineBuffer::CircularArcTo(double x1, double y1, double x2, double y2)
 {
     _ASSERT(point_count() > 0);
@@ -259,6 +272,7 @@
     ArcTo(cx, cy, r, r, startAngle, endAngle);
 }
 
+
 //computes cubic spline parameter to be used
 //when approximating an elliptical arc
 double LineBuffer::CubicApproxParameter(double halfAngle)
@@ -271,6 +285,7 @@
     return (4.0/3.0) * (1.0 - cos(halfAngle)) / sin(halfAngle);
 }
 
+
 void LineBuffer::ArcTo(double cx, double cy, double a, double b, double startRad, double endRad)
 {
     double extent = endRad - startRad;
@@ -318,6 +333,7 @@
     }
 }
 
+
 void LineBuffer::TesselateCubicTo(double px2, double py2, double px3, double py3, double px4, double py4)
 {
     //get the start point
@@ -399,6 +415,7 @@
     LineTo(px4, py4);
 }
 
+
 void LineBuffer::TesselateQuadTo(double px2, double py2, double px3, double py3)
 {
     //get the start point
@@ -472,6 +489,7 @@
     LineTo(px3, py3);
 }
 
+
 ///////////////////////////////////////////////////////////////////////////////
 ///////////////////////////////////////////////////////////////////////////////
 ////
@@ -482,6 +500,7 @@
 ///////////////////////////////////////////////////////////////////////////////
 ///////////////////////////////////////////////////////////////////////////////
 
+
 //simple helper macro that reads x and y and skip z and m and does coord sys transform
 #define READ_POINT(x, y)            \
                 x = *dreader++;     \
@@ -769,6 +788,7 @@
     }
 }
 
+
 #define WRITE_INT(os, val) { \
                              \
     int val2 = val;          \
@@ -995,9 +1015,7 @@
 }
 
 
-
-
-//WARNING: caller responsible for deleting resulting line buffer
+//WARNING: caller is responsible for deleting resulting line buffer
 //if return is equal to this pointer, no clipping was needed (geometry was
 //fully inside given box), so no need to free it
 //if return pointer is NULL, geometry was fully outside the clip box
@@ -1052,6 +1070,7 @@
     }
 }
 
+
 LineBuffer* LineBuffer::ClipPoints(RS_Bounds& b, LineBuffer* dst)
 {
     dst->m_geom_type = m_geom_type;
@@ -1394,10 +1413,9 @@
         lb->m_pts[lb->m_cur_pts-2] = x;
         lb->m_pts[lb->m_cur_pts-1] = y;
     }
+}
 
-} // end: AppendLBClipVertex()
 
-
 LineBuffer* LineBuffer::ClipPolyline(RS_Bounds& b, LineBuffer* dest)
 {
     _ASSERT(dest);
@@ -1483,6 +1501,7 @@
         return clipCode;
 } // end: OpsClipCode()
 
+
 //------------------------------------------------------------------------------
 //
 // FUNCTION: OpsClipLine().
@@ -1765,6 +1784,7 @@
     return Centroid::PolylineCentroid(maxcntr, maxnumpts, cx, cy, slope);
 }
 
+
 void LineBuffer::PolylineCentroid(double* cx, double* cy, double* slope)
 {
     int numpts = 0;
@@ -1815,6 +1835,7 @@
     }
 }
 
+
 ///////////////////////////////////////////////////////////////////////////////
 ///////////////////////////////////////////////////////////////////////////////
 ////

Modified: trunk/MgDev/Common/Stylization/LineBuffer.h
===================================================================
--- trunk/MgDev/Common/Stylization/LineBuffer.h	2007-03-06 17:02:52 UTC (rev 1157)
+++ trunk/MgDev/Common/Stylization/LineBuffer.h	2007-03-06 23:31:17 UTC (rev 1158)
@@ -99,7 +99,9 @@
     inline int            cntr_count()  { return m_cur_cntr + 1; }
     inline const RS_Bounds& bounds()    { return m_bounds; }
 
-private:
+protected:
+    //empty constructor for use by inheriting classes
+    LineBuffer();
 
     unsigned char* m_types;
     double* m_pts;
@@ -158,7 +160,6 @@
     STYLIZATION_API void FreeLineBuffer(LineBuffer*);
 
 private:
-
     DataValueStack<LineBuffer> m_pool;
 };
 

Modified: trunk/MgDev/Common/Stylization/Makefile.am
===================================================================
--- trunk/MgDev/Common/Stylization/Makefile.am	2007-03-06 17:02:52 UTC (rev 1157)
+++ trunk/MgDev/Common/Stylization/Makefile.am	2007-03-06 23:31:17 UTC (rev 1158)
@@ -54,9 +54,16 @@
   SimpleOverpost.cpp \
   RS_ByteData.cpp \
   FontManager.cpp \
-  complex_polygon_gd.cpp
+  complex_polygon_gd.cpp \
+  RS_FontEngine.cpp \
+  SE_Bounds.cpp \
+  SE_ExpressionBase.cpp \
+  SE_LineBuffer.cpp \
+  SE_PositioningAlgorithms.cpp \
+  SE_Renderer.cpp \
+  SE_StyleVisitor.cpp \
+  StylizationEngine.cpp
 
-
 noinst_HEADERS = \
   Bounds.h \
   LineBuffer.h \
@@ -122,7 +129,19 @@
   FontManager.h \
   SymbolVisitor.h \
   SLDSymbols.h \
-  complex_polygon_gd.h
+  complex_polygon_gd.h \
+  RS_FontEngine.h \
+  SE_Bounds.h \
+  SE_ConvexHull.h \
+  SE_ExpressionBase.h \
+  SE_Include.h \
+  SE_LineBuffer.h \
+  SE_Matrix.h \
+  SE_PositioningAlgorithms.h \
+  SE_Renderer.h \
+  SE_StyleVisitor.h \
+  SE_SymbolManager.h \
+  StylizationEngine.h
 
 AM_CXXFLAGS = @CXXFLAGS@ -DDWFTK_BUILD_EXPAT
 

Added: trunk/MgDev/Common/Stylization/RS_FontEngine.cpp
===================================================================
--- trunk/MgDev/Common/Stylization/RS_FontEngine.cpp	                        (rev 0)
+++ trunk/MgDev/Common/Stylization/RS_FontEngine.cpp	2007-03-06 23:31:17 UTC (rev 1158)
@@ -0,0 +1,817 @@
+//
+//  Copyright (C) 2004-2007 by Autodesk, Inc.
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of version 2.1 of the GNU Lesser
+//  General Public License as published by the Free Software Foundation.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+//
+
+#include "stdafx.h"
+#include "RendererStyles.h"
+#include "FontManager.h"
+#include "RS_FontEngine.h"
+#include "Renderer.h"
+#include "SE_Renderer.h"
+#include "SE_Matrix.h"
+
+#define ROUND(x) (int)((x) + 0.5)
+
+//////////////////////////////////////////////////////////////////////////////
+RS_FontEngine::RS_FontEngine()
+{
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+RS_FontEngine::~RS_FontEngine()
+{
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+void RS_FontEngine::InitFontEngine(Renderer* renderer, SE_Renderer* serenderer)
+{
+    m_renderer = renderer;
+    m_serenderer = serenderer;
+
+    //we need the renderer to be an SE_Renderer in order to draw screen space geometry (like underline)
+    _ASSERT(m_serenderer);
+
+    SE_Matrix xform;
+    m_serenderer->GetWorldToScreenTransform(xform);
+
+    m_bYup = xform.y1 > 0;
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+const RS_Font* RS_FontEngine::FindFont(RS_FontDef& def)
+{
+    return FontManager::Instance()->FindFont(def.name().c_str(),
+                          (def.style() & RS_FontStyle_Bold) != 0,
+                          (def.style() & RS_FontStyle_Italic) != 0);
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+bool RS_FontEngine::GetTextMetrics(const RS_String& s, RS_TextDef& tdef, RS_TextMetrics& ret, bool bPathText)
+{
+    // font matching
+    const RS_Font* font = FindFont(tdef.font());
+
+    if (!font)
+        return false;
+
+    //determine pixel space font height
+    double hgt = MetersToPixels(tdef.font().units(), tdef.font().height());
+
+    //-------------------------------------------------------
+    // text extent and alignment computation
+    //-------------------------------------------------------
+
+    //get overall extent and char spacing
+    RS_F_Point fpts[4];
+
+    if (bPathText)
+    {
+        size_t len = s.length();
+        float* spacing = (float*)alloca(len * 2 * sizeof(float));
+        MeasureString(s, hgt, font, 0.0, fpts, spacing);
+        ret.char_advances.reserve(len);
+        for (int i=0; i<len; i++)
+            ret.char_advances.push_back(spacing[i]);
+        ret.text_width = fabs(fpts[1].x - fpts[0].x);
+        ret.text_height = fabs(fpts[2].y - fpts[0].y);
+    }
+    else
+    {
+        //-------------------------------------------------------
+        // break up the string up into individual lines
+        //-------------------------------------------------------
+
+        // font height gives the distance from one baseline to the next
+        // increase this by a factor of 1.05 (what GD uses)
+        double font_height = font->m_height * hgt / font->m_units_per_EM;
+        double line_height = 1.05 * font_height;
+
+        // make a temporary copy
+        size_t len = s.length();
+        wchar_t* cpy = (wchar_t*)alloca((len + 1) * sizeof(wchar_t));
+        wcscpy(cpy, s.c_str());
+
+        // break it up
+        std::vector<wchar_t*> line_breaks;
+        size_t num_lines = SplitLabel(cpy, line_breaks);
+
+        //if there were line breaks, remember each separate line in the metrics
+        if (num_lines > 1)
+        {
+            ret.line_breaks.reserve(num_lines);
+            for (int i=0; i<num_lines; i++)
+                ret.line_breaks.push_back(line_breaks[i]);
+        }
+
+        //we will store the h and v offset for each line in the char pos array
+        ret.line_pos.reserve(num_lines);
+
+        // base vertical offset is the same for each line of text
+        double vAlignBaseOffset = GetVerticalAlignmentOffset(tdef.valign(), font, hgt, line_height, num_lines);
+
+        ret.line_pos.resize(num_lines);
+
+        for (size_t k=0; k<num_lines; ++k)
+        {
+            wchar_t* txt = line_breaks[k];
+
+            // get the unrotated extent of this sub-string
+            MeasureString(txt, hgt, font, 0.0, fpts, NULL);
+
+            // horizontal offset depends on the sub-string width, while
+            // vertical offset depends on the line of text
+            ret.line_pos[k].hOffset = GetHorizontalAlignmentOffset(tdef.halign(), fpts);
+            if (m_bYup)
+                ret.line_pos[k].vOffset = vAlignBaseOffset - k*line_height;
+            else
+                ret.line_pos[k].vOffset = vAlignBaseOffset + k*line_height;
+
+            //remember unrotated extent of text
+            for (int i=0; i<4; i++)
+            {
+                ret.line_pos[k].ext[i].x = fpts[i].x + ret.line_pos[k].hOffset;
+                ret.line_pos[k].ext[i].y = fpts[i].y + ret.line_pos[k].vOffset;
+            }
+        }
+    }
+
+    //the width and height of this particular string
+    ret.font = font;
+    ret.font_height = hgt;
+    ret.text = s;
+
+    return true;
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+// Finds occurences of line breaks and adds the start pointer of each
+// line to the supplied array.  Line breaks can be any of the following:
+//   "\\n"                      // sequence currently used by MG OS / Enterprise
+//   \n\r  (char 13 + char 10)  // common in RDBMS like Oracle
+//   \r\n  (char 10 + char 13)
+//   \n    (char 13)            // used by MG 6.5
+//   \r    (char 10)            // common in Linux
+size_t RS_FontEngine::SplitLabel(wchar_t* label, std::vector<wchar_t*>& line_breaks)
+{
+    _ASSERT(label != NULL);
+    if (label == NULL)
+        return 0;
+
+    // first line
+    line_breaks.push_back(label);
+
+    for (;;)
+    {
+        // find the next line break - note that we must search
+        // for the 2-character sequences FIRST
+        wchar_t* found;
+        for (;;)
+        {
+            found = ::wcsstr(label, L"\\n");
+            if (found != NULL)
+            {
+                // null terminate line break (2 characters)
+                *found++ = 0;
+                *found++ = 0;
+                break;
+            }
+
+            found = ::wcsstr(label, L"\n\r");
+            if (found != NULL)
+            {
+                // null terminate line break (2 characters)
+                *found++ = 0;
+                *found++ = 0;
+                break;
+            }
+
+            found = ::wcsstr(label, L"\r\n");
+            if (found != NULL)
+            {
+                // null terminate line break (2 characters)
+                *found++ = 0;
+                *found++ = 0;
+                break;
+            }
+
+            found = ::wcsstr(label, L"\n");
+            if (found != NULL)
+            {
+                // null terminate line break (1 character)
+                *found++ = 0;
+                break;
+            }
+
+            found = ::wcsstr(label, L"\r");
+            if (found != NULL)
+            {
+                // null terminate line break (1 character)
+                *found++ = 0;
+            }
+
+            break;
+        }
+
+        if (found == NULL)
+            break;
+
+        label = found;
+        line_breaks.push_back(label);
+    }
+
+    return line_breaks.size();
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+//Computes character placement for a text stored in TextMetrics
+//The characters are placed along the given path.
+//This function assumes that GetTextMetrics has been used to initialize
+//the incoming TextMetrics structure.
+//This function assumes that the CharPos array passed in has enough space
+//to contain the computed position for each character along the path
+//This function may also modify the TextMetrics with updated font and text sizes
+//if it chooses to scale the font to make it better fit the given path
+bool RS_FontEngine::LayoutPathText(RS_TextMetrics& tm,
+                        const RS_F_Point* pts, int npts, double* seglens,
+                        double param_position, RS_VAlignment valign, int layout_option)
+{
+    int numchars = (int)tm.text.length();
+    tm.char_pos.reserve(numchars);
+
+    if (!seglens)
+    {
+        //If they were not passed in,
+        //find length of each segment in the screen space path
+        //we will use it to position characters along the curve
+        //It is recommended that the caller passes in a precomputed array
+        //if they will be laying out multiple labels on the same curve
+        _ASSERT(npts < 16384);
+        seglens = (double*)alloca(sizeof(double) * npts);
+        seglens[0] = 0.0;
+
+        for (int i=1; i<npts; i++)
+        {
+            double dx = pts[i].x - pts[i-1].x;
+            double dy = pts[i].y - pts[i-1].y;
+            seglens[i] = seglens[i-1] + sqrt(dx*dx + dy*dy);
+        }
+    }
+
+    //determine in which direction we should follow the polyline
+    //so that the label points up more likely than down
+    //find the length of polyline that requires inverting versus
+    //length that does not and see which one is bigger
+    //TODO: this loop should really be performed on the piece of the
+    //polyline where we will be labeling since otherwise features like
+    //circles can throw it off and so a label may still end up upside down
+    double inverted_len = 0.0;
+
+    for (int m=0; m<npts - 1; m++)
+    {
+        RS_F_Point p0 = pts[m];
+        RS_F_Point p1 = pts[m+1];
+
+        double angle = -atan2(p1.y - p0.y, p1.x - p0.x);
+
+        if (angle > M_PI/2.0 || angle < -M_PI/2.0)
+            inverted_len += seglens[m+1] - seglens[m];
+        else
+            inverted_len -= seglens[m+1] - seglens[m];
+    }
+
+    bool reverse = (inverted_len > 0.0);
+
+    double pathlen = seglens[npts - 1];
+
+    //compute font height that better fits the geometry
+    //but limit scaling to be in the range [0.5 - 1.0]
+    double font_scale = rs_min(1.0, rs_max(0.5, pathlen / (1.1 * tm.text_width)));
+
+    //scale all things we measured by the font scaling factor determined
+    //baed on the path length
+    if (font_scale != 1.0)
+    {
+        //don't bother measuring the string with the new height,
+        //scaling should work almost as good
+        tm.font_height *= font_scale;
+        tm.text_width *= font_scale;
+        tm.text_height *= font_scale;
+
+        for (int i=0; i<numchars; i++)
+            tm.char_advances[i] *= font_scale;
+    }
+
+    //distance of current character along current segment
+    //initialize to start position, based on given parametric position
+    //along the polyline
+    double dist_along_segment = param_position * pathlen - 0.5 * tm.text_width;
+
+    //j indicates index of segment we are on with current character
+    int j;
+
+    //segment for current character
+    RS_F_Point start;
+    RS_F_Point end;
+
+    if (reverse)
+    {
+        //case where we want to walk along the polyline
+        //in reverse
+
+        //compute starting segment
+        for (j=npts-2; j>=0; j--)
+            if (dist_along_segment < pathlen - seglens[j])
+                break;
+
+        if (j < 0) j=0;
+
+        start = pts[j+1];
+        end = pts[j];
+        dist_along_segment -= pathlen - seglens[j+1];
+    }
+    else
+    {
+        //case where we follow the polyline forwards
+
+        //compute starting segment
+        for (j=0; j<npts-1; j++)
+            if (dist_along_segment < seglens[j+1])
+                break;
+
+        if (j >= npts-1)
+            j = npts-2;
+
+        start = pts[j];
+        end = pts[j+1];
+        dist_along_segment -= seglens[j];
+    }
+
+    //length of current segment
+    double seg_len = seglens[j+1] - seglens[j];
+
+    //position of current character relative to the left end of the string
+    double char_pos = 0;
+
+    //The premise here is that we will compute three positions along the path
+    //for each character - one for the left corner, one for the right
+    //and one for the centerpoint
+    //We will compute a tangent vector based on the left and right points
+    //and then position the character relative to the point computed for its
+    //center with the normal comuted from the left and right points
+    //Note that the end position of one character equals the start position
+    //of the next, so in fact we need to compute 2 * n + 1 points
+    RS_F_Point* positions = (RS_F_Point*)alloca(sizeof(RS_F_Point) * (numchars * 2 + 1));
+
+    for (int i=0; i <= numchars * 2; i++)
+    {
+        //check if we need to move to next segment
+        while (dist_along_segment > seg_len)
+        {
+            if (reverse)
+            {
+                //case where we go in reverse direction of the path
+                if (j > 0)
+                {
+                    j--;
+                    dist_along_segment -= seg_len;
+                    seg_len = seglens[j+1] - seglens[j];
+                    start = pts[j+1];
+                    end = pts[j];
+                }
+                else
+                    break;
+            }
+            else
+            {
+                //case where we go forward along the path
+                if (j < npts - 2)
+                {
+                    j++;
+                    dist_along_segment -= seg_len;
+                    seg_len = seglens[j+1] - seglens[j];
+                    start = pts[j];
+                    end = pts[j+1];
+                }
+                else
+                    break;
+            }
+        }
+
+        //compute position along current segment using weighted
+        //normalized end-start vector
+        double weight = dist_along_segment / seg_len;
+        double dx = end.x - start.x;
+        double dy = end.y - start.y;
+
+        positions[i].x = start.x + dx * weight;
+        positions[i].y = start.y + dy * weight;
+
+        //kerned width of current character
+        int index = i / 2; //which character are we working with -- 3 iterations for each one
+        double char_width = (index >= numchars - 1) ? tm.text_width - char_pos : tm.char_advances[index];
+
+        //advance cursor by half the width of the current character
+        dist_along_segment += char_width * 0.5;
+        char_pos += char_width * 0.5;
+    }
+
+    char_pos = 0.0;
+
+    tm.char_pos.resize(numchars);
+
+    //now compute character placement and angles based on the positioning points
+    for (int i=0; i<numchars; i++)
+    {
+        //find angle based on left and right of character
+        double anglerad = -atan2(positions[2*i+2].y - positions[2*i].y,positions[2*i+2].x - positions[2*i].x);
+
+        //kerned width of current character
+        double char_width = (i == numchars - 1) ? tm.text_width - char_pos : tm.char_advances[i];
+        double char_width_2 = 0.5 * char_width;
+
+        //and now find a lower left insertion point
+        //based on the midpoint anchor and the angle
+        CharPos pos;
+        tm.char_pos[i].x = positions[2*i+1].x - cos(anglerad) * char_width_2;
+        tm.char_pos[i].y = positions[2*i+1].y + sin(anglerad) * char_width_2; //y down means + sin
+        tm.char_pos[i].anglerad = anglerad;
+
+        char_pos += char_width;
+    }
+
+    //get vertical alignment delta
+    double voffset = GetVerticalAlignmentOffset(valign, tm.font, tm.font_height, tm.font_height * 1.05, 1);
+
+    //apply vertical alignment to character position
+    //horizontal alignment is ignored in this case
+    for (size_t i=0; i<numchars; i++)
+    {
+        // add in the rotated vertical alignment contribution
+        double angle = tm.char_pos[i].anglerad;
+
+        double cs = cos(angle);
+        double sn = sin(angle);
+        double hAlignOffset = -sn*voffset;
+        double vAlignOffset =  cs*voffset;
+
+        //adjust insertion point
+        tm.char_pos[i].x += hAlignOffset;
+        tm.char_pos[i].y -= vAlignOffset;
+    }
+
+    return true;
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+void RS_FontEngine::DrawBlockText(RS_TextMetrics& tm, RS_TextDef& tdef, double insx, double insy)
+{
+    //radian CCW rotation
+    double rotation = tdef.rotation() * M_PI / 180.0;
+
+    double cos_a = cos(rotation);
+    double sin_a = sin(rotation);
+
+    if (m_bYup)
+        sin_a = -sin_a;
+
+    // get the overall unrotated bounds
+    RS_Bounds b(DBL_MAX, DBL_MAX, -DBL_MAX, -DBL_MAX);
+
+    for (int i=0; i<tm.line_pos.size(); i++)
+    {
+        b.add_point(tm.line_pos[i].ext[0]);
+        b.add_point(tm.line_pos[i].ext[2]);
+    }
+
+    RS_F_Point fpts[4];
+    b.get_points(fpts);
+
+    // draw the opaque background first, if requested
+    if (tdef.textbg() == RS_TextBackground_Opaque)
+    {
+        // rotate and translate it
+        for (int j=0; j<4; ++j)
+        {
+            double tmpX = fpts[j].x;
+            double tmpY = fpts[j].y;
+            fpts[j].x = insx + tmpX * cos_a + tmpY * sin_a;
+            fpts[j].y = insy - tmpX * sin_a + tmpY * cos_a;
+        }
+
+        // draw a filled rectangle
+        SE_Geometry geom;
+        double points[10] = {fpts[0].x, fpts[0].y, 
+                             fpts[1].x, fpts[1].y, 
+                             fpts[2].x, fpts[2].y,
+                             fpts[3].x, fpts[3].y,
+                             fpts[0].x, fpts[0].y};
+        int contours[1] = {5};
+        geom.points = points;
+        geom.n_pts = 5;
+        geom.contours = contours;
+        geom.n_cntrs = 1;
+        geom.geom_type = (int)FdoGeometryType_Polygon;
+
+        m_serenderer->DrawScreenPolygon(geom, tdef.bgcolor().argb());
+    }
+
+    for (size_t k=0; k<tm.line_pos.size(); ++k)
+    {
+        const RS_String* txt;
+
+        if (tm.line_pos.size() == 1)
+            txt = &tm.text;
+        else
+            txt = &tm.line_breaks.at(k);
+
+        LinePos& pos = tm.line_pos[k];
+
+        // add the rotated original offset for this line to the insertion point
+        // to get the actual draw point
+        double insX = insx + pos.hOffset * cos_a + pos.vOffset * sin_a;
+        double insY = insy - pos.hOffset * sin_a + pos.vOffset * cos_a;
+
+        int posx = (int)floor(insX + 0.5);
+        int posy = (int)floor(insY + 0.5);
+
+        // render the ghosted text, if requested
+        if (tdef.textbg() == RS_TextBackground_Ghosted)
+        {
+            DrawString(*txt, posx-1, posy, tm.font_height, tm.font, tdef.bgcolor(), rotation);
+            DrawString(*txt, posx+1, posy, tm.font_height, tm.font, tdef.bgcolor(), rotation);
+            DrawString(*txt, posx, posy-1, tm.font_height, tm.font, tdef.bgcolor(), rotation);
+            DrawString(*txt, posx, posy+1, tm.font_height, tm.font, tdef.bgcolor(), rotation);
+        }
+
+        // render the primary text
+        DrawString(*txt, posx, posy, tm.font_height, tm.font, tdef.color(), rotation);
+
+        // render the underline, if requested
+        if (tdef.font().style() & RS_FontStyle_Underline)
+        {
+            // estimate underline line width as % of font height
+            double line_width = (double)tm.font->m_underline_thickness * tm.font_height / (double)tm.font->m_units_per_EM;
+            double line_pos = - (double)tm.font->m_underline_position * tm.font_height / (double)tm.font->m_units_per_EM;
+
+            // the line's start point is the insertion point, but shifted vertically by line_pos
+            double x0 = insX + line_pos * sin_a;
+            double y0 = insY + line_pos * cos_a;
+
+
+            // the end point is a horizontal shift by the text width
+            double textwidth = pos.ext[1].x - pos.ext[0].x;
+            double x1 = x0 + textwidth * cos_a;
+            double y1 = y0 - textwidth * sin_a;
+
+            // draw the thick line
+            SE_Geometry geom;
+            double points[4] = {x0, y0, x1, y1};
+            int contours[1] = {2};
+            geom.points = points;
+            geom.n_pts = 2;
+            geom.contours = contours;
+            geom.n_cntrs = 1;
+            geom.geom_type = (int)FdoGeometryType_LineString;
+
+            m_serenderer->DrawScreenPolyline(geom, tdef.color().argb(), line_width);
+        }
+    }
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+//Draws a text which has been previously laid out using LayoutPathText
+//The tdef argument is only used to get the underline option and the text colors
+//Everything else is stored in the TextMetrics context structure and the CharPos
+//array, which were previously computed by LayoutPathText
+void RS_FontEngine::DrawPathText(RS_TextMetrics& tm, RS_TextDef& tdef)
+{
+    int numchars = tm.text.length();
+
+    //draw the characters, each in its computed position
+    RS_String c;
+    for (size_t i=0; i<numchars; ++i)
+    {
+        c = tm.text[i];
+
+        //compute screen position and round
+        int posx = ROUND(tm.char_pos[i].x);
+        int posy = ROUND(tm.char_pos[i].y);
+        double anglerad = tm.char_pos[i].anglerad;
+
+        if (tdef.textbg() == RS_TextBackground_Ghosted)
+        {
+            DrawString(c, posx-1, posy, tm.font_height, tm.font, tdef.bgcolor(), anglerad);
+            DrawString(c, posx+1, posy, tm.font_height, tm.font, tdef.bgcolor(), anglerad);
+            DrawString(c, posx, posy-1, tm.font_height, tm.font, tdef.bgcolor(), anglerad);
+            DrawString(c, posx, posy+1, tm.font_height, tm.font, tdef.bgcolor(), anglerad);
+        }
+
+        DrawString(c, posx, posy, tm.font_height, tm.font, tdef.color(), anglerad);
+    }
+
+    //render underline
+    if (tdef.font().style() & RS_FontStyle_Underline)
+    {
+        //estimate underline line width as % of font height
+        double line_width = (double)tm.font->m_underline_thickness * tm.font_height / (double)tm.font->m_units_per_EM;
+        //underline position w.r.t. baseline. Invert y while at it
+        double line_pos = - (double)tm.font->m_underline_position * tm.font_height / (double)tm.font->m_units_per_EM;
+
+        double total_advance = 0.0;
+
+        //used to keep track of last position of the underline, which is
+        //drawn piecewise for each character
+        double last_x = tm.char_pos[0].x + sin(tm.char_pos[0].anglerad) * line_pos;
+        double last_y = tm.char_pos[0].y + cos(tm.char_pos[0].anglerad) * line_pos;
+        double sx, sy, ex, ey;
+
+        //draw the characters, each in its computed position
+        for (size_t i=0; i<numchars; i++)
+        {
+            //width of character - not really exact width since
+            //it takes kerning into account, but should be good enough
+            //we could measure each character separately but that seems like
+            //too many calls to FreeType
+            double advance = (i == numchars-1)? tm.text_width - total_advance : tm.char_advances[i];
+            total_advance += advance;
+
+            sx = last_x;
+            sy = last_y;
+
+            if (i == numchars - 1)
+            {
+                //estimate bottom right corner of last character
+                double eex = tm.char_pos[i].x + cos(tm.char_pos[i].anglerad) * advance;
+                double eey = tm.char_pos[i].y - sin(tm.char_pos[i].anglerad) * advance;
+
+                //now take into account underline offset
+                ex = eex + sin(tm.char_pos[i].anglerad) * line_pos;
+                ey = eey + cos(tm.char_pos[i].anglerad) * line_pos;
+            }
+            else
+            {
+                //move position by underline offset
+                ex = tm.char_pos[i+1].x + sin(tm.char_pos[i+1].anglerad) * line_pos;
+                ey = tm.char_pos[i+1].y + cos(tm.char_pos[i+1].anglerad) * line_pos;
+            }
+
+            SE_Geometry geom;
+            double points[4] = {sx, sy, ex, ey};
+            int contours[1] = {2};
+            geom.points = points;
+            geom.n_pts = 2;
+            geom.contours = contours;
+            geom.n_cntrs = 1;
+            geom.geom_type = (int)FdoGeometryType_LineString;
+
+            m_serenderer->DrawScreenPolyline(geom, tdef.color().argb(), line_width);
+
+            last_x = ex;
+            last_y = ey;
+        }
+    }
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+// Computes the Y offset that must be applied to the unrotated text to
+// obtain the specified vertical alignment.  Positive Y points down.
+double RS_FontEngine::GetVerticalAlignmentOffset(RS_VAlignment vAlign, const RS_Font* font,
+                                      double actual_height, double line_height,
+                                      size_t numLines)
+{
+    double offsetY = 0.0;
+
+    // According to FreeType:
+    //
+    //   * The face's ascender is the vertical distance from the baseline
+    //     to the topmost point of any glyph in the face.  This field's
+    //     value is positive.
+    //
+    //   * The face's descender is the vertical distance from the baseline
+    //     to the bottommost point of any glyph in the face.  This field's
+    //     value is *negative* for values below the baseline.
+    //
+    //   * The face's height is the vertical distance from one baseline to
+    //     the next when writing several lines of text.  Its value is always
+    //     positive.  The value can be computed as `ascender+descender+line_gap'.
+
+    // FreeType doesn't provide the capline - for now just use the ascent.
+    double em_square_size = font->m_units_per_EM;
+    double font_ascent    = font->m_ascender * actual_height / em_square_size;
+    double font_descent   = font->m_descender * actual_height / em_square_size;
+    double font_capline   = font_ascent;
+
+    switch (vAlign)
+    {
+    case RS_VAlignment_Descent:
+        // must also account for the total number of lines
+        offsetY = font_descent - line_height*(numLines - 1);
+        break;
+
+    case RS_VAlignment_Base:
+        // must also account for the total number of lines
+        offsetY = - line_height*(numLines - 1);
+        break;
+
+    case RS_VAlignment_Half:
+        // must also account for the total number of lines
+        offsetY = 0.5*(font_capline - line_height*(numLines - 1));
+        break;
+
+    case RS_VAlignment_Cap:
+        offsetY = font_capline;
+        break;
+
+    case RS_VAlignment_Ascent:
+        offsetY = font_ascent;
+        break;
+    }
+
+    if (m_bYup)
+        offsetY = -offsetY; //TODO: do we need to mult this by numLines?
+
+    return offsetY;
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+// Computes the X offset that must be applied to the unrotated text to
+// obtain the specified horizontal alignment.
+double RS_FontEngine::GetHorizontalAlignmentOffset(RS_HAlignment hAlign, RS_F_Point* extent)
+{
+    double offsetX = 0.0;
+
+    switch (hAlign)
+    {
+    case RS_HAlignment_Left:
+        offsetX = -extent[0].x;
+        break;
+
+    case RS_HAlignment_Center:
+        offsetX = -0.5*(extent[0].x + extent[1].x);
+        break;
+
+    case RS_HAlignment_Right:
+        offsetX = -extent[1].x;
+        break;
+    }
+
+    return offsetX;
+}
+
+
+//-----------------------------------------------------------------------------
+//scale an input number in meters to a mapping
+//space number given a device or mapping space unit.
+//-----------------------------------------------------------------------------
+double RS_FontEngine::MeterToMapSize(RS_Units unit, double number)
+{
+    double scale_factor;
+
+    if (unit == RS_Units_Device) // in meters, fixed size
+        scale_factor = m_renderer->GetMapScale() / m_renderer->GetMetersPerUnit();
+    else
+        scale_factor = 1.0 / m_renderer->GetMetersPerUnit();
+
+    return number * scale_factor;
+}
+
+//-----------------------------------------------------------------------------
+//scale an input number in meters to pixel
+//space number given a device or mapping space unit.
+//-----------------------------------------------------------------------------
+double RS_FontEngine::MetersToPixels(RS_Units unit, double number)
+{
+    double scale_factor;
+
+    double m2px = m_renderer->GetDpi() * (100 / 2.54);
+
+    if (unit == RS_Units_Device)
+        scale_factor = m2px; //device units simply returns scale to convert meters to pixels
+    else
+        scale_factor = m2px / m_renderer->GetMapScale(); //for mapping space we also take map scale into account
+
+    return number * scale_factor;
+}


Property changes on: trunk/MgDev/Common/Stylization/RS_FontEngine.cpp
___________________________________________________________________
Name: svn:eol-style
   + native

Added: trunk/MgDev/Common/Stylization/RS_FontEngine.h
===================================================================
--- trunk/MgDev/Common/Stylization/RS_FontEngine.h	                        (rev 0)
+++ trunk/MgDev/Common/Stylization/RS_FontEngine.h	2007-03-06 23:31:17 UTC (rev 1158)
@@ -0,0 +1,130 @@
+//
+//  Copyright (C) 2004-2007 by Autodesk, Inc.
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of version 2.1 of the GNU Lesser
+//  General Public License as published by the Free Software Foundation.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+//
+
+#ifndef RS_FONTENGINE_H
+#define RS_FONTENGINE_H
+
+struct RS_Font;
+class Renderer;
+class SE_Renderer;
+struct SE_Matrix;
+
+
+struct CharPos
+{
+    double x;
+    double y;
+    double anglerad;
+};
+
+
+struct LinePos
+{
+    RS_F_Point ext[4];
+    double hOffset;
+    double vOffset;
+};
+
+
+class RS_TextMetrics
+{
+public:
+    RS_TextMetrics()
+        : font(NULL),
+          font_height(0),
+          text_width(0),
+          text_height(0)
+    {
+    }
+
+    const RS_Font* font;
+    double font_height;
+    double text_width;
+    double text_height;
+    RS_String text;
+
+    //for path text -- character advances and positions
+    std::vector<float> char_advances;
+    std::vector<CharPos> char_pos;
+
+    //for block text -- line positions
+    std::vector<LinePos> line_pos;
+    std::vector<RS_String> line_breaks;
+};
+
+
+class RS_FontEngine
+{
+public:
+    RS_FontEngine();
+    virtual ~RS_FontEngine();
+
+    virtual void InitFontEngine(Renderer* renderer, SE_Renderer* serenderer);
+
+    virtual void DrawString(const RS_String& s,
+                            int              x,
+                            int              y,
+                            double           height,
+                            const RS_Font*   font,
+                            const RS_Color&  color,
+                            double           angle) = 0;
+
+    virtual void MeasureString(const RS_String& s,
+                               double           height,
+                               const RS_Font*   font,
+                               double           angle,
+                               RS_F_Point*      res,
+                               float*           offsets) = 0;
+
+    const RS_Font* FindFont(RS_FontDef& def);
+
+    size_t SplitLabel(wchar_t* label, std::vector<wchar_t*>& line_breaks);
+
+    bool GetTextMetrics(const RS_String& s, RS_TextDef& tdef, RS_TextMetrics& ret, bool bPathText);
+
+    bool LayoutPathText(RS_TextMetrics& tm, const RS_F_Point* pts, int npts, double* seglens,
+                        double param_position, RS_VAlignment valign, int layout_option);
+
+    void DrawPathText(RS_TextMetrics& tm, RS_TextDef& tdef);
+
+    void DrawBlockText(RS_TextMetrics& tm, RS_TextDef& tdef, double insx, double insy);
+
+    double GetVerticalAlignmentOffset(RS_VAlignment vAlign, const RS_Font* font,
+                                      double actual_height, double line_height,
+                                      size_t numLines);
+
+    double GetHorizontalAlignmentOffset(RS_HAlignment hAlign, RS_F_Point* extent);
+
+    //----------------------------------------------------------------
+    //TODO: Those really belong as utility functions on the renderer itself
+    //      -- they are unrelated to fonts
+    //----------------------------------------------------------------
+    double MeterToMapSize(RS_Units unit, double number);
+    double MetersToPixels(RS_Units unit, double number);
+
+    bool   _Yup()
+    {
+        return m_bYup;
+    }
+
+public:
+    Renderer* m_renderer;
+    SE_Renderer* m_serenderer;
+    bool m_bYup;
+};
+
+#endif  // RS_FONTENGINE_H


Property changes on: trunk/MgDev/Common/Stylization/RS_FontEngine.h
___________________________________________________________________
Name: svn:eol-style
   + native

Modified: trunk/MgDev/Common/Stylization/RendererStyles.h
===================================================================
--- trunk/MgDev/Common/Stylization/RendererStyles.h	2007-03-06 17:02:52 UTC (rev 1157)
+++ trunk/MgDev/Common/Stylization/RendererStyles.h	2007-03-06 23:31:17 UTC (rev 1158)
@@ -41,11 +41,21 @@
     RS_VAlignment_Base,
     RS_VAlignment_Half,
     RS_VAlignment_Cap,
-    RS_VAlignment_Ascent,
+    RS_VAlignment_Ascent
 };
 
 
 //////////////////////////////////////////////////////////////////////////////
+enum RS_Justify
+{
+    RS_Justify_Left,
+    RS_Justify_Center,
+    RS_Justify_Right,
+    RS_Justify_Justify
+};
+
+
+//////////////////////////////////////////////////////////////////////////////
 enum RS_FontStyle_Mask
 {
     RS_FontStyle_Regular    = 0,
@@ -143,6 +153,16 @@
                 (m_red    & 0xFF);
     }
 
+    static RS_Color FromARGB(unsigned int argb)
+    {
+        RS_Color ret;
+        ret.m_alpha =  (argb >> 24) & 0xFF;
+        ret.m_red   =  (argb >> 16) & 0xFF;
+        ret.m_green =  (argb >> 8)  & 0xFF;
+        ret.m_blue  =   argb        & 0xFF;
+        return ret;
+    }
+
 private:
     int m_red;
     int m_green;
@@ -261,8 +281,10 @@
     RS_TextDef() :
         m_halign(RS_HAlignment_Center),
         m_valign(RS_VAlignment_Half),
+        m_justify(RS_Justify_Left),
         m_textbg(RS_TextBackground_None),
-        m_rotation(0.0)
+        m_rotation(0.0),
+        m_linespace(1.0)
     {
     }
 
@@ -270,27 +292,33 @@
                RS_VAlignment valign) :
         m_halign(halign),
         m_valign(valign),
+        m_justify(RS_Justify_Left),
         m_textbg(RS_TextBackground_None),
-        m_rotation(0.0)
+        m_rotation(0.0),
+        m_linespace(1.0)
     {
     }
 
     inline RS_HAlignment &         halign()    { return m_halign; }
     inline RS_VAlignment &         valign()    { return m_valign; }
+    inline RS_Justify &            justify()   { return m_justify; }
     inline RS_TextBackground &     textbg()    { return m_textbg; }
     inline RS_Color &              color()     { return m_color; }
     inline RS_Color &              bgcolor()   { return m_bgcolor; }
     inline RS_FontDef &            font()      { return m_font; }
     inline double &                rotation()  { return m_rotation; }
+    inline double &                linespace() { return m_linespace; }
 
 private:
     RS_HAlignment m_halign;
     RS_VAlignment m_valign;
+    RS_Justify m_justify;
     RS_TextBackground m_textbg;
     RS_Color m_color;
     RS_Color m_bgcolor;
     RS_FontDef m_font;
     double m_rotation;
+    double m_linespace;
 };
 
 
@@ -622,21 +650,16 @@
 
 
 //////////////////////////////////////////////////////////////////////////////
-struct CharPos
-{
-    double x;
-    double y;
-    double anglerad;
-};
-
-
-//////////////////////////////////////////////////////////////////////////////
 enum LabelAlgo
 {
     laSimple,
     laCurve,
     laSkeleton,
-    laPeriodicPolygon
+    laPeriodicPolygon,
+    laSESymbol
 };
 
+//////////////////////////////////////////////////////////////////////////////
+
+
 #endif

Added: trunk/MgDev/Common/Stylization/SE_Bounds.cpp
===================================================================
--- trunk/MgDev/Common/Stylization/SE_Bounds.cpp	                        (rev 0)
+++ trunk/MgDev/Common/Stylization/SE_Bounds.cpp	2007-03-06 23:31:17 UTC (rev 1158)
@@ -0,0 +1,178 @@
+//
+//  Copyright (C) 2007 Autodesk, Inc.
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of version 2.1 of the GNU Lesser
+//  General Public License as published by the Free Software Foundation.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+//
+
+#include "SE_Bounds.h"
+#include "SE_LineBuffer.h"
+#include "SE_ConvexHull.h"
+#include <float.h>
+
+void SE_Bounds::Add(double x, double y)
+{
+    if (size >= capacity)
+        return;
+    hull[2*size] = x;
+    hull[2*size+1] = y;
+
+    if (min[0] > x)
+        min[0] = x;
+    if (max[0] < x)
+        max[0] = x;
+    if (min[1] > y)
+        min[1] = y;
+    if (max[1] < y)
+        max[1] = y;
+
+    size++;
+}
+
+void SE_Bounds::Transform(SE_Matrix& xform)
+{
+    double *last = hull + 2*size;
+    double *cur = hull;
+    
+    while (cur < last)
+        xform.transform(*cur++, *cur++);
+}
+
+struct SimplePoint
+{
+    double x;
+    double y;
+};
+
+struct SimplePointUtil
+{
+    SE_INLINE double x(SimplePoint* point)
+    {
+        return point->x;
+    }
+
+    SE_INLINE double y(SimplePoint* point)
+    {
+        return point->y;
+    }
+
+    SE_INLINE bool equal(SimplePoint* a, SimplePoint* b)
+    {
+        return a->x == b->x && a->y == b->y;
+    }
+};
+
+void SE_Bounds::Free()
+{
+    pool->FreeBounds(this);
+}
+
+SE_Bounds* SE_Bounds::Clone()
+{
+    SE_Bounds* clone = pool->NewBounds(size);
+    clone->size = size;
+    clone->pivot = pivot;
+    clone->min[0] = min[0];
+    clone->min[1] = min[1];
+    clone->max[0] = max[0];
+    clone->max[1] = max[1];
+    memcpy(clone->hull, hull, size*2*sizeof(double));
+    return clone;
+}
+
+void SE_Bounds::Contained(double minx, double miny, double maxx, double maxy, double &growx, double &growy)
+{
+    double sx, sy;
+    
+    if (min[0] < minx)
+    {
+        sx = (minx - min[0])/(maxx - minx);
+        growx = (growx > sx) ? growx : sx;
+    }
+    if (max[0] > maxx)
+    {
+        sx = (max[0] - maxx)/(maxx - minx);
+        growx = (growx > sx) ? growx : sx;
+    }
+    if (min[1] < miny)
+    {
+        sy = (miny - min[1])/(maxy - miny);
+        growy = (growy > sy) ? growy : sy;
+    }
+    if (max[1] < maxy)
+    {
+        sy = (max[1] - maxy)/(maxy - miny);
+        growy = (growy > sy) ? growy : sy;
+    }
+}
+
+SE_Bounds* SE_Bounds::Union(SE_Bounds* bounds)
+{
+    /* Andrew Convex Hull again, but this time in linear time (the points of the
+     * convex hulls can be sorted in O(n) instead of O(n log n) since the U and L
+     * lines were both already in lexographic order. */
+    int usize = bounds->size + size;
+    double* vec;
+    if (usize > 4096) // we don't want an overflow here
+        vec = new double[2*usize];
+    else
+        vec = (double*)alloca(sizeof(double)*2*usize);
+        
+    double* start[4] = {hull, hull + 2*size - 2, bounds->hull, bounds->hull + 2*bounds->size - 2};
+    double* end[4] = {hull + 2*pivot, hull + 2*pivot - 2, bounds->hull + 2*bounds->pivot, bounds->hull + 2*bounds->pivot - 2};
+
+    bool invalid[4];
+    int pnts = 0;
+
+    /* Create a sorted list of all the vertices in both convex hulls */
+    for(;;)
+    {
+        invalid[0] = start[0] >= end[0];
+        invalid[1] = start[1] <= end[1];
+        invalid[2] = start[2] >= end[2];
+        invalid[3] = start[3] <= end[3];
+
+        if (invalid[0] && invalid[1] && invalid[2] && invalid[3])
+            break;
+
+        double lx = DBL_MAX, ly = DBL_MAX;
+        int index = -1;
+
+        for (int i = 0; i < 4; i++)
+            if (!invalid[i] && ((*start[i] < lx) || (*start[i] == lx && *(start[i]+1) <= ly)))
+            {
+                lx = *start[i];
+                ly = *(start[i]+1);
+                index = i;
+            }
+        if (index & 1) // U array
+            start[index] -= 2;
+        else // L array
+            start[index] += 2;
+        if (pnts < 2 || vec[pnts-2] != lx || vec[pnts-1] != ly)
+        {
+            vec[pnts++] = lx;
+            vec[pnts++] = ly;
+        }
+    }
+
+    double* last = vec + pnts - 2;
+    double* first = vec;
+
+    SE_Bounds* ubounds = AndrewHull<SimplePoint*, SimplePointUtil>((SimplePoint*)first, (SimplePoint*)last, pnts/2, pool);    
+
+    if (usize > 4096)
+        delete[] vec;
+
+    return ubounds;
+}
\ No newline at end of file


Property changes on: trunk/MgDev/Common/Stylization/SE_Bounds.cpp
___________________________________________________________________
Name: svn:eol-style
   + native

Added: trunk/MgDev/Common/Stylization/SE_Bounds.h
===================================================================
--- trunk/MgDev/Common/Stylization/SE_Bounds.h	                        (rev 0)
+++ trunk/MgDev/Common/Stylization/SE_Bounds.h	2007-03-06 23:31:17 UTC (rev 1158)
@@ -0,0 +1,49 @@
+//
+//  Copyright (C) 2007 Autodesk, Inc.
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of version 2.1 of the GNU Lesser
+//  General Public License as published by the Free Software Foundation.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+//
+
+#ifndef SE_BOUNDS_H
+#define SE_BOUNDS_H
+
+#include "Stylization.h"
+#include "SE_Matrix.h"
+
+struct SE_Bounds
+{
+friend class SE_LineBuffer;
+friend class SE_LineBufferPool;
+private:
+    SE_Bounds();
+    int capacity;
+    SE_LineBufferPool* pool;
+
+public:
+    double* hull;
+    int size;
+    int pivot;
+
+    double min[2];
+    double max[2];
+
+    STYLIZATION_API void Add(double x, double y);
+    STYLIZATION_API void Transform(SE_Matrix& xform);
+    STYLIZATION_API void Contained(double minx, double miny, double maxx, double maxy, double &growx, double &growy);
+    STYLIZATION_API void Free();
+    STYLIZATION_API SE_Bounds* Clone();
+    STYLIZATION_API SE_Bounds* Union(SE_Bounds* bounds);
+};
+
+#endif // SE_BOUNDS_H
\ No newline at end of file


Property changes on: trunk/MgDev/Common/Stylization/SE_Bounds.h
___________________________________________________________________
Name: svn:eol-style
   + native

Added: trunk/MgDev/Common/Stylization/SE_ConvexHull.h
===================================================================
--- trunk/MgDev/Common/Stylization/SE_ConvexHull.h	                        (rev 0)
+++ trunk/MgDev/Common/Stylization/SE_ConvexHull.h	2007-03-06 23:31:17 UTC (rev 1158)
@@ -0,0 +1,154 @@
+//
+//  Copyright (C) 2007 Autodesk, Inc.
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of version 2.1 of the GNU Lesser
+//  General Public License as published by the Free Software Foundation.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+//
+
+#ifndef SE_CONVEXHULL_H
+#define SE_CONVEXHULL_H
+
+#include "SE_LineBuffer.h"
+
+#define PointLeft(pt0x, pt0y, pt1x, pt1y, pt2x, pt2y) \
+    (((pt1x - pt0x)*(pt2y - pt0y) - (pt2x - pt0x)*(pt1y - pt0y)) > 0)
+
+struct SimplePOINT
+{
+    SE_INLINE double x(void* point)
+    {
+        return ((double*)point)[0];
+    }
+
+    SE_INLINE double y(void* point)
+    {
+        return ((double*)point)[1];
+    }
+
+    SE_INLINE bool equal(void* a, void* b)
+    {
+        return x(a) == x(b) && y(a) == y(b);
+    }
+};
+
+template<class ITER, class POINT> SE_Bounds* AndrewHull(ITER spoints, ITER epoints, int npoints, SE_LineBufferPool* pool)
+{
+    POINT pnt;
+    ITER minxminy, minxmaxy, maxxminy, maxxmaxy;    
+
+    ITER iter = spoints;
+    
+    minxminy = iter++;
+    while ((iter != epoints) && (pnt.x(iter) == pnt.x(minxminy)))
+        iter++;
+    if (pnt.x(iter) == pnt.x(minxminy)) // all points have the same x coordinate
+    {
+        SE_Bounds* bounds = pool->NewBounds(3);
+        bounds->pivot = 1;
+        bounds->Add(pnt.x(minxminy), pnt.y(minxminy));
+        if (pnt.y(iter) != pnt.y(minxminy))
+            bounds->Add(pnt.x(iter), pnt.y(iter));
+        bounds->Add(pnt.x(minxminy), pnt.y(minxminy));
+        return bounds;
+    }
+    minxmaxy = --iter;
+
+    iter = epoints;
+    maxxmaxy = iter--;
+    while((iter != spoints) && (pnt.x(iter) == pnt.x(maxxmaxy)))
+        iter--;
+    if (pnt.x(iter) == pnt.x(maxxmaxy))
+        maxxminy = iter;
+    else
+        maxxminy = ++iter;
+
+    double* buffer;
+    if (npoints > 4096) // we don't want an overflow here
+        buffer = new double[4*npoints];
+    else
+        buffer = (double*)alloca(sizeof(double)*4*npoints);
+
+    /* Compute Lower Hull */
+    double* stack = buffer;
+    *stack++ = pnt.x(minxmaxy);
+    *stack++ = pnt.y(minxmaxy);
+    iter = minxmaxy;
+
+    while (iter++ != maxxminy)
+    {
+        if (PointLeft(pnt.x(minxminy), pnt.y(minxminy), pnt.x(maxxminy), pnt.y(maxxminy), pnt.x(iter), pnt.y(iter)) && iter != maxxminy)
+        /* this point is trivially above the lower bounding line, and cannot be in the lower hull */
+            continue;
+        
+        while ((stack - buffer) > 2) /* we have to have at least 2 points before this is defined */
+        {
+            if (PointLeft(*(stack - 4), *(stack - 3), *(stack - 2), *(stack - 1), pnt.x(iter), pnt.y(iter)))
+                break; /* current point is inside the lower hull */
+            else
+                stack -= 2; /* current point is outside the lower hull, replace the last point */
+        }
+        *stack++ = pnt.x(iter);
+        *stack++ = pnt.y(iter);
+    }
+
+    /* Compute Upper Hull */
+    double *ubuf = stack;
+
+    if (!pnt.equal(maxxmaxy, maxxminy))
+    {
+        *stack++ = pnt.x(maxxmaxy);
+        *stack++ = pnt.y(maxxmaxy);
+    }
+    iter = maxxminy;
+
+    while (iter-- != minxmaxy)
+    {
+        if (PointLeft(pnt.x(maxxmaxy), pnt.y(maxxmaxy), pnt.x(minxmaxy), pnt.y(minxmaxy), pnt.x(iter), pnt.y(iter)) && iter != minxmaxy)
+        /* this point is trivially below the upper bounding line, and cannot be in the upper hull */
+            continue;
+        
+        while ((stack - ubuf) > 2) /* we have to have at least 2 points before this is defined */
+        {
+            if (PointLeft(*(stack - 4), *(stack - 3), *(stack - 2), *(stack - 1), pnt.x(iter), pnt.y(iter)))
+                break; /* current point is inside the upper hull */
+            else
+                stack -= 2; /* current point is outside the upper hull, replace the last point */
+        }
+        *stack++ = pnt.x(iter);
+        *stack++ = pnt.y(iter);
+    }
+
+    if (!pnt.equal(minxmaxy, minxminy))
+    {
+        *stack++ = pnt.x(minxminy);
+        *stack++ = pnt.y(minxminy);
+    }
+
+    SE_Bounds* bounds = pool->NewBounds((int)(stack - buffer)/2);
+    bounds->pivot = (int)(ubuf - buffer)/2;
+    double* point = buffer;
+
+    while(point < stack)
+    {
+        double x = *point++;
+        double y = *point++;
+        bounds->Add(x, y);
+    }
+
+    if (npoints > 4096)
+        delete[] buffer;
+
+    return bounds;
+}
+
+#endif // SE_CONVEXHULL_H
\ No newline at end of file


Property changes on: trunk/MgDev/Common/Stylization/SE_ConvexHull.h
___________________________________________________________________
Name: svn:eol-style
   + native

Added: trunk/MgDev/Common/Stylization/SE_ExpressionBase.cpp
===================================================================
--- trunk/MgDev/Common/Stylization/SE_ExpressionBase.cpp	                        (rev 0)
+++ trunk/MgDev/Common/Stylization/SE_ExpressionBase.cpp	2007-03-06 23:31:17 UTC (rev 1158)
@@ -0,0 +1,224 @@
+//
+//  Copyright (C) 2007 by Autodesk, Inc.
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of version 2.1 of the GNU Lesser
+//  General Public License as published by the Free Software Foundation.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+//
+
+#include "stdafx.h"
+#include "SE_ExpressionBase.h"
+#include "StylizationEngine.h"
+
+#include "SimpleSymbolDefinition.h"
+
+#include <wctype.h>
+
+using namespace MDFMODEL_NAMESPACE;
+
+void SE_ExpressionBase::SetParameterValues(OverrideCollection* overrides)
+{
+    m_parameters.clear();
+    int length = overrides->GetCount();
+    for (int i = 0; i < length; i++)
+    {
+        Override* over = overrides->GetAt(i);
+        const wchar_t* name = over->GetParameterIdentifier().c_str();
+        const wchar_t* symbol = over->GetSymbolName().c_str();
+        const wchar_t* value = over->GetParameterValue().c_str();
+        m_parameters[ParamId(symbol, name)] = value;
+    }
+}
+
+void SE_ExpressionBase::SetDefaultValues(SimpleSymbolDefinition* definition)
+{
+    m_defaults.clear();
+
+    ParameterCollection* parameters = definition->GetParameterDefinition();
+    m_symbol = definition->GetName().c_str();
+
+    int length = parameters->GetCount();
+    for (int i = 0; i < length; i++)
+    {
+        Parameter* param = parameters->GetAt(i);
+        const wchar_t* name = param->GetIdentifier().c_str();
+        const wchar_t* value = param->GetDefaultValue().c_str();
+        m_defaults[name] = value;
+    }
+}
+
+void SE_ExpressionBase::ReplaceParameters(const MdfModel::MdfString& exprstr, const wchar_t* fallback)
+{
+    MdfString::size_type startIdx, endIdx, count;
+    MdfString::iterator beginIter;
+    const wchar_t *name, *value;
+
+    m_buffer.assign(exprstr);
+    startIdx = endIdx = 0;
+
+    for(;;)
+    {
+        startIdx = m_buffer.find(L'%', startIdx);
+        if (startIdx == MdfString::npos)
+            break;
+
+        endIdx = m_buffer.find(L'%', startIdx + 1);
+        if (endIdx == MdfString::npos)
+            break;
+
+        count = endIdx - startIdx - 1;
+        m_param.assign(m_buffer, startIdx + 1, count);
+        name = m_param.c_str();
+
+        /* If there is a space in the parameter name, this is not a parameter.  This way,
+         * if we add a modulus operator or something, parsing will not be completely screwed up,
+         * although we should probably check for a few more illegal characters as well (checking
+         * for legal characters doesn't seem viable in the face of localization) */
+        bool notParam = false;
+        for (size_t i = 0; i < count; i++)
+            if (iswspace(name[i]))
+                notParam = true;
+        if (notParam)
+        {
+            startIdx = endIdx;
+            continue;
+        }
+
+        ParameterMap::const_iterator paramIter = m_parameters.find(ParamId(m_symbol, name));
+
+        if (paramIter == m_parameters.end())
+        {
+            DefaultMap::const_iterator defIter = m_defaults.find(name);
+            if (defIter == m_defaults.end())
+                value = fallback;
+            else
+                value = (*defIter).second;
+        }
+        else
+            value = (*paramIter).second;
+
+        beginIter = m_buffer.begin();
+        m_buffer.replace(beginIter + startIdx, beginIter + endIdx + 1, value);
+        startIdx += wcslen(value);
+    }
+}
+
+void SE_ExpressionBase::ParseDoubleExpression(const MdfModel::MdfString& exprstr, SE_Double& val)
+{
+    ReplaceParameters(exprstr, L"0.0");
+    const wchar_t* cstr = m_buffer.c_str();
+    size_t len = m_buffer.size();
+    size_t chars = 0;
+    val.expression = NULL;
+
+    if (len == 0)
+    {
+        val.value = 0;
+        return;
+    }
+
+    int ret = swscanf(cstr, L"%lf%n", &val.value, &chars);
+
+    if (ret == 1 && chars == len)
+        return;
+
+    val.expression = FdoExpression::Parse(cstr);
+}
+
+void SE_ExpressionBase::ParseIntegerExpression(const MdfModel::MdfString& exprstr, SE_Integer& val)
+{
+    ReplaceParameters(exprstr, L"0");
+    const wchar_t* cstr = m_buffer.c_str();
+    size_t len = m_buffer.size();
+    size_t chars = 0;
+    val.expression = NULL;
+
+    if (len == 0)
+    {
+        val.value = 0;
+        return;
+    }
+
+    int ret = swscanf(cstr, L"%d%n", &val.value, &chars);
+
+    if (ret == 1 && chars == len)
+        return;
+
+    val.expression = FdoExpression::Parse(cstr);
+}
+
+void SE_ExpressionBase::ParseBooleanExpression(const MdfModel::MdfString& exprstr, SE_Boolean& val)
+{
+    ReplaceParameters(exprstr, L"false");
+    const wchar_t* cstr = m_buffer.c_str();
+    size_t len = m_buffer.size();
+    val.expression = NULL;
+
+    if (len == 0)
+    {
+        val.value = false;
+        return;
+    }
+    
+    if (_wcsnicmp(cstr, L"true", 5) == 0)
+    {
+        val.value = true;
+        return;
+    }
+    else if (_wcsnicmp(cstr, L"false", 6) == 0)
+    {
+        val.value = false;
+        return;
+    }
+
+    val.expression = FdoExpression::Parse(cstr);
+}
+
+void SE_ExpressionBase::ParseStringExpression(const MdfModel::MdfString& exprstr, SE_String& val)
+{
+    ReplaceParameters(exprstr, L"");
+
+    //TODO: we need to add Parse functions that know what the string they are parsing represents.
+    //for example ParseHorizontalAlignment. This way we can determine if the value is a constant
+    //or an expression that needs to be evaluated all the time.
+    if (exprstr.empty())
+    {
+        val.expression = NULL;
+        val.value = L"";
+    }
+    else
+        val.expression = FdoExpression::Parse(m_buffer.c_str());
+}
+
+void SE_ExpressionBase::ParseColorExpression(const MdfModel::MdfString& exprstr, SE_Color& val)
+{
+    ReplaceParameters(exprstr, L"FF000000");
+    const wchar_t* cstr = m_buffer.c_str();
+    size_t len = m_buffer.size();
+    size_t chars = 0;
+    val.expression = NULL;
+
+    if (len == 0)
+    {
+        val = 0;
+        return;
+    }
+
+    int ret = swscanf(cstr, L"%X%n", &val.argb(), &chars);
+
+    if (ret == 1 && chars == len)
+    {
+        return;
+    }
+    
+    val.expression = FdoExpression::Parse(cstr);
+}


Property changes on: trunk/MgDev/Common/Stylization/SE_ExpressionBase.cpp
___________________________________________________________________
Name: svn:eol-style
   + native

Added: trunk/MgDev/Common/Stylization/SE_ExpressionBase.h
===================================================================
--- trunk/MgDev/Common/Stylization/SE_ExpressionBase.h	                        (rev 0)
+++ trunk/MgDev/Common/Stylization/SE_ExpressionBase.h	2007-03-06 23:31:17 UTC (rev 1158)
@@ -0,0 +1,82 @@
+//
+//  Copyright (C) 2007 by Autodesk, Inc.
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of version 2.1 of the GNU Lesser
+//  General Public License as published by the Free Software Foundation.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+//
+
+#ifndef SE_EXPRESSIONBASE_H
+#define SE_EXPRESSIONBASE_H
+
+#include <map>
+#include <string>
+
+#include "SimpleSymbolDefinition.h"
+#include "CompositeSymbolization.h"
+
+struct SE_Double;
+struct SE_Integer;
+struct SE_Boolean;
+struct SE_String;
+struct SE_Color;
+
+typedef std::pair<const wchar_t*, const wchar_t*> ParamId;
+
+struct ParamCmpLess : std::binary_function<ParamId&, ParamId&, bool>
+{
+public:
+    bool operator( ) (const ParamId& a, const ParamId& b) const
+    {
+        int symcmp = _wcsicmp(a.first, b.first);
+        if (symcmp == 0)
+            return _wcsicmp(a.second, b.second) < 0;
+        
+        return symcmp < 0;
+    }
+};
+
+struct StrCmpLess : std::binary_function<const wchar_t*, const wchar_t*, bool>
+{
+public:
+    bool operator( ) (const wchar_t* a, const wchar_t* b) const
+    {
+        return _wcsicmp(a, b) < 0;
+    }
+};
+
+typedef std::map<ParamId, const wchar_t*, ParamCmpLess> ParameterMap;
+typedef std::map<const wchar_t*, const wchar_t*, StrCmpLess> DefaultMap; 
+
+class SE_ExpressionBase
+{
+public:
+    void ParseDoubleExpression(const MdfModel::MdfString& exprstr, SE_Double& val);
+    void ParseIntegerExpression(const MdfModel::MdfString& exprstr, SE_Integer& val);
+    void ParseBooleanExpression(const MdfModel::MdfString& exprstr, SE_Boolean& val);
+    void ParseStringExpression(const MdfModel::MdfString& exprstr, SE_String& val);
+    void ParseColorExpression(const MdfModel::MdfString& exprstr, SE_Color& val);
+    
+    void SetParameterValues(MdfModel::OverrideCollection* overrides);
+    void SetDefaultValues(MdfModel::SimpleSymbolDefinition* definition);
+
+private:
+    void ReplaceParameters(const MdfModel::MdfString& exprstr, const wchar_t* fallback);
+    
+    ParameterMap m_parameters;
+    DefaultMap m_defaults;
+    const wchar_t* m_symbol;
+    MdfModel::MdfString m_buffer;
+    MdfModel::MdfString m_param;
+};
+
+#endif // SE_EXPRESSIONBASE_H


Property changes on: trunk/MgDev/Common/Stylization/SE_ExpressionBase.h
___________________________________________________________________
Name: svn:eol-style
   + native

Added: trunk/MgDev/Common/Stylization/SE_Include.h
===================================================================
--- trunk/MgDev/Common/Stylization/SE_Include.h	                        (rev 0)
+++ trunk/MgDev/Common/Stylization/SE_Include.h	2007-03-06 23:31:17 UTC (rev 1158)
@@ -0,0 +1,480 @@
+//
+//  Copyright (C) 2007 by Autodesk, Inc.
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of version 2.1 of the GNU Lesser
+//  General Public License as published by the Free Software Foundation.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+//
+
+#ifndef SE_INCLUDE_H
+#define SE_INCLUDE_H
+
+#include <math.h>
+#include <map>
+
+#include "FilterExecutor.h"
+#include "SE_Matrix.h"
+#include "SE_LineBuffer.h"
+
+using namespace MDFMODEL_NAMESPACE;
+
+#define SE_INLINE inline
+
+enum SE_PrimitiveType
+{
+    SE_PolylinePrimitive,
+    SE_PolygonPrimitive,
+    SE_TextPrimitive,
+    SE_RasterPrimitive
+};
+
+enum SE_StyleType
+{
+    SE_PointStyleType,
+    SE_LineStyleType,
+    SE_AreaStyleType
+};
+
+struct SE_Color
+{
+    unsigned char b, g, r, a; // argb, but little endian
+    FdoExpression* expression;
+
+    SE_INLINE SE_Color() : expression(NULL) { *((unsigned int*)this) = 0; }
+    ~SE_Color() { if (expression) expression->Release(); }
+
+    // Retrieve argb color
+    SE_INLINE unsigned int evaluate(RS_FilterExecutor* processor)
+    {
+        if (expression)
+        {
+            expression->Process(processor);
+            *((unsigned int*)this) = (unsigned int)processor->GetInt64Result();
+        }
+        
+        return *((unsigned int*)this);
+    }
+
+    SE_INLINE void operator=(unsigned int val) { *((unsigned int*)this) = val; }
+    SE_INLINE bool empty() { return (*(unsigned int*)this) == 0 && expression == NULL; }
+    SE_INLINE unsigned int& argb() { return (*(unsigned int*)this); }
+};
+
+struct SE_Double
+{
+    double value;
+    FdoExpression* expression;
+
+    SE_INLINE SE_Double() : expression(NULL),value(0.0)  {  }
+    SE_INLINE SE_Double(double d) : value(d), expression(NULL) { }
+    ~SE_Double() { if (expression) expression->Release(); }
+
+    SE_INLINE double evaluate(RS_FilterExecutor* processor)
+    {
+        if (expression)
+        {
+            expression->Process(processor);
+            value = processor->GetDoubleResult();
+        }
+
+        return value;
+    }
+
+    SE_INLINE void operator=(double d)  { value = d; }
+};
+
+struct SE_Integer
+{
+    int value;
+    FdoExpression* expression;
+
+    SE_INLINE SE_Integer() : expression(NULL), value(0) { }
+    SE_INLINE SE_Integer(int i) : value(i), expression(NULL) { }
+    ~SE_Integer() { if (expression) expression->Release(); }
+
+    SE_INLINE int evaluate(RS_FilterExecutor* processor)
+    {
+        if (expression)
+        {
+            expression->Process(processor);
+            value = (int)processor->GetInt64Result();
+        }
+
+        return value;
+    }
+
+    SE_INLINE void SE_Integer::operator=(int i)  { value = i; }
+};
+
+struct SE_Boolean
+{
+    bool value;
+    FdoExpression* expression;
+
+    SE_INLINE SE_Boolean() : expression(NULL), value(false) { }
+    SE_INLINE SE_Boolean(bool b) : value(b), expression(NULL) { }
+    ~SE_Boolean() { if (expression) expression->Release(); }
+
+    SE_INLINE bool evaluate(RS_FilterExecutor* processor)
+    {
+        if (expression)
+        {
+            expression->Process(processor);
+            value = (bool)processor->GetBooleanResult();
+        }
+
+        return value;
+    }
+
+    SE_INLINE void operator=(bool b) { value = b; }
+};
+
+struct SE_String
+{
+    const wchar_t* value;
+    FdoExpression* expression;
+
+    SE_INLINE SE_String() : expression(NULL), value(NULL) { }
+    SE_INLINE SE_String(const wchar_t* s) : value(s), expression(NULL) { }
+    ~SE_String() { if (expression) expression->Release(); }
+
+    SE_INLINE const wchar_t* evaluate(RS_FilterExecutor* processor)
+    {
+        if (expression)
+        {
+            expression->Process(processor);
+            value = processor->GetStringResult();
+        }
+
+        return value;
+    }
+
+    SE_INLINE void operator=(const wchar_t* s) { value = s; }
+};
+
+//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+//
+//        SE_Primitives
+//
+//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+struct SE_Primitive
+{
+    SE_PrimitiveType type;
+    GraphicElement::ResizeControl resize;
+    bool cacheable;
+};
+
+struct SE_Polyline : public SE_Primitive
+{
+    SE_LineBuffer* geometry;
+    SE_Double weight;
+    SE_Color color;
+
+    SE_INLINE SE_Polyline() : weight(0.0) { type = SE_PolylinePrimitive; }
+};
+
+struct SE_Polygon : public SE_Polyline
+{
+    SE_Color fill;
+
+    SE_INLINE SE_Polygon() { type = SE_PolygonPrimitive; weight = 0.0; } 
+};
+
+/* Font/properties caching is left to the implementor of SE_Renderer */
+struct SE_Text : public SE_Primitive
+{
+    SE_String textExpr;
+    SE_String fontExpr;
+    SE_Double position[2];
+    SE_Double size; // pt
+    SE_Double angle;
+    SE_Boolean underlined;
+    SE_Boolean italic;
+    SE_Boolean bold;
+    SE_Double lineSpacing;
+    SE_String hAlignment;
+    SE_String vAlignment;
+    SE_String justification;
+    SE_Color textColor;
+    SE_Color ghostColor;
+
+    SE_INLINE SE_Text() { type = SE_TextPrimitive;  }
+};
+
+struct SE_Raster : public SE_Primitive
+{
+    SE_String pngPath;
+    unsigned char* pngPtr;
+    int pngSize;
+    SE_Double position[2];
+    SE_Double extent[2];
+    SE_Double angle;
+
+    SE_INLINE SE_Raster() { type = SE_RasterPrimitive; }
+};
+
+
+//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+//
+//        SE_RenderPrimitives
+//
+//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+struct SE_RenderPrimitive
+{
+    SE_PrimitiveType type;
+    bool resize;
+    SE_Bounds* bounds;
+};
+
+struct SE_RenderPolyline : public SE_RenderPrimitive
+{
+    SE_LineBuffer* geometry;
+    double weight;
+    unsigned int color;
+
+    SE_INLINE SE_RenderPolyline() { type = SE_PolylinePrimitive; }
+};
+
+struct SE_RenderPolygon : public SE_RenderPolyline
+{
+    unsigned int fill;
+
+    SE_INLINE SE_RenderPolygon() { type = SE_PolygonPrimitive; }
+};
+
+struct SE_RenderText : public SE_RenderPrimitive
+{
+    const wchar_t* text;
+    double position[2];
+
+    RS_TextDef tdef;
+
+    SE_INLINE SE_RenderText() { type = SE_TextPrimitive; }
+};
+
+/* Caching, if any, is left to the implementor of SE_Renderer */
+struct SE_RenderRaster : public SE_RenderPrimitive
+{
+    unsigned char* pngPtr;
+    int pngSize;
+    double position[2];
+    double extent[2];
+    double angle;
+
+    SE_INLINE SE_RenderRaster() : pngPtr(0), pngSize(0) { type = SE_RasterPrimitive; }
+};
+
+typedef std::vector<SE_Primitive*> SE_Symbol;
+typedef std::vector<SE_RenderPrimitive*> SE_RenderSymbol;
+
+//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+//
+//        SE_Styles
+//
+//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+struct SE_Style
+{
+    SE_StyleType type;
+    SE_Symbol symbol;
+    SE_Integer renderPass;
+
+    bool useBox;
+    SE_Double resizePosition[2];
+    SE_Double resizeSize[2];
+    ResizeBox::GrowControl resize;
+
+    SE_INLINE SE_Style(SE_StyleType stype) : type(stype) { }
+
+    ~SE_Style()
+    {
+        for (SE_Symbol::iterator iter = symbol.begin(); iter != symbol.end(); iter++)
+            delete *iter;
+    }
+};
+
+struct SE_PointStyle : public SE_Style
+{
+    SE_INLINE SE_PointStyle() : SE_Style(SE_PointStyleType) { }
+
+    Usage::AngleControl orientation;
+    SE_Double angle;
+    SE_Double offset[2];
+};
+
+struct SE_LineStyle : public SE_Style
+{
+    SE_INLINE SE_LineStyle() : SE_Style(SE_LineStyleType) { }
+
+    Usage::AngleControl orientation;
+    LineUsage::UnitsControl units;
+    LineUsage::VertexControl overlap;
+    Path::LineJoin join;
+
+    SE_Double startOffset;
+    SE_Double endOffset;
+    SE_Double repeat;
+    SE_Double angleLimit;
+    SE_Double angle;
+};
+
+struct SE_AreaStyle : public SE_Style
+{
+    SE_INLINE SE_AreaStyle() : SE_Style(SE_AreaStyleType) { }
+
+    Usage::AngleControl orientation;
+    AreaUsage::OriginControl origincontrol;
+    AreaUsage::ClippingControl clipping;
+
+    SE_Double origin[2];
+    SE_Double repeat[2];
+    SE_Double angle;
+    SE_Double bufferWidth;
+};
+
+//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+//
+//        SE_RenderStyles
+//
+//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+struct SE_RenderStyle
+{
+    SE_INLINE SE_RenderStyle(SE_StyleType stype) 
+        : type(stype),
+          drawLast(false),
+          checkExclusionRegions(false),
+          addToExclusionRegions(false),
+          bounds(NULL)
+    { }
+
+    ~SE_RenderStyle()
+    {
+        for (SE_RenderSymbol::iterator iter = symbol.begin(); iter != symbol.end(); iter++)
+            delete *iter;
+    }
+
+    SE_StyleType type;
+    SE_RenderSymbol symbol;
+    SE_Bounds* bounds;
+
+    int renderPass;
+
+    bool drawLast;
+    bool checkExclusionRegions;
+    bool addToExclusionRegions;
+};
+
+struct SE_RenderPointStyle : public SE_RenderStyle
+{
+    SE_INLINE SE_RenderPointStyle() : SE_RenderStyle(SE_PointStyleType) { }
+};
+
+struct SE_RenderLineStyle : public SE_RenderStyle
+{
+    SE_INLINE SE_RenderLineStyle() : SE_RenderStyle(SE_LineStyleType) { }
+
+    Usage::AngleControl orientation;
+    LineUsage::UnitsControl units;
+    LineUsage::VertexControl overlap;
+    Path::LineJoin join;
+
+    double startOffset;
+    double endOffset;
+    double repeat;
+    double angleLimit;
+    double angle;
+};
+
+struct SE_RenderAreaStyle : public SE_RenderStyle
+{
+    SE_INLINE SE_RenderAreaStyle() : SE_RenderStyle(SE_AreaStyleType) { }
+
+    AreaUsage::OriginControl origincontrol;
+    AreaUsage::AngleControl orientation;
+    AreaUsage::ClippingControl clipping;
+
+    unsigned int background;
+    double origin[2];
+    double repeat[2];
+    double angle;
+    double radius;
+};
+
+
+class SE_LabelInfo
+{
+public:
+    SE_RenderStyle* symbol;
+    double x;
+    double y;
+    double dx;
+    double dy;
+    double anglerad;
+    RS_Units dunits;    
+    
+    SE_INLINE SE_LabelInfo() :
+        x(0.0),
+        y(0.0),
+        dx(0.0),
+        dy(0.0),
+        anglerad(0.0),
+        symbol(NULL)
+    { }
+
+    SE_INLINE SE_LabelInfo (double _x, double _y, double _dx, double _dy, RS_Units _dunits, double _anglerad, SE_RenderStyle* _symbol)
+                 : x(_x), y(_y), dx(_dx), dy(_dy), dunits(_dunits), anglerad(_anglerad), symbol(_symbol)
+    { }
+};
+
+
+struct SE_Symbolization
+{
+    std::vector<SE_Style*> styles;
+
+    SE_Double scale[2];
+    SE_Double absOffset[2];
+    MdfModel::SizeContext context;
+    SE_Boolean drawLast;
+    SE_Boolean checkExclusionRegions;
+    SE_Boolean addToExclusionRegions;
+    std::wstring positioningAlgorithm;
+
+    ~SE_Symbolization()
+    {
+        for (std::vector<SE_Style*>::iterator iter = styles.begin(); iter != styles.end(); iter++)
+            delete *iter;
+
+        styles.clear();
+    }
+};
+
+struct SE_Rule
+{
+    std::vector<SE_Symbolization*> symbolization;
+    FdoFilter* filter;
+    
+    ~SE_Rule()
+    {
+        if (filter) filter->Release();
+
+        for (std::vector<SE_Symbolization*>::iterator iter = symbolization.begin(); iter != symbolization.end(); iter++)
+            delete *iter;
+
+        symbolization.clear();
+    }
+};
+
+
+#endif // SE_INCLUDE_H


Property changes on: trunk/MgDev/Common/Stylization/SE_Include.h
___________________________________________________________________
Name: svn:eol-style
   + native

Added: trunk/MgDev/Common/Stylization/SE_LineBuffer.cpp
===================================================================
--- trunk/MgDev/Common/Stylization/SE_LineBuffer.cpp	                        (rev 0)
+++ trunk/MgDev/Common/Stylization/SE_LineBuffer.cpp	2007-03-06 23:31:17 UTC (rev 1158)
@@ -0,0 +1,682 @@
+//
+//  Copyright (C) 2007 Autodesk, Inc.
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of version 2.1 of the GNU Lesser
+//  General Public License as published by the Free Software Foundation.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+//
+
+#include "SE_LineBuffer.h"
+#include "SE_ConvexHull.h"
+#include "SE_Bounds.h"
+
+#define _USE_MATH_DEFINES
+#include <math.h>
+#include <float.h>
+
+#define GROWTH_FACTOR 1.5
+
+#define ENSURE_POINT_BUFFER(points) \
+    if ((m_npts + (points)) > m_max_pts) \
+        ResizeBuffer((void**)&m_pts, 2*sizeof(double), (points), m_npts, m_max_pts);
+
+#define ENSURE_XF_POINT_BUFFER(points) \
+    if ((m_xf_npts + (points)) > m_max_xf_pts) \
+        ResizeBuffer((void**)&m_xf_pts, 2*sizeof(double), (points), m_xf_npts, m_max_xf_pts);
+
+#define ENSURE_INST_POINT_BUFFER(points) \
+    if ((m_inst_npts + (points)) > m_max_inst_pts) \
+        ResizeBuffer((void**)&m_inst_pts, 2*sizeof(double), (points), m_inst_npts, m_max_inst_pts);
+
+#define ENSURE_XF_CNTR_BUFFER(points) \
+    if ((m_xf_ncntrs + (points)) > m_max_xf_cntrs) \
+        ResizeBuffer((void**)&m_xf_cntrs, sizeof(int), (points), m_xf_ncntrs, m_max_xf_cntrs);
+
+#define ENSURE_INST_CNTR_BUFFER(points) \
+    if ((m_inst_ncntrs + (points)) > m_max_inst_cntrs) \
+        ResizeBuffer((void**)&m_inst_cntrs, sizeof(int), (points), m_inst_ncntrs, m_max_inst_cntrs);
+
+#define ENSURE_SEG_BUFFER(points) \
+    if ((m_nsegs + (points)) > m_max_segs) \
+        ResizeBuffer((void**)&m_segs, sizeof(SE_LB_SegType), (points), m_nsegs, m_max_segs);
+
+inline void SineCosineMax(double sAng, double sSine, double sCosine, double eAng, double eSine, double eCosine, double &maxSine, double &maxCosine)
+{
+    int quadrants = ((int)(sAng*2.0/M_PI) << 2) | (int)(eAng*2.0/M_PI);
+
+    switch(quadrants)
+    {
+    case 0: /* Q1 -> Q1, sine increasing, cosine decreasing */
+        maxSine = eSine;
+        maxCosine = sCosine;
+        return;
+    case 1: /* Q1 -> Q2, sine local maximum, cosine local minimum */
+        maxSine = 1.0;
+        maxCosine = (sCosine > eCosine ? sCosine : eCosine);
+        return;
+    case 2: /* Q1 -> Q3, sine local maximum, cosine local maximum */
+        maxSine = 1.0;
+        maxCosine = 1.0;
+        return;
+    case 3: /* Q1 -> Q4, sine local maximum, cosine local maximum */
+        maxSine = 1.0;
+        maxCosine = 1.0;
+        return;
+    /* case 4: Q2 -> Q1 */
+    case 5: /* Q2 -> Q2, sine decreasing, cosine increasing */
+        maxSine = sSine;
+        maxCosine = eCosine;
+        return;
+    case 6: /* Q2 -> Q3, sine decreasing, increasing, cosine local maximum */
+        maxSine = (sSine > eSine ? sSine : eSine);
+        maxCosine = 1.0;
+        return;
+    case 7: /* Q2 -> Q4, sine local maximum, cosine local maximum */
+        maxSine = 1.0;
+        maxCosine = 1.0;
+        return;
+    /* case 8:  Q3 -> Q1 */
+    /* case 9:  Q3 -> Q2 */
+    case 10: /* Q3 -> Q3, sine increasing, cosine decreasing */
+        maxSine = eSine;
+        maxCosine = sCosine;
+        return;
+    case 11: /* Q3 -> Q4, sine local maximum, cosine local minimum */
+        maxSine = 1.0;
+        maxCosine = (sCosine > eCosine ? sCosine : eCosine);
+        return;
+    /* case 12: Q4 -> Q1 */
+    /* case 13: Q4 -> Q2 */
+    /* case 14: Q4 -> Q3 */
+    case 15: /* Q4 -> Q4, sine decreasing, cosine increasing */
+        maxSine = sSine;
+        maxCosine = eCosine;
+        return;
+    default:
+        maxSine = 1.0;
+        maxCosine = 1.0;
+        return;
+    }
+}
+
+inline void TransformScale(SE_Matrix& xform, double &sx, double &sy)
+{
+    sx = sqrt(xform.x0*xform.x0 + xform.x1*xform.x1);
+    sy = sqrt(xform.y0*xform.y0 + xform.y1*xform.y1);
+}
+
+inline void LineExt(double dx, double dy, double hweight, double &vx, double &vy)
+{
+    double scale = hweight/sqrt(dx*dx + dy*dy);
+    vx = dy*scale;
+    vy = -dy*scale;
+}
+
+struct PointUtil
+{
+    SE_INLINE double x(std::set<std::pair<double,double>, PointLess>::iterator iter)
+    {
+        return (*iter).first;
+    }
+
+    SE_INLINE double y(std::set<std::pair<double,double>, PointLess>::iterator iter)
+    {
+        return (*iter).second;
+    }
+
+    SE_INLINE bool equal(std::set<std::pair<double,double>, PointLess>::iterator a,
+                         std::set<std::pair<double,double>, PointLess>::iterator b)
+    {
+        return ((*a).first == (*b).first) && ((*a).second == (*b).second);
+    }
+};
+
+SE_Bounds* SE_LineBuffer::ComputeConvexHull(double* pnts, int* cntrs, int ncntrs, double weight)
+{
+    // Monotone Chain Convex Hull Algorithm (Andrew, 1979)
+    m_ch_ptbuf.clear();
+
+    double hweight = weight/2.0;
+    double* cur = pnts;
+    double* last;
+    for (int i = 0; i < ncntrs; i++)
+    {
+        last = cur + cntrs[i]*2;
+
+        if (weight > 0)
+        {
+            double x, y, lx, ly, vx, vy;
+            x = *cur++;
+            y = *cur++;
+            lx = *cur++;
+            ly = *cur++;
+            LineExt(lx-x, ly-y, hweight, vx, vy);
+            /* For each segment, add the bounding box of the rectangle formed by applying line weight */
+            /* TODO: this result will be correct if the line is drawn with bevel joins...Map and MG,
+               however, appear to be using round joins at the moment. */
+            m_ch_ptbuf.insert(std::pair<double,double>(x + vx, y + vy));
+            m_ch_ptbuf.insert(std::pair<double,double>(x - vx, y - vy));
+            m_ch_ptbuf.insert(std::pair<double,double>(lx + vx, ly + vy));        
+            m_ch_ptbuf.insert(std::pair<double,double>(lx - vx, ly - vy));
+
+            while(cur < last)
+            {
+                x = *cur++;
+                y = *cur++;
+                LineExt(x-lx, y-ly, hweight, vx, vy);
+                m_ch_ptbuf.insert(std::pair<double,double>(x + vx, y + vy));
+                m_ch_ptbuf.insert(std::pair<double,double>(x - vx, y - vy));
+                m_ch_ptbuf.insert(std::pair<double,double>(lx + vx, ly + vy));
+                m_ch_ptbuf.insert(std::pair<double,double>(lx - vx, ly - vy));
+                lx = x;
+                ly = y;
+            }
+        }
+        else /* Weight might be zero...such as if the buffer holds pure geometry from a LineBuffer */
+        {
+            double x, y;
+            while(cur < last)
+            {
+                x = *cur++;
+                y = *cur++;
+                m_ch_ptbuf.insert(std::pair<double,double>(x, y));
+            }
+        }
+    }
+
+    std::set<std::pair<double,double>, PointLess>::iterator end = m_ch_ptbuf.end();
+    std::set<std::pair<double,double>, PointLess>::iterator iter = m_ch_ptbuf.begin();
+
+    return AndrewHull<std::set<std::pair<double,double>, PointLess>::iterator, PointUtil>
+        (iter, --end, (int)m_ch_ptbuf.size(), m_pool);
+}
+
+SE_LineBuffer::SE_LineBuffer(int size) :
+    m_npts(0),
+    m_nsegs(0),
+    m_xf_ncntrs(0),
+    m_inst_ncntrs(0),
+    m_xf_npts(0),
+    m_inst_npts(0),
+    m_max_xf_pts(size),
+    m_max_inst_pts(size),
+    m_max_xf_cntrs(size),
+    m_max_inst_cntrs(size),
+    m_max_pts(size),
+    m_max_segs(size),
+    m_xf_tol(-1.0),
+    m_xf_weight(-1.0),
+    m_src_lb(NULL),
+    m_xf_bounds(NULL),
+    m_inst_bounds(NULL)
+{
+    m_pts = new double[size*2];
+    m_xf_pts = new double[size*2];
+    m_inst_pts = new double[size*2];
+    m_xf_cntrs = new int[size];
+    m_inst_cntrs = new int[size];
+    m_segs = new SE_LB_SegType[size];
+}
+
+SE_LineBuffer::~SE_LineBuffer()
+{
+    delete[] m_pts;
+    delete[] m_xf_pts;
+    delete[] m_inst_pts;
+    delete[] m_xf_cntrs;
+    delete[] m_inst_cntrs;
+    delete[] m_segs;
+}
+
+void SE_LineBuffer::MoveTo(double x, double y)
+{
+    ENSURE_POINT_BUFFER(1);
+    ENSURE_SEG_BUFFER(1);
+
+    double* cur_pt = m_pts + 2*m_npts++;
+    *cur_pt++ = x;
+    *cur_pt = y;
+
+    m_start[0] = x;
+    m_start[1] = y;
+
+    m_segs[m_nsegs++] = SegType_MoveTo;
+}
+
+void SE_LineBuffer::LineTo(double x, double y)
+{
+    ENSURE_POINT_BUFFER(1);
+    ENSURE_SEG_BUFFER(1);
+
+    double* cur_pt = m_pts + 2*m_npts++;
+    *cur_pt++ = x;
+    *cur_pt = y;
+
+    m_segs[m_nsegs++] = SegType_LineTo;
+}
+
+void SE_LineBuffer::EllipticalArcTo(double cx, double cy, double rx, double ry, double sAng, double eAng, double rotation)
+{
+    ENSURE_POINT_BUFFER(7);
+    ENSURE_SEG_BUFFER(1);
+
+    double* cur_pt = m_pts + 2*m_npts;
+    *cur_pt++ = cx;
+    *cur_pt++ = cy;
+    *cur_pt++ = rx;
+    *cur_pt++ = ry;
+    *cur_pt++ = sAng;
+    *cur_pt++ = eAng;
+    *cur_pt = rotation;
+
+    m_npts += 7;
+    m_segs[m_nsegs++] = SegType_EllipticalArc;
+}
+
+void SE_LineBuffer::Close()
+{
+    LineTo(m_start[0], m_start[1]);
+}
+
+void SE_LineBuffer::Reset()
+{
+    m_npts = m_xf_npts = m_xf_ncntrs = m_nsegs = m_inst_npts = m_inst_ncntrs = 0;
+    if (m_xf_bounds)
+    {
+        m_pool->FreeBounds(m_xf_bounds);
+        m_xf_bounds = NULL;
+    }
+    if (m_inst_bounds)
+    {
+        m_pool->FreeBounds(m_inst_bounds);
+        m_inst_bounds = NULL;
+    }
+    m_src_lb = NULL;
+    m_xf_tol = m_xf_weight = -1.0;
+    m_xf.setIdentity();
+}
+
+void SE_LineBuffer::ResizeBuffer(void** buffer, int unitsize, int mininc, int cur_pts, int& max_pts)
+{
+    int max_newpts = (int)(max_pts*GROWTH_FACTOR) + 1;
+    if (max_newpts - max_pts < mininc)
+        max_newpts += mininc;
+     
+    void* newbuf = new char[unitsize*max_newpts];
+    memcpy(newbuf, *buffer, cur_pts*unitsize);
+    delete[] *buffer;
+    *buffer = newbuf;
+    max_pts = max_newpts;
+}
+
+void SE_LineBuffer::Transform(const SE_Matrix& xform, double weight, double tolerance)
+{
+    if (m_xf == xform && m_xf_tol == tolerance && m_xf_weight == weight)
+        return;
+
+    if (m_xf_bounds)
+    {
+        m_pool->FreeBounds(m_xf_bounds);
+        m_xf_bounds = NULL;
+    }
+
+    if (m_src_lb)
+    {
+        SetToTransform(m_src_lb, xform);
+        return;
+    }
+
+    m_xf = xform;
+    m_xf_tol = tolerance;
+    m_xf_weight = weight;
+
+    SE_LB_SegType* endseg = m_segs + m_nsegs;
+    SE_LB_SegType* curseg = m_segs;
+    int src_idx = 0;
+    int dst_idx = 0;
+    while(curseg != endseg)
+    {
+        switch(*curseg++)
+        {
+        case SegType_MoveTo:
+            ENSURE_XF_CNTR_BUFFER(1);
+            m_xf_cntrs[m_xf_ncntrs++] = 0;
+        case SegType_LineTo:
+            ENSURE_XF_POINT_BUFFER(1);
+            xform.transform(m_pts[src_idx], m_pts[src_idx+1], m_xf_pts[dst_idx], m_xf_pts[dst_idx+1]);
+            src_idx += 2;
+            dst_idx += 2;
+            m_xf_cntrs[m_xf_ncntrs-1]++;
+            m_xf_npts++;
+            break;
+        case SegType_EllipticalArc:
+            {
+                double cx = m_pts[src_idx++];
+                double cy = m_pts[src_idx++];
+                double rx = m_pts[src_idx++];
+                double ry = m_pts[src_idx++];
+                double sAng = m_pts[src_idx++];
+                double eAng = m_pts[src_idx++];
+                double rot = m_pts[src_idx++];
+
+                /* TODO: change the # of segments based on the tolerance?...up to 4 for now */
+                int nsegs = (int)(4.0*(eAng - sAng)/(2*M_PI)) + 1; // eAng - sAng is (0, 2pi), so this is {1,2,3,4}.
+                double span = (eAng - sAng)/(double)nsegs;
+                
+                double sec = 1.0/cos(span/2.0);
+                double alpha = sin(span)*(sqrt(1.0 + 3.0/sec/sec) - 1)/3.0;
+                double rcos = cos(rot), rsin = sin(rot);
+                
+                double ex, ey, sx, sy;
+                double scos, ssin, ecos, esin;
+                double sa, ea;
+
+                ecos = cos(sAng);
+                esin = sin(sAng);
+                ex = rx*ecos;
+                ey = ry*esin;
+                ea = sAng;
+
+                for (int i = 0; i < nsegs; i++)
+                {
+                    sa = ea;
+                    ea = sa + span;
+
+                    scos = ecos;
+                    ssin = esin;
+                    ecos = cos(ea);
+                    esin = sin(ea);
+
+                    sx = ex;
+                    sy = ey;
+                    ex = rx*ecos;
+                    ey = ry*esin;
+
+                    double c1x = sx - alpha*rx*ssin;
+                    double c1y = sy + alpha*ry*scos;
+                    double c2x = ex + alpha*rx*esin;
+                    double c2y = ey - alpha*ry*ecos;
+
+                    /* Here, we fine the maximum 2nd derivative over the interval in question, and
+                       calculate the number of segments, assuming a deviation of the segment length *
+                       the second derivative must be within the tolerance */
+                    double mx, my;
+                    SineCosineMax(sa, ssin, scos, ea, esin, ecos, my, mx);
+                    mx *= rx;
+                    my *= ry;
+                    int steps = (int)((span/tolerance)*sqrt(mx*mx + my*my)) + 1;
+                    ENSURE_XF_POINT_BUFFER(steps + 1);
+                    m_xf_cntrs[m_xf_ncntrs-1] += steps + 1;
+                    m_xf_npts += steps + 1;
+
+                    if (rot != 0.0)
+                    {
+                        double tx, ty;
+                        tx = ex, ty = ey;
+                        ex = tx*rcos + ty*rsin;
+                        ey = ty*rcos - tx*rsin;
+                        tx = c1x, ty = c1y;
+                        c1x = tx*rcos + ty*rsin;
+                        c1y = ty*rcos - tx*rsin;
+                        tx = c2x, ty = c2y;
+                        c2x = tx*rcos + ty*rsin;
+                        c2y = ty*rcos - tx*rsin;
+                        tx = mx, ty = my;
+                    }
+
+                    ex += cx;
+                    ey += cy;
+                    c1x += cx;
+                    c1y += cy;
+                    c2x += cx;
+                    c2y += cy;
+
+                    TessellateCubicTo(m_xf_pts + dst_idx, c1x, c1y, c2x, c2y, ex, ey, steps);
+                    dst_idx += steps + 1;
+                }
+
+                break;
+            }
+        }
+    }
+}
+
+void SE_LineBuffer::InstanceTransform(const SE_Matrix& xform, SE_Geometry& geom, SE_Bounds** bounds)
+{
+    m_inst_npts = 0;
+    m_inst_ncntrs = 0;
+    ENSURE_INST_POINT_BUFFER(m_xf_npts);
+    //ENSURE_INST_CNTR_BUFFER(m_inst_ncntrs); For this transform, the same number of points
+    double* src = m_xf_pts;
+    double* dst = m_inst_pts;
+    double* last = m_xf_pts + m_xf_npts*2;
+    while (src < last)
+    {
+        double sx = *src++;
+        double sy = *src++;
+        double* ix = dst++;
+        double* iy = dst++;
+        xform.transform(sx, sy, *ix, *iy);
+    }
+    m_inst_npts = m_xf_npts;
+    geom.points = m_inst_pts;
+    geom.n_pts = m_inst_npts;
+    geom.contours = m_xf_cntrs;
+    geom.n_cntrs = m_xf_ncntrs;
+
+    geom.geom_type = xf_geom_type();
+
+    if (bounds)
+    {
+        SE_Bounds* srcbounds = xf_bounds();
+        SE_Bounds* dstbounds = *bounds;
+        dstbounds = m_pool->NewBounds(srcbounds->size);
+        for(int i = 0; i < srcbounds->size; i++)
+            xform.transform(srcbounds->hull[2*i], srcbounds->hull[2*i+1], dstbounds->hull[2*i], dstbounds->hull[2*i+1]);
+        dstbounds->size = srcbounds->size;
+        dstbounds->max[0] = srcbounds->max[0];
+        dstbounds->max[1] = srcbounds->max[1];
+        dstbounds->min[0] = srcbounds->min[0];
+        dstbounds->min[1] = srcbounds->min[1];
+    }
+}
+
+bool SE_LineBuffer::Empty()
+{
+    if (m_src_lb)
+        return m_src_lb->point_count() == 0;
+    else
+        return m_npts == 0;
+}
+
+void SE_LineBuffer::TessellateCubicTo(double* pts, double px2, double py2, double px3, double py3, double px4, double py4, int steps)
+{
+    //get the start point
+    double px1 = pts[-2];
+    double py1 = pts[-1];
+
+    double dt = 1.0/(double)steps;
+
+    double dt3 = dt * dt * dt;
+
+    double pre1 = 3.0 * dt;
+    double pre2 = pre1 * dt;
+    double pre3 = pre2 + pre2;
+    double pre4 = 6.0 * dt3;
+
+    double temp1x = px1 - 2.0 * px2 + px3;
+    double temp1y = py1 - 2.0 * py2 + py3;
+    double temp2x = 3.0 * (px2 - px3) - px1 + px4;
+    double temp2y = 3.0 * (py2 - py3) - py1 + py4;
+
+    double fx    = px1;
+    double fy    = py1;
+    double dfx   = (px2 - px1) * pre1 + temp1x * pre2 + temp2x * dt3;
+    double dfy   = (py2 - py1) * pre1 + temp1y * pre2 + temp2y * dt3;
+    double ddfx  = temp1x * pre3 + temp2x * pre4;
+    double ddfy  = temp1y * pre3 + temp2y * pre4;
+    double dddfx = temp2x * pre4;
+    double dddfy = temp2y * pre4;
+
+    // forward differencing loop
+    while(steps--)
+    {
+        fx   += dfx;
+        fy   += dfy;
+        dfx  += ddfx;
+        dfy  += ddfy;
+        ddfy += dddfy;
+        ddfx += dddfx;
+
+        m_xf.transform(fx, fy, pts[0], pts[1]);
+        pts += 2;
+    }
+
+    *pts++ = px4;
+    *pts++ = py4;
+}
+
+SE_Bounds* SE_LineBuffer::xf_bounds()
+{
+    if (m_xf_bounds == NULL)
+        m_xf_bounds = ComputeConvexHull(m_xf_pts, m_xf_cntrs, m_xf_ncntrs, m_xf_weight);
+
+    return m_xf_bounds;
+}
+
+void SE_LineBuffer::xf_longest_edge(double& x0, double& y0, double& x1, double& y1)
+{
+    int* cntr_end = m_xf_cntrs + m_xf_ncntrs;
+    int* contours = m_xf_cntrs;
+    double* points = m_xf_pts;
+
+    while(contours < cntr_end)
+    {
+        double* pnt_end = points + 2*(*contours++);
+        double maxlensq = -1.0, lastx, lasty;
+        lastx = x0 = x1 = *points++;
+        lasty = y0 = y1 = *points++;
+
+        while (points < pnt_end)
+        {
+            double x = *points++;
+            double y = *points++;
+            double lensq = (x - lastx)*(x - lastx) + (y - lasty)*(y - lasty);
+            if (lensq > maxlensq)
+            {
+                maxlensq = lensq;
+                x0 = lastx; y0 = lasty;
+                x1 = x; y1 = y;
+            }
+            lastx = x;
+            lasty = y;
+        }
+    }
+}
+
+int SE_LineBuffer::xf_geom_type()
+{
+    if (m_src_lb)
+        return m_src_lb->geom_type();
+    return -1;
+}
+
+void SE_LineBuffer::Centroid(LineBuffer::GeomOperationType type, double* x, double * y, double * slope)
+{
+    if (m_src_lb)
+    {
+        double dx = 1.0;
+        m_src_lb->Centroid(type, x, y, slope);
+        m_xf.transform(*x, *y);
+        m_xf.transformVector(*slope, dx);
+        *slope /= dx;
+    }
+}
+
+void SE_LineBuffer::SetToTransform(LineBuffer* lb, const SE_Matrix& xform)
+{
+    m_src_lb = lb;
+    m_xf = xform;
+    m_xf_tol = 0.0;
+    m_xf_weight = 0.0;
+
+    ENSURE_XF_POINT_BUFFER(lb->point_count());
+    ENSURE_XF_CNTR_BUFFER(lb->cntr_count());
+
+    m_xf_ncntrs = lb->cntr_count();
+    memcpy(m_xf_cntrs, lb->cntrs(), sizeof(int)*m_xf_ncntrs);
+    
+    m_xf_npts = lb->point_count();
+    double *srcpts = lb->points();
+
+    for (int i = 0; i < 2*m_xf_npts; i += 2)
+        xform.transform(srcpts[i], srcpts[i+1], m_xf_pts[i], m_xf_pts[i+1]);
+}
+
+SE_LineBufferPool::~SE_LineBufferPool()
+{
+    while (!m_lb_pool.empty())
+        delete m_lb_pool.pop();
+    while (!m_bnd_pool.empty())
+        free(m_bnd_pool.pop());
+}
+
+SE_LineBuffer* SE_LineBufferPool::NewLineBuffer(int requestSize)
+{
+    if (!m_lb_pool.empty())
+    {
+        SE_LineBuffer* lb = m_lb_pool.pop();
+        lb->Reset();
+        return lb;
+    }
+    else
+    {
+        SE_LineBuffer* buf = new SE_LineBuffer(requestSize);
+        buf->m_pool = this;
+        return buf;
+    }
+}
+
+void SE_LineBufferPool::FreeLineBuffer(SE_LineBuffer* lb)
+{
+    m_lb_pool.push(lb);
+}
+
+SE_Bounds* SE_LineBufferPool::NewBounds(int size)
+{
+    if (!m_bnd_pool.empty())
+    {
+        SE_Bounds* bounds = m_bnd_pool.pop();
+        if (bounds->capacity >= size)
+        {
+            bounds->size = 0;
+            bounds->min[0] = bounds->min[1] = DBL_MAX;
+            bounds->max[0] = bounds->max[1] = -DBL_MAX;
+            return bounds;
+        }
+        free(bounds);
+    }
+
+    SE_Bounds* bounds = (SE_Bounds*)malloc(sizeof(SE_Bounds) + 2*size*sizeof(double));
+    bounds->hull = (double*)((char*)(bounds) + sizeof(SE_Bounds));
+    bounds->capacity = size;
+    bounds->size = 0;
+    bounds->min[0] = bounds->min[1] = DBL_MAX;
+    bounds->max[0] = bounds->max[1] = -DBL_MAX;
+    bounds->pool = this;
+    return bounds;
+}
+
+void SE_LineBufferPool::FreeBounds(SE_Bounds* bounds)
+{
+    m_bnd_pool.push(bounds);
+}
\ No newline at end of file


Property changes on: trunk/MgDev/Common/Stylization/SE_LineBuffer.cpp
___________________________________________________________________
Name: svn:eol-style
   + native

Added: trunk/MgDev/Common/Stylization/SE_LineBuffer.h
===================================================================
--- trunk/MgDev/Common/Stylization/SE_LineBuffer.h	                        (rev 0)
+++ trunk/MgDev/Common/Stylization/SE_LineBuffer.h	2007-03-06 23:31:17 UTC (rev 1158)
@@ -0,0 +1,134 @@
+//
+//  Copyright (C) 2007 Autodesk, Inc.
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of version 2.1 of the GNU Lesser
+//  General Public License as published by the Free Software Foundation.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+//
+
+#ifndef SE_LINEBUFFER_H
+#define SE_LINEBUFFER_H
+
+#include "LineBuffer.h"
+#include "SE_Matrix.h"
+#include <set>
+
+struct PointLess : std::binary_function<std::pair<double, double>&, std::pair<double, double>&, bool>
+{
+public:
+    bool operator( ) (const std::pair<double, double>& a, const std::pair<double, double>& b) const
+    {
+        return (a.first < b.first) || (a.first == b.first && a.second < b.second);
+    }
+};
+
+struct SE_Geometry
+{
+    double* points;
+    int n_pts;
+    int* contours;
+    int n_cntrs;
+    int geom_type;
+};
+
+struct SE_Bounds;
+
+class SE_LineBuffer
+{
+friend class SE_LineBufferPool;
+private:
+        SE_LineBuffer(int size);
+        ~SE_LineBuffer();
+public:
+    enum SE_LB_SegType
+    {
+        SegType_MoveTo,
+        SegType_LineTo,
+        SegType_EllipticalArc
+    };    
+    
+    STYLIZATION_API void SetToTransform(LineBuffer* lb, const SE_Matrix& xform);
+
+    STYLIZATION_API void MoveTo(double x, double y);
+    STYLIZATION_API void LineTo(double x, double y);
+    STYLIZATION_API void EllipticalArcTo(double cx, double cy, double rx, double ry, double sAng, double eAng, double rotation);
+    STYLIZATION_API void Close();
+    STYLIZATION_API void Transform(const SE_Matrix& xform, double weight = 0.0, double tolerance = .25);
+    STYLIZATION_API void InstanceTransform(const SE_Matrix& xform, SE_Geometry& geom, SE_Bounds** bounds);
+    STYLIZATION_API bool Empty();
+
+    STYLIZATION_API SE_Bounds* xf_bounds();
+    STYLIZATION_API void xf_longest_edge(double& x0, double& y0, double& x1, double& y1);
+    STYLIZATION_API void Centroid(LineBuffer::GeomOperationType type, double* x, double * y, double * slope);
+    STYLIZATION_API int xf_geom_type();
+    SE_INLINE double* xf_points() { return m_xf_pts; }
+    SE_INLINE int xf_point_cnt() { return m_xf_npts; }
+    SE_INLINE int* xf_cntrs() { return m_xf_cntrs; }
+    SE_INLINE int xf_cntr_cnt() { return m_xf_ncntrs; }
+
+private:
+    void Reset();
+    void ResizeBuffer(void** buffer, int unitsize, int mininc, int cur_pts, int& max_pts);
+    void TessellateCubicTo(double* pts, double px2, double py2, double px3, double py3, double px4, double py4, int steps);
+    SE_Bounds* ComputeConvexHull(double* pnts, int* cntrs, int ncntrs, double weight);
+    
+    SE_LineBufferPool* m_pool;
+    LineBuffer* m_src_lb;
+
+    double* m_pts;
+    double* m_xf_pts;
+    double* m_inst_pts;
+    int* m_xf_cntrs;
+    int* m_inst_cntrs;
+    SE_LB_SegType* m_segs;
+
+    /* TODO: maintaining this buffer for every instance is wasteful */
+    std::set<std::pair<double, double>, PointLess> m_ch_ptbuf;
+
+    SE_Matrix m_xf;
+    SE_Bounds* m_xf_bounds;
+    SE_Bounds* m_inst_bounds;
+    double m_xf_tol;
+    double m_xf_weight;
+    
+    double m_start[2];
+
+    int m_npts;
+    int m_xf_npts;
+    int m_inst_npts;
+    int m_xf_ncntrs;
+    int m_inst_ncntrs;
+    int m_nsegs;
+
+    int m_max_xf_cntrs;
+    int m_max_inst_cntrs;
+    int m_max_pts;
+    int m_max_xf_pts;
+    int m_max_inst_pts;
+    int m_max_segs;
+};
+
+class SE_LineBufferPool
+{
+public:
+    STYLIZATION_API virtual ~SE_LineBufferPool();
+    STYLIZATION_API SE_LineBuffer* NewLineBuffer(int requestSize);
+    STYLIZATION_API SE_Bounds* NewBounds(int size);
+    STYLIZATION_API void FreeBounds(SE_Bounds* bounds);
+    STYLIZATION_API void FreeLineBuffer(SE_LineBuffer*);
+
+private:
+    DataValueStack<SE_LineBuffer> m_lb_pool;
+    DataValueStack<SE_Bounds> m_bnd_pool;
+};
+
+#endif // SE_LINEBUFFER_H
\ No newline at end of file


Property changes on: trunk/MgDev/Common/Stylization/SE_LineBuffer.h
___________________________________________________________________
Name: svn:eol-style
   + native

Added: trunk/MgDev/Common/Stylization/SE_Matrix.h
===================================================================
--- trunk/MgDev/Common/Stylization/SE_Matrix.h	                        (rev 0)
+++ trunk/MgDev/Common/Stylization/SE_Matrix.h	2007-03-06 23:31:17 UTC (rev 1158)
@@ -0,0 +1,253 @@
+//
+//  Copyright (C) 2007 by Autodesk, Inc.
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of version 2.1 of the GNU Lesser
+//  General Public License as published by the Free Software Foundation.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+//
+
+#ifndef SE_MATRIX_INL
+#define SE_MATRIX_INL
+
+#include <math.h>
+
+#define SE_INLINE inline
+
+struct SE_Matrix
+{
+    double x0, x1, x2, y0, y1, y2;
+
+    SE_INLINE SE_Matrix();
+    SE_INLINE SE_Matrix(const SE_Matrix & matrix);
+    SE_INLINE SE_Matrix(double x0, double x1, double x2,
+                        double y0, double y1, double y2);
+    
+    SE_INLINE void setIdentity();
+    /* Scale, then rotate, then translate */
+    SE_INLINE void setTransform(double scaleX, double scaleY, double transX, double transY);
+    /* Scale, then translate */
+    SE_INLINE void setTransform(double scaleX, double scaleY, double transX, double transY, double rot);
+    SE_INLINE void scaleX(double x);
+    SE_INLINE void scaleY(double y);
+    SE_INLINE void scale(double x, double y);
+    SE_INLINE void translateX(double x);
+    SE_INLINE void translateY(double y);
+    SE_INLINE void translate(double x, double y);
+    SE_INLINE void rotate(double angle);
+
+    SE_INLINE void premultiply(const SE_Matrix& matrix);
+    SE_INLINE void postmultiply(const SE_Matrix& matrix);
+    SE_INLINE void transform(double& x, double& y) const;
+    SE_INLINE void transform(double x, double y, double& tx, double& ty) const;
+    SE_INLINE void transformVector(double& x, double& y) const;
+    SE_INLINE void transformVector(double x, double y, double& tx, double &ty) const;
+
+    SE_INLINE void inverse(SE_Matrix& inv);
+
+    SE_INLINE void operator*=(const SE_Matrix& matrix);
+    SE_INLINE bool operator==(const SE_Matrix& matrix);
+};
+
+
+// Function definitions
+
+SE_Matrix::SE_Matrix() :
+    x0(1.0), x1(0.0), x2(0.0),
+    y0(0.0), y1(1.0), y2(0.0)
+{ }
+
+SE_Matrix::SE_Matrix( double a00, double a01, double a02,
+                      double a10, double a11, double a12) :
+    x0(a00), x1(a01), x2(a02),
+    y0(a10), y1(a11), y2(a12)
+{ }
+
+SE_Matrix::SE_Matrix(const SE_Matrix & matrix) :
+    x0(matrix.x0), x1(matrix.x1), x2(matrix.x2),
+    y0(matrix.y0), y1(matrix.y1), y2(matrix.y2)
+{ }
+
+void SE_Matrix::setIdentity()
+{
+    x0 = y1 = 1.0;
+    x1 = x2 = y0 = y2 = 0.0;
+}
+
+void SE_Matrix::setTransform(double scaleX, double scaleY, double transX, double transY)
+{
+    x0 = scaleX;
+    x1 = 0.0;
+    x2 = transX;
+
+    y0 = 0.0;
+    y1 = scaleY;
+    y2 = transY;
+}
+
+void SE_Matrix::setTransform(double scaleX, double scaleY, double transX, double transY, double rot)
+{
+    double sine = sin(rot);
+    double cosine = cos(rot);
+
+    x0 = scaleX*cosine;
+    x1 = scaleY*sine;
+    x2 = transX;
+
+    y0 = -scaleX*sine;
+    y1 = scaleY*cosine;
+    y2 = transY;
+}
+
+void SE_Matrix::scaleX(double x)
+{
+    x0 *= x;
+    x1 *= x;
+    x2 *= x;
+}
+
+void SE_Matrix::scaleY(double y)
+{
+    y0 *= y;
+    y1 *= y;
+    y2 *= y;
+}
+
+void SE_Matrix::scale(double x, double y)
+{
+    x0 *= x;
+    x1 *= x;
+    x2 *= x;
+    y0 *= y;
+    y1 *= y;
+    y2 *= y;
+}
+
+void SE_Matrix::translateX(double x)
+{
+    x2 += x;
+}
+
+void SE_Matrix::translateY(double y)
+{
+    y2 += y;
+}
+
+void SE_Matrix::translate(double x, double y)
+{
+    x2 += x;
+    y2 += y;
+}
+
+void SE_Matrix::rotate(double angle)
+{
+    double a00, a01, a02, a10, a11, a12;
+
+    double cosine = cos(angle);
+    double sine = sin(angle);
+
+    a00 = x0*cosine + y0*sine;
+    a10 = y0*cosine - x0*sine;
+
+    a01 = x1*cosine + y1*sine;
+    a11 = y1*cosine - x1*sine;
+
+    a02 = x2*cosine + y2*sine;
+    a12 = y2*cosine - x2*sine;
+
+    x0 = a00; x1 = a01; x2 = a02;
+    y0 = a10; y1 = a11; y2 = a12;
+}
+
+void SE_Matrix::premultiply(const SE_Matrix & matrix)
+{
+    double a00, a01, a02, a10, a11, a12;
+
+    a00 = x0*matrix.x0 + y0*matrix.x1;
+    a10 = x0*matrix.y0 + y0*matrix.y1;
+
+    a01 = x1*matrix.x0 + y1*matrix.x1;
+    a11 = x1*matrix.y0 + y1*matrix.y1;
+
+    a02 = x2*matrix.x0 + y2*matrix.x1 + matrix.x2;
+    a12 = x2*matrix.y0 + y2*matrix.y1 + matrix.y2;
+
+    x0 = a00; x1 = a01; x2 = a02;
+    y0 = a10; y1 = a11; y2 = a12;
+}
+
+void SE_Matrix::postmultiply(const SE_Matrix& matrix)
+{
+    double a00, a01, a02, a10, a11, a12;
+
+    a00 = x0*matrix.x0 + x1*matrix.y0;
+    a10 = y0*matrix.x0 + y1*matrix.y0;
+
+    a01 = x0*matrix.x1 + x1*matrix.y1;
+    a11 = y0*matrix.x1 + y1*matrix.y1;
+
+    a02 = x0*matrix.x2 + x1*matrix.y2 + x2;
+    a12 = y0*matrix.x2 + y1*matrix.y2 + y2;
+
+    x0 = a00; x1 = a01; x2 = a02;
+    y0 = a10; y1 = a11; y2 = a12;
+}
+
+void SE_Matrix::transform(double &x, double &y) const
+{
+    double vx = x, vy = y;
+    x = vx*x0 + vy*x1 + x2;
+    y = vx*y0 + vy*y1 + y2;
+}
+
+void SE_Matrix::transform(double x, double y, double& tx, double& ty) const
+{
+    tx = x*x0 + y*x1 + x2;
+    ty = x*y0 + y*y1 + y2;
+}
+
+void SE_Matrix::transformVector(double& x, double& y) const
+{
+    double vx = x, vy = y;
+    x = vx*x0 + vy*x1;
+    y = vx*y0 + vy*y1;
+}
+
+void SE_Matrix::transformVector(double x, double y, double& tx, double &ty) const
+{
+    tx = x*x0 + y*x1;
+    ty = x*y0 + y*y1;
+}
+
+void SE_Matrix::operator*=(const SE_Matrix & matrix)
+{
+    premultiply(matrix);
+}
+
+bool SE_Matrix::operator==(const SE_Matrix& matrix)
+{
+    return (x0 == matrix.x0 && x1 == matrix.x1 && x2 == matrix.x2 && 
+            y0 == matrix.y0 && y1 == matrix.y1 && y2 == matrix.y2);
+}
+
+void SE_Matrix::inverse(SE_Matrix& inv)
+{
+    double idet = 1.0 / (x0 * y1 - y0 * x1);
+    
+    inv.x0 = y1 * idet;
+    inv.x1 = -x1 * idet;
+    inv.y0 = -y0 * idet;
+    inv.y1 = x0 * idet;
+    inv.x2 = (y2 * x1 - x2 * y1) * idet;
+    inv.y2 = (x2 * y0 - y2 * x0) * idet;
+}
+
+#endif // SE_MATRIX_INL


Property changes on: trunk/MgDev/Common/Stylization/SE_Matrix.h
___________________________________________________________________
Name: svn:eol-style
   + native

Added: trunk/MgDev/Common/Stylization/SE_PositioningAlgorithms.cpp
===================================================================
--- trunk/MgDev/Common/Stylization/SE_PositioningAlgorithms.cpp	                        (rev 0)
+++ trunk/MgDev/Common/Stylization/SE_PositioningAlgorithms.cpp	2007-03-06 23:31:17 UTC (rev 1158)
@@ -0,0 +1,211 @@
+
+#include "stdafx.h"
+#include "SE_Include.h"
+#include "SE_PositioningAlgorithms.h"
+#include "SE_Renderer.h"
+#include "SE_Bounds.h"
+
+
+SE_RenderPointStyle* DeepClonePointStyle(SE_RenderPointStyle* st)
+{
+    SE_RenderPointStyle* ret = new SE_RenderPointStyle(); //LEAK
+    *ret = *st;
+    ret->bounds = st->bounds->Clone(); //LEAK
+    SE_RenderText* txt = new SE_RenderText(); //LEAK
+    *txt = *((SE_RenderText*)st->symbol[0]);
+    ret->symbol[0] = txt;
+
+    return ret;
+}
+
+void SE_PositioningAlgorithms::EightBall(SE_Renderer*    renderer, 
+                          SE_LineBuffer*  geometry, 
+                          SE_Matrix&      xform, 
+                          SE_Style*       style, 
+                          SE_RenderStyle* rstyle, 
+                          double          mm2px
+                          )
+{
+    //this placement algorithm implements the MapGuide dynamic point labeling algorithm 
+    //which means 8 candidate labels generated for each symbol
+    
+    double cx = 0.0;
+    double cy = 0.0;
+    double dummy;
+
+    //get actual feature point
+    geometry->Centroid(LineBuffer::ctPoint, &cx, &cy, &dummy);
+
+    //assume there is a single text label in the render symbol
+    //and extract it from in there
+    SE_RenderPointStyle* rstyle2 = new SE_RenderPointStyle(); //LEAK
+    rstyle2->addToExclusionRegions = rstyle->addToExclusionRegions;
+    rstyle2->checkExclusionRegions = rstyle->checkExclusionRegions;
+    rstyle2->drawLast = rstyle->drawLast;
+    rstyle2->renderPass = rstyle->renderPass;
+    rstyle2->bounds = rstyle->bounds->Clone();
+    SE_RenderText* txt = NULL;
+    
+    for (SE_RenderSymbol::iterator iter = rstyle->symbol.begin(); iter != rstyle->symbol.end(); iter++)
+    {
+        if ((*iter)->type == SE_TextPrimitive)
+        {
+            SE_RenderText* rt = (SE_RenderText*)(*iter);
+
+            txt = new SE_RenderText();
+            *txt = *rt;
+            rstyle2->symbol.push_back(txt);
+
+            break;
+        }
+    }
+
+    //also need to get the bounds of the last drawn point symbol, so that we know how much to offset the label
+    //TODO:
+    RS_Bounds symbol_bounds(1,1,0,0); //init to invalid
+    double symbol_width = 0.001 * 32.0 / renderer->GetPixelsPerMillimeterScreen(); //symbol width in meters
+    double symbol_height = 0.001 * 32.0 / renderer->GetPixelsPerMillimeterScreen(); //symbol height in meters
+    double symbol_rot_deg = 0.0;
+
+    double op_pts[16];
+    
+    // calculate a 2 pixel offset to allow for label ghosting
+    double offset = 0.001 * 2.0 / renderer->GetPixelsPerMillimeterScreen(); //2 pixels (in meters)
+    
+    //compute how far label needs to be offset from
+    //center point of symbol
+
+    double w = 0.5 * symbol_width;
+    double h = 0.5 * symbol_height;
+    double ch = 0;		// vertical center point
+    double cw = 0;		// horizontal center point
+
+    w += offset;
+    h += offset;
+    
+    bool useBounds = symbol_bounds.IsValid();
+    if (useBounds)
+    {
+        symbol_bounds.maxx += offset;    symbol_bounds.maxy += offset;
+        symbol_bounds.minx -= offset;    symbol_bounds.miny -= offset;
+        ch = (symbol_bounds.maxy + symbol_bounds.miny)/2.;
+        cw = (symbol_bounds.maxx + symbol_bounds.minx)/2.;
+    }
+
+    //take into account rotation of the symbol
+    //find increased extents of the symbol bounds
+    //due to the rotation
+    if (symbol_rot_deg != 0.0)
+    {
+        double rotRad = symbol_rot_deg * (M_PI/180.); //symbol_rot assumed to be in radians
+        double cs = cos(rotRad);
+        double sn = sin(rotRad);
+
+        double wcs, nwcs, wsn, nwsn, hsn, nhsn, hcs, nhcs, cwsn, cwcs, chsn, chcs;
+        // check to see if the bounds have been set
+        if (useBounds)
+        {
+            wcs = symbol_bounds.maxx * cs;   nwcs = symbol_bounds.minx * cs;
+            wsn = symbol_bounds.maxx * sn;   nwsn = symbol_bounds.minx * sn;
+            hsn = symbol_bounds.maxy * sn;   nhsn = symbol_bounds.miny * sn;
+            hcs = symbol_bounds.maxy * cs;   nhcs = symbol_bounds.miny * cs;
+        }
+        else
+        {
+            wcs = w * cs;   nwcs = -wcs;
+            wsn = w * sn;   nwsn = -wsn;
+            hsn = h * sn;   nhsn = -hsn;
+            hcs = h * cs;   nhcs = -hcs;
+        }
+       
+        cwsn = cw * sn;		chsn = ch * sn; 
+        cwcs = cw * cs;		chcs = ch * cs;
+
+        // find the octant that the marker is rotated into, and shift the points accordingly.
+        // this way, the overpost points are still within 22.5 degrees of an axis-aligned box.
+        // (position 0 will always be the closest to Center-Right)
+        double nangle = fmod(symbol_rot_deg, 360);
+        if (nangle < 0)
+            nangle += 360.;
+        int i = (((int)((nangle/45.) + .5)) << 1) & 0x0000000f; // i is 2 * the octant
+        op_pts[i++] = wcs - chsn;  op_pts[i++] = wsn + chcs;   i &= 0x0000000f; // & 15 does (mod 16)
+        op_pts[i++] = wcs - hsn;   op_pts[i++] = wsn + hcs;    i &= 0x0000000f;
+        op_pts[i++] = cwcs - hsn;  op_pts[i++] = cwsn + hcs;   i &= 0x0000000f;
+        op_pts[i++] = nwcs - hsn;  op_pts[i++] = nwsn + hcs;   i &= 0x0000000f;
+        op_pts[i++] = nwcs - chsn; op_pts[i++] = nwsn + chcs;  i &= 0x0000000f;
+        op_pts[i++] = nwcs - nhsn; op_pts[i++] = nwsn + nhcs;  i &= 0x0000000f;
+        op_pts[i++] = cwcs -nhsn;  op_pts[i++] = cwsn + nhcs;  i &= 0x0000000f;
+        op_pts[i++] = wcs - nhsn;  op_pts[i]   = wsn + nhcs;
+    }
+    else
+    {
+        if (!useBounds)
+        {
+            symbol_bounds.maxx = w;	symbol_bounds.minx = -w;
+            symbol_bounds.maxy = h;	symbol_bounds.miny = -h;
+        }
+        op_pts[0] = symbol_bounds.maxx;	op_pts[1] = ch;
+        op_pts[2] = symbol_bounds.maxx;	op_pts[3] = symbol_bounds.maxy;
+        op_pts[4] = cw;				    op_pts[5] = symbol_bounds.maxy;
+        op_pts[6] = symbol_bounds.minx;	op_pts[7] = symbol_bounds.maxy;
+        op_pts[8] = symbol_bounds.minx;	op_pts[9] = ch;
+        op_pts[10] = symbol_bounds.minx;op_pts[11] = symbol_bounds.miny;
+        op_pts[12] = cw;			    op_pts[13] = symbol_bounds.miny;
+        op_pts[14] = symbol_bounds.maxx;op_pts[15] = symbol_bounds.miny;
+    }
+
+    //OK, who says I can't write bad code? Behold:
+    SE_LabelInfo candidates[8];
+
+    SE_RenderPointStyle* st0 = DeepClonePointStyle(rstyle2);
+    ((SE_RenderText*)st0->symbol[0])->tdef.halign() = RS_HAlignment_Left;
+    ((SE_RenderText*)st0->symbol[0])->tdef.valign() = RS_VAlignment_Half;
+    candidates[0] = SE_LabelInfo(cx, cy, op_pts[0], op_pts[1], RS_Units_Device, 0.0, st0);
+
+    SE_RenderPointStyle* st1 = DeepClonePointStyle(st0);
+    ((SE_RenderText*)st1->symbol[0])->tdef.valign() = RS_VAlignment_Descent;
+    candidates[1] = SE_LabelInfo(cx, cy, op_pts[2], op_pts[3], RS_Units_Device, 0.0, st1);
+
+    SE_RenderPointStyle* st2 = DeepClonePointStyle(st1);
+    ((SE_RenderText*)st2->symbol[0])->tdef.halign() = RS_HAlignment_Center;
+    candidates[2] = SE_LabelInfo(cx, cy, op_pts[4], op_pts[5], RS_Units_Device, 0.0, st2);
+
+    SE_RenderPointStyle* st3 = DeepClonePointStyle(st2);
+    ((SE_RenderText*)st3->symbol[0])->tdef.halign() = RS_HAlignment_Right;
+    candidates[3] = SE_LabelInfo(cx, cy, op_pts[6], op_pts[7], RS_Units_Device, 0.0, st3);
+
+    SE_RenderPointStyle* st4 = DeepClonePointStyle(st3);
+    ((SE_RenderText*)st4->symbol[0])->tdef.valign() = RS_VAlignment_Half;
+    candidates[4] = SE_LabelInfo(cx, cy, op_pts[8], op_pts[9], RS_Units_Device, 0.0, st4);
+
+    SE_RenderPointStyle* st5 = DeepClonePointStyle(st4);
+    ((SE_RenderText*)st5->symbol[0])->tdef.valign() = RS_VAlignment_Ascent;
+    candidates[5] = SE_LabelInfo(cx, cy, op_pts[10], op_pts[11], RS_Units_Device, 0.0, st5);
+
+    SE_RenderPointStyle* st6 = DeepClonePointStyle(st5);
+    ((SE_RenderText*)st6->symbol[0])->tdef.halign() = RS_HAlignment_Center;
+    candidates[6] = SE_LabelInfo(cx, cy, op_pts[12], op_pts[13], RS_Units_Device, 0.0, st6);
+
+    SE_RenderPointStyle* st7 = DeepClonePointStyle(st6);
+    ((SE_RenderText*)st7->symbol[0])->tdef.halign() = RS_HAlignment_Left;
+    candidates[7] = SE_LabelInfo(cx, cy, op_pts[14], op_pts[15], RS_Units_Device, 0.0, st7);
+
+    renderer->ProcessLabelGroup(candidates, 8, RS_OverpostType_FirstFit, true, NULL);
+}
+    
+
+void SE_PositioningAlgorithms::MultipleHighwaysShields(SE_Renderer*    renderer, 
+                          SE_LineBuffer*  geometry, 
+                          SE_Matrix&      xform, 
+                          SE_Style*       style, 
+                          SE_RenderStyle* rstyle, 
+                          double          mm2px
+                          )
+{
+
+
+
+
+}
+
+


Property changes on: trunk/MgDev/Common/Stylization/SE_PositioningAlgorithms.cpp
___________________________________________________________________
Name: svn:eol-style
   + native

Added: trunk/MgDev/Common/Stylization/SE_PositioningAlgorithms.h
===================================================================
--- trunk/MgDev/Common/Stylization/SE_PositioningAlgorithms.h	                        (rev 0)
+++ trunk/MgDev/Common/Stylization/SE_PositioningAlgorithms.h	2007-03-06 23:31:17 UTC (rev 1158)
@@ -0,0 +1,38 @@
+class SE_Renderer;
+class SE_LineBuffer;
+struct SE_Matrix;
+struct SE_Style;
+struct SE_RenderStyle;
+
+
+class SE_PositioningAlgorithms
+{
+
+public:
+
+    static void EightBall(SE_Renderer*    renderer, 
+                          SE_LineBuffer*  geometry, 
+                          SE_Matrix&      xform, 
+                          SE_Style*       style, 
+                          SE_RenderStyle* rstyle, 
+                          double          mm2px
+                          );
+    
+
+    static void MultipleHighwaysShields(SE_Renderer*    renderer, 
+                          SE_LineBuffer*  geometry, 
+                          SE_Matrix&      xform, 
+                          SE_Style*       style, 
+                          SE_RenderStyle* rstyle, 
+                          double          mm2px
+                          );
+
+private:
+
+
+
+
+
+
+
+};


Property changes on: trunk/MgDev/Common/Stylization/SE_PositioningAlgorithms.h
___________________________________________________________________
Name: svn:eol-style
   + native

Added: trunk/MgDev/Common/Stylization/SE_Renderer.cpp
===================================================================
--- trunk/MgDev/Common/Stylization/SE_Renderer.cpp	                        (rev 0)
+++ trunk/MgDev/Common/Stylization/SE_Renderer.cpp	2007-03-06 23:31:17 UTC (rev 1158)
@@ -0,0 +1,198 @@
+//
+//  Copyright (C) 2007 by Autodesk, Inc.
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of version 2.1 of the GNU Lesser
+//  General Public License as published by the Free Software Foundation.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+//
+
+#include "stdafx.h"
+#include "SE_Renderer.h"
+#include "SE_LineBuffer.h"
+#include "RS_FontEngine.h"
+
+using namespace MDFMODEL_NAMESPACE;
+
+void SE_Renderer::SetLineBufferPool(SE_LineBufferPool* pool)
+{
+    m_lbp = pool;
+}
+
+void SE_Renderer::ProcessPoint(SE_LineBuffer* geometry, SE_RenderPointStyle* style)
+{
+    SE_Matrix xform;
+
+    SE_Geometry geom;
+    geom.n_pts = 1;
+    geom.n_cntrs = 0;
+    geom.geom_type = geometry->xf_geom_type();
+
+    /* Render the points */
+    for (int i = 0; i < geometry->xf_point_cnt(); i++)
+    {
+        xform.setIdentity();
+        xform.translate(geometry->xf_points()[2*i], geometry->xf_points()[2*i+1]);
+        double pt[2] = {geometry->xf_points()[2*i], geometry->xf_points()[2*i+1]};
+        geom.points = pt;
+        if (style->drawLast)
+            AddLabel(&geom, style, xform, 0);
+        else
+            DrawSymbol(style->symbol, xform, 0);
+    }
+}
+
+void SE_Renderer::ProcessLine(SE_LineBuffer* geometry, SE_RenderLineStyle* style)
+{
+    SE_Matrix xform;
+    SE_Geometry geom;
+    geom.points = geometry->xf_points();
+    geom.n_pts = geometry->xf_point_cnt();
+    geom.contours = geometry->xf_cntrs();
+    geom.n_cntrs = geometry->xf_cntr_cnt();
+    geom.geom_type = geometry->xf_geom_type();
+
+    bool yUp = GetFontEngine()->_Yup();
+    
+    int ptindex = 0;
+
+    //convert increment to pixels
+    double increment = style->repeat; //TODO: is this already scaled by the mm to pixel scale?
+
+    for (int j=0; j<geom.n_cntrs; j++)
+    {
+        //current polyline
+        int ptcount = geom.contours[j];
+        double* pts = geom.points + 2*ptindex;
+
+        //pixel position along the current segment
+        //of the polyline
+        double drawpos = style->startOffset; //position of symbol along current segment of the polyline 
+                                             //TODO: is this already scaled by the mm to pixel scale?
+
+        int cur_seg = 0;
+
+        while (cur_seg < ptcount - 1)
+        {
+            xform.setIdentity();
+
+            //current line segment
+            double* seg = pts + cur_seg * 2;
+            
+            //get length
+            double dx = seg[2] - seg[0];
+            double dy = seg[3] - seg[1];
+            double len = sqrt(dx*dx + dy*dy);
+
+            //check if completely skipping current segment since it is smaller than
+            //the increment
+            if (drawpos < len)
+            {
+                //compute linear deltas for x and y directions
+                // -- we will use these to quickly move along the line
+                //without having to do too much math
+                double dx_incr, dy_incr;
+                double slope;
+
+                slope = atan2(dy, dx);
+                dx_incr = cos(slope);
+                dy_incr = sin(slope);
+
+                xform.rotate(yUp ? slope : -slope); // negative for y-inversion
+                xform.translate(seg[0] + dx_incr * drawpos, seg[1] + dy_incr * drawpos);
+                dx_incr *= increment;
+                dy_incr *= increment;
+
+                //loop-draw the symbol along the current segment,
+                //moving along by increment pixels
+                while (drawpos < len)
+                {                    
+                    if (style->drawLast)
+                        AddLabel(&geom, style, xform, style->orientation == LineUsage::FromGeometry ? slope : style->angle);
+                    else
+                        DrawSymbol(style->symbol, xform, style->orientation == LineUsage::FromGeometry ? slope : style->angle);
+
+                    xform.translate(dx_incr, dy_incr);
+                    drawpos += increment; 
+                }
+            }
+            
+            drawpos -= len;
+            cur_seg++;
+        }
+
+        ptindex += ptcount;
+    }
+}
+
+void SE_Renderer::ProcessArea(SE_LineBuffer* /*geometry*/, SE_RenderAreaStyle* /*style*/)
+{
+}
+
+void SE_Renderer::DrawSymbol(SE_RenderSymbol& symbol, const SE_Matrix& posxform, double anglerad)
+{
+    for (unsigned i = 0; i < symbol.size(); i++)
+    {
+        SE_RenderPrimitive* primitive = symbol[i];
+
+        if (primitive->type == SE_PolygonPrimitive || primitive->type == SE_PolylinePrimitive)
+        {
+            SE_RenderPolyline* pl = (SE_RenderPolyline*)primitive;
+
+            SE_Geometry geometry;
+            pl->geometry->InstanceTransform(posxform, geometry, NULL);
+
+            if (primitive->type == SE_PolygonPrimitive)
+                DrawScreenPolygon( geometry, ((SE_RenderPolygon*)primitive)->fill );
+
+                DrawScreenPolyline( geometry, pl->color, pl->weight );
+        }
+        else if (primitive->type == SE_TextPrimitive)
+        {
+            SE_RenderText* tp = (SE_RenderText*)primitive;
+
+            //TODO take into account rotation if drawing along a line and
+            //the angle control is "from geometry"
+            double x, y;
+            posxform.transform(tp->position[0], tp->position[1], x, y);
+
+            if (anglerad != 0)
+            {
+                RS_TextDef tdef2 = tp->tdef;
+                tdef2.rotation() = anglerad * (180 / M_PI);
+                DrawScreenText(tp->text, tdef2, x, y, NULL, 0, 0.0);
+            }
+            else
+            {
+                DrawScreenText(tp->text, tp->tdef, x, y, NULL, 0, 0.0);
+            }
+        }
+        else if (primitive->type == SE_RasterPrimitive)
+        {
+            SE_RenderRaster* rp = (SE_RenderRaster*)primitive;
+
+            double x, y;
+            posxform.transform(rp->position[0], rp->position[1], x, y);
+
+            DrawScreenRaster(rp->pngPtr, rp->pngSize, RS_ImageFormat_PNG, -1, -1, x, y, rp->extent[0], rp->extent[1], anglerad * (180 / M_PI));
+        }
+     }
+}
+
+
+void SE_Renderer::AddLabel(SE_Geometry* geom, SE_RenderStyle* style, SE_Matrix& xform, double angle)
+{
+    SE_LabelInfo info(xform.x2, xform.y2, 0.0, 0.0, RS_Units_Device, angle, style);
+    
+    RS_OverpostType type = RS_OverpostType_AllFit;
+
+    ProcessLabelGroup(&info, 1, type, true /*style->addToExclusionRegions*/, geom);
+}


Property changes on: trunk/MgDev/Common/Stylization/SE_Renderer.cpp
___________________________________________________________________
Name: svn:eol-style
   + native

Added: trunk/MgDev/Common/Stylization/SE_Renderer.h
===================================================================
--- trunk/MgDev/Common/Stylization/SE_Renderer.h	                        (rev 0)
+++ trunk/MgDev/Common/Stylization/SE_Renderer.h	2007-03-06 23:31:17 UTC (rev 1158)
@@ -0,0 +1,66 @@
+//
+//  Copyright (C) 2007 by Autodesk, Inc.
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of version 2.1 of the GNU Lesser
+//  General Public License as published by the Free Software Foundation.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+//
+
+#ifndef SE_RENDERER_H
+#define SE_RENDERER_H
+
+#include "SE_Include.h"
+
+class RS_FontEngine;
+
+class SE_Renderer
+{
+public:
+    void SetLineBufferPool(SE_LineBufferPool* pool);
+    /* SE_RenderSymbol, under associated xform, is in screen space, and geometry is in screen space */
+    virtual void ProcessPoint(SE_LineBuffer* geometry, SE_RenderPointStyle* style);
+    virtual void ProcessLine(SE_LineBuffer* geometry, SE_RenderLineStyle* style);
+    virtual void ProcessArea(SE_LineBuffer* geometry, SE_RenderAreaStyle* style);
+
+    virtual void DrawSymbol(SE_RenderSymbol& symbol, const SE_Matrix& xform, double anglerad);
+
+    virtual void DrawScreenPolyline(SE_Geometry& polyline, unsigned int color, double weight) = 0; // px
+    virtual void DrawScreenPolygon(SE_Geometry& polygon, unsigned int fill) = 0;
+    virtual void DrawScreenRaster(unsigned char* data, int length, RS_ImageFormat format, int native_width, int native_height, 
+        double x, double y, double w, double h, double angledeg) = 0;
+    virtual void DrawScreenText(const RS_String& txt, RS_TextDef& tdef, double insx, double insy, double* path, int npts, double param_position) = 0;
+
+    virtual void GetWorldToScreenTransform(SE_Matrix& xform) = 0;
+    virtual void WorldToScreenPoint(double& inx, double& iny, double& ox, double& oy) = 0;
+    virtual void ScreenToWorldPoint(double& inx, double& iny, double& ox, double& oy) = 0;
+
+    virtual double GetPixelsPerMillimeterScreen() = 0;
+    virtual double GetPixelsPerMillimeterWorld() = 0;
+
+    virtual RS_FontEngine* GetFontEngine() = 0;
+
+    //labeling -- this is the entry API for adding SE labels
+    //to the label mananger
+    virtual void ProcessLabelGroup(SE_LabelInfo*    labels,
+                                   int              nlabels,
+                                   RS_OverpostType  type,
+                                   bool             exclude,
+                                   SE_Geometry*     path = NULL) = 0;
+
+private:
+    void AddLabel(SE_Geometry* geom, SE_RenderStyle* style, SE_Matrix& xform, double angle);
+
+protected:
+    SE_LineBufferPool* m_lbp;
+};
+
+#endif // SE_RENDERER_H


Property changes on: trunk/MgDev/Common/Stylization/SE_Renderer.h
___________________________________________________________________
Name: svn:eol-style
   + native

Added: trunk/MgDev/Common/Stylization/SE_StyleVisitor.cpp
===================================================================
--- trunk/MgDev/Common/Stylization/SE_StyleVisitor.cpp	                        (rev 0)
+++ trunk/MgDev/Common/Stylization/SE_StyleVisitor.cpp	2007-03-06 23:31:17 UTC (rev 1158)
@@ -0,0 +1,593 @@
+//
+//  Copyright (C) 2007 by Autodesk, Inc.
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of version 2.1 of the GNU Lesser
+//  General Public License as published by the Free Software Foundation.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+//
+
+#include "stdafx.h"
+#include "StylizationEngine.h"
+#include "SE_StyleVisitor.h"
+#include "SE_SymbolManager.h"
+#include "SE_LineBuffer.h"
+
+#define _USE_MATH_DEFINES
+#include <math.h>
+#include <wctype.h>
+
+using namespace MDFMODEL_NAMESPACE;
+
+#define SMALL_ANGLE(s,e) ((s) < M_PI ? ((e) >= (s)) && ((e) < M_PI + (s)) : ((e) >= (s)) || ((s) < (s) - M_PI))
+
+struct ArcDefinition
+{
+    double x0, y0, x1, y1;
+    double rx, ry;
+    double rotation;
+    bool largeArc, clockwise;
+};
+
+struct ArcData
+{
+    double cx, cy;
+    double startAng, endAng;
+    double rotation;
+};
+
+bool ParseArc(ArcDefinition& def, ArcData& data);
+
+SE_StyleVisitor::SE_StyleVisitor(SE_SymbolManager* resources, SE_LineBufferPool* lbp)
+{
+    m_resources = resources;
+    m_lbp = lbp;
+    m_primitive = NULL;
+}
+
+void SE_StyleVisitor::VisitPointUsage(PointUsage& pntRpt)
+{
+    SE_PointStyle* style = new SE_PointStyle();
+    m_style = style;
+    ParseDoubleExpression(pntRpt.GetAngle(), style->angle);
+    ParseDoubleExpression(pntRpt.GetOriginOffsetX(), style->offset[0]);
+    ParseDoubleExpression(pntRpt.GetOriginOffsetY(), style->offset[1]);
+    style->orientation = pntRpt.GetAngleControl();
+}
+
+void SE_StyleVisitor::VisitLineUsage(LineUsage& lnRpt)
+{
+    SE_LineStyle* style = new SE_LineStyle();
+    m_style = style;
+    ParseDoubleExpression(lnRpt.GetStartOffset(), style->startOffset);
+    ParseDoubleExpression(lnRpt.GetEndOffset(), style->endOffset);
+    ParseDoubleExpression(lnRpt.GetRepeat(), style->repeat);
+    ParseDoubleExpression(lnRpt.GetAngle(), style->angle);
+    ParseDoubleExpression(lnRpt.GetVertexAngleLimit(), style->angleLimit);
+}
+
+void SE_StyleVisitor::VisitAreaUsage(AreaUsage& areaRpt)
+{
+    SE_AreaStyle* style = new SE_AreaStyle();
+    m_style = style;
+    ParseDoubleExpression(areaRpt.GetAngle(), style->angle);
+    ParseDoubleExpression(areaRpt.GetOriginX(), style->origin[0]);
+    ParseDoubleExpression(areaRpt.GetOriginY(), style->origin[1]);
+    ParseDoubleExpression(areaRpt.GetRepeatX(), style->repeat[0]);
+    ParseDoubleExpression(areaRpt.GetRepeatY(), style->repeat[1]);
+    ParseDoubleExpression(areaRpt.GetBufferWidth(), style->bufferWidth);
+}
+
+bool SE_StyleVisitor::ParseDouble(const wchar_t*& str, double& val)
+{
+    size_t length;
+    swscanf(str, L" %lf %n", &val, &length);
+    str += length;
+    return length > 0;
+}
+
+bool SE_StyleVisitor::ParseDoublePair(const wchar_t*& str, double& x, double& y)
+{
+    size_t length;
+    swscanf(str, L" %lf , %lf %n", &x, &y, &length);
+    str += length;
+    return length > 0;
+}
+
+bool SE_StyleVisitor::ParseGeometry(const MdfString& geometry, SE_LineBuffer& buffer)
+{
+    const wchar_t* data = geometry.c_str();
+    const wchar_t* end = data + geometry.size();
+
+    double x, y;
+    double lx = 0.0, ly = 0.0;
+    double sx, sy, rx, ry, rot, large, cw;
+
+    SE_LineBuffer* lb = &buffer;
+    
+    wchar_t tag, ptag = 0;
+
+    for (;data < end; )
+    {
+        if (iswspace(*data))
+        {
+            data++;
+            continue;
+        }
+        
+        tag = *data++;
+
+TagSwitch:
+        switch(tag)
+        {
+        case L'm': // Move relative x,y
+            if (lb->Empty() || !ParseDoublePair(data, x, y))
+                return false;
+            lx += x;
+            ly += y;
+            lb->MoveTo(lx, ly);
+            break;
+        case L'M': // Move absolute x,y
+            if (!ParseDoublePair(data, lx, ly))
+                return false;
+            lb->MoveTo(lx, ly);
+            break;
+        case L'l': // Line relative x,y
+            if (lb->Empty() || !ParseDoublePair(data, x, y))
+                return false;
+            lx += x;
+            ly += y;
+            lb->LineTo(lx,ly);
+            break;
+        case L'L': // Line absolute x,y
+            if (!ParseDoublePair(data, lx, ly))
+                return false;
+            lb->LineTo(lx, ly);
+            break;
+        case L'h': // Horizontal line relative x
+            if (lb->Empty() || !ParseDouble(data, x))
+                return false;
+            lx += x;
+            lb->LineTo(lx, ly);
+            break;
+        case L'H': // Horizontal line absolute x
+            if (!ParseDouble(data, lx))
+                return false;
+            lb->LineTo(lx, ly);
+            break;
+        case L'v': // Vertical line relative y
+            if (lb->Empty() || !ParseDouble(data, y))
+                return false;
+            ly += y;
+            lb->LineTo(lx, ly);
+            break;
+        case L'V': // Vertical line absolute y
+            if (!ParseDouble(data, ly))
+                return false;
+            lb->LineTo(lx, ly);
+            break;
+        case L'a': // Arc segment relative (rx,ry rotation arc,sweep x,y)
+            if (lb->Empty())
+                return false;
+        case L'A': // Arc segment absolute (rx,ry rotation isLarge isclockwise x,y)
+            if (!ParseDoublePair(data, rx, ry))
+                return false;
+            if (!ParseDouble(data, rot))
+                return false;
+            if (!ParseDouble(data, large))
+                return false;
+            if (!ParseDouble(data, cw))
+                return false;
+            if (!ParseDoublePair(data, x, y))
+                return false;
+            
+            sx = lx;
+            sy = ly;
+
+            if (tag == 'a')
+            {
+                lx += x;
+                ly += y;
+            }
+            else
+            {
+                lx = x;
+                ly = y;
+            }
+    
+            if (rx == 0 || ry == 0)
+            {
+                lb->LineTo(lx, ly);
+                break;
+            }
+
+            ArcDefinition arcdef;
+            ArcData arcdata;
+            arcdef.x0 = sx; arcdef.y0 = sy;
+            arcdef.x1 = lx; arcdef.y1 = ly;
+            arcdef.rx = rx; arcdef.ry = ry;
+            arcdef.clockwise = cw != 0; arcdef.largeArc = large != 0;
+            arcdef.rotation = rot;
+            if (!ParseArc(arcdef, arcdata))
+                return false;
+
+            lb->EllipticalArcTo(arcdata.cx, arcdata.cy, arcdef.rx, arcdef.ry, arcdata.startAng, arcdata.endAng, arcdata.rotation);
+            break;
+        case L'z': // Line segment to start point of figure
+        case L'Z':
+            lb->Close();
+            break;
+        // Instead of another tag, more data representing another record of the same type
+        default:
+            if (ptag == 0)
+                return false;
+            data--;
+            tag = ptag;
+            goto TagSwitch;
+        }
+        ptag = tag;
+    }
+    
+    return true;
+}
+
+bool ParseArc(ArcDefinition& def, ArcData& data)
+{
+    double x0 = def.x0, y0 = def.y0;
+    double x1 = def.x1, y1 = def.y1;
+    double rx = def.rx, ry = def.ry;
+    double rotrad = 0.0;
+
+    if (def.rotation != 0.0)
+    {
+        rotrad = def.rotation*M_PI/180.0;
+        /* Derotate the points, so we can handle only the axis-oriented case */
+        double sine = sin(-rotrad);
+        double cosine = cos(-rotrad);
+        x0 = def.x0*cosine + def.y0*sine;
+        y0 = def.y0*cosine - def.x0*sine;
+        x1 = def.x1*cosine + def.y1*sine;
+        y1 = def.y1*cosine - def.x1*sine;
+    }
+
+    /* Laboriously calculate center */
+    double x02 = x0*x0;
+    double x12 = x1*x1;
+    double x012 = x02 - x12;
+    double rx2 = rx*rx;
+    double ry2 = ry*ry;
+    double rxy2 = rx2*ry2;
+    double rx4 = rx2*rx2;
+    double ry4 = ry2*ry2;
+    double dx = (x0-x1);
+    double dx2 = dx*dx;
+    double dy = (y0-y1);
+    double sy = (y0+y1);
+    double dy2 = dy*dy;
+
+    /* Solution to system of equations {(x0 - cx)^2/a^2 + (y0 - cy)^2/b^2 = 1,
+                                        (x1 - cx)^2/a^2 + (y1 - cy)^2/b^2 = 1}
+       verified with Mathematica. */
+
+    double a = 2*(ry2*dx2 + rx2*dy2);
+    double ay = rx2*a;
+    double ax = ry2*dx*a;
+    double sq = sqrt(rxy2*dx2*(-ry4*dx2*dx2 + 2*rxy2*dx2*(2*ry2 - dy2) - rx2*rx2*dy2*(-4*ry2 + dy2)));
+    double sqy = sq;
+    double sqx = (y1-y0)*sq;
+    double mby = rxy2*sy*dx2 + rx4*dy2*sy;
+    double mbx = rxy2*x012*dy2 + ry4*dx2*x012;
+
+    double cx0, cx1, cy0, cy1;
+
+    if (ax == 0)
+    {
+        //x0 equal to x1 -- vertical chord
+        cx0 = x0;
+        cx1 = x1;        
+    }
+    else
+    {
+        cx0 = (mbx + sqx)/ax;
+        cx1 = (mbx - sqx)/ax;
+    }
+
+    if (ay == 0)
+    {
+        //this means that y0 and y1 were equal so chord is horizontal
+        cy0 = y0;
+        cy1 = y1;
+    }
+    else
+    {
+        cy0 = (mby + sqy)/ay;
+        cy1 = (mby - sqy)/ay;
+    }
+
+    double sAng = atan2(y0-cy0, x0-cx0);
+    if (sAng < 0)
+        sAng += 2*M_PI;
+    double eAng = atan2(y1-cy0, x1-cx0);
+    if (eAng < 0)
+        eAng += 2*M_PI;
+
+    /* TODO: scale radii until properly specified instead of failing */
+    if (!_finite(cx0) || _isnan(cx0) || 
+        !_finite(cx1) || _isnan(cx1) || 
+        !_finite(cy0) || _isnan(cy0) ||
+        !_finite(cy1) || _isnan(cy1))
+        return false;
+
+
+    double cx = cx0, cy = cy0;
+    bool small = SMALL_ANGLE(sAng, eAng);
+    if ((small && !def.clockwise && def.largeArc) || (small && def.clockwise && !def.largeArc)) // reject
+    {
+        cx = cx1, cy = cy1;
+        sAng = atan2(y0-cy0, x0-cx1);
+        if (sAng < 0)
+            sAng += 2*M_PI;
+        eAng = atan2(y1-cy1, x1-cx1);
+        if (eAng < 0)
+            eAng += 2*M_PI;
+    }
+
+    if (def.clockwise)
+    {
+        double temp = sAng;
+        sAng = eAng;
+        eAng = temp;
+    }
+
+    if (eAng < sAng)
+        eAng += 2*M_PI;
+
+    if (def.rotation != 0)
+    {
+        /* Rerotate the center */
+        double tcx = cx, tcy = cy;
+        double sine = sin(rotrad);
+        double cosine = cos(rotrad);
+        cx = tcx*cosine + tcy*sine;
+        cy = tcy*cosine - tcx*sine;
+    }
+
+    data.cx = cx; data.cy = cy;
+    data.endAng = eAng; data.startAng = sAng;
+    return true;
+}
+
+void SE_StyleVisitor::VisitPath(Path& path)
+{
+    SE_Color color;
+    const MdfString& geometry = path.GetGeometry();
+
+    ParseColorExpression(path.GetFillColor(), color);
+
+    if (m_primitive)
+        delete m_primitive;
+
+    if (color.empty())
+    {
+        SE_Polyline* line = new SE_Polyline();
+        m_primitive = line;
+        line->geometry = m_lbp->NewLineBuffer(4);
+        ParseGeometry(geometry, *line->geometry);
+        ParseDoubleExpression(path.GetLineWeight(), line->weight);
+        ParseColorExpression(path.GetLineColor(), line->color);
+        /* If the color is transparent, there is no point in drawing this path,
+         * so we will change it to black. */
+        if (line->color.argb() == 0)
+            line->color.a = 255;
+        line->cacheable = !(line->weight.expression || 
+                            line->color.expression);
+    }
+    else
+    {
+        SE_Polygon* polygon = new SE_Polygon();
+        m_primitive = polygon;
+        polygon->geometry = m_lbp->NewLineBuffer(4);
+        ParseGeometry(geometry, *polygon->geometry);
+        ParseDoubleExpression(path.GetLineWeight(), polygon->weight);
+        polygon->fill = color;
+        ParseColorExpression(path.GetLineColor(), polygon->color);
+        polygon->cacheable = !(polygon->weight.expression || 
+                            polygon->color.expression || 
+                            polygon->fill.expression);
+    }
+}
+
+void SE_StyleVisitor::VisitImage(Image& image)
+{
+    SE_Raster* primitive = new SE_Raster();
+    m_primitive = primitive;
+    
+    if (image.GetContent().size())
+    {
+        /* Handle this; Base64 as MdfString is not a particularly inspired plan */
+        primitive->pngPtr = NULL;
+    }
+    else
+    {
+        //TODO: Disallow expressions for now since 
+        //ParseStringExpression(image.GetReference(), primitive->pngPath);
+        primitive->pngPath.value = image.GetReference().c_str();
+        primitive->pngPath.expression = NULL;
+
+        if (primitive->pngPath.expression == NULL) // constant path
+            primitive->pngPtr = m_resources->GetImageData(image.GetReference().c_str(), primitive->pngSize);
+        else
+            primitive->pngPtr = NULL;
+    }
+
+    ParseDoubleExpression(image.GetPositionX(), primitive->position[0]);
+    ParseDoubleExpression(image.GetPositionY(), primitive->position[1]);
+    ParseDoubleExpression(image.GetSizeX(), primitive->extent[0]);
+    ParseDoubleExpression(image.GetSizeY(), primitive->extent[1]);
+    ParseDoubleExpression(image.GetAngle(), primitive->angle);
+
+    primitive->cacheable = !(primitive->position[0].expression ||
+                             primitive->position[1].expression ||
+                             primitive->extent[0].expression ||
+                             primitive->extent[1].expression ||
+                             primitive->angle.expression) && primitive->pngPtr;
+}
+
+void SE_StyleVisitor::VisitText(Text& text)
+{
+    SE_Text* primitive = new SE_Text();
+    m_primitive = primitive;
+
+    ParseStringExpression(text.GetString(), primitive->textExpr);
+    ParseStringExpression(text.GetFontName(), primitive->fontExpr);
+    ParseDoubleExpression(text.GetHeight(), primitive->size);
+    ParseDoubleExpression(text.GetAngle(), primitive->angle);
+    ParseDoubleExpression(text.GetPositionX(), primitive->position[0]);
+    ParseDoubleExpression(text.GetPositionY(), primitive->position[1]);
+    ParseDoubleExpression(text.GetLineSpacing(), primitive->lineSpacing);
+    ParseBooleanExpression(text.GetUnderlined(), primitive->underlined);
+    ParseBooleanExpression(text.GetBold(), primitive->bold);
+    ParseBooleanExpression(text.GetItalic(), primitive->italic);
+    ParseColorExpression(text.GetTextColor(), primitive->textColor);
+    ParseColorExpression(text.GetGhostColor(), primitive->ghostColor);
+    ParseStringExpression(text.GetHorizontalAlignment(), primitive->hAlignment);
+    ParseStringExpression(text.GetVerticalAlignment(), primitive->vAlignment);
+    ParseStringExpression(text.GetJustification(), primitive->justification);
+
+    primitive->cacheable = !(primitive->textExpr.expression ||
+                             primitive->fontExpr.expression ||
+                             primitive->size.expression ||
+                             primitive->angle.expression ||
+                             primitive->position[0].expression ||
+                             primitive->position[1].expression ||
+                             primitive->lineSpacing.expression ||
+                             primitive->underlined.expression ||
+                             primitive->bold.expression ||
+                             primitive->italic.expression ||
+                             primitive->textColor.expression ||
+                             primitive->ghostColor.expression ||
+                             primitive->hAlignment.expression ||
+                             primitive->vAlignment.expression ||
+                             primitive->justification.expression);
+}
+
+void SE_StyleVisitor::VisitSimpleSymbolDefinition(MdfModel::SimpleSymbolDefinition& simpleSymbol)
+{
+    m_style = NULL;
+
+    SetDefaultValues(&simpleSymbol);
+
+    // TODO - We need a hint that says what feature geometry type we're
+    //        working with, so that we can get the relevant usage.  For
+    //        just keep the first non-NULL usage we find.
+    Usage* usage = simpleSymbol.GetPointUsage();
+    if (usage == NULL)
+        usage = simpleSymbol.GetLineUsage();
+    if (usage == NULL)
+        usage = simpleSymbol.GetAreaUsage();
+    if (usage == NULL)
+        return;
+
+    usage->AcceptVisitor(*this);
+
+    GraphicElementCollection* graphics = simpleSymbol.GetGraphics();
+
+    int count = graphics->GetCount();
+    for (int i = 0; i < count; i++)
+    {
+        GraphicElement* elem = graphics->GetAt(i);
+        elem->AcceptVisitor(*this);
+        
+        if (m_primitive)
+        {
+            m_primitive->resize = elem->GetResizeControl();
+            m_style->symbol.push_back(m_primitive);
+        }
+
+        m_primitive = NULL;
+    }
+
+    ResizeBox* box = simpleSymbol.GetResizeBox();
+    m_style->useBox = box != NULL;
+    if (m_style->useBox)
+    {
+        ParseDoubleExpression(box->GetSizeX(), m_style->resizeSize[0]);
+        ParseDoubleExpression(box->GetSizeY(), m_style->resizeSize[1]);
+        ParseDoubleExpression(box->GetPositionX(), m_style->resizePosition[0]);
+        ParseDoubleExpression(box->GetPositionY(), m_style->resizePosition[1]);
+        m_style->resize = box->GetGrowControl();
+    }
+
+    m_symbolization->styles.push_back(m_style);
+}
+
+void SE_StyleVisitor::VisitCompoundSymbolDefinition(MdfModel::CompoundSymbolDefinition& compoundSymbol)
+{
+    SimpleSymbolCollection* symbols = compoundSymbol.GetSymbols();
+    int len = symbols->GetCount();
+    for (int i = 0; i < len; i++)
+    {
+        SimpleSymbol* sym = symbols->GetAt(i);
+        SimpleSymbolDefinition* def = sym->GetSymbolDefinition();
+        const MdfString& ref = sym->GetSymbolReference();
+
+        if (def == NULL)
+        {
+            def = dynamic_cast<SimpleSymbolDefinition*>(m_resources->GetSymbolDefinition(ref.c_str()));        
+            if (def == NULL)
+                return;
+        }
+        
+        VisitSimpleSymbolDefinition(*def);
+
+        if (m_style)
+            ParseIntegerExpression(sym->GetRenderingPass(), m_style->renderPass);
+    }
+}
+
+void SE_StyleVisitor::Convert(std::vector<SE_Symbolization*>& result, MdfModel::CompositeSymbolization* symbolization)
+{
+    if (symbolization == NULL)
+        return;
+
+    SetParameterValues(symbolization->GetParameterOverrides());
+
+    SymbolInstanceCollection* symbols = symbolization->GetSymbolCollection();
+    int nSymbols = symbols->GetCount();
+
+    for (int i = 0; i < nSymbols; i++)
+    {
+        SymbolInstance* instance = symbols->GetAt(i);
+        SymbolDefinition* sd = m_resources->GetSymbolDefinition(instance->GetSymbolReference().c_str());
+        if (sd == NULL)
+            continue;
+
+        m_symbolization = new SE_Symbolization;
+
+        m_symbolization->context = instance->GetSizeContext();
+        
+        ParseBooleanExpression(instance->GetDrawLast(), m_symbolization->drawLast);
+        ParseBooleanExpression(instance->GetAddToExclusionRegion(), m_symbolization->addToExclusionRegions);
+        ParseBooleanExpression(instance->GetCheckExclusionRegion(), m_symbolization->checkExclusionRegions);
+
+        if (!instance->GetPositioningAlgorithm().empty())
+            m_symbolization->positioningAlgorithm = instance->GetPositioningAlgorithm();
+        
+        ParseDoubleExpression(instance->GetScaleX(), m_symbolization->scale[0]);
+        ParseDoubleExpression(instance->GetScaleY(), m_symbolization->scale[1]);
+        ParseDoubleExpression(instance->GetInsertionOffsetX(), m_symbolization->absOffset[0]);
+        ParseDoubleExpression(instance->GetInsertionOffsetY(), m_symbolization->absOffset[1]);
+
+        sd->AcceptVisitor(*this);
+
+        result.push_back(m_symbolization);
+    }
+}


Property changes on: trunk/MgDev/Common/Stylization/SE_StyleVisitor.cpp
___________________________________________________________________
Name: svn:eol-style
   + native

Added: trunk/MgDev/Common/Stylization/SE_StyleVisitor.h
===================================================================
--- trunk/MgDev/Common/Stylization/SE_StyleVisitor.h	                        (rev 0)
+++ trunk/MgDev/Common/Stylization/SE_StyleVisitor.h	2007-03-06 23:31:17 UTC (rev 1158)
@@ -0,0 +1,77 @@
+//
+//  Copyright (C) 2007 by Autodesk, Inc.
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of version 2.1 of the GNU Lesser
+//  General Public License as published by the Free Software Foundation.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+//
+
+#ifndef SE_STYLEVISITOR_H
+#define SE_STYLEVISITOR_H
+
+#include "SE_ExpressionBase.h"
+#include "IUsageVisitor.h"
+#include "IGraphicElementVisitor.h"
+#include "ISymbolDefinitionVisitor.h"
+
+class SE_SymbolManager;
+class SE_LineBuffer;
+class SE_LineBufferPool;
+struct SE_Style;
+struct SE_RenderStyle;
+struct SE_Primitive;
+struct SE_RenderPrimitive;
+struct SE_Symbolization;
+struct SE_Matrix;
+
+namespace MDFMODEL_NAMESPACE
+{
+    class CompositeSymbolization;
+    class SimpleSymbolDefinition;
+    class CompoundSymbolDefinition;
+}
+
+class SE_StyleVisitor : public MdfModel::IUsageVisitor, public MdfModel::IGraphicElementVisitor, public MdfModel::ISymbolDefinitionVisitor, private SE_ExpressionBase
+{
+public:
+    SE_StyleVisitor(SE_SymbolManager* resources, SE_LineBufferPool* lbp);
+
+    /* IUsageVisitor */
+    virtual void VisitPointUsage(MdfModel::PointUsage& pntRpt);
+    virtual void VisitLineUsage(MdfModel::LineUsage& lnRpt);
+    virtual void VisitAreaUsage(MdfModel::AreaUsage& areaRpt);
+
+    /* IGraphicElementVisitor */
+    virtual void VisitPath(MdfModel::Path& path);
+    virtual void VisitImage(MdfModel::Image&);
+    virtual void VisitText(MdfModel::Text&);
+
+    /* ISymbolDefinitionVisitor */
+    virtual void VisitSimpleSymbolDefinition(MdfModel::SimpleSymbolDefinition& simpleSymbol);
+    virtual void VisitCompoundSymbolDefinition(MdfModel::CompoundSymbolDefinition& compoundSymbol);
+
+    void Convert(std::vector<SE_Symbolization*>& styles, MdfModel::CompositeSymbolization* symbolization);
+private:
+    SE_Style* ParseSymbol(MdfModel::CompoundSymbolDefinition* symbol);
+    void ParseSymbol(SimpleSymbolDefinition* symbol, SE_Matrix& xform, SE_Symbol* primitives, SE_RenderSymbol* renderPrimitives);
+    bool ParseDouble(const wchar_t*& str, double& val);
+    bool ParseDoublePair(const wchar_t*& str, double& x, double& y);
+    bool ParseGeometry(const MdfModel::MdfString& geometry, SE_LineBuffer& buffer);
+
+    SE_SymbolManager* m_resources;
+    SE_LineBufferPool* m_lbp;
+    SE_Symbolization* m_symbolization;
+    SE_Style* m_style;
+    SE_Primitive* m_primitive;
+};
+
+#endif // SE_STYLEVISITOR_H


Property changes on: trunk/MgDev/Common/Stylization/SE_StyleVisitor.h
___________________________________________________________________
Name: svn:eol-style
   + native

Added: trunk/MgDev/Common/Stylization/SE_SymbolManager.h
===================================================================
--- trunk/MgDev/Common/Stylization/SE_SymbolManager.h	                        (rev 0)
+++ trunk/MgDev/Common/Stylization/SE_SymbolManager.h	2007-03-06 23:31:17 UTC (rev 1158)
@@ -0,0 +1,33 @@
+//
+//  Copyright (C) 2007 by Autodesk, Inc.
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of version 2.1 of the GNU Lesser
+//  General Public License as published by the Free Software Foundation.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+//
+
+#ifndef SE_SYMBOLMANAGER_H
+#define SE_SYMBOLMANAGER_H
+
+namespace MdfModel
+{
+    class SymbolDefinition;
+};
+
+class SE_SymbolManager
+{
+public:
+    virtual MdfModel::SymbolDefinition* GetSymbolDefinition(const wchar_t* resource) = 0;
+    virtual unsigned char* GetImageData(const wchar_t* resource, int& length) = 0;
+};
+
+#endif


Property changes on: trunk/MgDev/Common/Stylization/SE_SymbolManager.h
___________________________________________________________________
Name: svn:eol-style
   + native

Modified: trunk/MgDev/Common/Stylization/SimpleOverpost.cpp
===================================================================
--- trunk/MgDev/Common/Stylization/SimpleOverpost.cpp	2007-03-06 17:02:52 UTC (rev 1157)
+++ trunk/MgDev/Common/Stylization/SimpleOverpost.cpp	2007-03-06 23:31:17 UTC (rev 1158)
@@ -25,8 +25,11 @@
 }
 
 
-bool SimpleOverpost::Overlaps(RS_Bounds& b)
+bool SimpleOverpost::Overlaps(RS_F_Point* pts, int npts)
 {
+    RS_Bounds b;
+    ComputeBounds(pts, npts, b);
+
     //look if the bounds overlaps current overpost regions
     for (size_t i=0; i<m_excludes.size(); i++)
     {
@@ -39,8 +42,11 @@
 }
 
 
-void SimpleOverpost::AddRegion(RS_Bounds& b)
+void SimpleOverpost::AddRegion(RS_F_Point* pts, int npts)
 {
+    RS_Bounds b;
+    ComputeBounds(pts, npts, b);
+
     m_excludes.push_back(b);
 }
 
@@ -55,3 +61,18 @@
 {
     m_excludes.clear();
 }
+
+
+//////////////////////////////////////////////////////////////////////////////
+//computes axis aligned bounds of a point set
+void SimpleOverpost::ComputeBounds(RS_F_Point* RESTRICT pts, int npts, RS_Bounds& b)
+{
+    if (!npts)
+        return;
+
+    b.minx = b.maxx = pts[0].x;
+    b.miny = b.maxy = pts[0].y;
+
+    for (int i=1; i<npts; i++)
+        b.add_point(pts[i]);
+}

Modified: trunk/MgDev/Common/Stylization/SimpleOverpost.h
===================================================================
--- trunk/MgDev/Common/Stylization/SimpleOverpost.h	2007-03-06 17:02:52 UTC (rev 1157)
+++ trunk/MgDev/Common/Stylization/SimpleOverpost.h	2007-03-06 23:31:17 UTC (rev 1158)
@@ -25,16 +25,17 @@
 //a given region overlaps existing overpost/exclusion regions
 class SimpleOverpost
 {
-
 public:
     ~SimpleOverpost();
 
-    bool Overlaps(RS_Bounds& b);
-    void AddRegion(RS_Bounds& b);
+    bool Overlaps(RS_F_Point* pts, int npts);
+    void AddRegion(RS_F_Point* pts, int npts);
     void AddRegions(SimpleOverpost& mgr);
     void Clear();
 
 private:
+    void ComputeBounds(RS_F_Point* RESTRICT pts, int npts, RS_Bounds& b);
+
     std::vector<RS_Bounds> m_excludes;
 };
 

Modified: trunk/MgDev/Common/Stylization/Stylization.h
===================================================================
--- trunk/MgDev/Common/Stylization/Stylization.h	2007-03-06 17:02:52 UTC (rev 1157)
+++ trunk/MgDev/Common/Stylization/Stylization.h	2007-03-06 23:31:17 UTC (rev 1158)
@@ -51,6 +51,7 @@
 #include "LineTypeStyle.h"
 #include "AreaTypeStyle.h"
 #include "PointTypeStyle.h"
+#include "CompositeTypeStyle.h"
 
 #include "AreaRule.h"
 #include "LineRule.h"
@@ -67,7 +68,19 @@
 #include "MarkSymbol.h"
 #include "FontSymbol.h"
 #include "ImageSymbol.h"
+#include "SimpleSymbolDefinition.h"
+#include "CompoundSymbolDefinition.h"
 #include "ISymbolVisitor.h"
+#include "IUsageVisitor.h"
+#include "ISymbolDefinitionVisitor.h"
+#include "IGraphicElementVisitor.h"
+#include "CompositeSymbolization.h"
+#include "PointUsage.h"
+#include "LineUsage.h"
+#include "AreaUsage.h"
+#include "Path.h"
+#include "Text.h"
+#include "Image.h"
 
 //FDO headers
 #include "Fdo.h"

Modified: trunk/MgDev/Common/Stylization/Stylization.vcproj
===================================================================
--- trunk/MgDev/Common/Stylization/Stylization.vcproj	2007-03-06 17:02:52 UTC (rev 1157)
+++ trunk/MgDev/Common/Stylization/Stylization.vcproj	2007-03-06 23:31:17 UTC (rev 1158)
@@ -128,7 +128,7 @@
 				InlineFunctionExpansion="2"
 				EnableIntrinsicFunctions="true"
 				FavorSizeOrSpeed="1"
-				OmitFramePointers="true"
+				OmitFramePointers="false"
 				AdditionalIncludeDirectories="..\..\Oem\DWFTK7.1\develop\global\src;..\..\Oem\DWFTK7.1\develop\global\src\dwf;..\..\Oem\DWFTK7.1\develop\global\src\dwfemap;..\..\Oem\FDO\inc;..\..\Oem\gd\gd;..\MdfModel;..\..\Oem\gd\freetype\include;..\..\Oem\gd\lpng;..\..\Oem\gd\zlib"
 				PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;STYLIZATION_EXPORTS;DWFTK_USE_DWFCORE_ZLIB;DWFTK_BUILD_EXPAT;DWFCORE_STATIC;DWFTK_STATIC;WHIP_STATIC_LIB;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE"
 				ExceptionHandling="2"
@@ -385,14 +385,6 @@
 				>
 			</File>
 			<File
-				RelativePath=".\FontManager.cpp"
-				>
-			</File>
-			<File
-				RelativePath=".\FontManager.h"
-				>
-			</File>
-			<File
 				RelativePath=".\GDFillPatterns.cpp"
 				>
 			</File>
@@ -661,6 +653,102 @@
 				>
 			</File>
 		</Filter>
+		<Filter
+			Name="StyleEngine"
+			>
+			<File
+				RelativePath=".\SE_Bounds.cpp"
+				>
+			</File>
+			<File
+				RelativePath=".\SE_Bounds.h"
+				>
+			</File>
+			<File
+				RelativePath=".\SE_ConvexHull.h"
+				>
+			</File>
+			<File
+				RelativePath=".\SE_ExpressionBase.cpp"
+				>
+			</File>
+			<File
+				RelativePath=".\SE_ExpressionBase.h"
+				>
+			</File>
+			<File
+				RelativePath=".\SE_Include.h"
+				>
+			</File>
+			<File
+				RelativePath=".\SE_LineBuffer.cpp"
+				>
+			</File>
+			<File
+				RelativePath=".\SE_LineBuffer.h"
+				>
+			</File>
+			<File
+				RelativePath=".\SE_Matrix.h"
+				>
+			</File>
+			<File
+				RelativePath=".\SE_PositioningAlgorithms.cpp"
+				>
+			</File>
+			<File
+				RelativePath=".\SE_PositioningAlgorithms.h"
+				>
+			</File>
+			<File
+				RelativePath=".\SE_Renderer.cpp"
+				>
+			</File>
+			<File
+				RelativePath=".\SE_Renderer.h"
+				>
+			</File>
+			<File
+				RelativePath=".\SE_StyleVisitor.cpp"
+				>
+			</File>
+			<File
+				RelativePath=".\SE_StyleVisitor.h"
+				>
+			</File>
+			<File
+				RelativePath=".\SE_SymbolManager.h"
+				>
+			</File>
+			<File
+				RelativePath=".\StylizationEngine.cpp"
+				>
+			</File>
+			<File
+				RelativePath=".\StylizationEngine.h"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="FontEngine"
+			>
+			<File
+				RelativePath=".\FontManager.cpp"
+				>
+			</File>
+			<File
+				RelativePath=".\FontManager.h"
+				>
+			</File>
+			<File
+				RelativePath=".\RS_FontEngine.cpp"
+				>
+			</File>
+			<File
+				RelativePath=".\RS_FontEngine.h"
+				>
+			</File>
+		</Filter>
 		<File
 			RelativePath=".\stdafx.h"
 			>

Added: trunk/MgDev/Common/Stylization/StylizationEngine.cpp
===================================================================
--- trunk/MgDev/Common/Stylization/StylizationEngine.cpp	                        (rev 0)
+++ trunk/MgDev/Common/Stylization/StylizationEngine.cpp	2007-03-06 23:31:17 UTC (rev 1158)
@@ -0,0 +1,561 @@
+//
+//  Copyright (C) 2007 by Autodesk, Inc.
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of version 2.1 of the GNU Lesser
+//  General Public License as published by the Free Software Foundation.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+//
+
+#include "stdafx.h"
+#include "StylizationEngine.h"
+#include "SE_LineBuffer.h"
+#include "SE_ConvexHull.h"
+#include "SE_Bounds.h"
+#include "SE_StyleVisitor.h"
+#include "SE_Renderer.h"
+#include "SE_SymbolManager.h"
+#include "SE_PositioningAlgorithms.h"
+#include "RS_FontEngine.h"
+
+#include <algorithm>
+#include <functional>
+
+using namespace MDFMODEL_NAMESPACE;
+
+
+StylizationEngine::StylizationEngine(SE_SymbolManager* resources) :
+    m_resources(resources)
+{
+    m_pool = new SE_LineBufferPool;
+    m_visitor = new SE_StyleVisitor(resources, m_pool);
+}
+
+StylizationEngine::~StylizationEngine()
+{
+    ClearCache();
+    delete m_pool;
+    delete m_visitor;
+}
+
+void StylizationEngine::Stylize( SE_Renderer* renderer,
+                                 RS_FeatureReader* feature,
+                                 RS_FilterExecutor* executor,
+                                 LineBuffer* geometry,
+                                 CompositeTypeStyle* style )
+{
+    if (m_renderer == NULL || m_reader == NULL || m_exec == NULL)
+        return;
+
+    m_renderer = renderer;
+    m_reader = feature;
+    m_exec = executor;
+
+    m_renderer->GetWorldToScreenTransform(m_w2s);
+    m_mm2pxs = m_renderer->GetPixelsPerMillimeterScreen();
+    m_mm2pxw = m_renderer->GetPixelsPerMillimeterWorld();
+    m_renderer->SetLineBufferPool(m_pool);
+
+    SE_Rule*& rules = m_rules[style];
+    RuleCollection* rulecoll = style->GetRules();
+    int nRules = rulecoll->GetCount();
+
+    if (rules == NULL)
+    {
+        SE_Rule* rulecache = new SE_Rule[nRules];
+        rules = rulecache;
+        
+        for (int i = 0; i < nRules; i++)
+        {
+            CompositeRule* r = (CompositeRule*)rulecoll->GetAt(i);
+            const MdfString& filterstr = r->GetFilter();
+            rulecache[i].filter = NULL;
+            
+            if (!filterstr.empty())
+            {
+                try
+                {
+                    FdoFilter::Parse(filterstr.c_str());
+                }
+                catch (FdoException* e)
+                {
+                    e->Release();
+                }
+            }
+
+            m_visitor->Convert(rulecache[i].symbolization, r->GetSymbolization());
+        }
+    }
+
+    std::vector<SE_Symbolization*>* symbolization = NULL;
+
+    for (int i = 0; i < nRules; i++)
+    {
+        bool match = rules[i].filter == NULL;
+        
+        if (!match)
+        {
+            rules[i].filter->Process(executor);
+            match = executor->GetResult();
+        }
+
+        if (match)
+        {
+            symbolization = &rules[i].symbolization;
+            break;
+        }
+    }
+
+    if (symbolization == NULL)
+        return;
+
+    /* TODO: Obey the indices--Get rid of the indices alltogther--single pass! */
+    
+    SE_LineBuffer* xformGeom = m_pool->NewLineBuffer(geometry->point_count());
+
+    xformGeom->SetToTransform(geometry, m_w2s);
+
+    for (std::vector<SE_Symbolization*>::const_iterator iter = symbolization->begin(); iter != symbolization->end(); iter++)
+    {
+        SE_Symbolization* sym = *iter;
+
+        double mm2px = (sym->context == MappingUnits ? m_mm2pxw : m_mm2pxs);
+        SE_Matrix xform;
+        xform.setTransform( sym->scale[0].evaluate(m_exec), 
+                            sym->scale[1].evaluate(m_exec),
+                            sym->absOffset[0].evaluate(m_exec)*mm2px, 
+                            sym->absOffset[1].evaluate(m_exec)*mm2px );
+        xform.scale(mm2px, mm2px);
+        
+        for (std::vector<SE_Style*>::const_iterator siter = sym->styles.begin(); siter != sym->styles.end(); siter++)
+        {
+            SE_Style* style = *siter;
+
+            SE_Matrix tmpxform = xform; //TODO: this is lame, but necessary since the xform can be modified
+                                        //when we evalute the style, in the case of point style set on a
+                                        //non-point geometry
+
+            //allocate a render style into which we will evaluate all styles (and the expressions inside them)
+            SE_RenderStyle* rstyle = NULL;
+            switch(style->type)
+            {
+                case SE_PointStyleType:
+                    //this call may modify xform to apply the necessary rotation 
+                    rstyle = EvaluatePointStyle(xformGeom, tmpxform, (SE_PointStyle*)style, mm2px);
+                    break;
+                case SE_LineStyleType:
+                    rstyle = EvaluateLineStyle(tmpxform, (SE_LineStyle*)style);
+                    break;
+                case SE_AreaStyleType:
+                    rstyle = EvaluateAreaStyle(tmpxform, (SE_AreaStyle*)style);
+                    break;
+            }
+            
+            //evaluate values that are common to all styles           
+            rstyle->renderPass = style->renderPass.evaluate(m_exec);
+            rstyle->addToExclusionRegions = sym->addToExclusionRegions.evaluate(m_exec);
+            rstyle->checkExclusionRegions = sym->checkExclusionRegions.evaluate(m_exec);
+            rstyle->drawLast = sym->drawLast.evaluate(m_exec);
+
+            //evaluate the graphic elements
+            EvaluateSymbols(tmpxform, style, rstyle, mm2px); 
+
+            if (!sym->positioningAlgorithm.empty() && sym->positioningAlgorithm != L"Default")
+            {
+                LayoutCustomLabel(xformGeom, tmpxform, style, rstyle, mm2px);
+            }
+            else
+            {
+                switch(style->type)
+                {
+                case SE_PointStyleType:
+                    m_renderer->ProcessPoint(xformGeom, (SE_RenderPointStyle*)rstyle);
+                    break;
+                case SE_LineStyleType:
+                    m_renderer->ProcessLine(xformGeom, (SE_RenderLineStyle*)rstyle);
+                    break;
+                case SE_AreaStyleType:
+                    m_renderer->ProcessArea(xformGeom, (SE_RenderAreaStyle*)rstyle);
+                    break;
+                }
+            }
+
+            //TODO: LEAK: the RenderStyles used for labeling are leaked because of this -- we need to free them somehow
+            if (!sym->drawLast.evaluate(m_exec))
+                delete rstyle;
+        }
+    }
+    m_pool->FreeLineBuffer(xformGeom);
+}
+
+SE_RenderPointStyle* StylizationEngine::EvaluatePointStyle(SE_LineBuffer* geometry, SE_Matrix& xform, SE_PointStyle* style, double mm2px)
+{
+    SE_RenderPointStyle* render = new SE_RenderPointStyle();
+
+    double offsetX = 0, offsetY = 0;
+    double rotation = 0;
+
+    LineBuffer::GeomOperationType type;
+
+    switch(geometry->xf_geom_type())
+    {
+    case FdoGeometryType_LineString:
+    case FdoGeometryType_MultiLineString:
+        type = LineBuffer::ctLine;
+        break;
+    case FdoGeometryType_Polygon:
+    case FdoGeometryType_MultiPolygon:
+        type = LineBuffer::ctArea;
+        break;
+    case FdoGeometryType_Point:
+    case FdoGeometryType_MultiPoint:
+        type = LineBuffer::ctPoint;
+        break;
+    default:
+        type = LineBuffer::ctNone;
+        break;
+    }
+
+    if (style->orientation == PointUsage::FromGeometry)
+    {
+        if (type == LineBuffer::ctLine || type == LineBuffer::ctArea)
+        {
+            double x0, x1, y0, y1;
+            geometry->xf_longest_edge(x0, y0, x1, y1);
+            rotation = atan2(y1 - y0, x1 - x0); //TODO: this is probably affected by which way y goes in the renderer (yUp or yDown)
+            if (rotation < 0)
+                rotation += 2*M_PI;
+        }
+        else
+            rotation = 0.0;
+    }
+    else
+        rotation = style->angle.evaluate(m_exec)*M_PI/180.0;
+
+    SE_Matrix sxform;
+
+    offsetX = style->offset[0].evaluate(m_exec)*mm2px;
+    offsetY = style->offset[1].evaluate(m_exec)*mm2px;
+    sxform.translate(offsetX, offsetY);
+    sxform.rotate(rotation);
+    sxform.premultiply(xform);
+    xform = sxform;
+
+    return render;
+}
+
+SE_RenderLineStyle* StylizationEngine::EvaluateLineStyle(SE_Matrix& xform, SE_LineStyle* style)
+{
+    SE_RenderLineStyle* render = new SE_RenderLineStyle();
+
+    render->angle = style->angle.evaluate(m_exec)*(M_PI/180.0);
+    render->angleLimit = style->angleLimit.evaluate(m_exec)*(M_PI/180.0);
+    render->endOffset = style->endOffset.evaluate(m_exec)*xform.x0; // x0 is x scale * mm2px
+    render->repeat = style->repeat.evaluate(m_exec)*xform.x0;
+    render->startOffset = style->startOffset.evaluate(m_exec)*xform.x0;
+
+    render->units = style->units;
+    render->orientation = style->orientation;
+    render->overlap = style->overlap;
+    render->join = style->join;
+
+    return render;
+}
+
+SE_RenderAreaStyle* StylizationEngine::EvaluateAreaStyle(SE_Matrix& xform, SE_AreaStyle* style)
+{
+    SE_RenderAreaStyle* render = new SE_RenderAreaStyle();
+
+    render->orientation = style->orientation;
+    render->clipping = style->clipping;
+    render->origincontrol = style->origincontrol;
+
+    return render;
+}
+
+
+void StylizationEngine::EvaluateSymbols(SE_Matrix& xform, SE_Style* style, SE_RenderStyle* renderStyle, double mm2px)
+{
+    double dx, dy, sx, sy;
+    double minx, maxx, miny, maxy;
+    double growx, growy;
+    if (style->useBox)
+    {
+        dx = style->resizePosition[0].evaluate(m_exec);
+        dy = style->resizePosition[1].evaluate(m_exec);
+        sx = style->resizeSize[0].evaluate(m_exec)/2.0;
+        sy = style->resizeSize[1].evaluate(m_exec)/2.0;
+
+        xform.transform(dx - sx, dy - sy, minx, miny);
+        xform.transform(dx + sx, dy + sy, maxx, maxy);
+        xform.transform(dx, dy);
+
+        growx = 0.0;
+        growy = 0.0;
+    }
+
+    for (SE_Symbol::const_iterator src = style->symbol.begin(); src != style->symbol.end(); src++)
+    {
+        SE_Primitive* sym = *src;
+        SE_RenderPrimitive* rsym = NULL;
+
+        switch(sym->type)
+        {
+        case SE_PolygonPrimitive:
+            rsym = new SE_RenderPolygon();
+            ((SE_RenderPolygon*)rsym)->fill = ((SE_Polygon*)sym)->fill.evaluate(m_exec);
+        case SE_PolylinePrimitive:
+            {
+                if (!rsym) rsym = new SE_RenderPolyline();
+                SE_Polyline* p = (SE_Polyline*) sym;
+                SE_RenderPolyline* rp = (SE_RenderPolyline*)rsym;
+                rp->weight = p->weight.evaluate(m_exec)*mm2px;
+                rp->geometry = p->geometry;
+                rp->geometry->Transform(xform, rp->weight);
+                rp->bounds = p->geometry->xf_bounds();
+                rp->color = p->color.evaluate(m_exec);
+            }
+            break;
+        case SE_TextPrimitive:
+            {
+                rsym = new SE_RenderText();
+                SE_Text* t = (SE_Text*)sym;
+                SE_RenderText* rt = (SE_RenderText*)rsym;
+                rt->text = t->textExpr.evaluate(m_exec);
+                rt->position[0] = t->position[0].evaluate(m_exec)*mm2px;
+                rt->position[1] = t->position[1].evaluate(m_exec)*mm2px;//TODO: take into account y-up or y-down!
+                xform.transform(rt->position[0], rt->position[1]);
+
+                rt->tdef.font().name() =  t->fontExpr.evaluate(m_exec);
+                rt->tdef.font().height() = t->size.evaluate(m_exec)*0.001*xform.y1/mm2px; //convert mm to meters which is what RS_TextDef expects
+                rt->tdef.linespace() = t->lineSpacing.evaluate(m_exec);
+                rt->tdef.rotation() = t->angle.evaluate(m_exec);
+
+                int style = RS_FontStyle_Regular;
+
+                if (t->underlined.evaluate(m_exec)) style |= (int)RS_FontStyle_Underline;
+                if (t->italic.evaluate(m_exec)) style |= (int)RS_FontStyle_Italic;
+                if (t->bold.evaluate(m_exec)) style |= (int)RS_FontStyle_Bold;
+
+                rt->tdef.font().style() = (RS_FontStyle_Mask)style;
+
+                rt->tdef.color() = RS_Color::FromARGB(t->textColor.evaluate(m_exec));
+                rt->tdef.bgcolor() = RS_Color::FromARGB(t->ghostColor.evaluate(m_exec));
+
+                const wchar_t* hAlign = t->hAlignment.evaluate(m_exec);
+                if (hAlign)
+                {
+                    if (wcscmp(hAlign, L"Left") == 0)           
+                        rt->tdef.halign() = RS_HAlignment_Left;
+                    else if (wcscmp(hAlign, L"Center") == 0)    
+                        rt->tdef.halign() = RS_HAlignment_Center;
+                    else if (wcscmp(hAlign, L"Right") == 0)     
+                        rt->tdef.halign() = RS_HAlignment_Right;
+                }
+
+                const wchar_t* vAlign = t->vAlignment.evaluate(m_exec);
+                if (vAlign)
+                {
+                    if (wcscmp(vAlign, L"Bottom") == 0)         
+                        rt->tdef.valign() = RS_VAlignment_Descent;
+                    else if (wcscmp(vAlign, L"Baseline") == 0)  
+                        rt->tdef.valign() = RS_VAlignment_Base;
+                    else if (wcscmp(vAlign, L"Halfline") == 0)  
+                        rt->tdef.valign() = RS_VAlignment_Half;
+                    else if (wcscmp(vAlign, L"Capline") == 0)   
+                        rt->tdef.valign() = RS_VAlignment_Cap;
+                    else if (wcscmp(vAlign, L"Top") == 0)       
+                        rt->tdef.valign() = RS_VAlignment_Ascent;
+                }
+
+                RS_TextMetrics tm;
+                SE_Matrix txf;
+                m_renderer->GetFontEngine()->GetTextMetrics(rt->text, rt->tdef, tm, false);
+                txf.rotate(rt->tdef.rotation()*M_PI/180.0);
+                txf.translate(rt->position[0], rt->position[1]);
+
+                double* buffer = (double*)alloca(tm.line_pos.size()*sizeof(double)*8);
+                double* ptr = buffer;
+                for(size_t k = 0; k < tm.line_pos.size(); k++)
+                {
+                    const RS_F_Point* pts = tm.line_pos[k].ext;
+                    txf.transform(pts[0].x, pts[0].y, ptr[0], ptr[1]);
+                    txf.transform(pts[1].x, pts[1].y, ptr[2], ptr[3]);
+                    txf.transform(pts[2].x, pts[2].y, ptr[4], ptr[5]);
+                    txf.transform(pts[3].x, pts[3].y, ptr[6], ptr[7]);
+                    ptr += 8;
+                }
+
+                std::sort((std::pair<double,double>*)buffer, (std::pair<double,double>*)(ptr - 2), PointLess( ));
+                rt->bounds = AndrewHull<std::pair<double,double>*,SimplePOINT>
+                    ((std::pair<double,double>*)buffer, 
+                    ((std::pair<double,double>*)ptr) - 1, 
+                    (int)tm.line_pos.size()*4, m_pool);
+            }
+            break;
+        case SE_RasterPrimitive:
+            {
+                rsym = new SE_RenderRaster();
+                SE_Raster* r = (SE_Raster*)sym;
+                SE_RenderRaster* rr = (SE_RenderRaster*)rsym;
+
+                if (!r->pngPtr)
+                {
+                    rr->pngPtr = m_resources->GetImageData(r->pngPath.evaluate(m_exec), rr->pngSize);
+                }
+                else
+                {
+                    rr->pngPtr = r->pngPtr;
+                    rr->pngSize = r->pngSize;
+                }
+
+                rr->position[0] = r->position[0].evaluate(m_exec)*mm2px;
+                rr->position[1] = r->position[1].evaluate(m_exec)*mm2px;
+                xform.transform(rr->position[0], rr->position[1]);
+                rr->extent[0] = r->extent[0].evaluate(m_exec)*xform.x0;
+                rr->extent[1] = r->extent[1].evaluate(m_exec)*xform.y1;
+                rr->angle = r->angle.evaluate(m_exec)*(M_PI/180.0);
+
+                rr->bounds = m_pool->NewBounds(5);
+                SE_Matrix rxf;
+                rxf.rotate(rr->angle);
+                rxf.translate(rr->position[0], rr->position[1]);
+
+                double w = rr->extent[0]/2.0;
+                double h = rr->extent[1]/2.0;
+                double sx, sy, x, y;
+
+                rxf.transform(w, h, sx, sy); // upper right
+                rr->bounds->Add(sx, sy);
+                rxf.transform(w, -h, x, y); // lower right
+                rr->bounds->Add(x, y);
+                rxf.transform(-w, -h, x, y); // lower left
+                rr->bounds->Add(x, y);
+                rxf.transform(-w, h, x, y); // upper left
+                rr->bounds->Add(x, y);
+                rr->bounds->Add(sx, sy); // upper right
+            }
+            break;
+        default: break;
+        }
+
+        if (rsym)
+        {
+            if (renderStyle->bounds)
+            {
+                SE_Bounds* bounds = renderStyle->bounds;
+                renderStyle->bounds = renderStyle->bounds->Union(rsym->bounds);
+                
+                if (style->useBox && sym->resize == GraphicElement::AddToResizeBox)
+                    bounds->Contained(minx, miny, maxx, maxy, growx, growy);
+
+                bounds->Free();
+            }
+            else
+                renderStyle->bounds = rsym->bounds->Clone();
+            rsym->resize = sym->resize == GraphicElement::AdjustToResizeBox;
+            renderStyle->symbol.push_back(rsym);
+        }
+    }
+
+    if (style->useBox)
+    {
+        switch(style->resize)
+        {
+        case ResizeBox::GrowInX:
+            growy = 0.0;
+            break;
+        case ResizeBox::GrowInY:
+            growx = 0.0;
+            break;
+        case ResizeBox::GrowInXYMaintainAspect:
+            if (growy > growx)
+                growx = growy;
+            else if (growx > growy)
+                growy = growx;
+        }
+
+        if (growx != 0 || growy != 0)
+        {
+            SE_Matrix totalxf(xform);
+            SE_Matrix growxf;
+            growxf.translate(-dx, -dy);
+            growxf.scale(1.0 + growx, 1.0 + growy);
+            growxf.translate(dx, dy);
+            totalxf.premultiply(growxf);
+
+            for (SE_RenderSymbol::iterator rs = renderStyle->symbol.begin(); rs != renderStyle->symbol.end(); rs++)
+            {
+                SE_RenderPrimitive* rsym = *rs;
+                if (rsym->resize)
+                {
+                    switch(rsym->type)
+                    {
+                    case SE_PolygonPrimitive:
+                    case SE_PolylinePrimitive:
+                        {
+                            SE_RenderPolyline* rp = (SE_RenderPolyline*)rsym;
+                            rp->geometry->Transform(totalxf, rp->weight);
+                            rp->bounds = rp->geometry->xf_bounds();
+                            break;
+                        }
+                    case SE_TextPrimitive:
+                        {
+                            SE_RenderText* rt = (SE_RenderText*)rsym;
+                            growxf.transform(rt->position[0], rt->position[1]);
+                            rt->tdef.font().height() *= growxf.y1;
+                            break;
+                        }
+                    case SE_RasterPrimitive:
+                        {
+                            SE_RenderRaster* rr = (SE_RenderRaster*)rsym;
+                            growxf.transform(rr->position[0], rr->position[1]);
+                            rr->extent[0] *= growxf.x0;
+                            rr->extent[1] *= growxf.y1;
+                            break;
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
+
+
+void StylizationEngine::LayoutCustomLabel(SE_LineBuffer* geometry, SE_Matrix& xform, SE_Style* style, SE_RenderStyle* rstyle, double mm2px)
+{
+    //here we decide which one to call based on the name of the positioning algorithm
+    //if (style->positioningAlgorithm == 8Candidates)
+    //{
+        SE_PositioningAlgorithms::EightBall(m_renderer, geometry, xform, style, rstyle, mm2px);
+        
+    //}
+    //else if (style->positioningAlgorithm == MultipleHighwayShields)
+    //{
+
+    //}
+     
+}
+
+//clears cached filters/styles/etc
+void StylizationEngine::ClearCache()
+{
+    
+    std::map<CompositeTypeStyle*, SE_Rule*>::iterator iter = m_rules.begin();
+
+    for (; iter != m_rules.end(); iter++)
+    {
+        //TODO: deleting the SE_Rule causes a heap corruption that needs to be tracked down
+        //delete iter->second;
+    }
+
+    m_rules.clear();
+}


Property changes on: trunk/MgDev/Common/Stylization/StylizationEngine.cpp
___________________________________________________________________
Name: svn:eol-style
   + native

Added: trunk/MgDev/Common/Stylization/StylizationEngine.h
===================================================================
--- trunk/MgDev/Common/Stylization/StylizationEngine.h	                        (rev 0)
+++ trunk/MgDev/Common/Stylization/StylizationEngine.h	2007-03-06 23:31:17 UTC (rev 1158)
@@ -0,0 +1,77 @@
+//
+//  Copyright (C) 2004-2007 by Autodesk, Inc.
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of version 2.1 of the GNU Lesser
+//  General Public License as published by the Free Software Foundation.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+//
+
+#ifndef STYLIZATION_ENGINE_H
+#define STYLIZATION_ENGINE_H
+
+#include "SE_Matrix.h"
+#include "SE_Include.h"
+
+class SE_SymbolManager;
+class RS_FeatureReader;
+class RS_FilterExecutor;
+class SE_LineBuffer;
+class SE_LineBufferPool;
+class SE_Renderer;
+class SE_StyleVisitor;
+class LineBuffer;
+
+namespace MDFMODEL_NAMESPACE
+{
+    class CompositeTypeStyle;
+}
+
+using namespace MDFMODEL_NAMESPACE;
+
+class StylizationEngine
+{
+public:
+    StylizationEngine(SE_SymbolManager* resources);
+    /* TODO: don't leak basically everything */
+    ~StylizationEngine();
+    /* TODO: add stylize layer to this class, and reset functionality to RS_FeatureReader API & implementations
+     * Stylizize one CompoundSymbol feature and label per run; investigate caching possiblities to avoid
+     * filter execution on subsequent passes */
+    void Stylize(SE_Renderer* renderer,
+                 RS_FeatureReader* feature,
+                 RS_FilterExecutor* executor,
+                 LineBuffer* geometry,
+                 CompositeTypeStyle* style);
+
+    void ClearCache();
+private:
+
+    SE_RenderPointStyle* EvaluatePointStyle(SE_LineBuffer* geometry, SE_Matrix& xform, SE_PointStyle* style, double mm2px);
+    SE_RenderAreaStyle* EvaluateAreaStyle(SE_Matrix& xform, SE_AreaStyle* style);
+    SE_RenderLineStyle* EvaluateLineStyle(SE_Matrix& xform, SE_LineStyle* style);
+
+
+    void LayoutCustomLabel(SE_LineBuffer* geometry, SE_Matrix& xform, SE_Style* style, SE_RenderStyle* rstyle, double mm2px);
+    void EvaluateSymbols(SE_Matrix& xform, SE_Style* style, SE_RenderStyle* renderStyle, double mm2px);
+    SE_Renderer* m_renderer;
+    RS_FilterExecutor* m_exec;
+    RS_FeatureReader* m_reader;
+    SE_Matrix m_w2s;
+    double m_mm2pxs;
+    double m_mm2pxw;
+    SE_SymbolManager* m_resources;
+    SE_LineBufferPool* m_pool;
+    SE_StyleVisitor* m_visitor;
+    std::map<CompositeTypeStyle*, SE_Rule*> m_rules;
+};
+
+#endif // STYLIZATION_ENGINE_H


Property changes on: trunk/MgDev/Common/Stylization/StylizationEngine.h
___________________________________________________________________
Name: svn:eol-style
   + native

Modified: trunk/MgDev/Common/Stylization/Stylizer.h
===================================================================
--- trunk/MgDev/Common/Stylization/Stylizer.h	2007-03-06 17:02:52 UTC (rev 1157)
+++ trunk/MgDev/Common/Stylization/Stylizer.h	2007-03-06 23:31:17 UTC (rev 1158)
@@ -26,6 +26,7 @@
 class Renderer;
 class GeometryAdapter;
 class CSysTransformer;
+class SE_SymbolManager;
 
 ///<summary>
 ///Stylization interrupt callback -- return true to cancel stylization
@@ -40,11 +41,10 @@
 class Stylizer
 {
 public:
-
     ///<summary>
     ///Sets the Renderer object for this Stylizer
     ///</summary>
-    virtual void Initialize(Renderer* renderer) = 0;
+    virtual void Initialize(Renderer* renderer, SE_SymbolManager* sman = NULL) = 0;
 
     ///<summary>
     /// Stylizes a feature (FDO based) layer.
@@ -66,7 +66,6 @@
                                      void*                                userData
                                      ) = 0;
 
-
     ///<summary>
     /// Stylizes a drawing (DWF based) layer.
     ///</summary>
@@ -91,14 +90,11 @@
     virtual void SetStylizeFeature(  FdoClassDefinition* classDef,
                                      GeometryAdapter* sg) = 0;
 
-
-
     STYLIZATION_API static MdfModel::VectorScaleRange* FindScaleRange(MdfModel::VectorScaleRangeCollection& src,
                                          double mapScale);
 
     STYLIZATION_API static MdfModel::GridScaleRange* FindScaleRange(MdfModel::GridScaleRangeCollection& src,
                                          double mapScale);
-
 };
 
 #endif

Modified: trunk/MgDev/Common/Stylization/SymbolVisitor.h
===================================================================
--- trunk/MgDev/Common/Stylization/SymbolVisitor.h	2007-03-06 17:02:52 UTC (rev 1157)
+++ trunk/MgDev/Common/Stylization/SymbolVisitor.h	2007-03-06 23:31:17 UTC (rev 1158)
@@ -33,7 +33,10 @@
         stFont       = 3,
         stW2D        = 4,
         stBlock      = 5,
-        stText       = 6 //will not get that as a point symbol -- it's for labels only
+        stText       = 6, //will not get that as a point symbol -- it's for labels only
+        stLine       = 7,
+        stFill       = 8,
+        stPoint      = 9
     };
 
     SymbolVisitor()
@@ -86,7 +89,6 @@
     }
 
 private:
-
     eSymbolType m_type;
 };
 

Modified: trunk/MgDev/Common/Stylization/stdafx.h
===================================================================
--- trunk/MgDev/Common/Stylization/stdafx.h	2007-03-06 17:02:52 UTC (rev 1157)
+++ trunk/MgDev/Common/Stylization/stdafx.h	2007-03-06 23:31:17 UTC (rev 1158)
@@ -30,6 +30,7 @@
 #define _wcsnicmp wcsncasecmp
 #define _wcsicmp wcscasecmp
 #define _isnan isnan
+#define _finite finite
 
 #endif //_WIN32
 

Modified: trunk/MgDev/Server/src/Services/Kml/ServerKmlService.cpp
===================================================================
--- trunk/MgDev/Server/src/Services/Kml/ServerKmlService.cpp	2007-03-06 17:02:52 UTC (rev 1157)
+++ trunk/MgDev/Server/src/Services/Kml/ServerKmlService.cpp	2007-03-06 23:31:17 UTC (rev 1158)
@@ -467,11 +467,9 @@
             extents->GetLowerLeftCoordinate()->GetY(),
             extents->GetUpperRightCoordinate()->GetX(),
             extents->GetUpperRightCoordinate()->GetY());
-        Ptr<MgFeatureReader> featureReader = MgStylizationUtil::ExecuteFeatureQuery(m_svcFeature, rsExtent, vl, NULL, destCs, layerCs, NULL);
-        if (featureReader.p)
+        RSMgFeatureReader* rdr = MgStylizationUtil::ExecuteFeatureQuery(m_svcFeature, rsExtent, vl, NULL, destCs, layerCs, NULL);
+        if (rdr)
         {
-            //wrap in an RS_FeatureReader
-            RSMgFeatureReader rsrdr(featureReader, vl->GetGeometry());
             RS_FeatureClassInfo fcInfo(vl->GetFeatureName());
             MdfModel::NameStringPairCollection* pmappings = vl->GetPropertyMappings();
             for (int j=0; j<pmappings->GetCount(); j++)
@@ -480,9 +478,10 @@
                 fcInfo.add_mapping(m->GetName(), m->GetValue());
             }
             renderer.StartLayer(&layerInfo, &fcInfo);
-            stylizer.StylizeFeatures(vl, &rsrdr, csTrans, NULL, NULL);
+            stylizer.StylizeFeatures(vl, rdr, csTrans, NULL, NULL);
             renderer.EndLayer();
         }
+        delete rdr;
     }
 /*    else if(gl != NULL)
     {

Modified: trunk/MgDev/Server/src/Services/Mapping/Makefile.am
===================================================================
--- trunk/MgDev/Server/src/Services/Mapping/Makefile.am	2007-03-06 17:02:52 UTC (rev 1157)
+++ trunk/MgDev/Server/src/Services/Mapping/Makefile.am	2007-03-06 23:31:17 UTC (rev 1158)
@@ -42,6 +42,7 @@
   RSMgFeatureReader.cpp \
   RSMgRaster.cpp \
   RSMgSymbolManager.cpp \
+  SEMgSymbolManager.cpp \
   LegendPlotUtil.cpp \
   StylizationUtil.cpp
 
@@ -66,6 +67,7 @@
   RSMgRaster.h \
   RSMgInputStream.h \
   RSMgSymbolManager.h \
+  SEMgSymbolManager.h \
   LegendPlotUtil.h \
   StylizationUtil.h
 

Modified: trunk/MgDev/Server/src/Services/Mapping/RSMgFeatureReader.cpp
===================================================================
--- trunk/MgDev/Server/src/Services/Mapping/RSMgFeatureReader.cpp	2007-03-06 17:02:52 UTC (rev 1157)
+++ trunk/MgDev/Server/src/Services/Mapping/RSMgFeatureReader.cpp	2007-03-06 23:31:17 UTC (rev 1158)
@@ -34,12 +34,17 @@
                        }
 
 
-RSMgFeatureReader::RSMgFeatureReader(MgFeatureReader* reader, const STRING& geomPropName)
+RSMgFeatureReader::RSMgFeatureReader(MgFeatureReader* reader, MgFeatureService* svcFeature, MgResourceIdentifier* featResId, MgFeatureQueryOptions* options, const STRING& geomPropName)
 {
     assert(NULL != reader);
     m_reader = reader;
     SAFE_ADDREF(m_reader);
 
+    //stuff needed for resetting the reader
+    m_svcFeature = SAFE_ADDREF(svcFeature);
+    m_resId = SAFE_ADDREF(featResId);
+    m_options = SAFE_ADDREF(options);
+
     //use geometry property given by user
     m_geomPropName = geomPropName;
     m_rasterPropName = L"";
@@ -138,6 +143,9 @@
 
     SAFE_RELEASE(m_reader);
     SAFE_RELEASE(m_class);
+    SAFE_RELEASE(m_svcFeature);
+    SAFE_RELEASE(m_resId);
+    SAFE_RELEASE(m_options);
 
     delete [] m_vProps;
     delete [] m_propNames;
@@ -158,6 +166,18 @@
     RSFR_CATCH()
 }
 
+void RSMgFeatureReader::Reset()
+{
+    RSFR_TRY()
+
+    m_reader->Close();
+    SAFE_RELEASE(m_reader);
+
+    m_reader = m_svcFeature->SelectFeatures(m_resId, m_class->GetClassName(), m_options);
+
+    RSFR_CATCH()
+}
+
 bool RSMgFeatureReader::IsNull(const wchar_t* propertyName)
 {
     RSFR_TRY()

Modified: trunk/MgDev/Server/src/Services/Mapping/RSMgFeatureReader.h
===================================================================
--- trunk/MgDev/Server/src/Services/Mapping/RSMgFeatureReader.h	2007-03-06 17:02:52 UTC (rev 1157)
+++ trunk/MgDev/Server/src/Services/Mapping/RSMgFeatureReader.h	2007-03-06 23:31:17 UTC (rev 1158)
@@ -36,10 +36,8 @@
 //RS_FeatureReader implementation based on an MgFeatureReader
 class MG_SERVER_MAPPING_API RSMgFeatureReader : public RS_FeatureReader
 {
-
 public:
-
-    RSMgFeatureReader(MgFeatureReader* reader, const STRING& geomPropName);
+    RSMgFeatureReader(MgFeatureReader* reader, MgFeatureService* svcFeature, MgResourceIdentifier* featResId, MgFeatureQueryOptions* options, const STRING& geomPropName);
     virtual ~RSMgFeatureReader();
 
     //--------------------------------------------
@@ -50,6 +48,8 @@
 
     virtual void            Close       ();
 
+    virtual void            Reset       ();
+
     virtual int             GetPropertyType(const wchar_t* propertyName);
 
     virtual bool            IsNull      (const wchar_t* propertyName);
@@ -93,7 +93,6 @@
     virtual const wchar_t*const*  GetPropNames(int& count);
 
 private:
-
     MgFeatureReader* m_reader;
     MgClassDefinition* m_class;
 
@@ -107,6 +106,11 @@
     STRING m_geomPropName;
     STRING m_rasterPropName;
     STRING m_cachePropValue;
+
+    //needed for resetting of the reader
+    MgFeatureService* m_svcFeature;
+    MgResourceIdentifier* m_resId;
+    MgFeatureQueryOptions* m_options;
 };
 
 #endif

Added: trunk/MgDev/Server/src/Services/Mapping/SEMgSymbolManager.cpp
===================================================================
--- trunk/MgDev/Server/src/Services/Mapping/SEMgSymbolManager.cpp	                        (rev 0)
+++ trunk/MgDev/Server/src/Services/Mapping/SEMgSymbolManager.cpp	2007-03-06 23:31:17 UTC (rev 1158)
@@ -0,0 +1,159 @@
+//
+//  Copyright (C) 2007 by Autodesk, Inc.
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of version 2.1 of the GNU Lesser
+//  General Public License as published by the Free Software Foundation.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+//
+
+#include "ServerMappingServiceDefs.h"
+#include "SEMgSymbolManager.h"
+#include "SAX2Parser.h"
+#include "MapGuideCommon.h"
+
+#define SYMBOL_ERROR (SymbolDefinition*)1
+#define IMAGE_ERROR (unsigned char*)1
+
+SEMgSymbolManager::SEMgSymbolManager(MgResourceService* svc)
+{
+    m_svcResource = svc;
+    SAFE_ADDREF(m_svcResource);
+}
+
+SEMgSymbolManager::~SEMgSymbolManager()
+{
+    SAFE_RELEASE(m_svcResource);
+
+    //free up cached symbols
+    for (std::map<STRING, SymbolDefinition*>::iterator iter = m_mSymbolCache.begin();
+        iter != m_mSymbolCache.end(); iter++)
+    {
+        if (iter->second != SYMBOL_ERROR)
+            delete (SymbolDefinition*)(iter->second);
+    }
+
+    for (std::map<STRING, unsigned char*>::iterator iter = m_mImageCache.begin();
+        iter != m_mImageCache.end(); iter++)
+    {
+        if (iter->second != IMAGE_ERROR)
+            delete[] (unsigned char*)(iter->second);
+    }
+}
+
+SymbolDefinition* SEMgSymbolManager::GetSymbolDefinition(const wchar_t* resource)
+{
+    STRING uniqueName = STRING(resource);
+    SymbolDefinition* ret = m_mSymbolCache[uniqueName];
+
+    //check if we errored on this symbol before and
+    //don't try again
+    if (ret == SYMBOL_ERROR)
+        return NULL;
+
+    if (!ret)
+    {
+        try
+        {
+            Ptr<MgByteReader> sdReader;
+
+            if (wcsncmp(uniqueName.c_str(), L"Library://", 10) == 0)
+            {
+                //get and parse the mapdef
+                MgResourceIdentifier resId(uniqueName);
+                sdReader = m_svcResource->GetResourceContent(&resId, L"");
+            }
+            else
+            {
+                sdReader = new MgByteReader(uniqueName, MgMimeType::Xml, false);
+            }
+
+            Ptr<MgByteSink> sink = new MgByteSink(sdReader);
+            Ptr<MgByte> bytes = sink->ToBuffer();
+
+            assert(bytes->GetLength() > 0);
+
+            MdfParser::SAX2Parser parser;
+            parser.ParseString((const char *)bytes->Bytes(), bytes->GetLength());
+
+            assert(parser.GetSucceeded());
+
+            // detach the feature layer definition from the parser - it's
+            // now the caller's responsibility to delete it
+            ret = parser.DetachSymbolDefinition();
+
+            assert(ret);
+
+            m_mSymbolCache[uniqueName] = ret;
+        }
+        catch (MgException* e)
+        {
+            //either symbol or symbol library was not found
+            //Set it to something else that's invalid (like 1) in the cache so that
+            //we know there was an error and don't try to get it again.
+            e->Release();
+            ret = NULL;
+            m_mSymbolCache[uniqueName] = SYMBOL_ERROR;
+        }
+    }
+
+    return ret;
+}
+
+unsigned char* SEMgSymbolManager::GetImageData(const wchar_t* resource, int& length)
+{
+    STRING uniqueName = STRING(resource);
+    unsigned char* ret = m_mImageCache[uniqueName];
+    length = 0;
+
+    if (ret == IMAGE_ERROR)
+        return NULL;
+
+    if (!ret)
+    {
+        try
+        {
+            Ptr<MgByteReader> sdReader;
+
+            if (wcsncmp(uniqueName.c_str(), L"Library://", 10) == 0)
+            {
+                MgResourceIdentifier resId(uniqueName);
+
+                //get and parse the mapdef
+                sdReader = m_svcResource->GetResourceContent(&resId, L"");
+            }
+            else
+            {
+                sdReader = new MgByteReader(uniqueName, MgMimeType::Png, false);
+            }
+
+            INT64 len = sdReader->GetLength();
+            if (len > 0 && len < 16*1024*1024) // draw the line at 16 MB
+            {
+                ret = new unsigned char[len];
+                length = (int)len;
+                sdReader->Read(ret, length);
+                m_mImageCache[uniqueName] = ret;
+            }
+        }
+        catch (MgException* e)
+        {
+            //either symbol or symbol library was not found
+            //Set it to something else that's invalid (like 1) in the cache so that
+            //we know there was an error and don't try to get it again.
+            e->Release();
+            ret = NULL;
+            m_mImageCache[uniqueName] = IMAGE_ERROR;
+        }
+    }
+
+    return ret;
+}


Property changes on: trunk/MgDev/Server/src/Services/Mapping/SEMgSymbolManager.cpp
___________________________________________________________________
Name: svn:eol-style
   + native

Added: trunk/MgDev/Server/src/Services/Mapping/SEMgSymbolManager.h
===================================================================
--- trunk/MgDev/Server/src/Services/Mapping/SEMgSymbolManager.h	                        (rev 0)
+++ trunk/MgDev/Server/src/Services/Mapping/SEMgSymbolManager.h	2007-03-06 23:31:17 UTC (rev 1158)
@@ -0,0 +1,51 @@
+//
+//  Copyright (C) 2007 by Autodesk, Inc.
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of version 2.1 of the GNU Lesser
+//  General Public License as published by the Free Software Foundation.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+//
+
+#ifndef SEMG_SYMBOL_MANAGER_H
+#define SEMG_SYMBOL_MANAGER_H
+
+#include "Stylization.h"
+#include "SE_SymbolManager.h"
+
+class MgResourceService;
+
+namespace MdfModel
+{
+    class SymbolDefinition;
+};
+
+using namespace MdfModel;
+
+// MappingService specific implementation of the RS_SymbolManager interface.
+// It retrieves DWF symbol data from the resource service and caches it
+// for reuse by stylization.
+class MG_SERVER_MAPPING_API SEMgSymbolManager : public SE_SymbolManager
+{
+public:
+    SEMgSymbolManager(MgResourceService* svc);
+    virtual ~SEMgSymbolManager();
+
+    virtual SymbolDefinition* GetSymbolDefinition(const wchar_t* resource);
+    virtual unsigned char* GetImageData(const wchar_t* resource, int& length);
+
+private:
+    MgResourceService* m_svcResource;
+    std::map<STRING, SymbolDefinition*> m_mSymbolCache;
+    std::map<STRING, unsigned char*> m_mImageCache;
+};
+
+#endif


Property changes on: trunk/MgDev/Server/src/Services/Mapping/SEMgSymbolManager.h
___________________________________________________________________
Name: svn:eol-style
   + native

Modified: trunk/MgDev/Server/src/Services/Mapping/ServerMappingService.vcproj
===================================================================
--- trunk/MgDev/Server/src/Services/Mapping/ServerMappingService.vcproj	2007-03-06 17:02:52 UTC (rev 1157)
+++ trunk/MgDev/Server/src/Services/Mapping/ServerMappingService.vcproj	2007-03-06 23:31:17 UTC (rev 1158)
@@ -602,6 +602,30 @@
 			>
 		</File>
 		<File
+			RelativePath=".\SEMgSymbolManager.cpp"
+			>
+			<FileConfiguration
+				Name="Debug|Win32"
+				ExcludedFromBuild="true"
+				>
+				<Tool
+					Name="VCCLCompilerTool"
+				/>
+			</FileConfiguration>
+			<FileConfiguration
+				Name="Release|Win32"
+				ExcludedFromBuild="true"
+				>
+				<Tool
+					Name="VCCLCompilerTool"
+				/>
+			</FileConfiguration>
+		</File>
+		<File
+			RelativePath=".\SEMgSymbolManager.h"
+			>
+		</File>
+		<File
 			RelativePath=".\ServerMappingDllExport.h"
 			>
 		</File>

Modified: trunk/MgDev/Server/src/Services/Mapping/ServerMappingServiceBuild.cpp
===================================================================
--- trunk/MgDev/Server/src/Services/Mapping/ServerMappingServiceBuild.cpp	2007-03-06 17:02:52 UTC (rev 1157)
+++ trunk/MgDev/Server/src/Services/Mapping/ServerMappingServiceBuild.cpp	2007-03-06 23:31:17 UTC (rev 1158)
@@ -36,3 +36,4 @@
 #include "LegendPlotUtil.cpp"
 #include "StylizationUtil.cpp"
 #include "ServerMappingService.cpp"
+#include "SEMgSymbolManager.cpp"

Modified: trunk/MgDev/Server/src/Services/Mapping/StylizationUtil.cpp
===================================================================
--- trunk/MgDev/Server/src/Services/Mapping/StylizationUtil.cpp	2007-03-06 17:02:52 UTC (rev 1157)
+++ trunk/MgDev/Server/src/Services/Mapping/StylizationUtil.cpp	2007-03-06 23:31:17 UTC (rev 1158)
@@ -132,7 +132,7 @@
 
 
 
-MgFeatureReader* MgStylizationUtil::ExecuteFeatureQuery(MgFeatureService* svcFeature,
+RSMgFeatureReader* MgStylizationUtil::ExecuteFeatureQuery(MgFeatureService* svcFeature,
                                                         RS_Bounds& extent,
                                                         MdfModel::VectorLayerDefinition* vl,
                                                         const wchar_t* overrideFilter,
@@ -286,7 +286,8 @@
 
             //finally try without a filter
             // TODO: could it be an extension name and not a FeatureClassName?
-            rdr = svcFeature->SelectFeatures(featResId, vl->GetFeatureName(), NULL);
+            options = NULL;
+            rdr = svcFeature->SelectFeatures(featResId, vl->GetFeatureName(), options);
         }
     }
 
@@ -294,11 +295,11 @@
     printf("  ExecuteFeatureQuery() total time = %6.4f (s)\n", (GetTickCount()-dwStart)/1000.0);
 #endif
 
-    return SAFE_ADDREF(rdr.p);
+    return new RSMgFeatureReader(rdr.p, svcFeature, featResId.p, options, vl->GetGeometry());
 }
 
 
-MgFeatureReader * MgStylizationUtil::ExecuteRasterQuery(MgFeatureService* svcFeature,
+RSMgFeatureReader * MgStylizationUtil::ExecuteRasterQuery(MgFeatureService* svcFeature,
                                                         RS_Bounds& extent,
                                                         MdfModel::GridLayerDefinition* gl,
                                                         const wchar_t* overrideFilter,
@@ -423,13 +424,122 @@
 
         //finally try without a filter
         // TODO: could it be an extension name and not a FeatureClassName?
-        rdr = svcFeature->SelectFeatures(featResId, gl->GetFeatureName(), NULL);
+        options = NULL;
+        rdr = svcFeature->SelectFeatures(featResId, gl->GetFeatureName(), options);
     }
 
-    return SAFE_ADDREF(rdr.p);
+    return new RSMgFeatureReader(rdr.p, svcFeature, featResId.p, options, L"clipped_raster");
 }
 
+MgStylizationUtil::TransformCache* MgStylizationUtil::GetLayerToMapTransform(TransformCacheMap& cache,
+                                                         CREFSTRING featureName,
+                                                         MgResourceIdentifier* resId,
+                                                         MgCoordinateSystem* dstCs,
+                                                         MgCoordinateSystemFactory* csFactory,
+                                                         MgFeatureService* svcFeature)
+{
+    TransformCache* item = NULL;
 
+    // Now get the coordinate system of the layer data.
+    // Feature Service caches these so we only take the performance hit on
+    // the 1st one that is not cached.
+
+    // Parse the feature name for the schema and class
+    STRING::size_type nDelimiter = featureName.find(L":");
+    STRING schemaName;
+    STRING className;
+
+    if(STRING::npos == nDelimiter)
+    {
+        schemaName = L"";
+        className = featureName;
+    }
+    else
+    {
+        schemaName = featureName.substr(0, nDelimiter);
+        className = featureName.substr(nDelimiter + 1);
+    }
+
+    STRING spatialContextAssociation = L"";
+
+    // Get the class definition so that we can find the spatial context association
+    Ptr<MgClassDefinition> classDef = svcFeature->GetClassDefinition(resId, schemaName, className);
+    Ptr<MgPropertyDefinitionCollection> propDefCol = classDef->GetProperties();
+
+    // Find the spatial context for the geometric property. Use the first one if there are many defined.
+    for(int index=0;index<propDefCol->GetCount();index++)
+    {
+        Ptr<MgPropertyDefinition> propDef = propDefCol->GetItem(index);
+        if (propDef->GetPropertyType () == MgFeaturePropertyType::GeometricProperty)
+        {
+            // We found the geometric property
+            MgGeometricPropertyDefinition* geomProp = static_cast<MgGeometricPropertyDefinition*>(propDef.p);
+            spatialContextAssociation = geomProp->GetSpatialContextAssociation();
+            break;
+        }
+    }
+
+    // We want all of the spatial contexts
+    Ptr<MgSpatialContextReader> csrdr = svcFeature->GetSpatialContexts(resId, false);
+
+    // This is the strategy we use for picking the spatial context
+    // Find the 1st spatial context that satisfies one of the following: (Processed in order)
+    // 1) Matches the association spatial context name
+    // 2) The 1st spatial context returned
+    // 3) FAIL - none of the above could be satisfied
+
+    Ptr<MgCoordinateSystem> srcCs = (MgCoordinateSystem*)NULL;
+
+    if (dstCs)
+    {
+        STRING srcwkt = L"";
+        STRING csrName = L"";
+        bool bHaveFirstSpatialContext = false;
+
+        while(csrdr->ReadNext())
+        {
+            csrName = csrdr->GetName();
+            if((!spatialContextAssociation.empty()) && (csrName == spatialContextAssociation))
+            {
+                // Match found for the association)
+                srcwkt = csrdr->GetCoordinateSystemWkt();
+                break;
+            }
+            else if(!bHaveFirstSpatialContext)
+            {
+                // This is the 1st spatial context returned
+                // This will be overwritten if we find the association
+                srcwkt = csrdr->GetCoordinateSystemWkt();
+                bHaveFirstSpatialContext = true;
+            }
+        }
+
+        // Create coordinate system transformer
+        if (!srcwkt.empty())
+        {
+            TransformCacheMap::const_iterator iter = cache.find(srcwkt);
+            if (cache.end() != iter) item = (*iter).second;
+            if (NULL == item)
+            {
+                Ptr<MgCoordinateSystem> srcCs = csFactory->Create(srcwkt);
+                if (srcCs.p)
+                {
+                    item = new TransformCache(new MgCSTrans(srcCs, dstCs), srcCs);
+                    cache[srcwkt] = item;
+                }
+            }
+        }
+    }
+    else
+    {
+        // No coordinate system!!!
+        // We fail here and do not use a default
+    }
+
+    return item;
+}
+
+
 void MgStylizationUtil::StylizeLayers(MgResourceService* svcResource,
                                       MgFeatureService* svcFeature,
                                       MgDrawingService* svcDrawing,
@@ -456,8 +566,6 @@
 
     for (int i = layers->GetCount()-1; i >= 0; i--)
     {
-        TransformCache* cached = NULL;
-        MgCSTrans* xformer = NULL;
         MdfModel::LayerDefinition* ldf = NULL;
 
         Ptr<MgLayerBase> mapLayer = layers->GetItem(i);
@@ -564,114 +672,9 @@
                         extent.maxy += mcsOffset;
                     }
 
-                    //now get the coordinate system of the layer data
-                    // Feature Service caches these so we only take the performance hit on
-                    // the 1st one that is not cached.
+                    //get a transform from layer coord sys to map coord sys
+                    TransformCache* item = GetLayerToMapTransform(transformCache, vl->GetFeatureName(), featResId, dstCs, csFactory, svcFeature);
 
-                    // Need to determine the name of the spatial context for this layer
-                    MdfModel::MdfString featureName = vl->GetFeatureName();
-
-                    // Parse the feature name for the schema and class
-                    STRING::size_type nDelimiter = featureName.find(L":");
-                    STRING schemaName;
-                    STRING className;
-
-                    if(STRING::npos == nDelimiter)
-                    {
-                        schemaName = L"";
-                        className = featureName;
-                    }
-                    else
-                    {
-                        schemaName = featureName.substr(0, nDelimiter);
-                        className = featureName.substr(nDelimiter + 1);
-                    }
-
-                    STRING spatialContextAssociation = L"";
-
-                    // Get the class definition so that we can find the spatial context association
-                    Ptr<MgClassDefinition> classDef = svcFeature->GetClassDefinition(featResId, schemaName, className);
-                    Ptr<MgPropertyDefinitionCollection> propDefCol = classDef->GetProperties();
-
-                    // Find the spatial context for the geometric property. Use the first one if there are many defined.
-                    for(int index=0;index<propDefCol->GetCount();index++)
-                    {
-                        Ptr<MgPropertyDefinition> propDef = propDefCol->GetItem(index);
-                        if (propDef->GetPropertyType () == MgFeaturePropertyType::GeometricProperty)
-                        {
-                            // We found the geometric property
-                            MgGeometricPropertyDefinition* geomProp = static_cast<MgGeometricPropertyDefinition*>(propDef.p);
-                            spatialContextAssociation = geomProp->GetSpatialContextAssociation();
-                            break;
-                        }
-                    }
-
-                    // We want all of the spatial contexts
-                    Ptr<MgSpatialContextReader> csrdr = svcFeature->GetSpatialContexts(featResId, false);
-
-                    // This is the strategy we use for picking the spatial context
-                    // Find the 1st spatial context that satisfies one of the following: (Processed in order)
-                    // 1) Matches the association spatial context name
-                    // 2) The 1st spatial context returned
-                    // 3) FAIL - none of the above could be satisfied
-
-                    Ptr<MgCoordinateSystem> srcCs = (MgCoordinateSystem*)NULL;
-
-                    if (dstCs)
-                    {
-                        STRING srcwkt = L"";
-                        STRING csrName = L"";
-                        bool bHaveFirstSpatialContext = false;
-
-                        while(csrdr->ReadNext())
-                        {
-                            csrName = csrdr->GetName();
-                            if((!spatialContextAssociation.empty()) && (csrName == spatialContextAssociation))
-                            {
-                                // Match found for the association)
-                                srcwkt = csrdr->GetCoordinateSystemWkt();
-                                break;
-                            }
-                            else if(!bHaveFirstSpatialContext)
-                            {
-                                // This is the 1st spatial context returned
-                                // This will be overwritten if we find the association
-                                srcwkt = csrdr->GetCoordinateSystemWkt();
-                                bHaveFirstSpatialContext = true;
-                            }
-                        }
-
-                        // Create coordinate system transformer
-                        if (!srcwkt.empty())
-                        {
-                            
-                            TransformCacheMap::const_iterator iter = transformCache.find(srcwkt);
-                            if (transformCache.end() != iter) cached = (*iter).second;
-                            if (NULL != cached)
-                            {
-                                srcCs = cached->GetCoordSys();
-                                xformer = cached->GetTransform();
-                            }
-                            else 
-                            {
-                                srcCs = csFactory->Create(srcwkt);
-                                if (srcCs.p)
-                                {
-                                    xformer = new MgCSTrans(srcCs, dstCs);
-                                    cached = new TransformCache(xformer, srcCs);
-                                    transformCache[srcwkt] = cached;
-                                }
-                            }
-                            
-                        }
-
-                    }
-                    else
-                    {
-                        // No coordinate system!!!
-                        // We fail here and do not use a default
-                    }
-
                     //extract hyperlink and tooltip info
                     if (!vl->GetToolTip().empty()) legendInfo.hastooltips() = true;
                     if (!vl->GetUrl().empty()) legendInfo.hashyperlinks() = true;
@@ -746,14 +749,12 @@
                         //we are not drawing the actual geometry
                         if (maxStrokes == 0)
                         {
-                            Ptr<MgFeatureReader> rdr = ExecuteFeatureQuery(svcFeature, extent, vl, overrideFilter.c_str(), dstCs, srcCs, cached);
-                            if (rdr.p)
+                            RSMgFeatureReader* rdr = ExecuteFeatureQuery(svcFeature, extent, vl, overrideFilter.c_str(), dstCs, item ? item->GetCoordSys() : NULL, item);
+                            if (rdr)
                             {
-                                //wrap the MgFeatureReader in our RSMgFeatureReader wrapper
-                                RSMgFeatureReader rsrdr(rdr, vl->GetGeometry());
-
-                                ds->StylizeFeatures(vl, &rsrdr, xformer, NULL, NULL);
+                                ds->StylizeFeatures(vl, rdr, item->GetTransform(), NULL, NULL);
                             }
+                            delete rdr;
                         }
                         else
                         {
@@ -782,14 +783,12 @@
                                     syms->Adopt(syms2->GetAt(min(i, syms2->GetCount()-1)));
                                 }
 
-                                Ptr<MgFeatureReader> rdr = ExecuteFeatureQuery(svcFeature, extent, vl, overrideFilter.c_str(), dstCs, srcCs, cached);
-                                if (rdr.p)
+                                RSMgFeatureReader* rdr = ExecuteFeatureQuery(svcFeature, extent, vl, overrideFilter.c_str(), dstCs, item ? item->GetCoordSys() : NULL, item);
+                                if (rdr)
                                 {
-                                    //wrap in an RS_FeatureReader
-                                    RSMgFeatureReader rsrdr(rdr, vl->GetGeometry());
-
-                                    ds->StylizeFeatures(vl, &rsrdr, xformer, NULL, NULL);
+                                    ds->StylizeFeatures(vl, rdr, item->GetTransform(), NULL, NULL);
                                 }
+                                delete rdr;
 
                                 //transfer line styles back to layer definition
                                 for (int m=0; m<rules->GetCount(); m++)
@@ -828,17 +827,15 @@
                     }
                     else
                     {
-                        Ptr<MgFeatureReader> rdr = ExecuteFeatureQuery(svcFeature, extent, vl, overrideFilter.c_str(), dstCs, srcCs, cached);
-                        if (rdr.p)
+                        RSMgFeatureReader* rdr = ExecuteFeatureQuery(svcFeature, extent, vl, overrideFilter.c_str(), dstCs, item ? item->GetCoordSys() : NULL, item);
+                        if (rdr)
                         {
-                            //wrap the MgFeatureReader in our RSMgFeatureReader wrapper
-                            RSMgFeatureReader rsrdr(rdr, vl->GetGeometry());
-
                             //stylize into output format
                             dr->StartLayer(&legendInfo, &fcinfo);
-                            ds->StylizeFeatures(vl, &rsrdr, xformer, NULL, NULL);
+                            ds->StylizeFeatures(vl, rdr, item ? item->GetTransform() : NULL, NULL, NULL);
                             dr->EndLayer();
                         }
+                        delete rdr;
                     }
                 }
                 else
@@ -877,105 +874,9 @@
                     // Need to determine the name of the spatial context for this layer
                     MdfModel::MdfString featureName = gl->GetFeatureName();
 
-                    // Parse the feature name for the schema and class
-                    STRING::size_type nDelimiter = featureName.find(L":");
-                    STRING schemaName;
-                    STRING className;
+                    //get a transform from layer coord sys to map coord sys
+                    TransformCache* item = GetLayerToMapTransform(transformCache, gl->GetFeatureName(), featResId, dstCs, csFactory, svcFeature);
 
-                    if(STRING::npos == nDelimiter)
-                    {
-                        schemaName = L"";
-                        className = featureName;
-                    }
-                    else
-                    {
-                        schemaName = featureName.substr(0, nDelimiter);
-                        className = featureName.substr(nDelimiter + 1);
-                    }
-
-                    STRING spatialContextAssociation = L"";
-
-                    // Get the class definition so that we can find the spatial context association
-                    Ptr<MgClassDefinition> classDef = svcFeature->GetClassDefinition(featResId, schemaName, className);
-                    Ptr<MgPropertyDefinitionCollection> propDefCol = classDef->GetProperties();
-
-                    // Find the spatial context for the geometric property. Use the first one if there are many defined.
-                    for(int index=0;index<propDefCol->GetCount();index++)
-                    {
-                        Ptr<MgPropertyDefinition> propDef = propDefCol->GetItem(index);
-                        if (propDef->GetPropertyType () == MgFeaturePropertyType::GeometricProperty)
-                        {
-                            // We found the geometric property
-                            MgGeometricPropertyDefinition* geomProp = static_cast<MgGeometricPropertyDefinition*>(propDef.p);
-                            spatialContextAssociation = geomProp->GetSpatialContextAssociation();
-                            break;
-                        }
-                    }
-
-                    // We want all of the spatial contexts
-                    Ptr<MgSpatialContextReader> csrdr = svcFeature->GetSpatialContexts(featResId, false);
-
-                    // This is the strategy we use for picking the spatial context
-                    // Find the 1st spatial context that satisfies one of the following: (Processed in order)
-                    // 1) Matches the association spatial context name
-                    // 2) The 1st spatial context returned
-                    // 3) FAIL - none of the above could be satisfied
-
-                    Ptr<MgCoordinateSystem> srcCs = (MgCoordinateSystem*)NULL;
-
-                    if (dstCs)
-                    {
-                        STRING srcwkt = L"";
-                        STRING csrName = L"";
-                        bool bHaveFirstSpatialContext = false;
-
-                        while(csrdr->ReadNext())
-                        {
-                            csrName = csrdr->GetName();
-                            if((!spatialContextAssociation.empty()) && (csrName == spatialContextAssociation))
-                            {
-                                // Match found for the association)
-                                srcwkt = csrdr->GetCoordinateSystemWkt();
-                                break;
-                            }
-                            else if(!bHaveFirstSpatialContext)
-                            {
-                                // This is the 1st spatial context returned
-                                // This will be overwritten if we find the association
-                                srcwkt = csrdr->GetCoordinateSystemWkt();
-                                bHaveFirstSpatialContext = true;
-                            }
-                        }
-
-                        // Create coordinate system transformer
-                        if (!srcwkt.empty())
-                        {
-                            TransformCacheMap::const_iterator iter = transformCache.find(srcwkt);
-                            if (transformCache.end() != iter) cached = (*iter).second;
-                            if (NULL != cached)
-                            {
-                                srcCs = cached->GetCoordSys();
-                                xformer = cached->GetTransform();
-                            }
-                            else 
-                            {
-                                srcCs = csFactory->Create(srcwkt);
-                                if (srcCs.p)
-                                {
-                                    xformer = new MgCSTrans(srcCs, dstCs);
-                                    cached = new TransformCache(xformer, srcCs);
-                                    transformCache[srcwkt] = cached;
-                                }
-                            }
-                            
-                        }
-                    }
-                    else
-                    {
-                        // No coordinate system!!!
-                        // We fail here and do not use a default
-                    }
-
                     //grid layer does not yet have hyperlink or tooltip
                     //extract hyperlink and tooltip info
                     //if (!gl->GetToolTip().empty()) legendInfo.hastooltips() = true;
@@ -1018,23 +919,15 @@
                     }
 
                     //perform the raster query
-                    Ptr<MgFeatureReader> rdr = ExecuteRasterQuery(svcFeature, extent, gl, overrideFilter.c_str(), dstCs, srcCs, width, height);
-                    if (rdr.p)
+                    RSMgFeatureReader* rdr = ExecuteRasterQuery(svcFeature, extent, gl, overrideFilter.c_str(), dstCs, item ? item->GetCoordSys() : NULL, width, height);
+                    if (rdr)
                     {
-                        //wrap the MgFeatureReader in our RSMgFeatureReader wrapper
-                        //TODO: For raster layers we need to check for the "Image" property name
-                        //and replace that by clipped_raster which is the computed geometry
-                        //property we are using instead of the actual raster property
-                        //Post-preview we should write code to get the feature schema
-                        //and examine that for raster properties.
-                        //const MdfModel::MdfString& flgeom = gl->GetGeometry();
-                        RSMgFeatureReader rsrdr(rdr, L"clipped_raster");
-
                         //stylize into a dwf
                         dr->StartLayer(&legendInfo, &fcinfo);
-                        ds->StylizeGridLayer(gl, &rsrdr, xformer, NULL, NULL);
+                        ds->StylizeGridLayer(gl, rdr, item->GetTransform(), NULL, NULL);
                         dr->EndLayer();
                     }
+                    delete rdr;
                 }
 
                 #ifdef _DEBUG
@@ -1060,6 +953,9 @@
                     size_t i0 = st.find(L"<CoordinateSpace>");
                     size_t i1 = st.find(L"</CoordinateSpace>");
 
+                    TransformCache* cached = NULL;
+                    MgCSTrans* xformer = NULL;
+
                     if (   i0 != STRING::npos
                         && i1 != STRING::npos)
                     {
@@ -1075,7 +971,7 @@
                             {
                                 xformer = cached->GetTransform();
                             }
-                            else 
+                            else
                             {
                                 Ptr<MgCoordinateSystem> srcCs = csFactory->Create(cs);
                                 if (srcCs.p)
@@ -1142,7 +1038,6 @@
             delete ldf;
             ldf = NULL;
         }
-
     }
 
     #ifdef _DEBUG
@@ -1662,9 +1557,25 @@
                                         }
 
                                         //override colors
-                                        ParseColor(marksym->GetFill()->GetForegroundColor(), mdef.style().color());
-                                        ParseColor(marksym->GetEdge()->GetColor(), mdef.style().outline().color());
-                                        ParseColor(marksym->GetFill()->GetBackgroundColor(), mdef.style().background());
+                                        if (marksym->GetFill())
+                                        {
+                                            ParseColor(marksym->GetFill()->GetForegroundColor(), mdef.style().color());
+                                            ParseColor(marksym->GetFill()->GetBackgroundColor(), mdef.style().background());
+                                        }
+                                        else
+                                        {
+                                            mdef.style().color() = RS_Color(RS_Color::EMPTY_COLOR_RGBA);
+                                            mdef.style().background() = RS_Color(RS_Color::EMPTY_COLOR_RGBA);
+                                        }
+
+                                        if (marksym->GetEdge())
+                                        {
+                                            ParseColor(marksym->GetEdge()->GetColor(), mdef.style().outline().color());
+                                        }
+                                        else
+                                        {
+                                            mdef.style().outline().color() = RS_Color(RS_Color::EMPTY_COLOR_RGBA);
+                                        }
                                     }
                                     break;
                                 case SymbolVisitor::stFont:
@@ -1692,8 +1603,8 @@
                                         ParseColor(fontSym->GetForegroundColor(), mdef.style().color());
                                     }
                                 //TODO: other types of symbols
-                                default: break;
-
+                                default:
+                                    break;
                                 }
                             }
                         }

Modified: trunk/MgDev/Server/src/Services/Mapping/StylizationUtil.h
===================================================================
--- trunk/MgDev/Server/src/Services/Mapping/StylizationUtil.h	2007-03-06 17:02:52 UTC (rev 1157)
+++ trunk/MgDev/Server/src/Services/Mapping/StylizationUtil.h	2007-03-06 23:31:17 UTC (rev 1158)
@@ -33,6 +33,7 @@
 class MgMap;
 class MgCoordinateSystem;
 class MgCSTrans;
+class RSMgFeatureReader;
 
 //Common stylization utility code -- used by both the mapping and rendering services
 class MG_SERVER_MAPPING_API MgStylizationUtil
@@ -77,7 +78,7 @@
                               double scale,
                               bool selection = false);
 
-    static MgFeatureReader * ExecuteFeatureQuery(MgFeatureService* svcFeature,
+    static RSMgFeatureReader * ExecuteFeatureQuery(MgFeatureService* svcFeature,
                                                  RS_Bounds& extent,
                                                  MdfModel::VectorLayerDefinition* vl,
                                                  const wchar_t* overrideFilter,
@@ -85,7 +86,7 @@
                                                  MgCoordinateSystem* layerCs,
                                                  TransformCache* cache);
 
-    static MgFeatureReader * ExecuteRasterQuery(MgFeatureService* svcFeature,
+    static RSMgFeatureReader * ExecuteRasterQuery(MgFeatureService* svcFeature,
                                                 RS_Bounds& extent,
                                                 MdfModel::GridLayerDefinition* gl,
                                                 const wchar_t* overrideFilter,
@@ -94,6 +95,12 @@
                                                 int width,
                                                 int height);
 
+    static MgStylizationUtil::TransformCache* MgStylizationUtil::GetLayerToMapTransform(TransformCacheMap& cache,
+                                                         CREFSTRING featureName,
+                                                         MgResourceIdentifier* resId,
+                                                         MgCoordinateSystem* dstCs,
+                                                         MgCoordinateSystemFactory* csFactory,
+                                                         MgFeatureService* svcFeature);
 
     static MdfModel::MapDefinition* GetMapDefinition(MgResourceService* svcResource, MgResourceIdentifier* resId);
     static MdfModel::LayerDefinition* GetLayerDefinition(MgResourceService* svcResource, MgResourceIdentifier* resId);

Modified: trunk/MgDev/Server/src/Services/Rendering/ServerRenderingService.cpp
===================================================================
--- trunk/MgDev/Server/src/Services/Rendering/ServerRenderingService.cpp	2007-03-06 17:02:52 UTC (rev 1157)
+++ trunk/MgDev/Server/src/Services/Rendering/ServerRenderingService.cpp	2007-03-06 23:31:17 UTC (rev 1158)
@@ -24,14 +24,11 @@
 #include "RSMgSymbolManager.h"
 #include "RSMgFeatureReader.h"
 #include "FeatureInfoRenderer.h"
-
+#include "SEMgSymbolManager.h"
 #include "StylizationUtil.h"
-
-
 #include "LegendPlotUtil.h"
 
 
-
 // the maximum number of allowed pixels for rendered images
 static const INT32 MAX_PIXELS = 16384*16384;
 
@@ -636,8 +633,10 @@
     RSMgSymbolManager mgr(m_svcResource);
     dr->SetSymbolManager(&mgr);
 
+    SEMgSymbolManager semgr(m_svcResource);
+
     DefaultStylizer ds;
-    ds.Initialize(dr);
+    ds.Initialize(dr, &semgr);
 
     RS_Color bgcolor(0, 0, 0, 255); //not used -- GDRenderer is already initialized to the correct bgcolor
 
@@ -1056,7 +1055,7 @@
 
                 // TODO: can FeatureName be an extension name rather than a FeatureClass?
                 Ptr<MgFeatureReader> rdr = m_svcFeature->SelectFeatures(featResId, vl->GetFeatureName(), options);
-                RSMgFeatureReader rsrdr(rdr, vl->GetGeometry());
+                RSMgFeatureReader rsrdr(rdr, m_svcFeature, featResId, options, vl->GetGeometry());
 
                 DefaultStylizer ds;
                 ds.Initialize(selRenderer);



More information about the mapguide-commits mailing list