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

Generated by: LCOV version 1.10