diff options
Diffstat (limited to 'svx/source/xoutdev/_xpoly.cxx')
-rw-r--r-- | svx/source/xoutdev/_xpoly.cxx | 2138 |
1 files changed, 2138 insertions, 0 deletions
diff --git a/svx/source/xoutdev/_xpoly.cxx b/svx/source/xoutdev/_xpoly.cxx new file mode 100644 index 000000000000..5aa4b205bc88 --- /dev/null +++ b/svx/source/xoutdev/_xpoly.cxx @@ -0,0 +1,2138 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: _xpoly.cxx,v $ + * $Revision: 1.19 $ + * + * 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_svx.hxx" +#include <osl/endian.h> +#include <tools/stream.hxx> +#include <tools/debug.hxx> +#include <tools/poly.hxx> + +#include <svx/xpoly.hxx> +#include "xpolyimp.hxx" +#include <basegfx/polygon/b2dpolygon.hxx> +#include <basegfx/point/b2dpoint.hxx> +#include <basegfx/vector/b2dvector.hxx> +#include <basegfx/polygon/b2dpolygontools.hxx> +#include <vcl/salbtype.hxx> // FRound +#include <basegfx/range/b2drange.hxx> +#include <basegfx/numeric/ftools.hxx> + +#define GLOBALOVERFLOW + +DBG_NAME(XPolygon); +DBG_NAME(XPolyPolygon); + +/************************************************************************* +|* +|* ImpXPolygon::ImpXPolygon() +|* +|* Beschreibung +|* Ersterstellung 08.11.94 +|* Letzte Aenderung 12.01.95 ESO +|* +*************************************************************************/ + +ImpXPolygon::ImpXPolygon( USHORT nInitSize, USHORT _nResize ) +{ + pPointAry = NULL; + pFlagAry = NULL; + bDeleteOldPoints = FALSE; + nSize = 0; + nResize = _nResize; + nPoints = 0; + nRefCount = 1; + + Resize( nInitSize ); +} + +/************************************************************************* +|* +|* ImpXPolygon::ImpXPolygon() +|* +|* Beschreibung +|* Ersterstellung 08.11.94 +|* Letzte Aenderung 12.01.95 ESO +|* +*************************************************************************/ + +ImpXPolygon::ImpXPolygon( const ImpXPolygon& rImpXPoly ) +{ + ( (ImpXPolygon&) rImpXPoly ).CheckPointDelete(); + + pPointAry = NULL; + pFlagAry = NULL; + bDeleteOldPoints = FALSE; + nSize = 0; + ImpXPolygon::nResize = rImpXPoly.nResize; + nPoints = 0; + nRefCount = 1; + + Resize( rImpXPoly.nSize ); + + // Kopieren + nPoints = rImpXPoly.nPoints; + memcpy( pPointAry, rImpXPoly.pPointAry, nSize*sizeof( Point ) ); + memcpy( pFlagAry, rImpXPoly.pFlagAry, nSize ); +} + +/************************************************************************* +|* +|* ImpXPolygon::~ImpXPolygon() +|* +|* Beschreibung +|* Ersterstellung 08.11.94 +|* Letzte Aenderung 12.01.95 ESO +|* +*************************************************************************/ + +ImpXPolygon::~ImpXPolygon() +{ + delete[] (char*) pPointAry; + delete[] pFlagAry; + if ( bDeleteOldPoints ) + delete[] (char*) pOldPointAry; +} + +/************************************************************************* +|* +|* ImpXPolygon::operator==() +|* +|* Ersterstellung Joe 26-09-95 +|* Letzte Aenderung +|* +*************************************************************************/ + + +bool ImpXPolygon::operator==(const ImpXPolygon& rImpXPoly) const +{ + return nPoints==rImpXPoly.nPoints && + (nPoints==0 || + (memcmp(pPointAry,rImpXPoly.pPointAry,nPoints*sizeof(Point))==0 && + memcmp(pFlagAry,rImpXPoly.pFlagAry,nPoints)==0)); +} + +/************************************************************************* +|* +|* ImpXPolygon::Resize() +|* +|* !!! Polygongroesse aendern - wenn bDeletePoints FALSE, dann den +|* Point-Array nicht loeschen, sondern in pOldPointAry sichern und +|* das Flag bDeleteOldPoints setzen. Beim naechsten Zugriff wird +|* das Array dann geloescht. +|* Damit wird verhindert, dass bei XPoly[n] = XPoly[0] durch ein +|* Resize der fuer den rechten Ausdruck verwendete Point-Array +|* vorzeitig geloescht wird. +|* Ersterstellung 08.11.94 +|* Letzte Aenderung 12.01.95 ESO +|* +*************************************************************************/ + +void ImpXPolygon::Resize( USHORT nNewSize, BOOL bDeletePoints ) +{ + if( nNewSize == nSize ) + return; + + BYTE* pOldFlagAry = pFlagAry; + USHORT nOldSize = nSize; + + CheckPointDelete(); + pOldPointAry = pPointAry; + + // Neue Groesse auf vielfaches von nResize runden, sofern Objekt + // nicht neu angelegt wurde (nSize != 0) + if ( nSize != 0 && nNewSize > nSize ) + { + DBG_ASSERT(nResize, "Resize-Versuch trotz nResize = 0 !"); + nNewSize = nSize + ((nNewSize-nSize-1) / nResize + 1) * nResize; + } + // Punkt Array erzeugen + nSize = nNewSize; + pPointAry = (Point*)new char[ nSize*sizeof( Point ) ]; + memset( pPointAry, 0, nSize*sizeof( Point ) ); + + // Flag Array erzeugen + pFlagAry = new BYTE[ nSize ]; + memset( pFlagAry, 0, nSize ); + + // Eventuell umkopieren + if( nOldSize ) + { + if( nOldSize < nSize ) + { + memcpy( pPointAry, pOldPointAry, nOldSize*sizeof( Point ) ); + memcpy( pFlagAry, pOldFlagAry, nOldSize ); + } + else + { + memcpy( pPointAry, pOldPointAry, nSize*sizeof( Point ) ); + memcpy( pFlagAry, pOldFlagAry, nSize ); + + // Anzahl der gueltigen Punkte anpassen + if( nPoints > nSize ) + nPoints = nSize; + } + if ( bDeletePoints ) delete[] (char*) pOldPointAry; + else bDeleteOldPoints = TRUE; + delete[] pOldFlagAry; + } +} + + +/************************************************************************* +|* +|* ImpXPolygon::InsertSpace() +|* +|* Beschreibung +|* Ersterstellung 08.11.94 +|* Letzte Aenderung 29.03.95 ESO +|* +*************************************************************************/ + +void ImpXPolygon::InsertSpace( USHORT nPos, USHORT nCount ) +{ + CheckPointDelete(); + + if ( nPos > nPoints ) + nPos = nPoints; + + // Wenn Polygon zu klein dann groesser machen + if( (nPoints + nCount) > nSize ) + Resize( nPoints + nCount ); + + // Wenn nicht hinter dem letzten Punkt eingefuegt wurde, + // den Rest nach hinten schieben + if( nPos < nPoints ) + { + USHORT nMove = nPoints - nPos; + memmove( &pPointAry[nPos+nCount], &pPointAry[nPos], + nMove * sizeof(Point) ); + memmove( &pFlagAry[nPos+nCount], &pFlagAry[nPos], nMove ); + } + memset( &pPointAry[nPos], 0, nCount * sizeof( Point ) ); + memset( &pFlagAry [nPos], 0, nCount ); + + nPoints = nPoints + nCount; +} + + +/************************************************************************* +|* +|* ImpXPolygon::Remove() +|* +|* Beschreibung +|* Ersterstellung 08.11.94 +|* Letzte Aenderung 12.01.94 ESO +|* +*************************************************************************/ + +void ImpXPolygon::Remove( USHORT nPos, USHORT nCount ) +{ + CheckPointDelete(); + + if( (nPos + nCount) <= nPoints ) + { + USHORT nMove = nPoints - nPos - nCount; + + if( nMove ) + { + memmove( &pPointAry[nPos], &pPointAry[nPos+nCount], + nMove * sizeof(Point) ); + memmove( &pFlagAry[nPos], &pFlagAry[nPos+nCount], nMove ); + } + memset( &pPointAry[nPoints - nCount], 0, nCount * sizeof( Point ) ); + memset( &pFlagAry [nPoints - nCount], 0, nCount ); + nPoints = nPoints - nCount; + } +} + + +/************************************************************************* +|* +|* XPolygon::XPolygon() +|* +|* Beschreibung +|* Ersterstellung 08.11.94 +|* Letzte Aenderung 08.11.94 +|* +*************************************************************************/ + +XPolygon::XPolygon( USHORT nSize, USHORT nResize ) +{ + DBG_CTOR(XPolygon,NULL); + pImpXPolygon = new ImpXPolygon( nSize, nResize ); +} + +/************************************************************************* +|* +|* XPolygon::XPolygon() +|* +|* Beschreibung +|* Ersterstellung 08.11.94 +|* Letzte Aenderung 08.11.94 +|* +*************************************************************************/ + +XPolygon::XPolygon( const XPolygon& rXPoly ) +{ + DBG_CTOR(XPolygon,NULL); + pImpXPolygon = rXPoly.pImpXPolygon; + pImpXPolygon->nRefCount++; +} + +/************************************************************************* +|* +|* XPolygon::XPolygon() +|* +|* XPolygon aus einem Standardpolygon erstellen +|* Ersterstellung 18.01.95 ESO +|* Letzte Aenderung 18.01.95 ESO +|* +*************************************************************************/ + +XPolygon::XPolygon( const Polygon& rPoly ) +{ + DBG_CTOR(XPolygon,NULL); + + USHORT nSize = rPoly.GetSize(); + pImpXPolygon = new ImpXPolygon( nSize ); + pImpXPolygon->nPoints = nSize; + + for( USHORT i = 0; i < nSize; i++ ) + { + pImpXPolygon->pPointAry[i] = rPoly[i]; + pImpXPolygon->pFlagAry[i] = (BYTE) rPoly.GetFlags( i ); + } +} + +/************************************************************************* +|* +|* XPolygon::XPolygon() +|* +|* Rechteck (auch mit abgerundeten Ecken) als Bezierpolygon erzeugen +|* Ersterstellung 09.01.95 ESO +|* Letzte Aenderung 09.01.95 ESO +|* +*************************************************************************/ + +XPolygon::XPolygon(const Rectangle& rRect, long nRx, long nRy) +{ + DBG_CTOR(XPolygon,NULL); + pImpXPolygon = new ImpXPolygon(17); + long nWh = (rRect.GetWidth() - 1) / 2; + long nHh = (rRect.GetHeight() - 1) / 2; + + if ( nRx > nWh ) nRx = nWh; + if ( nRy > nHh ) nRy = nHh; + + // Rx negativ, damit Umlauf im Uhrzeigersinn erfolgt + nRx = -nRx; + + // Faktor fuer Kontrollpunkte der Bezierkurven: 8/3 * (sin(45g) - 0.5) + long nXHdl = (long)(0.552284749 * nRx); + long nYHdl = (long)(0.552284749 * nRy); + USHORT nPos = 0; + + if ( nRx && nRy ) + { + Point aCenter; + + for (USHORT nQuad = 0; nQuad < 4; nQuad++) + { + switch ( nQuad ) + { + case 0: aCenter = rRect.TopLeft(); + aCenter.X() -= nRx; + aCenter.Y() += nRy; + break; + case 1: aCenter = rRect.TopRight(); + aCenter.X() += nRx; + aCenter.Y() += nRy; + break; + case 2: aCenter = rRect.BottomRight(); + aCenter.X() += nRx; + aCenter.Y() -= nRy; + break; + case 3: aCenter = rRect.BottomLeft(); + aCenter.X() -= nRx; + aCenter.Y() -= nRy; + break; + } + GenBezArc(aCenter, nRx, nRy, nXHdl, nYHdl, 0, 900, nQuad, nPos); + pImpXPolygon->pFlagAry[nPos ] = (BYTE) XPOLY_SMOOTH; + pImpXPolygon->pFlagAry[nPos+3] = (BYTE) XPOLY_SMOOTH; + nPos += 4; + } + } + else + { + pImpXPolygon->pPointAry[nPos++] = rRect.TopLeft(); + pImpXPolygon->pPointAry[nPos++] = rRect.TopRight(); + pImpXPolygon->pPointAry[nPos++] = rRect.BottomRight(); + pImpXPolygon->pPointAry[nPos++] = rRect.BottomLeft(); + } + pImpXPolygon->pPointAry[nPos] = pImpXPolygon->pPointAry[0]; + pImpXPolygon->nPoints = nPos + 1; +} + +/************************************************************************* +|* +|* XPolygon::XPolygon() +|* +|* Ellipsen(bogen) als Bezierpolygon erzeugen +|* Ersterstellung 09.01.95 +|* Letzte Aenderung 09.01.95 +|* +*************************************************************************/ + +XPolygon::XPolygon(const Point& rCenter, long nRx, long nRy, + USHORT nStartAngle, USHORT nEndAngle, BOOL bClose) +{ + DBG_CTOR(XPolygon,NULL); + pImpXPolygon = new ImpXPolygon(17); + + nStartAngle %= 3600; + if ( nEndAngle > 3600 ) nEndAngle %= 3600; + BOOL bFull = (nStartAngle == 0 && nEndAngle == 3600); + + // Faktor fuer Kontrollpunkte der Bezierkurven: 8/3 * (sin(45g) - 0.5) + long nXHdl = (long)(0.552284749 * nRx); + long nYHdl = (long)(0.552284749 * nRy); + USHORT nPos = 0; + BOOL bLoopEnd = FALSE; + + do + { + USHORT nA1, nA2; + USHORT nQuad = nStartAngle / 900; + if ( nQuad == 4 ) nQuad = 0; + bLoopEnd = CheckAngles(nStartAngle, nEndAngle, nA1, nA2); + GenBezArc(rCenter, nRx, nRy, nXHdl, nYHdl, nA1, nA2, nQuad, nPos); + nPos += 3; + if ( !bLoopEnd ) + pImpXPolygon->pFlagAry[nPos] = (BYTE) XPOLY_SMOOTH; + + } while ( !bLoopEnd ); + + // Wenn kein Vollkreis, dann ggf. Enden mit Mittelpunkt verbinden + if ( !bFull && bClose ) + pImpXPolygon->pPointAry[++nPos] = rCenter; + + if ( bFull ) + { + pImpXPolygon->pFlagAry[0 ] = (BYTE) XPOLY_SMOOTH; + pImpXPolygon->pFlagAry[nPos] = (BYTE) XPOLY_SMOOTH; + } + pImpXPolygon->nPoints = nPos + 1; +} + +/************************************************************************* +|* +|* XPolygon::~XPolygon() +|* +|* Beschreibung +|* Ersterstellung 08.11.94 +|* Letzte Aenderung 08.11.94 +|* +*************************************************************************/ + +XPolygon::~XPolygon() +{ + DBG_DTOR(XPolygon,NULL); + if( pImpXPolygon->nRefCount > 1 ) + pImpXPolygon->nRefCount--; + else + delete pImpXPolygon; +} + +/************************************************************************* +|* +|* XPolygon::CheckReference() +|* +|* Referenzzaehler desImpXPoly pruefen und ggf. von diesem abkoppeln +|* Ersterstellung 17.01.95 ESO +|* Letzte Aenderung 17.01.95 ESO +|* +*************************************************************************/ + +void XPolygon::CheckReference() +{ + if( pImpXPolygon->nRefCount > 1 ) + { + pImpXPolygon->nRefCount--; + pImpXPolygon = new ImpXPolygon( *pImpXPolygon ); + } +} + +/************************************************************************* +|* +|* XPolygon::SetSize() +|* +|* Beschreibung +|* Ersterstellung 08.11.94 +|* Letzte Aenderung 08.11.94 +|* +*************************************************************************/ + +void XPolygon::SetSize( USHORT nNewSize ) +{ + CheckReference(); + pImpXPolygon->Resize( nNewSize ); +} + +/************************************************************************* +|* +|* XPolygon::GetSize() +|* +|* Beschreibung +|* Ersterstellung 08.11.94 +|* Letzte Aenderung 12.01.95 ESO +|* +*************************************************************************/ + +USHORT XPolygon::GetSize() const +{ + pImpXPolygon->CheckPointDelete(); + return pImpXPolygon->nSize; +} + +/************************************************************************* +|* +|* XPolygon::SetPointCount() +|* +|* Beschreibung +|* Ersterstellung 08.11.94 +|* Letzte Aenderung 12.01.95 ESO +|* +*************************************************************************/ + +void XPolygon::SetPointCount( USHORT nPoints ) +{ + pImpXPolygon->CheckPointDelete(); + CheckReference(); + + if( pImpXPolygon->nSize < nPoints ) + pImpXPolygon->Resize( nPoints ); + + if ( nPoints < pImpXPolygon->nPoints ) + { + USHORT nSize = pImpXPolygon->nPoints - nPoints; + memset( &pImpXPolygon->pPointAry[nPoints], 0, nSize * sizeof( Point ) ); + memset( &pImpXPolygon->pFlagAry [nPoints], 0, nSize ); + } + pImpXPolygon->nPoints = nPoints; +} + +/************************************************************************* +|* +|* XPolygon::GetPointCount() +|* +|* Beschreibung +|* Ersterstellung 08.11.94 +|* Letzte Aenderung 12.01.95 ESO +|* +*************************************************************************/ + +USHORT XPolygon::GetPointCount() const +{ + pImpXPolygon->CheckPointDelete(); + return pImpXPolygon->nPoints; +} + +/************************************************************************* +|* +|* XPolygon::Insert() +|* +|* Beschreibung +|* Ersterstellung 08.11.94 +|* Letzte Aenderung 08.11.94 +|* +*************************************************************************/ + +void XPolygon::Insert( USHORT nPos, const Point& rPt, XPolyFlags eFlags ) +{ + CheckReference(); + if (nPos>pImpXPolygon->nPoints) nPos=pImpXPolygon->nPoints; + pImpXPolygon->InsertSpace( nPos, 1 ); + pImpXPolygon->pPointAry[nPos] = rPt; + pImpXPolygon->pFlagAry[nPos] = (BYTE)eFlags; +} + +/************************************************************************* +|* +|* XPolygon::Insert() +|* +|* Beschreibung +|* Ersterstellung 08.11.94 +|* Letzte Aenderung 08.11.94 +|* +*************************************************************************/ + +void XPolygon::Insert( USHORT nPos, const XPolygon& rXPoly ) +{ + CheckReference(); + if (nPos>pImpXPolygon->nPoints) nPos=pImpXPolygon->nPoints; + + USHORT nPoints = rXPoly.GetPointCount(); + + pImpXPolygon->InsertSpace( nPos, nPoints ); + + memcpy( &(pImpXPolygon->pPointAry[nPos]), + rXPoly.pImpXPolygon->pPointAry, + nPoints*sizeof( Point ) ); + memcpy( &(pImpXPolygon->pFlagAry[nPos]), + rXPoly.pImpXPolygon->pFlagAry, + nPoints ); +} + +/************************************************************************* +|* +|* XPolygon::Insert() +|* +|* Beschreibung +|* Ersterstellung 08.11.94 +|* Letzte Aenderung 08.11.94 +|* +*************************************************************************/ + +void XPolygon::Insert( USHORT nPos, const Polygon& rPoly ) +{ + CheckReference(); + if (nPos>pImpXPolygon->nPoints) nPos=pImpXPolygon->nPoints; + + USHORT nPoints = rPoly.GetSize(); + + pImpXPolygon->InsertSpace( nPos, nPoints ); + + USHORT i; + for( i=0; i < nPoints; i++ ) + pImpXPolygon->pPointAry[i] = rPoly[i]; + + // Die Flags sind durch das InsertSpace bereits auf 0 gesetzt +} + +/************************************************************************* +|* +|* XPolygon::Remove() +|* +|* Beschreibung +|* Ersterstellung 08.11.94 +|* Letzte Aenderung 08.11.94 +|* +*************************************************************************/ + +void XPolygon::Remove( USHORT nPos, USHORT nCount ) +{ + CheckReference(); + pImpXPolygon->Remove( nPos, nCount ); +} + +/************************************************************************* +|* +|* XPolygon::Move() +|* +|* Beschreibung +|* Ersterstellung 09.11.94 +|* Letzte Aenderung 09.11.94 +|* +*************************************************************************/ + +void XPolygon::Move( long nHorzMove, long nVertMove ) +{ + if ( !nHorzMove && !nVertMove ) + return; + + CheckReference(); + + // Punkte verschieben + USHORT nCount = pImpXPolygon->nPoints; + for ( USHORT i = 0; i < nCount; i++ ) + { + Point* pPt = &(pImpXPolygon->pPointAry[i]); + pPt->X() += nHorzMove; + pPt->Y() += nVertMove; + } +} + +/************************************************************************* +|* +|* XPolygon::GetBoundRect() +|* +|* Beschreibung +|* Ersterstellung 09.11.94 +|* Letzte Aenderung 12.01.95 ESO +|* +*************************************************************************/ + +Rectangle XPolygon::GetBoundRect() const +{ + pImpXPolygon->CheckPointDelete(); + Rectangle aRetval; + + if(pImpXPolygon->nPoints) + { + // #i37709# + // For historical reasons the control points are not part of the + // BoundRect. This makes it necessary to subdivide the polygon to + // get a relatively correct BoundRect. Numerically, this is not + // correct and never was. + + const basegfx::B2DRange aPolygonRange(basegfx::tools::getRange(getB2DPolygon())); + aRetval = Rectangle( + FRound(aPolygonRange.getMinX()), FRound(aPolygonRange.getMinY()), + FRound(aPolygonRange.getMaxX()), FRound(aPolygonRange.getMaxY())); + } + + return aRetval; +} + +/************************************************************************* +|* +|* XPolygon::operator[]() +|* +|* Beschreibung +|* Ersterstellung 08.11.94 +|* Letzte Aenderung 12.01.95 +|* +*************************************************************************/ + +const Point& XPolygon::operator[]( USHORT nPos ) const +{ + DBG_ASSERT(nPos < pImpXPolygon->nPoints, "Ungueltiger Index bei const-Arrayzugriff auf XPolygon"); + + pImpXPolygon->CheckPointDelete(); + return pImpXPolygon->pPointAry[nPos]; +} + +/************************************************************************* +|* +|* XPolygon::operator[]() +|* +|* Beschreibung +|* Ersterstellung 08.11.94 +|* Letzte Aenderung 12.01.95 ESO +|* +*************************************************************************/ + +Point& XPolygon::operator[]( USHORT nPos ) +{ + pImpXPolygon->CheckPointDelete(); + CheckReference(); + + if( nPos >= pImpXPolygon->nSize ) + { + DBG_ASSERT(pImpXPolygon->nResize, "Ungueltiger Index bei Arrayzugriff auf XPolygon"); + pImpXPolygon->Resize(nPos + 1, FALSE); + } + if( nPos >= pImpXPolygon->nPoints ) + pImpXPolygon->nPoints = nPos + 1; + + return pImpXPolygon->pPointAry[nPos]; +} + +/************************************************************************* +|* +|* XPolygon::operator=() +|* +|* Beschreibung Zuweisungsoperator +|* Ersterstellung ESO 22.11.94 +|* Letzte Aenderung ESO 12.01.95 +|* +*************************************************************************/ + +XPolygon& XPolygon::operator=( const XPolygon& rXPoly ) +{ + pImpXPolygon->CheckPointDelete(); + + rXPoly.pImpXPolygon->nRefCount++; + + if( pImpXPolygon->nRefCount > 1 ) + pImpXPolygon->nRefCount--; + else + delete pImpXPolygon; + + pImpXPolygon = rXPoly.pImpXPolygon; + return *this; +} + +/************************************************************************* +|* +|* XPolygon::operator==() +|* +|* Beschreibung Gleichheitsoperator +|* Ersterstellung ESO 22.11.94 +|* Letzte Aenderung Joe 26.09.95 +|* +*************************************************************************/ + +BOOL XPolygon::operator==( const XPolygon& rXPoly ) const +{ + pImpXPolygon->CheckPointDelete(); + if (rXPoly.pImpXPolygon==pImpXPolygon) return TRUE; + return *rXPoly.pImpXPolygon == *pImpXPolygon; +} + +/************************************************************************* +|* +|* XPolygon::operator!=() +|* +|* Beschreibung Ungleichheitsoperator +|* Ersterstellung ESO 22.11.94 +|* Letzte Aenderung Joe 26.09.95 +|* +*************************************************************************/ + +BOOL XPolygon::operator!=( const XPolygon& rXPoly ) const +{ + pImpXPolygon->CheckPointDelete(); + if (rXPoly.pImpXPolygon==pImpXPolygon) return FALSE; + return *rXPoly.pImpXPolygon != *pImpXPolygon; +} + +/************************************************************************* +|* +|* XPolygon::GetFlags() +|* +|* Flags fuer den Punkt an der Position nPos zurueckgeben +|* Ersterstellung ESO 11.11.94 +|* Letzte Aenderung ESO 12.01.95 +|* +*************************************************************************/ + +XPolyFlags XPolygon::GetFlags( USHORT nPos ) const +{ + pImpXPolygon->CheckPointDelete(); + return (XPolyFlags) pImpXPolygon->pFlagAry[nPos]; +} + +/************************************************************************* +|* +|* XPolygon::SetFlags() +|* +|* Flags fuer den Punkt an der Position nPos setzen +|* Ersterstellung ESO 11.11.94 +|* Letzte Aenderung ESO 12.01.95 +|* +*************************************************************************/ + +void XPolygon::SetFlags( USHORT nPos, XPolyFlags eFlags ) +{ + pImpXPolygon->CheckPointDelete(); + CheckReference(); + pImpXPolygon->pFlagAry[nPos] = (BYTE) eFlags; +} + +/************************************************************************* +|* +|* XPolygon::IsControl() +|* +|* Kurzform zur Abfrage des CONTROL-Flags +|* Ersterstellung ESO 09.01.95 +|* Letzte Aenderung ESO 12.01.95 +|* +*************************************************************************/ + +BOOL XPolygon::IsControl(USHORT nPos) const +{ + return ( (XPolyFlags) pImpXPolygon->pFlagAry[nPos] == XPOLY_CONTROL ); +} + +/************************************************************************* +|* +|* XPolygon::IsSmooth() +|* +|* Kurzform zur Abfrage von SMOOTH- und SYMMTR-Flag +|* Ersterstellung ESO 18.04.95 +|* Letzte Aenderung ESO 18.04.95 +|* +*************************************************************************/ + +BOOL XPolygon::IsSmooth(USHORT nPos) const +{ + XPolyFlags eFlag = (XPolyFlags) pImpXPolygon->pFlagAry[nPos]; + return ( eFlag == XPOLY_SMOOTH || eFlag == XPOLY_SYMMTR ); +} + +/************************************************************************* +|* +|* XPolygon::CalcDistance() +|* +|* Abstand zwischen zwei Punkten berechnen +|* Ersterstellung ESO 09.01.95 +|* Letzte Aenderung ESO 09.01.95 +|* +*************************************************************************/ + +double XPolygon::CalcDistance(USHORT nP1, USHORT nP2) +{ + const Point& rP1 = pImpXPolygon->pPointAry[nP1]; + const Point& rP2 = pImpXPolygon->pPointAry[nP2]; + double fDx = rP2.X() - rP1.X(); + double fDy = rP2.Y() - rP1.Y(); + return sqrt(fDx * fDx + fDy * fDy); +} + +/************************************************************************* +|* +|* XPolygon::SubdivideBezier() +|* +|* Bezierkurve unterteilen +|* Ersterstellung ESO 09.01.95 +|* Letzte Aenderung ESO 09.01.95 +|* +*************************************************************************/ + +void XPolygon::SubdivideBezier(USHORT nPos, BOOL bCalcFirst, double fT) +{ + Point* pPoints = pImpXPolygon->pPointAry; + double fT2 = fT * fT; + double fT3 = fT * fT2; + double fU = 1.0 - fT; + double fU2 = fU * fU; + double fU3 = fU * fU2; + USHORT nIdx = nPos; + short nPosInc, nIdxInc; + + if ( bCalcFirst ) + { + nPos += 3; + nPosInc = -1; + nIdxInc = 0; + } + else + { + nPosInc = 1; + nIdxInc = 1; + } + pPoints[nPos].X() = (long) (fU3 * pPoints[nIdx ].X() + + fT * fU2 * pPoints[nIdx+1].X() * 3 + + fT2 * fU * pPoints[nIdx+2].X() * 3 + + fT3 * pPoints[nIdx+3].X()); + pPoints[nPos].Y() = (long) (fU3 * pPoints[nIdx ].Y() + + fT * fU2 * pPoints[nIdx+1].Y() * 3 + + fT2 * fU * pPoints[nIdx+2].Y() * 3 + + fT3 * pPoints[nIdx+3].Y()); + nPos = nPos + nPosInc; + nIdx = nIdx + nIdxInc; + pPoints[nPos].X() = (long) (fU2 * pPoints[nIdx ].X() + + fT * fU * pPoints[nIdx+1].X() * 2 + + fT2 * pPoints[nIdx+2].X()); + pPoints[nPos].Y() = (long) (fU2 * pPoints[nIdx ].Y() + + fT * fU * pPoints[nIdx+1].Y() * 2 + + fT2 * pPoints[nIdx+2].Y()); + nPos = nPos + nPosInc; + nIdx = nIdx + nIdxInc; + pPoints[nPos].X() = (long) (fU * pPoints[nIdx ].X() + + fT * pPoints[nIdx+1].X()); + pPoints[nPos].Y() = (long) (fU * pPoints[nIdx ].Y() + + fT * pPoints[nIdx+1].Y()); +} + +/************************************************************************/ + +void XPolygon::GenBezArc(const Point& rCenter, long nRx, long nRy, + long nXHdl, long nYHdl, USHORT nStart, USHORT nEnd, + USHORT nQuad, USHORT nFirst) +{ + Point* pPoints = pImpXPolygon->pPointAry; + pPoints[nFirst ] = rCenter; + pPoints[nFirst+3] = rCenter; + + if ( nQuad == 1 || nQuad == 2 ) + { + nRx = -nRx; nXHdl = -nXHdl; + } + if ( nQuad == 0 || nQuad == 1 ) + { + nRy = -nRy; nYHdl = -nYHdl; + } + + if ( nQuad == 0 || nQuad == 2 ) + { + pPoints[nFirst].X() += nRx; pPoints[nFirst+3].Y() += nRy; + } + else + { + pPoints[nFirst].Y() += nRy; pPoints[nFirst+3].X() += nRx; + } + pPoints[nFirst+1] = pPoints[nFirst]; + pPoints[nFirst+2] = pPoints[nFirst+3]; + + if ( nQuad == 0 || nQuad == 2 ) + { + pPoints[nFirst+1].Y() += nYHdl; pPoints[nFirst+2].X() += nXHdl; + } + else + { + pPoints[nFirst+1].X() += nXHdl; pPoints[nFirst+2].Y() += nYHdl; + } + if ( nStart > 0 ) + SubdivideBezier(nFirst, FALSE, (double)nStart / 900); + if ( nEnd < 900 ) + SubdivideBezier(nFirst, TRUE, (double)(nEnd-nStart) / (900-nStart)); + SetFlags(nFirst+1, XPOLY_CONTROL); + SetFlags(nFirst+2, XPOLY_CONTROL); +} + +/************************************************************************/ + +BOOL XPolygon::CheckAngles(USHORT& nStart, USHORT nEnd, USHORT& nA1, USHORT& nA2) +{ + if ( nStart == 3600 ) nStart = 0; + if ( nEnd == 0 ) nEnd = 3600; + USHORT nStPrev = nStart; + USHORT nMax = (nStart / 900 + 1) * 900; + USHORT nMin = nMax - 900; + + if ( nEnd >= nMax || nEnd <= nStart ) nA2 = 900; + else nA2 = nEnd - nMin; + nA1 = nStart - nMin; + nStart = nMax; + + // TRUE zurueck, falls letztes Segment berechnet wurde + return (nStPrev < nEnd && nStart >= nEnd); +} + +/************************************************************************* +|* +|* XPolygon::CalcSmoothJoin() +|* +|* glatten Uebergang zu einer Bezierkurve berechnen, indem der +|* entsprechende Punkt auf die Verbindungslinie von zwei anderen +|* Punkten projiziert wird +|* Center = End- bzw. Anfangspunkt der Bezierkurve +|* Drag = der bewegte Punkt, der die Verschiebung von Pnt vorgibt +|* Pnt = der zu modifizierende Punkt +|* Wenn Center am Anfang bzw. Ende des Polygons liegt, wird Pnt +|* auf die entgegengesetzte Seite verlegt +|* Ersterstellung ESO 09.01.95 +|* Letzte Aenderung ESO 18.04.95 +|* +\************************************************************************/ + +void XPolygon::CalcSmoothJoin(USHORT nCenter, USHORT nDrag, USHORT nPnt) +{ + CheckReference(); + +// USHORT nMaxPnt = pImpXPolygon->nPoints - 1; + +// if ( nCenter == nMaxPnt ) nPnt = 1; +// else if ( nCenter == 0 ) nPnt = nMaxPnt - 1; + + // Wenn nPnt kein Control-Punkt, d.h. nicht verschiebbar, dann + // statt dessen nDrag auf der Achse nCenter-nPnt verschieben + if ( !IsControl(nPnt) ) + { + USHORT nTmp = nDrag; + nDrag = nPnt; + nPnt = nTmp; + } + Point* pPoints = pImpXPolygon->pPointAry; + Point aDiff = pPoints[nDrag] - pPoints[nCenter]; + double fDiv = CalcDistance(nCenter, nDrag); + + if ( fDiv ) + { + double fRatio = CalcDistance(nCenter, nPnt) / fDiv; + // bei SMOOTH bisherige Laenge beibehalten + if ( GetFlags(nCenter) == XPOLY_SMOOTH || !IsControl(nDrag) ) + { + aDiff.X() = (long) (fRatio * aDiff.X()); + aDiff.Y() = (long) (fRatio * aDiff.Y()); + } + pPoints[nPnt] = pPoints[nCenter] - aDiff; + } +} + +/************************************************************************* +|* +|* XPolygon::CalcTangent() +|* +|* Tangente fuer den Uebergang zwischen zwei Bezierkurven berechnen +|* Center = End- bzw. Anfangspunkt der Bezierkurven +|* Prev = vorheriger Zugpunkt +|* Next = naechster Zugpunkt +|* Ersterstellung ESO 09.01.95 +|* Letzte Aenderung ESO 18.04.95 +|* +\************************************************************************/ + +void XPolygon::CalcTangent(USHORT nCenter, USHORT nPrev, USHORT nNext) +{ + CheckReference(); + + double fAbsLen = CalcDistance(nNext, nPrev); + + if ( fAbsLen ) + { + const Point& rCenter = pImpXPolygon->pPointAry[nCenter]; + Point& rNext = pImpXPolygon->pPointAry[nNext]; + Point& rPrev = pImpXPolygon->pPointAry[nPrev]; + Point aDiff = rNext - rPrev; + double fNextLen = CalcDistance(nCenter, nNext) / fAbsLen; + double fPrevLen = CalcDistance(nCenter, nPrev) / fAbsLen; + + // bei SYMMTR gleiche Laenge fuer beide Seiten + if ( GetFlags(nCenter) == XPOLY_SYMMTR ) + { + fPrevLen = (fNextLen + fPrevLen) / 2; + fNextLen = fPrevLen; + } + rNext.X() = rCenter.X() + (long) (fNextLen * aDiff.X()); + rNext.Y() = rCenter.Y() + (long) (fNextLen * aDiff.Y()); + rPrev.X() = rCenter.X() - (long) (fPrevLen * aDiff.X()); + rPrev.Y() = rCenter.Y() - (long) (fPrevLen * aDiff.Y()); + } +} + +/************************************************************************* +|* +|* XPolygon::PointsToBezier() +|* +|* wandelt vier Polygonpunkte in eine Bezierkurve durch diese Punkte um +|* Ersterstellung ESO 09.01.95 +|* Letzte Aenderung ESO 09.01.95 +|* +\************************************************************************/ + +void XPolygon::PointsToBezier(USHORT nFirst) +{ + double nFullLength, nPart1Length, nPart2Length; + double fX0, fY0, fX1, fY1, fX2, fY2, fX3, fY3; + double fTx1, fTx2, fTy1, fTy2; + double fT1, fU1, fT2, fU2, fV; + Point* pPoints = pImpXPolygon->pPointAry; + + if ( nFirst > pImpXPolygon->nPoints - 4 || IsControl(nFirst) || + IsControl(nFirst+1) || IsControl(nFirst+2) || IsControl(nFirst+3) ) + return; + + CheckReference(); + + fTx1 = pPoints[nFirst+1].X(); + fTy1 = pPoints[nFirst+1].Y(); + fTx2 = pPoints[nFirst+2].X(); + fTy2 = pPoints[nFirst+2].Y(); + fX0 = pPoints[nFirst ].X(); + fY0 = pPoints[nFirst ].Y(); + fX3 = pPoints[nFirst+3].X(); + fY3 = pPoints[nFirst+3].Y(); + + nPart1Length = CalcDistance(nFirst, nFirst+1); + nPart2Length = nPart1Length + CalcDistance(nFirst+1, nFirst+2); + nFullLength = nPart2Length + CalcDistance(nFirst+2, nFirst+3); + if ( nFullLength < 20 ) + return; + + if ( nPart2Length == nFullLength ) + nPart2Length -= 1; + if ( nPart1Length == nFullLength ) + nPart1Length = nPart2Length - 1; + if ( nPart1Length <= 0 ) + nPart1Length = 1; + if ( nPart2Length <= 0 || nPart2Length == nPart1Length ) + nPart2Length = nPart1Length + 1; + + fT1 = nPart1Length / nFullLength; + fU1 = 1.0 - fT1; + fT2 = nPart2Length / nFullLength; + fU2 = 1.0 - fT2; + fV = 3 * (1.0 - (fT1 * fU2) / (fT2 * fU1)); + + fX1 = fTx1 / (fT1 * fU1 * fU1) - fTx2 * fT1 / (fT2 * fT2 * fU1 * fU2); + fX1 /= fV; + fX1 -= fX0 * ( fU1 / fT1 + fU2 / fT2) / 3; + fX1 += fX3 * ( fT1 * fT2 / (fU1 * fU2)) / 3; + + fY1 = fTy1 / (fT1 * fU1 * fU1) - fTy2 * fT1 / (fT2 * fT2 * fU1 * fU2); + fY1 /= fV; + fY1 -= fY0 * ( fU1 / fT1 + fU2 / fT2) / 3; + fY1 += fY3 * ( fT1 * fT2 / (fU1 * fU2)) / 3; + + fX2 = fTx2 / (fT2 * fT2 * fU2 * 3) - fX0 * fU2 * fU2 / ( fT2 * fT2 * 3); + fX2 -= fX1 * fU2 / fT2; + fX2 -= fX3 * fT2 / (fU2 * 3); + + fY2 = fTy2 / (fT2 * fT2 * fU2 * 3) - fY0 * fU2 * fU2 / ( fT2 * fT2 * 3); + fY2 -= fY1 * fU2 / fT2; + fY2 -= fY3 * fT2 / (fU2 * 3); + + pPoints[nFirst+1] = Point((long) fX1, (long) fY1); + pPoints[nFirst+2] = Point((long) fX2, (long) fY2); + SetFlags(nFirst+1, XPOLY_CONTROL); + SetFlags(nFirst+2, XPOLY_CONTROL); +} + +/************************************************************************* +|* +|* XPolygon::Translate() +|* +|* Polygon auf den uebergebenen Punkt verschieben +|* Ersterstellung ESO 17.01.95 +|* Letzte Aenderung ESO 17.01.95 +|* +*************************************************************************/ + +void XPolygon::Translate(const Point& rTrans) +{ + pImpXPolygon->CheckPointDelete(); + CheckReference(); + + USHORT nPntCnt = pImpXPolygon->nPoints; + + for (USHORT i = 0; i < nPntCnt; i++) + pImpXPolygon->pPointAry[i] += rTrans; +} + +/************************************************************************* +|* +|* XPolygon::Rotate() +|* +|* Alle Punkte um den Punkt rCenter drehen, Sinus und Cosinus +|* muessen uebergeben werden +|* Ersterstellung ESO 09.01.95 +|* Letzte Aenderung ESO 17.01.95 +|* +*************************************************************************/ + +void XPolygon::Rotate(const Point& rCenter, double fSin, double fCos) +{ + pImpXPolygon->CheckPointDelete(); + CheckReference(); + + long nX; + long nY; + long nNewX; + long nNewY; + long nCenterX = rCenter.X(); + long nCenterY = rCenter.Y(); + + USHORT nPntCnt = pImpXPolygon->nPoints; + + for (USHORT i = 0; i < nPntCnt; i++) + { + Point *pPt = &(pImpXPolygon->pPointAry[i]); + nX = pPt->X()-nCenterX; + nY = pPt->Y()-nCenterY; + nNewX = (long)floor(fCos * nX + fSin * nY + 0.5); + nNewY = -(long)floor(fSin * nX - fCos * nY + 0.5); + pPt->X() = nNewX + nCenterX; + pPt->Y() = nNewY + nCenterY; + + /* und so stand das in einem anderen File auf T: + dass ich am 29-11-1995 gegettet habe. Joe M. + USHORT nPntCnt = pImpXPolygon->nPoints; + + for (USHORT i = 0; i < nPntCnt; i++) + { + Point P = pImpXPolygon->pPointAry[i] - rCenter; + long X = P.X(); + long Y = P.Y(); + P.X() = (long)floor(fCos * X + fSin * Y + 0.5); + P.Y() = -(long)floor(fSin * X - fCos * Y + 0.5); + pImpXPolygon->pPointAry[i] = P + rCenter; + */ + } +} + +/************************************************************************* +|* +|* XPolygon::Rotate() +|* +|* Alle Punkte um den Punkt rCenter mit dem Winkel nAngle drehen +|* Winkel in 10tel Grad, Wertebereich 0 - 3600 +|* Ersterstellung ESO 17.01.95 +|* Letzte Aenderung ESO 17.01.95 +|* +*************************************************************************/ + +void XPolygon::Rotate(const Point& rCenter, USHORT nAngle) +{ + nAngle %= 3600; + + if ( nAngle != 0 ) + { + double fAngle = F_PI * nAngle / 1800; + double fSin = sin(fAngle); + double fCos = cos(fAngle); + Rotate(rCenter, fSin, fCos); + } +} + +/************************************************************************* +|* +|* XPolygon::Scale() +|* +|* XPolygon in X- und/oder Y-Richtung skalieren +|* Ersterstellung ESO 01.02.95 +|* Letzte Aenderung ESO 01.02.95 +|* +*************************************************************************/ + +void XPolygon::Scale(double fSx, double fSy) +{ + pImpXPolygon->CheckPointDelete(); + CheckReference(); + + USHORT nPntCnt = pImpXPolygon->nPoints; + + for (USHORT i = 0; i < nPntCnt; i++) + { + Point& rPnt = pImpXPolygon->pPointAry[i]; + rPnt.X() = (long)(fSx * rPnt.X()); + rPnt.Y() = (long)(fSy * rPnt.Y()); + } +} + +/************************************************************************* +|* +|* XPolygon::SlantX() +|* +|* XPolygon in X-Richtung um einen beliebigen Winkel kippen, +|* bezogen auf eine Referenz-Y-Koordinate +|* Ersterstellung ESO 01.02.95 +|* Letzte Aenderung ESO 01.02.95 +|* +*************************************************************************/ + +void XPolygon::SlantX(long nYRef, double fSin, double fCos) +{ + pImpXPolygon->CheckPointDelete(); + CheckReference(); + + USHORT nPntCnt = pImpXPolygon->nPoints; + + for (USHORT i = 0; i < nPntCnt; i++) + { + Point& rPnt = pImpXPolygon->pPointAry[i]; + long nDy = rPnt.Y() - nYRef; + rPnt.X() += (long)(fSin * nDy); + rPnt.Y() = nYRef + (long)(fCos * nDy); + } +} + +/************************************************************************* +|* +|* XPolygon::SlantY() +|* +|* XPolygon in Y-Richtung um einen beliebigen Winkel kippen, +|* bezogen auf eine Referenz-X-Koordinate +|* Ersterstellung ESO 01.02.95 +|* Letzte Aenderung ESO 01.02.95 +|* +*************************************************************************/ + +void XPolygon::SlantY(long nXRef, double fSin, double fCos) +{ + pImpXPolygon->CheckPointDelete(); + CheckReference(); + + USHORT nPntCnt = pImpXPolygon->nPoints; + + for (USHORT i = 0; i < nPntCnt; i++) + { + Point& rPnt = pImpXPolygon->pPointAry[i]; + long nDx = rPnt.X() - nXRef; + rPnt.X() = nXRef + (long)(fCos * nDx); + rPnt.Y() -= (long)(fSin * nDx); + } +} + +/************************************************************************* +|* +|* XPolygon::Distort() +|* +|* XPolygon verzerren, indem die Koordinaten relativ zu einem +|* Referenzrechteck in ein beliebiges Viereck skaliert werden +|* Zuordnung der Viereck-Punkte im Polygon zum Referenzrechteck: +|* 0: links oben 0----1 +|* 1: rechts oben | | +|* 2: rechts unten 3----2 +|* 3: links unten +|* Ersterstellung ESO 07.07.95 +|* Letzte Aenderung ESO 07.07.95 +|* +*************************************************************************/ + +void XPolygon::Distort(const Rectangle& rRefRect, + const XPolygon& rDistortedRect) +{ + pImpXPolygon->CheckPointDelete(); + CheckReference(); + + long Xr, Wr, X1, X2, X3, X4; + long Yr, Hr, Y1, Y2, Y3, Y4; + double fTx, fTy, fUx, fUy; + + Xr = rRefRect.Left(); + Yr = rRefRect.Top(); + Wr = rRefRect.GetWidth(); + Hr = rRefRect.GetHeight(); + + if ( Wr && Hr ) + { + DBG_ASSERT(rDistortedRect.pImpXPolygon->nPoints >= 4, + "Distort-Rechteck zu klein"); + + X1 = rDistortedRect[0].X(); + Y1 = rDistortedRect[0].Y(); + X2 = rDistortedRect[1].X(); + Y2 = rDistortedRect[1].Y(); + X3 = rDistortedRect[3].X(); + Y3 = rDistortedRect[3].Y(); + X4 = rDistortedRect[2].X(); + Y4 = rDistortedRect[2].Y(); + + USHORT nPntCnt = pImpXPolygon->nPoints; + + for (USHORT i = 0; i < nPntCnt; i++) + { + Point& rPnt = pImpXPolygon->pPointAry[i]; + + fTx = (double)(rPnt.X() - Xr) / Wr; + fTy = (double)(rPnt.Y() - Yr) / Hr; + fUx = 1.0 - fTx; + fUy = 1.0 - fTy; + + rPnt.X() = (long) ( fUy * (fUx * X1 + fTx * X2) + + fTy * (fUx * X3 + fTx * X4) ); + rPnt.Y() = (long) ( fUx * (fUy * Y1 + fTy * Y3) + + fTx * (fUy * Y2 + fTy * Y4) ); + } + } +} + +/************************************************************************* +|* +|* Bestimme den linken, unteren Punkt des Polygons und richte das +|* Polygon so aus, dass dieser Punkt auf dem Index 0 liegt +|* +\************************************************************************/ + +void XPolygon::Rotate20() +{ + pImpXPolygon->CheckPointDelete(); + CheckReference(); + + double fMinY = pImpXPolygon->pPointAry->Y(); + double fMinX = pImpXPolygon->pPointAry->X(); + long nPntCnt = pImpXPolygon->nPoints; + long nIndex0 = 0; + + for (long nPoints = 1; + nPoints < nPntCnt; + nPoints ++) + { + Point &rPnt = pImpXPolygon->pPointAry[nPoints]; + + if ((rPnt.X () < fMinX) || (fMinX == rPnt.X ()) && + (fMinY >= rPnt.Y ())) + { + fMinX = rPnt.X (); + fMinY = rPnt.Y (); + nIndex0 = nPoints; + } + } + + if (nIndex0 < nPntCnt) + { + Point *pTemp = new Point [nIndex0]; + memcpy (pTemp, pImpXPolygon->pPointAry, nIndex0 * sizeof (Point)); + memcpy (pImpXPolygon->pPointAry, &pImpXPolygon->pPointAry [nIndex0], (nPntCnt - nIndex0) * sizeof (Point)); + memcpy (&pImpXPolygon->pPointAry [nIndex0], pTemp, nIndex0 * sizeof (Point)); + delete[] pTemp; + } +} + +basegfx::B2DPolygon XPolygon::getB2DPolygon() const +{ + // #i74631# use tools Polygon class for conversion to not have the code doubled + // here. This needs one more conversion but avoids different convertors in + // the long run + DBG_ASSERT(pImpXPolygon != 0, "XPolygon::getB2DPolygon(): XPolygon has no implementation incarnated (!)"); + const Polygon aSource(GetPointCount(), pImpXPolygon->pPointAry, pImpXPolygon->pFlagAry); + + return aSource.getB2DPolygon(); +} + +XPolygon::XPolygon(const basegfx::B2DPolygon& rPolygon) +{ + // #i74631# use tools Polygon class for conversion to not have the code doubled + // here. This needs one more conversion but avoids different convertors in + // the long run + DBG_CTOR(XPolygon,NULL); + + const Polygon aSource(rPolygon); + USHORT nSize = aSource.GetSize(); + pImpXPolygon = new ImpXPolygon( nSize ); + pImpXPolygon->nPoints = nSize; + + for( USHORT i = 0; i < nSize; i++ ) + { + pImpXPolygon->pPointAry[i] = aSource[i]; + pImpXPolygon->pFlagAry[i] = (BYTE) aSource.GetFlags( i ); + } +} + +//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +//+--------------- XPolyPolygon -----------------------------------------+ +//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +/************************************************************************* +|* +|* ImpXPolyPolygon::ImpXPolyPolygon() +|* +|* Beschreibung Erzeugt das XPolygon-Array +|* Ersterstellung CL 09.11.94 +|* Letzte Aenderung MM 09.11.94 +|* +*************************************************************************/ + +ImpXPolyPolygon::ImpXPolyPolygon( const ImpXPolyPolygon& rImpXPolyPoly ) : + aXPolyList( rImpXPolyPoly.aXPolyList ) +{ + nRefCount = 1; + + // Einzelne Elemente duplizieren + XPolygon* pXPoly = aXPolyList.First(); + while ( pXPoly ) + { + aXPolyList.Replace( new XPolygon( *(aXPolyList.GetCurObject()) ) ); + pXPoly = aXPolyList.Next(); + } +} + + +/************************************************************************* +|* +|* ImpXPolyPolygon::~ImpXPolyPolygon() +|* +|* Beschreibung Loescht das Polygon-Array +|* Ersterstellung CL 09.06.93 +|* Letzte Aenderung CL 09.06.93 +|* +*************************************************************************/ + +ImpXPolyPolygon::~ImpXPolyPolygon() +{ + XPolygon* pXPoly = aXPolyList.First(); + while( pXPoly ) + { + delete pXPoly; + pXPoly = aXPolyList.Next(); + } +} + +/************************************************************************* +|* +|* ImpXPolyPolygon::operator==() +|* +|* Ersterstellung Joe 26-09-95 +|* Letzte Aenderung +|* +*************************************************************************/ + + +bool ImpXPolyPolygon::operator==(const ImpXPolyPolygon& rImpXPolyPoly) const +{ + USHORT nAnz=(USHORT)aXPolyList.Count(); + const XPolygonList& rCmpList=rImpXPolyPoly.aXPolyList; + if (nAnz!=(USHORT)rCmpList.Count()) return FALSE; + bool bEq=true; + for (USHORT i=nAnz; i>0 && bEq;) { + i--; + bEq= *aXPolyList.GetObject(i) == *rCmpList.GetObject(i); + } + return bEq; +} + +/************************************************************************* +|* +|* XPolyPolygon::XPolyPolygon() +|* +|* Beschreibung POLY.SDW +|* Ersterstellung CL 27.01.93 +|* Letzte Aenderung CL 27.01.93 +|* +*************************************************************************/ + +XPolyPolygon::XPolyPolygon( USHORT nInitSize, USHORT nResize ) +{ + DBG_CTOR(XPolyPolygon,NULL); + pImpXPolyPolygon = new ImpXPolyPolygon( nInitSize, nResize ); +} + + +/************************************************************************* +|* +|* XPolyPolygon::XPolyPolygon() +|* +|* Beschreibung POLY.SDW +|* Ersterstellung CL 27.01.93 +|* Letzte Aenderung CL 27.01.93 +|* +*************************************************************************/ + +XPolyPolygon::XPolyPolygon( const XPolygon& rXPoly ) +{ + DBG_CTOR(XPolyPolygon,NULL); + pImpXPolyPolygon = new ImpXPolyPolygon; + pImpXPolyPolygon->aXPolyList.Insert( new XPolygon( rXPoly ) ); +} + +/************************************************************************* +|* +|* XPolyPolygon::XPolyPolygon() +|* +|* Beschreibung POLY.SDW +|* Ersterstellung CL 27.01.93 +|* Letzte Aenderung CL 27.01.93 +|* +*************************************************************************/ + +XPolyPolygon::XPolyPolygon( const XPolyPolygon& rXPolyPoly ) +{ + DBG_CTOR(XPolyPolygon,NULL); + pImpXPolyPolygon = rXPolyPoly.pImpXPolyPolygon; + pImpXPolyPolygon->nRefCount++; +} + +/************************************************************************* +|* +|* XPolyPolygon::XPolyPolygon() +|* +|* XPolyPolygon aus einen Standard-PolyPolygon erzeugen +|* Ersterstellung 18.01.95 ESO +|* Letzte Aenderung 18.01.95 ESO +|* +*************************************************************************/ + +XPolyPolygon::XPolyPolygon( const PolyPolygon& rPolyPoly ) +{ + DBG_CTOR(XPolyPolygon,NULL); + pImpXPolyPolygon = new ImpXPolyPolygon; + + for (USHORT i = 0; i < rPolyPoly.Count(); i++) + pImpXPolyPolygon->aXPolyList.Insert( + new XPolygon(rPolyPoly.GetObject(i)) ); +} + +/************************************************************************* +|* +|* XPolyPolygon::~XPolyPolygon() +|* +|* Beschreibung POLY.SDW +|* Ersterstellung CL 27.01.93 +|* Letzte Aenderung CL 27.01.93 +|* +*************************************************************************/ + +XPolyPolygon::~XPolyPolygon() +{ + DBG_DTOR(XPolyPolygon,NULL); + if( pImpXPolyPolygon->nRefCount > 1 ) + pImpXPolyPolygon->nRefCount--; + else + delete pImpXPolyPolygon; +} + +/************************************************************************* +|* +|* XPolygon::CheckReference() +|* +|* Referenzzaehler desImpXPolyPoly pruefen und ggf. von diesem abkoppeln +|* Ersterstellung 18.01.95 ESO +|* Letzte Aenderung 18.01.95 ESO +|* +*************************************************************************/ + +void XPolyPolygon::CheckReference() +{ + if( pImpXPolyPolygon->nRefCount > 1 ) + { + pImpXPolyPolygon->nRefCount--; + pImpXPolyPolygon = new ImpXPolyPolygon( *pImpXPolyPolygon ); + } +} + +/************************************************************************* +|* +|* XPolyPolygon::Insert() +|* +|* Beschreibung POLY.SDW +|* Ersterstellung CL 27.01.93 +|* Letzte Aenderung CL 27.01.93 +|* +*************************************************************************/ + +void XPolyPolygon::Insert( const XPolygon& rXPoly, USHORT nPos ) +{ + CheckReference(); + XPolygon* pXPoly = new XPolygon( rXPoly ); + pImpXPolyPolygon->aXPolyList.Insert( pXPoly, nPos ); +} + +/************************************************************************* +|* +|* XPolyPolygon::Insert() +|* +|* saemtliche XPolygone aus einem XPolyPolygon einfuegen +|* Ersterstellung 18.01.95 ESO +|* Letzte Aenderung 18.01.95 ESO +|* +*************************************************************************/ + +void XPolyPolygon::Insert( const XPolyPolygon& rXPolyPoly, USHORT nPos ) +{ + CheckReference(); + + for (USHORT i = 0; i < rXPolyPoly.Count(); i++) + { + XPolygon* pXPoly = new XPolygon(rXPolyPoly[i]); + pImpXPolyPolygon->aXPolyList.Insert(pXPoly, nPos); + if ( nPos != XPOLYPOLY_APPEND ) + nPos++; + } +} + +/************************************************************************* +|* +|* XPolyPolygon::Remove() +|* +|* Beschreibung POLY.SDW +|* Ersterstellung CL 27.01.93 +|* Letzte Aenderung CL 27.01.93 +|* +*************************************************************************/ + +XPolygon XPolyPolygon::Remove( USHORT nPos ) +{ + CheckReference(); + XPolygon* pTmpXPoly = pImpXPolyPolygon->aXPolyList.Remove( nPos ); + XPolygon aXPoly( *pTmpXPoly ); + delete pTmpXPoly; + return aXPoly; +} + + +/************************************************************************* +|* +|* XPolyPolygon::Replace() +|* +|* Beschreibung POLY.SDW +|* Ersterstellung CL 27.01.93 +|* Letzte Aenderung CL 27.01.93 +|* +*************************************************************************/ + +XPolygon XPolyPolygon::Replace( const XPolygon& rXPoly, USHORT nPos ) +{ + CheckReference(); + XPolygon* pXPoly = new XPolygon( rXPoly ); + XPolygon* pTmpXPoly = pImpXPolyPolygon->aXPolyList.Replace( pXPoly, nPos ); + XPolygon aXPoly( *pTmpXPoly ); + delete pTmpXPoly; + return aXPoly; +} + + +/************************************************************************* +|* +|* XPolyPolygon::GetObject() +|* +|* Beschreibung POLY.SDW +|* Ersterstellung CL 27.01.93 +|* Letzte Aenderung CL 27.01.93 +|* +*************************************************************************/ + +const XPolygon& XPolyPolygon::GetObject( USHORT nPos ) const +{ + return *(pImpXPolyPolygon->aXPolyList.GetObject( nPos )); +} + + +/************************************************************************* +|* +|* XPolyPolygon::Clear() +|* +|* Beschreibung POLY.SDW +|* Ersterstellung CL 27.01.93 +|* Letzte Aenderung TH 17.10.94 +|* +*************************************************************************/ + +void XPolyPolygon::Clear() +{ + if ( pImpXPolyPolygon->nRefCount > 1 ) + { + pImpXPolyPolygon->nRefCount--; + pImpXPolyPolygon = new ImpXPolyPolygon(); + } + else + { + XPolygon* pXPoly = pImpXPolyPolygon->aXPolyList.First(); + while( pXPoly ) + { + delete pXPoly; + pXPoly = pImpXPolyPolygon->aXPolyList.Next(); + } + pImpXPolyPolygon->aXPolyList.Clear(); + } +} + + +/************************************************************************* +|* +|* XPolyPolygon::Count() +|* +|* Beschreibung +|* Ersterstellung CL 27.01.93 +|* Letzte Aenderung CL 27.01.93 +|* +*************************************************************************/ + +USHORT XPolyPolygon::Count() const +{ + return (USHORT)(pImpXPolyPolygon->aXPolyList.Count()); +} + + +/************************************************************************* +|* +|* XPolyPolygon::Move() +|* +|* Beschreibung POLY.SDW +|* Ersterstellung TH 04.10.94 +|* Letzte Aenderung TH 04.10.94 +|* +*************************************************************************/ + +void XPolyPolygon::Move( long nHorzMove, long nVertMove ) +{ + // Diese Abfrage sollte man fuer die DrawEngine durchfuehren + if ( !nHorzMove && !nVertMove ) + return; + + // Referenzcounter beruecksichtigen + CheckReference(); + + // Punkte verschieben + XPolygon* pXPoly = pImpXPolyPolygon->aXPolyList.First(); + while( pXPoly ) + { + pXPoly->Move( nHorzMove, nVertMove ); + pXPoly = pImpXPolyPolygon->aXPolyList.Next(); + } +} + +/************************************************************************* +|* +|* XPolyPolygon::GetBoundRect() +|* +|* Beschreibung POLY.SDW +|* Ersterstellung TH 04.10.94 +|* Letzte Aenderung TH 04.10.94 +|* +*************************************************************************/ + +Rectangle XPolyPolygon::GetBoundRect() const +{ + USHORT nXPoly = (USHORT)pImpXPolyPolygon->aXPolyList.Count(); + Rectangle aRect; + + for ( USHORT n = 0; n < nXPoly; n++ ) + { + const XPolygon* pXPoly = pImpXPolyPolygon->aXPolyList.GetObject( n ); + aRect.Union( pXPoly->GetBoundRect() ); + } + + return aRect; +} + + +/************************************************************************* +|* +|* XPolyPolygon::operator[]() +|* +|* Beschreibung POLY.SDW +|* Ersterstellung TH 28.10.94 +|* Letzte Aenderung TH 28.10.94 +|* +*************************************************************************/ + +XPolygon& XPolyPolygon::operator[]( USHORT nPos ) +{ + CheckReference(); + return *(pImpXPolyPolygon->aXPolyList.GetObject( nPos )); +} + +/************************************************************************* +|* +|* XPolyPolygon::operator=() +|* +|* Beschreibung POLY.SDW +|* Ersterstellung CL 27.01.93 +|* Letzte Aenderung CL 27.01.93 +|* +*************************************************************************/ + +XPolyPolygon& XPolyPolygon::operator=( const XPolyPolygon& rXPolyPoly ) +{ + rXPolyPoly.pImpXPolyPolygon->nRefCount++; + + if( pImpXPolyPolygon->nRefCount > 1 ) + pImpXPolyPolygon->nRefCount--; + else + delete pImpXPolyPolygon; + + pImpXPolyPolygon = rXPolyPoly.pImpXPolyPolygon; + return *this; +} + + +/************************************************************************* +|* +|* XPolyPolygon::operator==() +|* +|* Beschreibung POLY.SDW +|* Ersterstellung CL 27.01.93 +|* Letzte Aenderung Joe 27.01.93 +|* +*************************************************************************/ + +BOOL XPolyPolygon::operator==( const XPolyPolygon& rXPolyPoly ) const +{ + if (pImpXPolyPolygon==rXPolyPoly.pImpXPolyPolygon) return TRUE; + return *pImpXPolyPolygon == *rXPolyPoly.pImpXPolyPolygon; +} + + +/************************************************************************* +|* +|* XPolyPolygon::operator!=() +|* +|* Beschreibung POLY.SDW +|* Ersterstellung CL 27.01.93 +|* Letzte Aenderung Joe 27.01.93 +|* +*************************************************************************/ + +BOOL XPolyPolygon::operator!=( const XPolyPolygon& rXPolyPoly ) const +{ + if (pImpXPolyPolygon==rXPolyPoly.pImpXPolyPolygon) return FALSE; + return *pImpXPolyPolygon != *rXPolyPoly.pImpXPolyPolygon; +} + +/************************************************************************* +|* +|* XPolyPolygon::Translate() +|* +|* Alle Polygone auf den uebergebenen Punkt verschieben +|* Ersterstellung ESO 25.01.95 +|* Letzte Aenderung ESO 25.01.95 +|* +*************************************************************************/ + +void XPolyPolygon::Translate(const Point& rTrans) +{ + CheckReference(); + + for (USHORT i = 0; i < Count(); i++) + pImpXPolyPolygon->aXPolyList.GetObject(i)->Translate(rTrans); +} + +/************************************************************************* +|* +|* XPolyPolygon::Rotate() +|* +|* Alle Polygone um den Punkt rCenter drehen, Sinus und Cosinus +|* muessen uebergeben werden +|* Ersterstellung ESO 25.01.95 +|* Letzte Aenderung ESO 25.01.95 +|* +*************************************************************************/ + +void XPolyPolygon::Rotate(const Point& rCenter, double fSin, double fCos) +{ + CheckReference(); + + for (USHORT i = 0; i < Count(); i++) + pImpXPolyPolygon->aXPolyList.GetObject(i)->Rotate(rCenter, fSin, fCos); +} + +/************************************************************************* +|* +|* Bestimme den linken, unteren Punkt des Polygons und richte das +|* Polygon so aus, dass dieser Punkt auf dem Index 0 liegt +|* +\************************************************************************/ + +void XPolyPolygon::Rotate20() +{ + CheckReference(); + + for (USHORT i = 0; i < Count(); i++) + pImpXPolyPolygon->aXPolyList.GetObject(i)->Rotate20(); +} + +/************************************************************************* +|* +|* XPolyPolygon::Rotate() +|* +|* Alle Poylgone um den Punkt rCenter mit dem Winkel nAngle drehen +|* Winkel in 10tel Grad, Wertebereich 0 - 3600 +|* Ersterstellung ESO 25.01.95 +|* Letzte Aenderung ESO 25.01.95 +|* +*************************************************************************/ + +void XPolyPolygon::Rotate(const Point& rCenter, USHORT nAngle) +{ + nAngle %= 3600; + + if ( nAngle != 0 ) + { + double fAngle = F_PI * nAngle / 1800; + double fSin = sin(fAngle); + double fCos = cos(fAngle); + Rotate(rCenter, fSin, fCos); + } +} + +/************************************************************************* +|* +|* XPolyPolygon::Scale() +|* +|* Alle Polygone in X- und/oder Y-Richtung skalieren +|* Ersterstellung ESO 01.02.95 +|* Letzte Aenderung ESO 01.02.95 +|* +*************************************************************************/ + +void XPolyPolygon::Scale(double fSx, double fSy) +{ + CheckReference(); + + for (USHORT i = 0; i < Count(); i++) + pImpXPolyPolygon->aXPolyList.GetObject(i)->Scale(fSx, fSy); +} + +/************************************************************************* +|* +|* XPolyPolygon::SlantX() +|* +|* Alle Polygone in X-Richtung um einen beliebigen Winkel kippen, +|* bezogen auf eine Referenz-Y-Koordinate +|* Ersterstellung ESO 01.02.95 +|* Letzte Aenderung ESO 01.02.95 +|* +*************************************************************************/ + +void XPolyPolygon::SlantX(long nYRef, double fSin, double fCos) +{ + CheckReference(); + + for (USHORT i = 0; i < Count(); i++) + pImpXPolyPolygon->aXPolyList.GetObject(i)->SlantX(nYRef, fSin, fCos); +} + +/************************************************************************* +|* +|* XPolyPolygon::SlantY() +|* +|* Alle Polygone in Y-Richtung um einen beliebigen Winkel kippen, +|* bezogen auf eine Referenz-X-Koordinate +|* Ersterstellung ESO 01.02.95 +|* Letzte Aenderung ESO 01.02.95 +|* +*************************************************************************/ + +void XPolyPolygon::SlantY(long nXRef, double fSin, double fCos) +{ + CheckReference(); + + for (USHORT i = 0; i < Count(); i++) + pImpXPolyPolygon->aXPolyList.GetObject(i)->SlantY(nXRef, fSin, fCos); +} + +/************************************************************************* +|* +|* XPolygon::Distort() +|* +|* XPolygon verzerren, indem die Koordinaten relativ zu einem +|* Referenzrechteck in ein beliebiges Viereck skaliert werden +|* Zuordnung der Viereck-Punkte im Polygon zum Referenzrechteck: +|* 0: links oben 0----1 +|* 1: rechts oben | | +|* 2: rechts unten 3----2 +|* 3: links unten +|* Ersterstellung ESO 07.07.95 +|* Letzte Aenderung ESO 07.07.95 +|* +*************************************************************************/ + +void XPolyPolygon::Distort(const Rectangle& rRefRect, + const XPolygon& rDistortedRect) +{ + CheckReference(); + + for (USHORT i = 0; i < Count(); i++) + pImpXPolyPolygon->aXPolyList.GetObject(i)->Distort(rRefRect, + rDistortedRect); +} + +basegfx::B2DPolyPolygon XPolyPolygon::getB2DPolyPolygon() const +{ + basegfx::B2DPolyPolygon aRetval; + + for(sal_uInt16 a(0L); a < Count(); a++) + { + const XPolygon& rPoly = (*this)[a]; + aRetval.append(rPoly.getB2DPolygon()); + } + + return aRetval; +} + +XPolyPolygon::XPolyPolygon(const basegfx::B2DPolyPolygon& rPolyPolygon) +{ + DBG_CTOR(XPolyPolygon,NULL); + pImpXPolyPolygon = new ImpXPolyPolygon( 16, 16 ); + + for(sal_uInt32 a(0L); a < rPolyPolygon.count(); a++) + { + basegfx::B2DPolygon aCandidate = rPolyPolygon.getB2DPolygon(a); + XPolygon aNewPoly(aCandidate); + Insert(aNewPoly); + } +} + +// eof |