LCOV - code coverage report
Current view: top level - libreoffice/drawinglayer/source/primitive3d - polygontubeprimitive3d.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 0 310 0.0 %
Date: 2012-12-27 Functions: 0 10 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       5             :  * This Source Code Form is subject to the terms of the Mozilla Public
       6             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       7             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       8             :  *
       9             :  * This file incorporates work covered by the following license notice:
      10             :  *
      11             :  *   Licensed to the Apache Software Foundation (ASF) under one or more
      12             :  *   contributor license agreements. See the NOTICE file distributed
      13             :  *   with this work for additional information regarding copyright
      14             :  *   ownership. The ASF licenses this file to you under the Apache
      15             :  *   License, Version 2.0 (the "License"); you may not use this file
      16             :  *   except in compliance with the License. You may obtain a copy of
      17             :  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
      18             :  */
      19             : 
      20             : #include <drawinglayer/primitive3d/polygontubeprimitive3d.hxx>
      21             : #include <drawinglayer/attribute/materialattribute3d.hxx>
      22             : #include <basegfx/matrix/b3dhommatrix.hxx>
      23             : #include <basegfx/polygon/b3dpolypolygon.hxx>
      24             : #include <drawinglayer/primitive3d/polypolygonprimitive3d.hxx>
      25             : #include <basegfx/polygon/b3dpolypolygontools.hxx>
      26             : #include <drawinglayer/primitive3d/transformprimitive3d.hxx>
      27             : #include <drawinglayer/primitive3d/drawinglayer_primitivetypes3d.hxx>
      28             : 
      29             : //////////////////////////////////////////////////////////////////////////////
      30             : 
      31             : namespace drawinglayer
      32             : {
      33             :     namespace primitive3d
      34             :     {
      35             :         namespace // anonymous namespace
      36             :         {
      37           0 :             Primitive3DSequence getLineTubeSegments(
      38             :                 sal_uInt32 nSegments,
      39             :                 const attribute::MaterialAttribute3D& rMaterial)
      40             :             {
      41             :                 // static data for buffered tube primitives
      42           0 :                 static Primitive3DSequence aLineTubeList;
      43             :                 static sal_uInt32 nLineTubeSegments(0L);
      44           0 :                 static attribute::MaterialAttribute3D aLineMaterial;
      45             : 
      46             :                 // may exclusively change static data, use mutex
      47           0 :                 ::osl::Mutex m_mutex;
      48             : 
      49           0 :                 if(nSegments != nLineTubeSegments || !(rMaterial == aLineMaterial))
      50             :                 {
      51           0 :                     nLineTubeSegments = nSegments;
      52           0 :                     aLineMaterial = rMaterial;
      53           0 :                     aLineTubeList = Primitive3DSequence();
      54             :                 }
      55             : 
      56           0 :                 if(!aLineTubeList.hasElements() && 0L != nLineTubeSegments)
      57             :                 {
      58           0 :                     const basegfx::B3DPoint aLeft(0.0, 0.0, 0.0);
      59           0 :                     const basegfx::B3DPoint aRight(1.0, 0.0, 0.0);
      60           0 :                     basegfx::B3DPoint aLastLeft(0.0, 1.0, 0.0);
      61           0 :                     basegfx::B3DPoint aLastRight(1.0, 1.0, 0.0);
      62           0 :                     basegfx::B3DHomMatrix aRot;
      63           0 :                     aRot.rotate(F_2PI / (double)nLineTubeSegments, 0.0, 0.0);
      64           0 :                     aLineTubeList.realloc(nLineTubeSegments);
      65             : 
      66           0 :                     for(sal_uInt32 a(0L); a < nLineTubeSegments; a++)
      67             :                     {
      68           0 :                         const basegfx::B3DPoint aNextLeft(aRot * aLastLeft);
      69           0 :                         const basegfx::B3DPoint aNextRight(aRot * aLastRight);
      70           0 :                         basegfx::B3DPolygon aNewPolygon;
      71             : 
      72           0 :                         aNewPolygon.append(aNextLeft);
      73           0 :                         aNewPolygon.setNormal(0L, basegfx::B3DVector(aNextLeft - aLeft));
      74             : 
      75           0 :                         aNewPolygon.append(aLastLeft);
      76           0 :                         aNewPolygon.setNormal(1L, basegfx::B3DVector(aLastLeft - aLeft));
      77             : 
      78           0 :                         aNewPolygon.append(aLastRight);
      79           0 :                         aNewPolygon.setNormal(2L, basegfx::B3DVector(aLastRight - aRight));
      80             : 
      81           0 :                         aNewPolygon.append(aNextRight);
      82           0 :                         aNewPolygon.setNormal(3L, basegfx::B3DVector(aNextRight - aRight));
      83             : 
      84           0 :                         aNewPolygon.setClosed(true);
      85             : 
      86           0 :                         const basegfx::B3DPolyPolygon aNewPolyPolygon(aNewPolygon);
      87           0 :                         const Primitive3DReference xRef(new PolyPolygonMaterialPrimitive3D(aNewPolyPolygon, aLineMaterial, false));
      88           0 :                         aLineTubeList[a] = xRef;
      89             : 
      90           0 :                         aLastLeft = aNextLeft;
      91           0 :                         aLastRight = aNextRight;
      92           0 :                     }
      93             :                 }
      94             : 
      95           0 :                 return aLineTubeList;
      96             :             }
      97             : 
      98           0 :             Primitive3DSequence getLineCapSegments(
      99             :                 sal_uInt32 nSegments,
     100             :                 const attribute::MaterialAttribute3D& rMaterial)
     101             :             {
     102             :                 // static data for buffered tube primitives
     103           0 :                 static Primitive3DSequence aLineCapList;
     104             :                 static sal_uInt32 nLineCapSegments(0L);
     105           0 :                 static attribute::MaterialAttribute3D aLineMaterial;
     106             : 
     107             :                 // may exclusively change static data, use mutex
     108           0 :                 ::osl::Mutex m_mutex;
     109             : 
     110           0 :                 if(nSegments != nLineCapSegments || !(rMaterial == aLineMaterial))
     111             :                 {
     112           0 :                     nLineCapSegments = nSegments;
     113           0 :                     aLineMaterial = rMaterial;
     114           0 :                     aLineCapList = Primitive3DSequence();
     115             :                 }
     116             : 
     117           0 :                 if(!aLineCapList.hasElements() && 0L != nLineCapSegments)
     118             :                 {
     119           0 :                     const basegfx::B3DPoint aNull(0.0, 0.0, 0.0);
     120           0 :                     basegfx::B3DPoint aLast(0.0, 1.0, 0.0);
     121           0 :                     basegfx::B3DHomMatrix aRot;
     122           0 :                     aRot.rotate(F_2PI / (double)nLineCapSegments, 0.0, 0.0);
     123           0 :                     aLineCapList.realloc(nLineCapSegments);
     124             : 
     125           0 :                     for(sal_uInt32 a(0L); a < nLineCapSegments; a++)
     126             :                     {
     127           0 :                         const basegfx::B3DPoint aNext(aRot * aLast);
     128           0 :                         basegfx::B3DPolygon aNewPolygon;
     129             : 
     130           0 :                         aNewPolygon.append(aLast);
     131           0 :                         aNewPolygon.setNormal(0L, basegfx::B3DVector(aLast - aNull));
     132             : 
     133           0 :                         aNewPolygon.append(aNext);
     134           0 :                         aNewPolygon.setNormal(1L, basegfx::B3DVector(aNext - aNull));
     135             : 
     136           0 :                         aNewPolygon.append(aNull);
     137           0 :                         aNewPolygon.setNormal(2L, basegfx::B3DVector(-1.0, 0.0, 0.0));
     138             : 
     139           0 :                         aNewPolygon.setClosed(true);
     140             : 
     141           0 :                         const basegfx::B3DPolyPolygon aNewPolyPolygon(aNewPolygon);
     142           0 :                         const Primitive3DReference xRef(new PolyPolygonMaterialPrimitive3D(aNewPolyPolygon, aLineMaterial, false));
     143           0 :                         aLineCapList[a] = xRef;
     144             : 
     145           0 :                         aLast = aNext;
     146           0 :                     }
     147             :                 }
     148             : 
     149           0 :                 return aLineCapList;
     150             :             }
     151             : 
     152           0 :             Primitive3DSequence getLineCapRoundSegments(
     153             :                 sal_uInt32 nSegments,
     154             :                 const attribute::MaterialAttribute3D& rMaterial)
     155             :             {
     156             :                 // static data for buffered tube primitives
     157           0 :                 static Primitive3DSequence aLineCapRoundList;
     158             :                 static sal_uInt32 nLineCapRoundSegments(0);
     159           0 :                 static attribute::MaterialAttribute3D aLineMaterial;
     160             : 
     161             :                 // may exclusively change static data, use mutex
     162           0 :                 ::osl::Mutex m_mutex;
     163             : 
     164           0 :                 if(nSegments != nLineCapRoundSegments || !(rMaterial == aLineMaterial))
     165             :                 {
     166           0 :                     nLineCapRoundSegments = nSegments;
     167           0 :                     aLineMaterial = rMaterial;
     168           0 :                     aLineCapRoundList = Primitive3DSequence();
     169             :                 }
     170             : 
     171           0 :                 if(!aLineCapRoundList.hasElements() && nLineCapRoundSegments)
     172             :                 {
     173             :                     // calculate new horizontal segments
     174           0 :                     sal_uInt32 nVerSeg(nSegments / 2);
     175             : 
     176           0 :                     if(nVerSeg < 1)
     177             :                     {
     178           0 :                         nVerSeg = 1;
     179             :                     }
     180             : 
     181             :                     // create half-sphere; upper half of unit sphere
     182             :                     basegfx::B3DPolyPolygon aSphere(
     183             :                         basegfx::tools::createUnitSphereFillPolyPolygon(
     184             :                             nSegments,
     185             :                             nVerSeg,
     186             :                             true,
     187             :                             F_PI2, 0.0,
     188           0 :                             0.0, F_2PI));
     189           0 :                     const sal_uInt32 nCount(aSphere.count());
     190             : 
     191           0 :                     if(nCount)
     192             :                     {
     193             :                         // rotate to have sphere cap orientned to negative X-Axis; do not
     194             :                         // forget to transform normals, too
     195           0 :                         basegfx::B3DHomMatrix aSphereTrans;
     196             : 
     197           0 :                         aSphereTrans.rotate(0.0, 0.0, F_PI2);
     198           0 :                         aSphere.transform(aSphereTrans);
     199           0 :                         aSphere.transformNormals(aSphereTrans);
     200             : 
     201             :                         // realloc for primitives and create based on polygon snippets
     202           0 :                         aLineCapRoundList.realloc(nCount);
     203             : 
     204           0 :                         for(sal_uInt32 a(0); a < nCount; a++)
     205             :                         {
     206           0 :                             const basegfx::B3DPolygon aPartPolygon(aSphere.getB3DPolygon(a));
     207           0 :                             const basegfx::B3DPolyPolygon aPartPolyPolygon(aPartPolygon);
     208             : 
     209             :                             // need to create one primitive per Polygon since the primitive
     210             :                             // is for planar PolyPolygons which is definitely not the case here
     211           0 :                             aLineCapRoundList[a] = new PolyPolygonMaterialPrimitive3D(
     212             :                                 aPartPolyPolygon,
     213             :                                 rMaterial,
     214           0 :                                 false);
     215           0 :                         }
     216           0 :                     }
     217             :                 }
     218             : 
     219           0 :                 return aLineCapRoundList;
     220             :             }
     221             : 
     222           0 :             Primitive3DSequence getLineJoinSegments(
     223             :                 sal_uInt32 nSegments,
     224             :                 const attribute::MaterialAttribute3D& rMaterial,
     225             :                 double fAngle,
     226             :                 double /*fDegreeStepWidth*/,
     227             :                 double fMiterMinimumAngle,
     228             :                 basegfx::B2DLineJoin aLineJoin)
     229             :             {
     230             :                 // nSegments is for whole circle, adapt to half circle
     231           0 :                 const sal_uInt32 nVerSeg(nSegments >> 1L);
     232           0 :                 std::vector< BasePrimitive3D* > aResultVector;
     233             : 
     234           0 :                 if(nVerSeg)
     235             :                 {
     236           0 :                     if(basegfx::B2DLINEJOIN_ROUND == aLineJoin)
     237             :                     {
     238             :                         // calculate new horizontal segments
     239           0 :                         const sal_uInt32 nHorSeg(basegfx::fround((fAngle / F_2PI) * (double)nSegments));
     240             : 
     241           0 :                         if(nHorSeg)
     242             :                         {
     243             :                             // create half-sphere
     244           0 :                             const basegfx::B3DPolyPolygon aSphere(basegfx::tools::createUnitSphereFillPolyPolygon(nHorSeg, nVerSeg, true, F_PI2, -F_PI2, 0.0, fAngle));
     245             : 
     246           0 :                             for(sal_uInt32 a(0L); a < aSphere.count(); a++)
     247             :                             {
     248           0 :                                 const basegfx::B3DPolygon aPartPolygon(aSphere.getB3DPolygon(a));
     249           0 :                                 const basegfx::B3DPolyPolygon aPartPolyPolygon(aPartPolygon);
     250           0 :                                 BasePrimitive3D* pNew = new PolyPolygonMaterialPrimitive3D(aPartPolyPolygon, rMaterial, false);
     251           0 :                                 aResultVector.push_back(pNew);
     252           0 :                             }
     253             :                         }
     254             :                         else
     255             :                         {
     256             :                             // fallback to bevel when there is not at least one segment hor and ver
     257           0 :                             aLineJoin = basegfx::B2DLINEJOIN_BEVEL;
     258             :                         }
     259             :                     }
     260             : 
     261           0 :                     if(basegfx::B2DLINEJOIN_MIDDLE == aLineJoin
     262             :                         || basegfx::B2DLINEJOIN_BEVEL == aLineJoin
     263             :                         || basegfx::B2DLINEJOIN_MITER == aLineJoin)
     264             :                     {
     265           0 :                         if(basegfx::B2DLINEJOIN_MITER == aLineJoin)
     266             :                         {
     267           0 :                             const double fMiterAngle(fAngle/2.0);
     268             : 
     269           0 :                             if(fMiterAngle < fMiterMinimumAngle)
     270             :                             {
     271             :                                 // fallback to bevel when miter's angle is too small
     272           0 :                                 aLineJoin = basegfx::B2DLINEJOIN_BEVEL;
     273             :                             }
     274             :                         }
     275             : 
     276           0 :                         const double fInc(F_PI / (double)nVerSeg);
     277           0 :                         const double fSin(sin(-fAngle));
     278           0 :                         const double fCos(cos(-fAngle));
     279           0 :                         const bool bMiter(basegfx::B2DLINEJOIN_MITER == aLineJoin);
     280           0 :                         const double fMiterSin(bMiter ? sin(-(fAngle/2.0)) : 0.0);
     281           0 :                         const double fMiterCos(bMiter ? cos(-(fAngle/2.0)) : 0.0);
     282           0 :                         double fPos(-F_PI2);
     283           0 :                         basegfx::B3DPoint aPointOnXY, aPointRotY, aNextPointOnXY, aNextPointRotY;
     284           0 :                         basegfx::B3DPoint aCurrMiter, aNextMiter;
     285           0 :                         basegfx::B3DPolygon aNewPolygon, aMiterPolygon;
     286             : 
     287             :                         // close polygon
     288           0 :                         aNewPolygon.setClosed(true);
     289           0 :                         aMiterPolygon.setClosed(true);
     290             : 
     291           0 :                         for(sal_uInt32 a(0L); a < nVerSeg; a++)
     292             :                         {
     293           0 :                             const bool bFirst(0L == a);
     294           0 :                             const bool bLast(a + 1L == nVerSeg);
     295             : 
     296           0 :                             if(bFirst || !bLast)
     297             :                             {
     298           0 :                                 fPos += fInc;
     299             : 
     300             :                                 aNextPointOnXY = basegfx::B3DPoint(
     301             :                                     cos(fPos),
     302             :                                     sin(fPos),
     303           0 :                                     0.0);
     304             : 
     305             :                                 aNextPointRotY = basegfx::B3DPoint(
     306           0 :                                     aNextPointOnXY.getX() * fCos,
     307             :                                     aNextPointOnXY.getY(),
     308           0 :                                     aNextPointOnXY.getX() * fSin);
     309             : 
     310           0 :                                 if(bMiter)
     311             :                                 {
     312             :                                     aNextMiter = basegfx::B3DPoint(
     313             :                                         aNextPointOnXY.getX(),
     314             :                                         aNextPointOnXY.getY(),
     315           0 :                                         fMiterSin * (aNextPointOnXY.getX() / fMiterCos));
     316             :                                 }
     317             :                             }
     318             : 
     319           0 :                             if(bFirst)
     320             :                             {
     321           0 :                                 aNewPolygon.clear();
     322             : 
     323           0 :                                 if(bMiter)
     324             :                                 {
     325           0 :                                     aNewPolygon.append(basegfx::B3DPoint(0.0, -1.0, 0.0));
     326           0 :                                     aNewPolygon.append(aNextPointOnXY);
     327           0 :                                     aNewPolygon.append(aNextMiter);
     328             : 
     329           0 :                                     aMiterPolygon.clear();
     330           0 :                                     aMiterPolygon.append(basegfx::B3DPoint(0.0, -1.0, 0.0));
     331           0 :                                     aMiterPolygon.append(aNextMiter);
     332           0 :                                     aMiterPolygon.append(aNextPointRotY);
     333             :                                 }
     334             :                                 else
     335             :                                 {
     336           0 :                                     aNewPolygon.append(basegfx::B3DPoint(0.0, -1.0, 0.0));
     337           0 :                                     aNewPolygon.append(aNextPointOnXY);
     338           0 :                                     aNewPolygon.append(aNextPointRotY);
     339             :                                 }
     340             :                             }
     341           0 :                             else if(bLast)
     342             :                             {
     343           0 :                                 aNewPolygon.clear();
     344             : 
     345           0 :                                 if(bMiter)
     346             :                                 {
     347           0 :                                     aNewPolygon.append(basegfx::B3DPoint(0.0, 1.0, 0.0));
     348           0 :                                     aNewPolygon.append(aCurrMiter);
     349           0 :                                     aNewPolygon.append(aPointOnXY);
     350             : 
     351           0 :                                     aMiterPolygon.clear();
     352           0 :                                     aMiterPolygon.append(basegfx::B3DPoint(0.0, 1.0, 0.0));
     353           0 :                                     aMiterPolygon.append(aPointRotY);
     354           0 :                                     aMiterPolygon.append(aCurrMiter);
     355             :                                 }
     356             :                                 else
     357             :                                 {
     358           0 :                                     aNewPolygon.append(basegfx::B3DPoint(0.0, 1.0, 0.0));
     359           0 :                                     aNewPolygon.append(aPointRotY);
     360           0 :                                     aNewPolygon.append(aPointOnXY);
     361             :                                 }
     362             :                             }
     363             :                             else
     364             :                             {
     365           0 :                                 aNewPolygon.clear();
     366             : 
     367           0 :                                 if(bMiter)
     368             :                                 {
     369           0 :                                     aNewPolygon.append(aPointOnXY);
     370           0 :                                     aNewPolygon.append(aNextPointOnXY);
     371           0 :                                     aNewPolygon.append(aNextMiter);
     372           0 :                                     aNewPolygon.append(aCurrMiter);
     373             : 
     374           0 :                                     aMiterPolygon.clear();
     375           0 :                                     aMiterPolygon.append(aCurrMiter);
     376           0 :                                     aMiterPolygon.append(aNextMiter);
     377           0 :                                     aMiterPolygon.append(aNextPointRotY);
     378           0 :                                     aMiterPolygon.append(aPointRotY);
     379             :                                 }
     380             :                                 else
     381             :                                 {
     382           0 :                                     aNewPolygon.append(aPointRotY);
     383           0 :                                     aNewPolygon.append(aPointOnXY);
     384           0 :                                     aNewPolygon.append(aNextPointOnXY);
     385           0 :                                     aNewPolygon.append(aNextPointRotY);
     386             :                                 }
     387             :                             }
     388             : 
     389             :                             // set normals
     390           0 :                             for(sal_uInt32 b(0L); b < aNewPolygon.count(); b++)
     391             :                             {
     392           0 :                                 aNewPolygon.setNormal(b, basegfx::B3DVector(aNewPolygon.getB3DPoint(b)));
     393             :                             }
     394             : 
     395             :                             // create primitive
     396           0 :                             if(aNewPolygon.count())
     397             :                             {
     398           0 :                                 const basegfx::B3DPolyPolygon aNewPolyPolygon(aNewPolygon);
     399           0 :                                 BasePrimitive3D* pNew = new PolyPolygonMaterialPrimitive3D(aNewPolyPolygon, rMaterial, false);
     400           0 :                                 aResultVector.push_back(pNew);
     401             :                             }
     402             : 
     403           0 :                             if(bMiter && aMiterPolygon.count())
     404             :                             {
     405             :                                 // set normals
     406           0 :                                 for(sal_uInt32 c(0L); c < aMiterPolygon.count(); c++)
     407             :                                 {
     408           0 :                                     aMiterPolygon.setNormal(c, basegfx::B3DVector(aMiterPolygon.getB3DPoint(c)));
     409             :                                 }
     410             : 
     411             :                                 // create primitive
     412           0 :                                 const basegfx::B3DPolyPolygon aMiterPolyPolygon(aMiterPolygon);
     413           0 :                                 BasePrimitive3D* pNew = new PolyPolygonMaterialPrimitive3D(aMiterPolyPolygon, rMaterial, false);
     414           0 :                                 aResultVector.push_back(pNew);
     415             :                             }
     416             : 
     417             :                             // prepare next step
     418           0 :                             if(bFirst || !bLast)
     419             :                             {
     420           0 :                                 aPointOnXY = aNextPointOnXY;
     421           0 :                                 aPointRotY = aNextPointRotY;
     422             : 
     423           0 :                                 if(bMiter)
     424             :                                 {
     425           0 :                                     aCurrMiter = aNextMiter;
     426             :                                 }
     427             :                             }
     428           0 :                         }
     429             :                     }
     430             :                 }
     431             : 
     432           0 :                 Primitive3DSequence aRetval(aResultVector.size());
     433             : 
     434           0 :                 for(sal_uInt32 a(0L); a < aResultVector.size(); a++)
     435             :                 {
     436           0 :                     aRetval[a] = Primitive3DReference(aResultVector[a]);
     437             :                 }
     438             : 
     439           0 :                 return aRetval;
     440             :             }
     441             : 
     442           0 :             basegfx::B3DHomMatrix getRotationFromVector(const basegfx::B3DVector& rVector)
     443             :             {
     444             :                 // build transformation from unit vector to vector
     445           0 :                 basegfx::B3DHomMatrix aRetval;
     446             : 
     447             :                 // get applied rotations from angles in XY and in XZ (cartesian)
     448           0 :                 const double fRotInXY(atan2(rVector.getY(), rVector.getXZLength()));
     449           0 :                 const double fRotInXZ(atan2(-rVector.getZ(), rVector.getX()));
     450             : 
     451             :                 // apply rotations. Rot around Z needs to be done first, so apply in two steps
     452           0 :                 aRetval.rotate(0.0, 0.0, fRotInXY);
     453           0 :                 aRetval.rotate(0.0, fRotInXZ, 0.0);
     454             : 
     455           0 :                 return aRetval;
     456             :             }
     457             :         } // end of anonymous namespace
     458             :     } // end of namespace primitive3d
     459             : } // end of namespace drawinglayer
     460             : 
     461             : //////////////////////////////////////////////////////////////////////////////
     462             : 
     463             : using namespace com::sun::star;
     464             : 
     465             : //////////////////////////////////////////////////////////////////////////////
     466             : 
     467             : namespace drawinglayer
     468             : {
     469             :     namespace primitive3d
     470             :     {
     471           0 :         Primitive3DSequence PolygonTubePrimitive3D::impCreate3DDecomposition(const geometry::ViewInformation3D& /*rViewInformation*/) const
     472             :         {
     473           0 :             const sal_uInt32 nPointCount(getB3DPolygon().count());
     474           0 :             std::vector< BasePrimitive3D* > aResultVector;
     475             : 
     476           0 :             if(nPointCount)
     477             :             {
     478           0 :                 if(basegfx::fTools::more(getRadius(), 0.0))
     479             :                 {
     480           0 :                     const attribute::MaterialAttribute3D aMaterial(getBColor());
     481             :                     static sal_uInt32 nSegments(8); // default for 3d line segments, for more quality just raise this value (in even steps)
     482           0 :                     const bool bClosed(getB3DPolygon().isClosed());
     483           0 :                     const bool bNoLineJoin(basegfx::B2DLINEJOIN_NONE == getLineJoin());
     484           0 :                     const sal_uInt32 nLoopCount(bClosed ? nPointCount : nPointCount - 1);
     485           0 :                     basegfx::B3DPoint aLast(getB3DPolygon().getB3DPoint(nPointCount - 1));
     486           0 :                     basegfx::B3DPoint aCurr(getB3DPolygon().getB3DPoint(0));
     487             : 
     488           0 :                     for(sal_uInt32 a(0); a < nLoopCount; a++)
     489             :                     {
     490             :                         // get next data
     491           0 :                         const basegfx::B3DPoint aNext(getB3DPolygon().getB3DPoint((a + 1) % nPointCount));
     492           0 :                         const basegfx::B3DVector aForw(aNext - aCurr);
     493           0 :                         const double fForwLen(aForw.getLength());
     494             : 
     495           0 :                         if(basegfx::fTools::more(fForwLen, 0.0))
     496             :                         {
     497             :                             // find out if linecap is active
     498           0 :                             const bool bFirst(!a);
     499           0 :                             const bool bLast(a + 1 == nLoopCount);
     500           0 :                             const bool bLineCapPossible(!bClosed && (bFirst || bLast));
     501           0 :                             const bool bLineCapRound(bLineCapPossible && com::sun::star::drawing::LineCap_ROUND == getLineCap());
     502           0 :                             const bool bLineCapSquare(bLineCapPossible && com::sun::star::drawing::LineCap_SQUARE == getLineCap());
     503             : 
     504             :                             // get rotation from vector, this describes rotation from (1, 0, 0) to aForw
     505           0 :                             basegfx::B3DHomMatrix aRotVector(getRotationFromVector(aForw));
     506             : 
     507             :                             // prepare transformations for tube and cap
     508           0 :                             basegfx::B3DHomMatrix aTubeTrans;
     509           0 :                             basegfx::B3DHomMatrix aCapTrans;
     510             : 
     511             :                             // cap gets radius size
     512           0 :                             aCapTrans.scale(getRadius(), getRadius(), getRadius());
     513             : 
     514           0 :                             if(bLineCapSquare)
     515             :                             {
     516             :                                 // when square line cap just prolong line segment in X, maybe 2 x radius when
     517             :                                 // first and last (simple line segment)
     518           0 :                                 const double fExtraLength(bFirst && bLast ? getRadius() * 2.0 : getRadius());
     519             : 
     520           0 :                                 aTubeTrans.scale(fForwLen + fExtraLength, getRadius(), getRadius());
     521             : 
     522           0 :                                 if(bFirst)
     523             :                                 {
     524             :                                     // correct start positions for tube and cap when first and square prolonged
     525           0 :                                     aTubeTrans.translate(-getRadius(), 0.0, 0.0);
     526           0 :                                     aCapTrans.translate(-getRadius(), 0.0, 0.0);
     527             :                                 }
     528             :                             }
     529             :                             else
     530             :                             {
     531             :                                 // normal tube size
     532           0 :                                 aTubeTrans.scale(fForwLen, getRadius(), getRadius());
     533             :                             }
     534             : 
     535             :                             // rotate and translate tube and cap
     536           0 :                             aTubeTrans *= aRotVector;
     537           0 :                             aTubeTrans.translate(aCurr.getX(), aCurr.getY(), aCurr.getZ());
     538           0 :                             aCapTrans *= aRotVector;
     539           0 :                             aCapTrans.translate(aCurr.getX(), aCurr.getY(), aCurr.getZ());
     540             : 
     541           0 :                             if(bNoLineJoin || (!bClosed && bFirst))
     542             :                             {
     543             :                                 // line start edge, build transformed primitiveVector3D
     544           0 :                                 Primitive3DSequence aSequence;
     545             : 
     546           0 :                                 if(bLineCapRound && bFirst)
     547             :                                 {
     548             :                                     // LineCapRound used
     549           0 :                                     aSequence = getLineCapRoundSegments(nSegments, aMaterial);
     550             :                                 }
     551             :                                 else
     552             :                                 {
     553             :                                     // simple closing cap
     554           0 :                                     aSequence = getLineCapSegments(nSegments, aMaterial);
     555             :                                 }
     556             : 
     557           0 :                                 TransformPrimitive3D* pNewTransformedA = new TransformPrimitive3D(aCapTrans, aSequence);
     558           0 :                                 aResultVector.push_back(pNewTransformedA);
     559             :                             }
     560             :                             else
     561             :                             {
     562           0 :                                 const basegfx::B3DVector aBack(aCurr - aLast);
     563           0 :                                 const double fCross(basegfx::cross(aBack, aForw).getLength());
     564             : 
     565           0 :                                 if(!basegfx::fTools::equalZero(fCross))
     566             :                                 {
     567             :                                     // line connect non-parallel, aBack, aForw, use getLineJoin()
     568           0 :                                     const double fAngle(acos(aBack.scalar(aForw) / (fForwLen * aBack.getLength()))); // 0.0 .. F_PI2
     569             :                                     Primitive3DSequence aNewList(
     570             :                                         getLineJoinSegments(
     571             :                                             nSegments,
     572             :                                             aMaterial,
     573             :                                             fAngle,
     574             :                                             getDegreeStepWidth(),
     575             :                                             getMiterMinimumAngle(),
     576           0 :                                             getLineJoin()));
     577             : 
     578             :                                     // calculate transformation. First, get angle in YZ between nForw projected on (1, 0, 0) and nBack
     579           0 :                                     basegfx::B3DHomMatrix aInvRotVector(aRotVector);
     580           0 :                                     aInvRotVector.invert();
     581           0 :                                     basegfx::B3DVector aTransBack(aInvRotVector * aBack);
     582           0 :                                     const double fRotInYZ(atan2(aTransBack.getY(), aTransBack.getZ()));
     583             : 
     584             :                                     // create trans by rotating unit sphere with angle 90 degrees around Y, then 180-fRot in X.
     585             :                                     // Also apply usual scaling and translation
     586           0 :                                     basegfx::B3DHomMatrix aSphereTrans;
     587           0 :                                     aSphereTrans.rotate(0.0, F_PI2, 0.0);
     588           0 :                                     aSphereTrans.rotate(F_PI - fRotInYZ, 0.0, 0.0);
     589           0 :                                     aSphereTrans *= aRotVector;
     590           0 :                                     aSphereTrans.scale(getRadius(), getRadius(), getRadius());
     591           0 :                                     aSphereTrans.translate(aCurr.getX(), aCurr.getY(), aCurr.getZ());
     592             : 
     593             :                                     // line start edge, build transformed primitiveVector3D
     594             :                                     aResultVector.push_back(
     595             :                                         new TransformPrimitive3D(
     596             :                                             aSphereTrans,
     597           0 :                                             aNewList));
     598           0 :                                 }
     599             :                             }
     600             : 
     601             :                             // create line segments, build transformed primitiveVector3D
     602             :                             aResultVector.push_back(
     603             :                                 new TransformPrimitive3D(
     604             :                                     aTubeTrans,
     605           0 :                                     getLineTubeSegments(nSegments, aMaterial)));
     606             : 
     607           0 :                             if(bNoLineJoin || (!bClosed && bLast))
     608             :                             {
     609             :                                 // line end edge
     610           0 :                                 basegfx::B3DHomMatrix aBackCapTrans;
     611             : 
     612             :                                 // Mirror (line end) and radius scale
     613           0 :                                 aBackCapTrans.rotate(0.0, F_PI, 0.0);
     614           0 :                                 aBackCapTrans.scale(getRadius(), getRadius(), getRadius());
     615             : 
     616           0 :                                 if(bLineCapSquare && bLast)
     617             :                                 {
     618             :                                     // correct position when square and prolonged
     619           0 :                                     aBackCapTrans.translate(fForwLen + getRadius(), 0.0, 0.0);
     620             :                                 }
     621             :                                 else
     622             :                                 {
     623             :                                     // standard position
     624           0 :                                     aBackCapTrans.translate(fForwLen, 0.0, 0.0);
     625             :                                 }
     626             : 
     627             :                                 // rotate and translate to destination
     628           0 :                                 aBackCapTrans *= aRotVector;
     629           0 :                                 aBackCapTrans.translate(aCurr.getX(), aCurr.getY(), aCurr.getZ());
     630             : 
     631             :                                 // get primitiveVector3D
     632           0 :                                 Primitive3DSequence aSequence;
     633             : 
     634           0 :                                 if(bLineCapRound && bLast)
     635             :                                 {
     636             :                                     // LineCapRound used
     637           0 :                                     aSequence = getLineCapRoundSegments(nSegments, aMaterial);
     638             :                                 }
     639             :                                 else
     640             :                                 {
     641             :                                     // simple closing cap
     642           0 :                                     aSequence = getLineCapSegments(nSegments, aMaterial);
     643             :                                 }
     644             : 
     645             :                                 aResultVector.push_back(
     646             :                                     new TransformPrimitive3D(
     647             :                                         aBackCapTrans,
     648           0 :                                         aSequence));
     649           0 :                             }
     650             :                         }
     651             : 
     652             :                         // prepare next loop step
     653           0 :                         aLast = aCurr;
     654           0 :                         aCurr = aNext;
     655           0 :                     }
     656             :                 }
     657             :                 else
     658             :                 {
     659             :                     // create hairline
     660           0 :                     PolygonHairlinePrimitive3D* pNew = new PolygonHairlinePrimitive3D(getB3DPolygon(), getBColor());
     661           0 :                     aResultVector.push_back(pNew);
     662             :                 }
     663             :             }
     664             : 
     665             :             // prepare return value
     666           0 :             Primitive3DSequence aRetval(aResultVector.size());
     667             : 
     668           0 :             for(sal_uInt32 a(0L); a < aResultVector.size(); a++)
     669             :             {
     670           0 :                 aRetval[a] = Primitive3DReference(aResultVector[a]);
     671             :             }
     672             : 
     673           0 :             return aRetval;
     674             :         }
     675             : 
     676           0 :         PolygonTubePrimitive3D::PolygonTubePrimitive3D(
     677             :             const basegfx::B3DPolygon& rPolygon,
     678             :             const basegfx::BColor& rBColor,
     679             :             double fRadius, basegfx::B2DLineJoin aLineJoin,
     680             :             com::sun::star::drawing::LineCap aLineCap,
     681             :             double fDegreeStepWidth,
     682             :             double fMiterMinimumAngle)
     683             :         :   PolygonHairlinePrimitive3D(rPolygon, rBColor),
     684             :             maLast3DDecomposition(),
     685             :             mfRadius(fRadius),
     686             :             mfDegreeStepWidth(fDegreeStepWidth),
     687             :             mfMiterMinimumAngle(fMiterMinimumAngle),
     688             :             maLineJoin(aLineJoin),
     689           0 :             maLineCap(aLineCap)
     690             :         {
     691           0 :         }
     692             : 
     693           0 :         bool PolygonTubePrimitive3D::operator==(const BasePrimitive3D& rPrimitive) const
     694             :         {
     695           0 :             if(PolygonHairlinePrimitive3D::operator==(rPrimitive))
     696             :             {
     697           0 :                 const PolygonTubePrimitive3D& rCompare = (PolygonTubePrimitive3D&)rPrimitive;
     698             : 
     699           0 :                 return (getRadius() == rCompare.getRadius()
     700           0 :                     && getDegreeStepWidth() == rCompare.getDegreeStepWidth()
     701           0 :                     && getMiterMinimumAngle() == rCompare.getMiterMinimumAngle()
     702           0 :                     && getLineJoin() == rCompare.getLineJoin()
     703           0 :                     && getLineCap() == rCompare.getLineCap());
     704             :             }
     705             : 
     706           0 :             return false;
     707             :         }
     708             : 
     709           0 :         Primitive3DSequence PolygonTubePrimitive3D::get3DDecomposition(const geometry::ViewInformation3D& rViewInformation) const
     710             :         {
     711           0 :             ::osl::MutexGuard aGuard( m_aMutex );
     712             : 
     713           0 :             if(!getLast3DDecomposition().hasElements())
     714             :             {
     715           0 :                 const Primitive3DSequence aNewSequence(impCreate3DDecomposition(rViewInformation));
     716           0 :                 const_cast< PolygonTubePrimitive3D* >(this)->setLast3DDecomposition(aNewSequence);
     717             :             }
     718             : 
     719           0 :             return getLast3DDecomposition();
     720             :         }
     721             : 
     722             :         // provide unique ID
     723           0 :         ImplPrimitrive3DIDBlock(PolygonTubePrimitive3D, PRIMITIVE3D_ID_POLYGONTUBEPRIMITIVE3D)
     724             : 
     725             :     } // end of namespace primitive3d
     726             : } // end of namespace drawinglayer
     727             : 
     728             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10