[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*)&center, 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*)&center, 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*)&center, 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*)&center, 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