/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
/** Change polygon size * * @param nNewSize the new size of the polygon * @param bDeletePoints if FALSE, do not delete the point array directly but * wait for the next call before doing so. This prevents * errors with XPoly[n] = XPoly[0] where a resize might * destroy the right side point array too early.
*/ void ImpXPolygon::Resize( sal_uInt16 nNewSize, bool bDeletePoints )
{ if( nNewSize == nSize ) return;
// Round the new size to a multiple of nResize, if // the object was not newly created (nSize != 0) if ( nSize != 0 && nNewSize > nSize )
{
DBG_ASSERT(nResize, "Trying to resize but nResize = 0 !");
nNewSize = nSize + ((nNewSize-nSize-1) / nResize + 1) * nResize;
} // create point array
nSize = nNewSize;
pPointAry.reset( new Point[ nSize ] );
// create flag array
pFlagAry.reset( new PolyFlags[ nSize ] );
memset( pFlagAry.get(), 0, nSize );
// copy if needed if (nOldSize)
{ if( nOldSize < nSize )
{
memcpy( pPointAry.get(), pOldPointAry, nOldSize*sizeof( Point ) );
memcpy( pFlagAry.get(), pOldFlagAry, nOldSize );
} else
{
memcpy( pPointAry.get(), pOldPointAry, nSize*sizeof( Point ) );
memcpy( pFlagAry.get(), pOldFlagAry, nSize );
if(m_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.
/// get the flags for the point at the given position
PolyFlags XPolygon::GetFlags( sal_uInt16 nPos ) const
{
m_pImpXPolygon->CheckPointDelete(); return m_pImpXPolygon->pFlagAry[nPos];
}
/// set the flags for the point at the given position void XPolygon::SetFlags( sal_uInt16 nPos, PolyFlags eFlags )
{
std::as_const(m_pImpXPolygon)->CheckPointDelete();
m_pImpXPolygon->pFlagAry[nPos] = eFlags;
}
/// short path to read the CONTROL flag directly (TODO: better explain what the sense behind this flag is!) bool XPolygon::IsControl(sal_uInt16 nPos) const
{ return m_pImpXPolygon->pFlagAry[nPos] == PolyFlags::Control;
}
/// short path to read the SMOOTH and SYMMTR flag directly (TODO: better explain what the sense behind these flags is!) bool XPolygon::IsSmooth(sal_uInt16 nPos) const
{
PolyFlags eFlag = m_pImpXPolygon->pFlagAry[nPos]; return ( eFlag == PolyFlags::Smooth || eFlag == PolyFlags::Symmetric );
}
/** calculate the euclidean distance between two points * * @param nP1 The first point * @param nP2 The second point
*/ double XPolygon::CalcDistance(sal_uInt16 nP1, sal_uInt16 nP2)
{ const Point& rP1 = m_pImpXPolygon->pPointAry[nP1]; const Point& rP2 = m_pImpXPolygon->pPointAry[nP2]; double fDx = rP2.X() - rP1.X(); double fDy = rP2.Y() - rP1.Y(); return std::hypot(fDx, fDy);
}
void XPolygon::SubdivideBezier(sal_uInt16 nPos, bool bCalcFirst, double fT)
{
Point* pPoints = m_pImpXPolygon->pPointAry.get(); 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;
// returns true when the last segment was calculated return (nStPrev < nEnd && nStart >= nEnd);
}
/** Calculate a smooth transition to connect two Bézier curves * * This is done by projecting the corresponding point onto a line between * two other points. * * @param nCenter The point at the end or beginning of the curve. * If nCenter is at the end of the polygon the point is moved * to the opposite side. * @param nDrag The moved point that specifies the relocation. * @param nPnt The point to modify.
*/ void XPolygon::CalcSmoothJoin(sal_uInt16 nCenter, sal_uInt16 nDrag, sal_uInt16 nPnt)
{ // If nPoint is no control point, i.e. cannot be moved, then // move nDrag instead on the line between nCenter and nPnt if ( !IsControl(nPnt) )
std::swap( nDrag, nPnt );
Point* pPoints = m_pImpXPolygon->pPointAry.get();
Point aDiff = pPoints[nDrag] - pPoints[nCenter]; double fDiv = CalcDistance(nCenter, nDrag);
/** Calculate tangent between two Bézier curves * * @param nCenter start or end point of the curves * @param nPrev previous reference point * @param nNext next reference point
*/ void XPolygon::CalcTangent(sal_uInt16 nCenter, sal_uInt16 nPrev, sal_uInt16 nNext)
{ double fAbsLen = CalcDistance(nNext, nPrev);
Point aControlPoint1(static_cast<tools::Long>(fX1), static_cast<tools::Long>(fY1));
Point aControlPoint2(static_cast<tools::Long>(fX2), static_cast<tools::Long>(fY2));
// To prevent the curve from overshooting due to sharp direction changes in the given sequence of points, // compare the control point offsets against the full segment length. // Apply the calculated ControlPoints only if their offsets are within a reasonable range. if( fPointOffset1 < nFullLength && fPointOffset2 < nFullLength )
{
pPoints[nFirst + 1] = aControlPoint1;
pPoints[nFirst + 2] = aControlPoint2;
}
for (sal_uInt16 i = 0; i < nPntCnt; i++)
{
Point& rPnt = m_pImpXPolygon->pPointAry[i];
rPnt.setX( static_cast<tools::Long>(fSx * rPnt.X()) );
rPnt.setY( static_cast<tools::Long>(fSy * rPnt.Y()) );
}
}
/** * Distort a polygon by scaling its coordinates relative to a reference * rectangle into an arbitrary rectangle. * * Mapping between polygon corners and reference rectangle: * 0: top left 0----1 * 1: top right | | * 2: bottom right 3----2 * 3: bottom left
*/ void XPolygon::Distort(const tools::Rectangle& rRefRect, const XPolygon& rDistortedRect)
{
std::as_const(m_pImpXPolygon)->CheckPointDelete();
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 converters in // the long run const tools::Polygon aSource(GetPointCount(), m_pImpXPolygon->pPointAry.get(), m_pImpXPolygon->pFlagAry.get());
return aSource.getB2DPolygon();
}
XPolygon::XPolygon(const basegfx::B2DPolygon& rPolygon)
: m_pImpXPolygon( tools::Polygon( rPolygon ).GetSize() )
{ // #i74631# use tools Polygon class for conversion to not have the code doubled // here. This needs one more conversion but avoids different converters in // the long run
/// insert all XPolygons of a XPolyPolygon void XPolyPolygon::Insert( const XPolyPolygon& rXPolyPoly )
{ for ( size_t i = 0; i < rXPolyPoly.Count(); i++)
{
m_pImpXPolyPolygon->aXPolyList.emplace_back( rXPolyPoly[i] );
}
}
/** * Distort a polygon by scaling its coordinates relative to a reference * rectangle into an arbitrary rectangle. * * Mapping between polygon corners and reference rectangle: * 0: top left 0----1 * 1: top right | | * 2: bottom right 3----2 * 3: bottom left
*/ void XPolyPolygon::Distort(const tools::Rectangle& rRefRect, const XPolygon& rDistortedRect)
{ for (size_t i = 0; i < Count(); i++)
m_pImpXPolyPolygon->aXPolyList[ i ].Distort(rRefRect, rDistortedRect);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.