diff options
Diffstat (limited to 'basegfx/source/polygon/b3dpolygontools.cxx')
-rw-r--r-- | basegfx/source/polygon/b3dpolygontools.cxx | 1266 |
1 files changed, 0 insertions, 1266 deletions
diff --git a/basegfx/source/polygon/b3dpolygontools.cxx b/basegfx/source/polygon/b3dpolygontools.cxx deleted file mode 100644 index b56c837e2a..0000000000 --- a/basegfx/source/polygon/b3dpolygontools.cxx +++ /dev/null @@ -1,1266 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/************************************************************************* - * - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * Copyright 2000, 2010 Oracle and/or its affiliates. - * - * OpenOffice.org - a multi-platform office productivity suite - * - * This file is part of OpenOffice.org. - * - * OpenOffice.org is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License version 3 - * only, as published by the Free Software Foundation. - * - * OpenOffice.org is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License version 3 for more details - * (a copy is included in the LICENSE file that accompanied this code). - * - * You should have received a copy of the GNU Lesser General Public License - * version 3 along with OpenOffice.org. If not, see - * <http://www.openoffice.org/license.html> - * for a copy of the LGPLv3 License. - * - ************************************************************************/ - -// MARKER(update_precomp.py): autogen include statement, do not remove -#include "precompiled_basegfx.hxx" -#include <osl/diagnose.h> -#include <basegfx/polygon/b3dpolygontools.hxx> -#include <basegfx/polygon/b3dpolygon.hxx> -#include <basegfx/numeric/ftools.hxx> -#include <basegfx/range/b3drange.hxx> -#include <basegfx/point/b2dpoint.hxx> -#include <basegfx/matrix/b3dhommatrix.hxx> -#include <basegfx/polygon/b2dpolygon.hxx> -#include <basegfx/polygon/b2dpolygontools.hxx> -#include <basegfx/tuple/b3ituple.hxx> -#include <numeric> - -////////////////////////////////////////////////////////////////////////////// - -namespace basegfx -{ - namespace tools - { - // B3DPolygon tools - void checkClosed(B3DPolygon& rCandidate) - { - while(rCandidate.count() > 1L - && rCandidate.getB3DPoint(0L).equal(rCandidate.getB3DPoint(rCandidate.count() - 1L))) - { - rCandidate.setClosed(true); - rCandidate.remove(rCandidate.count() - 1L); - } - } - - // Get successor and predecessor indices. Returning the same index means there - // is none. Same for successor. - sal_uInt32 getIndexOfPredecessor(sal_uInt32 nIndex, const B3DPolygon& rCandidate) - { - OSL_ENSURE(nIndex < rCandidate.count(), "getIndexOfPredecessor: Access to polygon out of range (!)"); - - if(nIndex) - { - return nIndex - 1L; - } - else if(rCandidate.count()) - { - return rCandidate.count() - 1L; - } - else - { - return nIndex; - } - } - - sal_uInt32 getIndexOfSuccessor(sal_uInt32 nIndex, const B3DPolygon& rCandidate) - { - OSL_ENSURE(nIndex < rCandidate.count(), "getIndexOfPredecessor: Access to polygon out of range (!)"); - - if(nIndex + 1L < rCandidate.count()) - { - return nIndex + 1L; - } - else - { - return 0L; - } - } - - B3DRange getRange(const B3DPolygon& rCandidate) - { - B3DRange aRetval; - const sal_uInt32 nPointCount(rCandidate.count()); - - for(sal_uInt32 a(0L); a < nPointCount; a++) - { - const B3DPoint aTestPoint(rCandidate.getB3DPoint(a)); - aRetval.expand(aTestPoint); - } - - return aRetval; - } - - B3DVector getNormal(const B3DPolygon& rCandidate) - { - return rCandidate.getNormal(); - } - - B3DVector getPositiveOrientedNormal(const B3DPolygon& rCandidate) - { - B3DVector aRetval(rCandidate.getNormal()); - - if(ORIENTATION_NEGATIVE == getOrientation(rCandidate)) - { - aRetval = -aRetval; - } - - return aRetval; - } - - B2VectorOrientation getOrientation(const B3DPolygon& rCandidate) - { - B2VectorOrientation eRetval(ORIENTATION_NEUTRAL); - - if(rCandidate.count() > 2L) - { - const double fSignedArea(getSignedArea(rCandidate)); - - if(fSignedArea > 0.0) - { - eRetval = ORIENTATION_POSITIVE; - } - else if(fSignedArea < 0.0) - { - eRetval = ORIENTATION_NEGATIVE; - } - } - - return eRetval; - } - - double getSignedArea(const B3DPolygon& rCandidate) - { - double fRetval(0.0); - const sal_uInt32 nPointCount(rCandidate.count()); - - if(nPointCount > 2) - { - const B3DVector aAbsNormal(absolute(getNormal(rCandidate))); - sal_uInt16 nCase(3); // default: ignore z - - if(aAbsNormal.getX() > aAbsNormal.getY()) - { - if(aAbsNormal.getX() > aAbsNormal.getZ()) - { - nCase = 1; // ignore x - } - } - else if(aAbsNormal.getY() > aAbsNormal.getZ()) - { - nCase = 2; // ignore y - } - - B3DPoint aPreviousPoint(rCandidate.getB3DPoint(nPointCount - 1L)); - - for(sal_uInt32 a(0L); a < nPointCount; a++) - { - const B3DPoint aCurrentPoint(rCandidate.getB3DPoint(a)); - - switch(nCase) - { - case 1: // ignore x - fRetval += aPreviousPoint.getZ() * aCurrentPoint.getY(); - fRetval -= aPreviousPoint.getY() * aCurrentPoint.getZ(); - break; - case 2: // ignore y - fRetval += aPreviousPoint.getX() * aCurrentPoint.getZ(); - fRetval -= aPreviousPoint.getZ() * aCurrentPoint.getX(); - break; - case 3: // ignore z - fRetval += aPreviousPoint.getX() * aCurrentPoint.getY(); - fRetval -= aPreviousPoint.getY() * aCurrentPoint.getX(); - break; - } - - // prepare next step - aPreviousPoint = aCurrentPoint; - } - - switch(nCase) - { - case 1: // ignore x - fRetval /= 2.0 * aAbsNormal.getX(); - break; - case 2: // ignore y - fRetval /= 2.0 * aAbsNormal.getY(); - break; - case 3: // ignore z - fRetval /= 2.0 * aAbsNormal.getZ(); - break; - } - } - - return fRetval; - } - - double getArea(const B3DPolygon& rCandidate) - { - double fRetval(0.0); - - if(rCandidate.count() > 2) - { - fRetval = getSignedArea(rCandidate); - const double fZero(0.0); - - if(fTools::less(fRetval, fZero)) - { - fRetval = -fRetval; - } - } - - return fRetval; - } - - double getEdgeLength(const B3DPolygon& rCandidate, sal_uInt32 nIndex) - { - OSL_ENSURE(nIndex < rCandidate.count(), "getEdgeLength: Access to polygon out of range (!)"); - double fRetval(0.0); - const sal_uInt32 nPointCount(rCandidate.count()); - - if(nIndex < nPointCount) - { - if(rCandidate.isClosed() || ((nIndex + 1L) != nPointCount)) - { - const sal_uInt32 nNextIndex(getIndexOfSuccessor(nIndex, rCandidate)); - const B3DPoint aCurrentPoint(rCandidate.getB3DPoint(nIndex)); - const B3DPoint aNextPoint(rCandidate.getB3DPoint(nNextIndex)); - const B3DVector aVector(aNextPoint - aCurrentPoint); - fRetval = aVector.getLength(); - } - } - - return fRetval; - } - - double getLength(const B3DPolygon& rCandidate) - { - double fRetval(0.0); - const sal_uInt32 nPointCount(rCandidate.count()); - - if(nPointCount > 1L) - { - const sal_uInt32 nLoopCount(rCandidate.isClosed() ? nPointCount : nPointCount - 1L); - - for(sal_uInt32 a(0L); a < nLoopCount; a++) - { - const sal_uInt32 nNextIndex(getIndexOfSuccessor(a, rCandidate)); - const B3DPoint aCurrentPoint(rCandidate.getB3DPoint(a)); - const B3DPoint aNextPoint(rCandidate.getB3DPoint(nNextIndex)); - const B3DVector aVector(aNextPoint - aCurrentPoint); - fRetval += aVector.getLength(); - } - } - - return fRetval; - } - - B3DPoint getPositionAbsolute(const B3DPolygon& rCandidate, double fDistance, double fLength) - { - B3DPoint aRetval; - const sal_uInt32 nPointCount(rCandidate.count()); - - if(nPointCount > 1L) - { - sal_uInt32 nIndex(0L); - bool bIndexDone(false); - const double fZero(0.0); - double fEdgeLength(fZero); - - // get length if not given - if(fTools::equalZero(fLength)) - { - fLength = getLength(rCandidate); - } - - // handle fDistance < 0.0 - if(fTools::less(fDistance, fZero)) - { - if(rCandidate.isClosed()) - { - // if fDistance < 0.0 increment with multiple of fLength - sal_uInt32 nCount(sal_uInt32(-fDistance / fLength)); - fDistance += double(nCount + 1L) * fLength; - } - else - { - // crop to polygon start - fDistance = fZero; - bIndexDone = true; - } - } - - // handle fDistance >= fLength - if(fTools::moreOrEqual(fDistance, fLength)) - { - if(rCandidate.isClosed()) - { - // if fDistance >= fLength decrement with multiple of fLength - sal_uInt32 nCount(sal_uInt32(fDistance / fLength)); - fDistance -= (double)(nCount) * fLength; - } - else - { - // crop to polygon end - fDistance = fZero; - nIndex = nPointCount - 1L; - bIndexDone = true; - } - } - - // look for correct index. fDistance is now [0.0 .. fLength[ - if(!bIndexDone) - { - do - { - // get length of next edge - fEdgeLength = getEdgeLength(rCandidate, nIndex); - - if(fTools::moreOrEqual(fDistance, fEdgeLength)) - { - // go to next edge - fDistance -= fEdgeLength; - nIndex++; - } - else - { - // it's on this edge, stop - bIndexDone = true; - } - } while (!bIndexDone); - } - - // get the point using nIndex - aRetval = rCandidate.getB3DPoint(nIndex); - - // if fDistance != 0.0, move that length on the edge. The edge - // length is in fEdgeLength. - if(!fTools::equalZero(fDistance)) - { - sal_uInt32 nNextIndex(getIndexOfSuccessor(nIndex, rCandidate)); - const B3DPoint aNextPoint(rCandidate.getB3DPoint(nNextIndex)); - double fRelative(fZero); - - if(!fTools::equalZero(fEdgeLength)) - { - fRelative = fDistance / fEdgeLength; - } - - // add calculated average value to the return value - aRetval += interpolate(aRetval, aNextPoint, fRelative); - } - } - - return aRetval; - } - - B3DPoint getPositionRelative(const B3DPolygon& rCandidate, double fDistance, double fLength) - { - // get length if not given - if(fTools::equalZero(fLength)) - { - fLength = getLength(rCandidate); - } - - // multiply fDistance with real length to get absolute position and - // use getPositionAbsolute - return getPositionAbsolute(rCandidate, fDistance * fLength, fLength); - } - - void applyLineDashing(const B3DPolygon& rCandidate, const ::std::vector<double>& rDotDashArray, B3DPolyPolygon* pLineTarget, B3DPolyPolygon* pGapTarget, double fDotDashLength) - { - const sal_uInt32 nPointCount(rCandidate.count()); - const sal_uInt32 nDotDashCount(rDotDashArray.size()); - - if(fTools::lessOrEqual(fDotDashLength, 0.0)) - { - fDotDashLength = ::std::accumulate(rDotDashArray.begin(), rDotDashArray.end(), 0.0); - } - - if(fTools::more(fDotDashLength, 0.0) && (pLineTarget || pGapTarget) && nPointCount) - { - // clear targets - if(pLineTarget) - { - pLineTarget->clear(); - } - - if(pGapTarget) - { - pGapTarget->clear(); - } - - // prepare current edge's start - B3DPoint aCurrentPoint(rCandidate.getB3DPoint(0)); - const sal_uInt32 nEdgeCount(rCandidate.isClosed() ? nPointCount : nPointCount - 1); - - // prepare DotDashArray iteration and the line/gap switching bool - sal_uInt32 nDotDashIndex(0); - bool bIsLine(true); - double fDotDashMovingLength(rDotDashArray[0]); - B3DPolygon aSnippet; - - // iterate over all edges - for(sal_uInt32 a(0); a < nEdgeCount; a++) - { - // update current edge - double fLastDotDashMovingLength(0.0); - const sal_uInt32 nNextIndex((a + 1) % nPointCount); - const B3DPoint aNextPoint(rCandidate.getB3DPoint(nNextIndex)); - const double fEdgeLength(B3DVector(aNextPoint - aCurrentPoint).getLength()); - - while(fTools::less(fDotDashMovingLength, fEdgeLength)) - { - // new split is inside edge, create and append snippet [fLastDotDashMovingLength, fDotDashMovingLength] - const bool bHandleLine(bIsLine && pLineTarget); - const bool bHandleGap(!bIsLine && pGapTarget); - - if(bHandleLine || bHandleGap) - { - if(!aSnippet.count()) - { - aSnippet.append(interpolate(aCurrentPoint, aNextPoint, fLastDotDashMovingLength / fEdgeLength)); - } - - aSnippet.append(interpolate(aCurrentPoint, aNextPoint, fDotDashMovingLength / fEdgeLength)); - - if(bHandleLine) - { - pLineTarget->append(aSnippet); - } - else - { - pGapTarget->append(aSnippet); - } - - aSnippet.clear(); - } - - // prepare next DotDashArray step and flip line/gap flag - fLastDotDashMovingLength = fDotDashMovingLength; - fDotDashMovingLength += rDotDashArray[(++nDotDashIndex) % nDotDashCount]; - bIsLine = !bIsLine; - } - - // append snippet [fLastDotDashMovingLength, fEdgeLength] - const bool bHandleLine(bIsLine && pLineTarget); - const bool bHandleGap(!bIsLine && pGapTarget); - - if(bHandleLine || bHandleGap) - { - if(!aSnippet.count()) - { - aSnippet.append(interpolate(aCurrentPoint, aNextPoint, fLastDotDashMovingLength / fEdgeLength)); - } - - aSnippet.append(aNextPoint); - } - - // prepare move to next edge - fDotDashMovingLength -= fEdgeLength; - - // prepare next edge step (end point gets new start point) - aCurrentPoint = aNextPoint; - } - - // append last intermediate results (if exists) - if(aSnippet.count()) - { - if(bIsLine && pLineTarget) - { - pLineTarget->append(aSnippet); - } - else if(!bIsLine && pGapTarget) - { - pGapTarget->append(aSnippet); - } - } - - // check if start and end polygon may be merged - if(pLineTarget) - { - const sal_uInt32 nCount(pLineTarget->count()); - - if(nCount > 1) - { - // these polygons were created above, there exists none with less than two points, - // thus dircet point access below is allowed - const B3DPolygon aFirst(pLineTarget->getB3DPolygon(0)); - B3DPolygon aLast(pLineTarget->getB3DPolygon(nCount - 1)); - - if(aFirst.getB3DPoint(0).equal(aLast.getB3DPoint(aLast.count() - 1))) - { - // start of first and end of last are the same -> merge them - aLast.append(aFirst); - aLast.removeDoublePoints(); - pLineTarget->setB3DPolygon(0, aLast); - pLineTarget->remove(nCount - 1); - } - } - } - - if(pGapTarget) - { - const sal_uInt32 nCount(pGapTarget->count()); - - if(nCount > 1) - { - // these polygons were created above, there exists none with less than two points, - // thus dircet point access below is allowed - const B3DPolygon aFirst(pGapTarget->getB3DPolygon(0)); - B3DPolygon aLast(pGapTarget->getB3DPolygon(nCount - 1)); - - if(aFirst.getB3DPoint(0).equal(aLast.getB3DPoint(aLast.count() - 1))) - { - // start of first and end of last are the same -> merge them - aLast.append(aFirst); - aLast.removeDoublePoints(); - pGapTarget->setB3DPolygon(0, aLast); - pGapTarget->remove(nCount - 1); - } - } - } - } - else - { - // parameters make no sense, just add source to targets - if(pLineTarget) - { - pLineTarget->append(rCandidate); - } - - if(pGapTarget) - { - pGapTarget->append(rCandidate); - } - } - } - - B3DPolygon applyDefaultNormalsSphere( const B3DPolygon& rCandidate, const B3DPoint& rCenter) - { - B3DPolygon aRetval(rCandidate); - - for(sal_uInt32 a(0L); a < aRetval.count(); a++) - { - B3DVector aVector(aRetval.getB3DPoint(a) - rCenter); - aVector.normalize(); - aRetval.setNormal(a, aVector); - } - - return aRetval; - } - - B3DPolygon invertNormals( const B3DPolygon& rCandidate) - { - B3DPolygon aRetval(rCandidate); - - if(aRetval.areNormalsUsed()) - { - for(sal_uInt32 a(0L); a < aRetval.count(); a++) - { - aRetval.setNormal(a, -aRetval.getNormal(a)); - } - } - - return aRetval; - } - - B3DPolygon applyDefaultTextureCoordinatesParallel( const B3DPolygon& rCandidate, const B3DRange& rRange, bool bChangeX, bool bChangeY) - { - B3DPolygon aRetval(rCandidate); - - if(bChangeX || bChangeY) - { - // create projection of standard texture coordinates in (X, Y) onto - // the 3d coordinates straight - const double fWidth(rRange.getWidth()); - const double fHeight(rRange.getHeight()); - const bool bWidthSet(!fTools::equalZero(fWidth)); - const bool bHeightSet(!fTools::equalZero(fHeight)); - const double fOne(1.0); - - for(sal_uInt32 a(0L); a < aRetval.count(); a++) - { - const B3DPoint aPoint(aRetval.getB3DPoint(a)); - B2DPoint aTextureCoordinate(aRetval.getTextureCoordinate(a)); - - if(bChangeX) - { - if(bWidthSet) - { - aTextureCoordinate.setX((aPoint.getX() - rRange.getMinX()) / fWidth); - } - else - { - aTextureCoordinate.setX(0.0); - } - } - - if(bChangeY) - { - if(bHeightSet) - { - aTextureCoordinate.setY(fOne - ((aPoint.getY() - rRange.getMinY()) / fHeight)); - } - else - { - aTextureCoordinate.setY(fOne); - } - } - - aRetval.setTextureCoordinate(a, aTextureCoordinate); - } - } - - return aRetval; - } - - B3DPolygon applyDefaultTextureCoordinatesSphere( const B3DPolygon& rCandidate, const B3DPoint& rCenter, bool bChangeX, bool bChangeY) - { - B3DPolygon aRetval(rCandidate); - - if(bChangeX || bChangeY) - { - // create texture coordinates using sphere projection to cartesian coordinates, - // use object's center as base - const double fOne(1.0); - const sal_uInt32 nPointCount(aRetval.count()); - bool bPolarPoints(false); - sal_uInt32 a; - - // create center cartesian coordinates to have a possibility to decide if on boundary - // transitions which value to choose - const B3DRange aPlaneRange(getRange(rCandidate)); - const B3DPoint aPlaneCenter(aPlaneRange.getCenter() - rCenter); - const double fXCenter(fOne - ((atan2(aPlaneCenter.getZ(), aPlaneCenter.getX()) + F_PI) / F_2PI)); - - for(a = 0L; a < nPointCount; a++) - { - const B3DVector aVector(aRetval.getB3DPoint(a) - rCenter); - const double fY(fOne - ((atan2(aVector.getY(), aVector.getXZLength()) + F_PI2) / F_PI)); - B2DPoint aTexCoor(aRetval.getTextureCoordinate(a)); - - if(fTools::equalZero(fY)) - { - // point is a north polar point, no useful X-coordinate can be created. - if(bChangeY) - { - aTexCoor.setY(0.0); - - if(bChangeX) - { - bPolarPoints = true; - } - } - } - else if(fTools::equal(fY, fOne)) - { - // point is a south polar point, no useful X-coordinate can be created. Set - // Y-coordinte, though - if(bChangeY) - { - aTexCoor.setY(fOne); - - if(bChangeX) - { - bPolarPoints = true; - } - } - } - else - { - double fX(fOne - ((atan2(aVector.getZ(), aVector.getX()) + F_PI) / F_2PI)); - - // correct cartesinan point coordiante dependent from center value - if(fX > fXCenter + 0.5) - { - fX -= fOne; - } - else if(fX < fXCenter - 0.5) - { - fX += fOne; - } - - if(bChangeX) - { - aTexCoor.setX(fX); - } - - if(bChangeY) - { - aTexCoor.setY(fY); - } - } - - aRetval.setTextureCoordinate(a, aTexCoor); - } - - if(bPolarPoints) - { - // correct X-texture coordinates if polar points are contained. Those - // coordinates cannot be correct, so use prev or next X-coordinate - for(a = 0L; a < nPointCount; a++) - { - B2DPoint aTexCoor(aRetval.getTextureCoordinate(a)); - - if(fTools::equalZero(aTexCoor.getY()) || fTools::equal(aTexCoor.getY(), fOne)) - { - // get prev, next TexCoor and test for pole - const B2DPoint aPrevTexCoor(aRetval.getTextureCoordinate(a ? a - 1L : nPointCount - 1L)); - const B2DPoint aNextTexCoor(aRetval.getTextureCoordinate((a + 1L) % nPointCount)); - const bool bPrevPole(fTools::equalZero(aPrevTexCoor.getY()) || fTools::equal(aPrevTexCoor.getY(), fOne)); - const bool bNextPole(fTools::equalZero(aNextTexCoor.getY()) || fTools::equal(aNextTexCoor.getY(), fOne)); - - if(!bPrevPole && !bNextPole) - { - // both no poles, mix them - aTexCoor.setX((aPrevTexCoor.getX() + aNextTexCoor.getX()) / 2.0); - } - else if(!bNextPole) - { - // copy next - aTexCoor.setX(aNextTexCoor.getX()); - } - else - { - // copy prev, even if it's a pole, hopefully it is already corrected - aTexCoor.setX(aPrevTexCoor.getX()); - } - - aRetval.setTextureCoordinate(a, aTexCoor); - } - } - } - } - - return aRetval; - } - - bool isInEpsilonRange(const B3DPoint& rEdgeStart, const B3DPoint& rEdgeEnd, const B3DPoint& rTestPosition, double fDistance) - { - // build edge vector - const B3DVector aEdge(rEdgeEnd - rEdgeStart); - bool bDoDistanceTestStart(false); - bool bDoDistanceTestEnd(false); - - if(aEdge.equalZero()) - { - // no edge, just a point. Do one of the distance tests. - bDoDistanceTestStart = true; - } - else - { - // calculate fCut in aEdge - const B3DVector aTestEdge(rTestPosition - rEdgeStart); - const double fScalarTestEdge(aEdge.scalar(aTestEdge)); - const double fScalarStartEdge(aEdge.scalar(rEdgeStart)); - const double fScalarEdge(aEdge.scalar(aEdge)); - const double fCut((fScalarTestEdge - fScalarStartEdge) / fScalarEdge); - const double fZero(0.0); - const double fOne(1.0); - - if(fTools::less(fCut, fZero)) - { - // left of rEdgeStart - bDoDistanceTestStart = true; - } - else if(fTools::more(fCut, fOne)) - { - // right of rEdgeEnd - bDoDistanceTestEnd = true; - } - else - { - // inside line [0.0 .. 1.0] - const B3DPoint aCutPoint(interpolate(rEdgeStart, rEdgeEnd, fCut)); - const B3DVector aDelta(rTestPosition - aCutPoint); - const double fDistanceSquare(aDelta.scalar(aDelta)); - - if(fDistanceSquare <= fDistance * fDistance * fDistance) - { - return true; - } - else - { - return false; - } - } - } - - if(bDoDistanceTestStart) - { - const B3DVector aDelta(rTestPosition - rEdgeStart); - const double fDistanceSquare(aDelta.scalar(aDelta)); - - if(fDistanceSquare <= fDistance * fDistance * fDistance) - { - return true; - } - } - else if(bDoDistanceTestEnd) - { - const B3DVector aDelta(rTestPosition - rEdgeEnd); - const double fDistanceSquare(aDelta.scalar(aDelta)); - - if(fDistanceSquare <= fDistance * fDistance * fDistance) - { - return true; - } - } - - return false; - } - - bool isInEpsilonRange(const B3DPolygon& rCandidate, const B3DPoint& rTestPosition, double fDistance) - { - const sal_uInt32 nPointCount(rCandidate.count()); - - if(nPointCount) - { - const sal_uInt32 nEdgeCount(rCandidate.isClosed() ? nPointCount : nPointCount - 1L); - B3DPoint aCurrent(rCandidate.getB3DPoint(0)); - - if(nEdgeCount) - { - // edges - for(sal_uInt32 a(0); a < nEdgeCount; a++) - { - const sal_uInt32 nNextIndex((a + 1) % nPointCount); - const B3DPoint aNext(rCandidate.getB3DPoint(nNextIndex)); - - if(isInEpsilonRange(aCurrent, aNext, rTestPosition, fDistance)) - { - return true; - } - - // prepare next step - aCurrent = aNext; - } - } - else - { - // no edges, but points -> not closed. Check single point. Just - // use isInEpsilonRange with twice the same point, it handles those well - if(isInEpsilonRange(aCurrent, aCurrent, rTestPosition, fDistance)) - { - return true; - } - } - } - - return false; - } - - bool isInside(const B3DPolygon& rCandidate, const B3DPoint& rPoint, bool bWithBorder) - { - if(bWithBorder && isPointOnPolygon(rCandidate, rPoint, true)) - { - return true; - } - else - { - bool bRetval(false); - const B3DVector aPlaneNormal(rCandidate.getNormal()); - - if(!aPlaneNormal.equalZero()) - { - const sal_uInt32 nPointCount(rCandidate.count()); - - if(nPointCount) - { - B3DPoint aCurrentPoint(rCandidate.getB3DPoint(nPointCount - 1)); - const double fAbsX(fabs(aPlaneNormal.getX())); - const double fAbsY(fabs(aPlaneNormal.getY())); - const double fAbsZ(fabs(aPlaneNormal.getZ())); - - if(fAbsX > fAbsY && fAbsX > fAbsZ) - { - // normal points mostly in X-Direction, use YZ-Polygon projection for check - // x -> y, y -> z - for(sal_uInt32 a(0); a < nPointCount; a++) - { - const B3DPoint aPreviousPoint(aCurrentPoint); - aCurrentPoint = rCandidate.getB3DPoint(a); - - // cross-over in Z? - const bool bCompZA(fTools::more(aPreviousPoint.getZ(), rPoint.getZ())); - const bool bCompZB(fTools::more(aCurrentPoint.getZ(), rPoint.getZ())); - - if(bCompZA != bCompZB) - { - // cross-over in Y? - const bool bCompYA(fTools::more(aPreviousPoint.getY(), rPoint.getY())); - const bool bCompYB(fTools::more(aCurrentPoint.getY(), rPoint.getY())); - - if(bCompYA == bCompYB) - { - if(bCompYA) - { - bRetval = !bRetval; - } - } - else - { - const double fCompare( - aCurrentPoint.getY() - (aCurrentPoint.getZ() - rPoint.getZ()) * - (aPreviousPoint.getY() - aCurrentPoint.getY()) / - (aPreviousPoint.getZ() - aCurrentPoint.getZ())); - - if(fTools::more(fCompare, rPoint.getY())) - { - bRetval = !bRetval; - } - } - } - } - } - else if(fAbsY > fAbsX && fAbsY > fAbsZ) - { - // normal points mostly in Y-Direction, use XZ-Polygon projection for check - // x -> x, y -> z - for(sal_uInt32 a(0); a < nPointCount; a++) - { - const B3DPoint aPreviousPoint(aCurrentPoint); - aCurrentPoint = rCandidate.getB3DPoint(a); - - // cross-over in Z? - const bool bCompZA(fTools::more(aPreviousPoint.getZ(), rPoint.getZ())); - const bool bCompZB(fTools::more(aCurrentPoint.getZ(), rPoint.getZ())); - - if(bCompZA != bCompZB) - { - // cross-over in X? - const bool bCompXA(fTools::more(aPreviousPoint.getX(), rPoint.getX())); - const bool bCompXB(fTools::more(aCurrentPoint.getX(), rPoint.getX())); - - if(bCompXA == bCompXB) - { - if(bCompXA) - { - bRetval = !bRetval; - } - } - else - { - const double fCompare( - aCurrentPoint.getX() - (aCurrentPoint.getZ() - rPoint.getZ()) * - (aPreviousPoint.getX() - aCurrentPoint.getX()) / - (aPreviousPoint.getZ() - aCurrentPoint.getZ())); - - if(fTools::more(fCompare, rPoint.getX())) - { - bRetval = !bRetval; - } - } - } - } - } - else - { - // normal points mostly in Z-Direction, use XY-Polygon projection for check - // x -> x, y -> y - for(sal_uInt32 a(0); a < nPointCount; a++) - { - const B3DPoint aPreviousPoint(aCurrentPoint); - aCurrentPoint = rCandidate.getB3DPoint(a); - - // cross-over in Y? - const bool bCompYA(fTools::more(aPreviousPoint.getY(), rPoint.getY())); - const bool bCompYB(fTools::more(aCurrentPoint.getY(), rPoint.getY())); - - if(bCompYA != bCompYB) - { - // cross-over in X? - const bool bCompXA(fTools::more(aPreviousPoint.getX(), rPoint.getX())); - const bool bCompXB(fTools::more(aCurrentPoint.getX(), rPoint.getX())); - - if(bCompXA == bCompXB) - { - if(bCompXA) - { - bRetval = !bRetval; - } - } - else - { - const double fCompare( - aCurrentPoint.getX() - (aCurrentPoint.getY() - rPoint.getY()) * - (aPreviousPoint.getX() - aCurrentPoint.getX()) / - (aPreviousPoint.getY() - aCurrentPoint.getY())); - - if(fTools::more(fCompare, rPoint.getX())) - { - bRetval = !bRetval; - } - } - } - } - } - } - } - - return bRetval; - } - } - - bool isInside(const B3DPolygon& rCandidate, const B3DPolygon& rPolygon, bool bWithBorder) - { - const sal_uInt32 nPointCount(rPolygon.count()); - - for(sal_uInt32 a(0L); a < nPointCount; a++) - { - const B3DPoint aTestPoint(rPolygon.getB3DPoint(a)); - - if(!isInside(rCandidate, aTestPoint, bWithBorder)) - { - return false; - } - } - - return true; - } - - bool isPointOnLine(const B3DPoint& rStart, const B3DPoint& rEnd, const B3DPoint& rCandidate, bool bWithPoints) - { - if(rCandidate.equal(rStart) || rCandidate.equal(rEnd)) - { - // candidate is in epsilon around start or end -> inside - return bWithPoints; - } - else if(rStart.equal(rEnd)) - { - // start and end are equal, but candidate is outside their epsilon -> outside - return false; - } - else - { - const B3DVector aEdgeVector(rEnd - rStart); - const B3DVector aTestVector(rCandidate - rStart); - - if(areParallel(aEdgeVector, aTestVector)) - { - const double fZero(0.0); - const double fOne(1.0); - double fParamTestOnCurr(0.0); - - if(aEdgeVector.getX() > aEdgeVector.getY()) - { - if(aEdgeVector.getX() > aEdgeVector.getZ()) - { - // X is biggest - fParamTestOnCurr = aTestVector.getX() / aEdgeVector.getX(); - } - else - { - // Z is biggest - fParamTestOnCurr = aTestVector.getZ() / aEdgeVector.getZ(); - } - } - else - { - if(aEdgeVector.getY() > aEdgeVector.getZ()) - { - // Y is biggest - fParamTestOnCurr = aTestVector.getY() / aEdgeVector.getY(); - } - else - { - // Z is biggest - fParamTestOnCurr = aTestVector.getZ() / aEdgeVector.getZ(); - } - } - - if(fTools::more(fParamTestOnCurr, fZero) && fTools::less(fParamTestOnCurr, fOne)) - { - return true; - } - } - - return false; - } - } - - bool isPointOnPolygon(const B3DPolygon& rCandidate, const B3DPoint& rPoint, bool bWithPoints) - { - const sal_uInt32 nPointCount(rCandidate.count()); - - if(nPointCount > 1L) - { - const sal_uInt32 nLoopCount(rCandidate.isClosed() ? nPointCount : nPointCount - 1L); - B3DPoint aCurrentPoint(rCandidate.getB3DPoint(0)); - - for(sal_uInt32 a(0); a < nLoopCount; a++) - { - const B3DPoint aNextPoint(rCandidate.getB3DPoint((a + 1) % nPointCount)); - - if(isPointOnLine(aCurrentPoint, aNextPoint, rPoint, bWithPoints)) - { - return true; - } - - aCurrentPoint = aNextPoint; - } - } - else if(nPointCount && bWithPoints) - { - return rPoint.equal(rCandidate.getB3DPoint(0)); - } - - return false; - } - - bool getCutBetweenLineAndPlane(const B3DVector& rPlaneNormal, const B3DPoint& rPlanePoint, const B3DPoint& rEdgeStart, const B3DPoint& rEdgeEnd, double& fCut) - { - if(!rPlaneNormal.equalZero() && !rEdgeStart.equal(rEdgeEnd)) - { - const B3DVector aTestEdge(rEdgeEnd - rEdgeStart); - const double fScalarEdge(rPlaneNormal.scalar(aTestEdge)); - - if(!fTools::equalZero(fScalarEdge)) - { - const B3DVector aCompareEdge(rPlanePoint - rEdgeStart); - const double fScalarCompare(rPlaneNormal.scalar(aCompareEdge)); - - fCut = fScalarCompare / fScalarEdge; - return true; - } - } - - return false; - } - - bool getCutBetweenLineAndPolygon(const B3DPolygon& rCandidate, const B3DPoint& rEdgeStart, const B3DPoint& rEdgeEnd, double& fCut) - { - const sal_uInt32 nPointCount(rCandidate.count()); - - if(nPointCount > 2 && !rEdgeStart.equal(rEdgeEnd)) - { - const B3DVector aPlaneNormal(rCandidate.getNormal()); - - if(!aPlaneNormal.equalZero()) - { - const B3DPoint aPointOnPlane(rCandidate.getB3DPoint(0)); - - return getCutBetweenLineAndPlane(aPlaneNormal, aPointOnPlane, rEdgeStart, rEdgeEnd, fCut); - } - } - - return false; - } - - ////////////////////////////////////////////////////////////////////// - // comparators with tolerance for 3D Polygons - - bool equal(const B3DPolygon& rCandidateA, const B3DPolygon& rCandidateB, const double& rfSmallValue) - { - const sal_uInt32 nPointCount(rCandidateA.count()); - - if(nPointCount != rCandidateB.count()) - return false; - - const bool bClosed(rCandidateA.isClosed()); - - if(bClosed != rCandidateB.isClosed()) - return false; - - for(sal_uInt32 a(0); a < nPointCount; a++) - { - const B3DPoint aPoint(rCandidateA.getB3DPoint(a)); - - if(!aPoint.equal(rCandidateB.getB3DPoint(a), rfSmallValue)) - return false; - } - - return true; - } - - bool equal(const B3DPolygon& rCandidateA, const B3DPolygon& rCandidateB) - { - const double fSmallValue(fTools::getSmallValue()); - - return equal(rCandidateA, rCandidateB, fSmallValue); - } - - // snap points of horizontal or vertical edges to discrete values - B3DPolygon snapPointsOfHorizontalOrVerticalEdges(const B3DPolygon& rCandidate) - { - const sal_uInt32 nPointCount(rCandidate.count()); - - if(nPointCount > 1) - { - // Start by copying the source polygon to get a writeable copy. The closed state is - // copied by aRetval's initialisation, too, so no need to copy it in this method - B3DPolygon aRetval(rCandidate); - - // prepare geometry data. Get rounded from original - B3ITuple aPrevTuple(basegfx::fround(rCandidate.getB3DPoint(nPointCount - 1))); - B3DPoint aCurrPoint(rCandidate.getB3DPoint(0)); - B3ITuple aCurrTuple(basegfx::fround(aCurrPoint)); - - // loop over all points. This will also snap the implicit closing edge - // even when not closed, but that's no problem here - for(sal_uInt32 a(0); a < nPointCount; a++) - { - // get next point. Get rounded from original - const bool bLastRun(a + 1 == nPointCount); - const sal_uInt32 nNextIndex(bLastRun ? 0 : a + 1); - const B3DPoint aNextPoint(rCandidate.getB3DPoint(nNextIndex)); - const B3ITuple aNextTuple(basegfx::fround(aNextPoint)); - - // get the states - const bool bPrevVertical(aPrevTuple.getX() == aCurrTuple.getX()); - const bool bNextVertical(aNextTuple.getX() == aCurrTuple.getX()); - const bool bPrevHorizontal(aPrevTuple.getY() == aCurrTuple.getY()); - const bool bNextHorizontal(aNextTuple.getY() == aCurrTuple.getY()); - const bool bSnapX(bPrevVertical || bNextVertical); - const bool bSnapY(bPrevHorizontal || bNextHorizontal); - - if(bSnapX || bSnapY) - { - const B3DPoint aSnappedPoint( - bSnapX ? aCurrTuple.getX() : aCurrPoint.getX(), - bSnapY ? aCurrTuple.getY() : aCurrPoint.getY(), - aCurrPoint.getZ()); - - aRetval.setB3DPoint(a, aSnappedPoint); - } - - // prepare next point - if(!bLastRun) - { - aPrevTuple = aCurrTuple; - aCurrPoint = aNextPoint; - aCurrTuple = aNextTuple; - } - } - - return aRetval; - } - else - { - return rCandidate; - } - } - - } // end of namespace tools -} // end of namespace basegfx - -////////////////////////////////////////////////////////////////////////////// - -// eof - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |