blob: f3a08997b38e313f84ccb2ac5b2123300de1dcca [file] [log] [blame]
/**************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the 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( sal_uInt16 nInitSize, sal_uInt16 _nResize )
{
pPointAry = NULL;
pFlagAry = NULL;
bDeleteOldPoints = sal_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 = sal_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 sal_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( sal_uInt16 nNewSize, sal_Bool bDeletePoints )
{
if( nNewSize == nSize )
return;
sal_uInt8* pOldFlagAry = pFlagAry;
sal_uInt16 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 sal_uInt8[ 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 = sal_True;
delete[] pOldFlagAry;
}
}
/*************************************************************************
|*
|* ImpXPolygon::InsertSpace()
|*
|* Beschreibung
|* Ersterstellung 08.11.94
|* Letzte Aenderung 29.03.95 ESO
|*
*************************************************************************/
void ImpXPolygon::InsertSpace( sal_uInt16 nPos, sal_uInt16 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 )
{
sal_uInt16 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( sal_uInt16 nPos, sal_uInt16 nCount )
{
CheckPointDelete();
if( (nPos + nCount) <= nPoints )
{
sal_uInt16 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( sal_uInt16 nSize, sal_uInt16 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);
sal_uInt16 nSize = rPoly.GetSize();
pImpXPolygon = new ImpXPolygon( nSize );
pImpXPolygon->nPoints = nSize;
for( sal_uInt16 i = 0; i < nSize; i++ )
{
pImpXPolygon->pPointAry[i] = rPoly[i];
pImpXPolygon->pFlagAry[i] = (sal_uInt8) 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);
sal_uInt16 nPos = 0;
if ( nRx && nRy )
{
Point aCenter;
for (sal_uInt16 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 ] = (sal_uInt8) XPOLY_SMOOTH;
pImpXPolygon->pFlagAry[nPos+3] = (sal_uInt8) 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,
sal_uInt16 nStartAngle, sal_uInt16 nEndAngle, sal_Bool bClose)
{
DBG_CTOR(XPolygon,NULL);
pImpXPolygon = new ImpXPolygon(17);
nStartAngle %= 3600;
if ( nEndAngle > 3600 ) nEndAngle %= 3600;
sal_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);
sal_uInt16 nPos = 0;
sal_Bool bLoopEnd = sal_False;
do
{
sal_uInt16 nA1, nA2;
sal_uInt16 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] = (sal_uInt8) 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 ] = (sal_uInt8) XPOLY_SMOOTH;
pImpXPolygon->pFlagAry[nPos] = (sal_uInt8) 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( sal_uInt16 nNewSize )
{
CheckReference();
pImpXPolygon->Resize( nNewSize );
}
/*************************************************************************
|*
|* XPolygon::GetSize()
|*
|* Beschreibung
|* Ersterstellung 08.11.94
|* Letzte Aenderung 12.01.95 ESO
|*
*************************************************************************/
sal_uInt16 XPolygon::GetSize() const
{
pImpXPolygon->CheckPointDelete();
return pImpXPolygon->nSize;
}
/*************************************************************************
|*
|* XPolygon::SetPointCount()
|*
|* Beschreibung
|* Ersterstellung 08.11.94
|* Letzte Aenderung 12.01.95 ESO
|*
*************************************************************************/
void XPolygon::SetPointCount( sal_uInt16 nPoints )
{
pImpXPolygon->CheckPointDelete();
CheckReference();
if( pImpXPolygon->nSize < nPoints )
pImpXPolygon->Resize( nPoints );
if ( nPoints < pImpXPolygon->nPoints )
{
sal_uInt16 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
|*
*************************************************************************/
sal_uInt16 XPolygon::GetPointCount() const
{
pImpXPolygon->CheckPointDelete();
return pImpXPolygon->nPoints;
}
/*************************************************************************
|*
|* XPolygon::Insert()
|*
|* Beschreibung
|* Ersterstellung 08.11.94
|* Letzte Aenderung 08.11.94
|*
*************************************************************************/
void XPolygon::Insert( sal_uInt16 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] = (sal_uInt8)eFlags;
}
/*************************************************************************
|*
|* XPolygon::Insert()
|*
|* Beschreibung
|* Ersterstellung 08.11.94
|* Letzte Aenderung 08.11.94
|*
*************************************************************************/
void XPolygon::Insert( sal_uInt16 nPos, const XPolygon& rXPoly )
{
CheckReference();
if (nPos>pImpXPolygon->nPoints) nPos=pImpXPolygon->nPoints;
sal_uInt16 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( sal_uInt16 nPos, const Polygon& rPoly )
{
CheckReference();
if (nPos>pImpXPolygon->nPoints) nPos=pImpXPolygon->nPoints;
sal_uInt16 nPoints = rPoly.GetSize();
pImpXPolygon->InsertSpace( nPos, nPoints );
sal_uInt16 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( sal_uInt16 nPos, sal_uInt16 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
sal_uInt16 nCount = pImpXPolygon->nPoints;
for ( sal_uInt16 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[]( sal_uInt16 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[]( sal_uInt16 nPos )
{
pImpXPolygon->CheckPointDelete();
CheckReference();
if( nPos >= pImpXPolygon->nSize )
{
DBG_ASSERT(pImpXPolygon->nResize, "Ungueltiger Index bei Arrayzugriff auf XPolygon");
pImpXPolygon->Resize(nPos + 1, sal_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
|*
*************************************************************************/
sal_Bool XPolygon::operator==( const XPolygon& rXPoly ) const
{
pImpXPolygon->CheckPointDelete();
if (rXPoly.pImpXPolygon==pImpXPolygon) return sal_True;
return *rXPoly.pImpXPolygon == *pImpXPolygon;
}
/*************************************************************************
|*
|* XPolygon::operator!=()
|*
|* Beschreibung Ungleichheitsoperator
|* Ersterstellung ESO 22.11.94
|* Letzte Aenderung Joe 26.09.95
|*
*************************************************************************/
sal_Bool XPolygon::operator!=( const XPolygon& rXPoly ) const
{
pImpXPolygon->CheckPointDelete();
if (rXPoly.pImpXPolygon==pImpXPolygon) return sal_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( sal_uInt16 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( sal_uInt16 nPos, XPolyFlags eFlags )
{
pImpXPolygon->CheckPointDelete();
CheckReference();
pImpXPolygon->pFlagAry[nPos] = (sal_uInt8) eFlags;
}
/*************************************************************************
|*
|* XPolygon::IsControl()
|*
|* Kurzform zur Abfrage des CONTROL-Flags
|* Ersterstellung ESO 09.01.95
|* Letzte Aenderung ESO 12.01.95
|*
*************************************************************************/
sal_Bool XPolygon::IsControl(sal_uInt16 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
|*
*************************************************************************/
sal_Bool XPolygon::IsSmooth(sal_uInt16 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(sal_uInt16 nP1, sal_uInt16 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(sal_uInt16 nPos, sal_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;
sal_uInt16 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, sal_uInt16 nStart, sal_uInt16 nEnd,
sal_uInt16 nQuad, sal_uInt16 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, sal_False, (double)nStart / 900);
if ( nEnd < 900 )
SubdivideBezier(nFirst, sal_True, (double)(nEnd-nStart) / (900-nStart));
SetFlags(nFirst+1, XPOLY_CONTROL);
SetFlags(nFirst+2, XPOLY_CONTROL);
}
/************************************************************************/
sal_Bool XPolygon::CheckAngles(sal_uInt16& nStart, sal_uInt16 nEnd, sal_uInt16& nA1, sal_uInt16& nA2)
{
if ( nStart == 3600 ) nStart = 0;
if ( nEnd == 0 ) nEnd = 3600;
sal_uInt16 nStPrev = nStart;
sal_uInt16 nMax = (nStart / 900 + 1) * 900;
sal_uInt16 nMin = nMax - 900;
if ( nEnd >= nMax || nEnd <= nStart ) nA2 = 900;
else nA2 = nEnd - nMin;
nA1 = nStart - nMin;
nStart = nMax;
// sal_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(sal_uInt16 nCenter, sal_uInt16 nDrag, sal_uInt16 nPnt)
{
CheckReference();
// sal_uInt16 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) )
{
sal_uInt16 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(sal_uInt16 nCenter, sal_uInt16 nPrev, sal_uInt16 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(sal_uInt16 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();
sal_uInt16 nPntCnt = pImpXPolygon->nPoints;
for (sal_uInt16 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();
sal_uInt16 nPntCnt = pImpXPolygon->nPoints;
for (sal_uInt16 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.
sal_uInt16 nPntCnt = pImpXPolygon->nPoints;
for (sal_uInt16 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, sal_uInt16 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();
sal_uInt16 nPntCnt = pImpXPolygon->nPoints;
for (sal_uInt16 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();
sal_uInt16 nPntCnt = pImpXPolygon->nPoints;
for (sal_uInt16 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();
sal_uInt16 nPntCnt = pImpXPolygon->nPoints;
for (sal_uInt16 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();
sal_uInt16 nPntCnt = pImpXPolygon->nPoints;
for (sal_uInt16 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);
sal_uInt16 nSize = aSource.GetSize();
pImpXPolygon = new ImpXPolygon( nSize );
pImpXPolygon->nPoints = nSize;
for( sal_uInt16 i = 0; i < nSize; i++ )
{
pImpXPolygon->pPointAry[i] = aSource[i];
pImpXPolygon->pFlagAry[i] = (sal_uInt8) 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
{
sal_uInt16 nAnz=(sal_uInt16)aXPolyList.Count();
const XPolygonList& rCmpList=rImpXPolyPoly.aXPolyList;
if (nAnz!=(sal_uInt16)rCmpList.Count()) return sal_False;
bool bEq=true;
for (sal_uInt16 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( sal_uInt16 nInitSize, sal_uInt16 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 (sal_uInt16 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, sal_uInt16 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, sal_uInt16 nPos )
{
CheckReference();
for (sal_uInt16 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( sal_uInt16 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, sal_uInt16 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( sal_uInt16 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
|*
*************************************************************************/
sal_uInt16 XPolyPolygon::Count() const
{
return (sal_uInt16)(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
{
sal_uInt16 nXPoly = (sal_uInt16)pImpXPolyPolygon->aXPolyList.Count();
Rectangle aRect;
for ( sal_uInt16 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[]( sal_uInt16 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
|*
*************************************************************************/
sal_Bool XPolyPolygon::operator==( const XPolyPolygon& rXPolyPoly ) const
{
if (pImpXPolyPolygon==rXPolyPoly.pImpXPolyPolygon) return sal_True;
return *pImpXPolyPolygon == *rXPolyPoly.pImpXPolyPolygon;
}
/*************************************************************************
|*
|* XPolyPolygon::operator!=()
|*
|* Beschreibung POLY.SDW
|* Ersterstellung CL 27.01.93
|* Letzte Aenderung Joe 27.01.93
|*
*************************************************************************/
sal_Bool XPolyPolygon::operator!=( const XPolyPolygon& rXPolyPoly ) const
{
if (pImpXPolyPolygon==rXPolyPoly.pImpXPolyPolygon) return sal_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 (sal_uInt16 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 (sal_uInt16 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 (sal_uInt16 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, sal_uInt16 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 (sal_uInt16 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 (sal_uInt16 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 (sal_uInt16 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 (sal_uInt16 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