1*cdf0e10cSrcweir /************************************************************************* 2*cdf0e10cSrcweir * 3*cdf0e10cSrcweir * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4*cdf0e10cSrcweir * 5*cdf0e10cSrcweir * Copyright 2000, 2010 Oracle and/or its affiliates. 6*cdf0e10cSrcweir * 7*cdf0e10cSrcweir * OpenOffice.org - a multi-platform office productivity suite 8*cdf0e10cSrcweir * 9*cdf0e10cSrcweir * This file is part of OpenOffice.org. 10*cdf0e10cSrcweir * 11*cdf0e10cSrcweir * OpenOffice.org is free software: you can redistribute it and/or modify 12*cdf0e10cSrcweir * it under the terms of the GNU Lesser General Public License version 3 13*cdf0e10cSrcweir * only, as published by the Free Software Foundation. 14*cdf0e10cSrcweir * 15*cdf0e10cSrcweir * OpenOffice.org is distributed in the hope that it will be useful, 16*cdf0e10cSrcweir * but WITHOUT ANY WARRANTY; without even the implied warranty of 17*cdf0e10cSrcweir * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18*cdf0e10cSrcweir * GNU Lesser General Public License version 3 for more details 19*cdf0e10cSrcweir * (a copy is included in the LICENSE file that accompanied this code). 20*cdf0e10cSrcweir * 21*cdf0e10cSrcweir * You should have received a copy of the GNU Lesser General Public License 22*cdf0e10cSrcweir * version 3 along with OpenOffice.org. If not, see 23*cdf0e10cSrcweir * <http://www.openoffice.org/license.html> 24*cdf0e10cSrcweir * for a copy of the LGPLv3 License. 25*cdf0e10cSrcweir * 26*cdf0e10cSrcweir ************************************************************************/ 27*cdf0e10cSrcweir 28*cdf0e10cSrcweir // MARKER(update_precomp.py): autogen include statement, do not remove 29*cdf0e10cSrcweir #include "precompiled_drawinglayer.hxx" 30*cdf0e10cSrcweir 31*cdf0e10cSrcweir #include <drawinglayer/primitive3d/polygontubeprimitive3d.hxx> 32*cdf0e10cSrcweir #include <drawinglayer/attribute/materialattribute3d.hxx> 33*cdf0e10cSrcweir #include <basegfx/matrix/b3dhommatrix.hxx> 34*cdf0e10cSrcweir #include <basegfx/polygon/b3dpolypolygon.hxx> 35*cdf0e10cSrcweir #include <drawinglayer/primitive3d/polypolygonprimitive3d.hxx> 36*cdf0e10cSrcweir #include <basegfx/polygon/b3dpolypolygontools.hxx> 37*cdf0e10cSrcweir #include <drawinglayer/primitive3d/transformprimitive3d.hxx> 38*cdf0e10cSrcweir #include <drawinglayer/primitive3d/drawinglayer_primitivetypes3d.hxx> 39*cdf0e10cSrcweir 40*cdf0e10cSrcweir ////////////////////////////////////////////////////////////////////////////// 41*cdf0e10cSrcweir 42*cdf0e10cSrcweir namespace drawinglayer 43*cdf0e10cSrcweir { 44*cdf0e10cSrcweir namespace primitive3d 45*cdf0e10cSrcweir { 46*cdf0e10cSrcweir namespace // anonymous namespace 47*cdf0e10cSrcweir { 48*cdf0e10cSrcweir Primitive3DSequence getLineTubeSegments( 49*cdf0e10cSrcweir sal_uInt32 nSegments, 50*cdf0e10cSrcweir const attribute::MaterialAttribute3D& rMaterial) 51*cdf0e10cSrcweir { 52*cdf0e10cSrcweir // static data for buffered tube primitives 53*cdf0e10cSrcweir static Primitive3DSequence aLineTubeList; 54*cdf0e10cSrcweir static sal_uInt32 nLineTubeSegments(0L); 55*cdf0e10cSrcweir static attribute::MaterialAttribute3D aLineMaterial; 56*cdf0e10cSrcweir 57*cdf0e10cSrcweir // may exclusively change static data, use mutex 58*cdf0e10cSrcweir ::osl::Mutex m_mutex; 59*cdf0e10cSrcweir 60*cdf0e10cSrcweir if(nSegments != nLineTubeSegments || !(rMaterial == aLineMaterial)) 61*cdf0e10cSrcweir { 62*cdf0e10cSrcweir nLineTubeSegments = nSegments; 63*cdf0e10cSrcweir aLineMaterial = rMaterial; 64*cdf0e10cSrcweir aLineTubeList = Primitive3DSequence(); 65*cdf0e10cSrcweir } 66*cdf0e10cSrcweir 67*cdf0e10cSrcweir if(!aLineTubeList.hasElements() && 0L != nLineTubeSegments) 68*cdf0e10cSrcweir { 69*cdf0e10cSrcweir const basegfx::B3DPoint aLeft(0.0, 0.0, 0.0); 70*cdf0e10cSrcweir const basegfx::B3DPoint aRight(1.0, 0.0, 0.0); 71*cdf0e10cSrcweir basegfx::B3DPoint aLastLeft(0.0, 1.0, 0.0); 72*cdf0e10cSrcweir basegfx::B3DPoint aLastRight(1.0, 1.0, 0.0); 73*cdf0e10cSrcweir basegfx::B3DHomMatrix aRot; 74*cdf0e10cSrcweir aRot.rotate(F_2PI / (double)nLineTubeSegments, 0.0, 0.0); 75*cdf0e10cSrcweir aLineTubeList.realloc(nLineTubeSegments); 76*cdf0e10cSrcweir 77*cdf0e10cSrcweir for(sal_uInt32 a(0L); a < nLineTubeSegments; a++) 78*cdf0e10cSrcweir { 79*cdf0e10cSrcweir const basegfx::B3DPoint aNextLeft(aRot * aLastLeft); 80*cdf0e10cSrcweir const basegfx::B3DPoint aNextRight(aRot * aLastRight); 81*cdf0e10cSrcweir basegfx::B3DPolygon aNewPolygon; 82*cdf0e10cSrcweir 83*cdf0e10cSrcweir aNewPolygon.append(aNextLeft); 84*cdf0e10cSrcweir aNewPolygon.setNormal(0L, basegfx::B3DVector(aNextLeft - aLeft)); 85*cdf0e10cSrcweir 86*cdf0e10cSrcweir aNewPolygon.append(aLastLeft); 87*cdf0e10cSrcweir aNewPolygon.setNormal(1L, basegfx::B3DVector(aLastLeft - aLeft)); 88*cdf0e10cSrcweir 89*cdf0e10cSrcweir aNewPolygon.append(aLastRight); 90*cdf0e10cSrcweir aNewPolygon.setNormal(2L, basegfx::B3DVector(aLastRight - aRight)); 91*cdf0e10cSrcweir 92*cdf0e10cSrcweir aNewPolygon.append(aNextRight); 93*cdf0e10cSrcweir aNewPolygon.setNormal(3L, basegfx::B3DVector(aNextRight - aRight)); 94*cdf0e10cSrcweir 95*cdf0e10cSrcweir aNewPolygon.setClosed(true); 96*cdf0e10cSrcweir 97*cdf0e10cSrcweir const basegfx::B3DPolyPolygon aNewPolyPolygon(aNewPolygon); 98*cdf0e10cSrcweir const Primitive3DReference xRef(new PolyPolygonMaterialPrimitive3D(aNewPolyPolygon, aLineMaterial, false)); 99*cdf0e10cSrcweir aLineTubeList[a] = xRef; 100*cdf0e10cSrcweir 101*cdf0e10cSrcweir aLastLeft = aNextLeft; 102*cdf0e10cSrcweir aLastRight = aNextRight; 103*cdf0e10cSrcweir } 104*cdf0e10cSrcweir } 105*cdf0e10cSrcweir 106*cdf0e10cSrcweir return aLineTubeList; 107*cdf0e10cSrcweir } 108*cdf0e10cSrcweir 109*cdf0e10cSrcweir Primitive3DSequence getLineCapSegments( 110*cdf0e10cSrcweir sal_uInt32 nSegments, 111*cdf0e10cSrcweir const attribute::MaterialAttribute3D& rMaterial) 112*cdf0e10cSrcweir { 113*cdf0e10cSrcweir // static data for buffered tube primitives 114*cdf0e10cSrcweir static Primitive3DSequence aLineCapList; 115*cdf0e10cSrcweir static sal_uInt32 nLineCapSegments(0L); 116*cdf0e10cSrcweir static attribute::MaterialAttribute3D aLineMaterial; 117*cdf0e10cSrcweir 118*cdf0e10cSrcweir // may exclusively change static data, use mutex 119*cdf0e10cSrcweir ::osl::Mutex m_mutex; 120*cdf0e10cSrcweir 121*cdf0e10cSrcweir if(nSegments != nLineCapSegments || !(rMaterial == aLineMaterial)) 122*cdf0e10cSrcweir { 123*cdf0e10cSrcweir nLineCapSegments = nSegments; 124*cdf0e10cSrcweir aLineMaterial = rMaterial; 125*cdf0e10cSrcweir aLineCapList = Primitive3DSequence(); 126*cdf0e10cSrcweir } 127*cdf0e10cSrcweir 128*cdf0e10cSrcweir if(!aLineCapList.hasElements() && 0L != nLineCapSegments) 129*cdf0e10cSrcweir { 130*cdf0e10cSrcweir const basegfx::B3DPoint aNull(0.0, 0.0, 0.0); 131*cdf0e10cSrcweir basegfx::B3DPoint aLast(0.0, 1.0, 0.0); 132*cdf0e10cSrcweir basegfx::B3DHomMatrix aRot; 133*cdf0e10cSrcweir aRot.rotate(F_2PI / (double)nLineCapSegments, 0.0, 0.0); 134*cdf0e10cSrcweir aLineCapList.realloc(nLineCapSegments); 135*cdf0e10cSrcweir 136*cdf0e10cSrcweir for(sal_uInt32 a(0L); a < nLineCapSegments; a++) 137*cdf0e10cSrcweir { 138*cdf0e10cSrcweir const basegfx::B3DPoint aNext(aRot * aLast); 139*cdf0e10cSrcweir basegfx::B3DPolygon aNewPolygon; 140*cdf0e10cSrcweir 141*cdf0e10cSrcweir aNewPolygon.append(aLast); 142*cdf0e10cSrcweir aNewPolygon.setNormal(0L, basegfx::B3DVector(aLast - aNull)); 143*cdf0e10cSrcweir 144*cdf0e10cSrcweir aNewPolygon.append(aNext); 145*cdf0e10cSrcweir aNewPolygon.setNormal(1L, basegfx::B3DVector(aNext - aNull)); 146*cdf0e10cSrcweir 147*cdf0e10cSrcweir aNewPolygon.append(aNull); 148*cdf0e10cSrcweir aNewPolygon.setNormal(2L, basegfx::B3DVector(-1.0, 0.0, 0.0)); 149*cdf0e10cSrcweir 150*cdf0e10cSrcweir aNewPolygon.setClosed(true); 151*cdf0e10cSrcweir 152*cdf0e10cSrcweir const basegfx::B3DPolyPolygon aNewPolyPolygon(aNewPolygon); 153*cdf0e10cSrcweir const Primitive3DReference xRef(new PolyPolygonMaterialPrimitive3D(aNewPolyPolygon, aLineMaterial, false)); 154*cdf0e10cSrcweir aLineCapList[a] = xRef; 155*cdf0e10cSrcweir 156*cdf0e10cSrcweir aLast = aNext; 157*cdf0e10cSrcweir } 158*cdf0e10cSrcweir } 159*cdf0e10cSrcweir 160*cdf0e10cSrcweir return aLineCapList; 161*cdf0e10cSrcweir } 162*cdf0e10cSrcweir 163*cdf0e10cSrcweir Primitive3DSequence getLineJoinSegments( 164*cdf0e10cSrcweir sal_uInt32 nSegments, 165*cdf0e10cSrcweir const attribute::MaterialAttribute3D& rMaterial, 166*cdf0e10cSrcweir double fAngle, 167*cdf0e10cSrcweir double /*fDegreeStepWidth*/, 168*cdf0e10cSrcweir double fMiterMinimumAngle, 169*cdf0e10cSrcweir basegfx::B2DLineJoin aLineJoin) 170*cdf0e10cSrcweir { 171*cdf0e10cSrcweir // nSegments is for whole circle, adapt to half circle 172*cdf0e10cSrcweir const sal_uInt32 nVerSeg(nSegments >> 1L); 173*cdf0e10cSrcweir std::vector< BasePrimitive3D* > aResultVector; 174*cdf0e10cSrcweir 175*cdf0e10cSrcweir if(nVerSeg) 176*cdf0e10cSrcweir { 177*cdf0e10cSrcweir if(basegfx::B2DLINEJOIN_ROUND == aLineJoin) 178*cdf0e10cSrcweir { 179*cdf0e10cSrcweir // calculate new horizontal segments 180*cdf0e10cSrcweir const sal_uInt32 nHorSeg((sal_uInt32)((fAngle / F_2PI) * (double)nSegments)); 181*cdf0e10cSrcweir 182*cdf0e10cSrcweir if(nHorSeg) 183*cdf0e10cSrcweir { 184*cdf0e10cSrcweir // create half-sphere 185*cdf0e10cSrcweir const basegfx::B3DPolyPolygon aSphere(basegfx::tools::createUnitSphereFillPolyPolygon(nHorSeg, nVerSeg, true, F_PI2, -F_PI2, 0.0, fAngle)); 186*cdf0e10cSrcweir 187*cdf0e10cSrcweir for(sal_uInt32 a(0L); a < aSphere.count(); a++) 188*cdf0e10cSrcweir { 189*cdf0e10cSrcweir const basegfx::B3DPolygon aPartPolygon(aSphere.getB3DPolygon(a)); 190*cdf0e10cSrcweir const basegfx::B3DPolyPolygon aPartPolyPolygon(aPartPolygon); 191*cdf0e10cSrcweir BasePrimitive3D* pNew = new PolyPolygonMaterialPrimitive3D(aPartPolyPolygon, rMaterial, false); 192*cdf0e10cSrcweir aResultVector.push_back(pNew); 193*cdf0e10cSrcweir } 194*cdf0e10cSrcweir } 195*cdf0e10cSrcweir else 196*cdf0e10cSrcweir { 197*cdf0e10cSrcweir // fallback to bevel when there is not at least one segment hor and ver 198*cdf0e10cSrcweir aLineJoin = basegfx::B2DLINEJOIN_BEVEL; 199*cdf0e10cSrcweir } 200*cdf0e10cSrcweir } 201*cdf0e10cSrcweir 202*cdf0e10cSrcweir if(basegfx::B2DLINEJOIN_MIDDLE == aLineJoin 203*cdf0e10cSrcweir || basegfx::B2DLINEJOIN_BEVEL == aLineJoin 204*cdf0e10cSrcweir || basegfx::B2DLINEJOIN_MITER == aLineJoin) 205*cdf0e10cSrcweir { 206*cdf0e10cSrcweir if(basegfx::B2DLINEJOIN_MITER == aLineJoin) 207*cdf0e10cSrcweir { 208*cdf0e10cSrcweir const double fMiterAngle(fAngle/2.0); 209*cdf0e10cSrcweir 210*cdf0e10cSrcweir if(fMiterAngle < fMiterMinimumAngle) 211*cdf0e10cSrcweir { 212*cdf0e10cSrcweir // fallback to bevel when miter's angle is too small 213*cdf0e10cSrcweir aLineJoin = basegfx::B2DLINEJOIN_BEVEL; 214*cdf0e10cSrcweir } 215*cdf0e10cSrcweir } 216*cdf0e10cSrcweir 217*cdf0e10cSrcweir const double fInc(F_PI / (double)nVerSeg); 218*cdf0e10cSrcweir const double fSin(sin(-fAngle)); 219*cdf0e10cSrcweir const double fCos(cos(-fAngle)); 220*cdf0e10cSrcweir const bool bMiter(basegfx::B2DLINEJOIN_MITER == aLineJoin); 221*cdf0e10cSrcweir const double fMiterSin(bMiter ? sin(-(fAngle/2.0)) : 0.0); 222*cdf0e10cSrcweir const double fMiterCos(bMiter ? cos(-(fAngle/2.0)) : 0.0); 223*cdf0e10cSrcweir double fPos(-F_PI2); 224*cdf0e10cSrcweir basegfx::B3DPoint aPointOnXY, aPointRotY, aNextPointOnXY, aNextPointRotY; 225*cdf0e10cSrcweir basegfx::B3DPoint aCurrMiter, aNextMiter; 226*cdf0e10cSrcweir basegfx::B3DPolygon aNewPolygon, aMiterPolygon; 227*cdf0e10cSrcweir 228*cdf0e10cSrcweir // close polygon 229*cdf0e10cSrcweir aNewPolygon.setClosed(true); 230*cdf0e10cSrcweir aMiterPolygon.setClosed(true); 231*cdf0e10cSrcweir 232*cdf0e10cSrcweir for(sal_uInt32 a(0L); a < nVerSeg; a++) 233*cdf0e10cSrcweir { 234*cdf0e10cSrcweir const bool bFirst(0L == a); 235*cdf0e10cSrcweir const bool bLast(a + 1L == nVerSeg); 236*cdf0e10cSrcweir 237*cdf0e10cSrcweir if(bFirst || !bLast) 238*cdf0e10cSrcweir { 239*cdf0e10cSrcweir fPos += fInc; 240*cdf0e10cSrcweir 241*cdf0e10cSrcweir aNextPointOnXY = basegfx::B3DPoint( 242*cdf0e10cSrcweir cos(fPos), 243*cdf0e10cSrcweir sin(fPos), 244*cdf0e10cSrcweir 0.0); 245*cdf0e10cSrcweir 246*cdf0e10cSrcweir aNextPointRotY = basegfx::B3DPoint( 247*cdf0e10cSrcweir aNextPointOnXY.getX() * fCos, 248*cdf0e10cSrcweir aNextPointOnXY.getY(), 249*cdf0e10cSrcweir aNextPointOnXY.getX() * fSin); 250*cdf0e10cSrcweir 251*cdf0e10cSrcweir if(bMiter) 252*cdf0e10cSrcweir { 253*cdf0e10cSrcweir aNextMiter = basegfx::B3DPoint( 254*cdf0e10cSrcweir aNextPointOnXY.getX(), 255*cdf0e10cSrcweir aNextPointOnXY.getY(), 256*cdf0e10cSrcweir fMiterSin * (aNextPointOnXY.getX() / fMiterCos)); 257*cdf0e10cSrcweir } 258*cdf0e10cSrcweir } 259*cdf0e10cSrcweir 260*cdf0e10cSrcweir if(bFirst) 261*cdf0e10cSrcweir { 262*cdf0e10cSrcweir aNewPolygon.clear(); 263*cdf0e10cSrcweir 264*cdf0e10cSrcweir if(bMiter) 265*cdf0e10cSrcweir { 266*cdf0e10cSrcweir aNewPolygon.append(basegfx::B3DPoint(0.0, -1.0, 0.0)); 267*cdf0e10cSrcweir aNewPolygon.append(aNextPointOnXY); 268*cdf0e10cSrcweir aNewPolygon.append(aNextMiter); 269*cdf0e10cSrcweir 270*cdf0e10cSrcweir aMiterPolygon.clear(); 271*cdf0e10cSrcweir aMiterPolygon.append(basegfx::B3DPoint(0.0, -1.0, 0.0)); 272*cdf0e10cSrcweir aMiterPolygon.append(aNextMiter); 273*cdf0e10cSrcweir aMiterPolygon.append(aNextPointRotY); 274*cdf0e10cSrcweir } 275*cdf0e10cSrcweir else 276*cdf0e10cSrcweir { 277*cdf0e10cSrcweir aNewPolygon.append(basegfx::B3DPoint(0.0, -1.0, 0.0)); 278*cdf0e10cSrcweir aNewPolygon.append(aNextPointOnXY); 279*cdf0e10cSrcweir aNewPolygon.append(aNextPointRotY); 280*cdf0e10cSrcweir } 281*cdf0e10cSrcweir } 282*cdf0e10cSrcweir else if(bLast) 283*cdf0e10cSrcweir { 284*cdf0e10cSrcweir aNewPolygon.clear(); 285*cdf0e10cSrcweir 286*cdf0e10cSrcweir if(bMiter) 287*cdf0e10cSrcweir { 288*cdf0e10cSrcweir aNewPolygon.append(basegfx::B3DPoint(0.0, 1.0, 0.0)); 289*cdf0e10cSrcweir aNewPolygon.append(aCurrMiter); 290*cdf0e10cSrcweir aNewPolygon.append(aPointOnXY); 291*cdf0e10cSrcweir 292*cdf0e10cSrcweir aMiterPolygon.clear(); 293*cdf0e10cSrcweir aMiterPolygon.append(basegfx::B3DPoint(0.0, 1.0, 0.0)); 294*cdf0e10cSrcweir aMiterPolygon.append(aPointRotY); 295*cdf0e10cSrcweir aMiterPolygon.append(aCurrMiter); 296*cdf0e10cSrcweir } 297*cdf0e10cSrcweir else 298*cdf0e10cSrcweir { 299*cdf0e10cSrcweir aNewPolygon.append(basegfx::B3DPoint(0.0, 1.0, 0.0)); 300*cdf0e10cSrcweir aNewPolygon.append(aPointRotY); 301*cdf0e10cSrcweir aNewPolygon.append(aPointOnXY); 302*cdf0e10cSrcweir } 303*cdf0e10cSrcweir } 304*cdf0e10cSrcweir else 305*cdf0e10cSrcweir { 306*cdf0e10cSrcweir aNewPolygon.clear(); 307*cdf0e10cSrcweir 308*cdf0e10cSrcweir if(bMiter) 309*cdf0e10cSrcweir { 310*cdf0e10cSrcweir aNewPolygon.append(aPointOnXY); 311*cdf0e10cSrcweir aNewPolygon.append(aNextPointOnXY); 312*cdf0e10cSrcweir aNewPolygon.append(aNextMiter); 313*cdf0e10cSrcweir aNewPolygon.append(aCurrMiter); 314*cdf0e10cSrcweir 315*cdf0e10cSrcweir aMiterPolygon.clear(); 316*cdf0e10cSrcweir aMiterPolygon.append(aCurrMiter); 317*cdf0e10cSrcweir aMiterPolygon.append(aNextMiter); 318*cdf0e10cSrcweir aMiterPolygon.append(aNextPointRotY); 319*cdf0e10cSrcweir aMiterPolygon.append(aPointRotY); 320*cdf0e10cSrcweir } 321*cdf0e10cSrcweir else 322*cdf0e10cSrcweir { 323*cdf0e10cSrcweir aNewPolygon.append(aPointRotY); 324*cdf0e10cSrcweir aNewPolygon.append(aPointOnXY); 325*cdf0e10cSrcweir aNewPolygon.append(aNextPointOnXY); 326*cdf0e10cSrcweir aNewPolygon.append(aNextPointRotY); 327*cdf0e10cSrcweir } 328*cdf0e10cSrcweir } 329*cdf0e10cSrcweir 330*cdf0e10cSrcweir // set normals 331*cdf0e10cSrcweir for(sal_uInt32 b(0L); b < aNewPolygon.count(); b++) 332*cdf0e10cSrcweir { 333*cdf0e10cSrcweir aNewPolygon.setNormal(b, basegfx::B3DVector(aNewPolygon.getB3DPoint(b))); 334*cdf0e10cSrcweir } 335*cdf0e10cSrcweir 336*cdf0e10cSrcweir // create primitive 337*cdf0e10cSrcweir if(aNewPolygon.count()) 338*cdf0e10cSrcweir { 339*cdf0e10cSrcweir const basegfx::B3DPolyPolygon aNewPolyPolygon(aNewPolygon); 340*cdf0e10cSrcweir BasePrimitive3D* pNew = new PolyPolygonMaterialPrimitive3D(aNewPolyPolygon, rMaterial, false); 341*cdf0e10cSrcweir aResultVector.push_back(pNew); 342*cdf0e10cSrcweir } 343*cdf0e10cSrcweir 344*cdf0e10cSrcweir if(bMiter && aMiterPolygon.count()) 345*cdf0e10cSrcweir { 346*cdf0e10cSrcweir // set normals 347*cdf0e10cSrcweir for(sal_uInt32 c(0L); c < aMiterPolygon.count(); c++) 348*cdf0e10cSrcweir { 349*cdf0e10cSrcweir aMiterPolygon.setNormal(c, basegfx::B3DVector(aMiterPolygon.getB3DPoint(c))); 350*cdf0e10cSrcweir } 351*cdf0e10cSrcweir 352*cdf0e10cSrcweir // create primitive 353*cdf0e10cSrcweir const basegfx::B3DPolyPolygon aMiterPolyPolygon(aMiterPolygon); 354*cdf0e10cSrcweir BasePrimitive3D* pNew = new PolyPolygonMaterialPrimitive3D(aMiterPolyPolygon, rMaterial, false); 355*cdf0e10cSrcweir aResultVector.push_back(pNew); 356*cdf0e10cSrcweir } 357*cdf0e10cSrcweir 358*cdf0e10cSrcweir // prepare next step 359*cdf0e10cSrcweir if(bFirst || !bLast) 360*cdf0e10cSrcweir { 361*cdf0e10cSrcweir aPointOnXY = aNextPointOnXY; 362*cdf0e10cSrcweir aPointRotY = aNextPointRotY; 363*cdf0e10cSrcweir 364*cdf0e10cSrcweir if(bMiter) 365*cdf0e10cSrcweir { 366*cdf0e10cSrcweir aCurrMiter = aNextMiter; 367*cdf0e10cSrcweir } 368*cdf0e10cSrcweir } 369*cdf0e10cSrcweir } 370*cdf0e10cSrcweir } 371*cdf0e10cSrcweir } 372*cdf0e10cSrcweir 373*cdf0e10cSrcweir Primitive3DSequence aRetval(aResultVector.size()); 374*cdf0e10cSrcweir 375*cdf0e10cSrcweir for(sal_uInt32 a(0L); a < aResultVector.size(); a++) 376*cdf0e10cSrcweir { 377*cdf0e10cSrcweir aRetval[a] = Primitive3DReference(aResultVector[a]); 378*cdf0e10cSrcweir } 379*cdf0e10cSrcweir 380*cdf0e10cSrcweir return aRetval; 381*cdf0e10cSrcweir } 382*cdf0e10cSrcweir 383*cdf0e10cSrcweir basegfx::B3DHomMatrix getRotationFromVector(const basegfx::B3DVector& rVector) 384*cdf0e10cSrcweir { 385*cdf0e10cSrcweir // build transformation from unit vector to vector 386*cdf0e10cSrcweir basegfx::B3DHomMatrix aRetval; 387*cdf0e10cSrcweir 388*cdf0e10cSrcweir // get applied rotations from angles in XY and in XZ (cartesian) 389*cdf0e10cSrcweir const double fRotInXY(atan2(rVector.getY(), rVector.getXZLength())); 390*cdf0e10cSrcweir const double fRotInXZ(atan2(-rVector.getZ(), rVector.getX())); 391*cdf0e10cSrcweir 392*cdf0e10cSrcweir // apply rotations. Rot around Z needs to be done first, so apply in two steps 393*cdf0e10cSrcweir aRetval.rotate(0.0, 0.0, fRotInXY); 394*cdf0e10cSrcweir aRetval.rotate(0.0, fRotInXZ, 0.0); 395*cdf0e10cSrcweir 396*cdf0e10cSrcweir return aRetval; 397*cdf0e10cSrcweir } 398*cdf0e10cSrcweir } // end of anonymous namespace 399*cdf0e10cSrcweir } // end of namespace primitive3d 400*cdf0e10cSrcweir } // end of namespace drawinglayer 401*cdf0e10cSrcweir 402*cdf0e10cSrcweir ////////////////////////////////////////////////////////////////////////////// 403*cdf0e10cSrcweir 404*cdf0e10cSrcweir using namespace com::sun::star; 405*cdf0e10cSrcweir 406*cdf0e10cSrcweir ////////////////////////////////////////////////////////////////////////////// 407*cdf0e10cSrcweir 408*cdf0e10cSrcweir namespace drawinglayer 409*cdf0e10cSrcweir { 410*cdf0e10cSrcweir namespace primitive3d 411*cdf0e10cSrcweir { 412*cdf0e10cSrcweir Primitive3DSequence PolygonTubePrimitive3D::impCreate3DDecomposition(const geometry::ViewInformation3D& /*rViewInformation*/) const 413*cdf0e10cSrcweir { 414*cdf0e10cSrcweir const sal_uInt32 nPointCount(getB3DPolygon().count()); 415*cdf0e10cSrcweir std::vector< BasePrimitive3D* > aResultVector; 416*cdf0e10cSrcweir 417*cdf0e10cSrcweir if(0L != nPointCount) 418*cdf0e10cSrcweir { 419*cdf0e10cSrcweir if(basegfx::fTools::more(getRadius(), 0.0)) 420*cdf0e10cSrcweir { 421*cdf0e10cSrcweir const attribute::MaterialAttribute3D aMaterial(getBColor()); 422*cdf0e10cSrcweir static sal_uInt32 nSegments(8L); // default for 3d line segments, for more quality just raise this value (in even steps) 423*cdf0e10cSrcweir const bool bClosed(getB3DPolygon().isClosed()); 424*cdf0e10cSrcweir const bool bNoLineJoin(basegfx::B2DLINEJOIN_NONE == getLineJoin()); 425*cdf0e10cSrcweir const sal_uInt32 nLoopCount(bClosed ? nPointCount : nPointCount - 1L); 426*cdf0e10cSrcweir basegfx::B3DPoint aLast(getB3DPolygon().getB3DPoint(nPointCount - 1L)); 427*cdf0e10cSrcweir basegfx::B3DPoint aCurr(getB3DPolygon().getB3DPoint(0L)); 428*cdf0e10cSrcweir 429*cdf0e10cSrcweir for(sal_uInt32 a(0L); a < nLoopCount; a++) 430*cdf0e10cSrcweir { 431*cdf0e10cSrcweir // get next data 432*cdf0e10cSrcweir const basegfx::B3DPoint aNext(getB3DPolygon().getB3DPoint((a + 1L) % nPointCount)); 433*cdf0e10cSrcweir const basegfx::B3DVector aForw(aNext - aCurr); 434*cdf0e10cSrcweir const double fForwLen(aForw.getLength()); 435*cdf0e10cSrcweir 436*cdf0e10cSrcweir if(basegfx::fTools::more(fForwLen, 0.0)) 437*cdf0e10cSrcweir { 438*cdf0e10cSrcweir // get rotation from vector, this describes rotation from (1, 0, 0) to aForw 439*cdf0e10cSrcweir basegfx::B3DHomMatrix aRotVector(getRotationFromVector(aForw)); 440*cdf0e10cSrcweir 441*cdf0e10cSrcweir // create default transformation with scale and rotate 442*cdf0e10cSrcweir basegfx::B3DHomMatrix aVectorTrans; 443*cdf0e10cSrcweir aVectorTrans.scale(fForwLen, getRadius(), getRadius()); 444*cdf0e10cSrcweir aVectorTrans *= aRotVector; 445*cdf0e10cSrcweir aVectorTrans.translate(aCurr.getX(), aCurr.getY(), aCurr.getZ()); 446*cdf0e10cSrcweir 447*cdf0e10cSrcweir if(bNoLineJoin || (!bClosed && !a)) 448*cdf0e10cSrcweir { 449*cdf0e10cSrcweir // line start edge, build transformed primitiveVector3D 450*cdf0e10cSrcweir TransformPrimitive3D* pNewTransformedA = new TransformPrimitive3D(aVectorTrans, getLineCapSegments(nSegments, aMaterial)); 451*cdf0e10cSrcweir aResultVector.push_back(pNewTransformedA); 452*cdf0e10cSrcweir } 453*cdf0e10cSrcweir else 454*cdf0e10cSrcweir { 455*cdf0e10cSrcweir const basegfx::B3DVector aBack(aCurr - aLast); 456*cdf0e10cSrcweir const double fCross(basegfx::cross(aBack, aForw).getLength()); 457*cdf0e10cSrcweir 458*cdf0e10cSrcweir if(!basegfx::fTools::equalZero(fCross)) 459*cdf0e10cSrcweir { 460*cdf0e10cSrcweir // line connect non-parallel, aBack, aForw, use getLineJoin() 461*cdf0e10cSrcweir const double fAngle(acos(aBack.scalar(aForw) / (fForwLen * aBack.getLength()))); // 0.0 .. F_PI2 462*cdf0e10cSrcweir Primitive3DSequence aNewList(getLineJoinSegments(nSegments, aMaterial, fAngle, getDegreeStepWidth(), getMiterMinimumAngle(), getLineJoin())); 463*cdf0e10cSrcweir 464*cdf0e10cSrcweir // calculate transformation. First, get angle in YZ between nForw projected on (1, 0, 0) and nBack 465*cdf0e10cSrcweir basegfx::B3DHomMatrix aInvRotVector(aRotVector); 466*cdf0e10cSrcweir aInvRotVector.invert(); 467*cdf0e10cSrcweir basegfx::B3DVector aTransBack(aInvRotVector * aBack); 468*cdf0e10cSrcweir const double fRotInYZ(atan2(aTransBack.getY(), aTransBack.getZ())); 469*cdf0e10cSrcweir 470*cdf0e10cSrcweir // create trans by rotating unit sphere with angle 90 degrees around Y, then 180-fRot in X. 471*cdf0e10cSrcweir // Also apply usual scaling and translation 472*cdf0e10cSrcweir basegfx::B3DHomMatrix aSphereTrans; 473*cdf0e10cSrcweir aSphereTrans.rotate(0.0, F_PI2, 0.0); 474*cdf0e10cSrcweir aSphereTrans.rotate(F_PI - fRotInYZ, 0.0, 0.0); 475*cdf0e10cSrcweir aSphereTrans *= aRotVector; 476*cdf0e10cSrcweir aSphereTrans.scale(getRadius(), getRadius(), getRadius()); 477*cdf0e10cSrcweir aSphereTrans.translate(aCurr.getX(), aCurr.getY(), aCurr.getZ()); 478*cdf0e10cSrcweir 479*cdf0e10cSrcweir // line start edge, build transformed primitiveVector3D 480*cdf0e10cSrcweir TransformPrimitive3D* pNewTransformedB = new TransformPrimitive3D(aSphereTrans, aNewList); 481*cdf0e10cSrcweir aResultVector.push_back(pNewTransformedB); 482*cdf0e10cSrcweir } 483*cdf0e10cSrcweir } 484*cdf0e10cSrcweir 485*cdf0e10cSrcweir // create line segments, build transformed primitiveVector3D 486*cdf0e10cSrcweir TransformPrimitive3D* pNewTransformedC = new TransformPrimitive3D(aVectorTrans, getLineTubeSegments(nSegments, aMaterial)); 487*cdf0e10cSrcweir aResultVector.push_back(pNewTransformedC); 488*cdf0e10cSrcweir 489*cdf0e10cSrcweir if(bNoLineJoin || (!bClosed && ((a + 1L) == nLoopCount))) 490*cdf0e10cSrcweir { 491*cdf0e10cSrcweir // line end edge, first rotate (mirror) and translate, then use use aRotVector 492*cdf0e10cSrcweir basegfx::B3DHomMatrix aBackTrans; 493*cdf0e10cSrcweir aBackTrans.rotate(0.0, F_PI, 0.0); 494*cdf0e10cSrcweir aBackTrans.translate(1.0, 0.0, 0.0); 495*cdf0e10cSrcweir aBackTrans.scale(fForwLen, getRadius(), getRadius()); 496*cdf0e10cSrcweir aBackTrans *= aRotVector; 497*cdf0e10cSrcweir aBackTrans.translate(aCurr.getX(), aCurr.getY(), aCurr.getZ()); 498*cdf0e10cSrcweir 499*cdf0e10cSrcweir // line end edge, build transformed primitiveVector3D 500*cdf0e10cSrcweir TransformPrimitive3D* pNewTransformedD = new TransformPrimitive3D(aBackTrans, getLineCapSegments(nSegments, aMaterial)); 501*cdf0e10cSrcweir aResultVector.push_back(pNewTransformedD); 502*cdf0e10cSrcweir } 503*cdf0e10cSrcweir } 504*cdf0e10cSrcweir 505*cdf0e10cSrcweir // prepare next loop step 506*cdf0e10cSrcweir aLast = aCurr; 507*cdf0e10cSrcweir aCurr = aNext; 508*cdf0e10cSrcweir } 509*cdf0e10cSrcweir } 510*cdf0e10cSrcweir else 511*cdf0e10cSrcweir { 512*cdf0e10cSrcweir // create hairline 513*cdf0e10cSrcweir PolygonHairlinePrimitive3D* pNew = new PolygonHairlinePrimitive3D(getB3DPolygon(), getBColor()); 514*cdf0e10cSrcweir aResultVector.push_back(pNew); 515*cdf0e10cSrcweir } 516*cdf0e10cSrcweir } 517*cdf0e10cSrcweir 518*cdf0e10cSrcweir // prepare return value 519*cdf0e10cSrcweir Primitive3DSequence aRetval(aResultVector.size()); 520*cdf0e10cSrcweir 521*cdf0e10cSrcweir for(sal_uInt32 a(0L); a < aResultVector.size(); a++) 522*cdf0e10cSrcweir { 523*cdf0e10cSrcweir aRetval[a] = Primitive3DReference(aResultVector[a]); 524*cdf0e10cSrcweir } 525*cdf0e10cSrcweir 526*cdf0e10cSrcweir return aRetval; 527*cdf0e10cSrcweir } 528*cdf0e10cSrcweir 529*cdf0e10cSrcweir PolygonTubePrimitive3D::PolygonTubePrimitive3D( 530*cdf0e10cSrcweir const basegfx::B3DPolygon& rPolygon, 531*cdf0e10cSrcweir const basegfx::BColor& rBColor, 532*cdf0e10cSrcweir double fRadius, basegfx::B2DLineJoin aLineJoin, 533*cdf0e10cSrcweir double fDegreeStepWidth, 534*cdf0e10cSrcweir double fMiterMinimumAngle) 535*cdf0e10cSrcweir : PolygonHairlinePrimitive3D(rPolygon, rBColor), 536*cdf0e10cSrcweir maLast3DDecomposition(), 537*cdf0e10cSrcweir mfRadius(fRadius), 538*cdf0e10cSrcweir mfDegreeStepWidth(fDegreeStepWidth), 539*cdf0e10cSrcweir mfMiterMinimumAngle(fMiterMinimumAngle), 540*cdf0e10cSrcweir maLineJoin(aLineJoin) 541*cdf0e10cSrcweir { 542*cdf0e10cSrcweir } 543*cdf0e10cSrcweir 544*cdf0e10cSrcweir bool PolygonTubePrimitive3D::operator==(const BasePrimitive3D& rPrimitive) const 545*cdf0e10cSrcweir { 546*cdf0e10cSrcweir if(PolygonHairlinePrimitive3D::operator==(rPrimitive)) 547*cdf0e10cSrcweir { 548*cdf0e10cSrcweir const PolygonTubePrimitive3D& rCompare = (PolygonTubePrimitive3D&)rPrimitive; 549*cdf0e10cSrcweir 550*cdf0e10cSrcweir return (getRadius() == rCompare.getRadius() 551*cdf0e10cSrcweir && getDegreeStepWidth() == rCompare.getDegreeStepWidth() 552*cdf0e10cSrcweir && getMiterMinimumAngle() == rCompare.getMiterMinimumAngle() 553*cdf0e10cSrcweir && getLineJoin() == rCompare.getLineJoin()); 554*cdf0e10cSrcweir } 555*cdf0e10cSrcweir 556*cdf0e10cSrcweir return false; 557*cdf0e10cSrcweir } 558*cdf0e10cSrcweir 559*cdf0e10cSrcweir Primitive3DSequence PolygonTubePrimitive3D::get3DDecomposition(const geometry::ViewInformation3D& rViewInformation) const 560*cdf0e10cSrcweir { 561*cdf0e10cSrcweir ::osl::MutexGuard aGuard( m_aMutex ); 562*cdf0e10cSrcweir 563*cdf0e10cSrcweir if(!getLast3DDecomposition().hasElements()) 564*cdf0e10cSrcweir { 565*cdf0e10cSrcweir const Primitive3DSequence aNewSequence(impCreate3DDecomposition(rViewInformation)); 566*cdf0e10cSrcweir const_cast< PolygonTubePrimitive3D* >(this)->setLast3DDecomposition(aNewSequence); 567*cdf0e10cSrcweir } 568*cdf0e10cSrcweir 569*cdf0e10cSrcweir return getLast3DDecomposition(); 570*cdf0e10cSrcweir } 571*cdf0e10cSrcweir 572*cdf0e10cSrcweir // provide unique ID 573*cdf0e10cSrcweir ImplPrimitrive3DIDBlock(PolygonTubePrimitive3D, PRIMITIVE3D_ID_POLYGONTUBEPRIMITIVE3D) 574*cdf0e10cSrcweir 575*cdf0e10cSrcweir } // end of namespace primitive3d 576*cdf0e10cSrcweir } // end of namespace drawinglayer 577*cdf0e10cSrcweir 578*cdf0e10cSrcweir ////////////////////////////////////////////////////////////////////////////// 579*cdf0e10cSrcweir // eof 580