summaryrefslogtreecommitdiffstats
path: root/basegfx/source/polygon/b3dpolygon.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'basegfx/source/polygon/b3dpolygon.cxx')
-rw-r--r--basegfx/source/polygon/b3dpolygon.cxx1619
1 files changed, 1619 insertions, 0 deletions
diff --git a/basegfx/source/polygon/b3dpolygon.cxx b/basegfx/source/polygon/b3dpolygon.cxx
new file mode 100644
index 000000000..9be2f882c
--- /dev/null
+++ b/basegfx/source/polygon/b3dpolygon.cxx
@@ -0,0 +1,1619 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <osl/diagnose.h>
+#include <basegfx/polygon/b3dpolygon.hxx>
+#include <basegfx/point/b3dpoint.hxx>
+#include <basegfx/matrix/b3dhommatrix.hxx>
+#include <basegfx/point/b2dpoint.hxx>
+#include <basegfx/color/bcolor.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <rtl/math.hxx>
+#include <vector>
+#include <algorithm>
+
+namespace {
+
+class CoordinateData3D
+{
+ basegfx::B3DPoint maPoint;
+
+public:
+ CoordinateData3D()
+ : maPoint()
+ {
+ }
+
+ explicit CoordinateData3D(const basegfx::B3DPoint& rData)
+ : maPoint(rData)
+ {
+ }
+
+ const basegfx::B3DPoint& getCoordinate() const
+ {
+ return maPoint;
+ }
+
+ void setCoordinate(const basegfx::B3DPoint& rValue)
+ {
+ if(rValue != maPoint)
+ maPoint = rValue;
+ }
+
+ bool operator==(const CoordinateData3D& rData) const
+ {
+ return (maPoint == rData.getCoordinate());
+ }
+
+ void transform(const basegfx::B3DHomMatrix& rMatrix)
+ {
+ maPoint *= rMatrix;
+ }
+};
+
+class CoordinateDataArray3D
+{
+ typedef std::vector< CoordinateData3D > CoordinateData3DVector;
+
+ CoordinateData3DVector maVector;
+
+public:
+ explicit CoordinateDataArray3D(sal_uInt32 nCount)
+ : maVector(nCount)
+ {
+ }
+
+ CoordinateDataArray3D(const CoordinateDataArray3D& rOriginal, sal_uInt32 nIndex, sal_uInt32 nCount)
+ : maVector(rOriginal.maVector.begin() + nIndex, rOriginal.maVector.begin() + (nIndex + nCount))
+ {
+ }
+
+ ::basegfx::B3DVector getNormal() const
+ {
+ ::basegfx::B3DVector aRetval;
+ const sal_uInt32 nPointCount(maVector.size());
+
+ if(nPointCount > 2)
+ {
+ sal_uInt32 nISmallest(0);
+ sal_uInt32 a(0);
+ const basegfx::B3DPoint* pSmallest(&maVector[0].getCoordinate());
+ const basegfx::B3DPoint* pNext(nullptr);
+ const basegfx::B3DPoint* pPrev(nullptr);
+
+ // To guarantee a correctly oriented point, choose an outmost one
+ // which then cannot be concave
+ for(a = 1; a < nPointCount; a++)
+ {
+ const basegfx::B3DPoint& rCandidate = maVector[a].getCoordinate();
+
+ if((rCandidate.getX() < pSmallest->getX())
+ || (rCandidate.getX() == pSmallest->getX() && rCandidate.getY() < pSmallest->getY())
+ || (rCandidate.getX() == pSmallest->getX() && rCandidate.getY() == pSmallest->getY() && rCandidate.getZ() < pSmallest->getZ()))
+ {
+ nISmallest = a;
+ pSmallest = &rCandidate;
+ }
+ }
+
+ // look for a next point different from minimal one
+ for(a = (nISmallest + 1) % nPointCount; a != nISmallest; a = (a + 1) % nPointCount)
+ {
+ const basegfx::B3DPoint& rCandidate = maVector[a].getCoordinate();
+
+ if(!rCandidate.equal(*pSmallest))
+ {
+ pNext = &rCandidate;
+ break;
+ }
+ }
+
+ // look for a previous point different from minimal one
+ for(a = (nISmallest + nPointCount - 1) % nPointCount; a != nISmallest; a = (a + nPointCount - 1) % nPointCount)
+ {
+ const basegfx::B3DPoint& rCandidate = maVector[a].getCoordinate();
+
+ if(!rCandidate.equal(*pSmallest))
+ {
+ pPrev = &rCandidate;
+ break;
+ }
+ }
+
+ // we always have a minimal point. If we also have a different next and previous,
+ // we can calculate the normal
+ if(pNext && pPrev)
+ {
+ const basegfx::B3DVector aPrev(*pPrev - *pSmallest);
+ const basegfx::B3DVector aNext(*pNext - *pSmallest);
+
+ aRetval = cross(aPrev, aNext);
+ aRetval.normalize();
+ }
+ }
+
+ return aRetval;
+ }
+
+ sal_uInt32 count() const
+ {
+ return maVector.size();
+ }
+
+ bool operator==(const CoordinateDataArray3D& rCandidate) const
+ {
+ return (maVector == rCandidate.maVector);
+ }
+
+ const basegfx::B3DPoint& getCoordinate(sal_uInt32 nIndex) const
+ {
+ return maVector[nIndex].getCoordinate();
+ }
+
+ void setCoordinate(sal_uInt32 nIndex, const basegfx::B3DPoint& rValue)
+ {
+ maVector[nIndex].setCoordinate(rValue);
+ }
+
+ void insert(sal_uInt32 nIndex, const CoordinateData3D& rValue, sal_uInt32 nCount)
+ {
+ if(nCount)
+ {
+ // add nCount copies of rValue
+ CoordinateData3DVector::iterator aIndex(maVector.begin());
+ aIndex += nIndex;
+ maVector.insert(aIndex, nCount, rValue);
+ }
+ }
+
+ void insert(sal_uInt32 nIndex, const CoordinateDataArray3D& rSource)
+ {
+ const sal_uInt32 nCount(rSource.maVector.size());
+
+ if(nCount)
+ {
+ // insert data
+ CoordinateData3DVector::iterator aIndex(maVector.begin());
+ aIndex += nIndex;
+ CoordinateData3DVector::const_iterator aStart(rSource.maVector.begin());
+ CoordinateData3DVector::const_iterator aEnd(rSource.maVector.end());
+ maVector.insert(aIndex, aStart, aEnd);
+ }
+ }
+
+ void remove(sal_uInt32 nIndex, sal_uInt32 nCount)
+ {
+ if(nCount)
+ {
+ // remove point data
+ CoordinateData3DVector::iterator aStart(maVector.begin());
+ aStart += nIndex;
+ const CoordinateData3DVector::iterator aEnd(aStart + nCount);
+ maVector.erase(aStart, aEnd);
+ }
+ }
+
+ void flip()
+ {
+ if(maVector.size() <= 1)
+ return;
+
+ const sal_uInt32 nHalfSize(maVector.size() >> 1);
+ CoordinateData3DVector::iterator aStart(maVector.begin());
+ CoordinateData3DVector::iterator aEnd(maVector.end() - 1);
+
+ for(sal_uInt32 a(0); a < nHalfSize; a++)
+ {
+ std::swap(*aStart, *aEnd);
+ ++aStart;
+ --aEnd;
+ }
+ }
+
+ void transform(const ::basegfx::B3DHomMatrix& rMatrix)
+ {
+ for (auto & elem : maVector)
+ {
+ elem.transform(rMatrix);
+ }
+ }
+};
+
+class BColorArray
+{
+ typedef std::vector< ::basegfx::BColor > BColorDataVector;
+
+ BColorDataVector maVector;
+ sal_uInt32 mnUsedEntries;
+
+public:
+ explicit BColorArray(sal_uInt32 nCount)
+ : maVector(nCount),
+ mnUsedEntries(0)
+ {
+ }
+
+ BColorArray(const BColorArray& rOriginal, sal_uInt32 nIndex, sal_uInt32 nCount)
+ : maVector(),
+ mnUsedEntries(0)
+ {
+ BColorDataVector::const_iterator aStart(rOriginal.maVector.begin());
+ aStart += nIndex;
+ BColorDataVector::const_iterator aEnd(aStart);
+ assert(nCount <= rOriginal.maVector.size());
+ aEnd += nCount;
+ maVector.reserve(nCount);
+
+ for(; aStart != aEnd; ++aStart)
+ {
+ if(!aStart->equalZero())
+ mnUsedEntries++;
+
+ maVector.push_back(*aStart);
+ }
+ }
+
+ bool operator==(const BColorArray& rCandidate) const
+ {
+ return (maVector == rCandidate.maVector);
+ }
+
+ bool isUsed() const
+ {
+ return (mnUsedEntries != 0);
+ }
+
+ const ::basegfx::BColor& getBColor(sal_uInt32 nIndex) const
+ {
+ return maVector[nIndex];
+ }
+
+ void setBColor(sal_uInt32 nIndex, const ::basegfx::BColor& rValue)
+ {
+ bool bWasUsed(mnUsedEntries && !maVector[nIndex].equalZero());
+ bool bIsUsed(!rValue.equalZero());
+
+ if(bWasUsed)
+ {
+ if(bIsUsed)
+ {
+ maVector[nIndex] = rValue;
+ }
+ else
+ {
+ maVector[nIndex] = ::basegfx::BColor::getEmptyBColor();
+ mnUsedEntries--;
+ }
+ }
+ else
+ {
+ if(bIsUsed)
+ {
+ maVector[nIndex] = rValue;
+ mnUsedEntries++;
+ }
+ }
+ }
+
+ void insert(sal_uInt32 nIndex, const ::basegfx::BColor& rValue, sal_uInt32 nCount)
+ {
+ if(nCount)
+ {
+ // add nCount copies of rValue
+ BColorDataVector::iterator aIndex(maVector.begin());
+ aIndex += nIndex;
+ maVector.insert(aIndex, nCount, rValue);
+
+ if(!rValue.equalZero())
+ mnUsedEntries += nCount;
+ }
+ }
+
+ void insert(sal_uInt32 nIndex, const BColorArray& rSource)
+ {
+ const sal_uInt32 nCount(rSource.maVector.size());
+
+ if(nCount)
+ {
+ // insert data
+ BColorDataVector::iterator aIndex(maVector.begin());
+ aIndex += nIndex;
+ BColorDataVector::const_iterator aStart(rSource.maVector.begin());
+ BColorDataVector::const_iterator aEnd(rSource.maVector.end());
+ maVector.insert(aIndex, aStart, aEnd);
+
+ mnUsedEntries += std::count_if(aStart, aEnd,
+ [](BColorDataVector::const_reference rData) { return !rData.equalZero(); });
+ }
+ }
+
+ void remove(sal_uInt32 nIndex, sal_uInt32 nCount)
+ {
+ if(nCount)
+ {
+ const BColorDataVector::iterator aDeleteStart(maVector.begin() + nIndex);
+ const BColorDataVector::iterator aDeleteEnd(aDeleteStart + nCount);
+
+ auto nDeleteUsed = std::count_if(aDeleteStart, aDeleteEnd,
+ [](BColorDataVector::const_reference rData) { return !rData.equalZero(); });
+ mnUsedEntries -= std::min(mnUsedEntries, static_cast<sal_uInt32>(nDeleteUsed));
+
+ // remove point data
+ maVector.erase(aDeleteStart, aDeleteEnd);
+ }
+ }
+
+ void flip()
+ {
+ if(maVector.size() <= 1)
+ return;
+
+ const sal_uInt32 nHalfSize(maVector.size() >> 1);
+ BColorDataVector::iterator aStart(maVector.begin());
+ BColorDataVector::iterator aEnd(maVector.end() - 1);
+
+ for(sal_uInt32 a(0); a < nHalfSize; a++)
+ {
+ std::swap(*aStart, *aEnd);
+ ++aStart;
+ --aEnd;
+ }
+ }
+};
+
+class NormalsArray3D
+{
+ typedef std::vector< ::basegfx::B3DVector > NormalsData3DVector;
+
+ NormalsData3DVector maVector;
+ sal_uInt32 mnUsedEntries;
+
+public:
+ explicit NormalsArray3D(sal_uInt32 nCount)
+ : maVector(nCount),
+ mnUsedEntries(0)
+ {
+ }
+
+ NormalsArray3D(const NormalsArray3D& rOriginal, sal_uInt32 nIndex, sal_uInt32 nCount)
+ : maVector(),
+ mnUsedEntries(0)
+ {
+ NormalsData3DVector::const_iterator aStart(rOriginal.maVector.begin());
+ aStart += nIndex;
+ NormalsData3DVector::const_iterator aEnd(aStart);
+ aEnd += nCount;
+ maVector.reserve(nCount);
+
+ for(; aStart != aEnd; ++aStart)
+ {
+ if(!aStart->equalZero())
+ mnUsedEntries++;
+
+ maVector.push_back(*aStart);
+ }
+ }
+
+ bool operator==(const NormalsArray3D& rCandidate) const
+ {
+ return (maVector == rCandidate.maVector);
+ }
+
+ bool isUsed() const
+ {
+ return (mnUsedEntries != 0);
+ }
+
+ const ::basegfx::B3DVector& getNormal(sal_uInt32 nIndex) const
+ {
+ return maVector[nIndex];
+ }
+
+ void setNormal(sal_uInt32 nIndex, const ::basegfx::B3DVector& rValue)
+ {
+ bool bWasUsed(mnUsedEntries && !maVector[nIndex].equalZero());
+ bool bIsUsed(!rValue.equalZero());
+
+ if(bWasUsed)
+ {
+ if(bIsUsed)
+ {
+ maVector[nIndex] = rValue;
+ }
+ else
+ {
+ maVector[nIndex] = ::basegfx::B3DVector::getEmptyVector();
+ mnUsedEntries--;
+ }
+ }
+ else
+ {
+ if(bIsUsed)
+ {
+ maVector[nIndex] = rValue;
+ mnUsedEntries++;
+ }
+ }
+ }
+
+ void insert(sal_uInt32 nIndex, const ::basegfx::B3DVector& rValue, sal_uInt32 nCount)
+ {
+ if(nCount)
+ {
+ // add nCount copies of rValue
+ NormalsData3DVector::iterator aIndex(maVector.begin());
+ aIndex += nIndex;
+ maVector.insert(aIndex, nCount, rValue);
+
+ if(!rValue.equalZero())
+ mnUsedEntries += nCount;
+ }
+ }
+
+ void insert(sal_uInt32 nIndex, const NormalsArray3D& rSource)
+ {
+ const sal_uInt32 nCount(rSource.maVector.size());
+
+ if(nCount)
+ {
+ // insert data
+ NormalsData3DVector::iterator aIndex(maVector.begin());
+ aIndex += nIndex;
+ NormalsData3DVector::const_iterator aStart(rSource.maVector.begin());
+ NormalsData3DVector::const_iterator aEnd(rSource.maVector.end());
+ maVector.insert(aIndex, aStart, aEnd);
+
+ mnUsedEntries += std::count_if(aStart, aEnd,
+ [](NormalsData3DVector::const_reference rData) { return !rData.equalZero(); });
+ }
+ }
+
+ void remove(sal_uInt32 nIndex, sal_uInt32 nCount)
+ {
+ if(nCount)
+ {
+ const NormalsData3DVector::iterator aDeleteStart(maVector.begin() + nIndex);
+ const NormalsData3DVector::iterator aDeleteEnd(aDeleteStart + nCount);
+
+ auto nDeleteUsed = std::count_if(aDeleteStart, aDeleteEnd,
+ [](NormalsData3DVector::const_reference rData) { return !rData.equalZero(); });
+ mnUsedEntries -= std::min(mnUsedEntries, static_cast<sal_uInt32>(nDeleteUsed));
+
+ // remove point data
+ maVector.erase(aDeleteStart, aDeleteEnd);
+ }
+ }
+
+ void flip()
+ {
+ if(maVector.size() <= 1)
+ return;
+
+ const sal_uInt32 nHalfSize(maVector.size() >> 1);
+ NormalsData3DVector::iterator aStart(maVector.begin());
+ NormalsData3DVector::iterator aEnd(maVector.end() - 1);
+
+ for(sal_uInt32 a(0); a < nHalfSize; a++)
+ {
+ std::swap(*aStart, *aEnd);
+ ++aStart;
+ --aEnd;
+ }
+ }
+
+ void transform(const basegfx::B3DHomMatrix& rMatrix)
+ {
+ for (auto & elem : maVector)
+ {
+ elem *= rMatrix;
+ }
+ }
+};
+
+class TextureCoordinate2D
+{
+ typedef std::vector< ::basegfx::B2DPoint > TextureData2DVector;
+
+ TextureData2DVector maVector;
+ sal_uInt32 mnUsedEntries;
+
+public:
+ explicit TextureCoordinate2D(sal_uInt32 nCount)
+ : maVector(nCount),
+ mnUsedEntries(0)
+ {
+ }
+
+ TextureCoordinate2D(const TextureCoordinate2D& rOriginal, sal_uInt32 nIndex, sal_uInt32 nCount)
+ : maVector(),
+ mnUsedEntries(0)
+ {
+ TextureData2DVector::const_iterator aStart(rOriginal.maVector.begin());
+ aStart += nIndex;
+ TextureData2DVector::const_iterator aEnd(aStart);
+ aEnd += nCount;
+ maVector.reserve(nCount);
+
+ for(; aStart != aEnd; ++aStart)
+ {
+ if(!aStart->equalZero())
+ mnUsedEntries++;
+
+ maVector.push_back(*aStart);
+ }
+ }
+
+ bool operator==(const TextureCoordinate2D& rCandidate) const
+ {
+ return (maVector == rCandidate.maVector);
+ }
+
+ bool isUsed() const
+ {
+ return (mnUsedEntries != 0);
+ }
+
+ const ::basegfx::B2DPoint& getTextureCoordinate(sal_uInt32 nIndex) const
+ {
+ return maVector[nIndex];
+ }
+
+ void setTextureCoordinate(sal_uInt32 nIndex, const ::basegfx::B2DPoint& rValue)
+ {
+ bool bWasUsed(mnUsedEntries && !maVector[nIndex].equalZero());
+ bool bIsUsed(!rValue.equalZero());
+
+ if(bWasUsed)
+ {
+ if(bIsUsed)
+ {
+ maVector[nIndex] = rValue;
+ }
+ else
+ {
+ maVector[nIndex] = ::basegfx::B2DPoint::getEmptyPoint();
+ mnUsedEntries--;
+ }
+ }
+ else
+ {
+ if(bIsUsed)
+ {
+ maVector[nIndex] = rValue;
+ mnUsedEntries++;
+ }
+ }
+ }
+
+ void insert(sal_uInt32 nIndex, const ::basegfx::B2DPoint& rValue, sal_uInt32 nCount)
+ {
+ if(nCount)
+ {
+ // add nCount copies of rValue
+ TextureData2DVector::iterator aIndex(maVector.begin());
+ aIndex += nIndex;
+ maVector.insert(aIndex, nCount, rValue);
+
+ if(!rValue.equalZero())
+ mnUsedEntries += nCount;
+ }
+ }
+
+ void insert(sal_uInt32 nIndex, const TextureCoordinate2D& rSource)
+ {
+ const sal_uInt32 nCount(rSource.maVector.size());
+
+ if(nCount)
+ {
+ // insert data
+ TextureData2DVector::iterator aIndex(maVector.begin());
+ aIndex += nIndex;
+ TextureData2DVector::const_iterator aStart(rSource.maVector.begin());
+ TextureData2DVector::const_iterator aEnd(rSource.maVector.end());
+ maVector.insert(aIndex, aStart, aEnd);
+
+ mnUsedEntries += std::count_if(aStart, aEnd,
+ [](TextureData2DVector::const_reference rData) { return !rData.equalZero(); });
+ }
+ }
+
+ void remove(sal_uInt32 nIndex, sal_uInt32 nCount)
+ {
+ if(nCount)
+ {
+ const TextureData2DVector::iterator aDeleteStart(maVector.begin() + nIndex);
+ const TextureData2DVector::iterator aDeleteEnd(aDeleteStart + nCount);
+
+ auto nDeleteUsed = std::count_if(aDeleteStart, aDeleteEnd,
+ [](TextureData2DVector::const_reference rData) { return !rData.equalZero(); });
+ mnUsedEntries -= std::min(mnUsedEntries, static_cast<sal_uInt32>(nDeleteUsed));
+
+ // remove point data
+ maVector.erase(aDeleteStart, aDeleteEnd);
+ }
+ }
+
+ void flip()
+ {
+ if(maVector.size() <= 1)
+ return;
+
+ const sal_uInt32 nHalfSize(maVector.size() >> 1);
+ TextureData2DVector::iterator aStart(maVector.begin());
+ TextureData2DVector::iterator aEnd(maVector.end() - 1);
+
+ for(sal_uInt32 a(0); a < nHalfSize; a++)
+ {
+ std::swap(*aStart, *aEnd);
+ ++aStart;
+ --aEnd;
+ }
+ }
+
+ void transform(const ::basegfx::B2DHomMatrix& rMatrix)
+ {
+ for (auto & elem : maVector)
+ {
+ elem *= rMatrix;
+ }
+ }
+};
+
+}
+
+class ImplB3DPolygon
+{
+ // The point vector. This vector exists always and defines the
+ // count of members.
+ CoordinateDataArray3D maPoints;
+
+ // The BColor vector. This vectors are created on demand
+ // and may be zero.
+ std::unique_ptr<BColorArray> mpBColors;
+
+ // The Normals vector. This vectors are created on demand
+ // and may be zero.
+ std::unique_ptr<NormalsArray3D> mpNormals;
+
+ // The TextureCoordinates vector. This vectors are created on demand
+ // and may be zero.
+ std::unique_ptr<TextureCoordinate2D> mpTextureCoordinates;
+
+ // The calculated plane normal. mbPlaneNormalValid says if it's valid.
+ ::basegfx::B3DVector maPlaneNormal;
+
+ // flag which decides if this polygon is opened or closed
+ bool mbIsClosed : 1;
+
+ // flag which says if maPlaneNormal is up-to-date
+ bool mbPlaneNormalValid : 1;
+
+protected:
+ void invalidatePlaneNormal()
+ {
+ if(mbPlaneNormalValid)
+ {
+ mbPlaneNormalValid = false;
+ }
+ }
+
+public:
+ // This constructor is only used from the static identity polygon, thus
+ // the RefCount is set to 1 to never 'delete' this static incarnation.
+ ImplB3DPolygon()
+ : maPoints(0),
+ maPlaneNormal(::basegfx::B3DVector::getEmptyVector()),
+ mbIsClosed(false),
+ mbPlaneNormalValid(true)
+ {
+ // complete initialization with defaults
+ }
+
+ ImplB3DPolygon(const ImplB3DPolygon& rToBeCopied)
+ : maPoints(rToBeCopied.maPoints),
+ maPlaneNormal(rToBeCopied.maPlaneNormal),
+ mbIsClosed(rToBeCopied.mbIsClosed),
+ mbPlaneNormalValid(rToBeCopied.mbPlaneNormalValid)
+ {
+ // complete initialization using copy
+ if(rToBeCopied.mpBColors && rToBeCopied.mpBColors->isUsed())
+ {
+ mpBColors.reset( new BColorArray(*rToBeCopied.mpBColors) );
+ }
+
+ if(rToBeCopied.mpNormals && rToBeCopied.mpNormals->isUsed())
+ {
+ mpNormals.reset( new NormalsArray3D(*rToBeCopied.mpNormals) );
+ }
+
+ if(rToBeCopied.mpTextureCoordinates && rToBeCopied.mpTextureCoordinates->isUsed())
+ {
+ mpTextureCoordinates.reset( new TextureCoordinate2D(*rToBeCopied.mpTextureCoordinates) );
+ }
+ }
+
+ ImplB3DPolygon(const ImplB3DPolygon& rToBeCopied, sal_uInt32 nIndex, sal_uInt32 nCount)
+ : maPoints(rToBeCopied.maPoints, nIndex, nCount),
+ maPlaneNormal(::basegfx::B3DVector::getEmptyVector()),
+ mbIsClosed(rToBeCopied.mbIsClosed),
+ mbPlaneNormalValid(false)
+ {
+ // complete initialization using partly copy
+ if(rToBeCopied.mpBColors && rToBeCopied.mpBColors->isUsed())
+ {
+ mpBColors.reset( new BColorArray(*rToBeCopied.mpBColors, nIndex, nCount) );
+
+ if(!mpBColors->isUsed())
+ {
+ mpBColors.reset();
+ }
+ }
+
+ if(rToBeCopied.mpNormals && rToBeCopied.mpNormals->isUsed())
+ {
+ mpNormals.reset( new NormalsArray3D(*rToBeCopied.mpNormals, nIndex, nCount) );
+
+ if(!mpNormals->isUsed())
+ {
+ mpNormals.reset();
+ }
+ }
+
+ if(rToBeCopied.mpTextureCoordinates && rToBeCopied.mpTextureCoordinates->isUsed())
+ {
+ mpTextureCoordinates.reset( new TextureCoordinate2D(*rToBeCopied.mpTextureCoordinates, nIndex, nCount) );
+
+ if(!mpTextureCoordinates->isUsed())
+ {
+ mpTextureCoordinates.reset();
+ }
+ }
+ }
+
+ sal_uInt32 count() const
+ {
+ return maPoints.count();
+ }
+
+ bool isClosed() const
+ {
+ return mbIsClosed;
+ }
+
+ void setClosed(bool bNew)
+ {
+ if(bNew != mbIsClosed)
+ {
+ mbIsClosed = bNew;
+ }
+ }
+
+ bool impBColorsAreEqual(const ImplB3DPolygon& rCandidate) const
+ {
+ bool bBColorsAreEqual(true);
+
+ if(mpBColors)
+ {
+ if(rCandidate.mpBColors)
+ {
+ bBColorsAreEqual = (*mpBColors == *rCandidate.mpBColors);
+ }
+ else
+ {
+ // candidate has no BColors, so it's assumed all unused.
+ bBColorsAreEqual = !mpBColors->isUsed();
+ }
+ }
+ else
+ {
+ if(rCandidate.mpBColors)
+ {
+ // we have no TextureCoordinates, so it's assumed all unused.
+ bBColorsAreEqual = !rCandidate.mpBColors->isUsed();
+ }
+ }
+
+ return bBColorsAreEqual;
+ }
+
+ bool impNormalsAreEqual(const ImplB3DPolygon& rCandidate) const
+ {
+ bool bNormalsAreEqual(true);
+
+ if(mpNormals)
+ {
+ if(rCandidate.mpNormals)
+ {
+ bNormalsAreEqual = (*mpNormals == *rCandidate.mpNormals);
+ }
+ else
+ {
+ // candidate has no normals, so it's assumed all unused.
+ bNormalsAreEqual = !mpNormals->isUsed();
+ }
+ }
+ else
+ {
+ if(rCandidate.mpNormals)
+ {
+ // we have no normals, so it's assumed all unused.
+ bNormalsAreEqual = !rCandidate.mpNormals->isUsed();
+ }
+ }
+
+ return bNormalsAreEqual;
+ }
+
+ bool impTextureCoordinatesAreEqual(const ImplB3DPolygon& rCandidate) const
+ {
+ bool bTextureCoordinatesAreEqual(true);
+
+ if(mpTextureCoordinates)
+ {
+ if(rCandidate.mpTextureCoordinates)
+ {
+ bTextureCoordinatesAreEqual = (*mpTextureCoordinates == *rCandidate.mpTextureCoordinates);
+ }
+ else
+ {
+ // candidate has no TextureCoordinates, so it's assumed all unused.
+ bTextureCoordinatesAreEqual = !mpTextureCoordinates->isUsed();
+ }
+ }
+ else
+ {
+ if(rCandidate.mpTextureCoordinates)
+ {
+ // we have no TextureCoordinates, so it's assumed all unused.
+ bTextureCoordinatesAreEqual = !rCandidate.mpTextureCoordinates->isUsed();
+ }
+ }
+
+ return bTextureCoordinatesAreEqual;
+ }
+
+ bool operator==(const ImplB3DPolygon& rCandidate) const
+ {
+ if(mbIsClosed == rCandidate.mbIsClosed)
+ {
+ if(maPoints == rCandidate.maPoints)
+ {
+ if(impBColorsAreEqual(rCandidate))
+ {
+ if(impNormalsAreEqual(rCandidate))
+ {
+ if(impTextureCoordinatesAreEqual(rCandidate))
+ {
+ return true;
+ }
+ }
+ }
+ }
+ }
+
+ return false;
+ }
+
+ const ::basegfx::B3DPoint& getPoint(sal_uInt32 nIndex) const
+ {
+ return maPoints.getCoordinate(nIndex);
+ }
+
+ void setPoint(sal_uInt32 nIndex, const ::basegfx::B3DPoint& rValue)
+ {
+ maPoints.setCoordinate(nIndex, rValue);
+ invalidatePlaneNormal();
+ }
+
+ void insert(sal_uInt32 nIndex, const ::basegfx::B3DPoint& rPoint, sal_uInt32 nCount)
+ {
+ if(!nCount)
+ return;
+
+ CoordinateData3D aCoordinate(rPoint);
+ maPoints.insert(nIndex, aCoordinate, nCount);
+ invalidatePlaneNormal();
+
+ if(mpBColors)
+ {
+ mpBColors->insert(nIndex, ::basegfx::BColor::getEmptyBColor(), nCount);
+ }
+
+ if(mpNormals)
+ {
+ mpNormals->insert(nIndex, ::basegfx::B3DVector::getEmptyVector(), nCount);
+ }
+
+ if(mpTextureCoordinates)
+ {
+ mpTextureCoordinates->insert(nIndex, ::basegfx::B2DPoint::getEmptyPoint(), nCount);
+ }
+ }
+
+ const ::basegfx::BColor& getBColor(sal_uInt32 nIndex) const
+ {
+ if(mpBColors)
+ {
+ return mpBColors->getBColor(nIndex);
+ }
+ else
+ {
+ return ::basegfx::BColor::getEmptyBColor();
+ }
+ }
+
+ void setBColor(sal_uInt32 nIndex, const ::basegfx::BColor& rValue)
+ {
+ if(!mpBColors)
+ {
+ if(!rValue.equalZero())
+ {
+ mpBColors.reset( new BColorArray(maPoints.count()) );
+ mpBColors->setBColor(nIndex, rValue);
+ }
+ }
+ else
+ {
+ mpBColors->setBColor(nIndex, rValue);
+
+ if(!mpBColors->isUsed())
+ {
+ mpBColors.reset();
+ }
+ }
+ }
+
+ bool areBColorsUsed() const
+ {
+ return (mpBColors && mpBColors->isUsed());
+ }
+
+ void clearBColors()
+ {
+ mpBColors.reset();
+ }
+
+ const ::basegfx::B3DVector& getNormal() const
+ {
+ if(!mbPlaneNormalValid)
+ {
+ const_cast< ImplB3DPolygon* >(this)->maPlaneNormal = maPoints.getNormal();
+ const_cast< ImplB3DPolygon* >(this)->mbPlaneNormalValid = true;
+ }
+
+ return maPlaneNormal;
+ }
+
+ const ::basegfx::B3DVector& getNormal(sal_uInt32 nIndex) const
+ {
+ if(mpNormals)
+ {
+ return mpNormals->getNormal(nIndex);
+ }
+ else
+ {
+ return ::basegfx::B3DVector::getEmptyVector();
+ }
+ }
+
+ void setNormal(sal_uInt32 nIndex, const ::basegfx::B3DVector& rValue)
+ {
+ if(!mpNormals)
+ {
+ if(!rValue.equalZero())
+ {
+ mpNormals.reset( new NormalsArray3D(maPoints.count()) );
+ mpNormals->setNormal(nIndex, rValue);
+ }
+ }
+ else
+ {
+ mpNormals->setNormal(nIndex, rValue);
+
+ if(!mpNormals->isUsed())
+ {
+ mpNormals.reset();
+ }
+ }
+ }
+
+ void transformNormals(const ::basegfx::B3DHomMatrix& rMatrix)
+ {
+ if(mpNormals)
+ {
+ mpNormals->transform(rMatrix);
+ }
+ }
+
+ bool areNormalsUsed() const
+ {
+ return (mpNormals && mpNormals->isUsed());
+ }
+
+ void clearNormals()
+ {
+ mpNormals.reset();
+ }
+
+ const ::basegfx::B2DPoint& getTextureCoordinate(sal_uInt32 nIndex) const
+ {
+ if(mpTextureCoordinates)
+ {
+ return mpTextureCoordinates->getTextureCoordinate(nIndex);
+ }
+ else
+ {
+ return ::basegfx::B2DPoint::getEmptyPoint();
+ }
+ }
+
+ void setTextureCoordinate(sal_uInt32 nIndex, const ::basegfx::B2DPoint& rValue)
+ {
+ if(!mpTextureCoordinates)
+ {
+ if(!rValue.equalZero())
+ {
+ mpTextureCoordinates.reset( new TextureCoordinate2D(maPoints.count()) );
+ mpTextureCoordinates->setTextureCoordinate(nIndex, rValue);
+ }
+ }
+ else
+ {
+ mpTextureCoordinates->setTextureCoordinate(nIndex, rValue);
+
+ if(!mpTextureCoordinates->isUsed())
+ {
+ mpTextureCoordinates.reset();
+ }
+ }
+ }
+
+ bool areTextureCoordinatesUsed() const
+ {
+ return (mpTextureCoordinates && mpTextureCoordinates->isUsed());
+ }
+
+ void clearTextureCoordinates()
+ {
+ mpTextureCoordinates.reset();
+ }
+
+ void transformTextureCoordinates(const ::basegfx::B2DHomMatrix& rMatrix)
+ {
+ if(mpTextureCoordinates)
+ {
+ mpTextureCoordinates->transform(rMatrix);
+ }
+ }
+
+ void insert(sal_uInt32 nIndex, const ImplB3DPolygon& rSource)
+ {
+ const sal_uInt32 nCount(rSource.maPoints.count());
+
+ if(!nCount)
+ return;
+
+ maPoints.insert(nIndex, rSource.maPoints);
+ invalidatePlaneNormal();
+
+ if(rSource.mpBColors && rSource.mpBColors->isUsed())
+ {
+ if(!mpBColors)
+ {
+ mpBColors.reset( new BColorArray(maPoints.count()) );
+ }
+
+ mpBColors->insert(nIndex, *rSource.mpBColors);
+ }
+ else
+ {
+ if(mpBColors)
+ {
+ mpBColors->insert(nIndex, ::basegfx::BColor::getEmptyBColor(), nCount);
+ }
+ }
+
+ if(rSource.mpNormals && rSource.mpNormals->isUsed())
+ {
+ if(!mpNormals)
+ {
+ mpNormals.reset( new NormalsArray3D(maPoints.count()) );
+ }
+
+ mpNormals->insert(nIndex, *rSource.mpNormals);
+ }
+ else
+ {
+ if(mpNormals)
+ {
+ mpNormals->insert(nIndex, ::basegfx::B3DVector::getEmptyVector(), nCount);
+ }
+ }
+
+ if(rSource.mpTextureCoordinates && rSource.mpTextureCoordinates->isUsed())
+ {
+ if(!mpTextureCoordinates)
+ {
+ mpTextureCoordinates.reset( new TextureCoordinate2D(maPoints.count()) );
+ }
+
+ mpTextureCoordinates->insert(nIndex, *rSource.mpTextureCoordinates);
+ }
+ else
+ {
+ if(mpTextureCoordinates)
+ {
+ mpTextureCoordinates->insert(nIndex, ::basegfx::B2DPoint::getEmptyPoint(), nCount);
+ }
+ }
+ }
+
+ void remove(sal_uInt32 nIndex, sal_uInt32 nCount)
+ {
+ if(!nCount)
+ return;
+
+ maPoints.remove(nIndex, nCount);
+ invalidatePlaneNormal();
+
+ if(mpBColors)
+ {
+ mpBColors->remove(nIndex, nCount);
+
+ if(!mpBColors->isUsed())
+ {
+ mpBColors.reset();
+ }
+ }
+
+ if(mpNormals)
+ {
+ mpNormals->remove(nIndex, nCount);
+
+ if(!mpNormals->isUsed())
+ {
+ mpNormals.reset();
+ }
+ }
+
+ if(mpTextureCoordinates)
+ {
+ mpTextureCoordinates->remove(nIndex, nCount);
+
+ if(!mpTextureCoordinates->isUsed())
+ {
+ mpTextureCoordinates.reset();
+ }
+ }
+ }
+
+ void flip()
+ {
+ if(maPoints.count() <= 1)
+ return;
+
+ maPoints.flip();
+
+ if(mbPlaneNormalValid)
+ {
+ // mirror plane normal
+ maPlaneNormal = -maPlaneNormal;
+ }
+
+ if(mpBColors)
+ {
+ mpBColors->flip();
+ }
+
+ if(mpNormals)
+ {
+ mpNormals->flip();
+ }
+
+ if(mpTextureCoordinates)
+ {
+ mpTextureCoordinates->flip();
+ }
+ }
+
+ bool hasDoublePoints() const
+ {
+ if(mbIsClosed)
+ {
+ // check for same start and end point
+ const sal_uInt32 nIndex(maPoints.count() - 1);
+
+ if(maPoints.getCoordinate(0) == maPoints.getCoordinate(nIndex))
+ {
+ const bool bBColorEqual(!mpBColors || (mpBColors->getBColor(0) == mpBColors->getBColor(nIndex)));
+
+ if(bBColorEqual)
+ {
+ const bool bNormalsEqual(!mpNormals || (mpNormals->getNormal(0) == mpNormals->getNormal(nIndex)));
+
+ if(bNormalsEqual)
+ {
+ const bool bTextureCoordinatesEqual(!mpTextureCoordinates || (mpTextureCoordinates->getTextureCoordinate(0) == mpTextureCoordinates->getTextureCoordinate(nIndex)));
+
+ if(bTextureCoordinatesEqual)
+ {
+ return true;
+ }
+ }
+ }
+ }
+ }
+
+ // test for range
+ for(sal_uInt32 a(0); a < maPoints.count() - 1; a++)
+ {
+ if(maPoints.getCoordinate(a) == maPoints.getCoordinate(a + 1))
+ {
+ const bool bBColorEqual(!mpBColors || (mpBColors->getBColor(a) == mpBColors->getBColor(a + 1)));
+
+ if(bBColorEqual)
+ {
+ const bool bNormalsEqual(!mpNormals || (mpNormals->getNormal(a) == mpNormals->getNormal(a + 1)));
+
+ if(bNormalsEqual)
+ {
+ const bool bTextureCoordinatesEqual(!mpTextureCoordinates || (mpTextureCoordinates->getTextureCoordinate(a) == mpTextureCoordinates->getTextureCoordinate(a + 1)));
+
+ if(bTextureCoordinatesEqual)
+ {
+ return true;
+ }
+ }
+ }
+ }
+ }
+
+ return false;
+ }
+
+ void removeDoublePointsAtBeginEnd()
+ {
+ // Only remove DoublePoints at Begin and End when poly is closed
+ if(!mbIsClosed)
+ return;
+
+ bool bRemove;
+
+ do
+ {
+ bRemove = false;
+
+ if(maPoints.count() > 1)
+ {
+ const sal_uInt32 nIndex(maPoints.count() - 1);
+ bRemove = (maPoints.getCoordinate(0) == maPoints.getCoordinate(nIndex));
+
+ if(bRemove && mpBColors && mpBColors->getBColor(0) != mpBColors->getBColor(nIndex))
+ {
+ bRemove = false;
+ }
+
+ if(bRemove && mpNormals && mpNormals->getNormal(0) != mpNormals->getNormal(nIndex))
+ {
+ bRemove = false;
+ }
+
+ if(bRemove && mpTextureCoordinates && mpTextureCoordinates->getTextureCoordinate(0) != mpTextureCoordinates->getTextureCoordinate(nIndex))
+ {
+ bRemove = false;
+ }
+ }
+
+ if(bRemove)
+ {
+ const sal_uInt32 nIndex(maPoints.count() - 1);
+ remove(nIndex, 1);
+ }
+ } while(bRemove);
+ }
+
+ void removeDoublePointsWholeTrack()
+ {
+ sal_uInt32 nIndex(0);
+
+ // test as long as there are at least two points and as long as the index
+ // is smaller or equal second last point
+ while((maPoints.count() > 1) && (nIndex <= maPoints.count() - 2))
+ {
+ const sal_uInt32 nNextIndex(nIndex + 1);
+ bool bRemove(maPoints.getCoordinate(nIndex) == maPoints.getCoordinate(nNextIndex));
+
+ if(bRemove && mpBColors && mpBColors->getBColor(nIndex) != mpBColors->getBColor(nNextIndex))
+ {
+ bRemove = false;
+ }
+
+ if(bRemove && mpNormals && mpNormals->getNormal(nIndex) != mpNormals->getNormal(nNextIndex))
+ {
+ bRemove = false;
+ }
+
+ if(bRemove && mpTextureCoordinates && mpTextureCoordinates->getTextureCoordinate(nIndex) != mpTextureCoordinates->getTextureCoordinate(nNextIndex))
+ {
+ bRemove = false;
+ }
+
+ if(bRemove)
+ {
+ // if next is same as index and the control vectors are unused, delete index
+ remove(nIndex, 1);
+ }
+ else
+ {
+ // if different, step forward
+ nIndex++;
+ }
+ }
+ }
+
+ void transform(const ::basegfx::B3DHomMatrix& rMatrix)
+ {
+ maPoints.transform(rMatrix);
+
+ // Here, it seems to be possible to transform a valid plane normal and to avoid
+ // invalidation, but it's not true. If the transformation contains shears or e.g.
+ // perspective projection, the orthogonality to the transformed plane will not
+ // be preserved. It may be possible to test that at the matrix to not invalidate in
+ // all cases or to extract a matrix which does not 'shear' the vector which is
+ // a normal in this case. As long as this is not sure, i will just invalidate.
+ invalidatePlaneNormal();
+ }
+};
+
+namespace basegfx
+{
+ namespace {
+
+ B3DPolygon::ImplType const & getDefaultPolygon() {
+ static B3DPolygon::ImplType const singleton;
+ return singleton;
+ }
+
+ }
+
+ B3DPolygon::B3DPolygon() :
+ mpPolygon(getDefaultPolygon())
+ {
+ }
+
+ B3DPolygon::B3DPolygon(const B3DPolygon&) = default;
+
+ B3DPolygon::B3DPolygon(B3DPolygon&&) = default;
+
+ B3DPolygon::~B3DPolygon() = default;
+
+ B3DPolygon& B3DPolygon::operator=(const B3DPolygon&) = default;
+
+ B3DPolygon& B3DPolygon::operator=(B3DPolygon&&) = default;
+
+ bool B3DPolygon::operator==(const B3DPolygon& rPolygon) const
+ {
+ if(mpPolygon.same_object(rPolygon.mpPolygon))
+ return true;
+
+ return (*mpPolygon == *rPolygon.mpPolygon);
+ }
+
+ bool B3DPolygon::operator!=(const B3DPolygon& rPolygon) const
+ {
+ return !(*this == rPolygon);
+ }
+
+ sal_uInt32 B3DPolygon::count() const
+ {
+ return mpPolygon->count();
+ }
+
+ basegfx::B3DPoint const & B3DPolygon::getB3DPoint(sal_uInt32 nIndex) const
+ {
+ OSL_ENSURE(nIndex < mpPolygon->count(), "B3DPolygon access outside range (!)");
+
+ return mpPolygon->getPoint(nIndex);
+ }
+
+ void B3DPolygon::setB3DPoint(sal_uInt32 nIndex, const basegfx::B3DPoint& rValue)
+ {
+ OSL_ENSURE(nIndex < mpPolygon->count(), "B3DPolygon access outside range (!)");
+
+ if(getB3DPoint(nIndex) != rValue)
+ mpPolygon->setPoint(nIndex, rValue);
+ }
+
+ BColor const & B3DPolygon::getBColor(sal_uInt32 nIndex) const
+ {
+ OSL_ENSURE(nIndex < mpPolygon->count(), "B3DPolygon access outside range (!)");
+
+ return mpPolygon->getBColor(nIndex);
+ }
+
+ void B3DPolygon::setBColor(sal_uInt32 nIndex, const BColor& rValue)
+ {
+ OSL_ENSURE(nIndex < mpPolygon->count(), "B3DPolygon access outside range (!)");
+
+ if(mpPolygon->getBColor(nIndex) != rValue)
+ mpPolygon->setBColor(nIndex, rValue);
+ }
+
+ bool B3DPolygon::areBColorsUsed() const
+ {
+ return mpPolygon->areBColorsUsed();
+ }
+
+ void B3DPolygon::clearBColors()
+ {
+ if(mpPolygon->areBColorsUsed())
+ mpPolygon->clearBColors();
+ }
+
+ B3DVector const & B3DPolygon::getNormal() const
+ {
+ return mpPolygon->getNormal();
+ }
+
+ B3DVector const & B3DPolygon::getNormal(sal_uInt32 nIndex) const
+ {
+ OSL_ENSURE(nIndex < mpPolygon->count(), "B3DPolygon access outside range (!)");
+
+ return mpPolygon->getNormal(nIndex);
+ }
+
+ void B3DPolygon::setNormal(sal_uInt32 nIndex, const B3DVector& rValue)
+ {
+ OSL_ENSURE(nIndex < mpPolygon->count(), "B3DPolygon access outside range (!)");
+
+ if(mpPolygon->getNormal(nIndex) != rValue)
+ mpPolygon->setNormal(nIndex, rValue);
+ }
+
+ void B3DPolygon::transformNormals(const B3DHomMatrix& rMatrix)
+ {
+ if(mpPolygon->areNormalsUsed() && !rMatrix.isIdentity())
+ mpPolygon->transformNormals(rMatrix);
+ }
+
+ bool B3DPolygon::areNormalsUsed() const
+ {
+ return mpPolygon->areNormalsUsed();
+ }
+
+ void B3DPolygon::clearNormals()
+ {
+ if(mpPolygon->areNormalsUsed())
+ mpPolygon->clearNormals();
+ }
+
+ B2DPoint const & B3DPolygon::getTextureCoordinate(sal_uInt32 nIndex) const
+ {
+ OSL_ENSURE(nIndex < mpPolygon->count(), "B3DPolygon access outside range (!)");
+
+ return mpPolygon->getTextureCoordinate(nIndex);
+ }
+
+ void B3DPolygon::setTextureCoordinate(sal_uInt32 nIndex, const B2DPoint& rValue)
+ {
+ OSL_ENSURE(nIndex < mpPolygon->count(), "B3DPolygon access outside range (!)");
+
+ if(mpPolygon->getTextureCoordinate(nIndex) != rValue)
+ mpPolygon->setTextureCoordinate(nIndex, rValue);
+ }
+
+ void B3DPolygon::transformTextureCoordinates(const B2DHomMatrix& rMatrix)
+ {
+ if(mpPolygon->areTextureCoordinatesUsed() && !rMatrix.isIdentity())
+ mpPolygon->transformTextureCoordinates(rMatrix);
+ }
+
+ bool B3DPolygon::areTextureCoordinatesUsed() const
+ {
+ return mpPolygon->areTextureCoordinatesUsed();
+ }
+
+ void B3DPolygon::clearTextureCoordinates()
+ {
+ if(mpPolygon->areTextureCoordinatesUsed())
+ mpPolygon->clearTextureCoordinates();
+ }
+
+ void B3DPolygon::append(const basegfx::B3DPoint& rPoint, sal_uInt32 nCount)
+ {
+ if(nCount)
+ mpPolygon->insert(mpPolygon->count(), rPoint, nCount);
+ }
+
+ void B3DPolygon::append(const B3DPolygon& rPoly, sal_uInt32 nIndex, sal_uInt32 nCount)
+ {
+ if(!rPoly.count())
+ return;
+
+ if(!nCount)
+ {
+ nCount = rPoly.count();
+ }
+
+ if(nIndex == 0 && nCount == rPoly.count())
+ {
+ mpPolygon->insert(mpPolygon->count(), *rPoly.mpPolygon);
+ }
+ else
+ {
+ OSL_ENSURE(nIndex + nCount <= rPoly.mpPolygon->count(), "B3DPolygon Append outside range (!)");
+ ImplB3DPolygon aTempPoly(*rPoly.mpPolygon, nIndex, nCount);
+ mpPolygon->insert(mpPolygon->count(), aTempPoly);
+ }
+ }
+
+ void B3DPolygon::remove(sal_uInt32 nIndex, sal_uInt32 nCount)
+ {
+ OSL_ENSURE(nIndex + nCount <= mpPolygon->count(), "B3DPolygon Remove outside range (!)");
+
+ if(nCount)
+ mpPolygon->remove(nIndex, nCount);
+ }
+
+ void B3DPolygon::clear()
+ {
+ mpPolygon = getDefaultPolygon();
+ }
+
+ bool B3DPolygon::isClosed() const
+ {
+ return mpPolygon->isClosed();
+ }
+
+ void B3DPolygon::setClosed(bool bNew)
+ {
+ if(isClosed() != bNew)
+ mpPolygon->setClosed(bNew);
+ }
+
+ void B3DPolygon::flip()
+ {
+ if(count() > 1)
+ mpPolygon->flip();
+ }
+
+ bool B3DPolygon::hasDoublePoints() const
+ {
+ return (mpPolygon->count() > 1 && mpPolygon->hasDoublePoints());
+ }
+
+ void B3DPolygon::removeDoublePoints()
+ {
+ if(hasDoublePoints())
+ {
+ mpPolygon->removeDoublePointsAtBeginEnd();
+ mpPolygon->removeDoublePointsWholeTrack();
+ }
+ }
+
+ void B3DPolygon::transform(const basegfx::B3DHomMatrix& rMatrix)
+ {
+ if(mpPolygon->count() && !rMatrix.isIdentity())
+ {
+ mpPolygon->transform(rMatrix);
+ }
+ }
+} // end of namespace basegfx
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */