[mapguide-commits] r1353 - trunk/MgDev/Common/Stylization

svn_mapguide at osgeo.org svn_mapguide at osgeo.org
Thu Mar 22 21:54:26 EDT 2007


Author: jasonnogar
Date: 2007-03-22 21:54:26 -0400 (Thu, 22 Mar 2007)
New Revision: 1353

Added:
   trunk/MgDev/Common/Stylization/SE_LineStorage.cpp
   trunk/MgDev/Common/Stylization/SE_LineStorage.h
Modified:
   trunk/MgDev/Common/Stylization/Makefile.am
   trunk/MgDev/Common/Stylization/SE_IdentityJoin.cpp
   trunk/MgDev/Common/Stylization/SE_IdentityJoin.h
   trunk/MgDev/Common/Stylization/SE_MiterJoin.cpp
   trunk/MgDev/Common/Stylization/SE_MiterJoin.h
   trunk/MgDev/Common/Stylization/SE_PiecewiseTransform.h
   trunk/MgDev/Common/Stylization/Stylization.vcproj
Log:
Symbology:
 * Rewrite of the Join classes
   * Now supporting arbitrary # of joins on one symbol
   * Transform of entire linebuffers
   * Improved design.
   * Added to vcproj
 * SE_LineStorage
   * Moved out of LineBuffer.cpp into a separate file

Modified: trunk/MgDev/Common/Stylization/Makefile.am
===================================================================
--- trunk/MgDev/Common/Stylization/Makefile.am	2007-03-23 00:43:55 UTC (rev 1352)
+++ trunk/MgDev/Common/Stylization/Makefile.am	2007-03-23 01:54:26 UTC (rev 1353)
@@ -20,6 +20,7 @@
   SE_MiterJoin.cpp \
   SE_ExpressionBase.cpp \
   SE_LineBuffer.cpp \
+  SE_LineStorage.cpp \
   SE_PositioningAlgorithms.cpp \
   SE_Renderer.cpp \
   SE_StyleVisitor.cpp \
@@ -78,6 +79,7 @@
   SE_SymbolDefProxies.h \
   SE_RenderProxies.h \
   SE_LineBuffer.h \
+  SE_LineStorage.h \
   SE_Matrix.h \
   SE_PositioningAlgorithms.h \
   SE_Renderer.h \

Modified: trunk/MgDev/Common/Stylization/SE_IdentityJoin.cpp
===================================================================
--- trunk/MgDev/Common/Stylization/SE_IdentityJoin.cpp	2007-03-23 00:43:55 UTC (rev 1352)
+++ trunk/MgDev/Common/Stylization/SE_IdentityJoin.cpp	2007-03-23 01:54:26 UTC (rev 1353)
@@ -16,78 +16,123 @@
 //
 
 #include "SE_IdentityJoin.h"
+#include "SE_LineStorage.h"
 #include <float.h>
 
-SE_IdentityJoin::SE_IdentityJoin(RS_Bounds& bounds, double chop, bool end) :
-    m_chop(chop),
-    m_end(end),
-    m_identity_region(),
-    m_xf_bounds()
+SE_IdentityJoin::SE_IdentityJoin(RS_Bounds& bounds, double offset, const RS_F_Point& pt0, const RS_F_Point& pt1) :
+    m_xf_bounds(DBL_MAX, DBL_MAX, -DBL_MAX, -DBL_MAX),
+    m_xform()
 {
-    if (end)
+    RS_F_Point dp(pt1.x - pt0.x, pt1.y - pt0.y);
+    double len = sqrt(dp.x*dp.x + dp.y*dp.y);
+    double invlen = 1.0/len;
+    dp.x *= invlen;
+    dp.y *= invlen;
+    
+    /* Rotate around leading edge */
+    m_xform.translateX(-bounds.minx);
+    m_xform.rotate(dp.y, dp.x);
+    dp.x *= offset;
+    dp.y *= offset;
+    /* Position left edge offset pixels along the line from pt0 */
+    m_xform.translate(pt0.x + dp.x, pt0.y + dp.y);
+
+    m_bounds = bounds;
+    double underreach = len - bounds.width() - offset;
+    if (offset < 0)
     {
-        m_identity_region.minx = -DBL_MAX;
-        m_identity_region.maxx = bounds.maxx - chop;
-        m_xf_bounds.maxx = m_identity_region.maxx;
-        m_xf_bounds.minx = bounds.minx;
+        m_bounds.minx -= offset;
+        m_chop_start = m_bounds.minx;
     }
-    else
+    if (underreach < 0)
     {
-        m_identity_region.maxx = DBL_MAX;
-        m_identity_region.minx = bounds.minx + chop;
-        m_xf_bounds.minx = m_identity_region.minx;
-        m_xf_bounds.maxx = bounds.maxx;
+        m_bounds.maxx += underreach;
+        m_chop_end = m_bounds.maxx;
     }
-
-    m_identity_region.miny = -DBL_MAX;
-    m_identity_region.maxy = DBL_MAX;
-    m_xf_bounds.miny = bounds.miny;
-    m_xf_bounds.maxy = bounds.maxy;
 }
 
-RS_Bounds* SE_IdentityJoin::GetIdentityRegions(int &length)
-{
-    length = 1;
-    return &m_identity_region;
-}
-
 RS_F_Point* SE_IdentityJoin::GetDiscontinuities(int &length)
 {
     length = 0;
     return NULL;
 }
 
-RS_Bounds* SE_IdentityJoin::GetNonlinearRegions(int &length)
+RS_Bounds& SE_IdentityJoin::GetTransformedBounds()
 {
-    length = 0;
-    return NULL;
+    if (!m_xf_bounds.IsValid() && m_bounds.IsValid())
+    {
+        RS_F_Point xfpt;
+        
+        xfpt.x = m_bounds.minx;
+        xfpt.y = m_bounds.miny;
+        m_xform.transform(xfpt.x, xfpt.y);
+        m_xf_bounds.add_point(xfpt);
+
+        xfpt.x = m_bounds.minx;
+        xfpt.y = m_bounds.maxy;
+        m_xform.transform(xfpt.x, xfpt.y);
+        m_xf_bounds.add_point(xfpt);
+
+        xfpt.x = m_bounds.maxx;
+        xfpt.y = m_bounds.miny;
+        m_xform.transform(xfpt.x, xfpt.y);
+        m_xf_bounds.add_point(xfpt);
+
+        xfpt.x = m_bounds.maxx;
+        xfpt.y = m_bounds.maxy;
+        m_xform.transform(xfpt.x, xfpt.y);
+        m_xf_bounds.add_point(xfpt);
+    }
+
+    return m_xf_bounds;
 }
 
-RS_Bounds& SE_IdentityJoin::GetTransformedBounds()
+void SE_IdentityJoin::GetXChop(double& startx, double& endx)
 {
-    return m_xf_bounds;
+    startx = m_chop_start;
+    endx = m_chop_end;
 }
 
-double SE_IdentityJoin::GetXChop(bool &chopEnd)
+RS_F_Point* SE_IdentityJoin::Transform(const RS_F_Point& pt0, const RS_F_Point& pt1, int& length)
 {
-    chopEnd = m_end;
-    return m_chop;
+    length = 2;
+    m_xform.transform(pt0.x, pt0.y, m_points[0].x, m_points[0].y);
+    m_xform.transform(pt1.x, pt1.y, m_points[1].x, m_points[1].y);
+    return m_points;
 }
 
-void SE_IdentityJoin::Transform(double& /*x*/, double& /*y*/, SE_TransformInfo* info)
+void SE_IdentityJoin::Transform(SE_LineStorage* source, SE_LineStorage* dest, bool closed)
 {
-    if (info)
-    {
-        info->dXdx = 1.0;
-        info->dYdy = 1.0;
 
-        info->dYdx = 0.0;
-        info->dXdy = 0.0;
-        info->d2Xdx2 = 0.0;
-        info->d2Ydx2 = 0.0;
-        info->d2Xdy2 = 0.0;
-        info->d2Ydy2 = 0.0;
-        info->d2Xdxdy = 0.0;
-        info->d2Ydxdy = 0.0;
+    const RS_Bounds& bounds = source->bounds();
+    if (bounds.minx < m_chop_start || bounds.maxx > m_chop_end)
+    {   /* Chopping may be required */
+        dest->SetChopInfo(m_chop_start, m_chop_end, closed);
+        
+        int n_cntrs = source->cntr_count();
+        int* contours = source->cntrs();
+        double* src = source->points();
+
+        for (int i = 0; i < n_cntrs; i++)
+        {
+            double x, y;
+            double* last = src + 2*contours[i];
+            x = *src++;
+            y = *src++;
+            dest->EnsureContours(1);
+            dest->EnsurePoints(1);
+            dest->_MoveTo(x, y);
+
+            while (src < last)
+            {
+                x = *src++;
+                y = *src++;
+                dest->EnsurePoints(1);
+                dest->_LineTo(x, y);
+            }
+        }
+        dest->Transform(m_xform);
     }
+    else
+        dest->SetToTransform(m_xform, source);
 }

Modified: trunk/MgDev/Common/Stylization/SE_IdentityJoin.h
===================================================================
--- trunk/MgDev/Common/Stylization/SE_IdentityJoin.h	2007-03-23 00:43:55 UTC (rev 1352)
+++ trunk/MgDev/Common/Stylization/SE_IdentityJoin.h	2007-03-23 01:54:26 UTC (rev 1353)
@@ -19,30 +19,37 @@
 #define SE_IDENTITYJOIN_H
 
 #include "SE_PiecewiseTransform.h"
+#include "SE_Matrix.h"
 
 class SE_IdentityJoin : public SE_PiecewiseTransform
 {
 public:
     /* bounds:  The bounds of the symbol.
-     * chop:    The amount to remove in pixel units
-     * end:     The symbol is truncated backwards from maxx if true, or forwards from minx if not
+     * offset:  The distance along the line in pixels from pt0 to the beginning of the symbol
+     * pt0:     The start point of the line segment
+     * pt1:     The end point of the line segment
      */
-    SE_IdentityJoin(RS_Bounds& bounds, double chop, bool end);
+    SE_IdentityJoin(RS_Bounds& bounds, double offset, const RS_F_Point& pt0, const RS_F_Point& pt1);
 
     virtual RS_F_Point* GetDiscontinuities(int &length);
-    virtual RS_Bounds* GetIdentityRegions(int &length);
-    virtual RS_Bounds* GetNonlinearRegions(int &length);
     virtual RS_Bounds& GetTransformedBounds();
 
-    virtual double GetXChop(bool &chopEnd);
+    virtual void GetXChop(double& startx, double& endx);
 
-    virtual void Transform(double& x, double &y, SE_TransformInfo* info);
+    virtual RS_F_Point* Transform(const RS_F_Point& pt0, const RS_F_Point& pt1, int& length);
+    virtual void Transform(SE_LineStorage* src, SE_LineStorage* dst, bool closed);
 
+
 private:
-    double m_chop;
-    bool m_end;
-    RS_Bounds m_identity_region;
+    double m_chop_start;
+    double m_chop_end;
+
+    RS_F_Point m_points[2];
+
+    SE_Matrix m_xform;
+
     RS_Bounds m_xf_bounds;
+    RS_Bounds m_bounds;
 };
 
 #endif // SE_IDENTITYJOIN_H

Added: trunk/MgDev/Common/Stylization/SE_LineStorage.cpp
===================================================================
--- trunk/MgDev/Common/Stylization/SE_LineStorage.cpp	                        (rev 0)
+++ trunk/MgDev/Common/Stylization/SE_LineStorage.cpp	2007-03-23 01:54:26 UTC (rev 1353)
@@ -0,0 +1,208 @@
+//
+//  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 "SE_LineStorage.h"
+#include "stdafx.h"
+
+void SE_LineStorage::_MoveTo(double x, double y)
+{
+    if (m_do_chop && (x < m_chop_start || x > m_chop_end))
+    {
+        m_chop_x = x;
+        m_chop_y = y;
+        m_chopped = true;
+        return;
+    }
+
+    m_types[m_cur_types++] = (unsigned char)stMoveTo;
+    m_pts[m_cur_pts++] = x;
+    m_pts[m_cur_pts++] = y;
+
+    m_last_x = x;
+    m_last_y = y;
+
+    m_cntrs[++m_cur_cntr] = 1;
+}
+
+void SE_LineStorage::_LineTo(double x, double y)
+{
+    if (m_do_chop)
+    {
+        bool chopStart = x < m_chop_start;
+        if (chopStart || x > m_chop_end)
+        {
+            m_chop_x = x;
+            m_chop_y = y;
+            if (m_chopped)
+                return;
+
+            double lastx, lasty;
+            lastx = m_pts[m_cur_pts-2];
+            lasty = m_pts[m_cur_pts-1];
+            m_cross_x = chopStart ? m_chop_start : m_chop_end;
+            m_cross_y = lasty + (y - lasty)*(m_cross_x - lastx)/(x - lastx);
+            m_chopped = m_crossed = true;
+            x = m_cross_x;
+            y = m_cross_y;
+        }
+        else if (m_chopped)
+        {
+            double sy = m_chop_y + (y - m_chop_y)*(m_cross_x - m_chop_x)/(x - m_chop_x);
+            if (!m_close_chops || !m_crossed)
+            {
+                if (m_crossed)
+                    EnsureContours(1);
+                _MoveTo(m_cross_x, sy);
+            }
+            else
+            {
+                m_types[m_cur_types++] = (unsigned char)stLineTo;
+                m_pts[m_cur_pts++] = m_cross_x;
+                m_pts[m_cur_pts++] = sy;
+                m_cntrs[m_cur_cntr]++;
+            }
+            m_chopped = false;
+            if (x == m_cross_x)
+                return;
+            EnsurePoints(1);
+        }
+    }
+
+    m_types[m_cur_types++] = (unsigned char)stLineTo;
+    m_pts[m_cur_pts++] = x;
+    m_pts[m_cur_pts++] = y;
+
+    m_cntrs[m_cur_cntr]++;
+}
+
+void SE_LineStorage::SetToTransform(const SE_Matrix& xform, LineBuffer* lb)
+{
+    EnsurePoints(lb->point_count());
+    EnsureContours(lb->cntr_count());
+
+    int n_cntrs = lb->cntr_count();
+    int* contours = lb->cntrs();
+    double* src = lb->points();
+    double* dst = m_pts;
+
+    for (int i = 0; i < n_cntrs; i++)
+    {
+        double sx, sy, *tx, *ty;
+        double* last = src + 2*contours[i];
+        sx = *src++;
+        sy = *src++;
+        xform.transform(sx, sy, m_last_x, m_last_y);
+        *dst++ = m_last_x;
+        *dst++ = m_last_y;
+
+        while (src < last)
+        {
+            sx = *src++;
+            sy = *src++;
+            tx = dst++;
+            ty = dst++;
+            xform.transform(sx, sy, *tx, *ty);
+        }
+    }
+
+    memcpy(m_types, lb->types(), lb->point_count());
+    memcpy(m_cntrs, lb->cntrs(), sizeof(int)*lb->cntr_count());
+
+    m_cur_types = lb->point_count();
+    m_cur_pts = m_cur_types*2;
+    m_cur_cntr = lb->cntr_count() - 1;
+
+    m_geom_type = lb->geom_type();
+    xform.transform(m_last_x, m_last_y);
+}
+
+void SE_LineStorage::SetToCopy(SE_LineStorage* src)
+{
+    m_do_chop = src->m_do_chop;
+    m_chopped = src->m_chopped;
+    m_close_chops = src->m_close_chops;
+    m_crossed = src->m_crossed;
+    m_chop_start = src->m_chop_start;
+    m_chop_end = src->m_chop_end;
+    m_cross_x = src->m_cross_x;
+    m_cross_y = src->m_cross_y;
+    m_chop_x = src->m_chop_x;
+    m_chop_y = src->m_chop_y;
+    m_last_x = src->_LastX();
+    m_last_y = src->_LastY();
+    m_bounds = src->bounds();
+    m_geom_type = src->geom_type();
+    int grow_types = src->point_count() - m_types_len;
+    if (grow_types > 0)
+        EnsurePoints(m_types_len + grow_types);
+    int grow_cntrs = src->cntr_count() - m_cntrs_len;
+    if (grow_cntrs > 0)
+        EnsureContours(m_cntrs_len + grow_cntrs);
+    memcpy(m_pts, src->points(), sizeof(double)*2*src->point_count());
+    memcpy(m_types, src->types(), src->point_count());
+    memcpy(m_cntrs, src->cntrs(), sizeof(int)*src->cntr_count());
+    m_cur_pts = src->point_count()*2;
+    m_cur_types = src->point_count();
+    m_cur_cntr = src->cntr_count() - 1;
+}
+
+void SE_LineStorage::Transform(const SE_Matrix& xform)
+{
+    double* cur = m_pts;
+    double* end = m_pts + m_cur_pts;
+    double *x, *y;
+
+    while (cur < end)
+    {
+        x = cur++;
+        y = cur++;
+        xform.transform(*x, *y);
+    }
+}
+
+void SE_LineStorage::_ResizePoints(int n)
+{
+    int len = 2*m_pts_len;
+    if (len - m_pts_len < 2*n)
+        len += 2*n;
+
+    double* tempPts = new double[len];
+    memcpy(tempPts, m_pts, sizeof(double)*m_pts_len);
+    delete[] m_pts;
+    m_pts = tempPts;
+    m_pts_len = len;
+
+    len /= 2;
+    unsigned char* tempTypes = new unsigned char[len];
+    memcpy(tempTypes, m_types, sizeof(unsigned char) * m_types_len);
+    delete[] m_types;
+    m_types = tempTypes;
+    m_types_len = len;
+}
+
+void SE_LineStorage::_ResizeContours(int n)
+{
+    int len = 2*m_cntrs_len;
+    if (len - m_pts_len < n)
+        len += n;
+
+    int* tempCntrs = new int[len];
+    memcpy(tempCntrs, m_cntrs, sizeof(int)*m_cntrs_len);
+    delete[] m_cntrs;
+    m_cntrs = tempCntrs;
+    m_cntrs_len = len;
+}

Added: trunk/MgDev/Common/Stylization/SE_LineStorage.h
===================================================================
--- trunk/MgDev/Common/Stylization/SE_LineStorage.h	                        (rev 0)
+++ trunk/MgDev/Common/Stylization/SE_LineStorage.h	2007-03-23 01:54:26 UTC (rev 1353)
@@ -0,0 +1,141 @@
+//
+//  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_LINESTORAGE_H
+#define SE_LINESTORAGE_H
+
+#include "LineBuffer.h"
+#include "SE_Matrix.h"
+#include "SE_Bounds.h"
+
+class SE_LineStorage : public LineBuffer
+{
+public:
+    SE_INLINE SE_LineStorage(int size);
+    SE_INLINE void EnsurePoints(int n);
+    SE_INLINE void EnsureContours(int n);
+    SE_INLINE void SetBounds(double minx, double miny, double maxx, double maxy);
+    SE_INLINE void SetBounds(SE_Bounds* bounds);
+    SE_INLINE void SetChopInfo(double startx, double endx, bool closeChops);
+    SE_INLINE void Reset();
+    
+    SE_INLINE void _MoveToNoChop(double x, double y);
+    SE_INLINE void _LineToNoChop(double x, double y);
+    
+    void _MoveTo(double x, double y);
+    void _LineTo(double x, double y);
+    
+    /* Both of these methods invalidate the bounds.  SetBounds must be called manually to restore them. */
+    void SetToTransform(const SE_Matrix& xform, LineBuffer* src);
+    void SetToCopy(SE_LineStorage* src);
+    void Transform(const SE_Matrix& xform);
+
+private:
+    SE_INLINE double& _LastX() { return m_last_x; }
+    SE_INLINE double& _LastY() { return m_last_y; }
+    void _ResizePoints(int n);
+    void _ResizeContours(int n);
+
+    bool m_do_chop;
+    bool m_chopped;
+
+    bool m_close_chops;
+    bool m_crossed;
+    double m_chop_start;
+    double m_chop_end;
+    double m_cross_x;
+    double m_cross_y;
+    double m_chop_x;
+    double m_chop_y;
+};
+
+/* Inline Functions */
+
+SE_LineStorage::SE_LineStorage(int size) : 
+    LineBuffer(size),
+    m_do_chop(false),
+    m_chopped(false),
+    m_crossed(false)
+{ 
+}
+
+void SE_LineStorage::EnsurePoints(int n)
+{
+    if (m_cur_pts + 2*n >= m_pts_len)
+        _ResizePoints(n);
+}
+
+void SE_LineStorage::EnsureContours(int n)
+{
+    if (m_cur_cntr + 2 + n > m_cntrs_len)
+        _ResizeContours(n);
+}
+
+void SE_LineStorage::SetBounds(double minx, double miny, double maxx, double maxy)
+{
+    m_bounds.minx = minx;
+    m_bounds.miny = miny;
+    m_bounds.maxx = maxx;
+    m_bounds.maxy = maxy;
+}
+
+void SE_LineStorage::SetBounds(SE_Bounds* bounds)
+{
+    m_bounds.minx = bounds->min[0];
+    m_bounds.miny = bounds->min[1];
+    m_bounds.maxx = bounds->max[0];
+    m_bounds.maxy = bounds->max[1];
+}
+
+void SE_LineStorage::SetChopInfo(double startx, double endx, bool closeChops)
+{
+    m_do_chop = true;
+    m_chop_start = startx;
+    m_chop_end = endx;
+    m_close_chops = closeChops;
+}
+
+void SE_LineStorage::Reset()
+{
+    m_do_chop = false;
+    m_chopped = false;
+    m_crossed = false;
+    LineBuffer::Reset();
+}
+
+void SE_LineStorage::_MoveToNoChop(double x, double y)
+{
+    m_types[m_cur_types++] = (unsigned char)stMoveTo;
+    m_pts[m_cur_pts++] = x;
+    m_pts[m_cur_pts++] = y;
+
+    m_last_x = x;
+    m_last_y = y;
+
+    m_cntrs[++m_cur_cntr] = 1;
+}
+
+void SE_LineStorage::_LineToNoChop(double x, double y)
+{
+    m_types[m_cur_types++] = (unsigned char)stLineTo;
+    m_pts[m_cur_pts++] = x;
+    m_pts[m_cur_pts++] = y;
+
+    m_cntrs[m_cur_cntr]++;
+}
+
+#endif // SE_LINESTORAGE_H

Modified: trunk/MgDev/Common/Stylization/SE_MiterJoin.cpp
===================================================================
--- trunk/MgDev/Common/Stylization/SE_MiterJoin.cpp	2007-03-23 00:43:55 UTC (rev 1352)
+++ trunk/MgDev/Common/Stylization/SE_MiterJoin.cpp	2007-03-23 01:54:26 UTC (rev 1353)
@@ -16,230 +16,472 @@
 //
 
 #include "SE_MiterJoin.h"
+#include "SE_LineBuffer.h"
 #include "stdafx.h"
 
-/* TODO: use vectors instead of sAng, eAng */
+
 SE_MiterJoin::SE_MiterJoin
                          ( double limit, 
                            RS_Bounds& bounds, 
                            double vertexOffset, 
-                           double sAng, 
-                           double eAng, 
-                           double dx, 
-                           double dy, 
-                           double chopOffset )
+                           const RS_F_Point& prev,
+                           const RS_F_Point& vert,
+                           const RS_F_Point& next,
+                           bool noTransform ) :
+    m_sRot(),
+    m_eRot(),
+    m_j_bounds(),
+    m_xf_bounds(DBL_MAX, DBL_MAX, -DBL_MAX, -DBL_MAX)
 {
-    double V;    /* The location of the vertex in symbol coordinates */
-    double wn;   /* The height of the symbol below the line (inside the join) */
-    double wp;   /* The height of the symbol above the line (outside the join) */
-    double jn;   /* The length of the join above the line */
-    double jp;   /* The length of the join below the line */
-    double h;    /* The half-angle between the segments */
-    double t;    /* The tangent of the half-angle */
-    double c;    /* The cosine of the half-angle */
-    double s;    /* The sine of the half-angle */
-    double mmax; /* The length of the miter before the miter limit is applied */
-    double mlen; /* The miter length (the miter limit times the outside line thickness) */
-    double movr; /* The length of the portion of the miter that exceeds the miter length */
-
-    m_sAng = sAng;
-    m_eAng = eAng;
-
-    wn = bounds.miny < 0.0 ? -bounds.miny : 0.0;
-    wp = bounds.maxy > 0.0 ? bounds.maxy : 0.0;
+    double V;           /* The location of the vertex in symbol coordinates */
+    double wp;          /* The height of the positive portion of the symbol (above the centerline) */
+    double wn;          /* The height of the negative portion of the symbol (below the centerline) */
+    double wb;          /* The height of the beveled portion of the symbol */
+    double w;           /* The height of the join above or below the line (symmetrical) */
+    double jo;          /* The x distance from the vertex to the end of the outside join */
+    double ji;          /* The x distance from the vertex to the end of the inside join */
+    double t;           /* The tangent of the half-angle */
+    double ca;          /* The cosine of the angle */
+    double ch;          /* The cosine of the half-angle */
+    double sa;          /* The sine of the angle */
+    double mmax;        /* The length of the miter before the miter limit is applied */
+    double mmin;        /* The minimum miter limit (at which a flat bevel is possible) */
+    double mlen;        /* The miter length (the miter limit times the outside line thickness) */
+    double movr;        /* The length of the portion of the miter that exceeds the miter length */
+    double imprev;      /* The inverse magnitude of the (vert - prev) vector */
+    double imnext;      /* The invserse magnitude of the (next - vert) vector */
+    RS_F_Point nprev;   /* The normalized (vert - prev) vector */
+    RS_F_Point nnext;   /* The normalized (next - vert) vector */
+    bool clockwise;     /* If true, then the positive portion of the symbol is on the inside of the join */
+    bool rtl;           /* If true, then the line moves negatively in x */
     
-    /* If t is negative, then jn will become the miter length and jp will become the inside length */
-    h = (eAng - sAng)/2.0;
-    s = sin(h);
-    c = cos(h);
-    t = s/c; /* The calculations will be stable even if the tangent is INF or 0 (assuming a reasonable miter limit) */
     V = bounds.minx - vertexOffset;
-    
-    /* Rotation should occur about the vertex */
-    m_sRot.translateX(V);
-    m_sRot.rotate(sAng);
-    m_sRot.translate(dx - V, dy);
-    m_eRot.translateX(V);
-    m_eRot.rotate(eAng);
-    m_eRot.translate(dx - V, dy);
+    clockwise = PointLeft(prev.x, prev.y, vert.x, vert.y, next.x, next.y);
+    rtl = next.x < prev.x;
+   
+    nnext.x = next.x - vert.x;
+    nnext.y = next.y - vert.y;
+    imnext = 1.0/sqrt(nnext.x*nnext.x + nprev.y*nprev.y);
+    nnext.x *= imnext;
+    nnext.y *= imnext;
 
-    /* the tangent of the half angle is equal to the upper height over the upper join width */
-    jn = wn/t;
+    nprev.x = vert.x - prev.x;
+    nprev.y = vert.y - prev.y;
+    imprev = 1.0/sqrt(nprev.x*nprev.x + nprev.y*nprev.y);
+    nprev.x *= imprev;
+    nprev.y *= imprev;
 
-    /* the tangent of the half angle is equal to the lower height over the lower join width */
-    jp = wp/t;
- 
-    if (t < 0.0)
-    { /* The positive portion of the symbol is inside the join */
-        mmax = sqrt(wn*wn + jn*jn);
-        mlen = wn*limit;
-        if ((movr = mmax - mlen) > 0) /* the miter limit forces a bevel */
+    m_j_bounds.minx = vertexOffset; /* bounds.minx - V */
+    m_j_bounds.maxx = bounds.maxx - V;
+
+    if (noTransform)
+    {
+        m_eRot.translate(-vert.x, -vert.y);
+        m_eRot.rotate(-nprev.y, nprev.x); /* Undo leading segment rotation */
+
+        m_w2j.translate(-vert.x, -vert.y);
+        m_w2j.rotate(-nprev.y, nprev.x); /* rotate by -angle */
+        if (clockwise)
+        {   /* Flip across the line so we don't have to worry about this stuff */
+            m_w2j.scaleY(-1.0);
+            m_j2w.scaleY(-1.0);
+            m_j_bounds.miny = -bounds.maxy;
+            m_j_bounds.maxy = -bounds.miny;
+        }
+        else
         {
-            /* the cosine of the half angle is equal to the chopped length / the truncation of j */
-            jn -= movr/c;
-            jn = (jn < 0) ? 0.0 : jn;
+            m_j_bounds.miny = bounds.miny;
+            m_j_bounds.maxy = bounds.maxy;
         }
-        m_y_max_len = jn;
-        m_y_max = wn;
-        m_y_min_len = jp;
-        m_y_min = wp;
+        if (rtl)
+        {
+            m_w2j.scaleX(-1.0);
+            m_j2w.scaleX(-1.0);
+        }
+        m_j2w.rotate(nprev.y, nprev.x);
+        m_j2w.translate(vert.x, vert.y);
     }
     else
-    { /* The negative portion of the symbol is inside the join */
-        mmax = sqrt(wp*wp + jp*jp);
-        mlen = wp*limit;
-        if ((movr = mmax - mlen) > 0)
+    {
+        m_sRot.translateX(-V); /* translate by vert-(V,0), then by -vert */
+        m_sRot.rotate(nprev.y, nprev.x);
+        m_sRot.translate(vert.x, vert.y);
+        m_w2j.translateX(-V);
+        if (clockwise)
         {
-            jp -= movr/c;
-            jp = (jp < 0) ? 0.0 : jp;
+            m_w2j.scaleY(-1.0);
+            m_j2w.scaleY(-1.0);
         }
-        m_y_max_len = jp;
-        m_y_max = wp;
-        m_y_min_len = jn;
-        m_y_min = wn;
+        if (rtl)
+        {
+            m_w2j.scaleX(-1.0);
+            m_j2w.scaleX(-1.0);
+        }
+        m_w2j.translateX(V);
+        m_eRot.translateX(-V);
     }
+
+    /* Rotation should occur about the vertex */
+    m_eRot.rotate(nnext.y, nnext.x);
+    m_eRot.translate(vert.x, vert.y);
     
-    if (V + chopOffset < bounds.maxx)
-        m_chop = V + chopOffset;
-    else
-        m_chop = DBL_MAX;
+    m_eRot.postmultiply(m_j2w);
+    m_sRot.postmultiply(m_j2w);
 
-    /* The widest part of the transform is cosine of the half angle times the actual miter length.
-     * If there is no bevel, m_y_mid will be equal to m_y_max.
-     * Despite this mathemtical certainty, using an if ensures that m_y_mid == m_y_max in fp math */
+    wn = bounds.miny < 0.0 ? -bounds.miny : 0.0;
+    wp = bounds.maxy > 0.0 ? bounds.maxy : 0.0;
+    double hw = (wn > wp) ? wn : wp;
+    w = 2.0 * hw;
+
+    ca = -nprev.x*nnext.x - nprev.y*nnext.y; /* <-nprev, nnext> */
+    sa = fabs(-nprev.x*nnext.y + nprev.y*nnext.x); /* |-nprev X nnext| */
+    t = (1 - ca)/sa; /* From half angle identity: tan(x/2) = (1 - cos(x))/sin(x) */
+
+    /* the tangent of the half angle is equal to w/j */
+    jo = ji = hw/t;
+    mmax = sqrt(jo*jo + hw*hw);
+
+    /* Derivation of mmin:
+     * Let  A                                   be the area of the minimum bevel filled in between segments with no join
+     * Let  theta                               be the angle between the two segments
+     *
+     * A = w*w*sin(pi - theta)                  from the sine formula for the area of a triangle
+     * A = w*w*sin(theta)                       from identity sin(pi - theta) = sin(theta)
+     * 
+     * A/2 = w*mmin*sin(pi/2 - theta/2)         from applying the same formula to one half of the (isoceles) triangle
+     * A/2 = w*mmin*cos(theta/2)                from identity sin(pi/2 - theta) = cos(theta)
+     * A/2 = w*mmin*sqrt((1 + cos(theta))/2)    from cos(theta/2) = +/- sqrt((1 + cos(theta)/2), and theta/2 < pi/2, so positive
+     * w*w*sin(theta)/2 = w*wmin*sqrt((1 + cos(theta))/2)
+     * w*sa/2 = wmin*sqrt((1+ca)/2)
+     * wmin = hw*sa/sqrt((1+ca)/2)
+     */
+    ch = sqrt((1 + ca) / 2.0);
+    mmin = sa / ch;
+    mlen = hw * (limit < mmin ? mmin : limit);
+    movr = mmax - mlen;
+
     if (movr > 0)
     {
-        m_y_mid_len = (mmax < mlen ? mmax : mlen)*c;
-        m_y_mid = m_y_mid_len*t;
+        /* Todo: limit cannot go to zero */
+        double reduction = movr/mmax;
+        jo *= 1.0 - reduction;
+        wb = hw * reduction;
+        m_bevel_width = mlen * ch;
+        m_bevel_scale = (m_bevel_width - jo) / wb;
     }
     else
     {
-        m_y_mid_len = m_y_max_len;
-        m_y_mid = m_y_max;
+        wb = 0.0;
+        m_bevel_width = jo;
     }
-    m_x_vert = V;
-
+ 
+    m_height = hw;
+    m_width = ji;
+    m_top_width = jo;
+    m_bevel = hw - wb;
+    m_miter_scale = m_width * (m_bevel_width + m_width) / (m_bevel + m_height);
+    
     m_n_discontinuities = -1;
-    m_n_identity_regions = -1;
-    m_bounds = bounds;
-
-    /* Factor used in miter calculations (see comments in Transform) */
-    m_miter_scale = m_y_min_len*(m_y_mid_len + m_y_min_len)/(m_y_mid - m_y_min);
-    m_bevel_scale = (m_y_max - m_y_mid)*(m_y_mid_len - m_y_max_len);
-
 }
 
 RS_F_Point* SE_MiterJoin::GetDiscontinuities(int &length)
 {
     if (m_n_discontinuities == -1) /* Lazily initialize */
     {
-        m_first_discontinuity = NULL;
-        double minx = m_x_vert - m_y_min_len;
-        double maxx = m_x_vert + m_y_min_len;
-        if (m_bounds.minx < m_x_vert && m_y_mid != m_y_max)
+        m_n_discontinuities = 0;
+        int index = 0;
+
+        if (m_j_bounds.minx < -m_width)
         {
-            m_first_discontinuity = m_discontinuities;
             m_n_discontinuities++;
-            m_discontinuities[0].x = (minx > m_bounds.minx) ? minx : m_bounds.minx;
-            m_discontinuities[0].y = m_y_mid;
-            m_discontinuities[1].x = (m_bounds.maxx < m_x_vert) ? m_bounds.maxx : m_x_vert;
-            m_discontinuities[1].y = m_y_mid;
+            m_discontinuities[index].x = -m_width;
+            m_discontinuities[index].y = -m_height;
+            m_j2w.transform(m_discontinuities[index].x, m_discontinuities[index].y);
+            index++;
+            m_discontinuities[index].x = -m_width;
+            m_discontinuities[index].y = m_height;
+            m_j2w.transform(m_discontinuities[index].x, m_discontinuities[index].y);
         }
 
-        if (m_bounds.minx < m_x_vert && m_bounds.maxx > m_x_vert)
+        if (m_bevel > 0.0 && m_j_bounds.maxy > m_bevel)
         {
-            if (m_first_discontinuity == NULL)
-                m_first_discontinuity = m_discontinuities + 2;
             m_n_discontinuities++;
-            m_discontinuities[2].x = m_x_vert;
-            m_discontinuities[2].y = m_y_max;
-            m_discontinuities[3].x = m_x_vert;
-            m_discontinuities[3].y = m_y_min;
+            m_discontinuities[index].x = -m_width;
+            m_discontinuities[index].y = m_bevel;
+            m_j2w.transform(m_discontinuities[index].x, m_discontinuities[index].y);
+            index++;
+            m_discontinuities[index].x = 0.0;
+            m_discontinuities[index].y = m_bevel;
+            m_j2w.transform(m_discontinuities[index].x, m_discontinuities[index].y);
+            index++;
+
+            m_n_discontinuities++;
+            m_discontinuities[index].x = 0.0;
+            m_discontinuities[index].y = m_bevel;
+            m_j2w.transform(m_discontinuities[index].x, m_discontinuities[index].y);
+            index++;
+            m_discontinuities[index].x = m_width;
+            m_discontinuities[index].y = m_bevel;
+            m_j2w.transform(m_discontinuities[index].x, m_discontinuities[index].y);
+            index++;
         }
 
-        if (m_bounds.maxx > m_x_vert && m_y_mid != m_y_max)
+        if (m_j_bounds.minx < 0 && m_j_bounds.maxx > 0)
         {
-            if (m_first_discontinuity == NULL)
-                m_first_discontinuity = m_discontinuities + 4;
             m_n_discontinuities++;
-            m_discontinuities[4].x = (maxx < m_bounds.maxx) ? maxx : m_bounds.maxx;
-            m_discontinuities[4].y = m_y_mid;
-            m_discontinuities[5].x = (m_bounds.minx > m_x_vert) ? m_bounds.minx : m_x_vert;
-            m_discontinuities[5].y = m_y_mid;
+            m_discontinuities[index].x = 0;
+            m_discontinuities[index].y = -m_height;
+            m_j2w.transform(m_discontinuities[index].x, m_discontinuities[index].y);
+            index++;
+            m_discontinuities[index].x = 0;
+            m_discontinuities[index].y = m_height;
+            m_j2w.transform(m_discontinuities[index].x, m_discontinuities[index].y);
         }
+
+        if (m_j_bounds.maxx > m_width)
+        {
+            m_n_discontinuities++;
+            m_discontinuities[index].x = m_width;
+            m_discontinuities[index].y = -m_height;
+            m_j2w.transform(m_discontinuities[index].x, m_discontinuities[index].y);
+            index++;
+            m_discontinuities[index].x = m_width;
+            m_discontinuities[index].y = m_height;
+            m_j2w.transform(m_discontinuities[index].x, m_discontinuities[index].y);
+        }
     }
 
     length = m_n_discontinuities;
-    return m_first_discontinuity;
+    return m_discontinuities;
 }
 
-RS_Bounds* SE_MiterJoin::GetIdentityRegions(int &length)
+RS_Bounds& SE_MiterJoin::GetTransformedBounds()
 {
-    if (m_n_identity_regions == -1) /* Lazily initialize */
+    if (!m_xf_bounds.IsValid())
     {
-        m_first_identity_region = NULL;
-        m_n_identity_regions = 0;
+        RS_F_Point xfpt;
 
-        if (m_bounds.minx < m_x_vert - m_y_min_len)
-        {
-            m_first_identity_region = m_identity_region;
-            m_n_identity_regions++;
-            m_identity_region[0].minx = m_bounds.minx;
-            m_identity_region[0].maxx = m_x_vert - m_y_min_len;
-            m_identity_region[0].miny = m_bounds.miny;
-            m_identity_region[0].maxy = m_bounds.maxy;
-        }
+        xfpt.x = m_j_bounds.minx;
+        xfpt.y = m_j_bounds.miny;
+        _Transform(xfpt);
+        m_xf_bounds.add_point(xfpt);
 
-        if (m_bounds.maxx > m_x_vert + m_y_min_len && m_chop > m_x_vert + m_y_min_len)
-        {
-            if (m_first_identity_region == NULL)
-                m_first_identity_region = m_identity_region + 1;
-            m_n_identity_regions++;
-            m_identity_region[1].minx = m_x_vert + m_y_min_len;
-            m_identity_region[1].maxx = m_bounds.maxx > m_chop ? m_chop : m_bounds.maxx;
-            m_identity_region[1].miny = m_bounds.miny;
-            m_identity_region[1].maxy = m_bounds.maxy;
-        }
+        xfpt.x = m_j_bounds.maxx;
+        xfpt.y = m_j_bounds.maxy;
+        _Transform(xfpt);
+        m_xf_bounds.add_point(xfpt);
+
+        xfpt.x = 0.0;
+        xfpt.y = m_j_bounds.maxy;
+        _Transform(xfpt);
+        m_xf_bounds.add_point(xfpt);
+
+        xfpt.x = 0.0;
+        xfpt.y = m_j_bounds.miny;
+        _Transform(xfpt);
+        m_xf_bounds.add_point(xfpt);
+
+        xfpt.x = m_j_bounds.minx;
+        xfpt.y = m_j_bounds.maxy;
+        _Transform(xfpt);
+        m_xf_bounds.add_point(xfpt);
+
+        xfpt.x = m_j_bounds.maxx;
+        xfpt.y = m_j_bounds.miny;
+        _Transform(xfpt);
+        m_xf_bounds.add_point(xfpt);
     }
 
-    length = m_n_identity_regions;
-    return m_first_identity_region;
+    return m_xf_bounds;
 }
 
-RS_Bounds* SE_MiterJoin::GetNonlinearRegions(int &length)
+void SE_MiterJoin::GetXChop(double& startx, double& endx)
 {
-    length = 0;
-    return NULL;
+    startx = -DBL_MAX;
+    endx = DBL_MAX;
 }
 
-RS_Bounds& SE_MiterJoin::GetTransformedBounds()
+RS_F_Point* SE_MiterJoin::Transform(const RS_F_Point& pt0, const RS_F_Point& pt1, int& length)
 {
-    /* TODO: initialize, lazily */
-    return m_xf_bounds;
+    RS_F_Point head, tail;
+
+    m_w2j.transform(pt0.x, pt0.y, head.x, head.y);
+    m_w2j.transform(pt1.x, pt1.y, tail.x, tail.y);
+
+    if (head.x > tail.x) /* Swap 'em--the head comes first! */
+    {
+        m_points[0] = tail;
+        tail = head;
+        head = m_points[0];
+    }
+
+    _Explode(head, tail, length);
+
+    for (int i = 0; i < length; i++)
+        _Transform(m_points[i]);
+    return m_points;
 }
 
-double SE_MiterJoin::GetXChop(bool &chopEnd)
+void SE_MiterJoin::Transform(SE_LineStorage* src, SE_LineStorage* dst, bool /*closed*/)
 {
-    chopEnd = true;
-    return m_chop;
+    int n_cntrs = src->cntr_count();
+    int* contours = src->cntrs();
+    double* pts = src->points();
+    RS_F_Point head, tail;
+    int length;
+
+    for (int i = 0; i < n_cntrs; i++)
+    {
+        double x, y, lx, ly;
+        double* last = pts + 2*contours[i];
+        dst->EnsureContours(1);
+        lx = *pts++;
+        ly = *pts++;
+        m_w2j.transform(lx, ly);
+        bool first = true;
+        bool noswap;
+
+        while (pts < last)
+        {
+            x = *pts++;
+            y = *pts++;
+            m_w2j.transform(x, y);
+
+            head.x = x;
+            head.y = y;
+            tail.x = lx;
+            tail.y = ly;
+
+            if (noswap = head.x > tail.x) /* Swap 'em--the head comes first! */
+            {
+                m_points[0] = tail;
+                tail = head;
+                head = m_points[0];
+            }
+
+            _Explode(head, tail, length);
+            dst->EnsurePoints(length);
+            
+            int index, inc;
+            if (noswap)
+            {
+                index = 0;
+                inc = 1;
+            }
+            else
+            {
+                index = length - 1;
+                inc = -1;
+            }
+
+            if (first)
+            {
+                first = false;
+                _Transform(m_points[index]);
+                dst->_MoveToNoChop(m_points[index].x, m_points[index].y);
+            }
+
+            index += inc;
+
+            for (i = 1; i < length; i++)
+            {
+                RS_F_Point& pt = m_points[index];
+                index += inc;
+                _Transform(pt);
+                dst->_LineToNoChop(pt.x, pt.y);
+            }
+            lx = x;
+            ly = y;
+        }
+    }
 }
 
-void SE_MiterJoin::Transform(double& x, double &y, SE_TransformInfo* info)
+void SE_MiterJoin::_Explode(const RS_F_Point& head, const RS_F_Point& tail, int& length)
 {
-    /* By using these, max will always be > min */
-    bool start = x < m_x_vert;
-    double x_min = start ? m_x_vert - m_y_min_len : m_x_vert + m_y_min_len;
-    double dXdx, dXdy, d2Xdxdy;
+    RS_F_Point bevel, zero;
+    bool addBevel = false, addZero = false;
 
-    if (x >= m_x_vert - m_y_min_len && x <= m_x_vert + m_y_min_len)
+    length = 0;
+    double slope = (tail.y - head.y) / (tail.x - head.x);
+
+    m_points[length++] = head;
+
+    if (head.x < -m_width && tail.x > -m_width) /* Line crosses the beginning of the transform */
     {
-        if (y > m_y_mid && y <= m_y_max)
+        m_points[length].x = -m_width;
+        m_points[length++].y = head.y - slope * (m_width + head.x);
+    }
+
+    if ( (head.y < m_bevel && tail.y > m_bevel) || (head.y > m_bevel && tail.y < m_bevel) )
+    {
+        bevel.x = head.x + (m_bevel - head.y) / slope;
+        bevel.y = m_bevel;
+        addBevel = true;
+    }
+
+    if (head.x < 0.0 && tail.x > 0.0)
+    {
+        zero.y = head.y - slope * head.x;
+        zero.x = 0.0;
+        /* If, by some chance, the line crosses the bevel at x=0, don't add the point twice */
+        addZero = !addBevel || zero.x != bevel.x || zero.y != bevel.y;
+    }
+
+    if (addBevel && addZero)
+    {
+        if (bevel.x < zero.x)
         {
+            m_points[length++] = bevel;
+            m_points[length++] = zero;
+        }
+        else
+        {
+            m_points[length++] = zero;
+            m_points[length++] = bevel;
+        }
+    }
+    else if (addBevel)
+        m_points[length++] = bevel;
+    else if (addZero)
+        m_points[length++] = zero;
+
+    if (head.x < m_width && tail.x > m_width) /* Line crosses the end of the transform */
+    {
+        m_points[length].x = m_width;
+        m_points[length++].y = head.y + slope * (m_width - head.x);
+    }
+
+    m_points[length++] = tail;
+}
+
+/* Argument: point in join space
+ * Returns:  point in input space
+ */
+void SE_MiterJoin::_Transform(RS_F_Point& pt)
+{
+    double x_min;
+    SE_Matrix* postxf;
+    
+    if (pt.x <= 0)
+    {
+        x_min = -m_width;
+        postxf = &m_sRot;
+    }
+    else
+    {
+        x_min = m_width;
+        postxf = &m_eRot;
+    }
+
+    if (fabs(pt.x) <= m_width)
+    {
+        if (pt.y > m_bevel && pt.y <= m_height)
+        {
         /* The bevel transform can be described by the following function:
-         * X(x,y) = x_min + (x - x_min) * (y_max_len + (y_max - y) * (y_mid_len - y_max_len) / (y_max - y_mid)
+         * X(x,y) = x_min + (x - x_min) * (m_top_width + (m_height - y) * (m_bevel_width - m_top_width) / (m_height - m_bevel)
          *                                                          |------------- m_bevel_scale -------------|
          * where:
-         * dX/dx = y_max_len + (y_max - y) * scale
+         * dX/dx = m_top_width + (m_height - y) * scale
          * dX/dy = - (x - x_min) * scale
          * d2X/dx2 = 0
          * d2X/dy2 = 0
@@ -248,22 +490,19 @@
          * The transform is constant over Y, so
          * Y(x,y) = y
          */
-            double dy = m_y_max - y;
-            double dx = x - x_min;
+            double dy = m_height - pt.y;
+            double dx = pt.x - x_min;
 
-            x = x_min + dx * (m_y_max_len + dy * m_bevel_scale);
-            dXdx = m_y_max_len + dy * m_bevel_scale;
-            dXdy = dx * m_bevel_scale;
-            d2Xdxdy = -m_bevel_scale;
+            pt.x = x_min + dx * (m_top_width + dy * m_bevel_scale);
         }
-        else if (y <= m_y_mid && y >= m_y_min)
+        else if (pt.y <= m_bevel && pt.y >= -m_height)
         {
 
         /* The miter transform can be described by the following function:
-         * X(x,y) = x_min + (x - x_min) * (y - y_min) * y_min_len * (y_mid_len + y_min_len) / (y_mid - y_min)
+         * X(x,y) = x_min + (x - x_min) * (y + m_height) * m_width * (m_bevel_width + m_width) / (m_bevel + m_height)
          *                                             |------------------- m_miter_scale -------------------|
          * where:
-         * dX/dx = (y - y_min) * scale
+         * dX/dx = (y + m_height) * scale
          * dX/dy = (x - x_min) * scale
          * d2X/dx2 = 0
          * d2X/dy2 = 0
@@ -272,44 +511,12 @@
          * The transform is constant over Y, so
          * Y(x,y) = y
          */
-            double dx = x - x_min;
-            double dy = y - m_y_min;
+            double dx = pt.x - x_min;
+            double dy = pt.y + m_height;
 
-            x = x_min + dx * dy * m_miter_scale;
-            dXdx = dy * m_miter_scale;
-            dXdy = dx * m_miter_scale;
-            d2Xdxdy = m_miter_scale;
+            pt.x = x_min + dx * dy * m_miter_scale;
         }
-        else
-        {
-            dXdx = 1.0;
-            dXdy = 0.0;
-            d2Xdxdy = 0.0;
-        }
     }
-    else
-    {
-        dXdx = 1.0;
-        dXdy = 0.0;
-        d2Xdxdy = 0.0;
-    }
 
-    if (info)
-    {
-        info->dXdx = dXdx;
-        info->dXdy = dXdy;
-        info->dYdx = 0.0;
-        info->dYdy = 1.0;
-        info->d2Xdx2 = 0.0;
-        info->d2Ydx2 = 0.0;
-        info->d2Xdy2 = 0.0;
-        info->d2Ydy2 = 0.0;
-        info->d2Xdxdy = d2Xdxdy;
-        info->d2Ydxdy = 0.0;
-    }
-
-    if (start)
-        m_sRot.transform(x,y);
-    else
-        m_eRot.transform(x, y);
+    postxf->transform(pt.x, pt.y);
 }

Modified: trunk/MgDev/Common/Stylization/SE_MiterJoin.h
===================================================================
--- trunk/MgDev/Common/Stylization/SE_MiterJoin.h	2007-03-23 00:43:55 UTC (rev 1352)
+++ trunk/MgDev/Common/Stylization/SE_MiterJoin.h	2007-03-23 01:54:26 UTC (rev 1353)
@@ -25,57 +25,53 @@
 class SE_MiterJoin : public SE_PiecewiseTransform
 {
 public:
-    SE_MiterJoin(double limit,                  /* The miter limit of the join. */
-                 RS_Bounds& bounds,             /* The bounds of the unoriented symbol in pixel units. */
+    SE_MiterJoin(double limit,                  /* The miter limit of the join */
+                 RS_Bounds& bounds,             /* The bounds of the unoriented symbol in pixel units */
                  double vertexOffset,           /* The distance along the line (in pixels) from the 
                                                    beginning of the symbol to the vertex of the join 
                                                    (the value will be negative if the symbol starts before
-                                                   the join, and positive if it starts after the join). */
-                 double sAng,                   /* The angle of the first line segment. */
-                 double eAng,                   /* The angle of the second line segment. */
-                 double dx,                     /* The x offset of the origin of the symbol */
-                 double dy,                     /* The y offset of the origin of the symbol */
-                 double chopOffset = DBL_MAX);  /* The distance after the vertex at which to truncate the symbol */
+                                                   the join, and positive if it starts after the join) */
+                 const RS_F_Point& prev,        /* The point preceeding the vertex of the join in screen space */
+                 const RS_F_Point& vert,        /* The vertex of the join in screen space */
+                 const RS_F_Point& next,        /* The point following the vertex of the join in screen space */
+                 bool noTransform = true);      /* True if the symbol is already oriented appropriately along the leading segment */
 
     virtual RS_F_Point* GetDiscontinuities(int &length);
-    virtual RS_Bounds* GetIdentityRegions(int &length);
-    virtual RS_Bounds* GetNonlinearRegions(int &length);
     virtual RS_Bounds& GetTransformedBounds();
 
-    virtual double GetXChop(bool &chopEnd);
+    virtual void GetXChop(double& startx, double& endx);
 
-    /* Transform will apply the join transform, as well as the appropriate rotation */
-    virtual void Transform(double& x, double& y, SE_TransformInfo* info);
+    /* Transform will apply the join transform, as well as the appropriate orientation in screen space */
+    virtual RS_F_Point* Transform(const RS_F_Point& pt0, const RS_F_Point& pt1, int& length);
+    virtual void Transform(SE_LineStorage* src, SE_LineStorage* dst, bool closed);
 
 private:
-    double m_y_max;
-    double m_y_max_len;
-    double m_y_mid;
-    double m_y_mid_len;
-    double m_y_min;
-    double m_y_min_len;
+    void _Transform(RS_F_Point& pt);
+    void _Explode(const RS_F_Point& head, const RS_F_Point& tail, int& length);
 
-    double m_x_vert;
-    double m_miter_scale;
+    double m_height;      /* Height on each side from the center (ignoring bevel) in join space */
+    double m_bevel;       /* Height of the bevel in join space */
+    double m_width;       /* Distance from the center on each side that is transformed in join space*/
+    double m_bevel_width; /* Maximum transformed size of m_width */
+    double m_top_width;   /* Transformed size of m_width at m_height */
+
     double m_bevel_scale;
-    double m_sAng;
-    double m_eAng;
+    double m_miter_scale;
+
+    SE_Matrix m_w2j;      /* World space to join space transform */
+    SE_Matrix m_j2w;      /* Join space to world space transform */
+
+    RS_F_Point m_points[6];
     
     int m_n_discontinuities;
-    RS_F_Point* m_first_discontinuity;
-    RS_F_Point m_discontinuities[6];
+    RS_F_Point m_discontinuities[10];
 
-    int m_n_identity_regions;
-    RS_Bounds* m_first_identity_region;
-    RS_Bounds m_identity_region[2];
-    
     RS_Bounds m_bounds;
+    RS_Bounds m_j_bounds;
     RS_Bounds m_xf_bounds;
 
     SE_Matrix m_sRot;
     SE_Matrix m_eRot;
-
-    double m_chop;
 };
 
 #endif // SE_MITERJOIN_H

Modified: trunk/MgDev/Common/Stylization/SE_PiecewiseTransform.h
===================================================================
--- trunk/MgDev/Common/Stylization/SE_PiecewiseTransform.h	2007-03-23 00:43:55 UTC (rev 1352)
+++ trunk/MgDev/Common/Stylization/SE_PiecewiseTransform.h	2007-03-23 01:54:26 UTC (rev 1353)
@@ -20,19 +20,8 @@
 
 #include "Bounds.h"
 
-struct SE_TransformInfo
-{
-    double dXdx;
-    double dYdx;
-    double dXdy;
-    double dYdy;
-    double d2Xdx2;
-    double d2Ydx2;
-    double d2Xdy2;
-    double d2Ydy2;
-    double d2Xdxdy;
-    double d2Ydxdy;
-};
+class SE_LineStorage;
+class SE_LineBufferStorage;
 
 
 class SE_PiecewiseTransform
@@ -41,17 +30,16 @@
     /* Returned in the format pt00, pt01, pt10, pt11 etc. where each pair of points represents
      * the endpoints of a line along which the the transform is not smooth */
     virtual RS_F_Point* GetDiscontinuities(int &length) = 0;
-    /* Regions that are not transformed (other than rotation) */
-    virtual RS_Bounds* GetIdentityRegions(int &length) = 0;
-    /* Regions where simple linear of transformed points is insufficient */
-    virtual RS_Bounds* GetNonlinearRegions(int &length) = 0;
+    /* Transformed bounds take chop into account */
     virtual RS_Bounds& GetTransformedBounds() = 0;
 
-    /* Applying the chop is left to the caller */
-    virtual double GetXChop(bool &chopEnd) = 0;
+    /* Applying the chop is left to the caller.  Chop the symbol before startx and after endx. */
+    virtual void GetXChop(double& startx, double& endx) = 0;
 
-    /* The transform function is not aware of the chop value */
-    virtual void Transform(double& x, double& y, SE_TransformInfo* info) = 0;
+    /* This transform function is not aware of the chop value */
+    virtual RS_F_Point* Transform(const RS_F_Point& pt0, const RS_F_Point& pt1, int& length) = 0;
+    /* This transform function handles the chop as well */
+    virtual void Transform(SE_LineStorage* src, SE_LineStorage* dst, bool closed) = 0;
 };
 
 #endif // SE_PIECEWISETRANSFORM_H

Modified: trunk/MgDev/Common/Stylization/Stylization.vcproj
===================================================================
--- trunk/MgDev/Common/Stylization/Stylization.vcproj	2007-03-23 00:43:55 UTC (rev 1352)
+++ trunk/MgDev/Common/Stylization/Stylization.vcproj	2007-03-23 01:54:26 UTC (rev 1353)
@@ -677,6 +677,14 @@
 				>
 			</File>
 			<File
+				RelativePath=".\SE_IdentityJoin.cpp"
+				>
+			</File>
+			<File
+				RelativePath=".\SE_IdentityJoin.h"
+				>
+			</File>
+			<File
 				RelativePath=".\SE_LineBuffer.cpp"
 				>
 			</File>
@@ -685,10 +693,30 @@
 				>
 			</File>
 			<File
+				RelativePath=".\SE_LineStorage.cpp"
+				>
+			</File>
+			<File
+				RelativePath=".\SE_LineStorage.h"
+				>
+			</File>
+			<File
 				RelativePath=".\SE_Matrix.h"
 				>
 			</File>
 			<File
+				RelativePath=".\SE_MiterJoin.cpp"
+				>
+			</File>
+			<File
+				RelativePath=".\SE_MiterJoin.h"
+				>
+			</File>
+			<File
+				RelativePath=".\SE_PiecewiseTransform.h"
+				>
+			</File>
+			<File
 				RelativePath=".\SE_PositioningAlgorithms.cpp"
 				>
 			</File>



More information about the mapguide-commits mailing list