/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /************************************************************************* * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * Copyright 2008 by Sun Microsystems, Inc. * * Portions Copright 2011 Thorsten Behrens * * OpenOffice.org - a multi-platform office productivity suite * * This file is part of OpenOffice.org. * * OpenOffice.org is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version 3 * only, as published by the Free Software Foundation. * * OpenOffice.org is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License version 3 for more details * (a copy is included in the LICENSE file that accompanied this code). * * You should have received a copy of the GNU Lesser General Public License * version 3 along with OpenOffice.org. If not, see * * for a copy of the LGPLv3 License. * ************************************************************************/ // MARKER(update_precomp.py): autogen include statement, do not remove #include "precompiled_basegfx.hxx" #include #include #include #include #include #include #include #include #include using namespace ::com::sun::star; namespace basegfx { namespace unotools { B2DPolyPolygon polyPolygonBezierToB2DPolyPolygon(const drawing::PolyPolygonBezierCoords& rSourcePolyPolygon) throw( lang::IllegalArgumentException ) { const sal_Int32 nOuterSequenceCount(rSourcePolyPolygon.Coordinates.getLength()); B2DPolyPolygon aNewPolyPolygon; if(rSourcePolyPolygon.Flags.getLength() != nOuterSequenceCount) throw lang::IllegalArgumentException(); // get pointers to inner sequence const drawing::PointSequence* pInnerSequence = rSourcePolyPolygon.Coordinates.getConstArray(); const drawing::FlagSequence* pInnerSequenceFlags = rSourcePolyPolygon.Flags.getConstArray(); for(sal_Int32 a(0); a < nOuterSequenceCount; a++) { const sal_Int32 nInnerSequenceCount(pInnerSequence->getLength()); if(pInnerSequenceFlags->getLength() != nInnerSequenceCount) throw lang::IllegalArgumentException(); // prepare new polygon basegfx::B2DPolygon aNewPolygon; const awt::Point* pArray = pInnerSequence->getConstArray(); const drawing::PolygonFlags* pArrayFlags = pInnerSequenceFlags->getConstArray(); // get first point and flag basegfx::B2DPoint aNewCoordinatePair(pArray->X, pArray->Y); pArray++; drawing::PolygonFlags ePolyFlag(*pArrayFlags); pArrayFlags++; basegfx::B2DPoint aControlA; basegfx::B2DPoint aControlB; // first point is not allowed to be a control point if(drawing::PolygonFlags_CONTROL == ePolyFlag) throw lang::IllegalArgumentException(); // add first point as start point aNewPolygon.append(aNewCoordinatePair); for(sal_Int32 b(1); b < nInnerSequenceCount;) { // prepare loop bool bControlA(false); bool bControlB(false); // get next point and flag aNewCoordinatePair = basegfx::B2DPoint(pArray->X, pArray->Y); ePolyFlag = *pArrayFlags; pArray++; pArrayFlags++; b++; if(b < nInnerSequenceCount && drawing::PolygonFlags_CONTROL == ePolyFlag) { aControlA = aNewCoordinatePair; bControlA = true; // get next point and flag aNewCoordinatePair = basegfx::B2DPoint(pArray->X, pArray->Y); ePolyFlag = *pArrayFlags; pArray++; pArrayFlags++; b++; } if(b < nInnerSequenceCount && drawing::PolygonFlags_CONTROL == ePolyFlag) { aControlB = aNewCoordinatePair; bControlB = true; // get next point and flag aNewCoordinatePair = basegfx::B2DPoint(pArray->X, pArray->Y); ePolyFlag = *pArrayFlags; pArray++; pArrayFlags++; b++; } // two or no control points are consumed, another one would be an error. // It's also an error if only one control point was read if(drawing::PolygonFlags_CONTROL == ePolyFlag || bControlA != bControlB) throw lang::IllegalArgumentException(); // the previous writes used the B2DPolyPoygon -> PolyPolygon converter // which did not create minimal PolyPolygons, but created all control points // as null vectors (identical points). Because of the former P(CA)(CB)-norm of // B2DPolygon and it's unused sign of being the zero-vector and CA and CB being // relative to P, an empty edge was exported as P == CA == CB. Luckily, the new // export format can be read without errors by the old OOo-versions, so we need only // to correct here at read and do not need to export a wrong but compatible version // for the future. if(bControlA && aControlA.equal(aControlB) && aControlA.equal(aNewPolygon.getB2DPoint(aNewPolygon.count() - 1))) { bControlA = bControlB = false; } if(bControlA) { // add bezier edge aNewPolygon.appendBezierSegment(aControlA, aControlB, aNewCoordinatePair); } else { // add edge aNewPolygon.append(aNewCoordinatePair); } } // next sequence pInnerSequence++; pInnerSequenceFlags++; // #i72807# API import uses old line start/end-equal definition for closed, // so we need to correct this to closed state here basegfx::tools::checkClosed(aNewPolygon); // add new subpolygon aNewPolyPolygon.append(aNewPolygon); } return aNewPolyPolygon; } ///////////////////////////////////////////////////////////////////////////////// void b2DPolyPolygonToPolyPolygonBezier( const basegfx::B2DPolyPolygon& rPolyPoly, drawing::PolyPolygonBezierCoords& rRetval ) { rRetval.Coordinates.realloc(rPolyPoly.count()); rRetval.Flags.realloc(rPolyPoly.count()); drawing::PointSequence* pOuterSequence = rRetval.Coordinates.getArray(); drawing::FlagSequence* pOuterFlags = rRetval.Flags.getArray(); for(sal_uInt32 a=0;a aPoints; aPoints.reserve(nLoopCount); std::vector aFlags; aFlags.reserve(nLoopCount); // prepare insert index and current point basegfx::B2DCubicBezier aBezier; aBezier.setStartPoint(rPoly.getB2DPoint(0)); for(sal_uInt32 b(0L); b