polygontubeprimitive3d.cxx (464702f4) polygontubeprimitive3d.cxx (5aaf853b)
1/**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance

--- 142 unchanged lines hidden (view full) ---

151
152 aLast = aNext;
153 }
154 }
155
156 return aLineCapList;
157 }
158
1/**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance

--- 142 unchanged lines hidden (view full) ---

151
152 aLast = aNext;
153 }
154 }
155
156 return aLineCapList;
157 }
158
159 Primitive3DSequence getLineCapRoundSegments(
160 sal_uInt32 nSegments,
161 const attribute::MaterialAttribute3D& rMaterial)
162 {
163 // static data for buffered tube primitives
164 static Primitive3DSequence aLineCapRoundList;
165 static sal_uInt32 nLineCapRoundSegments(0);
166 static attribute::MaterialAttribute3D aLineMaterial;
167
168 // may exclusively change static data, use mutex
169 ::osl::Mutex m_mutex;
170
171 if(nSegments != nLineCapRoundSegments || !(rMaterial == aLineMaterial))
172 {
173 nLineCapRoundSegments = nSegments;
174 aLineMaterial = rMaterial;
175 aLineCapRoundList = Primitive3DSequence();
176 }
177
178 if(!aLineCapRoundList.hasElements() && nLineCapRoundSegments)
179 {
180 // calculate new horizontal segments
181 sal_uInt32 nVerSeg(nSegments / 2);
182
183 if(nVerSeg < 1)
184 {
185 nVerSeg = 1;
186 }
187
188 // create half-sphere; upper half of unit sphere
189 basegfx::B3DPolyPolygon aSphere(
190 basegfx::tools::createUnitSphereFillPolyPolygon(
191 nSegments,
192 nVerSeg,
193 true,
194 F_PI2, 0.0,
195 0.0, F_2PI));
196 const sal_uInt32 nCount(aSphere.count());
197
198 if(nCount)
199 {
200 // rotate to have sphere cap orientned to negative X-Axis; do not
201 // forget to transform normals, too
202 basegfx::B3DHomMatrix aSphereTrans;
203
204 aSphereTrans.rotate(0.0, 0.0, F_PI2);
205 aSphere.transform(aSphereTrans);
206 aSphere.transformNormals(aSphereTrans);
207
208 // realloc for primitives and create based on polygon snippets
209 aLineCapRoundList.realloc(nCount);
210
211 for(sal_uInt32 a(0); a < nCount; a++)
212 {
213 const basegfx::B3DPolygon aPartPolygon(aSphere.getB3DPolygon(a));
214 const basegfx::B3DPolyPolygon aPartPolyPolygon(aPartPolygon);
215
216 // need to create one primitive per Polygon since the primitive
217 // is for planar PolyPolygons which is definitely not the case here
218 aLineCapRoundList[a] = new PolyPolygonMaterialPrimitive3D(
219 aPartPolyPolygon,
220 rMaterial,
221 false);
222 }
223 }
224 }
225
226 return aLineCapRoundList;
227 }
228
159 Primitive3DSequence getLineJoinSegments(
160 sal_uInt32 nSegments,
161 const attribute::MaterialAttribute3D& rMaterial,
162 double fAngle,
163 double /*fDegreeStepWidth*/,
164 double fMiterMinimumAngle,
165 basegfx::B2DLineJoin aLineJoin)
166 {
167 // nSegments is for whole circle, adapt to half circle
168 const sal_uInt32 nVerSeg(nSegments >> 1L);
169 std::vector< BasePrimitive3D* > aResultVector;
170
171 if(nVerSeg)
172 {
173 if(basegfx::B2DLINEJOIN_ROUND == aLineJoin)
174 {
175 // calculate new horizontal segments
229 Primitive3DSequence getLineJoinSegments(
230 sal_uInt32 nSegments,
231 const attribute::MaterialAttribute3D& rMaterial,
232 double fAngle,
233 double /*fDegreeStepWidth*/,
234 double fMiterMinimumAngle,
235 basegfx::B2DLineJoin aLineJoin)
236 {
237 // nSegments is for whole circle, adapt to half circle
238 const sal_uInt32 nVerSeg(nSegments >> 1L);
239 std::vector< BasePrimitive3D* > aResultVector;
240
241 if(nVerSeg)
242 {
243 if(basegfx::B2DLINEJOIN_ROUND == aLineJoin)
244 {
245 // calculate new horizontal segments
176 const sal_uInt32 nHorSeg((sal_uInt32)((fAngle / F_2PI) * (double)nSegments));
246 const sal_uInt32 nHorSeg(basegfx::fround((fAngle / F_2PI) * (double)nSegments));
177
178 if(nHorSeg)
179 {
180 // create half-sphere
181 const basegfx::B3DPolyPolygon aSphere(basegfx::tools::createUnitSphereFillPolyPolygon(nHorSeg, nVerSeg, true, F_PI2, -F_PI2, 0.0, fAngle));
182
183 for(sal_uInt32 a(0L); a < aSphere.count(); a++)
184 {

--- 213 unchanged lines hidden (view full) ---

398//////////////////////////////////////////////////////////////////////////////
399
400using namespace com::sun::star;
401
402//////////////////////////////////////////////////////////////////////////////
403
404namespace drawinglayer
405{
247
248 if(nHorSeg)
249 {
250 // create half-sphere
251 const basegfx::B3DPolyPolygon aSphere(basegfx::tools::createUnitSphereFillPolyPolygon(nHorSeg, nVerSeg, true, F_PI2, -F_PI2, 0.0, fAngle));
252
253 for(sal_uInt32 a(0L); a < aSphere.count(); a++)
254 {

--- 213 unchanged lines hidden (view full) ---

468//////////////////////////////////////////////////////////////////////////////
469
470using namespace com::sun::star;
471
472//////////////////////////////////////////////////////////////////////////////
473
474namespace drawinglayer
475{
406 namespace primitive3d
407 {
408 Primitive3DSequence PolygonTubePrimitive3D::impCreate3DDecomposition(const geometry::ViewInformation3D& /*rViewInformation*/) const
409 {
410 const sal_uInt32 nPointCount(getB3DPolygon().count());
411 std::vector< BasePrimitive3D* > aResultVector;
476 namespace primitive3d
477 {
478 Primitive3DSequence PolygonTubePrimitive3D::impCreate3DDecomposition(const geometry::ViewInformation3D& /*rViewInformation*/) const
479 {
480 const sal_uInt32 nPointCount(getB3DPolygon().count());
481 std::vector< BasePrimitive3D* > aResultVector;
482
483 if(nPointCount)
484 {
485 if(basegfx::fTools::more(getRadius(), 0.0))
486 {
487 const attribute::MaterialAttribute3D aMaterial(getBColor());
488 static sal_uInt32 nSegments(8); // default for 3d line segments, for more quality just raise this value (in even steps)
489 const bool bClosed(getB3DPolygon().isClosed());
490 const bool bNoLineJoin(basegfx::B2DLINEJOIN_NONE == getLineJoin());
491 const sal_uInt32 nLoopCount(bClosed ? nPointCount : nPointCount - 1);
492 basegfx::B3DPoint aLast(getB3DPolygon().getB3DPoint(nPointCount - 1));
493 basegfx::B3DPoint aCurr(getB3DPolygon().getB3DPoint(0));
494
495 for(sal_uInt32 a(0); a < nLoopCount; a++)
496 {
497 // get next data
498 const basegfx::B3DPoint aNext(getB3DPolygon().getB3DPoint((a + 1) % nPointCount));
499 const basegfx::B3DVector aForw(aNext - aCurr);
500 const double fForwLen(aForw.getLength());
501
502 if(basegfx::fTools::more(fForwLen, 0.0))
503 {
504 // find out if linecap is active
505 const bool bFirst(!a);
506 const bool bLast(a + 1 == nLoopCount);
507 const bool bLineCapPossible(!bClosed && (bFirst || bLast));
508 const bool bLineCapRound(bLineCapPossible && com::sun::star::drawing::LineCap_ROUND == getLineCap());
509 const bool bLineCapSquare(bLineCapPossible && com::sun::star::drawing::LineCap_SQUARE == getLineCap());
412
510
413 if(0L != nPointCount)
414 {
415 if(basegfx::fTools::more(getRadius(), 0.0))
416 {
417 const attribute::MaterialAttribute3D aMaterial(getBColor());
418 static sal_uInt32 nSegments(8L); // default for 3d line segments, for more quality just raise this value (in even steps)
419 const bool bClosed(getB3DPolygon().isClosed());
420 const bool bNoLineJoin(basegfx::B2DLINEJOIN_NONE == getLineJoin());
421 const sal_uInt32 nLoopCount(bClosed ? nPointCount : nPointCount - 1L);
422 basegfx::B3DPoint aLast(getB3DPolygon().getB3DPoint(nPointCount - 1L));
423 basegfx::B3DPoint aCurr(getB3DPolygon().getB3DPoint(0L));
511 // get rotation from vector, this describes rotation from (1, 0, 0) to aForw
512 basegfx::B3DHomMatrix aRotVector(getRotationFromVector(aForw));
424
513
425 for(sal_uInt32 a(0L); a < nLoopCount; a++)
426 {
427 // get next data
428 const basegfx::B3DPoint aNext(getB3DPolygon().getB3DPoint((a + 1L) % nPointCount));
429 const basegfx::B3DVector aForw(aNext - aCurr);
430 const double fForwLen(aForw.getLength());
514 // prepare transformations for tube and cap
515 basegfx::B3DHomMatrix aTubeTrans;
516 basegfx::B3DHomMatrix aCapTrans;
431
517
432 if(basegfx::fTools::more(fForwLen, 0.0))
433 {
434 // get rotation from vector, this describes rotation from (1, 0, 0) to aForw
435 basegfx::B3DHomMatrix aRotVector(getRotationFromVector(aForw));
518 // cap gets radius size
519 aCapTrans.scale(getRadius(), getRadius(), getRadius());
436
520
437 // create default transformation with scale and rotate
438 basegfx::B3DHomMatrix aVectorTrans;
439 aVectorTrans.scale(fForwLen, getRadius(), getRadius());
440 aVectorTrans *= aRotVector;
441 aVectorTrans.translate(aCurr.getX(), aCurr.getY(), aCurr.getZ());
521 if(bLineCapSquare)
522 {
523 // when square line cap just prolong line segment in X, maybe 2 x radius when
524 // first and last (simple line segment)
525 const double fExtraLength(bFirst && bLast ? getRadius() * 2.0 : getRadius());
526
527 aTubeTrans.scale(fForwLen + fExtraLength, getRadius(), getRadius());
442
528
443 if(bNoLineJoin || (!bClosed && !a))
444 {
445 // line start edge, build transformed primitiveVector3D
446 TransformPrimitive3D* pNewTransformedA = new TransformPrimitive3D(aVectorTrans, getLineCapSegments(nSegments, aMaterial));
447 aResultVector.push_back(pNewTransformedA);
448 }
449 else
450 {
451 const basegfx::B3DVector aBack(aCurr - aLast);
452 const double fCross(basegfx::cross(aBack, aForw).getLength());
529 if(bFirst)
530 {
531 // correct start positions for tube and cap when first and square prolonged
532 aTubeTrans.translate(-getRadius(), 0.0, 0.0);
533 aCapTrans.translate(-getRadius(), 0.0, 0.0);
534 }
535 }
536 else
537 {
538 // normal tube size
539 aTubeTrans.scale(fForwLen, getRadius(), getRadius());
540 }
453
541
454 if(!basegfx::fTools::equalZero(fCross))
455 {
456 // line connect non-parallel, aBack, aForw, use getLineJoin()
457 const double fAngle(acos(aBack.scalar(aForw) / (fForwLen * aBack.getLength()))); // 0.0 .. F_PI2
458 Primitive3DSequence aNewList(getLineJoinSegments(nSegments, aMaterial, fAngle, getDegreeStepWidth(), getMiterMinimumAngle(), getLineJoin()));
542 // rotate and translate tube and cap
543 aTubeTrans *= aRotVector;
544 aTubeTrans.translate(aCurr.getX(), aCurr.getY(), aCurr.getZ());
545 aCapTrans *= aRotVector;
546 aCapTrans.translate(aCurr.getX(), aCurr.getY(), aCurr.getZ());
459
547
460 // calculate transformation. First, get angle in YZ between nForw projected on (1, 0, 0) and nBack
461 basegfx::B3DHomMatrix aInvRotVector(aRotVector);
462 aInvRotVector.invert();
463 basegfx::B3DVector aTransBack(aInvRotVector * aBack);
464 const double fRotInYZ(atan2(aTransBack.getY(), aTransBack.getZ()));
548 if(bNoLineJoin || (!bClosed && bFirst))
549 {
550 // line start edge, build transformed primitiveVector3D
551 Primitive3DSequence aSequence;
465
552
466 // create trans by rotating unit sphere with angle 90 degrees around Y, then 180-fRot in X.
467 // Also apply usual scaling and translation
468 basegfx::B3DHomMatrix aSphereTrans;
469 aSphereTrans.rotate(0.0, F_PI2, 0.0);
470 aSphereTrans.rotate(F_PI - fRotInYZ, 0.0, 0.0);
471 aSphereTrans *= aRotVector;
472 aSphereTrans.scale(getRadius(), getRadius(), getRadius());
473 aSphereTrans.translate(aCurr.getX(), aCurr.getY(), aCurr.getZ());
553 if(bLineCapRound && bFirst)
554 {
555 // LineCapRound used
556 aSequence = getLineCapRoundSegments(nSegments, aMaterial);
557 }
558 else
559 {
560 // simple closing cap
561 aSequence = getLineCapSegments(nSegments, aMaterial);
562 }
474
563
475 // line start edge, build transformed primitiveVector3D
476 TransformPrimitive3D* pNewTransformedB = new TransformPrimitive3D(aSphereTrans, aNewList);
477 aResultVector.push_back(pNewTransformedB);
478 }
479 }
564 TransformPrimitive3D* pNewTransformedA = new TransformPrimitive3D(aCapTrans, aSequence);
565 aResultVector.push_back(pNewTransformedA);
566 }
567 else
568 {
569 const basegfx::B3DVector aBack(aCurr - aLast);
570 const double fCross(basegfx::cross(aBack, aForw).getLength());
480
571
481 // create line segments, build transformed primitiveVector3D
482 TransformPrimitive3D* pNewTransformedC = new TransformPrimitive3D(aVectorTrans, getLineTubeSegments(nSegments, aMaterial));
483 aResultVector.push_back(pNewTransformedC);
572 if(!basegfx::fTools::equalZero(fCross))
573 {
574 // line connect non-parallel, aBack, aForw, use getLineJoin()
575 const double fAngle(acos(aBack.scalar(aForw) / (fForwLen * aBack.getLength()))); // 0.0 .. F_PI2
576 Primitive3DSequence aNewList(
577 getLineJoinSegments(
578 nSegments,
579 aMaterial,
580 fAngle,
581 getDegreeStepWidth(),
582 getMiterMinimumAngle(),
583 getLineJoin()));
484
584
485 if(bNoLineJoin || (!bClosed && ((a + 1L) == nLoopCount)))
486 {
487 // line end edge, first rotate (mirror) and translate, then use use aRotVector
488 basegfx::B3DHomMatrix aBackTrans;
489 aBackTrans.rotate(0.0, F_PI, 0.0);
490 aBackTrans.translate(1.0, 0.0, 0.0);
491 aBackTrans.scale(fForwLen, getRadius(), getRadius());
492 aBackTrans *= aRotVector;
493 aBackTrans.translate(aCurr.getX(), aCurr.getY(), aCurr.getZ());
494
495 // line end edge, build transformed primitiveVector3D
496 TransformPrimitive3D* pNewTransformedD = new TransformPrimitive3D(aBackTrans, getLineCapSegments(nSegments, aMaterial));
497 aResultVector.push_back(pNewTransformedD);
498 }
499 }
585 // calculate transformation. First, get angle in YZ between nForw projected on (1, 0, 0) and nBack
586 basegfx::B3DHomMatrix aInvRotVector(aRotVector);
587 aInvRotVector.invert();
588 basegfx::B3DVector aTransBack(aInvRotVector * aBack);
589 const double fRotInYZ(atan2(aTransBack.getY(), aTransBack.getZ()));
590
591 // create trans by rotating unit sphere with angle 90 degrees around Y, then 180-fRot in X.
592 // Also apply usual scaling and translation
593 basegfx::B3DHomMatrix aSphereTrans;
594 aSphereTrans.rotate(0.0, F_PI2, 0.0);
595 aSphereTrans.rotate(F_PI - fRotInYZ, 0.0, 0.0);
596 aSphereTrans *= aRotVector;
597 aSphereTrans.scale(getRadius(), getRadius(), getRadius());
598 aSphereTrans.translate(aCurr.getX(), aCurr.getY(), aCurr.getZ());
599
600 // line start edge, build transformed primitiveVector3D
601 aResultVector.push_back(
602 new TransformPrimitive3D(
603 aSphereTrans,
604 aNewList));
605 }
606 }
500
607
608 // create line segments, build transformed primitiveVector3D
609 aResultVector.push_back(
610 new TransformPrimitive3D(
611 aTubeTrans,
612 getLineTubeSegments(nSegments, aMaterial)));
613
614 if(bNoLineJoin || (!bClosed && bLast))
615 {
616 // line end edge
617 basegfx::B3DHomMatrix aBackCapTrans;
618
619 // Mirror (line end) and radius scale
620 aBackCapTrans.rotate(0.0, F_PI, 0.0);
621 aBackCapTrans.scale(getRadius(), getRadius(), getRadius());
622
623 if(bLineCapSquare && bLast)
624 {
625 // correct position when square and prolonged
626 aBackCapTrans.translate(fForwLen + getRadius(), 0.0, 0.0);
627 }
628 else
629 {
630 // standard position
631 aBackCapTrans.translate(fForwLen, 0.0, 0.0);
632 }
633
634 // rotate and translate to destination
635 aBackCapTrans *= aRotVector;
636 aBackCapTrans.translate(aCurr.getX(), aCurr.getY(), aCurr.getZ());
637
638 // get primitiveVector3D
639 Primitive3DSequence aSequence;
640
641 if(bLineCapRound && bLast)
642 {
643 // LineCapRound used
644 aSequence = getLineCapRoundSegments(nSegments, aMaterial);
645 }
646 else
647 {
648 // simple closing cap
649 aSequence = getLineCapSegments(nSegments, aMaterial);
650 }
651
652 aResultVector.push_back(
653 new TransformPrimitive3D(
654 aBackCapTrans,
655 aSequence));
656 }
657 }
658
501 // prepare next loop step
502 aLast = aCurr;
503 aCurr = aNext;
504 }
505 }
506 else
507 {
508 // create hairline

--- 12 unchanged lines hidden (view full) ---

521
522 return aRetval;
523 }
524
525 PolygonTubePrimitive3D::PolygonTubePrimitive3D(
526 const basegfx::B3DPolygon& rPolygon,
527 const basegfx::BColor& rBColor,
528 double fRadius, basegfx::B2DLineJoin aLineJoin,
659 // prepare next loop step
660 aLast = aCurr;
661 aCurr = aNext;
662 }
663 }
664 else
665 {
666 // create hairline

--- 12 unchanged lines hidden (view full) ---

679
680 return aRetval;
681 }
682
683 PolygonTubePrimitive3D::PolygonTubePrimitive3D(
684 const basegfx::B3DPolygon& rPolygon,
685 const basegfx::BColor& rBColor,
686 double fRadius, basegfx::B2DLineJoin aLineJoin,
687 com::sun::star::drawing::LineCap aLineCap,
529 double fDegreeStepWidth,
530 double fMiterMinimumAngle)
531 : PolygonHairlinePrimitive3D(rPolygon, rBColor),
532 maLast3DDecomposition(),
533 mfRadius(fRadius),
534 mfDegreeStepWidth(fDegreeStepWidth),
535 mfMiterMinimumAngle(fMiterMinimumAngle),
688 double fDegreeStepWidth,
689 double fMiterMinimumAngle)
690 : PolygonHairlinePrimitive3D(rPolygon, rBColor),
691 maLast3DDecomposition(),
692 mfRadius(fRadius),
693 mfDegreeStepWidth(fDegreeStepWidth),
694 mfMiterMinimumAngle(fMiterMinimumAngle),
536 maLineJoin(aLineJoin)
695 maLineJoin(aLineJoin),
696 maLineCap(aLineCap)
537 {
538 }
539
540 bool PolygonTubePrimitive3D::operator==(const BasePrimitive3D& rPrimitive) const
541 {
542 if(PolygonHairlinePrimitive3D::operator==(rPrimitive))
543 {
544 const PolygonTubePrimitive3D& rCompare = (PolygonTubePrimitive3D&)rPrimitive;
545
546 return (getRadius() == rCompare.getRadius()
547 && getDegreeStepWidth() == rCompare.getDegreeStepWidth()
548 && getMiterMinimumAngle() == rCompare.getMiterMinimumAngle()
697 {
698 }
699
700 bool PolygonTubePrimitive3D::operator==(const BasePrimitive3D& rPrimitive) const
701 {
702 if(PolygonHairlinePrimitive3D::operator==(rPrimitive))
703 {
704 const PolygonTubePrimitive3D& rCompare = (PolygonTubePrimitive3D&)rPrimitive;
705
706 return (getRadius() == rCompare.getRadius()
707 && getDegreeStepWidth() == rCompare.getDegreeStepWidth()
708 && getMiterMinimumAngle() == rCompare.getMiterMinimumAngle()
549 && getLineJoin() == rCompare.getLineJoin());
709 && getLineJoin() == rCompare.getLineJoin()
710 && getLineCap() == rCompare.getLineCap());
550 }
551
552 return false;
553 }
554
555 Primitive3DSequence PolygonTubePrimitive3D::get3DDecomposition(const geometry::ViewInformation3D& rViewInformation) const
556 {
557 ::osl::MutexGuard aGuard( m_aMutex );

--- 18 unchanged lines hidden ---
711 }
712
713 return false;
714 }
715
716 Primitive3DSequence PolygonTubePrimitive3D::get3DDecomposition(const geometry::ViewInformation3D& rViewInformation) const
717 {
718 ::osl::MutexGuard aGuard( m_aMutex );

--- 18 unchanged lines hidden ---