Author: alg
Date: Tue Jan 10 11:00:48 2012
New Revision: 1229503

URL: http://svn.apache.org/viewvc?rev=1229503&view=rev
Log:
linecaps: Adapted and partially overhauled 2D line geometry creation; Adapted 
3D line geometry creation (tubes) to support LineCap styles

Modified:
    
incubator/ooo/branches/alg/linecap/main/basegfx/inc/basegfx/polygon/b2dpolygontools.hxx
    
incubator/ooo/branches/alg/linecap/main/basegfx/source/polygon/b2dlinegeometry.cxx
    
incubator/ooo/branches/alg/linecap/main/basegfx/source/polygon/b2dpolygontools.cxx
    
incubator/ooo/branches/alg/linecap/main/drawinglayer/inc/drawinglayer/primitive3d/polygontubeprimitive3d.hxx
    
incubator/ooo/branches/alg/linecap/main/drawinglayer/source/primitive3d/polygonprimitive3d.cxx
    
incubator/ooo/branches/alg/linecap/main/drawinglayer/source/primitive3d/polygontubeprimitive3d.cxx
    
incubator/ooo/branches/alg/linecap/main/drawinglayer/source/primitive3d/sdrdecompositiontools3d.cxx

Modified: 
incubator/ooo/branches/alg/linecap/main/basegfx/inc/basegfx/polygon/b2dpolygontools.hxx
URL: 
http://svn.apache.org/viewvc/incubator/ooo/branches/alg/linecap/main/basegfx/inc/basegfx/polygon/b2dpolygontools.hxx?rev=1229503&r1=1229502&r2=1229503&view=diff
==============================================================================
--- 
incubator/ooo/branches/alg/linecap/main/basegfx/inc/basegfx/polygon/b2dpolygontools.hxx
 (original)
+++ 
incubator/ooo/branches/alg/linecap/main/basegfx/inc/basegfx/polygon/b2dpolygontools.hxx
 Tue Jan 10 11:00:48 2012
@@ -285,6 +285,9 @@ namespace basegfx
          */
         B2DPolygon createPolygonFromCircle( const B2DPoint& rCenter, double 
fRadius );
 
+        /// create half circle centered on (0,0) from [0 .. F_PI]
+        B2DPolygon createHalfUnitCircle();
+
                /** create a polygon which describes the unit circle and close 
it
 
                        @param nStartQuadrant

Modified: 
incubator/ooo/branches/alg/linecap/main/basegfx/source/polygon/b2dlinegeometry.cxx
URL: 
http://svn.apache.org/viewvc/incubator/ooo/branches/alg/linecap/main/basegfx/source/polygon/b2dlinegeometry.cxx?rev=1229503&r1=1229502&r2=1229503&view=diff
==============================================================================
--- 
incubator/ooo/branches/alg/linecap/main/basegfx/source/polygon/b2dlinegeometry.cxx
 (original)
+++ 
incubator/ooo/branches/alg/linecap/main/basegfx/source/polygon/b2dlinegeometry.cxx
 Tue Jan 10 11:00:48 2012
@@ -339,7 +339,13 @@ namespace basegfx
             }
         }
 
-               B2DPolygon createAreaGeometryForEdge(const B2DCubicBezier& 
rEdge, double fHalfLineWidth)
+        B2DPolyPolygon createAreaGeometryForEdge(
+            const B2DCubicBezier& rEdge, 
+            double fHalfLineWidth,
+            bool bStartRound,
+            bool bEndRound,
+            bool bStartSquare,
+            bool bEndSquare)
         {
             // create polygon for edge
             // Unfortunately, while it would be geometrically correct to not 
add
@@ -348,35 +354,102 @@ namespace basegfx
             if(rEdge.isBezier())
             {
                 // prepare target and data common for upper and lower
+                B2DPolyPolygon aRetval;
                 B2DPolygon aBezierPolygon;
-                   const B2DVector aPureEdgeVector(rEdge.getEndPoint() - 
rEdge.getStartPoint());
+                const B2DVector aPureEdgeVector(rEdge.getEndPoint() - 
rEdge.getStartPoint());
                 const double fEdgeLength(aPureEdgeVector.getLength());
                 const bool bIsEdgeLengthZero(fTools::equalZero(fEdgeLength));
-                const B2DVector aTangentA(rEdge.getTangent(0.0));
-                const B2DVector aTangentB(rEdge.getTangent(1.0));
+                B2DVector aTangentA(rEdge.getTangent(0.0)); 
aTangentA.normalize();
+                B2DVector aTangentB(rEdge.getTangent(1.0)); 
aTangentB.normalize();
+                const B2DVector 
aNormalizedPerpendicularA(getPerpendicular(aTangentA));
+                const B2DVector 
aNormalizedPerpendicularB(getPerpendicular(aTangentB));
+
+                // create upper displacement vectors and check if they cut
+                const B2DVector aPerpendStartA(aNormalizedPerpendicularA * 
-fHalfLineWidth);
+                const B2DVector aPerpendEndA(aNormalizedPerpendicularB * 
-fHalfLineWidth);
+                double fCutA(0.0);
+                const tools::CutFlagValue aCutA(tools::findCut(
+                    rEdge.getStartPoint(), aPerpendStartA,
+                    rEdge.getEndPoint(), aPerpendEndA, 
+                    CUTFLAG_ALL, &fCutA));
+                const bool bCutA(CUTFLAG_NONE != aCutA);
+
+                // create lower displacement vectors and check if they cut
+                const B2DVector aPerpendStartB(aNormalizedPerpendicularA * 
fHalfLineWidth);
+                const B2DVector aPerpendEndB(aNormalizedPerpendicularB * 
fHalfLineWidth);
+                double fCutB(0.0);
+                const tools::CutFlagValue aCutB(tools::findCut(
+                    rEdge.getEndPoint(), aPerpendEndB,
+                    rEdge.getStartPoint(), aPerpendStartB, 
+                    CUTFLAG_ALL, &fCutB));
+                const bool bCutB(CUTFLAG_NONE != aCutB);
 
-                // create upper edge.
+                // check if cut happens
+                const bool bCut(bCutA || bCutB);
+
+                // create left edge
+                if(bStartRound || bStartSquare)
                 {
-                    // create displacement vectors and check if they cut
-                    const B2DVector 
aPerpendStart(getNormalizedPerpendicular(aTangentA) * -fHalfLineWidth);
-                    const B2DVector 
aPerpendEnd(getNormalizedPerpendicular(aTangentB) * -fHalfLineWidth);
-                    double fCut(0.0);
-                    const tools::CutFlagValue aCut(tools::findCut(
-                        rEdge.getStartPoint(), aPerpendStart,
-                        rEdge.getEndPoint(), aPerpendEnd, 
-                        CUTFLAG_ALL, &fCut));
+                    basegfx::B2DPolygon aStartPolygon;
 
-                    if(CUTFLAG_NONE != aCut)
+                    if(bStartRound)
+                    {
+                        aStartPolygon = tools::createHalfUnitCircle();
+                        aStartPolygon.transform(
+                            
tools::createScaleShearXRotateTranslateB2DHomMatrix(
+                                fHalfLineWidth, fHalfLineWidth,
+                                0.0,
+                                atan2(aTangentA.getY(), aTangentA.getX()) + 
F_PI2,
+                                rEdge.getStartPoint().getX(), 
rEdge.getStartPoint().getY()));
+                    }
+                    else // bStartSquare
+                    {
+                        const basegfx::B2DPoint aStart(rEdge.getStartPoint() - 
(aTangentA * fHalfLineWidth));
+
+                        if(bCut)
+                        {
+                            aStartPolygon.append(rEdge.getStartPoint() + 
aPerpendStartB);
+                        }
+
+                        aStartPolygon.append(aStart + aPerpendStartB);
+                        aStartPolygon.append(aStart + aPerpendStartA);
+
+                        if(bCut)
+                        {
+                            aStartPolygon.append(rEdge.getStartPoint() + 
aPerpendStartA);
+                        }
+                    }
+
+                    if(bCut)
+                    {
+                        aStartPolygon.append(rEdge.getStartPoint());
+                        aStartPolygon.setClosed(true);
+                        aRetval.append(aStartPolygon);
+                    }
+                    else
+                    {
+                        aBezierPolygon.append(aStartPolygon);
+                    }
+                }
+                else
+                {
+                    // append original in-between point
+                    aBezierPolygon.append(rEdge.getStartPoint());
+                }
+
+                // create upper edge.
+                {
+                    if(bCutA)
                     {
                         // calculate cut point and add
-                        const B2DPoint aCutPoint(rEdge.getStartPoint() + 
(aPerpendStart * fCut));
+                        const B2DPoint aCutPoint(rEdge.getStartPoint() + 
(aPerpendStartA * fCutA));
                         aBezierPolygon.append(aCutPoint);
                     }
                     else
                     {
                         // create scaled bezier segment
-                        const B2DPoint aStart(rEdge.getStartPoint() + 
aPerpendStart);
-                        const B2DPoint aEnd(rEdge.getEndPoint() + aPerpendEnd);
+                        const B2DPoint aStart(rEdge.getStartPoint() + 
aPerpendStartA);
+                        const B2DPoint aEnd(rEdge.getEndPoint() + 
aPerpendEndA);
                         const B2DVector aEdge(aEnd - aStart);
                         const double fLength(aEdge.getLength());
                         const double fScale(bIsEdgeLengthZero ? 1.0 : fLength 
/ fEdgeLength);
@@ -388,31 +461,69 @@ namespace basegfx
                     }
                 }
 
-                // append original in-between point
-                aBezierPolygon.append(rEdge.getEndPoint());
+                // create right edge
+                if(bEndRound || bEndSquare)
+                {
+                    basegfx::B2DPolygon aEndPolygon;
 
-                // create lower edge. 
+                    if(bEndRound)
+                    {
+                        aEndPolygon = tools::createHalfUnitCircle();
+                        aEndPolygon.transform(
+                            
tools::createScaleShearXRotateTranslateB2DHomMatrix(
+                                fHalfLineWidth, fHalfLineWidth,
+                                0.0,
+                                atan2(aTangentB.getY(), aTangentB.getX()) - 
F_PI2,
+                                rEdge.getEndPoint().getX(), 
rEdge.getEndPoint().getY()));
+                    }
+                    else // bEndSquare
+                    {
+                        const basegfx::B2DPoint aEnd(rEdge.getEndPoint() + 
(aTangentB * fHalfLineWidth));
+
+                        if(bCut)
+                        {
+                            aEndPolygon.append(rEdge.getEndPoint() + 
aPerpendEndA);
+                        }
+
+                        aEndPolygon.append(aEnd + aPerpendEndA);
+                        aEndPolygon.append(aEnd + aPerpendEndB);
+
+                        if(bCut)
+                        {
+                            aEndPolygon.append(rEdge.getEndPoint() + 
aPerpendEndB);
+                        }
+                    }
+
+                    if(bCut)
+                    {
+                        aEndPolygon.append(rEdge.getEndPoint());
+                        aEndPolygon.setClosed(true);
+                        aRetval.append(aEndPolygon);
+                    }
+                    else
+                    {
+                        aBezierPolygon.append(aEndPolygon);
+                    }
+                }
+                else
                 {
-                    // create displacement vectors and check if they cut
-                    const B2DVector 
aPerpendStart(getNormalizedPerpendicular(aTangentA) * fHalfLineWidth);
-                    const B2DVector 
aPerpendEnd(getNormalizedPerpendicular(aTangentB) * fHalfLineWidth);
-                    double fCut(0.0);
-                    const tools::CutFlagValue aCut(tools::findCut(
-                        rEdge.getEndPoint(), aPerpendEnd,
-                        rEdge.getStartPoint(), aPerpendStart, 
-                        CUTFLAG_ALL, &fCut));
+                    // append original in-between point
+                    aBezierPolygon.append(rEdge.getEndPoint());
+                }
 
-                    if(CUTFLAG_NONE != aCut)
+                // create lower edge. 
+                {
+                    if(bCutB)
                     {
                         // calculate cut point and add
-                        const B2DPoint aCutPoint(rEdge.getEndPoint() + 
(aPerpendEnd * fCut));
+                        const B2DPoint aCutPoint(rEdge.getEndPoint() + 
(aPerpendEndB * fCutB));
                         aBezierPolygon.append(aCutPoint);
                     }
                     else
                     {
                         // create scaled bezier segment
-                        const B2DPoint aStart(rEdge.getEndPoint() + 
aPerpendEnd);
-                        const B2DPoint aEnd(rEdge.getStartPoint() + 
aPerpendStart);
+                        const B2DPoint aStart(rEdge.getEndPoint() + 
aPerpendEndB);
+                        const B2DPoint aEnd(rEdge.getStartPoint() + 
aPerpendStartB);
                         const B2DVector aEdge(aEnd - aStart);
                         const double fLength(aEdge.getLength());
                         const double fScale(bIsEdgeLengthZero ? 1.0 : fLength 
/ fEdgeLength);
@@ -424,39 +535,108 @@ namespace basegfx
                     }
                 }
 
-                // append original in-between point
-                aBezierPolygon.append(rEdge.getStartPoint());
-
                 // close and return
                 aBezierPolygon.setClosed(true);
-                return aBezierPolygon;
+                aRetval.append(aBezierPolygon);
+                
+                return aRetval;
             }
             else
             {
-                               // #i101491# emulate rEdge.getTangent call 
which applies a factor of 0.3 to the
-                               // full-length edge vector to have numerically 
exactly the same results as in the
-                               // createAreaGeometryForJoin implementation
-                   const B2DVector aEdgeTangent((rEdge.getEndPoint() - 
rEdge.getStartPoint()) * 0.3);
-                const B2DVector 
aPerpendEdgeVector(getNormalizedPerpendicular(aEdgeTangent) * fHalfLineWidth);
-                B2DPolygon aEdgePolygon;
+                // Get start and  end point, create tangent and set to needed 
length
+                B2DVector aTangent(rEdge.getEndPoint() - 
rEdge.getStartPoint());
+                aTangent.setLength(fHalfLineWidth);
                 
-                // create upper edge
-                aEdgePolygon.append(rEdge.getStartPoint() - 
aPerpendEdgeVector);
-                aEdgePolygon.append(rEdge.getEndPoint() - aPerpendEdgeVector);
-                
-                // append original in-between point
-                aEdgePolygon.append(rEdge.getEndPoint());
+                // prepare return value
+                B2DPolygon aEdgePolygon;
+
+                // buffered angle
+                double fAngle(0.0);
+                bool bAngle(false);
+
+                // buffered perpendicular
+                B2DVector aPerpend;
+                bool bPerpend(false);
+
+                // create left vertical
+                if(bStartRound)
+                {
+                    aEdgePolygon = tools::createHalfUnitCircle();
+                    fAngle = atan2(aTangent.getY(), aTangent.getX());
+                    bAngle = true;
+                    aEdgePolygon.transform(
+                        tools::createScaleShearXRotateTranslateB2DHomMatrix(
+                            fHalfLineWidth, fHalfLineWidth,
+                            0.0,
+                            fAngle + F_PI2,
+                            rEdge.getStartPoint().getX(), 
rEdge.getStartPoint().getY()));
+                }
+                else
+                {
+                    aPerpend.setX(-aTangent.getY());
+                    aPerpend.setY(aTangent.getX());
+                    bPerpend = true;
+
+                    if(bStartSquare)
+                    {
+                        const basegfx::B2DPoint aStart(rEdge.getStartPoint() - 
aTangent);
+
+                        aEdgePolygon.append(aStart + aPerpend);
+                        aEdgePolygon.append(aStart - aPerpend);
+                    }
+                    else
+                    {
+                        aEdgePolygon.append(rEdge.getStartPoint() + aPerpend);
+                        aEdgePolygon.append(rEdge.getStartPoint()); // keep 
the in-between point for numerical reasons
+                        aEdgePolygon.append(rEdge.getStartPoint() - aPerpend);
+                    }
+                }
 
-                // create lower edge
-                aEdgePolygon.append(rEdge.getEndPoint() + aPerpendEdgeVector);
-                aEdgePolygon.append(rEdge.getStartPoint() + 
aPerpendEdgeVector);
+                // create right vertical
+                if(bEndRound)
+                {
+                    basegfx::B2DPolygon 
aEndPolygon(tools::createHalfUnitCircle());
 
-                // append original in-between point
-                aEdgePolygon.append(rEdge.getStartPoint());
+                    if(!bAngle)
+                    {
+                        fAngle = atan2(aTangent.getY(), aTangent.getX());
+                    }
+
+                    aEndPolygon.transform(
+                        tools::createScaleShearXRotateTranslateB2DHomMatrix(
+                            fHalfLineWidth, fHalfLineWidth,
+                            0.0,
+                            fAngle - F_PI2,
+                            rEdge.getEndPoint().getX(), 
rEdge.getEndPoint().getY()));
+                    aEdgePolygon.append(aEndPolygon);
+                }
+                else
+                {
+                    if(!bPerpend)
+                    {
+                        aPerpend.setX(-aTangent.getY());
+                        aPerpend.setY(aTangent.getX());
+                    }
+
+                    if(bEndSquare)
+                    {
+                        const basegfx::B2DPoint aEnd(rEdge.getEndPoint() + 
aTangent);
+
+                        aEdgePolygon.append(aEnd - aPerpend);
+                        aEdgePolygon.append(aEnd + aPerpend);
+                    }
+                    else
+                    {
+                        aEdgePolygon.append(rEdge.getEndPoint() - aPerpend);
+                        aEdgePolygon.append(rEdge.getEndPoint()); // keep the 
in-between point for numerical reasons
+                        aEdgePolygon.append(rEdge.getEndPoint() + aPerpend);
+                    }
+                }
 
                 // close and return
                 aEdgePolygon.setClosed(true);
-                return aEdgePolygon;
+
+                return B2DPolyPolygon(aEdgePolygon);
             }
         }
 
@@ -567,82 +747,6 @@ namespace basegfx
 
             return aEdgePolygon;
         }
-
-        B2DPolygon createAreaGeometryForCap(
-            const B2DVector& rTangent,
-            const B2DPoint& rPoint,
-            double fHalfLineWidth,
-            com::sun::star::drawing::LineCap eCap,
-            bool bIsStart)
-        {
-            OSL_ENSURE(fHalfLineWidth > 0.0, "createAreaGeometryForJoin: 
LineWidth too small (!)");
-
-            const B2DVector aScaledPerpend(getNormalizedPerpendicular(rTangent)
-                                 * (bIsStart ? fHalfLineWidth : 
-fHalfLineWidth));
-            // Vector from rPoint towards cap
-            B2DVector aScaledTangent(rTangent);
-            aScaledTangent.normalize();
-            aScaledTangent *= (bIsStart ? -fHalfLineWidth : fHalfLineWidth);
-
-            B2DPolygon aCapPolygon;
-            const B2DPoint aStartPoint(rPoint + aScaledPerpend);
-            const B2DPoint aEndPoint(rPoint - aScaledPerpend);
-
-            switch(eCap)
-            {
-                case com::sun::star::drawing::LineCap_ROUND :
-                {
-                    // use tooling to add needed EllipseSegment
-                    double fAngleStart(atan2(aScaledPerpend.getY(), 
aScaledPerpend.getX()));
-
-                    // atan2 results are [-PI .. PI], consolidate to [0.0 .. 
2PI]
-                    if(fAngleStart < 0.0)
-                    {
-                        fAngleStart += F_2PI;
-                    }
-
-                    double fAngleEnd = fAngleStart + F_PI;
-                    if(fAngleEnd > F_2PI)
-                    {
-                        fAngleEnd -= F_2PI;
-                    }
-
-                    const B2DPolygon 
aBow(tools::createPolygonFromEllipseSegment(rPoint, fHalfLineWidth, 
fHalfLineWidth, fAngleStart, fAngleEnd));
-                    // #i101491#
-                    // use the original start/end positions; the ones from bow 
creation may be numerically
-                    // different due to their different creation. To guarantee 
good merging quality with edges
-                    // and edge roundings (and to reduce point count)
-                    
-                    // ToDo Are there at least two points in aBow ?
-                    aCapPolygon = aBow;
-                    aCapPolygon.setB2DPoint(0, aStartPoint);
-                    aCapPolygon.setB2DPoint(aBow.count() - 1, aEndPoint);
-                    aCapPolygon.append(rPoint);
-                    break;
-                }
-                case com::sun::star::drawing::LineCap_SQUARE :
-                {
-                    aCapPolygon.append(aStartPoint);
-                    aCapPolygon.append(aStartPoint + aScaledTangent);
-                    aCapPolygon.append(aEndPoint + aScaledTangent);
-                    aCapPolygon.append(aEndPoint);
-                    aCapPolygon.append(rPoint);
-                    break;
-                }
-                default: // com::sun::star::drawing::LineCap_BUTT
-                {
-                    // No cap.
-                    // ToDo. Is actually not called with BUTT. What setting is
-                    // useful to prevend errors, if called with BUTT anyway?
-                    break;
-                }
-            }
-
-            // create last polygon part for cap
-            aCapPolygon.setClosed(true);
-
-            return aCapPolygon;
-        }
     } // end of anonymus namespace
 
        namespace tools
@@ -697,7 +801,7 @@ namespace basegfx
                                const bool 
bEventuallyCreateLineJoin(B2DLINEJOIN_NONE != eJoin);
                 const bool bIsClosed(aCandidate.isClosed());
                 const sal_uInt32 nEdgeCount(bIsClosed ? nPointCount : 
nPointCount - 1);
-                const bool 
bCreateLineCap(com::sun::star::drawing::LineCap_BUTT != eCap);
+                const bool bLineCap(!bIsClosed && 
com::sun::star::drawing::LineCap_BUTT != eCap);
 
                 if(nEdgeCount)
                 {
@@ -707,18 +811,6 @@ namespace basegfx
                     // prepare edge
                     aEdge.setStartPoint(aCandidate.getB2DPoint(0));
 
-                    // eventually create start line cap
-                    if (!bIsClosed && bCreateLineCap)
-                    {
-                      
aEdge.setControlPointA(aCandidate.getNextControlPoint(0));
-                      aEdge.setControlPointB(aCandidate.getPrevControlPoint(1 
% nPointCount));
-                      aEdge.setEndPoint(aCandidate.getB2DPoint(1 % nPointCount 
));
-                      const B2DVector aTangentStart(aEdge.getTangent(0.0));
-                      aRetval.append(createAreaGeometryForCap(
-                                    aTangentStart, aEdge.getStartPoint(),
-                                    fHalfLineWidth, eCap, true /*IsStart*/));
-                    }
-
                     if(bIsClosed && bEventuallyCreateLineJoin)
                     {
                         // prepare previous edge
@@ -740,85 +832,110 @@ namespace basegfx
                         // check and create linejoin
                         if(bEventuallyCreateLineJoin && (bIsClosed || 0 != a))
                         {
-                                           const B2DVector 
aTangentPrev(aPrev.getTangent(1.0));
-                                           const B2DVector 
aTangentEdge(aEdge.getTangent(0.0));
+                            B2DVector aTangentPrev(aPrev.getTangent(1.0)); 
aTangentPrev.normalize();
+                            B2DVector aTangentEdge(aEdge.getTangent(0.0)); 
aTangentEdge.normalize();
                             B2VectorOrientation 
aOrientation(getOrientation(aTangentPrev, aTangentEdge));
 
-                                                       if(ORIENTATION_NEUTRAL 
== aOrientation)
-                                                       {
-                                                               // they are 
parallell or empty; if they are both not zero and point 
-                                                               // in opposite 
direction, a half-circle is needed
-                                                               
if(!aTangentPrev.equalZero() && !aTangentEdge.equalZero())
-                                                               {
-                                                                       const 
double fAngle(fabs(aTangentPrev.angle(aTangentEdge)));
-
-                                                                       
if(fTools::equal(fAngle, F_PI))
-                                                                       {
+                            if(ORIENTATION_NEUTRAL == aOrientation)
+                            {
+                                   // they are parallell or empty; if they are 
both not zero and point 
+                                   // in opposite direction, a half-circle is 
needed
+                                   if(!aTangentPrev.equalZero() && 
!aTangentEdge.equalZero())
+                                   {
+                                    const double 
fAngle(fabs(aTangentPrev.angle(aTangentEdge)));
+        
+                                    if(fTools::equal(fAngle, F_PI))
+                                    {
                                         // for half-circle production, 
fallback to positive
                                         // orientation
-                                                                               
aOrientation = ORIENTATION_POSITIVE;
-                                                                       }
-                                                               }
-                                                       }
+                                        aOrientation = ORIENTATION_POSITIVE;
+                                    }
+                                }
+                            }
 
                             if(ORIENTATION_POSITIVE == aOrientation)
                             {
-                                                               const B2DVector 
aPerpendPrev(getNormalizedPerpendicular(aTangentPrev) * -fHalfLineWidth);
-                                                               const B2DVector 
aPerpendEdge(getNormalizedPerpendicular(aTangentEdge) * -fHalfLineWidth);
+                                const B2DVector 
aPerpendPrev(getPerpendicular(aTangentPrev) * -fHalfLineWidth);
+                                const B2DVector 
aPerpendEdge(getPerpendicular(aTangentEdge) * -fHalfLineWidth);
                                 
-                                                               
aRetval.append(createAreaGeometryForJoin(
-                                    aTangentPrev, aTangentEdge,
-                                    aPerpendPrev, aPerpendEdge, 
-                                                                       
aEdge.getStartPoint(), fHalfLineWidth, 
-                                    eJoin, fMiterMinimumAngle));
+                                aRetval.append(
+                                    createAreaGeometryForJoin(
+                                        aTangentPrev, 
+                                        aTangentEdge,
+                                        aPerpendPrev, 
+                                        aPerpendEdge, 
+                                        aEdge.getStartPoint(), 
+                                        fHalfLineWidth, 
+                                        eJoin, 
+                                        fMiterMinimumAngle));
                             }
                             else if(ORIENTATION_NEGATIVE == aOrientation)
                             {
-                                                               const B2DVector 
aPerpendPrev(getNormalizedPerpendicular(aTangentPrev) * fHalfLineWidth);
-                                                               const B2DVector 
aPerpendEdge(getNormalizedPerpendicular(aTangentEdge) * fHalfLineWidth);
+                                const B2DVector 
aPerpendPrev(getPerpendicular(aTangentPrev) * fHalfLineWidth);
+                                const B2DVector 
aPerpendEdge(getPerpendicular(aTangentEdge) * fHalfLineWidth);
 
-                                                               
aRetval.append(createAreaGeometryForJoin(
-                                    aTangentEdge, aTangentPrev,
-                                    aPerpendEdge, aPerpendPrev, 
-                                                                       
aEdge.getStartPoint(), fHalfLineWidth, 
-                                    eJoin, fMiterMinimumAngle));
+                                aRetval.append(
+                                    createAreaGeometryForJoin(
+                                        aTangentEdge, 
+                                        aTangentPrev,
+                                        aPerpendEdge, 
+                                        aPerpendPrev, 
+                                        aEdge.getStartPoint(), 
+                                        fHalfLineWidth, 
+                                        eJoin, 
+                                        fMiterMinimumAngle));
                             }
                         }
 
                         // create geometry for edge
-                               aRetval.append(createAreaGeometryForEdge(aEdge, 
fHalfLineWidth));
+                        const bool bLast(a + 1 == nEdgeCount);
 
-                        // prepare next step
-                        if(bEventuallyCreateLineJoin)
+                        if(bLineCap)
+                        {
+                            const bool bFirst(!a);
+
+                            aRetval.append(
+                                createAreaGeometryForEdge(
+                                    aEdge, 
+                                    fHalfLineWidth,
+                                    bFirst && 
com::sun::star::drawing::LineCap_ROUND == eCap,
+                                    bLast && 
com::sun::star::drawing::LineCap_ROUND == eCap,
+                                    bFirst && 
com::sun::star::drawing::LineCap_SQUARE == eCap,
+                                    bLast && 
com::sun::star::drawing::LineCap_SQUARE == eCap));
+                        }
+                        else
                         {
-                            aPrev = aEdge;
+                            aRetval.append(
+                                createAreaGeometryForEdge(
+                                    aEdge, 
+                                    fHalfLineWidth,
+                                    false,
+                                    false,
+                                    false,
+                                    false));
                         }
 
-                        aEdge.setStartPoint(aEdge.getEndPoint());
-                    }
+                        // prepare next step
+                        if(!bLast)
+                        {
+                            if(bEventuallyCreateLineJoin)
+                            {
+                                aPrev = aEdge;
+                            }
 
-                    // eventually create end line cap
-                    if (!bIsClosed && bCreateLineCap)
-                    {
-                        aEdge.setStartPoint(aCandidate.getB2DPoint(nEdgeCount 
-1));
-                        
aEdge.setControlPointA(aCandidate.getNextControlPoint(nEdgeCount -1));
-                        
aEdge.setControlPointB(aCandidate.getPrevControlPoint(nEdgeCount % 
nPointCount));
-                        aEdge.setEndPoint(aCandidate.getB2DPoint(nEdgeCount % 
nPointCount ));
-                        const B2DVector aTangentEnd(aEdge.getTangent(1.0));
-                        aRetval.append(createAreaGeometryForCap(
-                                    aTangentEnd, aEdge.getEndPoint(),
-                                    fHalfLineWidth, eCap, false /*IsStart*/));
+                            aEdge.setStartPoint(aEdge.getEndPoint());
+                        }
                     }
                 }
-                // ToDo Returns empty PolyPolygon if rCandidate is a single 
point?
+
                 return aRetval;
-                       }
+            }
             else
             {
                 return B2DPolyPolygon(rCandidate);
             }
-               }
-       } // end of namespace tools
+        }
+    } // end of namespace tools
 } // end of namespace basegfx
 
 //////////////////////////////////////////////////////////////////////////////

Modified: 
incubator/ooo/branches/alg/linecap/main/basegfx/source/polygon/b2dpolygontools.cxx
URL: 
http://svn.apache.org/viewvc/incubator/ooo/branches/alg/linecap/main/basegfx/source/polygon/b2dpolygontools.cxx?rev=1229503&r1=1229502&r2=1229503&view=diff
==============================================================================
--- 
incubator/ooo/branches/alg/linecap/main/basegfx/source/polygon/b2dpolygontools.cxx
 (original)
+++ 
incubator/ooo/branches/alg/linecap/main/basegfx/source/polygon/b2dpolygontools.cxx
 Tue Jan 10 11:00:48 2012
@@ -1889,6 +1889,33 @@ namespace basegfx
             return aUnitCircle;
         }
 
+        B2DPolygon createHalfUnitCircle()
+        {
+            static B2DPolygon aUnitHalfCircle;
+
+            if(!aUnitHalfCircle.count())
+            {
+                const double fKappa((M_SQRT2 - 1.0) * 4.0 / 3.0);
+                const double fScaledKappa(fKappa * (1.0 / STEPSPERQUARTER));
+                const B2DHomMatrix 
aRotateMatrix(createRotateB2DHomMatrix(F_PI2 / STEPSPERQUARTER));
+                B2DPoint aPoint(1.0, 0.0);
+                B2DPoint aForward(1.0, fScaledKappa);
+                B2DPoint aBackward(1.0, -fScaledKappa);
+
+                aUnitHalfCircle.append(aPoint);
+
+                for(sal_uInt32 a(0); a < STEPSPERQUARTER * 2; a++)
+                {
+                    aPoint *= aRotateMatrix;
+                    aBackward *= aRotateMatrix;
+                    aUnitHalfCircle.appendBezierSegment(aForward, aBackward, 
aPoint);
+                    aForward *= aRotateMatrix;
+                }
+            }
+
+            return aUnitHalfCircle;
+        }
+
         B2DPolygon createPolygonFromUnitCircle(sal_uInt32 nStartQuadrant)
                {
             switch(nStartQuadrant % 4)

Modified: 
incubator/ooo/branches/alg/linecap/main/drawinglayer/inc/drawinglayer/primitive3d/polygontubeprimitive3d.hxx
URL: 
http://svn.apache.org/viewvc/incubator/ooo/branches/alg/linecap/main/drawinglayer/inc/drawinglayer/primitive3d/polygontubeprimitive3d.hxx?rev=1229503&r1=1229502&r2=1229503&view=diff
==============================================================================
--- 
incubator/ooo/branches/alg/linecap/main/drawinglayer/inc/drawinglayer/primitive3d/polygontubeprimitive3d.hxx
 (original)
+++ 
incubator/ooo/branches/alg/linecap/main/drawinglayer/inc/drawinglayer/primitive3d/polygontubeprimitive3d.hxx
 Tue Jan 10 11:00:48 2012
@@ -59,6 +59,7 @@ namespace drawinglayer
                        double                                                  
                        mfDegreeStepWidth;
                        double                                                  
                        mfMiterMinimumAngle;
                        basegfx::B2DLineJoin                                    
    maLineJoin;
+            com::sun::star::drawing::LineCap            maLineCap;
 
                protected:
                        /** access methods to maLast3DDecomposition. The usage 
of this methods may allow
@@ -76,7 +77,9 @@ namespace drawinglayer
                        PolygonTubePrimitive3D(
                                const basegfx::B3DPolygon& rPolygon, 
                                const basegfx::BColor& rBColor,
-                               double fRadius, basegfx::B2DLineJoin aLineJoin,
+                               double fRadius, 
+                basegfx::B2DLineJoin aLineJoin,
+                com::sun::star::drawing::LineCap aLineCap,
                                double fDegreeStepWidth = 10.0 * F_PI180,
                                double fMiterMinimumAngle = 15.0 * F_PI180);
 
@@ -85,6 +88,7 @@ namespace drawinglayer
                        double getDegreeStepWidth() const { return 
mfDegreeStepWidth; }
                        double getMiterMinimumAngle() const { return 
mfMiterMinimumAngle; }
                        basegfx::B2DLineJoin getLineJoin() const { return 
maLineJoin; }
+            com::sun::star::drawing::LineCap getLineCap() const { return 
maLineCap; }
 
                        /// compare operator
                        virtual bool operator==(const BasePrimitive3D& 
rPrimitive) const;

Modified: 
incubator/ooo/branches/alg/linecap/main/drawinglayer/source/primitive3d/polygonprimitive3d.cxx
URL: 
http://svn.apache.org/viewvc/incubator/ooo/branches/alg/linecap/main/drawinglayer/source/primitive3d/polygonprimitive3d.cxx?rev=1229503&r1=1229502&r2=1229503&view=diff
==============================================================================
--- 
incubator/ooo/branches/alg/linecap/main/drawinglayer/source/primitive3d/polygonprimitive3d.cxx
 (original)
+++ 
incubator/ooo/branches/alg/linecap/main/drawinglayer/source/primitive3d/polygonprimitive3d.cxx
 Tue Jan 10 11:00:48 2012
@@ -106,11 +106,18 @@ namespace drawinglayer
                                        // create fat line data
                                        const double 
fRadius(getLineAttribute().getWidth() / 2.0);
                                        const basegfx::B2DLineJoin 
aLineJoin(getLineAttribute().getLineJoin());
+                    const com::sun::star::drawing::LineCap 
aLineCap(getLineAttribute().getLineCap());
 
                                        for(sal_uInt32 a(0L); a < 
aHairLinePolyPolygon.count(); a++)
                                        {
                                                // create tube primitives
-                                               const Primitive3DReference 
xRef(new PolygonTubePrimitive3D(aHairLinePolyPolygon.getB3DPolygon(a), 
getLineAttribute().getColor(), fRadius, aLineJoin));
+                                               const Primitive3DReference xRef(
+                            new PolygonTubePrimitive3D(
+                                aHairLinePolyPolygon.getB3DPolygon(a), 
+                                getLineAttribute().getColor(), 
+                                fRadius, 
+                                aLineJoin,
+                                aLineCap));
                                                aRetval[a] = xRef;
                                        }
                                }

Modified: 
incubator/ooo/branches/alg/linecap/main/drawinglayer/source/primitive3d/polygontubeprimitive3d.cxx
URL: 
http://svn.apache.org/viewvc/incubator/ooo/branches/alg/linecap/main/drawinglayer/source/primitive3d/polygontubeprimitive3d.cxx?rev=1229503&r1=1229502&r2=1229503&view=diff
==============================================================================
--- 
incubator/ooo/branches/alg/linecap/main/drawinglayer/source/primitive3d/polygontubeprimitive3d.cxx
 (original)
+++ 
incubator/ooo/branches/alg/linecap/main/drawinglayer/source/primitive3d/polygontubeprimitive3d.cxx
 Tue Jan 10 11:00:48 2012
@@ -156,6 +156,76 @@ namespace drawinglayer
                                return aLineCapList;
                        }
 
+            Primitive3DSequence getLineCapRoundSegments(
+                sal_uInt32 nSegments, 
+                const attribute::MaterialAttribute3D& rMaterial)
+            {
+                // static data for buffered tube primitives
+                static Primitive3DSequence aLineCapRoundList;
+                static sal_uInt32 nLineCapRoundSegments(0);
+                static attribute::MaterialAttribute3D aLineMaterial;
+
+                // may exclusively change static data, use mutex
+                ::osl::Mutex m_mutex;
+
+                if(nSegments != nLineCapRoundSegments || !(rMaterial == 
aLineMaterial))
+                {
+                    nLineCapRoundSegments = nSegments;
+                    aLineMaterial = rMaterial;
+                    aLineCapRoundList = Primitive3DSequence();
+                }
+                
+                if(!aLineCapRoundList.hasElements() && nLineCapRoundSegments)
+                {
+                    // calculate new horizontal segments
+                    sal_uInt32 nVerSeg(nSegments / 2);
+
+                    if(nVerSeg < 1)
+                    {
+                        nVerSeg = 1;
+                    }
+
+                    // create half-sphere; upper half of unit sphere
+                    basegfx::B3DPolyPolygon aSphere(
+                        basegfx::tools::createUnitSphereFillPolyPolygon(
+                            nSegments, 
+                            nVerSeg, 
+                            true, 
+                            F_PI2, 0.0, 
+                            0.0, F_2PI));
+                    const sal_uInt32 nCount(aSphere.count());
+
+                    if(nCount)
+                    {
+                        // rotate to have sphere cap orientned to negative 
X-Axis; do not
+                        // forget to transform normals, too
+                        basegfx::B3DHomMatrix aSphereTrans;
+
+                        aSphereTrans.rotate(0.0, 0.0, F_PI2);
+                        aSphere.transform(aSphereTrans);
+                        aSphere.transformNormals(aSphereTrans);
+
+                        // realloc for primitives and create based on polygon 
snippets
+                        aLineCapRoundList.realloc(nCount);
+
+                        for(sal_uInt32 a(0); a < nCount; a++)
+                        {
+                            const basegfx::B3DPolygon 
aPartPolygon(aSphere.getB3DPolygon(a));
+                            const basegfx::B3DPolyPolygon 
aPartPolyPolygon(aPartPolygon);
+
+                            // need to create one primitive per Polygon since 
the primitive
+                            // is for planar PolyPolygons which is definitely 
not the case here
+                            aLineCapRoundList[a] = new 
PolyPolygonMaterialPrimitive3D(
+                                aPartPolyPolygon, 
+                                rMaterial, 
+                                false);
+                        }
+                    }
+                }
+                
+                return aLineCapRoundList;
+            }
+
                        Primitive3DSequence getLineJoinSegments(
                                sal_uInt32 nSegments, 
                                const attribute::MaterialAttribute3D& 
rMaterial, 
@@ -173,7 +243,7 @@ namespace drawinglayer
                                        if(basegfx::B2DLINEJOIN_ROUND == 
aLineJoin)
                                        {
                                                // calculate new horizontal 
segments
-                                               const sal_uInt32 
nHorSeg((sal_uInt32)((fAngle / F_2PI) * (double)nSegments));
+                                               const sal_uInt32 
nHorSeg(basegfx::fround((fAngle / F_2PI) * (double)nSegments));
 
                                                if(nHorSeg)
                                                {
@@ -403,100 +473,188 @@ using namespace com::sun::star;
 
 namespace drawinglayer
 {
-       namespace primitive3d
-       {
-               Primitive3DSequence 
PolygonTubePrimitive3D::impCreate3DDecomposition(const 
geometry::ViewInformation3D& /*rViewInformation*/) const
-               {
-                       const sal_uInt32 nPointCount(getB3DPolygon().count());
-                       std::vector< BasePrimitive3D* > aResultVector;
-
-                       if(0L != nPointCount)
-                       {
-                               if(basegfx::fTools::more(getRadius(), 0.0))
-                               {
-                                       const attribute::MaterialAttribute3D 
aMaterial(getBColor());
-                                       static sal_uInt32 nSegments(8L); // 
default for 3d line segments, for more quality just raise this value (in even 
steps)
-                                       const bool 
bClosed(getB3DPolygon().isClosed());
-                                       const bool 
bNoLineJoin(basegfx::B2DLINEJOIN_NONE == getLineJoin());
-                                       const sal_uInt32 nLoopCount(bClosed ? 
nPointCount : nPointCount - 1L);
-                                       basegfx::B3DPoint 
aLast(getB3DPolygon().getB3DPoint(nPointCount - 1L));
-                                       basegfx::B3DPoint 
aCurr(getB3DPolygon().getB3DPoint(0L));
-
-                                       for(sal_uInt32 a(0L); a < nLoopCount; 
a++)
-                                       {
-                                               // get next data
-                                               const basegfx::B3DPoint 
aNext(getB3DPolygon().getB3DPoint((a + 1L) % nPointCount));
-                                               const basegfx::B3DVector 
aForw(aNext - aCurr);
-                                               const double 
fForwLen(aForw.getLength());
-
-                                               
if(basegfx::fTools::more(fForwLen, 0.0))
-                                               {
-                                                       // get rotation from 
vector, this describes rotation from (1, 0, 0) to aForw
-                                                       basegfx::B3DHomMatrix 
aRotVector(getRotationFromVector(aForw));
-
-                                                       // create default 
transformation with scale and rotate
-                                                       basegfx::B3DHomMatrix 
aVectorTrans;
-                                                       
aVectorTrans.scale(fForwLen, getRadius(), getRadius());
-                                                       aVectorTrans *= 
aRotVector;
-                                                       
aVectorTrans.translate(aCurr.getX(), aCurr.getY(), aCurr.getZ());
-
-                                                       if(bNoLineJoin || 
(!bClosed && !a))
-                                                       {
-                                                               // line start 
edge, build transformed primitiveVector3D
-                                                               
TransformPrimitive3D* pNewTransformedA = new TransformPrimitive3D(aVectorTrans, 
getLineCapSegments(nSegments, aMaterial));
-                                                               
aResultVector.push_back(pNewTransformedA);
-                                                       }
-                                                       else
-                                                       {
-                                                               const 
basegfx::B3DVector aBack(aCurr - aLast);
-                                                               const double 
fCross(basegfx::cross(aBack, aForw).getLength());
-
-                                                               
if(!basegfx::fTools::equalZero(fCross))
-                                                               {
-                                                                       // line 
connect non-parallel, aBack, aForw, use getLineJoin()
-                                                                       const 
double fAngle(acos(aBack.scalar(aForw) / (fForwLen * aBack.getLength()))); // 
0.0 .. F_PI2
-                                                                       
Primitive3DSequence aNewList(getLineJoinSegments(nSegments, aMaterial, fAngle, 
getDegreeStepWidth(), getMiterMinimumAngle(), getLineJoin()));
-
-                                                                       // 
calculate transformation. First, get angle in YZ between nForw projected on (1, 
0, 0) and nBack
-                                                                       
basegfx::B3DHomMatrix aInvRotVector(aRotVector);
-                                                                       
aInvRotVector.invert();
-                                                                       
basegfx::B3DVector aTransBack(aInvRotVector * aBack);
-                                                                       const 
double fRotInYZ(atan2(aTransBack.getY(), aTransBack.getZ()));
-
-                                                                       // 
create trans by rotating unit sphere with angle 90 degrees around Y, then 
180-fRot in X.
-                                                                       // Also 
apply usual scaling and translation
-                                                                       
basegfx::B3DHomMatrix aSphereTrans;
-                                                                       
aSphereTrans.rotate(0.0, F_PI2, 0.0);
-                                                                       
aSphereTrans.rotate(F_PI - fRotInYZ, 0.0, 0.0);
-                                                                       
aSphereTrans *= aRotVector;
-                                                                       
aSphereTrans.scale(getRadius(), getRadius(), getRadius());
-                                                                       
aSphereTrans.translate(aCurr.getX(), aCurr.getY(), aCurr.getZ());
-
-                                                                       // line 
start edge, build transformed primitiveVector3D
-                                                                       
TransformPrimitive3D* pNewTransformedB = new TransformPrimitive3D(aSphereTrans, 
aNewList);
-                                                                       
aResultVector.push_back(pNewTransformedB);
-                                                               }
-                                                       }
-
-                                                       // create line 
segments, build transformed primitiveVector3D
-                                                       TransformPrimitive3D* 
pNewTransformedC = new TransformPrimitive3D(aVectorTrans, 
getLineTubeSegments(nSegments, aMaterial));
-                                                       
aResultVector.push_back(pNewTransformedC);
-
-                                                       if(bNoLineJoin || 
(!bClosed && ((a + 1L) == nLoopCount)))
-                                                       {
-                                                               // line end 
edge, first rotate (mirror) and translate, then use use aRotVector
-                                                               
basegfx::B3DHomMatrix aBackTrans;
-                                                               
aBackTrans.rotate(0.0, F_PI, 0.0);
-                                                               
aBackTrans.translate(1.0, 0.0, 0.0);
-                                                               
aBackTrans.scale(fForwLen, getRadius(), getRadius());
-                                                               aBackTrans *= 
aRotVector;
-                                                               
aBackTrans.translate(aCurr.getX(), aCurr.getY(), aCurr.getZ());
-                                                               
-                                                               // line end 
edge, build transformed primitiveVector3D
-                                                               
TransformPrimitive3D* pNewTransformedD = new TransformPrimitive3D(aBackTrans, 
getLineCapSegments(nSegments, aMaterial));
-                                                               
aResultVector.push_back(pNewTransformedD);
-                                                       }
-                                               }
+    namespace primitive3d
+    {
+        Primitive3DSequence 
PolygonTubePrimitive3D::impCreate3DDecomposition(const 
geometry::ViewInformation3D& /*rViewInformation*/) const
+        {
+            const sal_uInt32 nPointCount(getB3DPolygon().count());
+            std::vector< BasePrimitive3D* > aResultVector;
+            
+            if(nPointCount)
+            {
+                if(basegfx::fTools::more(getRadius(), 0.0))
+                {
+                    const attribute::MaterialAttribute3D 
aMaterial(getBColor());
+                    static sal_uInt32 nSegments(8); // default for 3d line 
segments, for more quality just raise this value (in even steps)
+                    const bool bClosed(getB3DPolygon().isClosed());
+                    const bool bNoLineJoin(basegfx::B2DLINEJOIN_NONE == 
getLineJoin());
+                    const sal_uInt32 nLoopCount(bClosed ? nPointCount : 
nPointCount - 1);
+                    basegfx::B3DPoint 
aLast(getB3DPolygon().getB3DPoint(nPointCount - 1));
+                    basegfx::B3DPoint aCurr(getB3DPolygon().getB3DPoint(0));
+                    
+                    for(sal_uInt32 a(0); a < nLoopCount; a++)
+                    {
+                        // get next data
+                        const basegfx::B3DPoint 
aNext(getB3DPolygon().getB3DPoint((a + 1) % nPointCount));
+                        const basegfx::B3DVector aForw(aNext - aCurr);
+                        const double fForwLen(aForw.getLength());
+                        
+                        if(basegfx::fTools::more(fForwLen, 0.0))
+                        {
+                            // find out if linecap is active
+                            const bool bFirst(!a);
+                            const bool bLast(a + 1 == nLoopCount);
+                            const bool bLineCapPossible(!bClosed && (bFirst || 
bLast));
+                            const bool bLineCapRound(bLineCapPossible && 
com::sun::star::drawing::LineCap_ROUND == getLineCap());
+                            const bool bLineCapSquare(bLineCapPossible && 
com::sun::star::drawing::LineCap_SQUARE == getLineCap());
+
+                            // get rotation from vector, this describes 
rotation from (1, 0, 0) to aForw
+                            basegfx::B3DHomMatrix 
aRotVector(getRotationFromVector(aForw));
+
+                            // prepare transformations for tube and cap
+                            basegfx::B3DHomMatrix aTubeTrans;
+                            basegfx::B3DHomMatrix aCapTrans;
+
+                            // cap gets radius size
+                            aCapTrans.scale(getRadius(), getRadius(), 
getRadius());
+
+                            if(bLineCapSquare)
+                            {
+                                // when square line cap just prolong line 
segment in X, maybe 2 x radius when
+                                // first and last (simple line segment)
+                                const double fExtraLength(bFirst && bLast ? 
getRadius() * 2.0 : getRadius());
+                                
+                                aTubeTrans.scale(fForwLen + fExtraLength, 
getRadius(), getRadius());
+
+                                if(bFirst)
+                                {
+                                    // correct start positions for tube and 
cap when first and square prolonged
+                                    aTubeTrans.translate(-getRadius(), 0.0, 
0.0);
+                                    aCapTrans.translate(-getRadius(), 0.0, 
0.0);
+                                }
+                            }
+                            else
+                            {
+                                // normal tube size
+                                aTubeTrans.scale(fForwLen, getRadius(), 
getRadius());
+                            }
+
+                            // rotate and translate tube and cap
+                            aTubeTrans *= aRotVector;
+                            aTubeTrans.translate(aCurr.getX(), aCurr.getY(), 
aCurr.getZ());
+                            aCapTrans *= aRotVector;
+                            aCapTrans.translate(aCurr.getX(), aCurr.getY(), 
aCurr.getZ());
+
+                            if(bNoLineJoin || (!bClosed && bFirst))
+                            {
+                                // line start edge, build transformed 
primitiveVector3D
+                                Primitive3DSequence aSequence;
+
+                                if(bLineCapRound && bFirst)
+                                {
+                                    // LineCapRound used
+                                    aSequence = 
getLineCapRoundSegments(nSegments, aMaterial);
+                                }
+                                else
+                                {
+                                    // simple closing cap
+                                    aSequence = getLineCapSegments(nSegments, 
aMaterial);
+                                }
+
+                                TransformPrimitive3D* pNewTransformedA = new 
TransformPrimitive3D(aCapTrans, aSequence);
+                                aResultVector.push_back(pNewTransformedA);
+                            }
+                            else
+                            {
+                                const basegfx::B3DVector aBack(aCurr - aLast);
+                                const double fCross(basegfx::cross(aBack, 
aForw).getLength());
+
+                                if(!basegfx::fTools::equalZero(fCross))
+                                {
+                                    // line connect non-parallel, aBack, 
aForw, use getLineJoin()
+                                    const double 
fAngle(acos(aBack.scalar(aForw) / (fForwLen * aBack.getLength()))); // 0.0 .. 
F_PI2
+                                    Primitive3DSequence aNewList(
+                                        getLineJoinSegments(
+                                            nSegments, 
+                                            aMaterial, 
+                                            fAngle, 
+                                            getDegreeStepWidth(), 
+                                            getMiterMinimumAngle(), 
+                                            getLineJoin()));
+
+                                    // calculate transformation. First, get 
angle in YZ between nForw projected on (1, 0, 0) and nBack
+                                    basegfx::B3DHomMatrix 
aInvRotVector(aRotVector);
+                                    aInvRotVector.invert();
+                                    basegfx::B3DVector 
aTransBack(aInvRotVector * aBack);
+                                    const double 
fRotInYZ(atan2(aTransBack.getY(), aTransBack.getZ()));
+                                    
+                                    // create trans by rotating unit sphere 
with angle 90 degrees around Y, then 180-fRot in X.
+                                    // Also apply usual scaling and translation
+                                    basegfx::B3DHomMatrix aSphereTrans;
+                                    aSphereTrans.rotate(0.0, F_PI2, 0.0);
+                                    aSphereTrans.rotate(F_PI - fRotInYZ, 0.0, 
0.0);
+                                    aSphereTrans *= aRotVector;
+                                    aSphereTrans.scale(getRadius(), 
getRadius(), getRadius());
+                                    aSphereTrans.translate(aCurr.getX(), 
aCurr.getY(), aCurr.getZ());
+                                    
+                                    // line start edge, build transformed 
primitiveVector3D
+                                    aResultVector.push_back(
+                                        new TransformPrimitive3D(
+                                            aSphereTrans, 
+                                            aNewList));
+                                }
+                            }
+
+                            // create line segments, build transformed 
primitiveVector3D
+                            aResultVector.push_back(
+                                new TransformPrimitive3D(
+                                    aTubeTrans, 
+                                    getLineTubeSegments(nSegments, 
aMaterial)));
+
+                            if(bNoLineJoin || (!bClosed && bLast))
+                            {
+                                // line end edge
+                                basegfx::B3DHomMatrix aBackCapTrans;
+
+                                // Mirror (line end) and radius scale
+                                aBackCapTrans.rotate(0.0, F_PI, 0.0);
+                                aBackCapTrans.scale(getRadius(), getRadius(), 
getRadius());
+
+                                if(bLineCapSquare && bLast)
+                                {
+                                    // correct position when square and 
prolonged
+                                    aBackCapTrans.translate(fForwLen + 
getRadius(), 0.0, 0.0);
+                                }
+                                else
+                                {
+                                    // standard position
+                                    aBackCapTrans.translate(fForwLen, 0.0, 
0.0);
+                                }
+
+                                // rotate and translate to destination
+                                aBackCapTrans *= aRotVector;
+                                aBackCapTrans.translate(aCurr.getX(), 
aCurr.getY(), aCurr.getZ());
+
+                                // get primitiveVector3D
+                                Primitive3DSequence aSequence;
+
+                                if(bLineCapRound && bLast)
+                                {
+                                    // LineCapRound used
+                                    aSequence = 
getLineCapRoundSegments(nSegments, aMaterial);
+                                }
+                                else
+                                {
+                                    // simple closing cap
+                                    aSequence = getLineCapSegments(nSegments, 
aMaterial);
+                                }
+
+                                aResultVector.push_back(
+                                    new TransformPrimitive3D(
+                                        aBackCapTrans, 
+                                        aSequence));
+                            }
+                        }
 
                                                // prepare next loop step
                                                aLast = aCurr;
@@ -526,6 +684,7 @@ namespace drawinglayer
                        const basegfx::B3DPolygon& rPolygon, 
                        const basegfx::BColor& rBColor,
                        double fRadius, basegfx::B2DLineJoin aLineJoin,
+            com::sun::star::drawing::LineCap aLineCap,
                        double fDegreeStepWidth,
                        double fMiterMinimumAngle)
                :       PolygonHairlinePrimitive3D(rPolygon, rBColor),
@@ -533,7 +692,8 @@ namespace drawinglayer
             mfRadius(fRadius),
                        mfDegreeStepWidth(fDegreeStepWidth),
                        mfMiterMinimumAngle(fMiterMinimumAngle),
-                       maLineJoin(aLineJoin)
+                       maLineJoin(aLineJoin),
+            maLineCap(aLineCap)
                {
                }
 
@@ -546,7 +706,8 @@ namespace drawinglayer
                                return (getRadius() == rCompare.getRadius()
                                        && getDegreeStepWidth() == 
rCompare.getDegreeStepWidth()
                                        && getMiterMinimumAngle() == 
rCompare.getMiterMinimumAngle()
-                                       && getLineJoin() == 
rCompare.getLineJoin());
+                                       && getLineJoin() == 
rCompare.getLineJoin()
+                    && getLineCap() == rCompare.getLineCap());
                        }
 
                        return false;

Modified: 
incubator/ooo/branches/alg/linecap/main/drawinglayer/source/primitive3d/sdrdecompositiontools3d.cxx
URL: 
http://svn.apache.org/viewvc/incubator/ooo/branches/alg/linecap/main/drawinglayer/source/primitive3d/sdrdecompositiontools3d.cxx?rev=1229503&r1=1229502&r2=1229503&view=diff
==============================================================================
--- 
incubator/ooo/branches/alg/linecap/main/drawinglayer/source/primitive3d/sdrdecompositiontools3d.cxx
 (original)
+++ 
incubator/ooo/branches/alg/linecap/main/drawinglayer/source/primitive3d/sdrdecompositiontools3d.cxx
 Tue Jan 10 11:00:48 2012
@@ -150,7 +150,7 @@ namespace drawinglayer
                        aScaledPolyPolygon.transform(rObjectTransform);
 
                        // create line and stroke attribute
-                       const attribute::LineAttribute 
aLineAttribute(rLine.getColor(), rLine.getWidth(), rLine.getJoin());
+                       const attribute::LineAttribute 
aLineAttribute(rLine.getColor(), rLine.getWidth(), rLine.getJoin(), 
rLine.getCap());
                        const attribute::StrokeAttribute 
aStrokeAttribute(rLine.getDotDashArray(), rLine.getFullDotDashLen());
 
                        // create primitives


Reply via email to