[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 = ©_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