1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 /* 3 * This file is part of the LibreOffice project. 4 * 5 * This Source Code Form is subject to the terms of the Mozilla Public 6 * License, v. 2.0. If a copy of the MPL was not distributed with this 7 * file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 * 9 * This file incorporates work covered by the following license notice: 10 * 11 * Licensed to the Apache Software Foundation (ASF) under one or more 12 * contributor license agreements. See the NOTICE file distributed 13 * with this work for additional information regarding copyright 14 * ownership. The ASF licenses this file to you under the Apache 15 * License, Version 2.0 (the "License"); you may not use this file 16 * except in compliance with the License. You may obtain a copy of 17 * the License at http://www.apache.org/licenses/LICENSE-2.0 . 18 */ 19 20 #include <com/sun/star/geometry/RealSize2D.hpp> 21 #include <com/sun/star/geometry/RealPoint2D.hpp> 22 #include <com/sun/star/geometry/RealRectangle2D.hpp> 23 #include <com/sun/star/geometry/RealRectangle3D.hpp> 24 #include <com/sun/star/geometry/RealBezierSegment2D.hpp> 25 #include <com/sun/star/geometry/AffineMatrix2D.hpp> 26 #include <com/sun/star/geometry/AffineMatrix3D.hpp> 27 #include <com/sun/star/geometry/IntegerSize2D.hpp> 28 #include <com/sun/star/geometry/IntegerRectangle2D.hpp> 29 #include <com/sun/star/lang/IllegalArgumentException.hpp> 30 #include <com/sun/star/rendering/XPolyPolygon2D.hpp> 31 #include <com/sun/star/rendering/XGraphicDevice.hpp> 32 #include <com/sun/star/awt/Rectangle.hpp> 33 #include <basegfx/utils/unopolypolygon.hxx> 34 #include <basegfx/matrix/b2dhommatrix.hxx> 35 #include <basegfx/matrix/b3dhommatrix.hxx> 36 #include <basegfx/point/b2dpoint.hxx> 37 #include <basegfx/range/b3drange.hxx> 38 #include <basegfx/range/b2irange.hxx> 39 #include <basegfx/polygon/b2dpolygon.hxx> 40 #include <basegfx/polygon/b2dpolypolygon.hxx> 41 #include <basegfx/utils/canvastools.hxx> 42 43 using namespace ::com::sun::star; 44 45 namespace basegfx::unotools 46 { 47 namespace 48 { bezierSequenceFromB2DPolygon(const::basegfx::B2DPolygon & rPoly)49 uno::Sequence< geometry::RealBezierSegment2D > bezierSequenceFromB2DPolygon(const ::basegfx::B2DPolygon& rPoly) 50 { 51 const sal_uInt32 nPointCount(rPoly.count()); 52 uno::Sequence< geometry::RealBezierSegment2D > outputSequence(nPointCount); 53 geometry::RealBezierSegment2D* pOutput = outputSequence.getArray(); 54 55 // fill sequences and imply closed polygon on this implementation layer 56 for(sal_uInt32 a(0); a < nPointCount; a++) 57 { 58 const basegfx::B2DPoint aStart(rPoly.getB2DPoint(a)); 59 const basegfx::B2DPoint aControlA(rPoly.getNextControlPoint(a)); 60 const basegfx::B2DPoint aControlB(rPoly.getPrevControlPoint((a + 1) % nPointCount)); 61 62 pOutput[a] = geometry::RealBezierSegment2D( 63 aStart.getX(), aStart.getY(), 64 aControlA.getX(), aControlA.getY(), 65 aControlB.getX(), aControlB.getY()); 66 } 67 68 return outputSequence; 69 } 70 pointSequenceFromB2DPolygon(const::basegfx::B2DPolygon & rPoly)71 uno::Sequence< geometry::RealPoint2D > pointSequenceFromB2DPolygon( const ::basegfx::B2DPolygon& rPoly ) 72 { 73 const sal_uInt32 nNumPoints( rPoly.count() ); 74 75 uno::Sequence< geometry::RealPoint2D > outputSequence( nNumPoints ); 76 geometry::RealPoint2D* pOutput = outputSequence.getArray(); 77 78 // fill sequence from polygon 79 sal_uInt32 i; 80 for( i=0; i<nNumPoints; ++i ) 81 { 82 const ::basegfx::B2DPoint aPoint( rPoly.getB2DPoint(i) ); 83 84 pOutput[i] = geometry::RealPoint2D( aPoint.getX(), 85 aPoint.getY() ); 86 } 87 88 return outputSequence; 89 } 90 } 91 bezierSequenceSequenceFromB2DPolyPolygon(const::basegfx::B2DPolyPolygon & rPolyPoly)92 uno::Sequence< uno::Sequence< geometry::RealBezierSegment2D > > bezierSequenceSequenceFromB2DPolyPolygon( const ::basegfx::B2DPolyPolygon& rPolyPoly ) 93 { 94 const sal_uInt32 nNumPolies( rPolyPoly.count() ); 95 sal_uInt32 i; 96 97 uno::Sequence< uno::Sequence< geometry::RealBezierSegment2D > > outputSequence( nNumPolies ); 98 uno::Sequence< geometry::RealBezierSegment2D >* pOutput = outputSequence.getArray(); 99 100 for( i=0; i<nNumPolies; ++i ) 101 { 102 pOutput[i] = bezierSequenceFromB2DPolygon( rPolyPoly.getB2DPolygon(i) ); 103 } 104 105 return outputSequence; 106 } 107 pointSequenceSequenceFromB2DPolyPolygon(const::basegfx::B2DPolyPolygon & rPolyPoly)108 uno::Sequence< uno::Sequence< geometry::RealPoint2D > > pointSequenceSequenceFromB2DPolyPolygon( const ::basegfx::B2DPolyPolygon& rPolyPoly ) 109 { 110 const sal_uInt32 nNumPolies( rPolyPoly.count() ); 111 sal_uInt32 i; 112 113 uno::Sequence< uno::Sequence< geometry::RealPoint2D > > outputSequence( nNumPolies ); 114 uno::Sequence< geometry::RealPoint2D >* pOutput = outputSequence.getArray(); 115 116 for( i=0; i<nNumPolies; ++i ) 117 { 118 pOutput[i] = pointSequenceFromB2DPolygon( rPolyPoly.getB2DPolygon(i) ); 119 } 120 121 return outputSequence; 122 } 123 xPolyPolygonFromB2DPolygon(const uno::Reference<rendering::XGraphicDevice> & xGraphicDevice,const::basegfx::B2DPolygon & rPoly)124 uno::Reference< rendering::XPolyPolygon2D > xPolyPolygonFromB2DPolygon( const uno::Reference< rendering::XGraphicDevice >& xGraphicDevice, 125 const ::basegfx::B2DPolygon& rPoly ) 126 { 127 uno::Reference< rendering::XPolyPolygon2D > xRes; 128 129 if( !xGraphicDevice.is() ) 130 return xRes; 131 132 if( rPoly.areControlPointsUsed() ) 133 { 134 uno::Sequence< uno::Sequence< geometry::RealBezierSegment2D > > outputSequence{ bezierSequenceFromB2DPolygon( rPoly )}; 135 136 xRes = xGraphicDevice->createCompatibleBezierPolyPolygon( outputSequence ); 137 } 138 else 139 { 140 uno::Sequence< uno::Sequence< geometry::RealPoint2D > > outputSequence{ 141 pointSequenceFromB2DPolygon( rPoly )}; 142 143 xRes = xGraphicDevice->createCompatibleLinePolyPolygon( outputSequence ); 144 } 145 146 if( xRes.is() && rPoly.isClosed() ) 147 xRes->setClosed( 0, true ); 148 149 return xRes; 150 } 151 xPolyPolygonFromB2DPolyPolygon(const uno::Reference<rendering::XGraphicDevice> & xGraphicDevice,const::basegfx::B2DPolyPolygon & rPolyPoly)152 uno::Reference< rendering::XPolyPolygon2D > xPolyPolygonFromB2DPolyPolygon( const uno::Reference< rendering::XGraphicDevice >& xGraphicDevice, 153 const ::basegfx::B2DPolyPolygon& rPolyPoly ) 154 { 155 uno::Reference< rendering::XPolyPolygon2D > xRes; 156 157 if( !xGraphicDevice.is() ) 158 return xRes; 159 160 const sal_uInt32 nNumPolies( rPolyPoly.count() ); 161 sal_uInt32 i; 162 163 if( rPolyPoly.areControlPointsUsed() ) 164 { 165 xRes = xGraphicDevice->createCompatibleBezierPolyPolygon( 166 bezierSequenceSequenceFromB2DPolyPolygon( rPolyPoly ) ); 167 } 168 else 169 { 170 xRes = xGraphicDevice->createCompatibleLinePolyPolygon( 171 pointSequenceSequenceFromB2DPolyPolygon( rPolyPoly ) ); 172 } 173 174 for( i=0; i<nNumPolies; ++i ) 175 { 176 xRes->setClosed( i, rPolyPoly.getB2DPolygon(i).isClosed() ); 177 } 178 179 return xRes; 180 } 181 polygonFromPoint2DSequence(const uno::Sequence<geometry::RealPoint2D> & points)182 ::basegfx::B2DPolygon polygonFromPoint2DSequence( const uno::Sequence< geometry::RealPoint2D >& points ) 183 { 184 const sal_Int32 nCurrSize( points.getLength() ); 185 186 ::basegfx::B2DPolygon aPoly; 187 188 for( sal_Int32 nCurrPoint=0; nCurrPoint<nCurrSize; ++nCurrPoint ) 189 aPoly.append( b2DPointFromRealPoint2D( points[nCurrPoint] ) ); 190 191 return aPoly; 192 } 193 polyPolygonFromPoint2DSequenceSequence(const uno::Sequence<uno::Sequence<geometry::RealPoint2D>> & points)194 ::basegfx::B2DPolyPolygon polyPolygonFromPoint2DSequenceSequence( const uno::Sequence< uno::Sequence< geometry::RealPoint2D > >& points ) 195 { 196 ::basegfx::B2DPolyPolygon aRes; 197 198 for( const auto & p : points ) 199 { 200 aRes.append( polygonFromPoint2DSequence( p ) ); 201 } 202 203 return aRes; 204 } 205 polygonFromBezier2DSequence(const uno::Sequence<geometry::RealBezierSegment2D> & curves)206 ::basegfx::B2DPolygon polygonFromBezier2DSequence( const uno::Sequence< geometry::RealBezierSegment2D >& curves ) 207 { 208 const sal_Int32 nSize(curves.getLength()); 209 basegfx::B2DPolygon aRetval; 210 211 if(nSize) 212 { 213 // prepare start with providing a start point. Use the first point from 214 // the sequence for this 215 const geometry::RealBezierSegment2D& rFirstSegment(curves[0]); // #i79917# first segment, not last 216 aRetval.append(basegfx::B2DPoint(rFirstSegment.Px, rFirstSegment.Py)); 217 218 for(sal_Int32 a(0); a < nSize; a++) 219 { 220 const geometry::RealBezierSegment2D& rCurrSegment(curves[a]); 221 const geometry::RealBezierSegment2D& rNextSegment(curves[(a + 1) % nSize]); 222 223 // append curved edge with the control points and the next point 224 aRetval.appendBezierSegment( 225 basegfx::B2DPoint(rCurrSegment.C1x, rCurrSegment.C1y), 226 basegfx::B2DPoint(rCurrSegment.C2x, rCurrSegment.C2y), // #i79917# Argh! An x for an y!! 227 basegfx::B2DPoint(rNextSegment.Px, rNextSegment.Py)); 228 } 229 230 // rescue the control point and remove the now double-added point 231 aRetval.setPrevControlPoint(0, aRetval.getPrevControlPoint(aRetval.count() - 1)); 232 aRetval.remove(aRetval.count() - 1); 233 } 234 235 return aRetval; 236 } 237 polyPolygonFromBezier2DSequenceSequence(const uno::Sequence<uno::Sequence<geometry::RealBezierSegment2D>> & curves)238 ::basegfx::B2DPolyPolygon polyPolygonFromBezier2DSequenceSequence( const uno::Sequence< uno::Sequence< geometry::RealBezierSegment2D > >& curves ) 239 { 240 ::basegfx::B2DPolyPolygon aRes; 241 242 for( const auto & c : curves ) 243 { 244 aRes.append( polygonFromBezier2DSequence( c ) ); 245 } 246 247 return aRes; 248 } 249 b2DPolyPolygonFromXPolyPolygon2D(const uno::Reference<rendering::XPolyPolygon2D> & xPoly)250 ::basegfx::B2DPolyPolygon b2DPolyPolygonFromXPolyPolygon2D( const uno::Reference< rendering::XPolyPolygon2D >& xPoly ) 251 { 252 ::basegfx::unotools::UnoPolyPolygon* pPolyImpl = 253 dynamic_cast< ::basegfx::unotools::UnoPolyPolygon* >( xPoly.get() ); 254 255 if( pPolyImpl ) 256 { 257 return pPolyImpl->getPolyPolygon(); 258 } 259 else 260 { 261 // not a known implementation object - try data source 262 // interfaces 263 const sal_Int32 nPolys( xPoly->getNumberOfPolygons() ); 264 265 uno::Reference< rendering::XBezierPolyPolygon2D > xBezierPoly( 266 xPoly, 267 uno::UNO_QUERY ); 268 269 if( xBezierPoly.is() ) 270 { 271 return ::basegfx::unotools::polyPolygonFromBezier2DSequenceSequence( 272 xBezierPoly->getBezierSegments( 0, 273 nPolys, 274 0, 275 -1 ) ); 276 } 277 else 278 { 279 uno::Reference< rendering::XLinePolyPolygon2D > xLinePoly( 280 xPoly, 281 uno::UNO_QUERY ); 282 283 // no implementation class and no data provider 284 // found - contract violation. 285 if( !xLinePoly.is() ) 286 { 287 throw lang::IllegalArgumentException( 288 "basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D(): Invalid input" 289 "poly-polygon, cannot retrieve vertex data", 290 uno::Reference< uno::XInterface >(), 291 0 ); 292 } 293 294 return ::basegfx::unotools::polyPolygonFromPoint2DSequenceSequence( 295 xLinePoly->getPoints( 0, 296 nPolys, 297 0, 298 -1 )); 299 } 300 } 301 } 302 homMatrixFromAffineMatrix(::basegfx::B2DHomMatrix & output,const geometry::AffineMatrix2D & input)303 ::basegfx::B2DHomMatrix& homMatrixFromAffineMatrix( ::basegfx::B2DHomMatrix& output, 304 const geometry::AffineMatrix2D& input ) 305 { 306 // ensure last row is [0,0,1] (and optimized away) 307 output.identity(); 308 309 output.set(0,0, input.m00); 310 output.set(0,1, input.m01); 311 output.set(0,2, input.m02); 312 output.set(1,0, input.m10); 313 output.set(1,1, input.m11); 314 output.set(1,2, input.m12); 315 316 return output; 317 } 318 homMatrixFromAffineMatrix3D(const::css::geometry::AffineMatrix3D & input)319 ::basegfx::B3DHomMatrix homMatrixFromAffineMatrix3D( const ::css::geometry::AffineMatrix3D& input ) 320 { 321 ::basegfx::B3DHomMatrix output; 322 323 output.set(0,0, input.m00); 324 output.set(0,1, input.m01); 325 output.set(0,2, input.m02); 326 output.set(0,3, input.m03); 327 328 output.set(1,0, input.m10); 329 output.set(1,1, input.m11); 330 output.set(1,2, input.m12); 331 output.set(1,3, input.m13); 332 333 output.set(2,0, input.m20); 334 output.set(2,1, input.m21); 335 output.set(2,2, input.m22); 336 output.set(2,3, input.m23); 337 338 return output; 339 } 340 affineMatrixFromHomMatrix(geometry::AffineMatrix2D & output,const::basegfx::B2DHomMatrix & input)341 geometry::AffineMatrix2D& affineMatrixFromHomMatrix( geometry::AffineMatrix2D& output, 342 const ::basegfx::B2DHomMatrix& input) 343 { 344 output.m00 = input.get(0,0); 345 output.m01 = input.get(0,1); 346 output.m02 = input.get(0,2); 347 output.m10 = input.get(1,0); 348 output.m11 = input.get(1,1); 349 output.m12 = input.get(1,2); 350 351 return output; 352 } 353 affineMatrixFromHomMatrix3D(geometry::AffineMatrix3D & output,const::basegfx::B3DHomMatrix & input)354 geometry::AffineMatrix3D& affineMatrixFromHomMatrix3D( 355 geometry::AffineMatrix3D& output, 356 const ::basegfx::B3DHomMatrix& input) 357 { 358 output.m00 = input.get(0,0); 359 output.m01 = input.get(0,1); 360 output.m02 = input.get(0,2); 361 output.m03 = input.get(0,3); 362 363 output.m10 = input.get(1,0); 364 output.m11 = input.get(1,1); 365 output.m12 = input.get(1,2); 366 output.m13 = input.get(1,3); 367 368 output.m20 = input.get(2,0); 369 output.m21 = input.get(2,1); 370 output.m22 = input.get(2,2); 371 output.m23 = input.get(2,3); 372 373 return output; 374 } 375 size2DFromB2DSize(const::basegfx::B2DVector & rVec)376 geometry::RealSize2D size2DFromB2DSize( const ::basegfx::B2DVector& rVec ) 377 { 378 return geometry::RealSize2D( rVec.getX(), 379 rVec.getY() ); 380 } 381 point2DFromB2DPoint(const::basegfx::B2DPoint & rPoint)382 geometry::RealPoint2D point2DFromB2DPoint( const ::basegfx::B2DPoint& rPoint ) 383 { 384 return geometry::RealPoint2D( rPoint.getX(), 385 rPoint.getY() ); 386 } 387 rectangle2DFromB2DRectangle(const::basegfx::B2DRange & rRect)388 geometry::RealRectangle2D rectangle2DFromB2DRectangle( const ::basegfx::B2DRange& rRect ) 389 { 390 return geometry::RealRectangle2D( rRect.getMinX(), 391 rRect.getMinY(), 392 rRect.getMaxX(), 393 rRect.getMaxY() ); 394 } 395 rectangle3DFromB3DRectangle(const::basegfx::B3DRange & rRect)396 geometry::RealRectangle3D rectangle3DFromB3DRectangle( const ::basegfx::B3DRange& rRect ) 397 { 398 return geometry::RealRectangle3D( rRect.getMinX(), 399 rRect.getMinY(), 400 rRect.getMinZ(), 401 rRect.getMaxX(), 402 rRect.getMaxY(), 403 rRect.getMaxZ()); 404 } 405 b2DPointFromRealPoint2D(const geometry::RealPoint2D & rPoint)406 ::basegfx::B2DPoint b2DPointFromRealPoint2D( const geometry::RealPoint2D& rPoint ) 407 { 408 return ::basegfx::B2DPoint( rPoint.X, 409 rPoint.Y ); 410 } 411 b2DRectangleFromRealRectangle2D(const geometry::RealRectangle2D & rRect)412 ::basegfx::B2DRange b2DRectangleFromRealRectangle2D( const geometry::RealRectangle2D& rRect ) 413 { 414 return ::basegfx::B2DRange( rRect.X1, 415 rRect.Y1, 416 rRect.X2, 417 rRect.Y2 ); 418 } 419 b3DRectangleFromRealRectangle3D(const geometry::RealRectangle3D & rRect)420 ::basegfx::B3DRange b3DRectangleFromRealRectangle3D( const geometry::RealRectangle3D& rRect ) 421 { 422 return ::basegfx::B3DRange( rRect.X1, 423 rRect.Y1, 424 rRect.Z1, 425 rRect.X2, 426 rRect.Y2, 427 rRect.Z2); 428 } 429 integerSize2DFromB2ISize(const::basegfx::B2IVector & rSize)430 geometry::IntegerSize2D integerSize2DFromB2ISize( const ::basegfx::B2IVector& rSize ) 431 { 432 return geometry::IntegerSize2D( rSize.getX(), 433 rSize.getY() ); 434 } 435 b2ISizeFromIntegerSize2D(const geometry::IntegerSize2D & rSize)436 ::basegfx::B2IVector b2ISizeFromIntegerSize2D( const geometry::IntegerSize2D& rSize ) 437 { 438 return ::basegfx::B2IVector( rSize.Width, 439 rSize.Height ); 440 } 441 b2IRectangleFromIntegerRectangle2D(const geometry::IntegerRectangle2D & rRectangle)442 ::basegfx::B2IRange b2IRectangleFromIntegerRectangle2D( const geometry::IntegerRectangle2D& rRectangle ) 443 { 444 return ::basegfx::B2IRange( rRectangle.X1, rRectangle.Y1, 445 rRectangle.X2, rRectangle.Y2 ); 446 } 447 b2IRectangleFromAwtRectangle(const awt::Rectangle & rRect)448 ::basegfx::B2IRange b2IRectangleFromAwtRectangle( const awt::Rectangle& rRect ) 449 { 450 return ::basegfx::B2IRange( rRect.X, 451 rRect.Y, 452 rRect.X + rRect.Width, 453 rRect.Y + rRect.Height ); 454 } 455 b2ISurroundingRangeFromB2DRange(const::basegfx::B2DRange & rRange)456 ::basegfx::B2IRange b2ISurroundingRangeFromB2DRange( const ::basegfx::B2DRange& rRange ) 457 { 458 return ::basegfx::B2IRange( static_cast<sal_Int32>( floor(rRange.getMinX()) ), 459 static_cast<sal_Int32>( floor(rRange.getMinY()) ), 460 static_cast<sal_Int32>( ceil(rRange.getMaxX()) ), 461 static_cast<sal_Int32>( ceil(rRange.getMaxY()) ) ); 462 } 463 b2DSurroundingIntegerRangeFromB2DRange(const::basegfx::B2DRange & rRange)464 ::basegfx::B2DRange b2DSurroundingIntegerRangeFromB2DRange( const ::basegfx::B2DRange& rRange ) 465 { 466 return ::basegfx::B2DRange( floor(rRange.getMinX()), 467 floor(rRange.getMinY()), 468 ceil(rRange.getMaxX()), 469 ceil(rRange.getMaxY()) ); 470 } 471 472 } // namespace 473 474 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 475