Files
libreoffice/basegfx/source/polygon/b2dpolypolygoncutter.cxx
Rüdiger Timm ba3d8ddffb INTEGRATION: CWS presentationengine01 (1.6.12); FILE MERGED
2004/11/17 18:55:16 thb 1.6.12.2: RESYNC: (1.6-1.7); FILE MERGED
2004/10/04 13:57:31 thb 1.6.12.1: #110496# Removed unused variables (due to gcc -Wall notification)
2004-11-26 17:38:59 +00:00

1039 lines
36 KiB
C++

/*************************************************************************
*
* $RCSfile: b2dpolypolygoncutter.cxx,v $
*
* $Revision: 1.8 $
*
* last change: $Author: rt $ $Date: 2004-11-26 18:38:59 $
*
* The Contents of this file are made available subject to the terms of
* either of the following licenses
*
* - GNU Lesser General Public License Version 2.1
* - Sun Industry Standards Source License Version 1.1
*
* Sun Microsystems Inc., October, 2000
*
* GNU Lesser General Public License Version 2.1
* =============================================
* Copyright 2000 by Sun Microsystems, Inc.
* 901 San Antonio Road, Palo Alto, CA 94303, USA
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1, as published by the Free Software Foundation.
*
* This library 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 for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*
*
* Sun Industry Standards Source License Version 1.1
* =================================================
* The contents of this file are subject to the Sun Industry Standards
* Source License Version 1.1 (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.openoffice.org/license.html.
*
* Software provided under this License is provided on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
* WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
* MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
* See the License for the specific provisions governing your rights and
* obligations concerning the Software.
*
* The Initial Developer of the Original Code is: Sun Microsystems, Inc.
*
* Copyright: 2000 by Sun Microsystems, Inc.
*
* All Rights Reserved.
*
* Contributor(s): _______________________________________
*
*
************************************************************************/
#ifndef _OSL_DIAGNOSE_H_
#include <osl/diagnose.h>
#endif
#ifndef _BGFX_NUMERIC_FTOOLS_HXX
#include <basegfx/numeric/ftools.hxx>
#endif
#ifndef _BGFX_POLYGON_B2DPOLYPOLYGONCUTTER_HXX
#include <basegfx/polygon/b2dpolypolygoncutter.hxx>
#endif
#ifndef _BGFX_NUMERIC_FTOOLS_HXX
#include <basegfx/numeric/ftools.hxx>
#endif
#ifndef _BGFX_POLYGON_B2DPOLYGON_HXX
#include <basegfx/polygon/b2dpolygon.hxx>
#endif
#ifndef _BGFX_POLYGON_B2DPOLYGONTOOLS_HXX
#include <basegfx/polygon/b2dpolygontools.hxx>
#endif
#include <algorithm>
//////////////////////////////////////////////////////////////////////////////
// B2DPolygonNode
namespace basegfx
{
class B2DPolygonNode
{
B2DPoint maPosition;
B2DPolygonNode* mpPrevious;
B2DPolygonNode* mpNext;
B2DPolygonNode* mpListPrevious;
B2DPolygonNode* mpListNext;
public:
B2DPolygonNode(const B2DPoint& rPosition, B2DPolygonNode* pPrevious);
~B2DPolygonNode();
B2DPolygonNode* getPrevious() const { return mpPrevious; }
B2DPolygonNode* getNext() const { return mpNext; }
const B2DPoint& getPosition() const { return maPosition; }
void calcMinMaxX(double& fMaxAX, double& fMinAX) const;
void calcMinMaxY(double& fMaxAY, double& fMinAY) const;
void swapPreviousNext() { B2DPolygonNode* pZwi = mpPrevious; mpPrevious = mpNext; mpNext = pZwi; }
void swapNextPointers(B2DPolygonNode* pCand);
void addToList(B2DPolygonNode*& rpList);
void remFromList(B2DPolygonNode*& rpList);
B2DRange getRange() const;
};
B2DPolygonNode::B2DPolygonNode(const B2DPoint& rPosition, B2DPolygonNode* pPrevious)
: maPosition(rPosition)
{
mpListPrevious = this;
mpListNext = this;
if(pPrevious)
{
mpNext = pPrevious->getNext();
mpPrevious = pPrevious;
mpNext->mpPrevious = this;
mpPrevious->mpNext = this;
}
else
{
mpPrevious = mpNext = this;
}
}
B2DPolygonNode::~B2DPolygonNode()
{
if(mpNext != this)
{
mpPrevious->mpNext = mpNext;
mpNext->mpPrevious = mpPrevious;
}
}
void B2DPolygonNode::calcMinMaxX(double& fMaxAX, double& fMinAX) const
{
if(maPosition.getX() > mpNext->maPosition.getX())
{
fMaxAX = maPosition.getX();
fMinAX = mpNext->maPosition.getX();
}
else
{
fMaxAX = mpNext->maPosition.getX();
fMinAX = maPosition.getX();
}
}
void B2DPolygonNode::calcMinMaxY(double& fMaxAY, double& fMinAY) const
{
if(maPosition.getY() > mpNext->maPosition.getY())
{
fMaxAY = maPosition.getY();
fMinAY = mpNext->maPosition.getY();
}
else
{
fMaxAY = mpNext->maPosition.getY();
fMinAY = maPosition.getY();
}
}
void B2DPolygonNode::swapNextPointers(B2DPolygonNode* pCand)
{
B2DPolygonNode* pTemporary = mpNext;
mpNext = pCand->mpNext;
pCand->mpNext = pTemporary;
mpNext->mpPrevious = this;
pCand->mpNext->mpPrevious = pCand;
}
void B2DPolygonNode::addToList(B2DPolygonNode*& rpList)
{
if(rpList)
{
mpListNext = rpList->mpListNext;
rpList->mpListNext = this;
mpListPrevious = rpList;
mpListNext->mpListPrevious = this;
}
else
{
rpList = this;
}
}
void B2DPolygonNode::remFromList(B2DPolygonNode*& rpList)
{
if(mpListNext != this)
{
if(rpList == this)
{
rpList = mpListPrevious;
}
mpListPrevious->mpListNext = mpListNext;
mpListNext->mpListPrevious = mpListPrevious;
mpListNext = mpListPrevious = this;
}
else
{
if(rpList == this)
{
rpList = 0L;
}
}
}
B2DRange B2DPolygonNode::getRange() const
{
B2DRange aRetval;
const B2DPolygonNode* pCurrent = this;
do {
aRetval.expand(pCurrent->getPosition());
pCurrent = pCurrent->getPrevious();
} while(pCurrent != this);
return aRetval;
}
} // end of namespace basegfx
//////////////////////////////////////////////////////////////////////////////
// B2DSimpleCut
namespace basegfx
{
class B2DSimpleCut
{
B2DPolygonNode* mpLeft;
B2DPolygonNode* mpRight;
public:
B2DSimpleCut(B2DPolygonNode* pL, B2DPolygonNode* pR)
: mpLeft(pL),
mpRight(pR)
{
}
void solve()
{
mpLeft->swapNextPointers(mpRight);
}
B2DPolygonNode* getLeft() const { return mpLeft; }
B2DPolygonNode* getRight() const { return mpRight; }
bool isSameCut(B2DPolygonNode* pA, B2DPolygonNode* pB) const
{
return ((pA == mpLeft && pB == mpRight) || (pB == mpLeft && pA == mpRight));
}
};
} // end of namespace basegfx
//////////////////////////////////////////////////////////////////////////////
// implementation B2DPolyPolygonCutter
namespace basegfx
{
B2DPolyPolygonCutter::~B2DPolyPolygonCutter()
{
for(sal_uInt32 a(0L); a < maPolygonList.size(); a++)
{
delete maPolygonList[a];
}
maPolygonList.clear();
}
//BFS08 void B2DPolyPolygonCutter::removeIncludedPolygons(bool bUseOr)
//BFS08 {
//BFS08 const sal_uInt32 aCount(maPolygonList.size());
//BFS08 B2DClipExtraPolygonInfo* pInfos = new B2DClipExtraPolygonInfo[aCount];
//BFS08 sal_uInt32 a, b;
//BFS08
//BFS08 // fill infos
//BFS08 for(a = 0L; a < aCount; a++)
//BFS08 {
//BFS08 pInfos[a].init(maPolygonList[a]);
//BFS08 }
//BFS08
//BFS08 // get all includes
//BFS08 for(a = 0L; a < aCount; a++)
//BFS08 {
//BFS08 B2DClipExtraPolygonInfo& rInfoA = pInfos[a];
//BFS08
//BFS08 for(b = 0L; b < aCount; b++)
//BFS08 {
//BFS08 B2DClipExtraPolygonInfo& rInfoB = pInfos[b];
//BFS08
//BFS08 if(a != b && doRangesInclude(rInfoA.getRange(), rInfoB.getRange()))
//BFS08 {
//BFS08 // volume B in A, test pA, pB for inclusion, with border
//BFS08 if(maPolygonList[a]->isPolygonInside(maPolygonList[b], true))
//BFS08 {
//BFS08 // pB is inside pA
//BFS08 rInfoB.changeDepth(rInfoA.getOrientation());
//BFS08 }
//BFS08 }
//BFS08 }
//BFS08 }
//BFS08
//BFS08 // delete removable
//BFS08 for(a = 0L, b = 0L; a < aCount; a++)
//BFS08 {
//BFS08 B2DClipExtraPolygonInfo& rInfo = pInfos[a];
//BFS08
//BFS08 if((bUseOr && rInfo.getDepth() != 0L) || (!bUseOr && rInfo.getDepth() < 1L))
//BFS08 {
//BFS08 B2DPolygonNodeVector::iterator aPosition(maPolygonList.begin() + b);
//BFS08 B2DPolygonNode* pCandidate = *aPosition;
//BFS08 maPolygonList.erase(aPosition);
//BFS08 deletePolygon(pCandidate);
//BFS08 }
//BFS08 else
//BFS08 {
//BFS08 b++;
//BFS08 }
//BFS08 }
//BFS08
//BFS08 // delete infos
//BFS08 delete[] pInfos;
//BFS08 }
void B2DPolyPolygonCutter::solveAllCuts(B2DSimpleCutVector& rCuts)
{
B2DPolygonNode* pNewList = 0L;
// add all nodes of polys to list
polysToList(pNewList);
// solve cuts
B2DSimpleCutVector::iterator aCandidate(rCuts.begin());
for(; aCandidate < rCuts.end(); aCandidate++)
{
B2DSimpleCut* pCut = *aCandidate;
pCut->solve();
delete pCut;
}
rCuts.clear();
// extract polys
listToPolys(pNewList);
}
void B2DPolyPolygonCutter::polysToList(B2DPolygonNode*& rpList)
{
B2DPolygonNodeVector::iterator aCandidate(maPolygonList.begin());
for(; aCandidate != maPolygonList.end(); aCandidate++)
{
addAllNodes(*aCandidate, rpList);
}
maPolygonList.clear();
}
void B2DPolyPolygonCutter::listToPolys(B2DPolygonNode*& rpList)
{
while(rpList)
{
// get one
B2DPolygonNode* pNew = extractNextPolygon(rpList);
if(pNew)
{
maPolygonList.push_back(pNew);
}
}
}
B2DPolygonNode* B2DPolyPolygonCutter::createNewPolygon(const B2DPolygon& rPolygon)
{
B2DPolygonNode* pRetval = NULL;
for(sal_uInt32 a(0L); a < rPolygon.count(); a++)
{
B2DPoint aPoint(rPolygon.getB2DPoint(a));
pRetval = new B2DPolygonNode(aPoint, pRetval);
}
return pRetval;
}
void B2DPolyPolygonCutter::deletePolygon(B2DPolygonNode* pCand)
{
B2DPolygonNode* pPoly = pCand;
while(pPoly)
{
B2DPolygonNode* pNext = pPoly->getNext();
if(pNext == pPoly)
{
pNext = 0L;
}
delete pPoly;
pPoly = pNext;
}
}
void B2DPolyPolygonCutter::addAllNodes(B2DPolygonNode* pPolygon, B2DPolygonNode*& rpList)
{
B2DPolygonNode* pAct = pPolygon;
do {
pAct->addToList(rpList);
pAct = pAct->getNext();
} while(pAct != pPolygon);
}
void B2DPolyPolygonCutter::addPolygon(const B2DPolygon& rPolygon)
{
if(rPolygon.isClosed() && rPolygon.count() > 2)
{
B2DPolygonNode* pNew = createNewPolygon(rPolygon);
maPolygonList.push_back(pNew);
}
}
void B2DPolyPolygonCutter::addPolyPolygon(const B2DPolyPolygon& rPolyPolygon)
{
for(sal_uInt32 a(0L); a < rPolyPolygon.count(); a++)
{
B2DPolygon aCandidate = rPolyPolygon.getB2DPolygon(a);
addPolygon(aCandidate);
}
}
B2DPolyPolygon B2DPolyPolygonCutter::getPolyPolygon()
{
B2DPolyPolygon aRetval;
B2DPolygonNodeVector::iterator aCandidate(maPolygonList.begin());
for(; aCandidate < maPolygonList.end(); aCandidate++)
{
B2DPolygonNode* pCand = *aCandidate;
B2DPolygonNode* pAct = pCand;
sal_uInt32 nCount(0L);
do {
nCount++;
pAct = pAct->getNext();
} while(pAct != pCand);
if(nCount > 2L)
{
B2DPolygon aNewPolygon;
do {
aNewPolygon.append(pAct->getPosition());
pAct = pAct->getNext();
} while(pAct != pCand);
aNewPolygon.setClosed(true);
aRetval.append(aNewPolygon);
}
deletePolygon(pCand);
}
maPolygonList.clear();
return aRetval;
}
B2DSimpleCut* B2DPolyPolygonCutter::getExistingCut(B2DSimpleCutVector& rTmpCuts, B2DPolygonNode* pA, B2DPolygonNode* pB)
{
for(sal_uInt32 a(0L); a < rTmpCuts.size(); a++)
{
B2DSimpleCut* pCand = rTmpCuts[a];
if(pCand->isSameCut(pA, pB))
{
return pCand;
}
}
return 0L;
}
B2DPolygonNode* B2DPolyPolygonCutter::extractNextPolygon(B2DPolygonNode*& rpList)
{
B2DPolygonNode* pStart = rpList;
// remove all nodes of this poly from list
B2DPolygonNode* pAct = pStart;
sal_uInt32 nNumNodes(0L);
do {
pAct->remFromList(rpList);
pAct = pAct->getNext();
nNumNodes++;
} while(pAct != pStart);
if(nNumNodes < 3L)
{
deletePolygon(pStart);
return 0L;
}
else
{
return pStart;
}
}
void B2DPolyPolygonCutter::removeSelfIntersections()
{
B2DSimpleCutVector aCuts;
B2DSimpleCutVector aNewCuts;
B2DPolygonNode* pCand;
B2DPolygonNode* pA;
B2DPolygonNode* pB;
double fMaxAX, fMinAX, fMaxAY, fMinAY;
double fMaxBX, fMinBX, fMaxBY, fMinBY;
double fCut;
// first job: Find all cuts and add points there
for(sal_uInt32 a(0L); a < maPolygonList.size(); a++)
{
pCand = maPolygonList[a];
pA = pCand;
// one run to find same start positions (so there is no need to
// search for existing cuts in main loop)
do {
pB = pA->getNext();
do {
if(pA->getPosition().equal(pB->getPosition()))
{
//BFS08 aNewCuts.push_back(new B2DSimpleCut(pA, pB, true, pCand->getOrientation()));
aNewCuts.push_back(new B2DSimpleCut(pA, pB));
}
// next B
pB = pB->getNext();
} while(pB != pCand);
// next A
pA = pA->getNext();
} while(pA->getNext() != pCand);
// second run to find real cuts
pA = pCand;
do {
// get bounds for this edge in poly
pA->calcMinMaxX(fMaxAX, fMinAX);
pA->calcMinMaxY(fMaxAY, fMinAY);
pB = pA->getNext();
do {
pB->calcMinMaxX(fMaxBX, fMinBX);
if(fTools::moreOrEqual(fMaxBX, fMinAX) // #116732#
&& fTools::moreOrEqual(fMaxAX, fMinBX)) // #116732#
{
pB->calcMinMaxY(fMaxBY, fMinBY);
if(fTools::moreOrEqual(fMaxBY, fMinAY) // #116732#
&& fTools::moreOrEqual(fMaxAY, fMinBY)) // #116732#
{
if(!pA->getPosition().equal(pB->getPosition()))
{
const B2DVector aVectorA(pA->getNext()->getPosition() - pA->getPosition());
const B2DVector aVectorB(pB->getNext()->getPosition() - pB->getPosition());
if(tools::findCut(pA->getPosition(), aVectorA, pB->getPosition(), aVectorB, CUTFLAG_LINE, &fCut))
{
// crossover, two new points
B2DPoint aNewPos(interpolate(pA->getPosition(), pA->getNext()->getPosition(), fCut));
B2DPolygonNode* pCutLo = new B2DPolygonNode(aNewPos, pA);
B2DPolygonNode* pCutHi = new B2DPolygonNode(aNewPos, pB);
//BFS08 aNewCuts.push_back(new B2DSimpleCut(pCutLo, pCutHi, true, pCand->getOrientation()));
aNewCuts.push_back(new B2DSimpleCut(pCutLo, pCutHi));
pA->calcMinMaxX(fMaxAX, fMinAX);
pA->calcMinMaxY(fMaxAY, fMinAY);
}
else
{
if(tools::isPointOnEdge(pA->getPosition(), pB->getPosition(), aVectorB, &fCut))
{
// startpoint A at edge B, one new point
B2DPolygonNode* pCutHi = new B2DPolygonNode(pA->getPosition(), pB);
//BFS08 aNewCuts.push_back(new B2DSimpleCut(pA, pCutHi, true, pCand->getOrientation()));
aNewCuts.push_back(new B2DSimpleCut(pA, pCutHi));
}
else if(tools::isPointOnEdge(pB->getPosition(), pA->getPosition(), aVectorA, &fCut))
{
// startpoint B at edge A, one new point
B2DPolygonNode* pCutLo = new B2DPolygonNode(pB->getPosition(), pA);
//BFS08 aNewCuts.push_back(new B2DSimpleCut(pCutLo, pB, true, pCand->getOrientation()));
aNewCuts.push_back(new B2DSimpleCut(pCutLo, pB));
pA->calcMinMaxX(fMaxAX, fMinAX);
pA->calcMinMaxY(fMaxAY, fMinAY);
}
}
}
}
}
// next B
pB = pB->getNext();
} while(pB != pCand);
// next A
pA = pA->getNext();
} while(pA->getNext() != pCand);
// copy new cuts to cuts
aCuts.insert(aCuts.begin(), aNewCuts.begin(), aNewCuts.end());
aNewCuts.clear();
}
// second job: if there were cuts, split polys
if(aCuts.size())
{
solveAllCuts(aCuts);
}
}
bool B2DPolyPolygonCutter::isCrossover(B2DPolygonNode* pA, B2DPolygonNode* pB)
{
// build entering vectors
B2DVector aVecA(pA->getPrevious()->getPosition() - pA->getPosition());
B2DVector aVecB(pB->getPrevious()->getPosition() - pA->getPosition());
aVecA.normalize();
aVecB.normalize();
double fDegreeA2 = atan2(aVecA.getY(), aVecA.getX());
double fDegreeB2 = atan2(aVecB.getY(), aVecB.getX());
// build leaving vectors
aVecA = pA->getNext()->getPosition() - pA->getPosition();
aVecB = pB->getNext()->getPosition() - pA->getPosition();
aVecA.normalize();
aVecB.normalize();
double fDegreeA1 = atan2(aVecA.getY(), aVecA.getX());
double fDegreeB1 = atan2(aVecB.getY(), aVecB.getX());
// compare
if(fDegreeA1 > fDegreeA2)
{
double fTemp = fDegreeA2;
fDegreeA2 = fDegreeA1;
fDegreeA1 = fTemp;
}
bool bB1Inside(fTools::more(fDegreeB1, fDegreeA1)
&& fTools::more(fDegreeA2, fDegreeB1));
bool bB2Inside(fTools::more(fDegreeB2, fDegreeA1)
&& fTools::more(fDegreeA2, fDegreeB2));
if(bB1Inside && bB2Inside)
{
return false;
}
bool bB1Outside(fTools::more(fDegreeA1, fDegreeB1)
|| fTools::more(fDegreeB1, fDegreeA2));
bool bB2Outside(fTools::more(fDegreeA1, fDegreeB2)
|| fTools::more(fDegreeB2, fDegreeA2));
return !(bB1Outside && bB2Outside);
}
bool B2DPolyPolygonCutter::isCrossover(B2DSimpleCut* pEnter, B2DSimpleCut* pLeave)
{
// build entering vectors
B2DVector aVecJ(pEnter->getLeft()->getNext()->getPosition() - pEnter->getLeft()->getPosition());
B2DVector aVecA(pEnter->getLeft()->getPrevious()->getPosition() - pEnter->getLeft()->getPosition());
B2DVector aVecB(pEnter->getRight()->getPrevious()->getPosition() - pEnter->getLeft()->getPosition());
aVecJ.normalize();
aVecA.normalize();
aVecB.normalize();
double fDegreeJo = atan2(aVecJ.getY(), aVecJ.getX());
double fDegreeA2 = atan2(aVecA.getY(), aVecA.getX()) - fDegreeJo;
double fDegreeB2 = atan2(aVecB.getY(), aVecB.getX()) - fDegreeJo;
// move to range [0..2PI[
while(fDegreeA2 < 0.0)
{
fDegreeA2 += (2.0 * F_PI);
}
while(fDegreeA2 >= (2.0 * F_PI))
{
fDegreeA2 -= (2.0 * F_PI);
}
// move to range [0..2PI[
while(fDegreeB2 < 0.0)
{
fDegreeB2 += (2.0 * F_PI);
}
while(fDegreeB2 >= (2.0 * F_PI))
{
fDegreeB2 -= (2.0 * F_PI);
}
bool bA2BiggerB2(fTools::more(fDegreeA2, fDegreeB2));
// build leaving vectors
aVecJ = pLeave->getLeft()->getPrevious()->getPosition() - pLeave->getLeft()->getPosition();
aVecA = pLeave->getLeft()->getNext()->getPosition() - pLeave->getLeft()->getPosition();
aVecB = pLeave->getRight()->getNext()->getPosition() - pLeave->getLeft()->getPosition();
aVecJ.normalize();
aVecA.normalize();
aVecB.normalize();
fDegreeJo = atan2(aVecJ.getY(), aVecJ.getX());
double fDegreeA1 = atan2(aVecA.getY(), aVecA.getX()) - fDegreeJo;
double fDegreeB1 = atan2(aVecB.getY(), aVecB.getX()) - fDegreeJo;
// move to range [0..2PI[
while(fDegreeA1 < 0.0)
{
fDegreeA1 += (2.0 * F_PI);
}
while(fDegreeA1 >= (2.0 * F_PI))
{
fDegreeA1 -= (2.0 * F_PI);
}
// move to range [0..2PI[
while(fDegreeB1 < 0)
{
fDegreeB1 += (2.0 * F_PI);
}
while(fDegreeB1 >= (2.0 * F_PI))
{
fDegreeB1 -= (2.0 * F_PI);
}
bool bA1BiggerB1(fTools::more(fDegreeA1, fDegreeB1));
// compare
return (bA1BiggerB1 == bA2BiggerB2);
}
bool B2DPolyPolygonCutter::isNextSamePos(B2DPolygonNode* pA, B2DPolygonNode* pB)
{
return pA->getNext()->getPosition().equal(pB->getNext()->getPosition());
}
bool B2DPolyPolygonCutter::isPrevSamePos(B2DPolygonNode* pA, B2DPolygonNode* pB)
{
return pA->getPrevious()->getPosition().equal(pB->getPrevious()->getPosition());
}
void B2DPolyPolygonCutter::removeDoubleIntersections()
{
double fMaxAX, fMinAX, fMaxAY, fMinAY;
double fMaxBX, fMinBX, fMaxBY, fMinBY;
double fCut;
B2DSimpleCutVector aCuts;
B2DSimpleCutVector aTmpCuts;
B2DSimpleCutVector aNewCuts;
B2DPolygonNode* pCandA;
B2DPolygonNode* pCandB;
B2DPolygonNode* pA;
B2DPolygonNode* pB;
sal_uInt32 a;
// create volume list for all polys for faster compares
B2DRange* pVolumes = new B2DRange[maPolygonList.size()];
for(a = 0L; a < maPolygonList.size(); a++)
{
pVolumes[a] = maPolygonList[a]->getRange();
}
// register cuts (and add points for them) between pCandA and pCandB
for(a = 0L; a + 1L < maPolygonList.size(); a++)
{
pCandA = maPolygonList[a];
for(sal_uInt32 b = a + 1L; b < maPolygonList.size(); b++)
{
if(pVolumes[a].overlaps(pVolumes[b]))
{
pCandB = maPolygonList[b];
pA = pCandA;
// one run to find same start positions (so there is no need to
// search for existing cuts in main loop)
do {
pB = pCandB;
do {
if(pA->getPosition().equal(pB->getPosition()))
{
aTmpCuts.push_back(new B2DSimpleCut(pA, pB));
}
// next B
pB = pB->getNext();
} while(pB != pCandB);
// next A
pA = pA->getNext();
} while(pA != pCandA);
// second run to find real cuts
pA = pCandA;
do {
// get bounds for this edge in poly
pA->calcMinMaxX(fMaxAX, fMinAX);
pA->calcMinMaxY(fMaxAY, fMinAY);
pB = pCandB;
do {
pB->calcMinMaxX(fMaxBX, fMinBX);
if(fTools::moreOrEqual(fMaxBX, fMinAX) // #116732#
&& fTools::moreOrEqual(fMaxAX, fMinBX)) // #116732#
{
pB->calcMinMaxY(fMaxBY, fMinBY);
if(fTools::moreOrEqual(fMaxBY, fMinAY) // #116732#
&& fTools::moreOrEqual(fMaxAY, fMinBY)) // #116732#
{
if(!pA->getPosition().equal(pB->getPosition()))
{
const B2DVector aVectorA(pA->getNext()->getPosition() - pA->getPosition());
const B2DVector aVectorB(pB->getNext()->getPosition() - pB->getPosition());
if(tools::findCut(pA->getPosition(), aVectorA, pB->getPosition(), aVectorB, CUTFLAG_LINE, &fCut))
{
// crossover, two new points, use as cutpoint
B2DPoint aNewPos(interpolate(pA->getPosition(), pA->getNext()->getPosition(), fCut));
B2DPolygonNode* pCutLo = new B2DPolygonNode(aNewPos, pA);
B2DPolygonNode* pCutHi = new B2DPolygonNode(aNewPos, pB);
aNewCuts.push_back(new B2DSimpleCut(pCutLo, pCutHi));
pA->calcMinMaxX(fMaxAX, fMinAX);
pA->calcMinMaxY(fMaxAY, fMinAY);
}
else
{
if(tools::isPointOnEdge(pA->getPosition(), pB->getPosition(), aVectorB, &fCut))
{
// startpoint A at edge B, one new point
// leaves or enters common section
B2DPolygonNode* pCutHi = new B2DPolygonNode(pA->getPosition(), pB);
aTmpCuts.push_back(new B2DSimpleCut(pA, pCutHi));
}
else if(tools::isPointOnEdge(pB->getPosition(), pA->getPosition(), aVectorA, &fCut))
{
// startpoint B at edge A, one new point
// leaves or enters common section
B2DPolygonNode* pCutLo = new B2DPolygonNode(pB->getPosition(), pA);
aTmpCuts.push_back(new B2DSimpleCut(pCutLo, pB));
pA->calcMinMaxX(fMaxAX, fMinAX);
pA->calcMinMaxY(fMaxAY, fMinAY);
}
}
}
}
}
// next B
pB = pB->getNext();
} while(pB != pCandB);
// next A
pA = pA->getNext();
} while(pA != pCandA);
// test all temporary cuts for simple criteria
for(sal_uInt32 c(0L); c < aTmpCuts.size();)
{
B2DSimpleCut* pCand = aTmpCuts[c];
bool bPrevSamePos(isPrevSamePos(pCand->getLeft(), pCand->getRight()));
bool bNextSamePos(isNextSamePos(pCand->getLeft(), pCand->getRight()));
bool bDelete(false);
bool bIncC(true);
if(bPrevSamePos && bNextSamePos)
{
// single point inside continued same direction section
bDelete = true;
}
else if(!bPrevSamePos && !bNextSamePos)
{
// this is no same direction section, test for real cut
if(isCrossover(pCand->getLeft(), pCand->getRight()))
{
// real cut, move to real cutlist
aNewCuts.push_back(pCand);
aTmpCuts.erase(aTmpCuts.begin() + c);
bIncC = false;
}
else
{
// no cut, just a touch in one point
bDelete = true;
}
}
// delete if wanted
if(bDelete)
{
delete pCand;
aTmpCuts.erase(aTmpCuts.begin() + c);
bIncC = false;
}
// next candidate
if(bIncC)
c++;
}
// are there entering/leaving same direction sections?
while(aTmpCuts.size())
{
// this cuts enter/leave a common same-direction section between
// polygons pCandA, pCandB. If it is a real crossover, a cutpoint
// for it is needed, else it can be ignored.
B2DSimpleCut* pCutA = aTmpCuts[0L];
aTmpCuts.erase(aTmpCuts.begin());
B2DPolygonNode* pActA = pCutA->getLeft();
B2DPolygonNode* pActB = pCutA->getRight();
if(aTmpCuts.size())
{
B2DSimpleCut* pCutB = 0L;
if(isNextSamePos(pCutA->getLeft(), pCutA->getRight()))
{
// this is a start node
B2DPolygonNode* pActA = pCutA->getLeft()->getNext();
B2DPolygonNode* pActB = pCutA->getRight()->getNext();
while(!pCutB && pActA != pCutA->getLeft())
{
if(!isNextSamePos(pActA, pActB))
{
pCutB = getExistingCut(aTmpCuts, pActA, pActB);
}
pActA = pActA->getNext();
pActB = pActB->getNext();
}
if(pCutB)
{
const B2DSimpleCutVector::iterator aFindResult = ::std::find(aTmpCuts.begin(), aTmpCuts.end(), pCutB);
aTmpCuts.erase(aFindResult);
if(isCrossover(pCutA, pCutB))
{
aNewCuts.push_back(pCutB);
}
else
{
delete pCutB;
}
}
}
else
{
// this is a end node
B2DPolygonNode* pActA = pCutA->getLeft()->getPrevious();
B2DPolygonNode* pActB = pCutA->getRight()->getPrevious();
while(!pCutB && pActA != pCutA->getLeft())
{
if(!isPrevSamePos(pActA, pActB))
{
pCutB = getExistingCut(aTmpCuts, pActA, pActB);
}
pActA = pActA->getPrevious();
pActB = pActB->getPrevious();
}
if(pCutB)
{
const B2DSimpleCutVector::iterator aFindResult = ::std::find(aTmpCuts.begin(), aTmpCuts.end(), pCutB);
aTmpCuts.erase(aFindResult);
if(isCrossover(pCutB, pCutA))
{
aNewCuts.push_back(pCutB);
}
else
{
delete pCutB;
}
}
}
}
// delete cut in EVERY case
delete pCutA;
}
// copy new cuts to all cuts
aCuts.insert(aCuts.begin(), aNewCuts.begin(), aNewCuts.end());
aNewCuts.clear();
}
}
}
// delete volume list again
delete[] pVolumes;
// are there cuts to solve? Solve them all in one run
if(aCuts.size())
{
solveAllCuts(aCuts);
}
}
} // end of namespace basegfx
//////////////////////////////////////////////////////////////////////////////
// eof