[mapguide-commits] r4973 - in trunk/MgDev/Common: Renderers
Stylization
svn_mapguide at osgeo.org
svn_mapguide at osgeo.org
Sat Jun 26 04:47:02 EDT 2010
Author: waltweltonlair
Date: 2010-06-26 08:47:02 +0000 (Sat, 26 Jun 2010)
New Revision: 4973
Modified:
trunk/MgDev/Common/Renderers/AGGW2DRewriter.cpp
trunk/MgDev/Common/Renderers/GDRenderer.cpp
trunk/MgDev/Common/Renderers/GDRenderer.h
trunk/MgDev/Common/Renderers/GDW2DRewriter.cpp
trunk/MgDev/Common/Stylization/LineBuffer.cpp
trunk/MgDev/Common/Stylization/LineBuffer.h
Log:
Fix #1338 (Stray linework being drawn)
The rendering code which handled WT_Ellipse Whip op-codes was not taking into account
the tilt angle of the ellipse (the overall rotation of the ellipse / elliptical arc).
It now does.
To implement this I extended the LineBuffer::ArcTo method to take an additional optional
argument specifying the rotation angle of the arc.
Modified: trunk/MgDev/Common/Renderers/AGGW2DRewriter.cpp
===================================================================
--- trunk/MgDev/Common/Renderers/AGGW2DRewriter.cpp 2010-06-26 04:45:17 UTC (rev 4972)
+++ trunk/MgDev/Common/Renderers/AGGW2DRewriter.cpp 2010-06-26 08:47:02 UTC (rev 4973)
@@ -367,9 +367,9 @@
color = override;
}
- WT_Logical_Point oldpos = filledEllipse.position();
+ WT_Logical_Point center = filledEllipse.position();
- LineBuffer* dstpts = rewriter->ProcessW2DPoints(file, (WT_Logical_Point*)&oldpos, 1, false);
+ LineBuffer* dstpts = rewriter->ProcessW2DPoints(file, (WT_Logical_Point*)¢er, 1, false);
std::auto_ptr<LineBuffer> spDstLB(dstpts);
if (!dstpts)
@@ -378,15 +378,24 @@
double major = rewriter->ScaleW2DNumber(file, filledEllipse.major());
double minor = rewriter->ScaleW2DNumber(file, filledEllipse.minor());
- double start = filledEllipse.start_degree() * (M_PI / 180.0);
- double end = filledEllipse.end_degree() * (M_PI / 180.0);
+ double start = filledEllipse.start_radian();
+ double end = filledEllipse.end_radian();
+ double tilt = filledEllipse.tilt_radian();
+ // compute start point
+ double rcos = cos(tilt);
+ double rsin = sin(tilt);
+ double tx = major * cos(start);
+ double ty = minor * sin(start);
+ double startX = dstpts->x_coord(0) + tx*rcos - ty*rsin;
+ double startY = dstpts->y_coord(0) + ty*rcos + tx*rsin;
+
LineBuffer* ell = LineBufferPool::NewLineBuffer(rewriter->GetBufferPool(), 20);
std::auto_ptr<LineBuffer> spEllLB(ell);
ell->SetDrawingScale(1.0);
- ell->MoveTo(dstpts->x_coord(0) + major * cos(start), dstpts->y_coord(0) + minor * sin(start));
- ell->ArcTo(dstpts->x_coord(0), dstpts->y_coord(0), major, minor, start, end);
+ ell->MoveTo(startX, startY);
+ ell->ArcTo(dstpts->x_coord(0), dstpts->y_coord(0), major, minor, start, end, tilt);
AGGRenderer::DrawScreenPolygon((agg_context*)rewriter->GetW2DTargetImage(), ell, NULL, color.argb());
@@ -419,9 +428,9 @@
color = override;
}
- WT_Logical_Point oldpos = outlineEllipse.position();
+ WT_Logical_Point center = outlineEllipse.position();
- LineBuffer* dstpts = rewriter->ProcessW2DPoints(file, (WT_Logical_Point*)&oldpos, 1, false);
+ LineBuffer* dstpts = rewriter->ProcessW2DPoints(file, (WT_Logical_Point*)¢er, 1, false);
std::auto_ptr<LineBuffer> spDstLB(dstpts);
if (!dstpts)
@@ -430,20 +439,29 @@
double major = rewriter->ScaleW2DNumber(file, outlineEllipse.major());
double minor = rewriter->ScaleW2DNumber(file, outlineEllipse.minor());
- double start = outlineEllipse.start_degree() * (M_PI / 180.0);
- double end = outlineEllipse.end_degree() * (M_PI / 180.0);
+ double start = outlineEllipse.start_radian();
+ double end = outlineEllipse.end_radian();
+ double tilt = outlineEllipse.tilt_radian();
- //get W2D line weight
- double weightpx = rewriter->ScaleW2DNumber(file, file.rendition().line_weight().weight_value());
- weightpx = rs_max(1.0, weightpx);
+ // compute start point
+ double rcos = cos(tilt);
+ double rsin = sin(tilt);
+ double tx = major * cos(start);
+ double ty = minor * sin(start);
+ double startX = dstpts->x_coord(0) + tx*rcos - ty*rsin;
+ double startY = dstpts->y_coord(0) + ty*rcos + tx*rsin;
LineBuffer* ell = LineBufferPool::NewLineBuffer(rewriter->GetBufferPool(), 20);
std::auto_ptr<LineBuffer> spEllLB(ell);
ell->SetDrawingScale(1.0);
- ell->MoveTo(dstpts->x_coord(0) + major * cos(start), dstpts->y_coord(0) + minor * sin(start));
- ell->ArcTo(dstpts->x_coord(0), dstpts->y_coord(0), major, minor, start, end);
+ ell->MoveTo(startX, startY);
+ ell->ArcTo(dstpts->x_coord(0), dstpts->y_coord(0), major, minor, start, end, tilt);
+ //get W2D line weight
+ double weightpx = rewriter->ScaleW2DNumber(file, file.rendition().line_weight().weight_value());
+ weightpx = rs_max(1.0, weightpx);
+
SE_LineStroke lineStroke(color.argb(), weightpx);
AGGRenderer::DrawScreenPolyline((agg_context*)rewriter->GetW2DTargetImage(), ell, NULL, lineStroke);
@@ -857,6 +875,7 @@
return WT_Result::Success;
}
+
WT_Result agr_process_layer(WT_Layer & layer, WT_File & file)
{
AGGRenderer* rewriter = (AGGRenderer*)file.stream_user_data();
Modified: trunk/MgDev/Common/Renderers/GDRenderer.cpp
===================================================================
--- trunk/MgDev/Common/Renderers/GDRenderer.cpp 2010-06-26 04:45:17 UTC (rev 4972)
+++ trunk/MgDev/Common/Renderers/GDRenderer.cpp 2010-06-26 08:47:02 UTC (rev 4973)
@@ -2204,6 +2204,15 @@
}
+// Fills and returns the point buffer using the supplied line buffer.
+// No transformations are applied.
+const RS_D_Point* GDRenderer::FillPointBuffer(LineBuffer* lb)
+{
+ _TransferPoints(lb, NULL);
+ return m_wtPointBuffer;
+}
+
+
void GDRenderer::UpdateSymbolTrans(WT_File& /*file*/, WT_Viewport& viewport)
{
_ASSERT(m_xformer);
Modified: trunk/MgDev/Common/Renderers/GDRenderer.h
===================================================================
--- trunk/MgDev/Common/Renderers/GDRenderer.h 2010-06-26 04:45:17 UTC (rev 4972)
+++ trunk/MgDev/Common/Renderers/GDRenderer.h 2010-06-26 08:47:02 UTC (rev 4973)
@@ -285,9 +285,9 @@
WT_Logical_Point* srcpts,
int numpts,
bool checkInBounds);
+ /*Do not export from DLL*/ double ScaleW2DNumber(WT_File& file, long number);
+ /*Do not export from DLL*/ const RS_D_Point* FillPointBuffer(LineBuffer* lb);
- /*Do not export from DLL*/ double ScaleW2DNumber(WT_File& file, long number);
-
private:
void AddW2DContent(RS_InputStream* in, CSysTransformer* xformer, const RS_String& w2dfilter);
Modified: trunk/MgDev/Common/Renderers/GDW2DRewriter.cpp
===================================================================
--- trunk/MgDev/Common/Renderers/GDW2DRewriter.cpp 2010-06-26 04:45:17 UTC (rev 4972)
+++ trunk/MgDev/Common/Renderers/GDW2DRewriter.cpp 2010-06-26 08:47:02 UTC (rev 4973)
@@ -410,37 +410,93 @@
color = override;
}
- WT_Logical_Point oldpos = filledEllipse.position();
+ WT_Logical_Point center = filledEllipse.position();
- const RS_D_Point* dstpts = rewriter->ProcessW2DPoints(file, (WT_Logical_Point*)&oldpos, 1, false);
+ const RS_D_Point* dstpts = rewriter->ProcessW2DPoints(file, (WT_Logical_Point*)¢er, 1, false);
- int major = ROUND(rewriter->ScaleW2DNumber(file, filledEllipse.major()));
- int minor = ROUND(rewriter->ScaleW2DNumber(file, filledEllipse.minor()));
+ //negate because GD is left-handed coords
+ double tilt = -filledEllipse.tilt_radian();
- //simple bounds check before we draw
- if ( !(dstpts[0].x + major < 0
- || dstpts[0].x - major > ((gdImagePtr)rewriter->GetW2DTargetImage())->sx
- || dstpts[0].y + minor < 0
- || dstpts[0].x - minor > ((gdImagePtr)rewriter->GetW2DTargetImage())->sy))
+ if (tilt == 0.0)
{
- //negate because GD is left-handed coords
- float end = 360.f - filledEllipse.start_degree();
- float start = 360.f - filledEllipse.end_degree();
+ // case where ellipse is unrotated
- //gd does not like negative angles (it's sin/cos lookup table doesn't)
- while (start < 0.f)
+ int major = ROUND(rewriter->ScaleW2DNumber(file, filledEllipse.major()));
+ int minor = ROUND(rewriter->ScaleW2DNumber(file, filledEllipse.minor()));
+
+ //simple bounds check before we draw
+ if ( !(dstpts[0].x + major < 0
+ || dstpts[0].x - major > ((gdImagePtr)rewriter->GetW2DTargetImage())->sx
+ || dstpts[0].y + minor < 0
+ || dstpts[0].x - minor > ((gdImagePtr)rewriter->GetW2DTargetImage())->sy))
{
- start += 360.f;
- end += 360.f;
+ //negate because GD is left-handed coords
+ float end = 360.f - filledEllipse.start_degree();
+ float start = 360.f - filledEllipse.end_degree();
+
+ //gd does not like negative angles (its sin/cos lookup table doesn't)
+ while (start < 0.f)
+ {
+ start += 360.f;
+ end += 360.f;
+ }
+
+ int gdc = ConvertColor((gdImagePtr)rewriter->GetW2DTargetImage(), color);
+ gdImageFilledArc((gdImagePtr)rewriter->GetW2DTargetImage(),
+ dstpts[0].x, dstpts[0].y,
+ major * 2, minor * 2,
+ (int)start, (int)end,
+ gdc, gdArc);
}
+ }
+ else
+ {
+ // case where ellipse is rotated
+ double rcos = cos(tilt);
+ double rsin = sin(tilt);
- //TODO: tilt. Need to tesselate into a line buffer in order to rotate.
- int gdc = ConvertColor((gdImagePtr)rewriter->GetW2DTargetImage(), color);
- gdImageFilledArc((gdImagePtr)rewriter->GetW2DTargetImage(),
- dstpts[0].x, dstpts[0].y,
- major, minor,
- (int)start, (int)end, //negate because GD is left-handed coords
- gdc, gdArc);
+ double major = rewriter->ScaleW2DNumber(file, filledEllipse.major());
+ double minor = rewriter->ScaleW2DNumber(file, filledEllipse.minor());
+
+ // the half-width / half-height of the bounding box for the rotated ellipse
+ int wid2 = (int)sqrt(major*major*rcos*rcos + minor*minor*rsin*rsin) + 1;
+ int hgt2 = (int)sqrt(major*major*rsin*rsin + minor*minor*rcos*rcos) + 1;
+
+ //simple bounds check before we draw
+ if ( !(dstpts[0].x + wid2 < 0
+ || dstpts[0].x - wid2 > ((gdImagePtr)rewriter->GetW2DTargetImage())->sx
+ || dstpts[0].y + hgt2 < 0
+ || dstpts[0].x - hgt2 > ((gdImagePtr)rewriter->GetW2DTargetImage())->sy))
+ {
+ //negate because GD is left-handed coords
+ double start = -filledEllipse.start_radian();
+ double end = -filledEllipse.end_radian();
+
+ // compute start point
+ double tx = major * cos(start);
+ double ty = minor * sin(start);
+ double startX = dstpts[0].x + tx*rcos - ty*rsin;
+ double startY = dstpts[0].y + ty*rcos + tx*rsin;
+
+ // use a line buffer to tessellate the arc
+ LineBuffer* ell = LineBufferPool::NewLineBuffer(rewriter->GetBufferPool(), 20);
+ std::auto_ptr<LineBuffer> spEllLB(ell);
+
+ ell->SetDrawingScale(1.0);
+ ell->MoveTo(startX, startY);
+ ell->ArcTo(dstpts[0].x, dstpts[0].y, major, minor, start, end, tilt);
+
+ int numpts = ell->point_count();
+ const RS_D_Point* dstpts = rewriter->FillPointBuffer(ell);
+
+ LineBufferPool::FreeLineBuffer(rewriter->GetBufferPool(), spEllLB.release());
+
+ int gdc = ConvertColor((gdImagePtr)rewriter->GetW2DTargetImage(), color);
+ gdImageFilledPolygon((gdImagePtr)rewriter->GetW2DTargetImage(),
+ (gdPointPtr)dstpts,
+ numpts,
+ gdc);
+ }
}
return WT_Result::Success;
@@ -469,62 +525,134 @@
color = override;
}
- WT_Logical_Point oldpos = outlineEllipse.position();
+ WT_Logical_Point center = outlineEllipse.position();
- const RS_D_Point* dstpts = rewriter->ProcessW2DPoints(file, (WT_Logical_Point*)&oldpos, 1, false);
+ const RS_D_Point* dstpts = rewriter->ProcessW2DPoints(file, (WT_Logical_Point*)¢er, 1, false);
- int major = ROUND(rewriter->ScaleW2DNumber(file, outlineEllipse.major()));
- int minor = ROUND(rewriter->ScaleW2DNumber(file, outlineEllipse.minor()));
+ //negate because GD is left-handed coords
+ double tilt = -outlineEllipse.tilt_radian();
- //simple bounds check before we draw
- if ( !(dstpts[0].x + major < 0
- || dstpts[0].x - major > ((gdImagePtr)rewriter->GetW2DTargetImage())->sx
- || dstpts[0].y + minor < 0
- || dstpts[0].x - minor > ((gdImagePtr)rewriter->GetW2DTargetImage())->sy))
+ if (tilt == 0.0)
{
- //negate because GD is left-handed coords
- float end = 360.f - outlineEllipse.start_degree();
- float start = 360.f - outlineEllipse.end_degree();
+ // case where ellipse is unrotated
- //gd does not like negative angles (it's sin/cos lookup table doesn't)
- while (start < 0.f)
+ int major = ROUND(rewriter->ScaleW2DNumber(file, outlineEllipse.major()));
+ int minor = ROUND(rewriter->ScaleW2DNumber(file, outlineEllipse.minor()));
+
+ //simple bounds check before we draw
+ if ( !(dstpts[0].x + major < 0
+ || dstpts[0].x - major > ((gdImagePtr)rewriter->GetW2DTargetImage())->sx
+ || dstpts[0].y + minor < 0
+ || dstpts[0].x - minor > ((gdImagePtr)rewriter->GetW2DTargetImage())->sy))
{
- start += 360.f;
- end += 360.f;
- }
+ //negate because GD is left-handed coords
+ float end = 360.f - outlineEllipse.start_degree();
+ float start = 360.f - outlineEllipse.end_degree();
- //TODO: tilt. Need to tesselate into a line buffer in order to rotate.
- int gdc = ConvertColor((gdImagePtr)rewriter->GetW2DTargetImage(), color);
+ //gd does not like negative angles (its sin/cos lookup table doesn't)
+ while (start < 0.f)
+ {
+ start += 360.f;
+ end += 360.f;
+ }
- ////////////////////////
- // handle thickness
+ ////////////////////////
+ // handle thickness
- //get W2D line weight
- int thick = ROUND(rewriter->ScaleW2DNumber(file, file.rendition().line_weight().weight_value()));
+ //get W2D line weight
+ int thick = ROUND(rewriter->ScaleW2DNumber(file, file.rendition().line_weight().weight_value()));
+ gdImagePtr brush1 = NULL;
- gdImagePtr brush1 = NULL;
+ if (thick > 1)
+ {
+ brush1 = rs_gdImageThickLineBrush(thick, color);
+ gdImageSetBrush((gdImagePtr)rewriter->GetW2DTargetImage(), brush1);
+ }
- if (thick > 1)
- {
- brush1 = rs_gdImageThickLineBrush(thick, color);
- gdImageSetBrush((gdImagePtr)rewriter->GetW2DTargetImage(), brush1);
+ int gdc = ConvertColor((gdImagePtr)rewriter->GetW2DTargetImage(), color);
+ gdImageArc((gdImagePtr)rewriter->GetW2DTargetImage(),
+ dstpts[0].x, dstpts[0].y,
+ major * 2, minor * 2,
+ (int)start, (int)end,
+ brush1 ? gdBrushed : gdc);
+
+ if (brush1)
+ {
+ gdImageSetBrush((gdImagePtr)rewriter->GetW2DTargetImage(), NULL);
+ gdImageDestroy(brush1);
+ }
}
+ }
+ else
+ {
+ // case where ellipse is rotated
+ double rcos = cos(tilt);
+ double rsin = sin(tilt);
- gdImageArc((gdImagePtr)rewriter->GetW2DTargetImage(),
- dstpts[0].x, dstpts[0].y,
- major * 2, minor * 2,
- (int)start, (int)end,
- brush1 ? gdBrushed : gdc);
+ double major = rewriter->ScaleW2DNumber(file, outlineEllipse.major());
+ double minor = rewriter->ScaleW2DNumber(file, outlineEllipse.minor());
- if (brush1)
+ // the half-width / half-height of the bounding box for the rotated ellipse
+ int wid2 = (int)sqrt(major*major*rcos*rcos + minor*minor*rsin*rsin) + 1;
+ int hgt2 = (int)sqrt(major*major*rsin*rsin + minor*minor*rcos*rcos) + 1;
+
+ //simple bounds check before we draw
+ if ( !(dstpts[0].x + wid2 < 0
+ || dstpts[0].x - wid2 > ((gdImagePtr)rewriter->GetW2DTargetImage())->sx
+ || dstpts[0].y + hgt2 < 0
+ || dstpts[0].x - hgt2 > ((gdImagePtr)rewriter->GetW2DTargetImage())->sy))
{
- gdImageSetBrush((gdImagePtr)rewriter->GetW2DTargetImage(), NULL);
- gdImageDestroy(brush1);
+ //negate because GD is left-handed coords
+ double start = -outlineEllipse.start_radian();
+ double end = -outlineEllipse.end_radian();
+
+ // compute start point
+ double tx = major * cos(start);
+ double ty = minor * sin(start);
+ double startX = dstpts[0].x + tx*rcos - ty*rsin;
+ double startY = dstpts[0].y + ty*rcos + tx*rsin;
+
+ // use a line buffer to tessellate the arc
+ LineBuffer* ell = LineBufferPool::NewLineBuffer(rewriter->GetBufferPool(), 20);
+ std::auto_ptr<LineBuffer> spEllLB(ell);
+
+ ell->SetDrawingScale(1.0);
+ ell->MoveTo(startX, startY);
+ ell->ArcTo(dstpts[0].x, dstpts[0].y, major, minor, start, end, tilt);
+
+ int numpts = ell->point_count();
+ const RS_D_Point* dstpts = rewriter->FillPointBuffer(ell);
+
+ LineBufferPool::FreeLineBuffer(rewriter->GetBufferPool(), spEllLB.release());
+
+ ////////////////////////
+ // handle thickness
+
+ //get W2D line weight
+ int thick = ROUND(rewriter->ScaleW2DNumber(file, file.rendition().line_weight().weight_value()));
+ gdImagePtr brush1 = NULL;
+
+ if (thick > 1)
+ {
+ brush1 = rs_gdImageThickLineBrush(thick, color);
+ gdImageSetBrush((gdImagePtr)rewriter->GetW2DTargetImage(), brush1);
+ }
+
+ int gdc = ConvertColor((gdImagePtr)rewriter->GetW2DTargetImage(), color);
+ gdImageOpenPolygon((gdImagePtr)rewriter->GetW2DTargetImage(),
+ (gdPointPtr)dstpts,
+ numpts,
+ brush1 ? gdBrushed : gdc);
+
+ if (brush1)
+ {
+ gdImageSetBrush((gdImagePtr)rewriter->GetW2DTargetImage(), NULL);
+ gdImageDestroy(brush1);
+ }
}
}
return WT_Result::Success;
-
}
Modified: trunk/MgDev/Common/Stylization/LineBuffer.cpp
===================================================================
--- trunk/MgDev/Common/Stylization/LineBuffer.cpp 2010-06-26 04:45:17 UTC (rev 4972)
+++ trunk/MgDev/Common/Stylization/LineBuffer.cpp 2010-06-26 08:47:02 UTC (rev 4973)
@@ -755,7 +755,7 @@
}
-void LineBuffer::ArcTo(double cx, double cy, double a, double b, double startRad, double endRad)
+void LineBuffer::ArcTo(double cx, double cy, double a, double b, double startRad, double endRad, double rotRad)
{
// store off arc start point index
EnsureArcsSpArray(2);
@@ -798,6 +798,10 @@
// get the angular separation corresponding to the number of segments
double dRad = extent / nSegs;
+ // account for the overall arc rotation
+ double rcos = cos(rotRad);
+ double rsin = sin(rotRad);
+
// add the segments
EnsurePoints(nSegs);
for (int i=1; i<=nSegs; ++i)
@@ -806,8 +810,8 @@
double tx = a * cos(ang);
double ty = b * sin(ang);
- double x = cx + tx;
- double y = cy + ty;
+ double x = cx + tx*rcos - ty*rsin;
+ double y = cy + ty*rcos + tx*rsin;
LineTo(x, y);
}
Modified: trunk/MgDev/Common/Stylization/LineBuffer.h
===================================================================
--- trunk/MgDev/Common/Stylization/LineBuffer.h 2010-06-26 04:45:17 UTC (rev 4972)
+++ trunk/MgDev/Common/Stylization/LineBuffer.h 2010-06-26 08:47:02 UTC (rev 4973)
@@ -105,7 +105,7 @@
// the fancy stuff
STYLIZATION_API void CircularArcTo(double midx, double midy, double endx, double endy);
STYLIZATION_API void CircularArcTo(double midx, double midy, double midz, double endx, double endy, double endz);
- STYLIZATION_API void ArcTo(double cx, double cy, double a, double b, double startRad, double endRad);
+ STYLIZATION_API void ArcTo(double cx, double cy, double a, double b, double startRad, double endRad, double rotRad = 0.0);
// STYLIZATION_API void QuadTo(double x2, double y2, double x3, double y3);
// STYLIZATION_API void CubicTo(double x2, double y2, double x3, double y3, double x4, double y4);
// STYLIZATION_API void AddEllipse(double cx, double cy, double a, double b);
More information about the mapguide-commits
mailing list