From 267c6f2ac71f92999e969232431ba04678e7437e Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Mon, 15 Apr 2024 07:54:39 +0200 Subject: Adding upstream version 4:24.2.0. Signed-off-by: Daniel Baumann --- include/basegfx/DrawCommands.hxx | 158 ++++++ include/basegfx/basegfxdllapi.h | 43 ++ include/basegfx/color/bcolor.hxx | 185 +++++++ include/basegfx/color/bcolormodifier.hxx | 447 +++++++++++++++++ include/basegfx/color/bcolortools.hxx | 43 ++ include/basegfx/curve/b2dbeziertools.hxx | 52 ++ include/basegfx/curve/b2dcubicbezier.hxx | 201 ++++++++ include/basegfx/matrix/b2dhommatrix.hxx | 158 ++++++ include/basegfx/matrix/b2dhommatrixtools.hxx | 218 ++++++++ include/basegfx/matrix/b3dhommatrix.hxx | 127 +++++ include/basegfx/matrix/b3dhommatrixtools.hxx | 44 ++ include/basegfx/matrix/hommatrixtemplate.hxx | 427 ++++++++++++++++ include/basegfx/numeric/ftools.hxx | 213 ++++++++ include/basegfx/pixel/bpixel.hxx | 98 ++++ include/basegfx/point/b2dpoint.hxx | 145 ++++++ include/basegfx/point/b2ipoint.hxx | 99 ++++ include/basegfx/point/b3dpoint.hxx | 123 +++++ include/basegfx/polygon/WaveLine.hxx | 38 ++ include/basegfx/polygon/b2dlinegeometry.hxx | 145 ++++++ include/basegfx/polygon/b2dpolygon.hxx | 281 +++++++++++ include/basegfx/polygon/b2dpolygonclipper.hxx | 65 +++ include/basegfx/polygon/b2dpolygoncutandtouch.hxx | 47 ++ include/basegfx/polygon/b2dpolygontools.hxx | 548 +++++++++++++++++++++ include/basegfx/polygon/b2dpolygontriangulator.hxx | 71 +++ include/basegfx/polygon/b2dpolypolygon.hxx | 171 +++++++ include/basegfx/polygon/b2dpolypolygoncutter.hxx | 144 ++++++ include/basegfx/polygon/b2dpolypolygontools.hxx | 297 +++++++++++ include/basegfx/polygon/b2dtrapezoid.hxx | 108 ++++ include/basegfx/polygon/b3dpolygon.hxx | 120 +++++ include/basegfx/polygon/b3dpolygontools.hxx | 129 +++++ include/basegfx/polygon/b3dpolypolygon.hxx | 113 +++++ include/basegfx/polygon/b3dpolypolygontools.hxx | 132 +++++ include/basegfx/range/Range2D.hxx | 184 +++++++ include/basegfx/range/b1drange.hxx | 159 ++++++ include/basegfx/range/b2dconnectedranges.hxx | 238 +++++++++ include/basegfx/range/b2dpolyrange.hxx | 93 ++++ include/basegfx/range/b2drange.hxx | 174 +++++++ include/basegfx/range/b2drangeclipper.hxx | 39 ++ include/basegfx/range/b2drectangle.hxx | 33 ++ include/basegfx/range/b2ibox.hxx | 190 +++++++ include/basegfx/range/b2irange.hxx | 140 ++++++ include/basegfx/range/b2irectangle.hxx | 33 ++ include/basegfx/range/b3drange.hxx | 227 +++++++++ include/basegfx/range/basicbox.hxx | 68 +++ include/basegfx/range/basicrange.hxx | 313 ++++++++++++ include/basegfx/raster/bzpixelraster.hxx | 91 ++++ include/basegfx/raster/rasterconvert3d.hxx | 421 ++++++++++++++++ include/basegfx/tuple/Size2D.hxx | 117 +++++ include/basegfx/tuple/Tuple2D.hxx | 180 +++++++ include/basegfx/tuple/Tuple3D.hxx | 122 +++++ include/basegfx/tuple/b2dtuple.hxx | 153 ++++++ include/basegfx/tuple/b2i64tuple.hxx | 87 ++++ include/basegfx/tuple/b2ituple.hxx | 95 ++++ include/basegfx/tuple/b3dtuple.hxx | 239 +++++++++ include/basegfx/tuple/b3ituple.hxx | 93 ++++ include/basegfx/utils/b2dclipstate.hxx | 92 ++++ include/basegfx/utils/bgradient.hxx | 329 +++++++++++++ include/basegfx/utils/canvastools.hxx | 167 +++++++ include/basegfx/utils/common.hxx | 33 ++ include/basegfx/utils/gradienttools.hxx | 526 ++++++++++++++++++++ include/basegfx/utils/keystoplerp.hxx | 85 ++++ include/basegfx/utils/lerp.hxx | 43 ++ include/basegfx/utils/rectcliptools.hxx | 72 +++ include/basegfx/utils/systemdependentdata.hxx | 111 +++++ include/basegfx/utils/tools.hxx | 124 +++++ include/basegfx/utils/unopolypolygon.hxx | 104 ++++ include/basegfx/utils/zoomtools.hxx | 22 + include/basegfx/vector/b2dsize.hxx | 99 ++++ include/basegfx/vector/b2dvector.hxx | 242 +++++++++ include/basegfx/vector/b2enums.hxx | 68 +++ include/basegfx/vector/b2isize.hxx | 60 +++ include/basegfx/vector/b2ivector.hxx | 129 +++++ include/basegfx/vector/b3dvector.hxx | 258 ++++++++++ 73 files changed, 11243 insertions(+) create mode 100644 include/basegfx/DrawCommands.hxx create mode 100644 include/basegfx/basegfxdllapi.h create mode 100644 include/basegfx/color/bcolor.hxx create mode 100644 include/basegfx/color/bcolormodifier.hxx create mode 100644 include/basegfx/color/bcolortools.hxx create mode 100644 include/basegfx/curve/b2dbeziertools.hxx create mode 100644 include/basegfx/curve/b2dcubicbezier.hxx create mode 100644 include/basegfx/matrix/b2dhommatrix.hxx create mode 100644 include/basegfx/matrix/b2dhommatrixtools.hxx create mode 100644 include/basegfx/matrix/b3dhommatrix.hxx create mode 100644 include/basegfx/matrix/b3dhommatrixtools.hxx create mode 100644 include/basegfx/matrix/hommatrixtemplate.hxx create mode 100644 include/basegfx/numeric/ftools.hxx create mode 100644 include/basegfx/pixel/bpixel.hxx create mode 100644 include/basegfx/point/b2dpoint.hxx create mode 100644 include/basegfx/point/b2ipoint.hxx create mode 100644 include/basegfx/point/b3dpoint.hxx create mode 100644 include/basegfx/polygon/WaveLine.hxx create mode 100644 include/basegfx/polygon/b2dlinegeometry.hxx create mode 100644 include/basegfx/polygon/b2dpolygon.hxx create mode 100644 include/basegfx/polygon/b2dpolygonclipper.hxx create mode 100644 include/basegfx/polygon/b2dpolygoncutandtouch.hxx create mode 100644 include/basegfx/polygon/b2dpolygontools.hxx create mode 100644 include/basegfx/polygon/b2dpolygontriangulator.hxx create mode 100644 include/basegfx/polygon/b2dpolypolygon.hxx create mode 100644 include/basegfx/polygon/b2dpolypolygoncutter.hxx create mode 100644 include/basegfx/polygon/b2dpolypolygontools.hxx create mode 100644 include/basegfx/polygon/b2dtrapezoid.hxx create mode 100644 include/basegfx/polygon/b3dpolygon.hxx create mode 100644 include/basegfx/polygon/b3dpolygontools.hxx create mode 100644 include/basegfx/polygon/b3dpolypolygon.hxx create mode 100644 include/basegfx/polygon/b3dpolypolygontools.hxx create mode 100644 include/basegfx/range/Range2D.hxx create mode 100644 include/basegfx/range/b1drange.hxx create mode 100644 include/basegfx/range/b2dconnectedranges.hxx create mode 100644 include/basegfx/range/b2dpolyrange.hxx create mode 100644 include/basegfx/range/b2drange.hxx create mode 100644 include/basegfx/range/b2drangeclipper.hxx create mode 100644 include/basegfx/range/b2drectangle.hxx create mode 100644 include/basegfx/range/b2ibox.hxx create mode 100644 include/basegfx/range/b2irange.hxx create mode 100644 include/basegfx/range/b2irectangle.hxx create mode 100644 include/basegfx/range/b3drange.hxx create mode 100644 include/basegfx/range/basicbox.hxx create mode 100644 include/basegfx/range/basicrange.hxx create mode 100644 include/basegfx/raster/bzpixelraster.hxx create mode 100644 include/basegfx/raster/rasterconvert3d.hxx create mode 100644 include/basegfx/tuple/Size2D.hxx create mode 100644 include/basegfx/tuple/Tuple2D.hxx create mode 100644 include/basegfx/tuple/Tuple3D.hxx create mode 100644 include/basegfx/tuple/b2dtuple.hxx create mode 100644 include/basegfx/tuple/b2i64tuple.hxx create mode 100644 include/basegfx/tuple/b2ituple.hxx create mode 100644 include/basegfx/tuple/b3dtuple.hxx create mode 100644 include/basegfx/tuple/b3ituple.hxx create mode 100644 include/basegfx/utils/b2dclipstate.hxx create mode 100644 include/basegfx/utils/bgradient.hxx create mode 100644 include/basegfx/utils/canvastools.hxx create mode 100644 include/basegfx/utils/common.hxx create mode 100644 include/basegfx/utils/gradienttools.hxx create mode 100644 include/basegfx/utils/keystoplerp.hxx create mode 100644 include/basegfx/utils/lerp.hxx create mode 100644 include/basegfx/utils/rectcliptools.hxx create mode 100644 include/basegfx/utils/systemdependentdata.hxx create mode 100644 include/basegfx/utils/tools.hxx create mode 100644 include/basegfx/utils/unopolypolygon.hxx create mode 100644 include/basegfx/utils/zoomtools.hxx create mode 100644 include/basegfx/vector/b2dsize.hxx create mode 100644 include/basegfx/vector/b2dvector.hxx create mode 100644 include/basegfx/vector/b2enums.hxx create mode 100644 include/basegfx/vector/b2isize.hxx create mode 100644 include/basegfx/vector/b2ivector.hxx create mode 100644 include/basegfx/vector/b3dvector.hxx (limited to 'include/basegfx') diff --git a/include/basegfx/DrawCommands.hxx b/include/basegfx/DrawCommands.hxx new file mode 100644 index 0000000000..14d3ad2459 --- /dev/null +++ b/include/basegfx/DrawCommands.hxx @@ -0,0 +1,158 @@ +/* -*- 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/. + */ + +#ifndef INCLUDED_BASEGFX_DRAWCOMMANDS_H +#define INCLUDED_BASEGFX_DRAWCOMMANDS_H + +#include +#include +#include + +#include +#include +#include +#include + +namespace gfx +{ +class DrawBase; + +class DrawCommand +{ +public: + std::vector> maChildren; +}; + +enum class DrawCommandType +{ + Root, + Rectangle, + Path +}; + +enum class GradientType +{ + Linear +}; + +class GradientStop +{ +public: + basegfx::BColor maColor; + float mfOffset; + float mfOpacity; +}; + +class GradientInfo +{ +public: + GradientType meType; + + std::vector maGradientStops; + + GradientInfo(GradientType eType) + : meType(eType) + { + } +}; + +class LinearGradientInfo : public GradientInfo +{ +public: + LinearGradientInfo() + : GradientInfo(GradientType::Linear) + , x1(0.0) + , y1(0.0) + , x2(0.0) + , y2(0.0) + { + } + + double x1; + double y1; + double x2; + double y2; + + basegfx::B2DHomMatrix maMatrix; +}; + +class DrawBase : public DrawCommand +{ +private: + DrawCommandType meType; + +public: + DrawBase(DrawCommandType eType) + : meType(eType) + { + } + + DrawCommandType getType() const { return meType; } +}; + +class DrawRoot : public DrawBase +{ +public: + basegfx::B2DRange maRectangle; + + DrawRoot() + : DrawBase(DrawCommandType::Root) + { + } +}; + +class DrawRectangle : public DrawBase +{ +public: + basegfx::B2DRange maRectangle; + double mnRx; + double mnRy; + + double mnStrokeWidth; + double mnOpacity; + std::shared_ptr mpFillColor; + std::shared_ptr mpStrokeColor; + std::shared_ptr mpFillGradient; + + DrawRectangle(basegfx::B2DRange const& rRectangle) + : DrawBase(DrawCommandType::Rectangle) + , maRectangle(rRectangle) + , mnRx(1.0) + , mnRy(1.0) + , mnStrokeWidth(1.0) + , mnOpacity(1.0) + { + } +}; + +class DrawPath : public DrawBase +{ +public: + basegfx::B2DPolyPolygon maPolyPolygon; + + double mnStrokeWidth; + double mnOpacity; + std::shared_ptr mpFillColor; + std::shared_ptr mpStrokeColor; + std::shared_ptr mpFillGradient; + + DrawPath(basegfx::B2DPolyPolygon aPolyPolygon) + : DrawBase(DrawCommandType::Path) + , maPolyPolygon(std::move(aPolyPolygon)) + , mnStrokeWidth(1.0) + , mnOpacity(1.0) + { + } +}; + +} // end namespace gfx + +#endif // INCLUDED_BASEGFX_DRAWCOMMANDS_H + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/include/basegfx/basegfxdllapi.h b/include/basegfx/basegfxdllapi.h new file mode 100644 index 0000000000..b1ef1709bc --- /dev/null +++ b/include/basegfx/basegfxdllapi.h @@ -0,0 +1,43 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_BASEGFX_BASEGFXDLLAPI_H +#define INCLUDED_BASEGFX_BASEGFXDLLAPI_H + +#include + +#if defined BASEGFX_STATICLIBRARY + +#define BASEGFX_DLLPUBLIC +#define BASEGFX_DLLPRIVATE + +#else /*BASEGFX_STATICLIBRARY*/ + +#if defined BASEGFX_DLLIMPLEMENTATION +#define BASEGFX_DLLPUBLIC SAL_DLLPUBLIC_EXPORT +#else +#define BASEGFX_DLLPUBLIC SAL_DLLPUBLIC_IMPORT +#endif +#define BASEGFX_DLLPRIVATE SAL_DLLPRIVATE + +#endif /*BASEGFX_STATICLIBRARY*/ + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/include/basegfx/color/bcolor.hxx b/include/basegfx/color/bcolor.hxx new file mode 100644 index 0000000000..a88488117c --- /dev/null +++ b/include/basegfx/color/bcolor.hxx @@ -0,0 +1,185 @@ +/* -*- 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 . + */ + +#pragma once + +#include + +#include +#include + +#include +#include + +namespace basegfx +{ + /** Base Color class with three double values + + This class derives all operators and common handling for + a 3D data class from B3DTuple. All necessary extensions + which are special for colors will be added here. + + @see B3DTuple + */ + class SAL_WARN_UNUSED BASEGFX_DLLPUBLIC BColor : public B3DTuple + { + public: + /** Create a Color with red, green and blue components from [0.0 to 1.0] + + The color is initialized to (0.0, 0.0, 0.0) + */ + BColor() + {} + + /** Create a 3D Color + + @param fRed + @param fGreen + @param fBlue + These parameters are used to initialize the red, green and blue intensities of the color + */ + BColor(double fRed, double fGreen, double fBlue) + : B3DTuple(fRed, fGreen, fBlue) + {} + + /** Create a 3D Color + + @param fLuminosity + The parameter is used to initialize the red, green and blue intensities of the color + */ + explicit BColor(double fLuminosity) + : B3DTuple(fLuminosity, fLuminosity, fLuminosity) + {} + + /** constructor with tuple to allow copy-constructing + from B3DTuple-based classes + */ + BColor(const ::basegfx::B3DTuple& rTuple) + : B3DTuple(rTuple) + {} + + // data access read + double getRed() const { return mnX; } + double getGreen() const { return mnY; } + double getBlue() const { return mnZ; } + + // data access write + void setRed(double fNew) { mnX = fNew; } + void setGreen(double fNew) { mnY = fNew; } + void setBlue(double fNew) { mnZ = fNew; } + + /** *=operator to allow usage from BColor, too + */ + BColor& operator*=( const BColor& rPnt ) + { + mnX *= rPnt.mnX; + mnY *= rPnt.mnY; + mnZ *= rPnt.mnZ; + return *this; + } + + /** *=operator to allow usage from BColor, too + */ + BColor& operator*=(double t) + { + mnX *= t; + mnY *= t; + mnZ *= t; + return *this; + } + + /** assignment operator to allow assigning the results + of B3DTuple calculations + */ + BColor& operator=( const ::basegfx::B3DTuple& rVec ) + { + mnX = rVec.getX(); + mnY = rVec.getY(); + mnZ = rVec.getZ(); + return *this; + } + + // luminance + double luminance() const + { + const double fRedWeight(77.0 / 256.0); // 0.30 + const double fGreenWeight(151.0 / 256.0); // 0.59 + const double fBlueWeight(28.0 / 256.0); // 0.11 + + return (mnX * fRedWeight + mnY * fGreenWeight + mnZ * fBlueWeight); + } + + // distances in color space + double getDistanceRed(const BColor& rColor) const { return (getRed() > rColor.getRed() ? getRed() - rColor.getRed() : rColor.getRed() - getRed()); } + double getDistanceGreen(const BColor& rColor) const { return (getGreen() > rColor.getGreen() ? getGreen() - rColor.getGreen() : rColor.getGreen() - getGreen()); } + double getDistanceBlue(const BColor& rColor) const { return (getBlue() > rColor.getBlue() ? getBlue() - rColor.getBlue() : rColor.getBlue() - getBlue()); } + + double getDistance(const BColor& rColor) const + { + const double fDistR(getDistanceRed(rColor)); + const double fDistG(getDistanceGreen(rColor)); + const double fDistB(getDistanceBlue(rColor)); + + return std::hypot(fDistR, fDistG, fDistB); + } + + double getMaximumDistance(const BColor& rColor) const + { + const double fDistR(getDistanceRed(rColor)); + const double fDistG(getDistanceGreen(rColor)); + const double fDistB(getDistanceBlue(rColor)); + + double fRetval(std::max(fDistR, fDistG)); + return std::max(fRetval, fDistB); + } + + // clamp color to [0.0..1.0] values in all three intensity components + BColor& clamp() + { + mnX = std::clamp(mnX, 0.0, 1.0); + mnY = std::clamp(mnY, 0.0, 1.0); + mnZ = std::clamp(mnZ, 0.0, 1.0); + return *this; + } + + void invert() + { + mnX = 1.0 - mnX; + mnY = 1.0 - mnY; + mnZ = 1.0 - mnZ; + } + + static const BColor& getEmptyBColor() + { + return static_cast( ::basegfx::B3DTuple::getEmptyTuple() ); + } + + }; + + template + std::basic_ostream & operator <<( + std::basic_ostream & stream, BColor const & color) + { + return stream + << '[' << color.getRed() << ", " << color.getGreen() << ", " + << color.getBlue() << ']'; + } +} // end of namespace basegfx + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/include/basegfx/color/bcolormodifier.hxx b/include/basegfx/color/bcolormodifier.hxx new file mode 100644 index 0000000000..1c2c4c776a --- /dev/null +++ b/include/basegfx/color/bcolormodifier.hxx @@ -0,0 +1,447 @@ +/* -*- 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 . + */ + +#pragma once + +#include +#include +#include +#include +#include + +#include + +#include +#include + +namespace basegfx +{ + /** base class to define color modifications + + The basic idea is to have instances of color modifiers where each + of these can be asked to get a modified version of a color. This + can be as easy as to return a fixed color, but may also do any + other computation based on the given source color and the local + algorithm to apply. + + This base implementation defines the abstract base class. Every + derivation offers another color blending effect, when needed with + parameters for that blending defined as members. + + As long as aw080 is not applied, an operator== is needed to implement + the operator== of the primitive based on this instances. + + For the exact definitions of the color blending applied refer to the + implementation of the method getModifiedColor + + BColorModifier is not copyable (no copy constructor, no assignment + operator); local values cannot be changed after construction. The + instances are cheap and the idea is to create them on demand. To + be able to reuse these as much as possible, a define for a + std::shared_ptr named BColorModifierSharedPtr exists below. + All usages should handle instances of BColorModifier encapsulated + into these shared pointers. + */ + class SAL_WARN_UNUSED BASEGFX_DLLPUBLIC BColorModifier + { + private: + BColorModifier(const BColorModifier&) = delete; + BColorModifier& operator=(const BColorModifier&) = delete; + protected: + // no one is allowed to incarnate the abstract base class + // except derivations + BColorModifier() {} + + public: + // no one should directly destroy it; all incarnations should be + // handled in a std::shared_ptr of type BColorModifierSharedPtr + virtual ~BColorModifier(); + + // compare operator + virtual bool operator==(const BColorModifier& rCompare) const = 0; + bool operator!=(const BColorModifier& rCompare) const + { + return !(operator==(rCompare)); + } + + // compute modified color + virtual ::basegfx::BColor getModifiedColor(const ::basegfx::BColor& aSourceColor) const = 0; + + virtual OUString getModifierName() const = 0; + }; + + /** convert color to gray + */ + class SAL_WARN_UNUSED BASEGFX_DLLPUBLIC BColorModifier_gray final : public BColorModifier + { + public: + BColorModifier_gray() + { + } + + virtual ~BColorModifier_gray() override; + + // compare operator + SAL_DLLPRIVATE virtual bool operator==(const BColorModifier& rCompare) const override; + + // compute modified color + SAL_DLLPRIVATE virtual ::basegfx::BColor getModifiedColor(const ::basegfx::BColor& aSourceColor) const override; + SAL_DLLPRIVATE virtual OUString getModifierName() const override; + }; + + /** invert color + + returns a color where red green and blue are inverted using 1.0 - n + */ + class SAL_WARN_UNUSED BASEGFX_DLLPUBLIC BColorModifier_invert final : public BColorModifier + { + public: + BColorModifier_invert() + { + } + + virtual ~BColorModifier_invert() override; + + // compare operator + SAL_DLLPRIVATE virtual bool operator==(const BColorModifier& rCompare) const override; + + // compute modified color + SAL_DLLPRIVATE virtual ::basegfx::BColor getModifiedColor(const ::basegfx::BColor& aSourceColor) const override; + SAL_DLLPRIVATE virtual OUString getModifierName() const override; + }; + + /** convert to alpha based on luminance + + returns a color where red green and blue are first weighted and added + to build a luminance value which is then inverted and used for red, + green and blue. The weights are r * 0.2125 + g * 0.7154 + b * 0.0721. + This derivation is used for the svg importer and does exactly what SVG + defines for this needed case. + */ + class SAL_WARN_UNUSED BASEGFX_DLLPUBLIC BColorModifier_luminance_to_alpha final : public BColorModifier + { + public: + BColorModifier_luminance_to_alpha() + { + } + + virtual ~BColorModifier_luminance_to_alpha() override; + + // compare operator + SAL_DLLPRIVATE virtual bool operator==(const BColorModifier& rCompare) const override; + + // compute modified color + SAL_DLLPRIVATE virtual ::basegfx::BColor getModifiedColor(const ::basegfx::BColor& aSourceColor) const override; + SAL_DLLPRIVATE virtual OUString getModifierName() const override; + }; + + /** replace color + + does not use the source color at all, but always returns the + given color, replacing everything. Useful e.g. for unified shadow + creation + */ + class SAL_WARN_UNUSED BASEGFX_DLLPUBLIC BColorModifier_replace final : public BColorModifier + { + private: + ::basegfx::BColor maBColor; + + public: + BColorModifier_replace(const ::basegfx::BColor& rBColor) + : maBColor(rBColor) + { + } + + virtual ~BColorModifier_replace() override; + + // data access + const ::basegfx::BColor& getBColor() const { return maBColor; } + + // compare operator + SAL_DLLPRIVATE virtual bool operator==(const BColorModifier& rCompare) const override; + + // compute modified color + SAL_DLLPRIVATE virtual ::basegfx::BColor getModifiedColor(const ::basegfx::BColor& aSourceColor) const override; + SAL_DLLPRIVATE virtual OUString getModifierName() const override; + }; + + /** interpolate color + + returns an interpolated color mixed by the given value (f) in the range + [0.0 .. 1.0] and the given color (col) as follows: + + col * (1 - f) + aSourceColor * f + */ + class SAL_WARN_UNUSED BASEGFX_DLLPUBLIC BColorModifier_interpolate final : public BColorModifier + { + private: + ::basegfx::BColor maBColor; + double mfValue; + + public: + BColorModifier_interpolate(const ::basegfx::BColor& rBColor, double fValue) + : maBColor(rBColor), + mfValue(fValue) + { + } + + virtual ~BColorModifier_interpolate() override; + + // compare operator + SAL_DLLPRIVATE virtual bool operator==(const BColorModifier& rCompare) const override; + + // compute modified color + SAL_DLLPRIVATE virtual ::basegfx::BColor getModifiedColor(const ::basegfx::BColor& aSourceColor) const override; + SAL_DLLPRIVATE virtual OUString getModifierName() const override; + }; + + /** Apply saturation + This derivation is used for the svg importer and does exactly what SVG + defines for this needed case. + + See: + https://www.w3.org/TR/filter-effects/#elementdef-fecolormatrix + */ + class SAL_WARN_UNUSED BASEGFX_DLLPUBLIC BColorModifier_saturate final : public BColorModifier + { + private: + basegfx::B3DHomMatrix maSatMatrix; + + public: + BColorModifier_saturate(double fValue); + + virtual ~BColorModifier_saturate() override; + + // compare operator + SAL_DLLPRIVATE virtual bool operator==(const BColorModifier& rCompare) const override; + + // compute modified color + SAL_DLLPRIVATE virtual ::basegfx::BColor getModifiedColor(const ::basegfx::BColor& aSourceColor) const override; + SAL_DLLPRIVATE virtual OUString getModifierName() const override; + }; + + /** Apply matrix + This derivation is used for the svg importer and does exactly what SVG + defines for this needed case. + + See: + https://www.w3.org/TR/filter-effects/#elementdef-fecolormatrix + */ + class SAL_WARN_UNUSED BASEGFX_DLLPUBLIC BColorModifier_matrix final : public BColorModifier + { + private: + std::vector maVector; + + public: + BColorModifier_matrix(std::vector aVector) + : maVector(aVector) + { + } + + virtual ~BColorModifier_matrix() override; + + // compare operator + SAL_DLLPRIVATE virtual bool operator==(const BColorModifier& rCompare) const override; + // compute modified color + SAL_DLLPRIVATE virtual ::basegfx::BColor getModifiedColor(const ::basegfx::BColor& aSourceColor) const override; + SAL_DLLPRIVATE virtual OUString getModifierName() const override; + }; + + /** Apply hueRotate + This derivation is used for the svg importer and does exactly what SVG + defines for this needed case. + + See: + https://www.w3.org/TR/filter-effects/#elementdef-fecolormatrix + */ + class SAL_WARN_UNUSED BASEGFX_DLLPUBLIC BColorModifier_hueRotate final : public BColorModifier + { + private: + basegfx::B3DHomMatrix maHueMatrix; + + public: + BColorModifier_hueRotate(double fRad); + + virtual ~BColorModifier_hueRotate() override; + + // compare operator + SAL_DLLPRIVATE virtual bool operator==(const BColorModifier& rCompare) const override; + + // compute modified color + SAL_DLLPRIVATE virtual ::basegfx::BColor getModifiedColor(const ::basegfx::BColor& aSourceColor) const override; + SAL_DLLPRIVATE virtual OUString getModifierName() const override; + }; + + /** convert color to black and white + + returns black when the luminance of the given color is less than + the given threshold value in the range [0.0 .. 1.0], else white + */ + class SAL_WARN_UNUSED BASEGFX_DLLPUBLIC BColorModifier_black_and_white final : public BColorModifier + { + private: + double mfValue; + + public: + BColorModifier_black_and_white(double fValue) + : mfValue(fValue) + { + } + + virtual ~BColorModifier_black_and_white() override; + + // compare operator + SAL_DLLPRIVATE virtual bool operator==(const BColorModifier& rCompare) const override; + + // compute modified color + SAL_DLLPRIVATE virtual ::basegfx::BColor getModifiedColor(const ::basegfx::BColor& aSourceColor) const override; + SAL_DLLPRIVATE virtual OUString getModifierName() const override; + }; + + /** gamma correction + + Input is a gamma correction value in the range ]0.0 .. 10.0]; the + color values get corrected using + + col(r,g,b) = clamp(pow(col(r,g,b), 1.0 / gamma), 0.0, 1.0) + */ + class SAL_WARN_UNUSED UNLESS_MERGELIBS(BASEGFX_DLLPUBLIC) BColorModifier_gamma final : public BColorModifier + { + private: + double mfValue; + double mfInvValue; + + bool mbUseIt : 1; + + public: + BColorModifier_gamma(double fValue); + + virtual ~BColorModifier_gamma() override; + + // compare operator + SAL_DLLPRIVATE virtual bool operator==(const BColorModifier& rCompare) const override; + + // compute modified color + virtual ::basegfx::BColor getModifiedColor(const ::basegfx::BColor& aSourceColor) const override; + SAL_DLLPRIVATE virtual OUString getModifierName() const override; + }; + + /** Red, Green, Blue, Luminance and Contrast correction + + Input are percent values from [-1.0 .. 1-0] which correspond to -100% to 100% + correction of Red, Green, Blue, Luminance or Contrast. 0.0 means no change of + the corresponding channel. All these are combined (but can be used single) to + - be able to cover a bigger change range utilizing the combination + - allow execution by a small, common, precalculated table + */ + class SAL_WARN_UNUSED UNLESS_MERGELIBS(BASEGFX_DLLPUBLIC) BColorModifier_RGBLuminanceContrast final : public BColorModifier + { + private: + double mfRed; + double mfGreen; + double mfBlue; + double mfLuminance; + double mfContrast; + + double mfContrastOff; + double mfRedOff; + double mfGreenOff; + double mfBlueOff; + + bool mbUseIt : 1; + + public: + BColorModifier_RGBLuminanceContrast(double fRed, double fGreen, double fBlue, double fLuminance, double fContrast); + + virtual ~BColorModifier_RGBLuminanceContrast() override; + + // compare operator + SAL_DLLPRIVATE virtual bool operator==(const BColorModifier& rCompare) const override; + + // compute modified color + SAL_DLLPRIVATE virtual ::basegfx::BColor getModifiedColor(const ::basegfx::BColor& aSourceColor) const override; + SAL_DLLPRIVATE virtual OUString getModifierName() const override; + }; + + /** mix a part of the original color with randomized color (mainly for debug visualizations) + */ + class SAL_WARN_UNUSED BASEGFX_DLLPUBLIC BColorModifier_randomize final : public BColorModifier + { + private: + // [0.0 .. 1.0] where 0.0 is no randomize, 1.0 is all random and in-between + // describes the mixed part. Default is 0.1 which means to mix with 10% random color + double mfRandomPart; + + public: + BColorModifier_randomize(double fRandomPart = 0.1); + + virtual ~BColorModifier_randomize() override; + + // compare operator + SAL_DLLPRIVATE virtual bool operator==(const BColorModifier& rCompare) const override; + + // compute modified color + SAL_DLLPRIVATE virtual ::basegfx::BColor getModifiedColor(const ::basegfx::BColor& aSourceColor) const override; + SAL_DLLPRIVATE virtual OUString getModifierName() const override; + }; + + /// typedef to allow working with shared instances of BColorModifier + /// for the whole mechanism + typedef std::shared_ptr< BColorModifier > BColorModifierSharedPtr; + + /** Class to hold a stack of BColorModifierSharedPtrs and to get the modified color with + applying all existing entry changes as defined in the stack. Instances of BColorModifier + can be pushed and popped to change the stack. + + All references to BColorModifier members use shared pointers, thus instances of + BColorModifierStack can be copied by the default mechanisms if needed. + */ + class BASEGFX_DLLPUBLIC BColorModifierStack final + { + ::std::vector< BColorModifierSharedPtr > maBColorModifiers; + + public: + sal_uInt32 count() const + { + return maBColorModifiers.size(); + } + + const BColorModifierSharedPtr& getBColorModifier(sal_uInt32 nIndex) const + { + OSL_ENSURE(nIndex < count(), "BColorModifierStack: Access out of range (!)"); + return maBColorModifiers[nIndex]; + } + + // get the color in its modified form by applying all existing BColorModifiers, + // from back to front (the newest first) + ::basegfx::BColor getModifiedColor(const ::basegfx::BColor& rSource) const; + + void push(const BColorModifierSharedPtr& rNew) + { + maBColorModifiers.push_back(rNew); + } + + void pop() + { + maBColorModifiers.pop_back(); + } + }; +} // end of namespace basegfx + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/include/basegfx/color/bcolortools.hxx b/include/basegfx/color/bcolortools.hxx new file mode 100644 index 0000000000..8af2b7c947 --- /dev/null +++ b/include/basegfx/color/bcolortools.hxx @@ -0,0 +1,43 @@ +/* -*- 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 . + */ + +#pragma once + +#include + +namespace basegfx +{ +class BColor; +} + +namespace basegfx::utils +{ +/// Transform from RGB to HSL +BASEGFX_DLLPUBLIC BColor rgb2hsl(const BColor& rRGBColor); +/// Transform from HSL to RGB +BASEGFX_DLLPUBLIC BColor hsl2rgb(const BColor& rHSLColor); + +/// Transform from RGB to HSV +BASEGFX_DLLPUBLIC BColor rgb2hsv(const BColor& rRGBColor); +/// Transform from HSV to RGB +BASEGFX_DLLPUBLIC BColor hsv2rgb(const BColor& rHSVColor); + +} // end of namespace basegfx + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/include/basegfx/curve/b2dbeziertools.hxx b/include/basegfx/curve/b2dbeziertools.hxx new file mode 100644 index 0000000000..b9c91fac0a --- /dev/null +++ b/include/basegfx/curve/b2dbeziertools.hxx @@ -0,0 +1,52 @@ +/* -*- 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 . + */ + +#pragma once + +#include +#include +#include + + +// predefines + +namespace basegfx +{ + class B2DCubicBezier; +} + + +namespace basegfx +{ + class BASEGFX_DLLPUBLIC B2DCubicBezierHelper + { + private: + ::std::vector< double > maLengthArray; + sal_uInt32 mnEdgeCount; + + public: + explicit B2DCubicBezierHelper(const B2DCubicBezier& rBase, sal_uInt32 nDivisions = 9); + + double getLength() const { if(!maLengthArray.empty()) return maLengthArray[maLengthArray.size() - 1]; else return 0.0; } + double distanceToRelative(double fDistance) const; + }; +} // end of namespace basegfx + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/include/basegfx/curve/b2dcubicbezier.hxx b/include/basegfx/curve/b2dcubicbezier.hxx new file mode 100644 index 0000000000..fe81ed523d --- /dev/null +++ b/include/basegfx/curve/b2dcubicbezier.hxx @@ -0,0 +1,201 @@ +/* -*- 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 . + */ + +#pragma once + +#include +#include +#include + +namespace basegfx +{ + class B2DPolygon; +} + +namespace basegfx +{ + class BASEGFX_DLLPUBLIC B2DCubicBezier + { + private: + B2DPoint maStartPoint; + B2DPoint maEndPoint; + B2DPoint maControlPointA; + B2DPoint maControlPointB; + + public: + B2DCubicBezier(); + B2DCubicBezier(const B2DCubicBezier& rBezier); + B2DCubicBezier(const B2DPoint& rStart, const B2DPoint& rControlPointA, const B2DPoint& rControlPointB, const B2DPoint& rEnd); + + // assignment operator + B2DCubicBezier& operator=(const B2DCubicBezier& rBezier); + + // compare operators + bool operator==(const B2DCubicBezier& rBezier) const; + bool operator!=(const B2DCubicBezier& rBezier) const; + bool equal(const B2DCubicBezier& rBezier) const; + + // test if vectors are used + bool isBezier() const; + + // test if contained bezier is trivial and reset vectors accordingly + void testAndSolveTrivialBezier(); + + /** get length of edge + + This method handles beziers and simple edges. For + beziers, the deviation describes the maximum allowed + deviation from the real edge length. The default + allows a deviation of 1% from the correct length. + + For beziers, there is no direct way to get the length, + thus this method may subdivide the bezier edge and may + not be cheap. + + @param fDeviation + The maximal allowed deviation between correct length + and bezier edge length + + @return + The length of the edge + */ + double getLength(double fDeviation = 0.01) const; + + // get distance between start and end point + SAL_DLLPRIVATE double getEdgeLength() const; + + // get length of control polygon + SAL_DLLPRIVATE double getControlPolygonLength() const; + + // data interface + const B2DPoint& getStartPoint() const { return maStartPoint; } + void setStartPoint(const B2DPoint& rValue) { maStartPoint = rValue; } + + const B2DPoint& getEndPoint() const { return maEndPoint; } + void setEndPoint(const B2DPoint& rValue) { maEndPoint = rValue; } + + const B2DPoint& getControlPointA() const { return maControlPointA; } + void setControlPointA(const B2DPoint& rValue) { maControlPointA = rValue; } + + const B2DPoint& getControlPointB() const { return maControlPointB; } + void setControlPointB(const B2DPoint& rValue) { maControlPointB = rValue; } + + /** get the tangent in point t + + This method handles all the exceptions, e.g. when control point + A is equal to start point and/or control point B is equal to end + point + + @param t + The bezier index in the range [0.0 .. 1.0]. It will be truncated. + + @return + The tangent vector in point t + */ + B2DVector getTangent(double t) const; + + /** adaptive subdivide by angle criteria + no start point is added, but all necessary created edges + and the end point + #i37443# allow the criteria to get unsharp in recursions + */ + SAL_DLLPRIVATE void adaptiveSubdivideByAngle(B2DPolygon& rTarget, double fAngleBound) const; + + /** #i37443# adaptive subdivide by nCount subdivisions + no start point is added, but all necessary created edges + and the end point + */ + SAL_DLLPRIVATE void adaptiveSubdivideByCount(B2DPolygon& rTarget, sal_uInt32 nCount) const; + + /** Subdivide cubic bezier segment. + + This function adaptively subdivides the bezier + segment into as much straight line segments as necessary, + such that the maximal orthogonal distance from any of the + segments to the true curve is less than the given error + value. + No start point is added, but all necessary created edges + and the end point + + @param rPoly + Output polygon. The subdivided bezier segment is added to + this polygon via B2DPolygon::append(). + + @param rCurve + The cubic bezier curve to subdivide + + @param fDistanceBound + Bound on the maximal distance of the approximation to the + true curve. + + @param nRecurseLimit + Bound on recursion for the bezier case. + */ + void adaptiveSubdivideByDistance(B2DPolygon& rTarget, double fDistanceBound, int nRecurseLimit = 30) const; + + // get point at given relative position + B2DPoint interpolatePoint(double t) const; + + // calculate the smallest distance from given point to this cubic bezier segment + // and return the value. The relative position on the segment is returned in rCut. + SAL_DLLPRIVATE double getSmallestDistancePointToBezierSegment(const B2DPoint& rTestPoint, double& rCut) const; + + // do a split at position t and fill both resulting segments + void split(double t, B2DCubicBezier* pBezierA, B2DCubicBezier* pBezierB) const; + + // extract snippet from fStart to fEnd from this bezier + SAL_DLLPRIVATE B2DCubicBezier snippet(double fStart, double fEnd) const; + + // get range including control points + B2DRange getRange() const; + + /** Get the minimum extremum position t + + @param rfResult + Will be changed and might possibly be set to a found split value, which should be in the + range [0.0 .. 1.0]. It will be the smallest current extremum; there may be more + + @return + Returns true if there was at least one extremum found + */ + SAL_DLLPRIVATE bool getMinimumExtremumPosition(double& rfResult) const; + + /** Get all extremum pos of this segment + + This method will calculate all extremum positions of the segment + and add them to rResults if they are in the range ]0.0 .. 1.0[ + + @param rResults + The vector of doubles where the results will be added. Evtl. + existing contents will be removed since an empty vector is a + necessary result to express that there are no extreme positions + anymore. Since there is an upper maximum of 4 values, it makes + sense to use reserve(4) at the vector as preparation. + */ + SAL_DLLPRIVATE void getAllExtremumPositions(::std::vector< double >& rResults) const; + + /// apply transformation given in matrix form + void transform(const basegfx::B2DHomMatrix& rMatrix); + + /// fround content + SAL_DLLPRIVATE void fround(); + }; +} // end of namespace basegfx + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/include/basegfx/matrix/b2dhommatrix.hxx b/include/basegfx/matrix/b2dhommatrix.hxx new file mode 100644 index 0000000000..8067b8e1c6 --- /dev/null +++ b/include/basegfx/matrix/b2dhommatrix.hxx @@ -0,0 +1,158 @@ +/* -*- 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 . + */ + +#pragma once + +#include + +#include + +#include +#include +#include + +namespace basegfx +{ + class B2DTuple; + + class SAL_WARN_UNUSED BASEGFX_DLLPUBLIC B2DHomMatrix + { + private: + // Since this is a graphics matrix, the last row is always 0 0 1, so we don't bother to store it. + std::array, 2> mfValues { + std::array{ 1.0, 0.0, 0.0 }, + std::array{ 0.0, 1.0, 0.0 } }; + + public: + constexpr B2DHomMatrix() = default; + + /** constructor to allow setting all needed values for a 3x2 matrix at once. The + parameter f_0x1 e.g. is the same as using set(0, 1, f) + */ + constexpr B2DHomMatrix(double f_0x0, double f_0x1, double f_0x2, double f_1x0, double f_1x1, double f_1x2) + { + mfValues[0][0] = f_0x0; + mfValues[0][1] = f_0x1; + mfValues[0][2] = f_0x2; + mfValues[1][0] = f_1x0; + mfValues[1][1] = f_1x1; + mfValues[1][2] = f_1x2; + } + + /** Convenience creator for declaration of the matrix that is commonly + used by web standards (SVG, CSS, HTML). + + Values a,b,c,d,e,f represent the following values in the matrix: + [a,c,e] [a,c,e] + [b,d,f] or [b,d,f] + [0,0,1] + + */ + static B2DHomMatrix abcdef(double da, double db, double dc, double dd, double de, double df) + { + return B2DHomMatrix(da, dc, de, db, dd, df); + } + + // Convenience accessor for value at 0,0 position in the matrix + double a() const { return get(0,0); } + // Convenience accessor for value at 1,0 position in the matrix + double b() const { return get(1,0); } + // Convenience accessor for value at 0,1 position in the matrix + double c() const { return get(0,1); } + // Convenience accessor for value at 1,1 position in the matrix + double d() const { return get(1,1); } + // Convenience accessor for value at 0,2 position in the matrix + double e() const { return get(0,2); } + // Convenience accessor for value at 1,2 position in the matrix + double f() const { return get(1,2); } + + double get(sal_uInt16 nRow, sal_uInt16 nColumn) const + { + return mfValues[nRow][nColumn]; + } + + void set(sal_uInt16 nRow, sal_uInt16 nColumn, double fValue) + { + mfValues[nRow][nColumn] = fValue; + } + + /** allow setting all needed values for a 3x2 matrix in one call. The + parameter f_0x1 e.g. is the same as using set(0, 1, f) + */ + void set3x2(double f_0x0, double f_0x1, double f_0x2, double f_1x0, double f_1x1, double f_1x2); + + // reset to a standard matrix + bool isIdentity() const; + void identity(); + + bool isInvertible() const; + bool invert(); + + void rotate(double fRadiant); + + void translate(double fX, double fY); + void translate(const B2DTuple& rTuple); + + void scale(double fX, double fY); + void scale(const B2DTuple& rTuple); + + // Shearing-Matrices + void shearX(double fSx); + void shearY(double fSy); + + bool operator==(const B2DHomMatrix& rMat) const; + bool operator!=(const B2DHomMatrix& rMat) const; + + // matrix multiplication from the left to the local + B2DHomMatrix& operator*=(const B2DHomMatrix& rMat); + + /** + * Help routine to decompose given homogen 3x3 matrix to components. A correction of the + * components is done to avoid inaccuracies. + * + * See basegfx::utils::createScaleShearXRotateTranslateB2DHomMatrix() for the opposite, to + * compose a homogen 3x3 matrix from components. + */ + bool decompose(B2DTuple& rScale, B2DTuple& rTranslate, double& rRotate, double& rShearX) const; + + private: + void computeAdjoint(double (&dst)[6]) const; + double computeDeterminant(double (&dst)[6]) const; + void doMulMatrix(const B2DHomMatrix& rMat); + }; + + inline B2DHomMatrix operator*(const B2DHomMatrix& rMatA, const B2DHomMatrix& rMatB) + { + B2DHomMatrix aMul(rMatB); + aMul *= rMatA; + return aMul; + } + + template + std::basic_ostream & operator <<( + std::basic_ostream & stream, B2DHomMatrix const & matrix) + { + return stream + << '[' << matrix.get(0, 0) << ' ' << matrix.get(0, 1) << ' ' + << matrix.get(0, 2) << "; " << matrix.get(1, 0) << ' ' + << matrix.get(1, 1) << ' ' << matrix.get(1, 2) << ']'; + } +} // end of namespace basegfx + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/include/basegfx/matrix/b2dhommatrixtools.hxx b/include/basegfx/matrix/b2dhommatrixtools.hxx new file mode 100644 index 0000000000..9b81f33d2a --- /dev/null +++ b/include/basegfx/matrix/b2dhommatrixtools.hxx @@ -0,0 +1,218 @@ +/* -*- 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 . + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +namespace basegfx { class B2DRange; } + +namespace basegfx::utils +{ + /** If the rotation angle is an approximate multiple of pi/2, + force fSin/fCos to -1/0/1, to maintain orthogonality (which + might also be advantageous for the other cases, but: for + multiples of pi/2, the exact values _can_ be attained. It + would be largely unintuitive, if a 180 degrees rotation + would introduce slight roundoff errors, instead of exactly + mirroring the coordinate system) + */ + void createSinCosOrthogonal(double& o_rSin, double& rCos, double fRadiant); + + /** Tooling methods for on-the-fly matrix generation e.g. for inline + multiplications + */ + BASEGFX_DLLPUBLIC B2DHomMatrix createScaleB2DHomMatrix(double fScaleX, double fScaleY); + BASEGFX_DLLPUBLIC B2DHomMatrix createShearXB2DHomMatrix(double fShearX); + BASEGFX_DLLPUBLIC B2DHomMatrix createShearYB2DHomMatrix(double fShearY); + BASEGFX_DLLPUBLIC B2DHomMatrix createRotateB2DHomMatrix(double fRadiant); + BASEGFX_DLLPUBLIC B2DHomMatrix createTranslateB2DHomMatrix(double fTranslateX, double fTranslateY); + + /// inline versions for parameters as tuples + inline B2DHomMatrix createScaleB2DHomMatrix(const B2DTuple& rScale) + { + return createScaleB2DHomMatrix(rScale.getX(), rScale.getY()); + } + + inline B2DHomMatrix createTranslateB2DHomMatrix(const B2DTuple& rTranslate) + { + return createTranslateB2DHomMatrix(rTranslate.getX(), rTranslate.getY()); + } + + /** Tooling methods for faster completely combined matrix creation + when scale, shearX, rotation and translation needs to be done in + exactly that order. It's faster since it directly calculates + each matrix value based on a symbolic calculation of the three + matrix multiplications. + Inline versions for parameters as tuples added, too. + */ + BASEGFX_DLLPUBLIC B2DHomMatrix createScaleShearXRotateTranslateB2DHomMatrix( + double fScaleX, double fScaleY, + double fShearX, + double fRadiant, + double fTranslateX, double fTranslateY); + inline B2DHomMatrix createScaleShearXRotateTranslateB2DHomMatrix( + const B2DTuple& rScale, + double fShearX, + double fRadiant, + const B2DTuple& rTranslate) + { + return createScaleShearXRotateTranslateB2DHomMatrix( + rScale.getX(), rScale.getY(), + fShearX, + fRadiant, + rTranslate.getX(), rTranslate.getY()); + } + + BASEGFX_DLLPUBLIC B2DHomMatrix createShearXRotateTranslateB2DHomMatrix( + double fShearX, + double fRadiant, + double fTranslateX, double fTranslateY); + inline B2DHomMatrix createShearXRotateTranslateB2DHomMatrix( + double fShearX, + double fRadiant, + const B2DTuple& rTranslate) + { + return createShearXRotateTranslateB2DHomMatrix( + fShearX, + fRadiant, + rTranslate.getX(), rTranslate.getY()); + } + + BASEGFX_DLLPUBLIC B2DHomMatrix createScaleTranslateB2DHomMatrix( + double fScaleX, double fScaleY, + double fTranslateX, double fTranslateY); + inline B2DHomMatrix createScaleTranslateB2DHomMatrix( + const B2DTuple& rScale, + const B2DTuple& rTranslate) + { + return createScaleTranslateB2DHomMatrix( + rScale.getX(), rScale.getY(), + rTranslate.getX(), rTranslate.getY()); + } + + /// special for the often used case of rotation around a point + BASEGFX_DLLPUBLIC B2DHomMatrix createRotateAroundPoint( + double fPointX, double fPointY, + double fRadiant); + inline B2DHomMatrix createRotateAroundPoint( + const B2DTuple& rPoint, + double fRadiant) + { + return createRotateAroundPoint( + rPoint.getX(), rPoint.getY(), + fRadiant); + } + + /// special for creating a mapping for a Range rotated around it's center + /// while keeping AspectRatio unchanged and staying inside the given Range + /// by optimally using the available space (no overlap or outside allowed) + B2DHomMatrix createRotateAroundCenterKeepAspectRatioStayInsideRange( + const basegfx::B2DRange& rTargetRange, + double fRotate); + + /// special for the case to map from source range to target range + BASEGFX_DLLPUBLIC B2DHomMatrix createSourceRangeTargetRangeTransform( + const B2DRange& rSourceRange, + const B2DRange& rTargetRange); + + /// create based on given CoordinateSystem which is defined by origin and x/yaxis + BASEGFX_DLLPUBLIC B2DHomMatrix createCoordinateSystemTransform( + const B2DPoint& rOrigin, + const B2DVector& rX, + const B2DVector& rY); + + /// get column vector from B2dHomMatrix, e.g. to extract coordinate system origin and x/yaxis + BASEGFX_DLLPUBLIC B2DTuple getColumn(const B2DHomMatrix& rMatrix, sal_uInt16 nCol); + + + class BASEGFX_DLLPUBLIC B2DHomMatrixBufferedDecompose + { + private: + B2DVector maScale; + B2DVector maTranslate; + double mfRotate; + double mfShearX; + + public: + B2DHomMatrixBufferedDecompose(const B2DHomMatrix& rB2DHomMatrix = B2DHomMatrix()) + : mfRotate(0.0), + mfShearX(0.0) + { + rB2DHomMatrix.decompose(maScale, maTranslate, mfRotate, mfShearX); + } + + // data access + B2DHomMatrix getB2DHomMatrix() const + { + return createScaleShearXRotateTranslateB2DHomMatrix( + maScale, mfShearX, mfRotate, maTranslate); + } + + const B2DVector& getScale() const { return maScale; } + const B2DVector& getTranslate() const { return maTranslate; } + double getRotate() const { return mfRotate; } + double getShearX() const { return mfShearX; } + }; + + class BASEGFX_DLLPUBLIC B2DHomMatrixBufferedOnDemandDecompose + { + private: + B2DHomMatrix maB2DHomMatrix; + B2DVector maScale; + B2DVector maTranslate; + double mfRotate; + double mfShearX; + + bool mbDecomposed : 1; + + void impCheckDecompose() + { + if(!mbDecomposed) + { + maB2DHomMatrix.decompose(maScale, maTranslate, mfRotate, mfShearX); + mbDecomposed = true; + } + } + + public: + B2DHomMatrixBufferedOnDemandDecompose(B2DHomMatrix aB2DHomMatrix = B2DHomMatrix()) + : maB2DHomMatrix(std::move(aB2DHomMatrix)), + mfRotate(0.0), + mfShearX(0.0), + mbDecomposed(false) + { + } + + // data access + const B2DHomMatrix& getB2DHomMatrix() const { return maB2DHomMatrix; } + const B2DVector& getScale() const { const_cast< B2DHomMatrixBufferedOnDemandDecompose* >(this)->impCheckDecompose(); return maScale; } + const B2DVector& getTranslate() const { const_cast< B2DHomMatrixBufferedOnDemandDecompose* >(this)->impCheckDecompose(); return maTranslate; } + double getRotate() const { const_cast< B2DHomMatrixBufferedOnDemandDecompose* >(this)->impCheckDecompose(); return mfRotate; } + double getShearX() const { const_cast< B2DHomMatrixBufferedOnDemandDecompose* >(this)->impCheckDecompose(); return mfShearX; } + }; +} // end of namespace basegfx::utils + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/include/basegfx/matrix/b3dhommatrix.hxx b/include/basegfx/matrix/b3dhommatrix.hxx new file mode 100644 index 0000000000..29603f88eb --- /dev/null +++ b/include/basegfx/matrix/b3dhommatrix.hxx @@ -0,0 +1,127 @@ +/* -*- 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 . + */ + +#pragma once + +#include +#include +#include +#include +#include + +namespace basegfx +{ + class B3DTuple; + class Impl3DHomMatrix; + + class BASEGFX_DLLPUBLIC B3DHomMatrix + { + public: + typedef o3tl::cow_wrapper< Impl3DHomMatrix, o3tl::ThreadSafeRefCountingPolicy > ImplType; + + private: + ImplType mpImpl; + + public: + B3DHomMatrix(); + B3DHomMatrix(const B3DHomMatrix& rMat); + B3DHomMatrix(B3DHomMatrix&& rMat); + ~B3DHomMatrix(); + + double get(sal_uInt16 nRow, sal_uInt16 nColumn) const; + void set(sal_uInt16 nRow, sal_uInt16 nColumn, double fValue); + + // test if last line is default to see if last line needs to be + // involved in calculations + bool isLastLineDefault() const; + + bool isIdentity() const; + /// Reset to the identity matrix + void identity(); + + /// Invert the matrix (if possible) + void invert(); + + /// Calc the matrix determinant + double determinant() const; + + /// Rotation + void rotate(double fAngleX,double fAngleY,double fAngleZ); + void rotate(const B3DTuple& rRotation); + + /// Translation + void translate(double fX, double fY, double fZ); + void translate(const B3DTuple& rTranslation); + + /// Scaling + void scale(double fX, double fY, double fZ); + void scale(const B3DTuple& rScale); + + // Shearing-Matrices + void shearXY(double fSx, double fSy); + void shearXZ(double fSx, double fSz); + + // Projection matrices, used for converting between eye and + // clip coordinates + void frustum(double fLeft = -1.0, double fRight = 1.0, + double fBottom = -1.0, double fTop = 1.0, + double fNear = 0.001, double fFar = 1.0); + + void ortho(double fLeft = -1.0, double fRight = 1.0, + double fBottom = -1.0, double fTop = 1.0, + double fNear = 0.0, double fFar = 1.0); + + // build orientation matrix + void orientation( + const B3DPoint& rVRP = B3DPoint(0.0,0.0,1.0), + B3DVector aVPN = B3DVector(0.0,0.0,1.0), + B3DVector aVUV = B3DVector(0.0,1.0,0.0)); + + // addition, subtraction + B3DHomMatrix& operator+=(const B3DHomMatrix& rMat); + B3DHomMatrix& operator-=(const B3DHomMatrix& rMat); + + // comparison + bool operator==(const B3DHomMatrix& rMat) const; + bool operator!=(const B3DHomMatrix& rMat) const; + + // multiplication, division by constant value + B3DHomMatrix& operator*=(double fValue); + B3DHomMatrix& operator/=(double fValue); + + // matrix multiplication (from the left) + B3DHomMatrix& operator*=(const B3DHomMatrix& rMat); + + // assignment operator + B3DHomMatrix& operator=(const B3DHomMatrix& rMat); + B3DHomMatrix& operator=(B3DHomMatrix&& rMat); + + // decomposition + void decompose(B3DTuple& rScale, B3DTuple& rTranslate, B3DTuple& rRotate, B3DTuple& rShear) const; + }; + + inline B3DHomMatrix operator*(const B3DHomMatrix& rMatA, const B3DHomMatrix& rMatB) + { + B3DHomMatrix aMul(rMatB); + aMul *= rMatA; + return aMul; + } +} // end of namespace basegfx + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/include/basegfx/matrix/b3dhommatrixtools.hxx b/include/basegfx/matrix/b3dhommatrixtools.hxx new file mode 100644 index 0000000000..6b65d24603 --- /dev/null +++ b/include/basegfx/matrix/b3dhommatrixtools.hxx @@ -0,0 +1,44 @@ +/* -*- 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 . + */ + +#pragma once + +#include +#include + +namespace com::sun::star::drawing +{ +struct HomogenMatrix; +} + +namespace basegfx::utils +{ +/* tooling methods for converting API matrices (drawing::HomogenMatrix) to + B3DHomMatrix. drawing::HomogenMatrix4 is not used by OOo + */ +BASEGFX_DLLPUBLIC B3DHomMatrix +UnoHomogenMatrixToB3DHomMatrix(const com::sun::star::drawing::HomogenMatrix& rMatrixIn); + +BASEGFX_DLLPUBLIC void +B3DHomMatrixToUnoHomogenMatrix(const B3DHomMatrix& rMatrixIn, + com::sun::star::drawing::HomogenMatrix& rMatrixOut); + +} // end of namespace basegfx::tools + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/include/basegfx/matrix/hommatrixtemplate.hxx b/include/basegfx/matrix/hommatrixtemplate.hxx new file mode 100644 index 0000000000..4f1300f533 --- /dev/null +++ b/include/basegfx/matrix/hommatrixtemplate.hxx @@ -0,0 +1,427 @@ +/* -*- 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 . + */ + +#pragma once + +#include +#include +#include + +namespace basegfx::internal + { + + inline constexpr double implGetDefaultValue(sal_uInt16 nRow, sal_uInt16 nColumn) + { + if(nRow == nColumn) + return 1.0; + return 0.0; + } + + template < sal_uInt16 RowSize > class ImplMatLine + { + double mfValue[RowSize]; + + public: + ImplMatLine() = default; + + explicit ImplMatLine(sal_uInt16 nRow) + { + for(sal_uInt16 a(0); a < RowSize; a++) + { + mfValue[a] = implGetDefaultValue(nRow, a); + } + } + + double get(sal_uInt16 nColumn) const + { + return mfValue[nColumn]; + } + + void set(sal_uInt16 nColumn, const double& rValue) + { + mfValue[nColumn] = rValue; + } + }; + + template < sal_uInt16 RowSize > class ImplHomMatrixTemplate + { + ImplMatLine< RowSize > maLine[RowSize]; + + public: + // Is last line used? + bool isLastLineDefault() const + { + for(sal_uInt16 a(0); a < RowSize; a++) + { + const double fDefault(implGetDefaultValue((RowSize - 1), a)); + const double fLineValue(maLine[RowSize-1].get(a)); + + if(fDefault != fLineValue) + { + return false; + } + } + return true; + } + + ImplHomMatrixTemplate() + { + // complete initialization with identity matrix, all lines + // were initialized with a trailing 1 followed by 0's. + for(sal_uInt16 a(0); a < RowSize; a++) + { + for(sal_uInt16 b(0); b < RowSize; b++) + maLine[a].set(b, implGetDefaultValue(a, b) ); + } + } + + ImplHomMatrixTemplate(const ImplHomMatrixTemplate& rToBeCopied) + { + operator=(rToBeCopied); + } + + ImplHomMatrixTemplate& operator=(const ImplHomMatrixTemplate& rToBeCopied) + { + if (this != &rToBeCopied) + { + // complete initialization using copy + for(sal_uInt16 a(0); a < RowSize; a++) + { + maLine[a] = rToBeCopied.maLine[a]; + } + } + return *this; + } + + static sal_uInt16 getEdgeLength() { return RowSize; } + + double get(sal_uInt16 nRow, sal_uInt16 nColumn) const + { + return maLine[nRow].get(nColumn); + } + + void set(sal_uInt16 nRow, sal_uInt16 nColumn, const double& rValue) + { + maLine[nRow].set(nColumn, rValue); + } + + // Left-upper decomposition + bool ludcmp(sal_uInt16 nIndex[], sal_Int16& nParity) + { + double fBig, fSum, fDum; + double fStorage[RowSize]; + sal_uInt16 a, b, c; + + // #i30874# Initialize nAMax (compiler warns) + sal_uInt16 nAMax = 0; + + nParity = 1; + + // Calc the max of each line. If a line is empty, + // stop immediately since matrix is not invertible then. + for(a = 0; a < RowSize; a++) + { + fBig = 0.0; + + for(b = 0; b < RowSize; b++) + { + double fTemp(fabs(get(a, b))); + + if(::basegfx::fTools::more(fTemp, fBig)) + { + fBig = fTemp; + } + } + + if(::basegfx::fTools::equalZero(fBig)) + { + return false; + } + + fStorage[a] = 1.0 / fBig; + } + + // start normalizing + for(b = 0; b < RowSize; b++) + { + for(a = 0; a < b; a++) + { + fSum = get(a, b); + + for(c = 0; c < a; c++) + { + fSum -= get(a, c) * get(c, b); + } + + set(a, b, fSum); + } + + fBig = 0.0; + + for(a = b; a < RowSize; a++) + { + fSum = get(a, b); + + for(c = 0; c < b; c++) + { + fSum -= get(a, c) * get(c, b); + } + + set(a, b, fSum); + fDum = fStorage[a] * fabs(fSum); + + if(::basegfx::fTools::moreOrEqual(fDum, fBig)) + { + fBig = fDum; + nAMax = a; + } + } + + if(b != nAMax) + { + for(c = 0; c < RowSize; c++) + { + fDum = get(nAMax, c); + set(nAMax, c, get(b, c)); + set(b, c, fDum); + } + + nParity = -nParity; + fStorage[nAMax] = fStorage[b]; + } + + nIndex[b] = nAMax; + + // here the failure of precision occurs + const double fValBB(fabs(get(b, b))); + + if(::basegfx::fTools::equalZero(fValBB)) + { + return false; + } + + if(b != (RowSize - 1)) + { + fDum = 1.0 / get(b, b); + + for(a = b + 1; a < RowSize; a++) + { + set(a, b, get(a, b) * fDum); + } + } + } + + return true; + } + + void lubksb(const sal_uInt16 nIndex[], double fRow[]) const + { + sal_uInt16 b, ip; + sal_Int16 a, a2 = -1; + double fSum; + + for(a = 0; a < RowSize; a++) + { + ip = nIndex[a]; + fSum = fRow[ip]; + fRow[ip] = fRow[a]; + + if(a2 >= 0) + { + for(b = a2; b < a; b++) + { + fSum -= get(a, b) * fRow[b]; + } + } + else if(!::basegfx::fTools::equalZero(fSum)) + { + a2 = a; + } + + fRow[a] = fSum; + } + + for(a = (RowSize - 1); a >= 0; a--) + { + fSum = fRow[a]; + + for(b = a + 1; b < RowSize; b++) + { + fSum -= get(a, b) * fRow[b]; + } + + const double fValueAA(get(a, a)); + + if(!::basegfx::fTools::equalZero(fValueAA)) + { + fRow[a] = fSum / get(a, a); + } + } + } + + bool isIdentity() const + { + for(sal_uInt16 a(0); a < RowSize; a++) + { + for(sal_uInt16 b(0); b < RowSize; b++) + { + const double fDefault(implGetDefaultValue(a, b)); + const double fValueAB(get(a, b)); + + if(!::basegfx::fTools::equal(fDefault, fValueAB)) + { + return false; + } + } + } + + return true; + } + + bool isInvertible() const + { + ImplHomMatrixTemplate aWork(*this); + sal_uInt16 nIndex[RowSize]; + sal_Int16 nParity; + + return aWork.ludcmp(nIndex, nParity); + } + + void doInvert(const ImplHomMatrixTemplate& rWork, const sal_uInt16 nIndex[]) + { + double fArray[RowSize]; + + for(sal_uInt16 a(0); a < RowSize; a++) + { + // prepare line + sal_uInt16 b; + for( b = 0; b < RowSize; b++) + { + fArray[b] = implGetDefaultValue(a, b); + } + + // expand line + rWork.lubksb(nIndex, fArray); + + // copy line transposed to this matrix + for( b = 0; b < RowSize; b++) + { + set(b, a, fArray[b]); + } + } + } + + double doDeterminant() const + { + ImplHomMatrixTemplate aWork(*this); + sal_uInt16 nIndex[RowSize]; + sal_Int16 nParity; + double fRetval(0.0); + + if(aWork.ludcmp(nIndex, nParity)) + { + fRetval = static_cast(nParity); + for(sal_uInt16 a(0); a < RowSize; a++) + { + fRetval *= aWork.get(a, a); + } + } + + return fRetval; + } + + void doAddMatrix(const ImplHomMatrixTemplate& rMat) + { + for(sal_uInt16 a(0); a < RowSize; a++) + { + for(sal_uInt16 b(0); b < RowSize; b++) + { + set(a, b, get(a, b) + rMat.get(a, b)); + } + } + } + + void doSubMatrix(const ImplHomMatrixTemplate& rMat) + { + for(sal_uInt16 a(0); a < RowSize; a++) + { + for(sal_uInt16 b(0); b < RowSize; b++) + { + set(a, b, get(a, b) - rMat.get(a, b)); + } + } + } + + void doMulMatrix(const double& rfValue) + { + for(sal_uInt16 a(0); a < RowSize; a++) + { + for(sal_uInt16 b(0); b < RowSize; b++) + { + set(a, b, get(a, b) * rfValue); + } + } + } + + void doMulMatrix(const ImplHomMatrixTemplate& rMat) + { + // create a copy as source for the original values + const ImplHomMatrixTemplate aCopy(*this); + + // TODO: maybe optimize cases where last line is [0 0 1]. + + double fValue(0.0); + + for(sal_uInt16 a(0); a < RowSize; ++a) + { + for(sal_uInt16 b(0); b < RowSize; ++b) + { + fValue = 0.0; + + for(sal_uInt16 c(0); c < RowSize; ++c) + fValue += aCopy.get(c, b) * rMat.get(a, c); + + set(a, b, fValue); + } + } + } + + bool isEqual(const ImplHomMatrixTemplate& rMat) const + { + for(sal_uInt16 a(0); a < RowSize; a++) + { + for(sal_uInt16 b(0); b < RowSize; b++) + { + const double fValueA(get(a, b)); + const double fValueB(rMat.get(a, b)); + + if(!::basegfx::fTools::equal(fValueA, fValueB)) + { + return false; + } + } + } + + return true; + } + }; + +} // namespace basegfx::internal + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/include/basegfx/numeric/ftools.hxx b/include/basegfx/numeric/ftools.hxx new file mode 100644 index 0000000000..1e7f0a34e7 --- /dev/null +++ b/include/basegfx/numeric/ftools.hxx @@ -0,0 +1,213 @@ +/* -*- 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 . + */ + +#pragma once + +#include +#include +#include +#include +#include +#include + + +// fTools defines + +namespace basegfx +{ + /** Round double to nearest integer + + @return the nearest integer + */ + inline sal_Int32 fround( double fVal ) + { + if (fVal >= 0.0) + { + if (fVal >= std::numeric_limits::max() - .5) + return std::numeric_limits::max(); + return static_cast(fVal + .5); + } + if (fVal <= std::numeric_limits::min() + .5) + return std::numeric_limits::min(); + return static_cast(fVal - .5); + } + + /** Round double to nearest integer + + @return the nearest 64 bit integer + */ + inline sal_Int64 fround64( double fVal ) + { + return fVal > 0.0 ? static_cast( fVal + .5 ) : -static_cast( -fVal + .5 ); + } + + /** Prune a small epsilon range around zero. + + Use this method e.g. for calculating scale values. There, it + is usually advisable not to set a scaling to 0.0, because that + yields singular transformation matrices. + + @param fVal + An arbitrary, but finite and valid number + + @return either fVal, or a small value slightly above (when + fVal>0) or below (when fVal<0) zero. + */ + inline double pruneScaleValue( double fVal ) + { + if(fVal < 0.0) + return std::min(fVal, -0.00001); + else + return std::max(fVal, 0.00001); + } + + /** Convert value from degrees to radians + */ + template constexpr double deg2rad( double v ) + { + // divide first, to get exact values for v being a multiple of + // 90 degrees + return v / (90.0 * DegMultiple) * M_PI_2; + } + + /** Convert value radians to degrees + */ + template constexpr double rad2deg( double v ) + { + // divide first, to get exact values for v being a multiple of + // pi/2 + return v / M_PI_2 * (90.0 * DegMultiple); + } + + /** Snap v to nearest multiple of fStep, from negative and + positive side. + + Examples: + + snapToNearestMultiple(-0.1, 0.5) = 0.0 + snapToNearestMultiple(0.1, 0.5) = 0.0 + snapToNearestMultiple(0.25, 0.5) = 0.0 + snapToNearestMultiple(0.26, 0.5) = 0.5 + */ + BASEGFX_DLLPUBLIC double snapToNearestMultiple(double v, const double fStep); + + /** Snap v to the range [0.0 .. fWidth] using modulo + */ + BASEGFX_DLLPUBLIC double snapToZeroRange(double v, double fWidth); + + /** Snap v to the range [fLow .. fHigh] using modulo + */ + double snapToRange(double v, double fLow, double fHigh); + + /** return fValue with the sign of fSignCarrier, thus evtl. changed + */ + inline double copySign(double fValue, double fSignCarrier) + { +#ifdef _WIN32 + return _copysign(fValue, fSignCarrier); +#else + return copysign(fValue, fSignCarrier); +#endif + } + + /** RotateFlyFrame3: Normalize to range defined by [0.0 ... fRange[, independent + if v is positive or negative. + + Examples: + + normalizeToRange(0.5, -1.0) = 0.0 + normalizeToRange(0.5, 0.0) = 0.0 + normalizeToRange(0.5, 1.0) = 0.5 + normalizeToRange(-0.5, 1.0) = 0.5 + normalizeToRange(-0.3, 1.0) = 0.7 + normalizeToRange(-0.7, 1.0) = 0.3 + normalizeToRange(3.5, 1.0) = 0.5 + normalizeToRange(3.3, 1.0) = 0.3 + normalizeToRange(3.7, 1.0) = 0.7 + normalizeToRange(-3.5, 1.0) = 0.5 + normalizeToRange(-3.3, 1.0) = 0.7 + normalizeToRange(-3.7, 1.0) = 0.3 + */ + BASEGFX_DLLPUBLIC double normalizeToRange(double v, const double fRange); + + namespace fTools + { + /// Get threshold value for equalZero and friends + inline double getSmallValue() { return 0.000000001f; } + + /// Compare against small value + template , int> = 0> + inline bool equalZero(const T& rfVal) + { + return (fabs(rfVal) <= getSmallValue()); + } + + /// Compare against given small value + template , int> = 0> + inline bool equalZero(const T& rfVal, const T& rfSmallValue) + { + return (fabs(rfVal) <= rfSmallValue); + } + + template , int> = 0> + inline bool equal(T const& rfValA, T const& rfValB) + { + // changed to approxEqual usage for better numerical correctness + return rtl_math_approxEqual(rfValA, rfValB); + } + + template , int> = 0> + inline bool equal(const T& rfValA, const T& rfValB, const T& rfSmallValue) + { + return (fabs(rfValA - rfValB) <= rfSmallValue); + } + + template , int> = 0> + inline bool less(const T& rfValA, const T& rfValB) + { + return (rfValA < rfValB && !equal(rfValA, rfValB)); + } + + template , int> = 0> + inline bool lessOrEqual(const T& rfValA, const T& rfValB) + { + return (rfValA < rfValB || equal(rfValA, rfValB)); + } + + template , int> = 0> + inline bool more(const T& rfValA, const T& rfValB) + { + return (rfValA > rfValB && !equal(rfValA, rfValB)); + } + + template , int> = 0> + inline bool moreOrEqual(const T& rfValA, const T& rfValB) + { + return (rfValA > rfValB || equal(rfValA, rfValB)); + } + + template , int> = 0> + inline bool betweenOrEqualEither(const T& rfValA, const T& rfValB, const T& rfValC) + { + return (rfValA > rfValB && rfValA < rfValC) || equal(rfValA, rfValB) || equal(rfValA, rfValC); + } + }; +} // end of namespace basegfx + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/include/basegfx/pixel/bpixel.hxx b/include/basegfx/pixel/bpixel.hxx new file mode 100644 index 0000000000..50209ec2ce --- /dev/null +++ b/include/basegfx/pixel/bpixel.hxx @@ -0,0 +1,98 @@ +/* -*- 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 . + */ + +#pragma once + +#include +#include + +namespace basegfx +{ + class BPixel final + { + union + { + struct + { + unsigned mnR : 8; // red intensity + unsigned mnG : 8; // green intensity + unsigned mnB : 8; // blue intensity + unsigned mnA : 8; // opacity, 0 == full transparence + } maRGBA; + + struct + { + unsigned mnValue : 32; // all values + } maCombinedRGBA; + } maPixelUnion; + + public: + BPixel() + { + maPixelUnion.maCombinedRGBA.mnValue = 0; + } + + // use explicit here to make sure everyone knows what he is doing. Values range from + // 0..255 integer here. + explicit BPixel(sal_uInt8 nRed, sal_uInt8 nGreen, sal_uInt8 nBlue, sal_uInt8 nAlpha) + { + maPixelUnion.maRGBA.mnR = nRed; + maPixelUnion.maRGBA.mnG = nGreen; + maPixelUnion.maRGBA.mnB = nBlue; + maPixelUnion.maRGBA.mnA = nAlpha; + } + + // constructor from BColor which uses double precision color, so change it + // to local integer format. It will also be clamped here. + BPixel(const BColor& rColor, sal_uInt8 nAlpha) + { + maPixelUnion.maRGBA.mnR = sal_uInt8((rColor.getRed() * 255.0) + 0.5); + maPixelUnion.maRGBA.mnG = sal_uInt8((rColor.getGreen() * 255.0) + 0.5); + maPixelUnion.maRGBA.mnB = sal_uInt8((rColor.getBlue() * 255.0) + 0.5); + maPixelUnion.maRGBA.mnA = nAlpha; + } + + // data access read + sal_uInt8 getRed() const { return maPixelUnion.maRGBA.mnR; } + sal_uInt8 getGreen() const { return maPixelUnion.maRGBA.mnG; } + sal_uInt8 getBlue() const { return maPixelUnion.maRGBA.mnB; } + sal_uInt8 getAlpha() const { return maPixelUnion.maRGBA.mnA; } + + // data access write + void setRed(sal_uInt8 nNew) { maPixelUnion.maRGBA.mnR = nNew; } + void setGreen(sal_uInt8 nNew) { maPixelUnion.maRGBA.mnG = nNew; } + void setBlue(sal_uInt8 nNew) { maPixelUnion.maRGBA.mnB = nNew; } + void setAlpha(sal_uInt8 nNew) { maPixelUnion.maRGBA.mnA = nNew; } + + // comparators + bool operator==( const BPixel& rPixel ) const + { + return (rPixel.maPixelUnion.maCombinedRGBA.mnValue == maPixelUnion.maCombinedRGBA.mnValue); + } + + bool operator!=( const BPixel& rPixel ) const + { + return (rPixel.maPixelUnion.maCombinedRGBA.mnValue != maPixelUnion.maCombinedRGBA.mnValue); + } + }; + + +} // end of namespace basegfx + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/include/basegfx/point/b2dpoint.hxx b/include/basegfx/point/b2dpoint.hxx new file mode 100644 index 0000000000..ce16965de0 --- /dev/null +++ b/include/basegfx/point/b2dpoint.hxx @@ -0,0 +1,145 @@ +/* -*- 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 . + */ + +#pragma once + +#include + +#include +#include +#include +#include + +namespace basegfx +{ + class B2DHomMatrix; + + /** Base Point class with two double values + + This class derives all operators and common handling for + a 2D data class from B2DTuple. All necessary extensions + which are special for points will be added here. + + @see B2DTuple + */ + class SAL_WARN_UNUSED B2DPoint : public ::basegfx::B2DTuple + { + public: + /** Create a 2D Point + + The point is initialized to (0.0, 0.0) + */ + B2DPoint() + {} + + /** Create a 2D Point + + @param fX + This parameter is used to initialize the X-coordinate + of the 2D Point. + + @param fY + This parameter is used to initialize the Y-coordinate + of the 2D Point. + */ + B2DPoint(double fX, double fY) + : B2DTuple(fX, fY) + {} + + /** Create a copy of a 2D Point + + @param rPoint + The 2D Point which will be copied. + */ + explicit B2DPoint(const ::basegfx::B2IPoint& rPoint) + : B2DTuple(rPoint) + {} + + /** constructor with tuple to allow copy-constructing + from B2DTuple-based classes + */ + B2DPoint(Tuple2D const& rTuple) + : B2DTuple(rTuple) + {} + + /** create a point from a size object */ + explicit B2DPoint(Size2D const& rSize) + : B2DTuple(rSize.getWidth(), rSize.getHeight()) + {} + + /** *=operator to allow usage from B2DPoint, too + */ + B2DPoint& operator*=( const B2DPoint& rPnt ) + { + mnX *= rPnt.mnX; + mnY *= rPnt.mnY; + return *this; + } + + /** *=operator to allow usage from B2DPoint, too + */ + B2DPoint& operator*=(double t) + { + mnX *= t; + mnY *= t; + return *this; + } + + /** assignment operator to allow assigning the results + of B2DTuple calculations + */ + BASEGFX_DLLPUBLIC B2DPoint& operator=(Tuple2D& rPoint) + { + mnX = rPoint.getX(); + mnY = rPoint.getY(); + return *this; + } + + /** Transform point by given transformation matrix. + + The translational components of the matrix are, in + contrast to B2DVector, applied. + */ + BASEGFX_DLLPUBLIC B2DPoint& operator*=( const ::basegfx::B2DHomMatrix& rMat ); + + static const B2DPoint& getEmptyPoint() + { + return static_cast( ::basegfx::B2DTuple::getEmptyTuple() ); + } + }; + + // external operators + + /** Transform B2DPoint by given transformation matrix. + + Since this is a Point, translational components of the + matrix are used. + */ + BASEGFX_DLLPUBLIC B2DPoint operator*( const B2DHomMatrix& rMat, const B2DPoint& rPoint ); + + template< typename charT, typename traits > + inline std::basic_ostream & operator <<( + std::basic_ostream & stream, const B2DPoint& point ) + { + return stream << "(" << point.getX() << "," << point.getY() << ")"; + } + +} // end of namespace basegfx + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/include/basegfx/point/b2ipoint.hxx b/include/basegfx/point/b2ipoint.hxx new file mode 100644 index 0000000000..9357e9f0fd --- /dev/null +++ b/include/basegfx/point/b2ipoint.hxx @@ -0,0 +1,99 @@ +/* -*- 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 . + */ + +#pragma once + +#include + +namespace basegfx +{ + class B2DHomMatrix; + + /** Base Point class with two sal_Int32 values + + This class derives all operators and common handling for + a 2D data class from B2ITuple. All necessary extensions + which are special for points will be added here. + + @see B2ITuple + */ + class SAL_WARN_UNUSED B2IPoint : public ::basegfx::B2ITuple + { + public: + /** Create a 2D Point + + The point is initialized to (0, 0) + */ + B2IPoint() + {} + + /** Create a 2D Point + + @param nX + This parameter is used to initialize the X-coordinate + of the 2D Point. + + @param nY + This parameter is used to initialize the Y-coordinate + of the 2D Point. + */ + B2IPoint(sal_Int32 nX, sal_Int32 nY) + : B2ITuple(nX, nY) + {} + + /** constructor with tuple to allow copy-constructing + from B2ITuple-based classes + */ + B2IPoint(const ::basegfx::B2ITuple& rTuple) + : B2ITuple(rTuple) + {} + + /** *=operator to allow usage from B2IPoint, too + */ + B2IPoint& operator*=( const B2IPoint& rPnt ) + { + mnX *= rPnt.mnX; + mnY *= rPnt.mnY; + return *this; + } + + /** *=operator to allow usage from B2IPoint, too + */ + B2IPoint& operator*=(sal_Int32 t) + { + mnX *= t; + mnY *= t; + return *this; + } + + /** assignment operator to allow assigning the results + of B2ITuple calculations + */ + B2IPoint& operator=( const ::basegfx::B2ITuple& rPoint ); + + /** Transform point by given transformation matrix. + + The translational components of the matrix are, in + contrast to B2DVector, applied. + */ + B2IPoint& operator*=( const ::basegfx::B2DHomMatrix& rMat ); + }; +} // end of namespace basegfx + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/include/basegfx/point/b3dpoint.hxx b/include/basegfx/point/b3dpoint.hxx new file mode 100644 index 0000000000..7b3352bff4 --- /dev/null +++ b/include/basegfx/point/b3dpoint.hxx @@ -0,0 +1,123 @@ +/* -*- 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 . + */ + +#pragma once + +#include +#include + +namespace basegfx +{ + class B3DHomMatrix; + + /** Base Point class with three double values + + This class derives all operators and common handling for + a 3D data class from B3DTuple. All necessary extensions + which are special for points will be added here. + + @see B3DTuple + */ + class SAL_WARN_UNUSED BASEGFX_DLLPUBLIC B3DPoint : public ::basegfx::B3DTuple + { + public: + /** Create a 3D Point + + The point is initialized to (0.0, 0.0, 0.0) + */ + B3DPoint() + {} + + /** Create a 3D Point + + @param fX + This parameter is used to initialize the X-coordinate + of the 3D Point. + + @param fY + This parameter is used to initialize the Y-coordinate + of the 3D Point. + + @param fZ + This parameter is used to initialize the Z-coordinate + of the 3D Point. + */ + B3DPoint(double fX, double fY, double fZ) + : B3DTuple(fX, fY, fZ) + {} + + /** constructor with tuple to allow copy-constructing + from B3DTuple-based classes + */ + B3DPoint(const ::basegfx::B3DTuple& rTuple) + : B3DTuple(rTuple) + {} + + /** *=operator to allow usage from B3DPoint, too + */ + B3DPoint& operator*=( const B3DPoint& rPnt ) + { + mnX *= rPnt.mnX; + mnY *= rPnt.mnY; + mnZ *= rPnt.mnZ; + return *this; + } + + /** *=operator to allow usage from B3DPoint, too + */ + B3DPoint& operator*=(double t) + { + mnX *= t; + mnY *= t; + mnZ *= t; + return *this; + } + + /** assignment operator to allow assigning the results + of B3DTuple calculations + */ + B3DPoint& operator=( const ::basegfx::B3DTuple& rVec ) + { + mnX = rVec.getX(); + mnY = rVec.getY(); + mnZ = rVec.getZ(); + return *this; + } + + /** Transform point by given transformation matrix. + + The translational components of the matrix are, in + contrast to B3DVector, applied. + */ + B3DPoint& operator*=( const ::basegfx::B3DHomMatrix& rMat ); + }; + + // external operators + + + /** Transform B3DPoint by given transformation matrix. + + Since this is a Point, translational components of the + matrix are used. + */ + BASEGFX_DLLPUBLIC B3DPoint operator*( const B3DHomMatrix& rMat, const B3DPoint& rPoint ); + +} // end of namespace basegfx + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/include/basegfx/polygon/WaveLine.hxx b/include/basegfx/polygon/WaveLine.hxx new file mode 100644 index 0000000000..b839c75198 --- /dev/null +++ b/include/basegfx/polygon/WaveLine.hxx @@ -0,0 +1,38 @@ +/* -*- 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/. + * + */ + +#pragma once + +#include +#include +#include + +namespace basegfx +{ +// Creates a polygon of a wave line in the input rectangle. +// +// The polygon is created with points at the center of the rectangle, +// and the quadratic control points at the upper and lower side. See +// the diagram below. +// +// *----Q---------------Q------------* +// | | +// |P-------P-------P-------P-------P| +// | | +// *------------Q---------------Q----* +// +// P is the point +// Q is the quadratic bezier control point +// +BASEGFX_DLLPUBLIC B2DPolygon createWaveLinePolygon(basegfx::B2DRectangle const& rRectangle); + +} // end of namespace basegfx + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/include/basegfx/polygon/b2dlinegeometry.hxx b/include/basegfx/polygon/b2dlinegeometry.hxx new file mode 100644 index 0000000000..ab9e54652c --- /dev/null +++ b/include/basegfx/polygon/b2dlinegeometry.hxx @@ -0,0 +1,145 @@ +/* -*- 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 . + */ + +#pragma once + +#include +#include +#include +#include +#include + +namespace basegfx::utils +{ + /** Create line start/end geometry element, mostly arrows and things like that. + + @param rCandidate + The polygon which needs to get that line ends and needs to have two points + at least. + + @param rArrow + The line start/end geometry. It is assumed that the tip is pointing + upwards. Result will be rotated and scaled to fit. + + @param bStart + describes if creation is for start or end of candidate. + + @param fWidth + defines the size of the element, it's describing the target width in X + of the arrow. + + @param fDockingPosition needs to be in [0.0 ..1.0] range, where 0.0 means + that the tip of the arrow will be aligned with the polygon start, 1.0 means + the bottom. The default of 0.5 describes a centered arrow. + + @param pConsumedLength + Using this parameter it is possible to get back how much from the candidate + geometry is overlapped by the created element (consumed). + + @param fCandidateLength + This should contain the length of rCandidate to allow work without + again calculating the length (which may be expensive with beziers). If 0.0 is + given, the length is calculated on demand. + + @param fShift + When it is necessary to count with the thickness of the line, it + makes sense to move the start position slightly - so define the shift. + + @return + The Line start and end polygon, correctly rotated and scaled + */ + BASEGFX_DLLPUBLIC B2DPolyPolygon createAreaGeometryForLineStartEnd( + const B2DPolygon& rCandidate, + const B2DPolyPolygon& rArrow, + bool bStart, + double fWidth, + double fCandidateLength, // 0.0 -> calculate self + double fDockingPosition, // 0->top, 1->bottom + double* pConsumedLength = nullptr, + double fShift = 0.0); + + /** create filled polygon geometry for lines with a line width + + This method will create bezier based, fillable polygons which + will resample the curve if it was extended for the given half + line width. It will remove extrema positions from contained + bezier segments and get as close as possible and defined by + the given parameters to the ideal result. + + It will check edges for trivial bezier to avoid unnecessary + bezier polygons. Care is taken to produce the in-between + polygon points (the ones original on the source polygon) since + it has showed that without those, the raster converters leave + non-filled gaps. + + @param rCandidate + The source polygon defining the hairline polygon path + + @param fHalfLineWidth + The width of the line to one side + + @param eJoin + The LineJoin if the edges meeting in a point do not have a C1 + or C2 continuity + + @param eCap + The kind of cap, which is added to the line. + + @param fMaxAllowedAngle + Allows to hand over the maximum allowed angle between an edge and + it's control vectors. The smaller, the more subdivisions will be + needed to create the filled geometry. Allowed range is cropped to + [M_PI_2 .. 0.01 * M_PI_2]. + + @param fMaxPartOfEdge + Allows to influence from with relative length of a control vector + compared to its edge a split is forced. The smaller, the more + subdivisions will be needed to create the filled geometry. Allowed + range is cropped to [1.0 .. 0.01] + + @param fMiterMinimumAngle + The minimum wanted angle between two edges when edge rounding + is using miter. When an edge is smaller than this (tighter) + the usual fallback to bevel is used. Allowed range is cropped + to [M_PI .. 0.01 * M_PI]. + + Commit 51b5b93092d6231615de470c62494c24e54828a1 needs + revert, we need the triangulation for X11 fat line drawing + + @param pTriangles + If given, the method will additionally add the created geometry as + B2DTriangle's + + @return + The tools::PolyPolygon containing the geometry of the extended line by + it's line width. Contains bezier segments and edge roundings as + needed and defined. + */ + BASEGFX_DLLPUBLIC B2DPolyPolygon createAreaGeometry( + const B2DPolygon& rCandidate, + double fHalfLineWidth, + B2DLineJoin eJoin, + css::drawing::LineCap eCap, + double fMaxAllowedAngle = basegfx::deg2rad(12.5), + double fMaxPartOfEdge = 0.4, + double fMiterMinimumAngle = basegfx::deg2rad(15.0)); + +} // end of namespace basegfx::utils + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/include/basegfx/polygon/b2dpolygon.hxx b/include/basegfx/polygon/b2dpolygon.hxx new file mode 100644 index 0000000000..c63bda845d --- /dev/null +++ b/include/basegfx/polygon/b2dpolygon.hxx @@ -0,0 +1,281 @@ +/* -*- 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 . + */ + +#pragma once + +#include +#include +#include + +#include +#include +#include +#include + +class ImplB2DPolygon; + +namespace basegfx +{ + class B2DPoint; + class B2DRange; + class B2DHomMatrix; + class B2DCubicBezier; + class B2DVector; + class SystemDependentData; + class SystemDependentDataManager; + typedef std::shared_ptr SystemDependentData_SharedPtr; +} + +namespace basegfx +{ + class SAL_WARN_UNUSED BASEGFX_DLLPUBLIC B2DPolygon + { + public: + typedef o3tl::cow_wrapper< ImplB2DPolygon > ImplType; + + private: + // internal data. + ImplType mpPolygon; + + public: + /// diverse constructors + B2DPolygon(); + B2DPolygon(const B2DPolygon& rPolygon); + B2DPolygon(B2DPolygon&& rPolygon); + B2DPolygon(const B2DPolygon& rPolygon, sal_uInt32 nIndex, sal_uInt32 nCount); + B2DPolygon(std::initializer_list rPoints); + + ~B2DPolygon(); + + /// assignment operator + B2DPolygon& operator=(const B2DPolygon& rPolygon); + B2DPolygon& operator=(B2DPolygon&& rPolygon); + + /// unshare this polygon with all internally shared instances + void makeUnique(); + + /// compare operators + bool operator==(const B2DPolygon& rPolygon) const; + + /// member count + sal_uInt32 count() const; + + /// Coordinate interface + basegfx::B2DPoint const & getB2DPoint(sal_uInt32 nIndex) const; + void setB2DPoint(sal_uInt32 nIndex, const basegfx::B2DPoint& rValue); + + /// Coordinate insert/append + void insert(sal_uInt32 nIndex, const basegfx::B2DPoint& rPoint, sal_uInt32 nCount = 1); + void append(const basegfx::B2DPoint& rPoint, sal_uInt32 nCount); + void append(const basegfx::B2DPoint& rPoint); + void reserve(sal_uInt32 nCount); + + /// Basic ControlPoint interface + basegfx::B2DPoint getPrevControlPoint(sal_uInt32 nIndex) const; + basegfx::B2DPoint getNextControlPoint(sal_uInt32 nIndex) const; + void setPrevControlPoint(sal_uInt32 nIndex, const basegfx::B2DPoint& rValue); + void setNextControlPoint(sal_uInt32 nIndex, const basegfx::B2DPoint& rValue); + void setControlPoints(sal_uInt32 nIndex, const basegfx::B2DPoint& rPrev, const basegfx::B2DPoint& rNext); + + /// ControlPoint resets + void resetPrevControlPoint(sal_uInt32 nIndex); + void resetNextControlPoint(sal_uInt32 nIndex); + void resetControlPoints(); + + /// Bezier segment append with control points. The current last polygon point is implicitly taken as start point. + void appendBezierSegment(const basegfx::B2DPoint& rNextControlPoint, + const basegfx::B2DPoint& rPrevControlPoint, + const basegfx::B2DPoint& rPoint); + + /// This is a shortcut to append a quadratic bezier segment. The current last polygon point is implicitly taken as start point. + /// Note that the quadratic bezier control points will be converted to cubic bezier with 2 control points. + void appendQuadraticBezierSegment(const basegfx::B2DPoint& rQuadControlPoint, + const basegfx::B2DPoint& rPoint); + + /// ControlPoint checks + bool areControlPointsUsed() const; + bool isPrevControlPointUsed(sal_uInt32 nIndex) const; + bool isNextControlPointUsed(sal_uInt32 nIndex) const; + B2VectorContinuity getContinuityInPoint(sal_uInt32 nIndex) const; + + /** bezier segment access + + This method also works when it is no bezier segment at all and will fill + the given B2DCubicBezier as needed. + In any case, the given B2DCubicBezier will be filled, if necessary with + the single start point (if no valid edge exists). + + @param nIndex + Index of the addressed edge's start point + + @param rTarget + The B2DCubicBezier to be filled. It's data WILL be changed. + */ + void getBezierSegment(sal_uInt32 nIndex, B2DCubicBezier& rTarget) const; + + /** Default adaptive subdivision access + + This method will return a default adaptive subdivision of the polygon. + If the polygon does not contain any bezier curve segments, it will + just return itself. + + The subdivision is created on first request and buffered, so when using + this subdivision You have the guarantee for fast accesses for multiple + usages. It is intended for tooling usage for tasks which would be hard + to accomplish on bezier segments (e.g. isInEpsilonRange). + + The current default subdivision uses adaptiveSubdivideByCount with 9 + subdivisions which gives 10 edges and 11 points per segment and is + usually pretty usable for processing purposes. There is no parameter + passing here ATM but it may be changed on demand. If needed, a TYPE + and PARAMETER (both defaulted) may be added to allow for switching + between the different kinds of subdivisioned and passing them one + parameter. + + The lifetime of the buffered subdivision is based on polygon changes. + When changing the polygon, it will be flushed. It is buffered at the + refcounted implementation class, so it will survive copy by value and + combinations in PolyPolygons. + + @return + The default (and buffered) subdivision of this polygon. It may + be this polygon itself when it has no bezier segments. It is guaranteed + to have no more bezier segments + */ + B2DPolygon const & getDefaultAdaptiveSubdivision() const; + + /** Get the B2DRange (Rectangle dimensions) of this B2DPolygon + + A polygon may have up to three ranges: + + (a) the range of the polygon points + (b) the range of the polygon points and control points + (c) the outer range of the subdivided bezier curve + + Ranges (a) and (c) are produced by tools::getRange(); resp. this + getB2DRange(). tools::getRangeWithControlPoints handles case (b). + + To get range (c) a simple solution would be to subdivide the polygon + and use getRange() on it. Since subdivision is expensive and decreases + the polygon quality, i added this new method. It will use a + methodology suggested by HDU. First, it gets the range (a). + Then it iterates over the bezier segments and for each it + first tests if the outer range of the bezier segment is already + contained in the result range. + + The subdivision itself uses getAllExtremumPositions() to only + calculate extremum points and to expand the result accordingly. + Thus it calculates maximal four extremum points on the bezier + segment, no split is used at all. + + @return + The outer range of the bezier curve/polygon + */ + B2DRange const & getB2DRange() const; + + /** append other 2D polygons + + The default (nIndex ==0 && nCount == 0) will append + the whole rPoly + + @param rPoly + The source polygon + + @param nIndex + The index to the first point of rPoly to append + + @param nCount + The number of points to append from rPoly, starting + from nIndex. If zero, as much as possible is appended + */ + void append(const B2DPolygon& rPoly, sal_uInt32 nIndex = 0, sal_uInt32 nCount = 0); + + /// remove points + void remove(sal_uInt32 nIndex, sal_uInt32 nCount = 1); + + /// clear all points + void clear(); + + /// closed state interface + bool isClosed() const; + void setClosed(bool bNew); + + /// flip polygon direction + void flip(); + + /// test if Polygon has double points + bool hasDoublePoints() const; + + /// remove double points, at the begin/end and follow-ups, too + void removeDoublePoints(); + + /// apply transformation given in matrix form + void transform(const basegfx::B2DHomMatrix& rMatrix); + + // exclusive management op's for SystemDependentData at B2DPolygon + template + std::shared_ptr getSystemDependentData() const + { + return std::static_pointer_cast(getSystemDependantDataInternal(typeid(T).hash_code())); + } + + template + std::shared_ptr addOrReplaceSystemDependentData(Args&&... args) const + { + std::shared_ptr r = std::make_shared(std::forward(args)...); + + // tdf#129845 only add to buffer if a relevant buffer time is estimated + if(r->calculateCombinedHoldCyclesInSeconds() > 0) + { + basegfx::SystemDependentData_SharedPtr r2(r); + addOrReplaceSystemDependentDataInternal(r2); + } + + return r; + } + + private: + void addOrReplaceSystemDependentDataInternal(SystemDependentData_SharedPtr& rData) const; + SystemDependentData_SharedPtr getSystemDependantDataInternal(size_t hash_code) const; + const basegfx::B2DVector& getPrevControlVector(sal_uInt32 nIndex) const; + const basegfx::B2DVector& getNextControlVector(sal_uInt32 nIndex) const; + }; + + // typedef for a vector of B2DPolygons + typedef ::std::vector< B2DPolygon > B2DPolygonVector; + + template< typename charT, typename traits > + inline std::basic_ostream & operator <<( + std::basic_ostream & stream, const B2DPolygon& poly ) + { + stream << "<" << poly.count() << ":"; + for (sal_uInt32 i = 0; i < poly.count(); i++) + { + if (i > 0) + stream << "--"; + stream << poly.getB2DPoint(i); + } + stream << ">"; + + return stream; + } + +} // end of namespace basegfx + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/include/basegfx/polygon/b2dpolygonclipper.hxx b/include/basegfx/polygon/b2dpolygonclipper.hxx new file mode 100644 index 0000000000..a6a2ce9d2f --- /dev/null +++ b/include/basegfx/polygon/b2dpolygonclipper.hxx @@ -0,0 +1,65 @@ +/* -*- 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 . + */ + +#pragma once + +#include +#include +#include + +namespace basegfx +{ + class B2DRange; +} + +namespace basegfx::utils +{ + // This method clips the given tools::PolyPolygon against a horizontal or vertical axis (parallel to X or Y axis). The axis is + // defined by bParallelToXAxis (true -> it's parallel to the X-Axis of the coordinate system, else to the Y-Axis) and the + // fValueOnOtherAxis (gives the translation to the coordinate system axis). For example, when You want to define + // a clip axis parallel to X.Axis and 100 above it, use bParallelToXAxis = true and fValueOnOtherAxis = 100. + // The value bAboveAxis defines on which side the return value will be (true -> above X, right of Y). + // The switch bStroke decides if the polygon is interpreted as area (false) or strokes (true). + B2DPolyPolygon clipPolyPolygonOnParallelAxis(const B2DPolyPolygon& rCandidate, bool bParallelToXAxis, bool bAboveAxis, double fValueOnOtherAxis, bool bStroke); + BASEGFX_DLLPUBLIC B2DPolyPolygon clipPolygonOnParallelAxis(const B2DPolygon& rCandidate, bool bParallelToXAxis, bool bAboveAxis, double fValueOnOtherAxis, bool bStroke); + + // Clip the given tools::PolyPolygon against the given range. bInside defines if the result will contain the + // parts which are contained in the range or vice versa. + // The switch bStroke decides if the polygon is interpreted as area (false) or strokes (true). + BASEGFX_DLLPUBLIC B2DPolyPolygon clipPolyPolygonOnRange(const B2DPolyPolygon& rCandidate, const B2DRange& rRange, bool bInside, bool bStroke); + BASEGFX_DLLPUBLIC B2DPolyPolygon clipPolygonOnRange(const B2DPolygon& rCandidate, const B2DRange& rRange, bool bInside, bool bStroke); + + // Clip given tools::PolyPolygon against given clipping polygon. + // The switch bStroke decides if the polygon is interpreted as area (false) or strokes (true). + // With stroke polygons, You get all line snippets inside rCip. + // With filled polygons, You get all tools::PolyPolygon parts which were inside rClip. + // The switch bInside decides if the parts inside the clip polygon or outside shall be created. + // The clip polygon is always assumed closed, even when it's isClosed() is false. + BASEGFX_DLLPUBLIC B2DPolyPolygon clipPolyPolygonOnPolyPolygon(const B2DPolyPolygon& rCandidate, const B2DPolyPolygon& rClip, + bool bInside, bool bStroke, size_t *pPointLimit = nullptr); + BASEGFX_DLLPUBLIC B2DPolyPolygon clipPolygonOnPolyPolygon(const B2DPolygon& rCandidate, const B2DPolyPolygon& rClip, bool bInside, bool bStroke); + + // clip the given polygon against the given range. the resulting polygon will always contain + // the inside parts which will always be interpreted as areas. the incoming polygon is expected + // to be a simple triangle list. the result is also a simple triangle list. + BASEGFX_DLLPUBLIC B2DPolygon clipTriangleListOnRange( const B2DPolygon& rCandidate, const B2DRange& rRange ); + +} // end of namespace basegfx::utils + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/include/basegfx/polygon/b2dpolygoncutandtouch.hxx b/include/basegfx/polygon/b2dpolygoncutandtouch.hxx new file mode 100644 index 0000000000..600ad1c5cd --- /dev/null +++ b/include/basegfx/polygon/b2dpolygoncutandtouch.hxx @@ -0,0 +1,47 @@ +/* -*- 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 . + */ + +#pragma once + +#include +#include + +namespace basegfx::utils +{ + +// look for self-intersections and self-touches (points on an edge) in given polygon and add +// extra points there. Result will have no touches or intersections on an edge, only on points +B2DPolygon addPointsAtCutsAndTouches(const B2DPolygon& rCandidate, size_t* pPointLimit = nullptr); + +// look for polypolygon-intersections and polypolygon-touches (point of poly A on an edge of poly B) in given tools::PolyPolygon and add +// extra points there. Result will have no touches or intersections between contained polygons on an edge, only on points. For +// convenience, the correction for self-intersections for each member polygon will be used, too. +B2DPolyPolygon addPointsAtCutsAndTouches(const B2DPolyPolygon& rCandidate, size_t* pPointLimit = nullptr); + +// look for intersections of rCandidate with the edge from rStart to rEnd and add extra points there. +// Points are only added in the range of the edge, not on the endless vector. +B2DPolygon addPointsAtCuts(const B2DPolygon& rCandidate, const B2DPoint& rStart, const B2DPoint& rEnd); + +// look for intersections of rCandidate with the mask Polygon and add extra points there. +// The mask polygon is assumed to be closed, even when it's not explicitly. +B2DPolygon addPointsAtCuts(const B2DPolygon& rCandidate, const B2DPolyPolygon& rMask); + +} // end of namespace basegfx + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/include/basegfx/polygon/b2dpolygontools.hxx b/include/basegfx/polygon/b2dpolygontools.hxx new file mode 100644 index 0000000000..d21d0bb63b --- /dev/null +++ b/include/basegfx/polygon/b2dpolygontools.hxx @@ -0,0 +1,548 @@ +/* -*- 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 . + */ + +#pragma once + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +namespace basegfx { class B2DPolyPolygon; } + +// Definitions for the cut flags used from the findCut methods +enum class CutFlagValue +{ + NONE = 0x0000, + LINE = 0x0001, + START1 = 0x0002, + START2 = 0x0004, + END1 = 0x0008, + END2 = 0x0010, + ALL = LINE|START1|START2|END1|END2, + DEFAULT = LINE|START2|END2, +}; +namespace o3tl +{ + template<> struct typed_flags : is_typed_flags {}; +} + +namespace basegfx +{ + class B2DPolygon; + class B2DRange; +} + +namespace basegfx::utils +{ + // B2DPolygon tools + + // open/close with point add/remove and control point corrections + BASEGFX_DLLPUBLIC void openWithGeometryChange(B2DPolygon& rCandidate); + BASEGFX_DLLPUBLIC void closeWithGeometryChange(B2DPolygon& rCandidate); + + /** Check if given polygon is closed. + + This is kind of a 'classic' method to support old polygon + definitions. Those old polygon definitions define the + closed state of the polygon using identical start and + endpoints. This method corrects this (removes double + start/end points) and sets the Closed()-state of the + polygon correctly. + */ + BASEGFX_DLLPUBLIC void checkClosed(B2DPolygon& rCandidate); + + // Get successor and predecessor indices. Returning the same index means there + // is none. Same for successor. + BASEGFX_DLLPUBLIC sal_uInt32 getIndexOfPredecessor(sal_uInt32 nIndex, const B2DPolygon& rCandidate); + BASEGFX_DLLPUBLIC sal_uInt32 getIndexOfSuccessor(sal_uInt32 nIndex, const B2DPolygon& rCandidate); + + // Get orientation of Polygon + BASEGFX_DLLPUBLIC B2VectorOrientation getOrientation(const B2DPolygon& rCandidate); + + // isInside tests for B2dPoint and other B2dPolygon. On border is not inside as long as + // not true is given in bWithBorder flag. + BASEGFX_DLLPUBLIC bool isInside(const B2DPolygon& rCandidate, const B2DPoint& rPoint, bool bWithBorder = false); + BASEGFX_DLLPUBLIC bool isInside(const B2DPolygon& rCandidate, const B2DPolygon& rPolygon, bool bWithBorder = false); + + /** Get the range of a polygon + + This method creates the outer range of the subdivided bezier curve. + For detailed discussion see B2DPolygon::getB2DRange() + + @param rCandidate + The B2DPolygon possibly containing bezier segments + + @return + The outer range of the bezier curve + */ + BASEGFX_DLLPUBLIC B2DRange getRange(const B2DPolygon& rCandidate); + + // get signed area of polygon + BASEGFX_DLLPUBLIC double getSignedArea(const B2DPolygon& rCandidate); + + // get area of polygon + BASEGFX_DLLPUBLIC double getArea(const B2DPolygon& rCandidate); + + /** get length of polygon edge from point nIndex to nIndex + 1 */ + BASEGFX_DLLPUBLIC double getEdgeLength(const B2DPolygon& rCandidate, sal_uInt32 nIndex); + + /** get length of polygon */ + BASEGFX_DLLPUBLIC double getLength(const B2DPolygon& rCandidate, bool bApproximateBezierLength = false); + + // get position on polygon for absolute given distance. If + // length is given, it is assumed the correct polygon length, if 0.0 it is calculated + // using getLength(...) + BASEGFX_DLLPUBLIC B2DPoint getPositionAbsolute(const B2DPolygon& rCandidate, double fDistance, double fLength = 0.0); + + // get position on polygon for relative given distance in range [0.0 .. 1.0]. If + // length is given, it is assumed the correct polygon length, if 0.0 it is calculated + // using getLength(...) + BASEGFX_DLLPUBLIC B2DPoint getPositionRelative(const B2DPolygon& rCandidate, double fDistance, double fLength = 0.0); + + // get a snippet from given polygon for absolute distances. The polygon is assumed + // to be opened (not closed). fFrom and fTo need to be in range [0.0 .. fLength], where + // fTo >= fFrom. If length is given, it is assumed the correct polygon length, + // if 0.0 it is calculated using getLength(...) + BASEGFX_DLLPUBLIC B2DPolygon getSnippetAbsolute(const B2DPolygon& rCandidate, double fFrom, double fTo, double fLength = 0.0); + + // Continuity check for point with given index + BASEGFX_DLLPUBLIC B2VectorContinuity getContinuityInPoint(const B2DPolygon& rCandidate, sal_uInt32 nIndex); + + // Subdivide all contained curves. Use distanceBound value if given. + BASEGFX_DLLPUBLIC B2DPolygon adaptiveSubdivideByDistance(const B2DPolygon& rCandidate, double fDistanceBound, int nRecurseLimit = 30); + + // Subdivide all contained curves. Use angleBound value if given. + BASEGFX_DLLPUBLIC B2DPolygon adaptiveSubdivideByAngle(const B2DPolygon& rCandidate, double fAngleBound = 0.0); + + // This version works with two points and vectors to define the + // edges for the cut test. + BASEGFX_DLLPUBLIC CutFlagValue findCut( + const B2DPoint& rEdge1Start, const B2DVector& rEdge1Delta, + const B2DPoint& rEdge2Start, const B2DVector& rEdge2Delta, + CutFlagValue aCutFlags = CutFlagValue::DEFAULT, + double* pCut1 = nullptr, double* pCut2 = nullptr); + + // test if point is on the given edge in range ]0.0..1.0[ without + // the start/end points. If so, return true and put the parameter + // value in pCut (if provided) + BASEGFX_DLLPUBLIC bool isPointOnEdge( + const B2DPoint& rPoint, + const B2DPoint& rEdgeStart, + const B2DVector& rEdgeDelta, + double* pCut = nullptr); + + /** Apply given LineDashing to given polygon + + This method is used to cut down line polygons to the needed + pieces when a dashing needs to be applied. + It is now capable of keeping contained bezier segments. + It is also capable of delivering line and non-line portions + depending on what target polygons You provide. This is useful + e.g. for dashed lines with two colors. + If the last and the first snippet in one of the results have + a common start/end ppoint, they will be merged to achieve as + view as needed result line snippets. This is also relevant for + further processing the results. + + @param rCandidate + The polygon based on which the snippets will be created. + + @param rDotDashArray + The line pattern given as array of length values + + @param pLineTarget + The target for line snippets, e.g. the first entry will be + a line segment with length rDotDashArray[0]. The given + polygon will be emptied as preparation. + + @param pGapTarget + The target for gap snippets, e.g. the first entry will be + a line segment with length rDotDashArray[1]. The given + polygon will be emptied as preparation. + + @param fFullDashDotLen + The summed-up length of the rDotDashArray. If zero, it will + be calculated internally. + + There is now a 2nd version that allows to provide callback + functions that get called when a snippet of a line/gap is + produced and needs to be added. This allows to use it like + a 'pipeline'. When using this (e.g. the 1st version uses + this internally to guarantee the same algorithm is used) + it is not needed to accumulate a potentially huge number + of polygons in the result-polyPolygons, but e.g. consume + them directly in the caller. Example is rendering a + dashed line but without creating the potentially huge amount + of polygons. + The 2nd version will also merge first/last line/gap snippets + if the input polygon is closed and the start/end-points match + accordingly - at the cost that this will be delivered last. + */ + BASEGFX_DLLPUBLIC void applyLineDashing( + const B2DPolygon& rCandidate, + const std::vector& rDotDashArray, + const std::function& rLineTargetCallback, + const std::function& rGapTargetCallback = std::function(), + double fDotDashLength = 0.0); + BASEGFX_DLLPUBLIC void applyLineDashing( + const B2DPolygon& rCandidate, + const ::std::vector& rDotDashArray, + B2DPolyPolygon* pLineTarget, + B2DPolyPolygon* pGapTarget = nullptr, + double fDotDashLength = 0.0); + + // test if point is inside epsilon-range around an edge defined + // by the two given points. Can be used for HitTesting. The epsilon-range + // is defined to be the rectangle centered to the given edge, using height + // 2 x fDistance, and the circle around both points with radius fDistance. + BASEGFX_DLLPUBLIC bool isInEpsilonRange(const B2DPoint& rEdgeStart, const B2DPoint& rEdgeEnd, const B2DPoint& rTestPosition, double fDistance); + + // test if point is inside epsilon-range around the given Polygon. Can be used + // for HitTesting. The epsilon-range is defined to be the rectangle centered + // to the given edge, using height 2 x fDistance, and the circle around both points + // with radius fDistance. + BASEGFX_DLLPUBLIC bool isInEpsilonRange(const B2DPolygon& rCandidate, const B2DPoint& rTestPosition, double fDistance); + + /** Create a polygon from a rectangle. + + @param rRect + The rectangle which describes the polygon size + + @param fRadiusX + @param fRadiusY + Radius of the edge rounding, relative to the rectangle size. 0.0 means no + rounding, 1.0 will lead to an ellipse + */ + BASEGFX_DLLPUBLIC B2DPolygon createPolygonFromRect( const B2DRectangle& rRect, double fRadiusX, double fRadiusY ); + + /** Create a polygon from a rectangle. + */ + BASEGFX_DLLPUBLIC B2DPolygon createPolygonFromRect( const B2DRectangle& rRect ); + + /** Create the unit polygon + */ + BASEGFX_DLLPUBLIC B2DPolygon const & createUnitPolygon(); + + /** Create a circle polygon with given radius. + + This method creates a circle approximation consisting of + 12 cubic bezier segments, which approximate the given + circle with an error of less than 0.5 percent. + + @param rCenter + Center point of the circle + + @param fRadius + Radius of the circle + */ + BASEGFX_DLLPUBLIC B2DPolygon createPolygonFromCircle( const B2DPoint& rCenter, double fRadius ); + + /// create half circle centered on (0,0) from [0 .. M_PI] + B2DPolygon const & createHalfUnitCircle(); + + /** create a polygon which describes the unit circle and close it + + @param nStartQuadrant + To be able to rebuild the old behaviour where the circles started at bottom, + this parameter is used. Default is 0 which is the first quadrant and the + polygon's start point will be the rightmost one. When using e.g. 1, the + first created quadrant will start at the YMax-position (with Y down on screens, + this is the lowest one). This is needed since when lines are dashed, toe old + geometry started at bottom point, else it would look different. + */ + BASEGFX_DLLPUBLIC B2DPolygon const & createPolygonFromUnitCircle(sal_uInt32 nStartQuadrant = 0); + + /** Create an ellipse polygon with given radii. + + This method creates an ellipse approximation consisting of + 12 cubic bezier segments, which approximate the given + ellipse with an error of less than 0.5 percent. + + @param rCenter + Center point of the circle + + @param fRadiusX + Radius of the ellipse in X direction + + @param fRadiusY + Radius of the ellipse in Y direction + + @param nStartQuadrant + With Y down on screens, 0 = 3 o'clock, 1 = 6 o'clock, 2 = 9 o'clock, 3 = 12 o'clock + */ + BASEGFX_DLLPUBLIC B2DPolygon createPolygonFromEllipse( const B2DPoint& rCenter, double fRadiusX, double fRadiusY, sal_uInt32 nStartQuadrant = 0); + + /** Create a unit ellipse polygon with the given angles, from start to end + */ + BASEGFX_DLLPUBLIC B2DPolygon createPolygonFromEllipseSegment( const B2DPoint& rCenter, double fRadiusX, double fRadiusY, double fStart, double fEnd ); + + BASEGFX_DLLPUBLIC B2DPolygon createPolygonFromUnitEllipseSegment( double fStart, double fEnd ); + + /** Predicate whether a given polygon is a rectangle. + + @param rPoly + Polygon to check + + @return true, if the polygon describes a rectangle + (polygon is closed, and the points are either cw or ccw + enumerations of a rectangle's vertices). Note that + intermediate points and duplicate points are ignored. + */ + BASEGFX_DLLPUBLIC bool isRectangle( const B2DPolygon& rPoly ); + + // create 3d polygon from given 2d polygon. The given fZCoordinate is used to expand the + // third coordinate. + BASEGFX_DLLPUBLIC B3DPolygon createB3DPolygonFromB2DPolygon(const B2DPolygon& rCandidate, double fZCoordinate = 0.0); + + // create 2d tools::PolyPolygon from given 3d PolyPolygon. All coordinates are transformed using the given + // matrix and the resulting x,y is used to form the new polygon. + BASEGFX_DLLPUBLIC B2DPolygon createB2DPolygonFromB3DPolygon(const B3DPolygon& rCandidate, const B3DHomMatrix& rMat); + + // calculate the smallest distance to given edge and return. The relative position on the edge is returned in Cut. + // That position is in the range [0.0 .. 1.0] and the returned distance is adapted accordingly to the start or end + // point of the edge + BASEGFX_DLLPUBLIC double getSmallestDistancePointToEdge(const B2DPoint& rPointA, const B2DPoint& rPointB, const B2DPoint& rTestPoint, double& rCut); + + // for each contained edge calculate the smallest distance. Return the index to the smallest + // edge in rEdgeIndex. The relative position on the edge is returned in rCut. + // If nothing was found (e.g. empty input plygon), DBL_MAX is returned. + BASEGFX_DLLPUBLIC double getSmallestDistancePointToPolygon(const B2DPolygon& rCandidate, const B2DPoint& rTestPoint, sal_uInt32& rEdgeIndex, double& rCut); + + // distort single point. rOriginal describes the original range, where the given points describe the distorted corresponding points. + BASEGFX_DLLPUBLIC B2DPoint distort(const B2DPoint& rCandidate, const B2DRange& rOriginal, const B2DPoint& rTopLeft, const B2DPoint& rTopRight, const B2DPoint& rBottomLeft, const B2DPoint& rBottomRight); + + // distort polygon. rOriginal describes the original range, where the given points describe the distorted corresponding points. + BASEGFX_DLLPUBLIC B2DPolygon distort(const B2DPolygon& rCandidate, const B2DRange& rOriginal, const B2DPoint& rTopLeft, const B2DPoint& rTopRight, const B2DPoint& rBottomLeft, const B2DPoint& rBottomRight); + + // expand all segments (which are not yet) to curve segments. This is done with setting the control + // vectors on the 1/3 resp. 2/3 distances on each segment. + BASEGFX_DLLPUBLIC B2DPolygon expandToCurve(const B2DPolygon& rCandidate); + + // expand given segment to curve segment. This is done with setting the control + // vectors on the 1/3 resp. 2/3 distances. The return value describes if a change took place. + BASEGFX_DLLPUBLIC bool expandToCurveInPoint(B2DPolygon& rCandidate, sal_uInt32 nIndex); + + // set continuity for given index. If not a curve, nothing will change. Non-curve points are not changed, too. + // The return value describes if a change took place. + BASEGFX_DLLPUBLIC bool setContinuityInPoint(B2DPolygon& rCandidate, sal_uInt32 nIndex, B2VectorContinuity eContinuity); + + // test if polygon contains neutral points. A neutral point is one whose orientation is neutral + // e.g. positioned on the edge of its predecessor and successor + BASEGFX_DLLPUBLIC bool hasNeutralPoints(const B2DPolygon& rCandidate); + + // remove neutral points. A neutral point is one whose orientation is neutral + // e.g. positioned on the edge of its predecessor and successor + BASEGFX_DLLPUBLIC B2DPolygon removeNeutralPoints(const B2DPolygon& rCandidate); + + // tests if polygon is convex + BASEGFX_DLLPUBLIC bool isConvex(const B2DPolygon& rCandidate); + + // calculates the orientation at edge nIndex + BASEGFX_DLLPUBLIC B2VectorOrientation getOrientationForIndex(const B2DPolygon& rCandidate, sal_uInt32 nIndex); + + // calculates if given point is on given line, taking care of the numerical epsilon + BASEGFX_DLLPUBLIC bool isPointOnLine(const B2DPoint& rStart, const B2DPoint& rEnd, const B2DPoint& rCandidate, bool bWithPoints); + + // calculates if given point is on given polygon, taking care of the numerical epsilon. Uses + // isPointOnLine internally + BASEGFX_DLLPUBLIC bool isPointOnPolygon(const B2DPolygon& rCandidate, const B2DPoint& rPoint, bool bWithPoints = true); + + // test if candidate is inside triangle + BASEGFX_DLLPUBLIC bool isPointInTriangle(const B2DPoint& rA, const B2DPoint& rB, const B2DPoint& rC, const B2DPoint& rCandidate, bool bWithBorder); + + // test if candidateA and candidateB are on the same side of the given line + bool arePointsOnSameSideOfLine(const B2DPoint& rStart, const B2DPoint& rEnd, const B2DPoint& rCandidateA, const B2DPoint& rCandidateB, bool bWithLine); + + // add triangles for given rCandidate to rTarget. For each triangle, 3 points will be added to rCandidate. + // All triangles will go from the start point of rCandidate to two consecutive points, building (rCandidate.count() - 2) + // triangles. + void addTriangleFan( + const B2DPolygon& rCandidate, + triangulator::B2DTriangleVector& rTarget); + + // grow for polygon. Move all geometry in each point in the direction of the normal in that point + // with the given amount. Value may be negative. + BASEGFX_DLLPUBLIC B2DPolygon growInNormalDirection(const B2DPolygon& rCandidate, double fValue); + + // force all sub-polygons to a point count of nSegments + BASEGFX_DLLPUBLIC B2DPolygon reSegmentPolygon(const B2DPolygon& rCandidate, sal_uInt32 nSegments); + + // create polygon state at t from 0.0 to 1.0 between the two polygons. Both polygons must have the same + // organisation, e.g. same amount of points + BASEGFX_DLLPUBLIC B2DPolygon interpolate(const B2DPolygon& rOld1, const B2DPolygon& rOld2, double t); + + // #i76891# Try to remove existing curve segments if they are simply edges + BASEGFX_DLLPUBLIC B2DPolygon simplifyCurveSegments(const B2DPolygon& rCandidate); + + // makes the given indexed point the new polygon start point. To do that, the points in the + // polygon will be rotated. This is only valid for closed polygons, for non-closed ones + // an assertion will be triggered + BASEGFX_DLLPUBLIC B2DPolygon makeStartPoint(const B2DPolygon& rCandidate, sal_uInt32 nIndexOfNewStatPoint); + + /** create edges of given length along given B2DPolygon + + @param rCandidate + The polygon to move along. Points at the given polygon are created, starting + at position fStart and stopping at less or equal to fEnd. The closed state is + preserved. + The polygon is subdivided if curve segments are included. That subdivision is the base + for the newly created points. + If the source is closed, the indirectly existing last edge may NOT have the + given length. + If the source is open, all edges will have the given length. You may use the last + point of the original when You want to add the last edge Yourself. + + @param fLength + The length of the created edges. If less or equal zero, an empty polygon is returned. + + @param fStart + The start distance for the first to be generated point. Use 0.0 to get the + original start point. Negative values are truncated to 0.0. + + @param fEnd + The maximum distance for the last point. No more points behind this distance will be created. + Use 0.0 to process the whole polygon. Negative values are truncated to 0.0. It also + needs to be more or equal to fStart, else it is truncated to fStart. + + @return + The newly created polygon + */ + B2DPolygon createEdgesOfGivenLength(const B2DPolygon& rCandidate, double fLength, double fStart = 0.0, double fEnd = 0.0); + + /** Create Waveline along given polygon + The implementation is based on createEdgesOfGivenLength and creates a curve + segment with the given dimensions for each created line segment. The polygon + is treated as if opened (closed state will be ignored) and only for whole + edges a curve segment will be created (no rest handling) + + @param rCandidate + The polygon along which the waveline will be created + + @param fWaveWidth + The length of a single waveline curve segment + + @param fgWaveHeight + The height of the waveline (amplitude) + */ + BASEGFX_DLLPUBLIC B2DPolygon createWaveline(const B2DPolygon& rCandidate, double fWaveWidth, double fWaveHeight); + + /** snap some polygon coordinates to discrete coordinates + + This method allows to snap some polygon points to discrete (integer) values + which equals e.g. a snap to discrete coordinates. It will snap points of + horizontal and vertical edges + + @param rCandidate + The source polygon + + @return + The modified version of the source polygon + */ + BASEGFX_DLLPUBLIC B2DPolygon snapPointsOfHorizontalOrVerticalEdges(const B2DPolygon& rCandidate); + + /// get the tangent with which the given point is entered seen from the previous + /// polygon path data. Take into account all stuff like closed state, zero-length edges and others. + BASEGFX_DLLPUBLIC B2DVector getTangentEnteringPoint(const B2DPolygon& rCandidate, sal_uInt32 nIndex); + + /// get the tangent with which the given point is left seen from the following + /// polygon path data. Take into account all stuff like closed state, zero-length edges and others. + BASEGFX_DLLPUBLIC B2DVector getTangentLeavingPoint(const B2DPolygon& rCandidate, sal_uInt32 nIndex); + + /// converters for css::drawing::PointSequence + BASEGFX_DLLPUBLIC B2DPolygon UnoPointSequenceToB2DPolygon( + const css::drawing::PointSequence& rPointSequenceSource); + BASEGFX_DLLPUBLIC void B2DPolygonToUnoPointSequence( + const B2DPolygon& rPolygon, + css::drawing::PointSequence& rPointSequenceRetval); + + /* converters for css::drawing::PointSequence and + css::drawing::FlagSequence to B2DPolygon (curved polygons) + */ + B2DPolygon UnoPolygonBezierCoordsToB2DPolygon( + const css::drawing::PointSequence& rPointSequenceSource, + const css::drawing::FlagSequence& rFlagSequenceSource); + void B2DPolygonToUnoPolygonBezierCoords( + const B2DPolygon& rPolyPolygon, + css::drawing::PointSequence& rPointSequenceRetval, + css::drawing::FlagSequence& rFlagSequenceRetval); + + /** Read poly-polygon from SVG. + + This function imports a poly-polygon from an SVG points + attribute (a plain list of coordinate pairs). + + @param o_rPoly + The output polygon. Note that svg:points can only define a + single polygon + + @param rSvgPointsAttribute + A valid SVG points attribute string + + @return true, if the string was successfully parsed + */ + BASEGFX_DLLPUBLIC bool importFromSvgPoints( B2DPolygon& o_rPoly, + std::u16string_view rSvgPointsAttribute ); + + /** Write poly-polygon to SVG. + + This function imports a non-bezier polygon to SVG points + (a plain list of coordinate pairs). + + @param rPoly + The polygon to export + + @param rSvgPointsAttribute + A valid SVG points attribute string + + @return true, if the string was successfully parsed + */ + BASEGFX_DLLPUBLIC OUString exportToSvgPoints( const B2DPolygon& rPoly ); + + /** Reduces the number of points using the Ramer-Douglas-Peucker (RDP) algorithm. If the input + polygon has control points or less than three points, the input polygon is returned + unchanged. Otherwise, a simplified polygon is returned. If the input polygon is closed, + the caller is expected to ensure that the first and last points of the polygon are + identical. The polygon is treated as open in this case. Closing the result polygon is not + performed here, but left to the caller. + + @param rCandidate + The source polygon from which the reduced polygon is generated + + @param fTolerance + The tolerance for the RDP algorithm. + + @return + A newly created polygon with reduced point count. + */ + BASEGFX_DLLPUBLIC B2DPolygon createSimplifiedPolygon(const B2DPolygon& rCandidate, + const double fTolerance); + +} // end of namespace basegfx::utils + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/include/basegfx/polygon/b2dpolygontriangulator.hxx b/include/basegfx/polygon/b2dpolygontriangulator.hxx new file mode 100644 index 0000000000..1fb2c9d542 --- /dev/null +++ b/include/basegfx/polygon/b2dpolygontriangulator.hxx @@ -0,0 +1,71 @@ +/* -*- 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 . + */ + +#pragma once + +#include +#include +#include + +#include + +namespace basegfx { class B2DPolyPolygon; } + +namespace basegfx::triangulator +{ + // Simple B2D-based triangle. Main reason is to + // keep the data types separated (before a B2DPolygon + // was used with the convention that three points in + // a row define a triangle) + class BASEGFX_DLLPUBLIC B2DTriangle + { + // positions + basegfx::B2DPoint maA; + basegfx::B2DPoint maB; + basegfx::B2DPoint maC; + + public: + B2DTriangle( + const basegfx::B2DPoint& rA, + const basegfx::B2DPoint& rB, + const basegfx::B2DPoint& rC) + : maA(rA), + maB(rB), + maC(rC) + { + } + + // get positions + const basegfx::B2DPoint& getA() const { return maA; } + const basegfx::B2DPoint& getB() const { return maB; } + const basegfx::B2DPoint& getC() const { return maC; } + }; + + // typedef for a vector of B2DTriangle + typedef ::std::vector< B2DTriangle > B2DTriangleVector; + + // triangulate given polygon + BASEGFX_DLLPUBLIC B2DTriangleVector triangulate(const ::basegfx::B2DPolygon& rCandidate); + + // triangulate given PolyPolygon + BASEGFX_DLLPUBLIC B2DTriangleVector triangulate(const ::basegfx::B2DPolyPolygon& rCandidate); + +} // end of namespace basegfx::triangulator + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/include/basegfx/polygon/b2dpolypolygon.hxx b/include/basegfx/polygon/b2dpolypolygon.hxx new file mode 100644 index 0000000000..d3177e3c4c --- /dev/null +++ b/include/basegfx/polygon/b2dpolypolygon.hxx @@ -0,0 +1,171 @@ +/* -*- 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 . + */ + +#pragma once + +#include +#include + +#include +#include +#include +#include +#include + +namespace basegfx +{ + class B2DHomMatrix; + class ImplB2DPolyPolygon; + + class BASEGFX_DLLPUBLIC B2DPolyPolygon + { + private: + o3tl::cow_wrapper mpPolyPolygon; + + public: + B2DPolyPolygon(); + B2DPolyPolygon(const B2DPolyPolygon& rPolyPolygon); + B2DPolyPolygon(B2DPolyPolygon&& rPolyPolygon); + explicit B2DPolyPolygon(const B2DPolygon& rPolygon); + ~B2DPolyPolygon(); + + // assignment operator + B2DPolyPolygon& operator=(const B2DPolyPolygon& rPolyPolygon); + B2DPolyPolygon& operator=(B2DPolyPolygon&& rPolyPolygon); + + /// unshare this poly-polygon (and all included polygons) with all internally shared instances + void makeUnique(); + + // compare operators + bool operator==(const B2DPolyPolygon& rPolyPolygon) const; + bool operator!=(const B2DPolyPolygon& rPolyPolygon) const; + + // polygon interface + sal_uInt32 count() const; + + B2DPolygon const & getB2DPolygon(sal_uInt32 nIndex) const; + void setB2DPolygon(sal_uInt32 nIndex, const B2DPolygon& rPolygon); + + // test for curve + bool areControlPointsUsed() const; + + // insert/append single polygon + void insert(sal_uInt32 nIndex, const B2DPolygon& rPolygon, sal_uInt32 nCount = 1); + void append(const B2DPolygon& rPolygon, sal_uInt32 nCount = 1); + void reserve(sal_uInt32 nCount); + + /** Default adaptive subdivision access + + For details refer to B2DPolygon::getDefaultAdaptiveSubdivision() + + @return + The default subdivision of this polygon + */ + B2DPolyPolygon getDefaultAdaptiveSubdivision() const; + + /** Get the B2DRange (Rectangle dimensions) of this B2DPolyPolygon + + For details refer to B2DPolygon::getB2DRange() + + @return + The outer range of the bezier curve/polygon + */ + B2DRange getB2DRange() const; + + // insert/append multiple polygons + void insert(sal_uInt32 nIndex, const B2DPolyPolygon& rPolyPolygon); + void append(const B2DPolyPolygon& rPolyPolygon); + + // remove + void remove(sal_uInt32 nIndex, sal_uInt32 nCount = 1); + + // reset to empty state + void clear(); + + // closed state + bool isClosed() const; + void setClosed(bool bNew); + + // flip polygon direction + void flip(); + + // test if tools::PolyPolygon has double points + bool hasDoublePoints() const; + + // remove double points, at the begin/end and follow-ups, too + void removeDoublePoints(); + + // apply transformation given in matrix form to the polygon + void transform(const basegfx::B2DHomMatrix& rMatrix); + + // polygon iterators (same iterator validity conditions as for vector) + const B2DPolygon* begin() const; + const B2DPolygon* end() const; + B2DPolygon* begin(); + B2DPolygon* end(); + + // exclusive management op's for SystemDependentData at B2DPolygon + template + std::shared_ptr getSystemDependentData() const + { + return std::static_pointer_cast(getSystemDependantDataInternal(typeid(T).hash_code())); + } + + template + std::shared_ptr addOrReplaceSystemDependentData(Args&&... args) const + { + std::shared_ptr r = std::make_shared(std::forward(args)...); + + // tdf#129845 only add to buffer if a relevant buffer time is estimated + if(r->calculateCombinedHoldCyclesInSeconds() > 0) + { + basegfx::SystemDependentData_SharedPtr r2(r); + addOrReplaceSystemDependentDataInternal(r2); + } + + return r; + } + + private: + void addOrReplaceSystemDependentDataInternal(SystemDependentData_SharedPtr& rData) const; + SystemDependentData_SharedPtr getSystemDependantDataInternal(size_t hash_code) const; + }; + + // typedef for a vector of B2DPolyPolygons + typedef ::std::vector< B2DPolyPolygon > B2DPolyPolygonVector; + + template< typename charT, typename traits > + inline std::basic_ostream & operator <<( + std::basic_ostream & stream, const B2DPolyPolygon& poly ) + { + stream << "[" << poly.count() << ":"; + for (sal_uInt32 i = 0; i < poly.count(); i++) + { + if (i > 0) + stream << ","; + stream << poly.getB2DPolygon(i); + } + stream << "]"; + + return stream; + } + +} // end of namespace basegfx + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/include/basegfx/polygon/b2dpolypolygoncutter.hxx b/include/basegfx/polygon/b2dpolypolygoncutter.hxx new file mode 100644 index 0000000000..55dd29cf8e --- /dev/null +++ b/include/basegfx/polygon/b2dpolypolygoncutter.hxx @@ -0,0 +1,144 @@ +/* -*- 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 . + */ + +#pragma once + +#include +#include + + +namespace basegfx::utils +{ + /** Solve all crossovers (aka self-intersections) in a polyPolygon. + + This re-layouts all contained polygons so that the result + will contain only non-cutting polygons. For that reason, + points will be added at crossover and touch points and the + single Polygons may be re-combined. The orientations of + the contained polygons in not changed but used as + topological information. Self crossovers of the contained + sub-polygons are implicitly handled, but to not lose the + topological information, it may be necessary to remove + self-intersections of the contained sub-polygons in a + preparing step and to explicitly correct their + orientations. + */ + BASEGFX_DLLPUBLIC B2DPolyPolygon solveCrossovers(const B2DPolyPolygon& rCandidate, + size_t* pPointLimit = nullptr); + + /** Solve all crossovers (aka self-intersections) in a Polygon + + Same as above, but for single polygons. Result will be + free of self-intersections. When result contains multiple + polygons, it may be necessary to rearrange their + orientations since holes may have been created (possibly use + correctOrientations). + */ + BASEGFX_DLLPUBLIC B2DPolyPolygon solveCrossovers(const B2DPolygon& rCandidate); + + /** Strip neutral polygons from PolyPolygon. + + Neutral polygons are ones who's orientation is neutral, so + normally they have no volume -> just closed paths. A + polygon with the same positive and negative oriented + volume is also neutral, so this may not be wanted. It is + safe to call with self-intersection-free polygons, though + (that's where it's mostly used). + */ + BASEGFX_DLLPUBLIC B2DPolyPolygon stripNeutralPolygons(const B2DPolyPolygon& rCandidate); + + /** Remove unnecessary/non-displayed polygons. + + Works only correct with self-intersection-free + polygons. For each polygon, the depth for the PolyPolygon + is calculated. The orientation is used to identify holes. + Start value for holes is -1, for polygons it's zero. Ech + time a polygon is contained in another one, it's depth is + increased when inside a polygon, decreased when inside a + hole. The result is a depth which e.g. is -1 for holes + outside everything, 1 for a polygon covered by another + polygon and zero for e.g. holes in a polygon or polygons + outside everything else. In the 2nd step, all polygons + with depth other than zero are removed. If bKeepAboveZero + is used, all polygons < 1 are removed. The bKeepAboveZero + mode is useful for clipping, e.g. just append one polygon + to another and use this mode -> only parts where two + polygons overlapped will be kept. In combination with + correct orientation of the input orientations and the + SolveCrossover calls this can be combined for logical + polygon operations or polygon clipping. + */ + BASEGFX_DLLPUBLIC B2DPolyPolygon stripDispensablePolygons(const B2DPolyPolygon& rCandidate, bool bKeepAboveZero = false); + + /** Emulate nonzero winding rule filling. + + Geometrically convert PolyPolygons which are proposed to + use nonzero fill rule to a representation where evenodd + paint will give the same result. To do this all + intersections and self-intersections get solved (the + polygons will be rearranged if needed). Then all polygons + which are inside another one with the same orientation get + deleted + */ + BASEGFX_DLLPUBLIC B2DPolyPolygon createNonzeroConform(const B2DPolyPolygon& rCandidate); + + // For convenience: the four basic operations OR, XOR, AND and DIFF for + // two PolyPolygons. These are combinations of the above methods. To not be forced + // to do evtl. already done preparations twice, You have to do the operations Yourself. + + // A source preparation consists of preparing it to be seen as XOR-Rule PolyPolygon, + // so it is freed of intersections, self-intersections and the orientations are corrected. + // Important is that it will define the same areas as before, but is intersection-free. + // As an example think about a single polygon looping in itself and having holes. To + // topologically correctly handle this, it is necessary to remove all intersections and + // to correct the orientations. The orientation of the isolated holes e.g. will be negative. + // Topologically it is necessary to prepare each polygon which is seen as entity. It is + // not sufficient just to concatenate them and prepare the result, this may be topologically + // different since the simple concatenation will be seen as XOR. To work correctly, You + // may need to OR those polygons. + + /// prep for ops - solve self-intersections and intersections, remove neutral parts and check orientations. + BASEGFX_DLLPUBLIC B2DPolyPolygon prepareForPolygonOperation(const B2DPolygon& rCandidate); + /// prep for ops - solve self-intersections and intersections, remove neutral parts and check orientations. + BASEGFX_DLLPUBLIC B2DPolyPolygon prepareForPolygonOperation(const B2DPolyPolygon& rCandidate); + + /// OR: Return all areas where CandidateA or CandidateB exist + BASEGFX_DLLPUBLIC B2DPolyPolygon solvePolygonOperationOr(const B2DPolyPolygon& rCandidateA, const B2DPolyPolygon& rCandidateB); + + /// XOR: Return all areas where CandidateA or CandidateB exist, but not both + BASEGFX_DLLPUBLIC B2DPolyPolygon solvePolygonOperationXor(const B2DPolyPolygon& rCandidateA, const B2DPolyPolygon& rCandidateB); + + /// AND: Return all areas where CandidateA and CandidateB exist + BASEGFX_DLLPUBLIC B2DPolyPolygon solvePolygonOperationAnd(const B2DPolyPolygon& rCandidateA, const B2DPolyPolygon& rCandidateB); + + /// DIFF: Return all areas where CandidateA is not covered by CandidateB (cut B out of A) + BASEGFX_DLLPUBLIC B2DPolyPolygon solvePolygonOperationDiff(const B2DPolyPolygon& rCandidateA, const B2DPolyPolygon& rCandidateB); + + /** merge all single PolyPolygons to a single, OR-ed PolyPolygon + + @param rInput + The source PolyPolygons + + @return A single tools::PolyPolygon containing the Or-merged result + */ + BASEGFX_DLLPUBLIC B2DPolyPolygon mergeToSinglePolyPolygon(const B2DPolyPolygonVector& rInput); + +} // end of namespace basegfx::utils + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/include/basegfx/polygon/b2dpolypolygontools.hxx b/include/basegfx/polygon/b2dpolypolygontools.hxx new file mode 100644 index 0000000000..8960946332 --- /dev/null +++ b/include/basegfx/polygon/b2dpolypolygontools.hxx @@ -0,0 +1,297 @@ +/* -*- 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 . + */ + +#pragma once + +#include +#include +#include +#include +#include +#include + +namespace com::sun::star::drawing { struct PolyPolygonBezierCoords; } + +namespace basegfx +{ + class B2DPolyPolygon; + class B2DRange; +} + +namespace basegfx::utils +{ + // B2DPolyPolygon tools + + // Check and evtl. correct orientations of all contained Polygons so that + // the orientations of contained polygons will variate to express areas and + // holes + BASEGFX_DLLPUBLIC B2DPolyPolygon correctOrientations(const B2DPolyPolygon& rCandidate); + + // make sure polygon with index 0L is not a hole. This may evtl. change the + // sequence of polygons, but allows to use polygon with index 0L to + // get the correct normal for the whole polyPolygon + BASEGFX_DLLPUBLIC B2DPolyPolygon correctOutmostPolygon(const B2DPolyPolygon& rCandidate); + + // Subdivide all contained curves. Use distanceBound value if given. + BASEGFX_DLLPUBLIC B2DPolyPolygon adaptiveSubdivideByDistance(const B2DPolyPolygon& rCandidate, double fDistanceBound, int nRecurseLimit = 30); + + // Subdivide all contained curves. Use distanceBound value if given. Else, a convenient one + // is created. + BASEGFX_DLLPUBLIC B2DPolyPolygon adaptiveSubdivideByAngle(const B2DPolyPolygon& rCandidate, double fAngleBound = 0.0); + + // isInside test for B2dPoint. On border is not inside as long as not true is given + // in bWithBorder flag. It is assumed that the orientations of the given polygon are correct. + BASEGFX_DLLPUBLIC bool isInside(const B2DPolyPolygon& rCandidate, const B2DPoint& rPoint, bool bWithBorder = false); + + /** Get the range of a polyPolygon + + For detailed description look at getRange(const B2DPolygon&). + This method just expands by the range of every sub-Polygon. + + @param rCandidate + The B2DPolyPolygon possibly containing bezier segments + + @return + The outer range of the polygon + */ + BASEGFX_DLLPUBLIC B2DRange getRange(const B2DPolyPolygon& rCandidate); + + // get signed area of polygon + BASEGFX_DLLPUBLIC double getSignedArea(const B2DPolyPolygon& rCandidate); + + // get area of polygon + BASEGFX_DLLPUBLIC double getArea(const B2DPolyPolygon& rCandidate); + + /** Apply given LineDashing to given polyPolygon + + For a description see applyLineDashing in b2dpolygontoos.hxx + */ + BASEGFX_DLLPUBLIC void applyLineDashing( + const B2DPolyPolygon& rCandidate, + const ::std::vector& rDotDashArray, + B2DPolyPolygon* pLineTarget, + double fFullDashDotLen = 0.0); + + // test if point is inside epsilon-range around the given PolyPolygon. Can be used + // for HitTesting. The epsilon-range is defined to be the tube around the PolyPolygon + // with distance fDistance and rounded edges (start and end point). + BASEGFX_DLLPUBLIC bool isInEpsilonRange(const B2DPolyPolygon& rCandidate, const B2DPoint& rTestPosition, double fDistance); + + /** Helper class to transport PointIndices to a PolyPolygon, + with an operator< for convenient sorting in a std::set usage + */ + class SAL_WARN_UNUSED BASEGFX_DLLPUBLIC PointIndex + { + private: + sal_uInt32 mnPolygonIndex; + sal_uInt32 mnPointIndex; + + public: + PointIndex(sal_uInt32 nPolygonIndex, sal_uInt32 nPointIndex) + : mnPolygonIndex(nPolygonIndex), + mnPointIndex(nPointIndex) + {} + + sal_uInt32 getPolygonIndex() const { return mnPolygonIndex; } + sal_uInt32 getPointIndex() const { return mnPointIndex; } + bool operator<(const PointIndex& rComp) const; + }; + + /** the PointIndexSet itself; it allows to define a 'selection'of + points in a tools::PolyPolygon by giving the polygon and point index. + Adding points double makes no sense, hence the std::set + */ + typedef o3tl::sorted_vector< PointIndex > PointIndexSet; + + /** Read poly-polygon from SVG. + + This function imports a poly-polygon from an SVG-D + attribute. + + @param o_rPolyPoly + The output poly-polygon + + @param rSvgDAttribute + A valid SVG-D attribute string + + @param bHandleRelativeNextPointCompatible + If set to true, the old error that after a relative 'z' command + the current point was not reset to the first point of the current + polygon is kept; this is needed to read odf files. + If false, pure svg is used; this is needed for svg import. + + @param pHelpPointIndexSet + If given, all points created in the target PolyPolygon + which are only helper points are added here using their + point indices; this are currently points created from + import of the 'a' and 'A' svg:d statements which create + bezier curve info as representation and maybe points + which are no 'real' svg:d points, but helper points. It + is necessary to identify these e.g. when markers need to + be created in the svg import + + @return true, if the string was successfully parsed + */ + BASEGFX_DLLPUBLIC bool importFromSvgD( + B2DPolyPolygon& o_rPolyPoly, + std::u16string_view rSvgDAttribute, + bool bHandleRelativeNextPointCompatible, + PointIndexSet* pHelpPointIndexSet); + + // grow for polyPolygon. Move all geometry in each point in the direction of the normal in that point + // with the given amount. Value may be negative. + BASEGFX_DLLPUBLIC B2DPolyPolygon growInNormalDirection(const B2DPolyPolygon& rCandidate, double fValue); + + // force all sub-polygons to a point count of nSegments + BASEGFX_DLLPUBLIC B2DPolyPolygon reSegmentPolyPolygon(const B2DPolyPolygon& rCandidate, sal_uInt32 nSegments); + + // create polygon state at t from 0.0 to 1.0 between the two polygons. Both polygons must have the same + // organisation, e.g. same amount of polygons + BASEGFX_DLLPUBLIC B2DPolyPolygon interpolate(const B2DPolyPolygon& rOld1, const B2DPolyPolygon& rOld2, double t); + + // create 3d tools::PolyPolygon from given 2d PolyPolygon. The given fZCoordinate is used to expand the + // third coordinate. + BASEGFX_DLLPUBLIC B3DPolyPolygon createB3DPolyPolygonFromB2DPolyPolygon(const B2DPolyPolygon& rCandidate, double fZCoordinate = 0.0); + + // create 2d tools::PolyPolygon from given 3d PolyPolygon. All coordinates are transformed using the given + // matrix and the resulting x,y is used to form the new polygon. + BASEGFX_DLLPUBLIC B2DPolyPolygon createB2DPolyPolygonFromB3DPolyPolygon(const B3DPolyPolygon& rCandidate, const B3DHomMatrix& rMat); + + // for each contained edge in each contained polygon calculate the smallest distance. Return the index to the smallest + // edge in rEdgeIndex and the index to the polygon in rPolygonIndex. The relative position on the edge is returned in rCut. + // If nothing was found (e.g. empty input plygon), DBL_MAX is returned. + BASEGFX_DLLPUBLIC double getSmallestDistancePointToPolyPolygon(const B2DPolyPolygon& rCandidate, const B2DPoint& rTestPoint, sal_uInt32& rPolygonIndex, sal_uInt32& rEdgeIndex, double& rCut); + + // distort PolyPolygon. rOriginal describes the original range, where the given points describe the distorted + // corresponding points. + BASEGFX_DLLPUBLIC B2DPolyPolygon distort(const B2DPolyPolygon& rCandidate, const B2DRange& rOriginal, const B2DPoint& rTopLeft, const B2DPoint& rTopRight, const B2DPoint& rBottomLeft, const B2DPoint& rBottomRight); + + // expand all segments (which are not yet) to curve segments. This is done with setting the control + // vectors on the 1/3 resp. 2/3 distances on each segment. + BASEGFX_DLLPUBLIC B2DPolyPolygon expandToCurve(const B2DPolyPolygon& rCandidate); + + /** Predicate whether a given poly-polygon is a rectangle. + + @param rPoly + tools::PolyPolygon to check + + @return true, if the poly-polygon describes a rectangle + (contains exactly one polygon, polygon is closed, and the + points are either cw or ccw enumerations of a rectangle's + vertices). Note that intermediate points and duplicate + points are ignored. + */ + BASEGFX_DLLPUBLIC bool isRectangle( const B2DPolyPolygon& rPoly ); + + /** Export poly-polygon to SVG. + + This function exports a poly-polygon into an SVG-D + statement. Currently, output of relative point sequences + is not yet supported (might cause slightly larger output) + + @param rPolyPoly + The poly-polygon to export + + @param bUseRelativeCoordinates + When true, all coordinate values are exported as relative + to the current position. This tends to save some space, + since fewer digits needs to be written. + + @param bDetectQuadraticBeziers + When true, the export tries to detect cubic bezier + segments in the input polygon, which can be represented by + quadratic bezier segments. Note that the generated string + causes versions prior to OOo2.0 to crash. + + @param bHandleRelativeNextPointCompatible + If set to true, the old error that after a relative 'z' command + the current point was not reset to the first point of the current + polygon is kept; this is needed to read odf files. + If false, pure svg is used; this is needed for svg import. + + @param bOOXMLMotionPath + If set to true, export string format that is acceptable for + for animation motion path for PowerPoint: always space delimited, + never neglect command char, always end with E, and do not export + H or V. + + @return the generated SVG-D statement (the XML d attribute + value alone, without any "" or "d="...") + */ + BASEGFX_DLLPUBLIC OUString exportToSvgD( + const B2DPolyPolygon& rPolyPoly, + bool bUseRelativeCoordinates, + bool bDetectQuadraticBeziers, + bool bHandleRelativeNextPointCompatible, + bool bOOXMLMotionPath = false); + + // #i76891# Try to remove existing curve segments if they are simply edges + BASEGFX_DLLPUBLIC B2DPolyPolygon simplifyCurveSegments(const B2DPolyPolygon& rCandidate); + + /** Creates polypolygon for seven-segment display number + + This function takes an integer number between 0 and 9 and + convert it into the well-known seven-segment display + number (like most digital clocks show their numbers). The + digit will exactly fit the unit rectangle. The polypolygon + will be a line polygon, i.e. if you need the segment parts + to have width, use createAreaGeometry() on the result. + + @param cNumber + Number from '0' to '9' as ASCII char, or '-', 'E' and '.' + to convert to 7 segment code + + @param bLitSegments + When true, return a polygon containing the segments that + are 'lit' for the given number. Return un-lit segments + otherwise. + */ + B2DPolyPolygon createSevenSegmentPolyPolygon(char cNumber, bool bLitSegments); + + /** snap some polygon coordinates to discrete coordinates + + This method allows to snap some polygon points to discrete (integer) values + which equals e.g. a snap to discrete coordinates. It will snap points of + horizontal and vertical edges + + @param rCandidate + The source polygon + + @return + The modified version of the source polygon + */ + BASEGFX_DLLPUBLIC B2DPolyPolygon snapPointsOfHorizontalOrVerticalEdges(const B2DPolyPolygon& rCandidate); + + /// converters for css::drawing::PointSequence + BASEGFX_DLLPUBLIC B2DPolyPolygon UnoPointSequenceSequenceToB2DPolyPolygon( + const css::drawing::PointSequenceSequence& rPointSequenceSequenceSource); + BASEGFX_DLLPUBLIC void B2DPolyPolygonToUnoPointSequenceSequence( + const B2DPolyPolygon& rPolyPolygon, + css::drawing::PointSequenceSequence& rPointSequenceSequenceRetval); + + /// converters for css::drawing::PolyPolygonBezierCoords (curved polygons) + BASEGFX_DLLPUBLIC B2DPolyPolygon UnoPolyPolygonBezierCoordsToB2DPolyPolygon( + const css::drawing::PolyPolygonBezierCoords& rPolyPolygonBezierCoordsSource); + BASEGFX_DLLPUBLIC void B2DPolyPolygonToUnoPolyPolygonBezierCoords( + const B2DPolyPolygon& rPolyPolygon, + css::drawing::PolyPolygonBezierCoords& rPolyPolygonBezierCoordsRetval); + +} // end of namespace basegfx::utils + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/include/basegfx/polygon/b2dtrapezoid.hxx b/include/basegfx/polygon/b2dtrapezoid.hxx new file mode 100644 index 0000000000..aeed7148e2 --- /dev/null +++ b/include/basegfx/polygon/b2dtrapezoid.hxx @@ -0,0 +1,108 @@ +/* -*- 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 . + */ + +#pragma once + +#include +#include +#include +#include + + +namespace basegfx { class B2DPolyPolygon; } +namespace basegfx { class B2DPoint; } + +namespace basegfx +{ + // class to hold a single trapezoid + class UNLESS_MERGELIBS(BASEGFX_DLLPUBLIC) B2DTrapezoid + { + private: + // Geometry data. YValues are down-oriented, this means bottom should + // be bigger than top to be below it. The constructor implementation + // guarantees: + + // - mfBottomY >= mfTopY + // - mfTopXRight >= mfTopXLeft + // - mfBottomXRight >= mfBottomXLeft + double mfTopXLeft; + double mfTopXRight; + double mfTopY; + double mfBottomXLeft; + double mfBottomXRight; + double mfBottomY; + + public: + // constructor + B2DTrapezoid( + const double& rfTopXLeft, + const double& rfTopXRight, + const double& rfTopY, + const double& rfBottomXLeft, + const double& rfBottomXRight, + const double& rfBottomY); + + // data read access + const double& getTopXLeft() const { return mfTopXLeft; } + const double& getTopXRight() const { return mfTopXRight; } + const double& getTopY() const { return mfTopY; } + const double& getBottomXLeft() const { return mfBottomXLeft; } + const double& getBottomXRight() const { return mfBottomXRight; } + const double& getBottomY() const { return mfBottomY; } + + // convenience method to get content as Polygon + B2DPolygon getB2DPolygon() const; + }; + + typedef ::std::vector< B2DTrapezoid > B2DTrapezoidVector; + +} // end of namespace basegfx + + +namespace basegfx::utils +{ + // convert SourcePolyPolygon to trapezoids. The trapezoids will be appended to + // ro_Result. ro_Result will not be cleared. If SourcePolyPolygon contains curves, + // it's default AdaptiveSubdivision will be used. + // CAUTION: Trapezoids are orientation-dependent in the sense that the upper and lower + // lines have to be parallel to the X-Axis, thus this subdivision is NOT simply usable + // for primitive decompositions. To use it, the shear and rotate parts of the + // involved transformations HAVE to be taken into account. + BASEGFX_DLLPUBLIC void trapezoidSubdivide( + B2DTrapezoidVector& ro_Result, + const B2DPolyPolygon& rSourcePolyPolygon); + + // directly create trapezoids from given edge. Depending on the given geometry, + // none up to three trapezoids will be created + void createLineTrapezoidFromEdge( + B2DTrapezoidVector& ro_Result, + const B2DPoint& rPointA, + const B2DPoint& rPointB, + double fLineWidth); + + // create trapezoids for all edges of the given polygon. The closed state of + // the polygon is taken into account. If curves are contained, the default + // AdaptiveSubdivision will be used. + void createLineTrapezoidFromB2DPolygon( + B2DTrapezoidVector& ro_Result, + const B2DPolygon& rPolygon, + double fLineWidth); +} // end of namespace basegfx::utils + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/include/basegfx/polygon/b3dpolygon.hxx b/include/basegfx/polygon/b3dpolygon.hxx new file mode 100644 index 0000000000..13f8ed293f --- /dev/null +++ b/include/basegfx/polygon/b3dpolygon.hxx @@ -0,0 +1,120 @@ +/* -*- 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 . + */ + +#pragma once + +#include +#include +#include + +class ImplB3DPolygon; + +namespace basegfx +{ + class B3DPoint; + class B3DHomMatrix; + class B3DVector; + class B2DPoint; + class B2DHomMatrix; + class BColor; +} + +namespace basegfx +{ + class BASEGFX_DLLPUBLIC B3DPolygon + { + public: + typedef o3tl::cow_wrapper< ImplB3DPolygon, o3tl::ThreadSafeRefCountingPolicy > ImplType; + + private: + // internal data. + ImplType mpPolygon; + + public: + B3DPolygon(); + B3DPolygon(const B3DPolygon& rPolygon); + B3DPolygon(B3DPolygon&& rPolygon); + ~B3DPolygon(); + + // assignment operator + B3DPolygon& operator=(const B3DPolygon& rPolygon); + B3DPolygon& operator=(B3DPolygon&& rPolygon); + + // compare operators + bool operator==(const B3DPolygon& rPolygon) const; + + // member count + sal_uInt32 count() const; + + // Coordinate interface + B3DPoint const & getB3DPoint(sal_uInt32 nIndex) const; + void setB3DPoint(sal_uInt32 nIndex, const B3DPoint& rValue); + + // Coordinate append + void append(const B3DPoint& rPoint, sal_uInt32 nCount = 1); + + // BColor interface + BColor const & getBColor(sal_uInt32 nIndex) const; + void setBColor(sal_uInt32 nIndex, const BColor& rValue); + bool areBColorsUsed() const; + void clearBColors(); + + // Normals interface + B3DVector const & getNormal() const; // plane normal + B3DVector const & getNormal(sal_uInt32 nIndex) const; // normal in each point + void setNormal(sal_uInt32 nIndex, const B3DVector& rValue); + void transformNormals(const B3DHomMatrix& rMatrix); + bool areNormalsUsed() const; + void clearNormals(); + + // TextureCoordinate interface + B2DPoint const & getTextureCoordinate(sal_uInt32 nIndex) const; + void setTextureCoordinate(sal_uInt32 nIndex, const B2DPoint& rValue); + void transformTextureCoordinates(const B2DHomMatrix& rMatrix); + bool areTextureCoordinatesUsed() const; + void clearTextureCoordinates(); + + // append other 2D polygons + void append(const B3DPolygon& rPoly, sal_uInt32 nIndex = 0, sal_uInt32 nCount = 0); + + // remove + void remove(sal_uInt32 nIndex, sal_uInt32 nCount = 1); + + // clear all points + void clear(); + + // closed state + bool isClosed() const; + void setClosed(bool bNew); + + // flip polygon direction + void flip(); + + // test if Polygon has double points + bool hasDoublePoints() const; + + // remove double points, at the begin/end and follow-ups, too + void removeDoublePoints(); + + // apply transformation given in matrix form to the polygon + void transform(const B3DHomMatrix& rMatrix); + }; +} // end of namespace basegfx + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/include/basegfx/polygon/b3dpolygontools.hxx b/include/basegfx/polygon/b3dpolygontools.hxx new file mode 100644 index 0000000000..2f890809cf --- /dev/null +++ b/include/basegfx/polygon/b3dpolygontools.hxx @@ -0,0 +1,129 @@ +/* -*- 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 . + */ + +#pragma once + +#include +#include + +#include +#include +#include + +namespace basegfx +{ + class B3DPolyPolygon; + class B3DPolygon; + class B3DRange; +} + +namespace basegfx::utils +{ + // B3DPolygon tools + + /** Check if given polygon is closed. This is kind of a + 'classic' method to support old polygon definitions. + Those old polygon definitions define the closed state + of the polygon using identical start and endpoints. This + method corrects this (removes double start/end points) + and sets the Closed()-state of the polygon correctly. + */ + BASEGFX_DLLPUBLIC void checkClosed(B3DPolygon& rCandidate); + + // Get successor and predecessor indices. Returning the same index means there + // is none. Same for successor. + BASEGFX_DLLPUBLIC sal_uInt32 getIndexOfSuccessor(sal_uInt32 nIndex, const B3DPolygon& rCandidate); + + // get size of polygon. Control vectors are included in that ranges. + BASEGFX_DLLPUBLIC B3DRange getRange(const B3DPolygon& rCandidate); + + // get length of polygon + BASEGFX_DLLPUBLIC double getLength(const B3DPolygon& rCandidate); + + /** Apply given LineDashing to given polygon + + For a description see applyLineDashing in b2dpolygontoos.hxx + Also 2nd version with callbacks, see comments in 2D version + */ + void applyLineDashing( + const B3DPolygon& rCandidate, + const std::vector& rDotDashArray, + const std::function& rLineTargetCallback, + double fDotDashLength = 0.0); + BASEGFX_DLLPUBLIC void applyLineDashing( + const B3DPolygon& rCandidate, + const ::std::vector& rDotDashArray, + B3DPolyPolygon* pLineTarget, + double fDotDashLength = 0.0); + + /** Create/replace normals for given 3d geometry with default normals from given center to outside. + rCandidate: the 3d geometry to change + rCenter: the center of the 3d geometry + */ + B3DPolygon applyDefaultNormalsSphere( const B3DPolygon& rCandidate, const B3DPoint& rCenter); + + /** invert normals for given 3d geometry. + */ + BASEGFX_DLLPUBLIC B3DPolygon invertNormals( const B3DPolygon& rCandidate); + + /** Create/replace texture coordinates for given 3d geometry with parallel projected one + rRange: the full range of the 3d geometry + If bChangeX, x texture coordinate will be recalculated. + If bChangeY, y texture coordinate will be recalculated. + */ + B3DPolygon applyDefaultTextureCoordinatesParallel( const B3DPolygon& rCandidate, const B3DRange& rRange, bool bChangeX, bool bChangeY); + + /** Create/replace texture coordinates for given 3d geometry with spherical one + rCenter: the centre of the used 3d geometry + If bChangeX, x texture coordinate will be recalculated. + If bChangeY, y texture coordinate will be recalculated. + */ + B3DPolygon applyDefaultTextureCoordinatesSphere( const B3DPolygon& rCandidate, const B3DPoint& rCenter, bool bChangeX, bool bChangeY); + + // isInside tests for B3DPoint. On border is not inside as long as not true is given in bWithBorder flag. + BASEGFX_DLLPUBLIC bool isInside(const B3DPolygon& rCandidate, const B3DPoint& rPoint, bool bWithBorder); + + // calculates if given point is on given line, taking care of the numerical epsilon + BASEGFX_DLLPUBLIC bool isPointOnLine(const B3DPoint& rStart, const B3DPoint& rEnd, const B3DPoint& rCandidate, bool bWithPoints); + + // calculates if given point is on given polygon, taking care of the numerical epsilon. Uses + // isPointOnLine internally + BASEGFX_DLLPUBLIC bool isPointOnPolygon(const B3DPolygon& rCandidate, const B3DPoint& rPoint); + + // helper to get a fCut position between a plane (given with normal and a point) + // and a line given by start and end point + BASEGFX_DLLPUBLIC bool getCutBetweenLineAndPlane(const B3DVector& rPlaneNormal, const B3DPoint& rPlanePoint, const B3DPoint& rEdgeStart, const B3DPoint& rEdgeEnd, double& fCut); + + /** snap some polygon coordinates to discrete coordinates + + This method allows to snap some polygon points to discrete (integer) values + which equals e.g. a snap to discrete coordinates. It will snap points of + horizontal and vertical edges + + @param rCandidate + The source polygon + + @return + The modified version of the source polygon + */ + BASEGFX_DLLPUBLIC B3DPolygon snapPointsOfHorizontalOrVerticalEdges(const B3DPolygon& rCandidate); + +} // end of namespace basegfx::utils + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/include/basegfx/polygon/b3dpolypolygon.hxx b/include/basegfx/polygon/b3dpolypolygon.hxx new file mode 100644 index 0000000000..14a062c08c --- /dev/null +++ b/include/basegfx/polygon/b3dpolypolygon.hxx @@ -0,0 +1,113 @@ +/* -*- 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 . + */ + +#pragma once + +#include +#include +#include + +class ImplB3DPolyPolygon; + +namespace basegfx +{ + class B3DPolygon; + class B3DHomMatrix; + class B2DHomMatrix; +} + +namespace basegfx +{ + class BASEGFX_DLLPUBLIC B3DPolyPolygon + { + public: + typedef o3tl::cow_wrapper< ImplB3DPolyPolygon, o3tl::ThreadSafeRefCountingPolicy > ImplType; + + private: + ImplType mpPolyPolygon; + + public: + B3DPolyPolygon(); + B3DPolyPolygon(const B3DPolyPolygon& rPolyPolygon); + B3DPolyPolygon(B3DPolyPolygon&& rPolygon); + explicit B3DPolyPolygon(const B3DPolygon& rPolygon); + ~B3DPolyPolygon(); + + // assignment operator + B3DPolyPolygon& operator=(const B3DPolyPolygon& rPolyPolygon); + B3DPolyPolygon& operator=(B3DPolyPolygon&& rPolyPolygon); + + // compare operators + bool operator==(const B3DPolyPolygon& rPolyPolygon) const; + bool operator!=(const B3DPolyPolygon& rPolyPolygon) const; + + // polygon interface + sal_uInt32 count() const; + + // B3DPolygon interface + B3DPolygon const & getB3DPolygon(sal_uInt32 nIndex) const; + void setB3DPolygon(sal_uInt32 nIndex, const B3DPolygon& rPolygon); + + // BColor interface + bool areBColorsUsed() const; + void clearBColors(); + + // Normals interface + void transformNormals(const B3DHomMatrix& rMatrix); + bool areNormalsUsed() const; + void clearNormals(); + + // TextureCoordinate interface + void transformTextureCoordinates(const B2DHomMatrix& rMatrix); + bool areTextureCoordinatesUsed() const; + void clearTextureCoordinates(); + + // append single polygon + void append(const B3DPolygon& rPolygon, sal_uInt32 nCount = 1); + + // append multiple polygons + void append(const B3DPolyPolygon& rPolyPolygon); + + // remove + void remove(sal_uInt32 nIndex, sal_uInt32 nCount = 1); + + // reset to empty state + void clear(); + + // flip polygon direction + void flip(); + + // test if tools::PolyPolygon has double points + bool hasDoublePoints() const; + + // remove double points, at the begin/end and follow-ups, too + void removeDoublePoints(); + + // apply transformation given in matrix form to the polygon + void transform(const basegfx::B3DHomMatrix& rMatrix); + + // polygon iterators (same iterator validity conditions as for vector) + const B3DPolygon* begin() const; + const B3DPolygon* end() const; + B3DPolygon* begin(); + B3DPolygon* end(); + }; +} // end of namespace basegfx + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/include/basegfx/polygon/b3dpolypolygontools.hxx b/include/basegfx/polygon/b3dpolypolygontools.hxx new file mode 100644 index 0000000000..d201696dc8 --- /dev/null +++ b/include/basegfx/polygon/b3dpolypolygontools.hxx @@ -0,0 +1,132 @@ +/* -*- 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 . + */ + +#pragma once + +#include +#include + +namespace com::sun::star::drawing { struct PolyPolygonShape3D; } + +namespace basegfx +{ + class B3DPolyPolygon; + class B3DRange; +} + +namespace basegfx::utils +{ + // B3DPolyPolygon tools + + // get size of PolyPolygon. Control vectors are included in that ranges. + BASEGFX_DLLPUBLIC B3DRange getRange(const B3DPolyPolygon& rCandidate); + + /** Create a unit 3D line polyPolygon which defines a cube. + */ + B3DPolyPolygon const & createUnitCubePolyPolygon(); + + /** Create a unit 3D fill polyPolygon which defines a cube. + */ + B3DPolyPolygon const & createUnitCubeFillPolyPolygon(); + + /** Create a 3D line polyPolygon from a B3DRange which defines a cube. + */ + BASEGFX_DLLPUBLIC B3DPolyPolygon createCubePolyPolygonFromB3DRange( const B3DRange& rRange); + + /** Create a 3D fill polyPolygon from a B3DRange which defines a cube. + */ + BASEGFX_DLLPUBLIC B3DPolyPolygon createCubeFillPolyPolygonFromB3DRange( const B3DRange& rRange); + + /** Create a unit 3D line polyPolygon which defines a sphere with the given count of hor and ver segments. + Result will be centered at (0.0, 0.0, 0.0) and sized [-1.0 .. 1.0] in all dimensions. + If nHorSeg == 0 and/or nVerSeg == 0, a default will be calculated to have a step at least each 15 degrees. + With VerStart, VerStop and hor range in cartesian may be specified to create a partial sphere only. + */ + B3DPolyPolygon createUnitSpherePolyPolygon( + sal_uInt32 nHorSeg, sal_uInt32 nVerSeg, + double fVerStart = M_PI_2, double fVerStop = -M_PI_2, + double fHorStart = 0.0, double fHorStop = 2 * M_PI); + + /** Create a 3D line polyPolygon from a B3DRange which defines a sphere with the given count of hor and ver segments. + If nHorSeg == 0 and/or nVerSeg == 0, a default will be calculated to have a step at least each 15 degrees. + With VerStart, VerStop and hor range in cartesian may be specified to create a partial sphere only. + */ + BASEGFX_DLLPUBLIC B3DPolyPolygon createSpherePolyPolygonFromB3DRange( + const B3DRange& rRange, + sal_uInt32 nHorSeg, sal_uInt32 nVerSeg, + double fVerStart = M_PI_2, double fVerStop = -M_PI_2, + double fHorStart = 0.0, double fHorStop = 2 * M_PI); + + /** same as createUnitSpherePolyPolygon, but creates filled polygons (closed and oriented) + There is one extra, the bool bNormals defines if normals will be set, default is false + */ + BASEGFX_DLLPUBLIC B3DPolyPolygon createUnitSphereFillPolyPolygon( + sal_uInt32 nHorSeg, sal_uInt32 nVerSeg, + bool bNormals = false, + double fVerStart = M_PI_2, double fVerStop = -M_PI_2, + double fHorStart = 0.0, double fHorStop = 2 * M_PI); + + /** same as createSpherePolyPolygonFromB3DRange, but creates filled polygons (closed and oriented) + There is one extra, the bool bNormals defines if normals will be set, default is false + */ + BASEGFX_DLLPUBLIC B3DPolyPolygon createSphereFillPolyPolygonFromB3DRange( + const B3DRange& rRange, + sal_uInt32 nHorSeg, sal_uInt32 nVerSeg, + bool bNormals = false, + double fVerStart = M_PI_2, double fVerStop = -M_PI_2, + double fHorStart = 0.0, double fHorStop = 2 * M_PI); + + /** Create/replace normals for given 3d geometry with default normals from given center to outside. + rCandidate: the 3d geometry to change + rCenter: the center of the 3d geometry + */ + BASEGFX_DLLPUBLIC B3DPolyPolygon applyDefaultNormalsSphere( const B3DPolyPolygon& rCandidate, const B3DPoint& rCenter); + + /** invert normals for given 3d geometry. + */ + BASEGFX_DLLPUBLIC B3DPolyPolygon invertNormals( const B3DPolyPolygon& rCandidate); + + /** Create/replace texture coordinates for given 3d geometry with parallel projected one + rRange: the full range of the 3d geometry + If bChangeX, x texture coordinate will be recalculated. + If bChangeY, y texture coordinate will be recalculated. + */ + BASEGFX_DLLPUBLIC B3DPolyPolygon applyDefaultTextureCoordinatesParallel( const B3DPolyPolygon& rCandidate, const B3DRange& rRange, bool bChangeX = true, bool bChangeY = true); + + /** Create/replace texture coordinates for given 3d geometry with spherical one + rCenter: the centre of the used 3d geometry + If bChangeX, x texture coordinate will be recalculated. + If bChangeY, y texture coordinate will be recalculated. + */ + BASEGFX_DLLPUBLIC B3DPolyPolygon applyDefaultTextureCoordinatesSphere( const B3DPolyPolygon& rCandidate, const B3DPoint& rCenter, bool bChangeX = true, bool bChangeY = true); + + // isInside test for B3DPoint. On border is not inside. + // It is assumed that the orientations of the given polygon are correct. + BASEGFX_DLLPUBLIC bool isInside(const B3DPolyPolygon& rCandidate, const B3DPoint& rPoint); + + /// converters for css::drawing::PolyPolygonShape3D + BASEGFX_DLLPUBLIC B3DPolyPolygon UnoPolyPolygonShape3DToB3DPolyPolygon( + const css::drawing::PolyPolygonShape3D& rPolyPolygonShape3DSource); + BASEGFX_DLLPUBLIC void B3DPolyPolygonToUnoPolyPolygonShape3D( + const B3DPolyPolygon& rPolyPolygonSource, + css::drawing::PolyPolygonShape3D& rPolyPolygonShape3DRetval); + +} // end of namespace basegfx::utils + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/include/basegfx/range/Range2D.hxx b/include/basegfx/range/Range2D.hxx new file mode 100644 index 0000000000..57e472a98a --- /dev/null +++ b/include/basegfx/range/Range2D.hxx @@ -0,0 +1,184 @@ +/* -*- 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 . + */ + +#pragma once + +#include +#include + +namespace basegfx +{ +template class Range2D +{ +protected: + basegfx::BasicRange maRangeX; + basegfx::BasicRange maRangeY; + +public: + typedef TYPE ValueType; + typedef TRAITS TraitsType; + + Range2D() = default; + + /// Create degenerate interval consisting of a single point + explicit Range2D(const Tuple2D& rTuple) + : maRangeX(rTuple.getX()) + , maRangeY(rTuple.getY()) + { + } + + /// Create proper interval between the two given points + Range2D(const Tuple2D& rTuple1, const Tuple2D& rTuple2) + : maRangeX(rTuple1.getX()) + , maRangeY(rTuple1.getY()) + { + expand(rTuple2); + } + + /// Create proper interval between the two given pairs + Range2D(TYPE x1, TYPE y1, TYPE x2, TYPE y2) + : maRangeX(x1) + , maRangeY(y1) + { + maRangeX.expand(x2); + maRangeY.expand(y2); + } + + /** Check if the interval set is empty + + @return false, if no value is in this set - having a + single point included will already return true. + */ + bool isEmpty() const { return maRangeX.isEmpty() || maRangeY.isEmpty(); } + + /// reset the object to empty state again, clearing all values + void reset() + { + maRangeX.reset(); + maRangeY.reset(); + } + + bool operator==(const Range2D& rRange) const + { + return maRangeX == rRange.maRangeX && maRangeY == rRange.maRangeY; + } + + bool operator!=(const Range2D& rRange) const + { + return maRangeX != rRange.maRangeX || maRangeY != rRange.maRangeY; + } + + bool equal(const Range2D& rRange) const + { + return maRangeX.equal(rRange.maRangeX) && maRangeY.equal(rRange.maRangeY); + } + + /// get lower bound of the set. returns arbitrary values for empty sets. + TYPE getMinX() const { return maRangeX.getMinimum(); } + + /// get lower bound of the set. returns arbitrary values for empty sets. + TYPE getMinY() const { return maRangeY.getMinimum(); } + + /// get upper bound of the set. returns arbitrary values for empty sets. + TYPE getMaxX() const { return maRangeX.getMaximum(); } + + /// get upper bound of the set. returns arbitrary values for empty sets. + TYPE getMaxY() const { return maRangeY.getMaximum(); } + + /// return difference between upper and lower X value. returns 0 for empty sets. + TYPE getWidth() const { return maRangeX.getRange(); } + + /// return difference between upper and lower Y value. returns 0 for empty sets. + TYPE getHeight() const { return maRangeY.getRange(); } + + /// return center X value of set. returns 0 for empty sets. + double getCenterX() const { return maRangeX.getCenter(); } + + /// return center Y value of set. returns 0 for empty sets. + double getCenterY() const { return maRangeY.getCenter(); } + + /// yields true if given point is contained in set + bool isInside(const Tuple2D& rTuple) const + { + return maRangeX.isInside(rTuple.getX()) && maRangeY.isInside(rTuple.getY()); + } + + /// yields true if rRange is inside, or equal to set + bool isInside(const Range2D& rRange) const + { + return maRangeX.isInside(rRange.maRangeX) && maRangeY.isInside(rRange.maRangeY); + } + + /// yields true if rRange at least partly inside set + bool overlaps(const Range2D& rRange) const + { + return maRangeX.overlaps(rRange.maRangeX) && maRangeY.overlaps(rRange.maRangeY); + } + + /// yields true if overlaps(rRange) does, and the overlap is larger than infinitesimal + bool overlapsMore(const Range2D& rRange) const + { + return maRangeX.overlapsMore(rRange.maRangeX) && maRangeY.overlapsMore(rRange.maRangeY); + } + + /// add point to the set, expanding as necessary + void expand(const Tuple2D& rTuple) + { + maRangeX.expand(rTuple.getX()); + maRangeY.expand(rTuple.getY()); + } + + /// add rRange to the set, expanding as necessary + void expand(const Range2D& rRange) + { + maRangeX.expand(rRange.maRangeX); + maRangeY.expand(rRange.maRangeY); + } + + /// calc set intersection + void intersect(const Range2D& rRange) + { + maRangeX.intersect(rRange.maRangeX); + maRangeY.intersect(rRange.maRangeY); + } + + /// grow set by fValue on all sides + void grow(TYPE fValue) + { + maRangeX.grow(fValue); + maRangeY.grow(fValue); + } + + /// grow set by axis aware values from rTuple + void grow(const Tuple2D& rTuple) + { + maRangeX.grow(rTuple.getX()); + maRangeY.grow(rTuple.getY()); + } + + /// clamp value on range + Tuple2D clamp(const Tuple2D& rTuple) const + { + return Tuple2D(maRangeX.clamp(rTuple.getX()), maRangeY.clamp(rTuple.getY())); + } +}; + +} // end of namespace basegfx + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/include/basegfx/range/b1drange.hxx b/include/basegfx/range/b1drange.hxx new file mode 100644 index 0000000000..14d7f30251 --- /dev/null +++ b/include/basegfx/range/b1drange.hxx @@ -0,0 +1,159 @@ +/* -*- 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 . + */ + +#pragma once + +#include + + +namespace basegfx +{ + + /** A one-dimensional interval over doubles + + This is a set of real numbers, bounded by a lower and an upper + value. All inbetween values are included in the set (see also + http://en.wikipedia.org/wiki/Interval_%28mathematics%29). + + The set is closed, i.e. the upper and the lower bound are + included (if you're used to the notation - we're talking about + [a,b] here, compared to half-open [a,b) or open intervals + (a,b)). + + That means, isInside(val) will return true also for values of + val=a or val=b. + */ + class B1DRange + { + ::basegfx::BasicRange< double, DoubleTraits > maRange; + + public: + B1DRange() {} + + /// Create degenerate interval consisting of a single double number + explicit B1DRange(double fStartValue) + : maRange(fStartValue) + { + } + + /// Create proper interval between the two given double values + B1DRange(double fStartValue1, double fStartValue2) + : maRange(fStartValue1) + { + expand(fStartValue2); + } + + /** Check if the interval set is empty + + @return false, if no value is in this set - having a + single value included will already return true. + */ + bool isEmpty() const + { + return maRange.isEmpty(); + } + + bool operator==( const B1DRange& rRange ) const + { + return (maRange == rRange.maRange); + } + + bool operator!=( const B1DRange& rRange ) const + { + return (maRange != rRange.maRange); + } + + /// get lower bound of the set. returns arbitrary values for empty sets. + double getMinimum() const + { + return maRange.getMinimum(); + } + + /// get upper bound of the set. returns arbitrary values for empty sets. + double getMaximum() const + { + return maRange.getMaximum(); + } + + /// return difference between upper and lower value. returns 0 for empty sets. + double getRange() const + { + return maRange.getRange(); + } + + /// return middle of upper and lower value. returns 0 for empty sets. + double getCenter() const + { + return maRange.getCenter(); + } + + /// yields true if value is contained in set + bool isInside(double fValue) const + { + return maRange.isInside(fValue); + } + + /// yields true if rRange at least partly inside set + bool overlaps(const B1DRange& rRange) const + { + return maRange.overlaps(rRange.maRange); + } + + /// yields true if overlaps(rRange) does, and the overlap is larger than infinitesimal + bool overlapsMore(const B1DRange& rRange) const + { + return maRange.overlapsMore(rRange.maRange); + } + + /// add fValue to the set, expanding as necessary + void expand(double fValue) + { + maRange.expand(fValue); + } + + /// add rRange to the set, expanding as necessary + void expand(const B1DRange& rRange) + { + maRange.expand(rRange.maRange); + } + + /// calc set intersection + void intersect(const B1DRange& rRange) + { + maRange.intersect(rRange.maRange); + } + + /// clamp value on range + double clamp(double fValue) const + { + return maRange.clamp(fValue); + } + }; + + /** Write to char stream */ + template + inline std::basic_ostream& operator<<( + std::basic_ostream& stream, const B1DRange& range) + { + return stream << "[" << range.getMinimum() << ", " << range.getMaximum() << "]"; + } + +} // end of namespace basegfx + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/include/basegfx/range/b2dconnectedranges.hxx b/include/basegfx/range/b2dconnectedranges.hxx new file mode 100644 index 0000000000..f452fffb54 --- /dev/null +++ b/include/basegfx/range/b2dconnectedranges.hxx @@ -0,0 +1,238 @@ +/* -*- 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 . + */ + +#pragma once + +#include +#include +#include +#include + + +namespace basegfx +{ + /** Calculate connected ranges from input ranges. + + This template constructs a list of connected ranges from the + given input ranges. That is, the output will contain a set of + ranges, itself containing a number of input ranges, which will + be mutually non-intersecting. + + Example: + + ------------------- + | -------| + | | || + | --- | || + | | | -------| -------- + | | +--------- | | | + | --+ | | | | + | | | | -------- + | ---------- | + ------------------- + class B2DConnectedRanges + { + public: + /// Type of the basic entity (rect + user data) + typedef ::std::pair< B2DRange, UserData > ComponentType; + typedef ::std::list< ComponentType > ComponentListType; + + /// List of (intersecting) components, plus overall bounds + struct ConnectedComponents + { + ComponentListType maComponentList; + B2DRange maTotalBounds; + }; + + typedef ::std::list< ConnectedComponents > ConnectedComponentsType; + + + /// Create the range calculator + B2DConnectedRanges() : + maDisjunctAggregatesList() + { + } + + /** Add an additional range. + + This method integrates a new range into the connected + ranges lists. The method has a worst-case time complexity + of O(n^2), with n denoting the number of already added + ranges (typically, for well-behaved input, it is O(n) + though). + */ + void addRange( const B2DRange& rRange, + const UserData& rUserData ) + { + // check whether fast path is possible: if new range is + // outside accumulated total range, can add it as a + // separate component right away. + const bool bNotOutsideEverything( + maTotalBounds.overlaps( rRange ) ); + + // update own global bounds range + maTotalBounds.expand( rRange ); + + // assemble anything intersecting with rRange into + // this new connected component + ConnectedComponents aNewConnectedComponent; + + // as at least rRange will be a member of + // aNewConnectedComponent (will be added below), can + // preset the overall bounds here. + aNewConnectedComponent.maTotalBounds = rRange; + + + // STAGE 1: Search for intersecting maDisjunctAggregatesList entries + + + // if rRange is empty, it will intersect with no + // maDisjunctAggregatesList member. Thus, we can safe us + // the check. + // if rRange is outside all other rectangle, skip here, + // too + if( bNotOutsideEverything && + !rRange.isEmpty() ) + { + typename ConnectedComponentsType::iterator aCurrAggregate; + typename ConnectedComponentsType::iterator aLastAggregate; + + // flag, determining whether we touched one or more of + // the maDisjunctAggregatesList entries. _If_ we did, + // we have to repeat the intersection process, because + // these changes might have generated new + // intersections. + bool bSomeAggregatesChanged; + + // loop, until bSomeAggregatesChanged stays false + do + { + // only continue loop if 'intersects' branch below was hit + bSomeAggregatesChanged = false; + + // iterate over all current members of maDisjunctAggregatesList + for( aCurrAggregate=maDisjunctAggregatesList.begin(), + aLastAggregate=maDisjunctAggregatesList.end(); + aCurrAggregate != aLastAggregate; ) + { + // first check if current component's bounds + // are empty. This ensures that distinct empty + // components are not merged into one + // aggregate. As a matter of fact, they have + // no position and size. + + if( !aCurrAggregate->maTotalBounds.isEmpty() && + aCurrAggregate->maTotalBounds.overlaps( + aNewConnectedComponent.maTotalBounds ) ) + { + // union the intersecting + // maDisjunctAggregatesList element into + // aNewConnectedComponent + + // calc union bounding box + aNewConnectedComponent.maTotalBounds.expand( aCurrAggregate->maTotalBounds ); + + // extract all aCurrAggregate components + // to aNewConnectedComponent + aNewConnectedComponent.maComponentList.splice( + aNewConnectedComponent.maComponentList.end(), + aCurrAggregate->maComponentList ); + + // remove and delete aCurrAggregate entry + // from list (we've gutted it's content + // above). list::erase() will update our + // iterator with the predecessor here. + aCurrAggregate = maDisjunctAggregatesList.erase( aCurrAggregate ); + + // at least one aggregate changed, need to rescan everything + bSomeAggregatesChanged = true; + } + else + { + ++aCurrAggregate; + } + } + } + while( bSomeAggregatesChanged ); + } + + + // STAGE 2: Add newly generated connected component list element + + + // add new component to the end of the component list + aNewConnectedComponent.maComponentList.push_back( + ComponentType( rRange, rUserData ) ); + + // do some consistency checks (aka post conditions) + OSL_ENSURE( !aNewConnectedComponent.maComponentList.empty(), + "B2DConnectedRanges::addRange(): empty aggregate list" ); + OSL_ENSURE( !aNewConnectedComponent.maTotalBounds.isEmpty() || + aNewConnectedComponent.maComponentList.size() == 1, + "B2DConnectedRanges::addRange(): empty ranges must be solitary"); + + // add aNewConnectedComponent as a new entry to + // maDisjunctAggregatesList + maDisjunctAggregatesList.push_back( aNewConnectedComponent ); + } + + /** Apply a functor to each of the disjunct component + aggregates. + + @param aFunctor + Functor to apply. Must provide an operator( const ConnectedComponents& ). + + @return a copy of the functor, as applied to all aggregates. + */ + template< typename UnaryFunctor > UnaryFunctor forEachAggregate( UnaryFunctor aFunctor ) const + { + return ::std::for_each( maDisjunctAggregatesList.begin(), + maDisjunctAggregatesList.end(), + aFunctor ); + } + + private: + B2DConnectedRanges(const B2DConnectedRanges&) = delete; + B2DConnectedRanges& operator=( const B2DConnectedRanges& ) = delete; + + /** Current list of disjunct sets of connected components + + Each entry corresponds to one of the top-level rectangles + in the drawing above. + */ + ConnectedComponentsType maDisjunctAggregatesList; + + /** Global bound rect over all added ranges. + */ + B2DRange maTotalBounds; + }; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/include/basegfx/range/b2dpolyrange.hxx b/include/basegfx/range/b2dpolyrange.hxx new file mode 100644 index 0000000000..9a366956ce --- /dev/null +++ b/include/basegfx/range/b2dpolyrange.hxx @@ -0,0 +1,93 @@ +/* -*- 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 . + */ + +#pragma once + +#include +#include +#include +#include + +namespace basegfx +{ + class B2DRange; + class B2DPolyPolygon; + class B2DHomMatrix; + class ImplB2DPolyRange; + + /** Multiple ranges in one object. + + This class combines multiple ranges in one object, providing a + total, enclosing range for it. + + You can use this class e.g. when updating views containing + rectangular objects. Add each modified object to a + B2DMultiRange, then test each viewable object against + intersection with the multi range. + + Similar in spirit to the poly-polygon vs. polygon relationship. + + Note that comparable to polygons, a poly-range can also + contain 'holes' - this is encoded via polygon orientation at + the poly-polygon, and via explicit flags for the poly-range. + */ + class BASEGFX_DLLPUBLIC B2DPolyRange + { + public: + typedef std::tuple ElementType; + + B2DPolyRange(); + ~B2DPolyRange(); + + /** Create a multi range with exactly one containing range + */ + B2DPolyRange( const B2DPolyRange& ); + B2DPolyRange& operator=( const B2DPolyRange& ); + + bool operator==(const B2DPolyRange&) const; + bool operator!=(const B2DPolyRange&) const; + + /// Number of included ranges + sal_uInt32 count() const; + + ElementType getElement(sal_uInt32 nIndex) const; + + // insert/append a single range + void appendElement(const B2DRange& rRange, B2VectorOrientation eOrient); + + void clear(); + + /** Test whether given range overlaps one or more of the + included ranges. Does *not* use overall range, but checks + individually. + */ + bool overlaps( const B2DRange& rRange ) const; + + /** Request a poly-polygon with solved cross-overs + */ + B2DPolyPolygon solveCrossovers() const; + + void transform(const B2DHomMatrix& rTranslate); + + private: + o3tl::cow_wrapper< ImplB2DPolyRange > mpImpl; + }; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/include/basegfx/range/b2drange.hxx b/include/basegfx/range/b2drange.hxx new file mode 100644 index 0000000000..b0f726ac0e --- /dev/null +++ b/include/basegfx/range/b2drange.hxx @@ -0,0 +1,174 @@ +/* -*- 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 . + */ + +#pragma once + +#include +#include + +#include +#include +#include +#include +#include + +namespace basegfx +{ + class B2IRange; + class B2DHomMatrix; + + /** A two-dimensional interval over doubles + + This is a set of real numbers, bounded by a lower and an upper + pair. All inbetween values are included in the set (see also + http://en.wikipedia.org/wiki/Interval_%28mathematics%29). + + The set is closed, i.e. the upper and the lower bound are + included (if you're used to the notation - we're talking about + [a,b] here, compared to half-open [a,b) or open intervals + (a,b)). + + That means, isInside(val) will return true also for values of + val=a or val=b. + + @see B1DRange + */ + class SAL_WARN_UNUSED B2DRange : public Range2D + { + public: + B2DRange() + : Range2D() + {} + + /// Create degenerate interval consisting of a single point + explicit B2DRange(const Tuple2D& rTuple) + : Range2D(rTuple) + { + } + + /// Create proper interval between the two given points + B2DRange(const Tuple2D& rTuple1, + const Tuple2D& rTuple2) + : Range2D(rTuple1, rTuple2) + { + } + + B2DRange(ValueType x1, ValueType y1, ValueType x2, ValueType y2) + : Range2D(x1, y1, x2, y2) + {} + + BASEGFX_DLLPUBLIC explicit B2DRange(const B2IRange& rRange); + + /// get lower bound of the set. returns arbitrary values for empty sets. + B2DPoint getMinimum() const + { + return B2DPoint( + maRangeX.getMinimum(), + maRangeY.getMinimum() + ); + } + + /// get upper bound of the set. returns arbitrary values for empty sets. + B2DPoint getMaximum() const + { + return B2DPoint( + maRangeX.getMaximum(), + maRangeY.getMaximum() + ); + } + + /// return difference between upper and lower point. returns (0,0) for empty sets. + B2DVector getRange() const + { + return B2DVector( + maRangeX.getRange(), + maRangeY.getRange() + ); + } + + /// return center point of set. returns (0,0) for empty sets. + B2DPoint getCenter() const + { + return B2DPoint( + maRangeX.getCenter(), + maRangeY.getCenter() + ); + } + + /** Transform Range by given transformation matrix. */ + BASEGFX_DLLPUBLIC void transform(const B2DHomMatrix& rMatrix); + + /** Transform Range by given transformation matrix. + + This operation transforms the Range by transforming all four possible + extrema points (corners) of the given range and building a new one. + This means that the range will grow evtl. when a shear and/or rotation + is part of the transformation. + */ + BASEGFX_DLLPUBLIC B2DRange& operator*=( const ::basegfx::B2DHomMatrix& rMat ); + + /** Get a range filled with (0.0, 0.0, 1.0, 1.0) */ + BASEGFX_DLLPUBLIC static const B2DRange& getUnitB2DRange(); + }; + + /** Transform B2DRange by given transformation matrix (see operator*=()) + */ + B2DRange operator*( const B2DHomMatrix& rMat, const B2DRange& rB2DRange ); + + /** Round double to nearest integer for 2D range + + @return the nearest integer for this range + */ + BASEGFX_DLLPUBLIC B2IRange fround(const B2DRange& rRange); + + /** Compute the set difference of the two given ranges + + This method calculates the symmetric difference (aka XOR) + between the two given ranges, and returning the resulting + ranges. Thus, the result will contain all areas where one, but + not both ranges lie. + + @param o_rResult + Result vector. The up to four difference ranges are returned + within this vector + + @param rFirst + The first range + + @param rSecond + The second range + + @return the input vector + */ + BASEGFX_DLLPUBLIC std::vector& computeSetDifference( + std::vector& o_rResult, + const B2DRange& rFirst, + const B2DRange& rSecond); + + /** Write to char stream */ + template + inline std::basic_ostream& operator<<( + std::basic_ostream& stream, const B2DRange& range) + { + return stream << range.getWidth() << "x" << range.getHeight() << "@" << range.getMinimum(); + } + +} // end of namespace basegfx + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/include/basegfx/range/b2drangeclipper.hxx b/include/basegfx/range/b2drangeclipper.hxx new file mode 100644 index 0000000000..6ea0a3f0e2 --- /dev/null +++ b/include/basegfx/range/b2drangeclipper.hxx @@ -0,0 +1,39 @@ +/* -*- 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 . + */ + +#pragma once + +#include +#include +#include + +namespace basegfx::utils +{ + /** Extract poly-polygon w/o self-intersections from poly-range + + Similar to the solveCrossovers(const B2DPolyPolygon&) + method, this one calculates a self-intersection-free + poly-polygon with the same topology, and encoding + inside/outsidedness via polygon orientation and layering. + */ + BASEGFX_DLLPUBLIC B2DPolyPolygon solveCrossovers(const std::vector& rRanges, + const std::vector& rOrientations); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/include/basegfx/range/b2drectangle.hxx b/include/basegfx/range/b2drectangle.hxx new file mode 100644 index 0000000000..ad8744b5dd --- /dev/null +++ b/include/basegfx/range/b2drectangle.hxx @@ -0,0 +1,33 @@ +/* -*- 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 . + */ + +#pragma once + +#include + +namespace basegfx +{ +// syntactic sugar: a B2DRange exactly models a Rectangle, thus, +// for interface clarity, we provide an alias name + +/// Alias name for interface clarity (not everybody is aware of the identity) +typedef B2DRange B2DRectangle; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/include/basegfx/range/b2ibox.hxx b/include/basegfx/range/b2ibox.hxx new file mode 100644 index 0000000000..2be733b93e --- /dev/null +++ b/include/basegfx/range/b2ibox.hxx @@ -0,0 +1,190 @@ +/* -*- 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 . + */ + +#pragma once + +#include + +#include +#include + +namespace basegfx +{ + /** A two-dimensional interval over integers + + This is most easily depicted as a set of integers, bounded by + a lower and an upper value - but excluding the upper + value. All inbetween values are included in the set (see also + http://en.wikipedia.org/wiki/Interval_%28mathematics%29). + + The set is half-open, i.e. the lower bound is included, the + upper bound not (if you're used to the notation - we're + talking about [a,b) here, compared to closed [a,b] or fully + open intervals (a,b)). + + If you don't need a half-open interval, check B2IRange. + + That means, isInside(val) will return true also for values of + val=a, but not for val=b. + + Alternatively, consider this a rectangle, where the rightmost + pixel column and the bottommost pixel row are excluded - this + is much like polygon filling. As a result, filling a given + rectangle with basebmp::BitmapDevice::fillPolyPolygon(), will + affect exactly the same set of pixel as isInside() would + return true for. + + @see B2IRange + */ + class B2IBox + { + public: + typedef sal_Int32 ValueType; + typedef Int32Traits TraitsType; + + B2IBox() {} + + /// Create degenerate interval that's still empty + explicit B2IBox(const B2ITuple& rTuple) + : maRangeX(rTuple.getX()), + maRangeY(rTuple.getY()) + { + } + + /// Create proper interval between the two given points + B2IBox(sal_Int32 x1, + sal_Int32 y1, + sal_Int32 x2, + sal_Int32 y2) : + maRangeX(x1), + maRangeY(y1) + { + maRangeX.expand(x2); + maRangeY.expand(y2); + } + + /// Create proper interval between the two given points + B2IBox(const B2ITuple& rTuple1, + const B2ITuple& rTuple2) : + maRangeX(rTuple1.getX()), + maRangeY(rTuple1.getY()) + { + expand( rTuple2 ); + } + + /** Check if the interval set is empty + + @return false, if no value is in this set - having a + single value included will still return false. + */ + bool isEmpty() const + { + return maRangeX.isEmpty() || maRangeY.isEmpty(); + } + + bool operator==( const B2IBox& rBox ) const + { + return (maRangeX == rBox.maRangeX + && maRangeY == rBox.maRangeY); + } + + bool operator!=( const B2IBox& rBox ) const + { + return (maRangeX != rBox.maRangeX + || maRangeY != rBox.maRangeY); + } + + /// get lower bound of the set. returns arbitrary values for empty sets. + sal_Int32 getMinX() const + { + return maRangeX.getMinimum(); + } + + /// get lower bound of the set. returns arbitrary values for empty sets. + sal_Int32 getMinY() const + { + return maRangeY.getMinimum(); + } + + /// get upper bound of the set. returns arbitrary values for empty sets. + sal_Int32 getMaxX() const + { + return maRangeX.getMaximum(); + } + + /// get upper bound of the set. returns arbitrary values for empty sets. + sal_Int32 getMaxY() const + { + return maRangeY.getMaximum(); + } + + /// return difference between upper and lower X value. returns 0 for empty sets. + sal_Int64 getWidth() const + { + return maRangeX.getRange(); + } + + /// return difference between upper and lower Y value. returns 0 for empty sets. + sal_Int64 getHeight() const + { + return maRangeY.getRange(); + } + + /// yields true if point is contained in set + bool isInside(const B2ITuple& rTuple) const + { + return ( + maRangeX.isInside(rTuple.getX()) + && maRangeY.isInside(rTuple.getY()) + ); + } + + /// add point to the set, expanding as necessary + void expand(const B2ITuple& rTuple) + { + maRangeX.expand(rTuple.getX()); + maRangeY.expand(rTuple.getY()); + } + + /// calc set intersection + void intersect(const B2IBox& rBox) + { + maRangeX.intersect(rBox.maRangeX); + maRangeY.intersect(rBox.maRangeY); + } + + private: + BasicBox maRangeX; + BasicBox maRangeY; + }; + +} // end of namespace basegfx + +template< typename charT, typename traits > +inline std::basic_ostream & operator <<( + std::basic_ostream & stream, const basegfx::B2IBox& box ) +{ + if (box.isEmpty()) + return stream << "EMPTY"; + else + return stream << box.getWidth() << 'x' << box.getHeight() + << "@(" << box.getMinX() << "," << box.getMinY() << ")"; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/include/basegfx/range/b2irange.hxx b/include/basegfx/range/b2irange.hxx new file mode 100644 index 0000000000..602e64eddb --- /dev/null +++ b/include/basegfx/range/b2irange.hxx @@ -0,0 +1,140 @@ +/* -*- 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 . + */ + +#pragma once + +#include +#include + +#include +#include +#include +#include +#include + +namespace basegfx +{ + /** A two-dimensional interval over integers + + This is a set of real numbers, bounded by a lower and an upper + pair. All inbetween values are included in the set (see also + http://en.wikipedia.org/wiki/Interval_%28mathematics%29). + + Probably you rather want B2IBox for integers. + + The set is closed, i.e. the upper and the lower bound are + included (if you're used to the notation - we're talking about + [a,b] here, compared to half-open [a,b) or open intervals + (a,b)). + + That means, isInside(val) will return true also for values of + val=a or val=b. + + @see B2IBox + */ + class B2IRange : public Range2D + { + public: + B2IRange() + : Range2D() + {} + + /// Create degenerate interval consisting of a single point + explicit B2IRange(const Tuple2D& rTuple) + : Range2D(rTuple) + { + } + + /// Create proper interval between the two given points + B2IRange(const Tuple2D& rTuple1, + const Tuple2D& rTuple2) + : Range2D(rTuple1, rTuple2) + { + } + + B2IRange(ValueType x1, ValueType y1, ValueType x2, ValueType y2) + : Range2D(x1, y1, x2, y2) + {} + + /// get lower bound of the set. returns arbitrary values for empty sets. + B2IPoint getMinimum() const + { + return B2IPoint( + maRangeX.getMinimum(), + maRangeY.getMinimum() + ); + } + + /// get upper bound of the set. returns arbitrary values for empty sets. + B2IPoint getMaximum() const + { + return B2IPoint( + maRangeX.getMaximum(), + maRangeY.getMaximum() + ); + } + + /// return difference between upper and lower point. returns (0,0) for empty sets. + B2I64Tuple getRange() const + { + return B2I64Tuple( + maRangeX.getRange(), + maRangeY.getRange() + ); + } + }; + + /** Compute the set difference of the two given ranges + + This method calculates the symmetric difference (aka XOR) + between the two given ranges, and returning the resulting + ranges. Thus, the result will contain all areas where one, but + not both ranges lie. + + @param o_rResult + Result vector. The up to four difference ranges are returned + within this vector + + @param rFirst + The first range + + @param rSecond + The second range + + @return the input vector + */ + BASEGFX_DLLPUBLIC std::vector& computeSetDifference( + std::vector& o_rResult, + const B2IRange& rFirst, + const B2IRange& rSecond); + + /** Write to char stream */ + template + inline std::basic_ostream& operator<<( + std::basic_ostream& stream, const B2IRange& range) + { + if (range.isEmpty()) + return stream << "EMPTY"; + else + return stream << range.getWidth() << 'x' << range.getHeight() << "@" << range.getMinimum(); + } + +} // end of namespace basegfx + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/include/basegfx/range/b2irectangle.hxx b/include/basegfx/range/b2irectangle.hxx new file mode 100644 index 0000000000..6356fa6cf0 --- /dev/null +++ b/include/basegfx/range/b2irectangle.hxx @@ -0,0 +1,33 @@ +/* -*- 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 . + */ + +#pragma once + +#include + +namespace basegfx +{ +// syntactic sugar: a B2IRange exactly models a Rectangle, thus, +// for interface clarity, we provide an alias name + +/// Alias name for interface clarity (not everybody is aware of the identity) +typedef B2IRange B2IRectangle; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/include/basegfx/range/b3drange.hxx b/include/basegfx/range/b3drange.hxx new file mode 100644 index 0000000000..338c4f54a0 --- /dev/null +++ b/include/basegfx/range/b3drange.hxx @@ -0,0 +1,227 @@ +/* -*- 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 . + */ + +#pragma once + +#include +#include +#include +#include +#include + +namespace basegfx +{ + class B3DHomMatrix; + + class SAL_WARN_UNUSED B3DRange + { + typedef ::basegfx::BasicRange< double, DoubleTraits > MyBasicRange; + + MyBasicRange maRangeX; + MyBasicRange maRangeY; + MyBasicRange maRangeZ; + + public: + B3DRange() {} + + explicit B3DRange(const B3DTuple& rTuple) + : maRangeX(rTuple.getX()), + maRangeY(rTuple.getY()), + maRangeZ(rTuple.getZ()) + { + } + + B3DRange(double x1, + double y1, + double z1, + double x2, + double y2, + double z2) + : maRangeX(x1), + maRangeY(y1), + maRangeZ(z1) + { + maRangeX.expand(x2); + maRangeY.expand(y2); + maRangeZ.expand(z2); + } + + B3DRange(const B3DTuple& rTuple1, + const B3DTuple& rTuple2) + : maRangeX(rTuple1.getX()), + maRangeY(rTuple1.getY()), + maRangeZ(rTuple1.getZ()) + { + expand(rTuple2); + } + + bool isEmpty() const + { + return ( + maRangeX.isEmpty() + || maRangeY.isEmpty() + || maRangeZ.isEmpty() + ); + } + + void reset() + { + maRangeX.reset(); + maRangeY.reset(); + maRangeZ.reset(); + } + + bool operator==( const B3DRange& rRange ) const + { + return (maRangeX == rRange.maRangeX + && maRangeY == rRange.maRangeY + && maRangeZ == rRange.maRangeZ); + } + + bool operator!=( const B3DRange& rRange ) const + { + return (maRangeX != rRange.maRangeX + || maRangeY != rRange.maRangeY + || maRangeZ != rRange.maRangeZ); + } + + double getMinX() const + { + return maRangeX.getMinimum(); + } + + double getMinY() const + { + return maRangeY.getMinimum(); + } + + double getMinZ() const + { + return maRangeZ.getMinimum(); + } + + double getMaxX() const + { + return maRangeX.getMaximum(); + } + + double getMaxY() const + { + return maRangeY.getMaximum(); + } + + double getMaxZ() const + { + return maRangeZ.getMaximum(); + } + + double getWidth() const + { + return maRangeX.getRange(); + } + + double getHeight() const + { + return maRangeY.getRange(); + } + + double getDepth() const + { + return maRangeZ.getRange(); + } + + B3DVector getRange() const + { + return B3DVector( + maRangeX.getRange(), + maRangeY.getRange(), + maRangeZ.getRange() + ); + } + + B3DPoint getCenter() const + { + return B3DPoint( + maRangeX.getCenter(), + maRangeY.getCenter(), + maRangeZ.getCenter() + ); + } + + bool overlaps(const B3DRange& rRange) const + { + return ( + maRangeX.overlaps(rRange.maRangeX) + && maRangeY.overlaps(rRange.maRangeY) + && maRangeZ.overlaps(rRange.maRangeZ) + ); + } + + void expand(const B3DTuple& rTuple) + { + maRangeX.expand(rTuple.getX()); + maRangeY.expand(rTuple.getY()); + maRangeZ.expand(rTuple.getZ()); + } + + void expand(const B3DRange& rRange) + { + maRangeX.expand(rRange.maRangeX); + maRangeY.expand(rRange.maRangeY); + maRangeZ.expand(rRange.maRangeZ); + } + + void grow(double fValue) + { + maRangeX.grow(fValue); + maRangeY.grow(fValue); + maRangeZ.grow(fValue); + } + + /// clamp value on range + B3DTuple clamp(const B3DTuple& rTuple) const + { + return B3DTuple( + maRangeX.clamp(rTuple.getX()), + maRangeY.clamp(rTuple.getY()), + maRangeZ.clamp(rTuple.getZ())); + } + + BASEGFX_DLLPUBLIC void transform(const B3DHomMatrix& rMatrix); + + /** Transform Range by given transformation matrix. + + This operation transforms the Range by transforming all eight possible + extrema points (corners) of the given range and building a new one. + This means that the range will grow evtl. when a shear and/or rotation + is part of the transformation. + */ + B3DRange& operator*=( const ::basegfx::B3DHomMatrix& rMat ); + + /** Get a range filled with (0.0, 0.0, 0.0, 1.0, 1.0, 1.0) */ + static const B3DRange& getUnitB3DRange(); + }; + + /** Transform B3DRange by given transformation matrix (see operator*=()) + */ + B3DRange operator*( const B3DHomMatrix& rMat, const B3DRange& rB2DRange ); + +} // end of namespace basegfx + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/include/basegfx/range/basicbox.hxx b/include/basegfx/range/basicbox.hxx new file mode 100644 index 0000000000..123d2b1b3e --- /dev/null +++ b/include/basegfx/range/basicbox.hxx @@ -0,0 +1,68 @@ +/* -*- 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 . + */ + +#pragma once + +#include + + +namespace basegfx +{ + /** Explicitly different from BasicRange, handling the inside predicates + differently. + + This is modelled after how polygon fill algorithms set pixel - + typically excluding rightmost and bottommost ones. + */ + class BasicBox : public BasicRange< sal_Int32, Int32Traits > + { + typedef BasicRange< sal_Int32, Int32Traits > Base; + public: + BasicBox() {} + + explicit BasicBox( sal_Int32 nValue ) : + Base( nValue ) + { + } + + bool isEmpty() const + { + return mnMinimum >= mnMaximum; + } + + using Base::isInside; + + bool isInside(sal_Int32 nValue) const + { + if(isEmpty()) + { + return false; + } + else + { + return (nValue >= mnMinimum) && (nValue < mnMaximum); + } + } + + using Base::overlaps; + }; + +} // end of namespace basegfx + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/include/basegfx/range/basicrange.hxx b/include/basegfx/range/basicrange.hxx new file mode 100644 index 0000000000..68c365d0b9 --- /dev/null +++ b/include/basegfx/range/basicrange.hxx @@ -0,0 +1,313 @@ +/* -*- 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 . + */ + +#pragma once + +#include +#include +#include + + +namespace basegfx +{ + template< typename T, typename Traits > class BasicRange + { + protected: + T mnMinimum; + T mnMaximum; + + public: + typedef T ValueType; + typedef Traits TraitsType; + + BasicRange() : + mnMinimum(Traits::maxVal()), + mnMaximum(Traits::minVal()) + { + } + + explicit BasicRange( T nValue ) : + mnMinimum(nValue), + mnMaximum(nValue) + { + } + + void reset() + { + mnMinimum = Traits::maxVal(); + mnMaximum = Traits::minVal(); + } + + bool isEmpty() const + { + return Traits::maxVal() == mnMinimum; + } + + T getMinimum() const { return mnMinimum; } + T getMaximum() const { return mnMaximum; } + + double getCenter() const + { + if(isEmpty()) + { + return 0.0; + } + else + { + return ((mnMaximum + mnMinimum) / 2.0); + } + } + + bool isInside(T nValue) const + { + if(isEmpty()) + { + return false; + } + else + { + return (nValue >= mnMinimum) && (nValue <= mnMaximum); + } + } + + bool isInside(const BasicRange& rRange) const + { + if(isEmpty()) + { + return false; + } + else + { + if(rRange.isEmpty()) + { + return false; + } + else + { + return (rRange.mnMinimum >= mnMinimum) && (rRange.mnMaximum <= mnMaximum); + } + } + } + + bool overlaps(const BasicRange& rRange) const + { + if(isEmpty()) + { + return false; + } + else + { + if(rRange.isEmpty()) + { + return false; + } + else + { + return (rRange.mnMaximum >= mnMinimum) && (rRange.mnMinimum <= mnMaximum); + } + } + } + + bool overlapsMore(const BasicRange& rRange) const + { + if(isEmpty() || rRange.isEmpty()) + return false; + // returns true if the overlap is more than just a touching at the limits + return ((rRange.mnMaximum > mnMinimum) && (rRange.mnMinimum < mnMaximum)); + } + + bool operator==( const BasicRange& rRange ) const + { + return (mnMinimum == rRange.mnMinimum && mnMaximum == rRange.mnMaximum); + } + + bool operator!=( const BasicRange& rRange ) const + { + return (mnMinimum != rRange.mnMinimum || mnMaximum != rRange.mnMaximum); + } + + bool equal(const BasicRange& rRange) const + { + return ( + fTools::equal(mnMinimum, rRange.mnMinimum) && + fTools::equal(mnMaximum, rRange.mnMaximum)); + } + + void expand(T nValue) + { + if(isEmpty()) + { + mnMinimum = mnMaximum = nValue; + } + else + { +// Silence over-eager warning emitted at least by GCC 4.9.2 in certain +// instantiations: +#if defined __GNUC__ && !defined __clang__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wstrict-overflow" +#endif + if(nValue < mnMinimum) +#if defined __GNUC__ && !defined __clang__ +#pragma GCC diagnostic pop +#endif + { + mnMinimum = nValue; + } + + if(nValue > mnMaximum) + { + mnMaximum = nValue; + } + } + } + + void expand(const BasicRange& rRange) + { + if(isEmpty()) + { + mnMinimum = rRange.mnMinimum; + mnMaximum = rRange.mnMaximum; + } + else + { + if(!rRange.isEmpty()) + { + if(rRange.mnMinimum < mnMinimum) + { + mnMinimum = rRange.mnMinimum; + } + + if(rRange.mnMaximum > mnMaximum) + { + mnMaximum = rRange.mnMaximum; + } + } + } + } + + void intersect(const BasicRange& rRange) + { + // here, overlaps also tests all isEmpty() conditions already. + if( !overlaps( rRange ) ) + { + reset(); + } + else + { + if(rRange.mnMinimum > mnMinimum) + { + mnMinimum = rRange.mnMinimum; + } + + if(rRange.mnMaximum < mnMaximum) + { + mnMaximum = rRange.mnMaximum; + } + } + } + + void grow(T nValue) + { + if(isEmpty()) + return; + + bool bLessThanZero(nValue < 0); + + if(nValue > 0 || bLessThanZero) + { + mnMinimum -= nValue; + mnMaximum += nValue; + + if(bLessThanZero) + { + // test if range did collapse + if(mnMinimum > mnMaximum) + { + // if yes, collapse to center + mnMinimum = mnMaximum = (mnMinimum + mnMaximum) / 2; + } + } + } + } + + T clamp(T nValue) const + { + if(isEmpty()) + { + return nValue; + } + else + { + if(nValue < mnMinimum) + { + return mnMinimum; + } + + if(nValue > mnMaximum) + { + return mnMaximum; + } + + return nValue; + } + } + +#if defined _MSC_VER && defined(_M_ARM64) +#pragma warning(push) +#pragma warning(disable: 4723) /* ignore: warning for (C4723) potential divide by 0 on windows arm64 build */ +#endif + typename Traits::DifferenceType getRange() const + { + if(isEmpty()) + { + return Traits::neutral(); + } + else + { + return (mnMaximum - mnMinimum); + } + } +#if defined _MSC_VER && defined(_M_ARM64) +#pragma warning( pop ) +#endif + }; + + // some pre-fabricated traits + struct DoubleTraits + { + static constexpr double minVal() { return DBL_MIN; }; + static constexpr double maxVal() { return DBL_MAX; }; + static constexpr double neutral() { return 0.0; }; + + typedef double DifferenceType; + }; + + struct Int32Traits + { + static constexpr sal_Int32 minVal() { return SAL_MIN_INT32; }; + static constexpr sal_Int32 maxVal() { return SAL_MAX_INT32; }; + static constexpr sal_Int32 neutral() { return 0; }; + + typedef sal_Int64 DifferenceType; + }; + +} // end of namespace basegfx + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/include/basegfx/raster/bzpixelraster.hxx b/include/basegfx/raster/bzpixelraster.hxx new file mode 100644 index 0000000000..52ebc3c6ec --- /dev/null +++ b/include/basegfx/raster/bzpixelraster.hxx @@ -0,0 +1,91 @@ +/* -*- 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 . + */ + +#pragma once + +#include +#include +#include +#include +#include + +namespace basegfx +{ + class BZPixelRaster + { + private: + BZPixelRaster(const BZPixelRaster&) = delete; + BZPixelRaster& operator=(const BZPixelRaster&) = delete; + + sal_uInt32 mnWidth; + sal_uInt32 mnHeight; + sal_uInt32 mnCount; + std::unique_ptr mpContent; + std::unique_ptr mpZBuffer; + + public: + // constructor/destructor + BZPixelRaster(sal_uInt32 nWidth, sal_uInt32 nHeight) + : mnWidth(nWidth), + mnHeight(nHeight), + mnCount(nWidth * nHeight), + mpContent(new BPixel[mnCount]), + mpZBuffer(new sal_uInt16[mnCount]) + { + memset(mpZBuffer.get(), 0, sizeof(sal_uInt16) * mnCount); + } + + // coordinate calcs between X/Y and span + sal_uInt32 getIndexFromXY(sal_uInt32 nX, sal_uInt32 nY) const { return (nX + (nY * mnWidth)); } + + // data access read + sal_uInt32 getWidth() const { return mnWidth; } + sal_uInt32 getHeight() const { return mnHeight; } + + // data access read only + const BPixel& getBPixel(sal_uInt32 nIndex) const + { + assert(nIndex < mnCount && "Access out of range"); + return mpContent[nIndex]; + } + + // data access read/write + BPixel& getBPixel(sal_uInt32 nIndex) + { + assert(nIndex < mnCount && "Access out of range"); + return mpContent[nIndex]; + } + + // data access read only + const sal_uInt16& getZ(sal_uInt32 nIndex) const + { + assert(nIndex < mnCount && "Access out of range"); + return mpZBuffer[nIndex]; + } + + // data access read/write + sal_uInt16& getZ(sal_uInt32 nIndex) + { + assert(nIndex < mnCount && "Access out of range"); + return mpZBuffer[nIndex]; + } + }; +} // end of namespace basegfx + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/include/basegfx/raster/rasterconvert3d.hxx b/include/basegfx/raster/rasterconvert3d.hxx new file mode 100644 index 0000000000..83f753e318 --- /dev/null +++ b/include/basegfx/raster/rasterconvert3d.hxx @@ -0,0 +1,421 @@ +/* -*- 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 . + */ + +#pragma once + +#include +#include +#include + +#include + +#include +#include +#include +#include + +namespace basegfx +{ + class B3DPolygon; + class B3DPolyPolygon; +} + +// interpolators for double precision + +namespace basegfx +{ + class ip_single + { + private: + double mfVal; + double mfInc; + + public: + ip_single() + : mfVal(0.0), + mfInc(0.0) + {} + + ip_single(double fVal, double fInc) + : mfVal(fVal), + mfInc(fInc) + {} + + double getVal() const { return mfVal; } + double getInc() const { return mfInc; } + + void increment(double fStep) { mfVal += fStep * mfInc; } + }; + + class ip_double + { + private: + ip_single maX; + ip_single maY; + + public: + ip_double() + {} + + ip_double(double fXVal, double fXInc, double fYVal, double fYInc) + : maX(fXVal, fXInc), + maY(fYVal, fYInc) + {} + + const ip_single& getX() const { return maX; } + const ip_single& getY() const { return maY; } + + void increment(double fStep) { maX.increment(fStep); maY.increment(fStep); } + }; + + class ip_triple + { + private: + ip_single maX; + ip_single maY; + ip_single maZ; + + public: + ip_triple() + {} + + ip_triple(double fXVal, double fXInc, double fYVal, double fYInc, double fZVal, double fZInc) + : maX(fXVal, fXInc), + maY(fYVal, fYInc), + maZ(fZVal, fZInc) + {} + + const ip_single& getX() const { return maX; } + const ip_single& getY() const { return maY; } + const ip_single& getZ() const { return maZ; } + + void increment(double fStep) { maX.increment(fStep); maY.increment(fStep); maZ.increment(fStep); } + }; + + // InterpolatorProvider3D to have a common source for allocating interpolators + // which may then be addressed using the index to the vectors + + #define SCANLINE_EMPTY_INDEX (0xffffffff) + + class InterpolatorProvider3D + { + private: + ::std::vector< ip_triple > maColorInterpolators; + ::std::vector< ip_triple > maNormalInterpolators; + ::std::vector< ip_double > maTextureInterpolators; + ::std::vector< ip_triple > maInverseTextureInterpolators; + + protected: + sal_uInt32 addColorInterpolator(const BColor& rA, const BColor& rB, double fInvYDelta) + { + double aDeltaRed(rB.getRed() - rA.getRed()); + + if(fTools::equalZero(aDeltaRed)) + { + aDeltaRed = 0.0; + } + else + { + aDeltaRed *= fInvYDelta; + } + + double aDeltaGreen(rB.getGreen() - rA.getGreen()); + + if(fTools::equalZero(aDeltaGreen)) + { + aDeltaGreen = 0.0; + } + else + { + aDeltaGreen *= fInvYDelta; + } + + double aDeltaBlue(rB.getBlue() - rA.getBlue()); + + if(fTools::equalZero(aDeltaBlue)) + { + aDeltaBlue = 0.0; + } + else + { + aDeltaBlue *= fInvYDelta; + } + + maColorInterpolators.push_back( + ip_triple( + rA.getRed(), aDeltaRed, + rA.getGreen(), aDeltaGreen, + rA.getBlue(), aDeltaBlue)); + + return (maColorInterpolators.size() - 1); + } + + sal_uInt32 addNormalInterpolator(const B3DVector& rA, const B3DVector& rB, double fInvYDelta) + { + double aDeltaX(rB.getX() - rA.getX()); + + if(fTools::equalZero(aDeltaX)) + { + aDeltaX = 0.0; + } + else + { + aDeltaX *= fInvYDelta; + } + + double aDeltaY(rB.getY() - rA.getY()); + + if(fTools::equalZero(aDeltaY)) + { + aDeltaY = 0.0; + } + else + { + aDeltaY *= fInvYDelta; + } + + double aDeltaZ(rB.getZ() - rA.getZ()); + + if(fTools::equalZero(aDeltaZ)) + { + aDeltaZ = 0.0; + } + else + { + aDeltaZ *= fInvYDelta; + } + + maNormalInterpolators.push_back( + ip_triple( + rA.getX(), aDeltaX, + rA.getY(), aDeltaY, + rA.getZ(), aDeltaZ)); + + return (maNormalInterpolators.size() - 1); + } + + sal_uInt32 addTextureInterpolator(const B2DPoint& rA, const B2DPoint& rB, double fInvYDelta) + { + double aDeltaX(rB.getX() - rA.getX()); + + if(fTools::equalZero(aDeltaX)) + { + aDeltaX = 0.0; + } + else + { + aDeltaX *= fInvYDelta; + } + + double aDeltaY(rB.getY() - rA.getY()); + + if(fTools::equalZero(aDeltaY)) + { + aDeltaY = 0.0; + } + else + { + aDeltaY *= fInvYDelta; + } + + maTextureInterpolators.push_back( + ip_double( + rA.getX(), aDeltaX, + rA.getY(), aDeltaY)); + + return (maTextureInterpolators.size() - 1); + } + + sal_uInt32 addInverseTextureInterpolator(const B2DPoint& rA, const B2DPoint& rB, double fZEyeA, double fZEyeB, double fInvYDelta) + { + double fZDelta(fZEyeB - fZEyeA); + const double fInvZEyeA(fTools::equalZero(fZEyeA) ? fZEyeA : 1.0 / fZEyeA); + double fInvZEyeB(fInvZEyeA); + + if(fTools::equalZero(fZDelta)) + { + fZDelta = 0.0; + } + else + { + fInvZEyeB = fTools::equalZero(fZEyeB) ? fZEyeB : 1.0 / fZEyeB; + fZDelta = (fInvZEyeB - fInvZEyeA) * fInvYDelta; + } + + const B2DPoint aInvA(rA * fInvZEyeA); + const B2DPoint aInvB(rB * fInvZEyeB); + const double aDeltaX((aInvB.getX() - aInvA.getX()) * fInvYDelta); + const double aDeltaY((aInvB.getY() - aInvA.getY()) * fInvYDelta); + + maInverseTextureInterpolators.push_back( + ip_triple( + aInvA.getX(), aDeltaX, + aInvA.getY(), aDeltaY, + fInvZEyeA, fZDelta)); + + return (maInverseTextureInterpolators.size() - 1); + } + + void reset() + { + maColorInterpolators.clear(); + maNormalInterpolators.clear(); + maTextureInterpolators.clear(); + maInverseTextureInterpolators.clear(); + } + + public: + InterpolatorProvider3D() {} + + ::std::vector< ip_triple >& getColorInterpolators() { return maColorInterpolators; } + ::std::vector< ip_triple >& getNormalInterpolators() { return maNormalInterpolators; } + ::std::vector< ip_double >& getTextureInterpolators() { return maTextureInterpolators; } + ::std::vector< ip_triple >& getInverseTextureInterpolators() { return maInverseTextureInterpolators; } + }; + + // RasterConversionLineEntry3D for Rasterconversion of 3D PolyPolygons + + class RasterConversionLineEntry3D + { + private: + ip_single maX; + ip_single maZ; + sal_Int32 mnY; + sal_uInt32 mnCount; + + sal_uInt32 mnColorIndex; + sal_uInt32 mnNormalIndex; + sal_uInt32 mnTextureIndex; + sal_uInt32 mnInverseTextureIndex; + + public: + RasterConversionLineEntry3D(const double& rfX, const double& rfDeltaX, const double& rfZ, const double& rfDeltaZ, sal_Int32 nY, sal_uInt32 nCount) + : maX(rfX, rfDeltaX), + maZ(rfZ, rfDeltaZ), + mnY(nY), + mnCount(nCount), + mnColorIndex(SCANLINE_EMPTY_INDEX), + mnNormalIndex(SCANLINE_EMPTY_INDEX), + mnTextureIndex(SCANLINE_EMPTY_INDEX), + mnInverseTextureIndex(SCANLINE_EMPTY_INDEX) + {} + + void setColorIndex(sal_uInt32 nIndex) { mnColorIndex = nIndex; } + void setNormalIndex(sal_uInt32 nIndex) { mnNormalIndex = nIndex; } + void setTextureIndex(sal_uInt32 nIndex) { mnTextureIndex = nIndex; } + void setInverseTextureIndex(sal_uInt32 nIndex) { mnInverseTextureIndex = nIndex; } + + bool operator<(const RasterConversionLineEntry3D& rComp) const + { + if(mnY == rComp.mnY) + { + return maX.getVal() < rComp.maX.getVal(); + } + + return mnY < rComp.mnY; + } + + bool decrementRasterConversionLineEntry3D(sal_uInt32 nStep) + { + if(nStep >= mnCount) + { + return false; + } + else + { + mnCount -= nStep; + return true; + } + } + + void incrementRasterConversionLineEntry3D(sal_uInt32 nStep, InterpolatorProvider3D& rProvider) + { + const double fStep(static_cast(nStep)); + maX.increment(fStep); + maZ.increment(fStep); + mnY += nStep; + + if(SCANLINE_EMPTY_INDEX != mnColorIndex) + { + rProvider.getColorInterpolators()[mnColorIndex].increment(fStep); + } + + if(SCANLINE_EMPTY_INDEX != mnNormalIndex) + { + rProvider.getNormalInterpolators()[mnNormalIndex].increment(fStep); + } + + if(SCANLINE_EMPTY_INDEX != mnTextureIndex) + { + rProvider.getTextureInterpolators()[mnTextureIndex].increment(fStep); + } + + if(SCANLINE_EMPTY_INDEX != mnInverseTextureIndex) + { + rProvider.getInverseTextureInterpolators()[mnInverseTextureIndex].increment(fStep); + } + } + + // data read access + const ip_single& getX() const { return maX; } + sal_Int32 getY() const { return mnY; } + const ip_single& getZ() const { return maZ; } + sal_uInt32 getColorIndex() const { return mnColorIndex; } + sal_uInt32 getNormalIndex() const { return mnNormalIndex; } + sal_uInt32 getTextureIndex() const { return mnTextureIndex; } + sal_uInt32 getInverseTextureIndex() const { return mnInverseTextureIndex; } + }; + + // the basic RasterConverter itself. Only one method needs to be overridden. The + // class itself is pure virtual + + class UNLESS_MERGELIBS(BASEGFX_DLLPUBLIC) RasterConverter3D : public InterpolatorProvider3D + { + private: + // the line entries for an area conversion run + ::std::vector< RasterConversionLineEntry3D > maLineEntries; + + struct lineComparator + { + bool operator()(const RasterConversionLineEntry3D* pA, const RasterConversionLineEntry3D* pB) + { + OSL_ENSURE(pA && pB, "lineComparator: empty pointer (!)"); + return pA->getX().getVal() < pB->getX().getVal(); + } + }; + + SAL_DLLPRIVATE void addArea(const B3DPolygon& rFill, const B3DHomMatrix* pViewToEye); + SAL_DLLPRIVATE void addArea(const B3DPolyPolygon& rFill, const B3DHomMatrix* pViewToEye); + SAL_DLLPRIVATE void addEdge(const B3DPolygon& rFill, sal_uInt32 a, sal_uInt32 b, const B3DHomMatrix* pViewToEye); + + SAL_DLLPRIVATE void rasterconvertB3DArea(sal_Int32 nStartLine, sal_Int32 nStopLine); + SAL_DLLPRIVATE void rasterconvertB3DEdge(const B3DPolygon& rLine, sal_uInt32 nA, sal_uInt32 nB, sal_Int32 nStartLine, sal_Int32 nStopLine, sal_uInt16 nLineWidth); + + virtual void processLineSpan(const RasterConversionLineEntry3D& rA, const RasterConversionLineEntry3D& rB, sal_Int32 nLine, sal_uInt32 nSpanCount) = 0; + + public: + RasterConverter3D(); + virtual ~RasterConverter3D(); + + void rasterconvertB3DPolyPolygon(const B3DPolyPolygon& rFill, const B3DHomMatrix* pViewToEye, sal_Int32 nStartLine, sal_Int32 nStopLine); + void rasterconvertB3DPolygon(const B3DPolygon& rLine, sal_Int32 nStartLine, sal_Int32 nStopLine, sal_uInt16 nLineWidth); + }; +} // end of namespace basegfx + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/include/basegfx/tuple/Size2D.hxx b/include/basegfx/tuple/Size2D.hxx new file mode 100644 index 0000000000..28b967636f --- /dev/null +++ b/include/basegfx/tuple/Size2D.hxx @@ -0,0 +1,117 @@ +/* -*- 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/. + * + */ + +#pragma once + +#include + +namespace basegfx +{ +template class Size2D : protected Tuple2D +{ +public: + Size2D(TYPE width, TYPE height) + : Tuple2D(width, height) + { + } + + Size2D(Tuple2D const& rTuple) + : Tuple2D(rTuple.getX(), rTuple.getY()) + { + } + + TYPE getWidth() const { return Tuple2D::getX(); } + + TYPE getHeight() const { return Tuple2D::getY(); } + + void setWidth(TYPE const& rWidth) { Tuple2D::setX(rWidth); } + + void setHeight(TYPE const& rHeight) { Tuple2D::setY(rHeight); } + + bool operator==(Size2D const& rSize) const { return Tuple2D::operator==(rSize); } + + bool operator!=(Size2D const& rSize) const { return Tuple2D::operator!=(rSize); } + + Size2D& operator-=(Size2D const& rSize) + { + Tuple2D::operator-=(rSize); + return *this; + } + + Size2D& operator+=(Size2D const& rSize) + { + Tuple2D::operator+=(rSize); + return *this; + } + + Size2D& operator/=(Size2D const& rSize) + { + Tuple2D::operator/=(rSize); + return *this; + } + + Size2D& operator*=(Size2D const& rSize) + { + Tuple2D::operator*=(rSize); + return *this; + } + + Size2D& operator*=(TYPE value) + { + Tuple2D::operator*=(value); + return *this; + } + + Size2D& operator/=(TYPE value) + { + Tuple2D::operator/=(value); + return *this; + } + + Size2D operator-(void) const { return Tuple2D::operator-(); } + + using Tuple2D::equalZero; +}; + +template +inline Size2D operator-(const Size2D& rSizeA, const Size2D& rSizeB) +{ + Size2D aNew(rSizeA); + aNew -= rSizeB; + return aNew; +} + +template +inline Size2D operator+(const Size2D& rSizeA, const Size2D& rSizeB) +{ + Size2D aNew(rSizeA); + aNew += rSizeB; + return aNew; +} + +template +inline Size2D operator*(const Size2D& rSizeA, const Size2D& rSizeB) +{ + Size2D aNew(rSizeA); + aNew *= rSizeB; + return aNew; +} + +template +inline Size2D operator/(const Size2D& rSizeA, const Size2D& rSizeB) +{ + Size2D aNew(rSizeA); + aNew /= rSizeB; + return aNew; +} + +} // end of namespace gfx + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/include/basegfx/tuple/Tuple2D.hxx b/include/basegfx/tuple/Tuple2D.hxx new file mode 100644 index 0000000000..7494b4d1b1 --- /dev/null +++ b/include/basegfx/tuple/Tuple2D.hxx @@ -0,0 +1,180 @@ +/* -*- 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/. + * + */ + +#pragma once + +#include +#include + +namespace basegfx +{ +template class Tuple2D +{ +protected: + TYPE mnX; + TYPE mnY; + +public: + /** Create a 2D Tuple + + @param nX + This parameter is used to initialize the X-coordinate + of the 2D Tuple. + + @param nY + This parameter is used to initialize the Y-coordinate + of the 2D Tuple. + */ + Tuple2D(TYPE x, TYPE y) + : mnX(x) + , mnY(y) + { + } + + double get(Axis2D eAxis) { return eAxis == Axis2D::X ? getX() : getY(); } + + void set(Axis2D eAxis, TYPE fValue) + { + if (eAxis == Axis2D::X) + setX(fValue); + else + setY(fValue); + } + + /// Get X-Coordinate of 2D Tuple + TYPE getX() const { return mnX; } + + /// Get Y-Coordinate of 2D Tuple + TYPE getY() const { return mnY; } + + /// Set X-Coordinate of 2D Tuple + void setX(TYPE fX) { mnX = fX; } + + /// Set Y-Coordinate of 2D Tuple + void setY(TYPE fY) { mnY = fY; } + + /// Adjust X-Coordinate of 2D Tuple + void adjustX(TYPE fX) { mnX += fX; } + + /// Adjust Y-Coordinate of 2D Tuple + void adjustY(TYPE fY) { mnY += fY; } + + // comparators with tolerance + + template , int> = 0> + bool equal(const Tuple2D& rTup) const + { + return mnX == rTup.mnX && mnY == rTup.mnY; + } + + template , int> = 0> + bool equal(const Tuple2D& rTup) const + { + return this == &rTup || (fTools::equal(mnX, rTup.mnX) && fTools::equal(mnY, rTup.mnY)); + } + + template , int> = 0> + bool equalZero() const + { + return mnX == 0 && mnY == 0; + } + + template , int> = 0> + bool equalZero() const + { + return fTools::equalZero(mnX) && fTools::equalZero(mnY); + } + + // operator overrides + + Tuple2D& operator+=(const Tuple2D& rTup) + { + mnX += rTup.mnX; + mnY += rTup.mnY; + return *this; + } + + Tuple2D& operator-=(const Tuple2D& rTup) + { + mnX -= rTup.mnX; + mnY -= rTup.mnY; + return *this; + } + + Tuple2D& operator/=(const Tuple2D& rTup) + { + mnX /= rTup.mnX; + mnY /= rTup.mnY; + return *this; + } + + Tuple2D& operator*=(const Tuple2D& rTup) + { + mnX *= rTup.mnX; + mnY *= rTup.mnY; + return *this; + } + + Tuple2D& operator*=(TYPE t) + { + mnX *= t; + mnY *= t; + return *this; + } + + Tuple2D& operator/=(TYPE t) + { + mnX /= t; + mnY /= t; + return *this; + } + + Tuple2D operator-(void) const { return Tuple2D(-mnX, -mnY); } + + bool operator==(const Tuple2D& rTup) const { return mnX == rTup.mnX && mnY == rTup.mnY; } + + bool operator!=(const Tuple2D& rTup) const { return !(*this == rTup); } +}; + +template +inline Tuple2D operator-(const Tuple2D& rTupA, const Tuple2D& rTupB) +{ + Tuple2D aNew(rTupA); + aNew -= rTupB; + return aNew; +} + +template +inline Tuple2D operator+(const Tuple2D& rTupA, const Tuple2D& rTupB) +{ + Tuple2D aNew(rTupA); + aNew += rTupB; + return aNew; +} + +template +inline Tuple2D operator*(const Tuple2D& rTupA, const Tuple2D& rTupB) +{ + Tuple2D aNew(rTupA); + aNew *= rTupB; + return aNew; +} + +template +inline Tuple2D operator/(const Tuple2D& rTupA, const Tuple2D& rTupB) +{ + Tuple2D aNew(rTupA); + aNew /= rTupB; + return aNew; +} + +} // end of namespace basegfx + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/include/basegfx/tuple/Tuple3D.hxx b/include/basegfx/tuple/Tuple3D.hxx new file mode 100644 index 0000000000..0b528c8341 --- /dev/null +++ b/include/basegfx/tuple/Tuple3D.hxx @@ -0,0 +1,122 @@ +/* -*- 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/. + * + */ + +#pragma once + +namespace basegfx +{ +template class Tuple3D +{ +protected: + TYPE mnX; + TYPE mnY; + TYPE mnZ; + +public: + /** Create a 3D Tuple + + @param x + This parameter is used to initialize the X-coordinate + of the 3D Tuple. + + @param y + This parameter is used to initialize the Y-coordinate + of the 3D Tuple. + + @param z + This parameter is used to initialize the Z-coordinate + of the 3D Tuple. + */ + Tuple3D(TYPE x, TYPE y, TYPE z) + : mnX(x) + , mnY(y) + , mnZ(z) + { + } + + /// Get X-Coordinate of 3D Tuple + TYPE getX() const { return mnX; } + + /// Get Y-Coordinate of 3D Tuple + TYPE getY() const { return mnY; } + + /// Get Z-Coordinate of 3D Tuple + TYPE getZ() const { return mnZ; } + + /// Set X-Coordinate of 3D Tuple + void setX(TYPE fX) { mnX = fX; } + + /// Set Y-Coordinate of 3D Tuple + void setY(TYPE fY) { mnY = fY; } + + /// Set Z-Coordinate of 3D Tuple + void setZ(TYPE fZ) { mnZ = fZ; } + + // operators + + Tuple3D& operator+=(const Tuple3D& rTup) + { + mnX += rTup.mnX; + mnY += rTup.mnY; + mnZ += rTup.mnZ; + return *this; + } + + Tuple3D& operator-=(const Tuple3D& rTup) + { + mnX -= rTup.mnX; + mnY -= rTup.mnY; + mnZ -= rTup.mnZ; + return *this; + } + + Tuple3D& operator/=(const Tuple3D& rTup) + { + mnX /= rTup.mnX; + mnY /= rTup.mnY; + mnZ /= rTup.mnZ; + return *this; + } + + Tuple3D& operator*=(const Tuple3D& rTup) + { + mnX *= rTup.mnX; + mnY *= rTup.mnY; + mnZ *= rTup.mnZ; + return *this; + } + + Tuple3D& operator*=(TYPE t) + { + mnX *= t; + mnY *= t; + mnZ *= t; + return *this; + } + + Tuple3D& operator/=(TYPE t) + { + mnX /= t; + mnY /= t; + mnZ /= t; + return *this; + } + + bool operator==(const Tuple3D& rTup) const + { + return mnX == rTup.mnX && mnY == rTup.mnY && mnZ == rTup.mnZ; + } + + bool operator!=(const Tuple3D& rTup) const { return !operator==(rTup); } +}; + +} // end of namespace basegfx + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/include/basegfx/tuple/b2dtuple.hxx b/include/basegfx/tuple/b2dtuple.hxx new file mode 100644 index 0000000000..a4558f0d34 --- /dev/null +++ b/include/basegfx/tuple/b2dtuple.hxx @@ -0,0 +1,153 @@ +/* -*- 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 . + */ + +#pragma once + +#include +#include +#include + +namespace basegfx +{ + class B2ITuple; + + /** Base class for all Points/Vectors with two double values + + This class provides all methods common to Point + and Vector classes which are derived from here. + + @derive Use this class to implement Points or Vectors + which are based on two double values + */ + class SAL_WARN_UNUSED B2DTuple : public Tuple2D + { + public: + + /** Create a 2D Tuple + + The tuple is initialized to (0.0, 0.0) + */ + B2DTuple() + : Tuple2D(0.0, 0.0) + {} + + /** Create a 2D Tuple + + @param fX + This parameter is used to initialize the X-coordinate + of the 2D Tuple. + + @param fY + This parameter is used to initialize the Y-coordinate + of the 2D Tuple. + */ + B2DTuple(double fX, double fY) + : Tuple2D(fX, fY) + {} + + B2DTuple(Tuple2D const& rTuple) + : Tuple2D(rTuple) + {} + + /** Create a copy of a 2D integer Tuple + + @param rTup + The 2D Tuple which will be copied. + */ + BASEGFX_DLLPUBLIC explicit B2DTuple(const B2ITuple& rTup); + + // operators + + B2DTuple operator-(void) const + { + return B2DTuple(-mnX, -mnY); + } + + BASEGFX_DLLPUBLIC static const B2DTuple& getEmptyTuple(); + }; + + // external operators + + + inline B2DTuple absolute(const B2DTuple& rTup) + { + B2DTuple aAbs( + fabs(rTup.getX()), + fabs(rTup.getY())); + return aAbs; + } + + inline B2DTuple interpolate(const B2DTuple& rOld1, const B2DTuple& rOld2, double t) + { + if(rOld1 == rOld2) + { + return rOld1; + } + else if(0.0 >= t) + { + return rOld1; + } + else if(1.0 <= t) + { + return rOld2; + } + else + { + return B2DTuple( + ((rOld2.getX() - rOld1.getX()) * t) + rOld1.getX(), + ((rOld2.getY() - rOld1.getY()) * t) + rOld1.getY()); + } + } + + inline B2DTuple average(const B2DTuple& rOld1, const B2DTuple& rOld2) + { + return B2DTuple( + rtl_math_approxEqual(rOld1.getX(), rOld2.getX()) ? rOld1.getX() : (rOld1.getX() + rOld2.getX()) * 0.5, + rtl_math_approxEqual(rOld1.getY(), rOld2.getY()) ? rOld1.getY() : (rOld1.getY() + rOld2.getY()) * 0.5); + } + + inline B2DTuple operator*(const B2DTuple& rTup, double t) + { + B2DTuple aNew(rTup); + aNew *= t; + return aNew; + } + + inline B2DTuple operator*(double t, const B2DTuple& rTup) + { + B2DTuple aNew(rTup); + aNew *= t; + return aNew; + } + + inline B2DTuple operator/(const B2DTuple& rTup, double t) + { + B2DTuple aNew(rTup); + aNew /= t; + return aNew; + } + + /** Round double to nearest integer for 2D tuple + + @return the nearest integer for this tuple + */ + BASEGFX_DLLPUBLIC B2ITuple fround(const B2DTuple& rTup); +} // end of namespace basegfx + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/include/basegfx/tuple/b2i64tuple.hxx b/include/basegfx/tuple/b2i64tuple.hxx new file mode 100644 index 0000000000..70838572f3 --- /dev/null +++ b/include/basegfx/tuple/b2i64tuple.hxx @@ -0,0 +1,87 @@ +/* -*- 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 . + */ + +#pragma once + +#include +#include +#include + +namespace basegfx +{ + /** Base class for all Points/Vectors with two sal_Int64 values + + This class provides all methods common to Point + and Vector classes which are derived from here. + + @derive Use this class to implement Points or Vectors + which are based on two sal_Int64 values + */ + class SAL_WARN_UNUSED BASEGFX_DLLPUBLIC B2I64Tuple : public Tuple2D + { + public: + /** Create a 2D Tuple + + The tuple is initialized to (0, 0) + */ + B2I64Tuple() + : Tuple2D(0, 0) + {} + + /** Create a 2D Tuple + + @param nX + This parameter is used to initialize the X-coordinate + of the 2D Tuple. + + @param nY + This parameter is used to initialize the Y-coordinate + of the 2D Tuple. + */ + B2I64Tuple(sal_Int64 nX, sal_Int64 nY) + : Tuple2D(nX, nY) + {} + + /** Create a copy of a 2D Tuple + + @param rTup + The 2D Tuple which will be copied. + */ + B2I64Tuple(const B2I64Tuple& rTup) + : Tuple2D(rTup.mnX, rTup.mnY) + {} + + // operators + + B2I64Tuple operator-(void) const + { + return B2I64Tuple(-mnX, -mnY); + } + + B2I64Tuple& operator=( const B2I64Tuple& rTup ) + { + mnX = rTup.mnX; + mnY = rTup.mnY; + return *this; + } + }; + +} // end of namespace basegfx + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/include/basegfx/tuple/b2ituple.hxx b/include/basegfx/tuple/b2ituple.hxx new file mode 100644 index 0000000000..e3f195596a --- /dev/null +++ b/include/basegfx/tuple/b2ituple.hxx @@ -0,0 +1,95 @@ +/* -*- 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 . + */ + +#pragma once + +#include +#include +#include + +namespace basegfx +{ + /** Base class for all Points/Vectors with two sal_Int32 values + + This class provides all methods common to Point + and Vector classes which are derived from here. + + @derive Use this class to implement Points or Vectors + which are based on two sal_Int32 values + */ + class SAL_WARN_UNUSED BASEGFX_DLLPUBLIC B2ITuple : public Tuple2D + { + public: + /** Create a 2D Tuple + + The tuple is initialized to (0, 0) + */ + B2ITuple() + : Tuple2D(0, 0) + {} + + /** Create a 2D Tuple + + @param nX + This parameter is used to initialize the X-coordinate + of the 2D Tuple. + + @param nY + This parameter is used to initialize the Y-coordinate + of the 2D Tuple. + */ + B2ITuple(sal_Int32 nX, sal_Int32 nY) + : Tuple2D(nX, nY) + {} + + // operators + + B2ITuple operator-(void) const + { + return B2ITuple(-mnX, -mnY); + } + }; + + // external operators + + + inline B2ITuple operator+(const B2ITuple& rTupA, const B2ITuple& rTupB) + { + B2ITuple aSum(rTupA); + aSum += rTupB; + return aSum; + } + + inline B2ITuple operator-(const B2ITuple& rTupA, const B2ITuple& rTupB) + { + B2ITuple aSub(rTupA); + aSub -= rTupB; + return aSub; + } + + inline B2ITuple operator*(sal_Int32 t, const B2ITuple& rTup) + { + B2ITuple aNew(rTup); + aNew *= t; + return aNew; + } + +} // end of namespace basegfx + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/include/basegfx/tuple/b3dtuple.hxx b/include/basegfx/tuple/b3dtuple.hxx new file mode 100644 index 0000000000..2701b2f25c --- /dev/null +++ b/include/basegfx/tuple/b3dtuple.hxx @@ -0,0 +1,239 @@ +/* -*- 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 . + */ + +#pragma once + +#include +#include +#include +#include + +namespace basegfx +{ + class B3ITuple; + + /** Base class for all Points/Vectors with three double values + + This class provides all methods common to Point + and Vector classes which are derived from here. + + @derive Use this class to implement Points or Vectors + which are based on three double values + */ + class SAL_WARN_UNUSED BASEGFX_DLLPUBLIC B3DTuple : public Tuple3D + { + public: + /** Create a 3D Tuple + + The tuple is initialized to (0.0, 0.0, 0.0) + */ + B3DTuple() + : Tuple3D(0.0, 0.0, 0.0) + {} + + /** Create a 3D Tuple + + @param fX + This parameter is used to initialize the X-coordinate + of the 3D Tuple. + + @param fY + This parameter is used to initialize the Y-coordinate + of the 3D Tuple. + + @param fZ + This parameter is used to initialize the Z-coordinate + of the 3D Tuple. + */ + B3DTuple(double fX, double fY, double fZ) + : Tuple3D(fX, fY, fZ) + {} + + /// Array-access to 3D Tuple + const double& operator[] (int nPos) const + { + // Here, normally two if(...)'s should be used. In the assumption that + // both double members can be accessed as an array a shortcut is used here. + // if(0 == nPos) return mnX; if(1 == nPos) return mnY; return mnZ; + return *((&mnX) + nPos); + } + + /// Array-access to 3D Tuple + double& operator[] (int nPos) + { + // Here, normally two if(...)'s should be used. In the assumption that + // both double members can be accessed as an array a shortcut is used here. + // if(0 == nPos) return mnX; if(1 == nPos) return mnY; return mnZ; + return *((&mnX) + nPos); + } + + // comparators with tolerance + + + bool equalZero() const + { + return (this == &getEmptyTuple() || + (::basegfx::fTools::equalZero(mnX) + && ::basegfx::fTools::equalZero(mnY) + && ::basegfx::fTools::equalZero(mnZ))); + } + + bool equal(const B3DTuple& rTup) const + { + return ( + this == &rTup || + (::basegfx::fTools::equal(mnX, rTup.mnX) && + ::basegfx::fTools::equal(mnY, rTup.mnY) && + ::basegfx::fTools::equal(mnZ, rTup.mnZ))); + } + + // operators + + B3DTuple operator-(void) const + { + return B3DTuple(-mnX, -mnY, -mnZ); + } + + bool operator==(const B3DTuple& rTup) const + { + return ::basegfx::fTools::equal(mnX, rTup.mnX) && + ::basegfx::fTools::equal(mnY, rTup.mnY) && + ::basegfx::fTools::equal(mnZ, rTup.mnZ); + } + + bool operator!=(const B3DTuple& rTup) const { return !operator==(rTup); } + + void correctValues(const double fCompareValue = 0.0) + { + if(0.0 == fCompareValue) + { + if(::basegfx::fTools::equalZero(mnX)) + { + mnX = 0.0; + } + + if(::basegfx::fTools::equalZero(mnY)) + { + mnY = 0.0; + } + + if(::basegfx::fTools::equalZero(mnZ)) + { + mnZ = 0.0; + } + } + else + { + if(::basegfx::fTools::equal(mnX, fCompareValue)) + { + mnX = fCompareValue; + } + + if(::basegfx::fTools::equal(mnY, fCompareValue)) + { + mnY = fCompareValue; + } + + if(::basegfx::fTools::equal(mnZ, fCompareValue)) + { + mnZ = fCompareValue; + } + } + } + + static const B3DTuple& getEmptyTuple(); + }; + + // external operators + + + inline B3DTuple interpolate(const B3DTuple& rOld1, const B3DTuple& rOld2, double t) + { + if(rOld1 == rOld2) + { + return rOld1; + } + else if(0.0 >= t) + { + return rOld1; + } + else if(1.0 <= t) + { + return rOld2; + } + else + { + return B3DTuple( + ((rOld2.getX() - rOld1.getX()) * t) + rOld1.getX(), + ((rOld2.getY() - rOld1.getY()) * t) + rOld1.getY(), + ((rOld2.getZ() - rOld1.getZ()) * t) + rOld1.getZ()); + } + } + + inline B3DTuple average(const B3DTuple& rOld1, const B3DTuple& rOld2) + { + return B3DTuple( + rtl_math_approxEqual(rOld1.getX(), rOld2.getX()) ? rOld1.getX() : (rOld1.getX() + rOld2.getX()) * 0.5, + rtl_math_approxEqual(rOld1.getY(), rOld2.getY()) ? rOld1.getY() : (rOld1.getY() + rOld2.getY()) * 0.5, + rtl_math_approxEqual(rOld1.getZ(), rOld2.getZ()) ? rOld1.getZ() : (rOld1.getZ() + rOld2.getZ()) * 0.5); + } + + inline B3DTuple operator+(const B3DTuple& rTupA, const B3DTuple& rTupB) + { + B3DTuple aSum(rTupA); + aSum += rTupB; + return aSum; + } + + inline B3DTuple operator-(const B3DTuple& rTupA, const B3DTuple& rTupB) + { + B3DTuple aSub(rTupA); + aSub -= rTupB; + return aSub; + } + + inline B3DTuple operator*(const B3DTuple& rTupA, const B3DTuple& rTupB) + { + B3DTuple aMul(rTupA); + aMul *= rTupB; + return aMul; + } + + inline B3DTuple operator*(const B3DTuple& rTup, double t) + { + B3DTuple aNew(rTup); + aNew *= t; + return aNew; + } + + inline B3DTuple operator/(const B3DTuple& rTup, double t) + { + B3DTuple aNew(rTup); + aNew /= t; + return aNew; + } + + /** Round double to nearest integer for 3D tuple + + @return the nearest integer for this tuple + */ + BASEGFX_DLLPUBLIC B3ITuple fround(const B3DTuple& rTup); +} // end of namespace basegfx + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/include/basegfx/tuple/b3ituple.hxx b/include/basegfx/tuple/b3ituple.hxx new file mode 100644 index 0000000000..72c9fa8140 --- /dev/null +++ b/include/basegfx/tuple/b3ituple.hxx @@ -0,0 +1,93 @@ +/* -*- 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 . + */ + +#pragma once + +#include +#include +#include + +namespace basegfx +{ + /** Base class for all Points/Vectors with three sal_Int32 values + + This class provides all methods common to Point + and Vector classes which are derived from here. + + @derive Use this class to implement Points or Vectors + which are based on three sal_Int32 values + */ + class SAL_WARN_UNUSED BASEGFX_DLLPUBLIC B3ITuple : public Tuple3D + { + public: + /** Create a 3D Tuple + + The tuple is initialized to (0, 0, 0) + */ + B3ITuple() + : Tuple3D(0, 0, 0) + {} + + /** Create a 3D Tuple + + @param nX + This parameter is used to initialize the X-coordinate + of the 3D Tuple. + + @param nY + This parameter is used to initialize the Y-coordinate + of the 3D Tuple. + + @param nZ + This parameter is used to initialize the Z-coordinate + of the 3D Tuple. + */ + B3ITuple(sal_Int32 nX, sal_Int32 nY, sal_Int32 nZ) + : Tuple3D(nX, nY, nZ) + {} + + /// Array-access to 3D Tuple + const sal_Int32& operator[] (int nPos) const + { + // Here, normally two if(...)'s should be used. In the assumption that + // both sal_Int32 members can be accessed as an array a shortcut is used here. + // if(0 == nPos) return mnX; if(1 == nPos) return mnY; return mnZ; + return *((&mnX) + nPos); + } + + /// Array-access to 3D Tuple + sal_Int32& operator[] (int nPos) + { + // Here, normally two if(...)'s should be used. In the assumption that + // both sal_Int32 members can be accessed as an array a shortcut is used here. + // if(0 == nPos) return mnX; if(1 == nPos) return mnY; return mnZ; + return *((&mnX) + nPos); + } + + // operators + + B3ITuple operator-(void) const + { + return B3ITuple(-mnX, -mnY, -mnZ); + } + }; + +} // end of namespace basegfx + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/include/basegfx/utils/b2dclipstate.hxx b/include/basegfx/utils/b2dclipstate.hxx new file mode 100644 index 0000000000..f4d9d9e7d6 --- /dev/null +++ b/include/basegfx/utils/b2dclipstate.hxx @@ -0,0 +1,92 @@ +/* -*- 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 . + */ + +#pragma once + +#include +#include + + +namespace basegfx +{ + class B2DRange; + class B2DPolyPolygon; + class B2DHomMatrix; +} + +namespace basegfx::utils +{ + class ImplB2DClipState; + + /** This class provides an optimized, symbolic clip state for graphical output + + Having a current 'clip' state is a common attribute of + almost all graphic output APIs, most of which internally + represent it via a list of rectangular bands. In contrast, + this implementation purely uses symbolic clips, but in a + quite efficient manner, deferring actual evaluation until + a clip representation is requested, and using faster code + paths for common special cases (like all-rectangle clips) + */ + class BASEGFX_DLLPUBLIC B2DClipState + { + public: + typedef o3tl::cow_wrapper< ImplB2DClipState > ImplType; + + private: + ImplType mpImpl; + + public: + /// Init clip, in 'cleared' state - everything is visible + B2DClipState(); + ~B2DClipState(); + B2DClipState( const B2DClipState& ); + B2DClipState( B2DClipState&& ); + explicit B2DClipState( const B2DPolyPolygon& ); + B2DClipState& operator=( const B2DClipState& ); + B2DClipState& operator=( B2DClipState&& ); + + /// Set clip to 'null' - nothing is visible + void makeNull(); + + /// returns true when clip is 'cleared' - everything is visible + bool isCleared() const; + + bool operator==(const B2DClipState&) const; + bool operator!=(const B2DClipState&) const; + + void unionRange(const B2DRange& ); + void unionPolyPolygon(const B2DPolyPolygon& ); + + void intersectRange(const B2DRange& ); + void intersectPolyPolygon(const B2DPolyPolygon& ); + + void subtractRange(const B2DRange& ); + void subtractPolyPolygon(const B2DPolyPolygon& ); + + void xorRange(const B2DRange& ); + void xorPolyPolygon(const B2DPolyPolygon& ); + + void transform(const B2DHomMatrix& ); + + B2DPolyPolygon const & getClipPoly() const; + }; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/include/basegfx/utils/bgradient.hxx b/include/basegfx/utils/bgradient.hxx new file mode 100644 index 0000000000..7d360beee4 --- /dev/null +++ b/include/basegfx/utils/bgradient.hxx @@ -0,0 +1,329 @@ +/* -*- 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/. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include + +namespace basegfx +{ +/* MCGR: Provide ColorStop definition + + This is the needed combination of offset and color: + + Offset is defined as: + - being in the range of [0.0 .. 1.0] (unit range) + - offsets outside are an error + - lowest/1st value equivalent to StartColor + - highest/last value equivalent to EndColor + - missing 0.0/1.0 entries are allowed + - at least one value (usually 0.0, StartColor) is required + - this allows to avoid massive testing in all places where + this data has to be accessed + + Color is defined as: + - RGB with unit values [0.0 .. 1.0] + + These definitions are packed in a std::vector ColorStops, + see typedef below. + */ +class BASEGFX_DLLPUBLIC BColorStop +{ +private: + // offset in the range of [0.0 .. 1.0] + double mfStopOffset; + + // RGB color of ColorStop entry + BColor maStopColor; + +public: + // constructor - defaults are needed to have a default constructor + // e.g. for usage in std::vector::insert (even when only reducing) + // ensure [0.0 .. 1.0] range for mfStopOffset + BColorStop(double fStopOffset = 0.0, const BColor& rStopColor = BColor()) + : mfStopOffset(fStopOffset) + , maStopColor(rStopColor) + { + // NOTE: I originally *corrected* mfStopOffset here by using + // mfStopOffset(std::max(0.0, std::min(fOffset, 1.0))) + // While that is formally correct, it moves an invalid + // entry to 0.0 or 1.0, thus creating additional wrong + // Start/EndColor entries. That may then 'overlay' the + // correct entry when corrections are applied to the + // vector of entries (see sortAndCorrectColorStops) + // which leads to getting the wanted Start/EndColor + // to be factically deleted, what is an error. + } + + double getStopOffset() const { return mfStopOffset; } + const BColor& getStopColor() const { return maStopColor; } + + // needed for std::sort + bool operator<(const BColorStop& rCandidate) const + { + return getStopOffset() < rCandidate.getStopOffset(); + } + + bool operator==(const BColorStop& rCandidate) const + { + return getStopOffset() == rCandidate.getStopOffset() + && getStopColor() == rCandidate.getStopColor(); + } + + bool operator!=(const BColorStop& rCandidate) const { return !(*this == rCandidate); } +}; + +/* MCGR: Provide ColorStops definition to the FillGradientAttribute + + This array should be sorted ascending by offsets, from lowest to + highest. Since all the primitive data definition where it is used + is read-only, this can/will be guaranteed by forcing/checking this + in the constructor, see ::FillGradientAttribute + */ +class BASEGFX_DLLPUBLIC BColorStops final : public std::vector +{ +public: + explicit BColorStops() + : vector() + { + } + BColorStops(const BColorStops& other) + : vector(other) + { + } + BColorStops(BColorStops&& other) noexcept + : vector(std::move(other)) + { + } + BColorStops(std::initializer_list init) + : vector(init) + { + } + BColorStops(const_iterator first, const_iterator last) + : vector(first, last) + { + } + + // constructor with two colors to explicitly create a + // BColorStops for StartColor @0.0 & EndColor @1.0 + BColorStops(const BColor& rStart, const BColor& rEnd); + + BColorStops& operator=(const BColorStops& r) + { + vector::operator=(r); + return *this; + } + BColorStops& operator=(BColorStops&& r) noexcept + { + vector::operator=(std::move(r)); + return *this; + } + + // helper data struct to support buffering entries in + // gradient texture mapping, see usages for more info + struct BColorStopRange + { + basegfx::BColor maColorStart; + basegfx::BColor maColorEnd; + double mfOffsetStart; + double mfOffsetEnd; + + BColorStopRange() + : maColorStart() + , maColorEnd() + , mfOffsetStart(0.0) + , mfOffsetEnd(0.0) + { + } + }; + + /* Helper to grep the correct ColorStop out of + ColorStops and interpolate as needed for given + relative value in fPosition in the range of [0.0 .. 1.0]. + It also takes care of evtl. given RequestedSteps. + */ + BColor getInterpolatedBColor(double fPosition, sal_uInt32 nRequestedSteps, + BColorStopRange& rLastColorStopRange) const; + + /* Tooling method that allows to replace the StartColor in a + vector of ColorStops. A vector in 'ordered state' is expected, + so you may use/have used sortAndCorrect. + This method is for convenience & backwards compatibility, please + think about handling multi-colored gradients directly. + */ + void replaceStartColor(const BColor& rStart); + + /* Tooling method that allows to replace the EndColor in a + vector of ColorStops. A vector in 'ordered state' is expected, + so you may use/have used sortAndCorrect. + This method is for convenience & backwards compatibility, please + think about handling multi-colored gradients directly. + */ + void replaceEndColor(const BColor& rEnd); + + /* Tooling method to linearly blend the Colors contained in + a given ColorStop vector against a given Color using the + given intensity values. + The intensity values fStartIntensity, fEndIntensity are + in the range of [0.0 .. 1.0] and describe how much the + blend is supposed to be done at the start color position + and the end color position respectively, where 0.0 means + to fully use the given BlendColor, 1.0 means to not change + the existing color in the ColorStop. + Every color entry in the given ColorStop is blended + relative to it's StopPosition, interpolating the + given intensities with the range [0.0 .. 1.0] to do so. + */ + void blendToIntensity(double fStartIntensity, double fEndIntensity, const BColor& rBlendColor); + + /* Tooling method to guarantee sort and correctness for + the given ColorStops vector. + A vector fulfilling these conditions is called to be + in 'ordered state'. + + At return, the following conditions are guaranteed: + - contains no ColorStops with offset < 0.0 (will + be removed) + - contains no ColorStops with offset > 1.0 (will + be removed) + - ColorStops with identical offsets are now allowed + - will be sorted from lowest offset to highest + + Some more notes: + - It can happen that the result is empty + - It is allowed to have consecutive entries with + the same color, this represents single-color + regions inside the gradient + - A entry with 0.0 is not required or forced, so + no 'StartColor' is technically required + - A entry with 1.0 is not required or forced, so + no 'EndColor' is technically required + + All this is done in one run (sort + O(N)) without + creating a copy of the data in any form + */ + void sortAndCorrect(); + + // check if we need last-ColorStop-correction. This returns true if the last + // two ColorStops have the same offset but different Colors. In that case the + // tessellation for gradients does have to create an extra ending/closing entry + bool checkPenultimate() const; + + /* Tooling method to check if a ColorStop vector is defined + by a single color. It returns true if this is the case. + If true is returned, rSingleColor contains that single + color for convenience. + NOTE: If no ColorStop is defined, a fallback to BColor-default + (which is black) and true will be returned + */ + bool isSingleColor(BColor& rSingleColor) const; + + /* Tooling method to reverse ColorStops, including offsets. + When also mirroring offsets a valid sort keeps valid. + */ + void reverseColorStops(); + + // createSpaceAtStart creates fOffset space at start by + // translating/scaling all entries to the right + void createSpaceAtStart(double fOffset); + + // removeSpaceAtStart removes fOffset space from start by + // translating/scaling entries more or equal to fOffset + // to the left. Entries less than fOffset will be removed + void removeSpaceAtStart(double fOffset); + + // try to detect if an empty/no-color-change area exists + // at the start and return offset to it. Returns 0.0 if not. + double detectPossibleOffsetAtStart() const; + + // returns true if the color stops are symmetrical in color and offset, otherwise false. + bool isSymmetrical() const; + // assume that the color stops represent an Axial gradient + // and replace with gradient stops to represent the same + // gradient as linear gradient + void doApplyAxial(); + + // apply Steps as 'hard' color stops + void doApplySteps(sal_uInt16 nStepCount); +}; + +class BASEGFX_DLLPUBLIC BGradient final +{ +private: + css::awt::GradientStyle eStyle; + + // MCGS: ColorStops in the range [0.0 .. 1.0], including StartColor/EndColor + basegfx::BColorStops aColorStops; + + Degree10 nAngle; + sal_uInt16 nBorder; + sal_uInt16 nOfsX; + sal_uInt16 nOfsY; + sal_uInt16 nIntensStart; + sal_uInt16 nIntensEnd; + sal_uInt16 nStepCount; + + static std::string GradientStyleToString(css::awt::GradientStyle eStyle); + +public: + BGradient(); + BGradient(const basegfx::BColorStops& rColorStops, + css::awt::GradientStyle eStyle = css::awt::GradientStyle_LINEAR, + Degree10 nAngle = 0_deg10, sal_uInt16 nXOfs = 50, sal_uInt16 nYOfs = 50, + sal_uInt16 nBorder = 0, sal_uInt16 nStartIntens = 100, sal_uInt16 nEndIntens = 100, + sal_uInt16 nSteps = 0); + + bool operator==(const BGradient& rGradient) const; + + void SetGradientStyle(css::awt::GradientStyle eNewStyle) { eStyle = eNewStyle; } + void SetColorStops(const basegfx::BColorStops& rSteps); + void SetAngle(Degree10 nNewAngle) { nAngle = nNewAngle; } + void SetBorder(sal_uInt16 nNewBorder) { nBorder = nNewBorder; } + void SetXOffset(sal_uInt16 nNewOffset) { nOfsX = nNewOffset; } + void SetYOffset(sal_uInt16 nNewOffset) { nOfsY = nNewOffset; } + void SetStartIntens(sal_uInt16 nNewIntens) { nIntensStart = nNewIntens; } + void SetEndIntens(sal_uInt16 nNewIntens) { nIntensEnd = nNewIntens; } + void SetSteps(sal_uInt16 nSteps) { nStepCount = nSteps; } + + css::awt::GradientStyle GetGradientStyle() const { return eStyle; } + const basegfx::BColorStops& GetColorStops() const { return aColorStops; } + Degree10 GetAngle() const { return nAngle; } + sal_uInt16 GetBorder() const { return nBorder; } + sal_uInt16 GetXOffset() const { return nOfsX; } + sal_uInt16 GetYOffset() const { return nOfsY; } + sal_uInt16 GetStartIntens() const { return nIntensStart; } + sal_uInt16 GetEndIntens() const { return nIntensEnd; } + sal_uInt16 GetSteps() const { return nStepCount; } + + boost::property_tree::ptree dumpAsJSON() const; + static BGradient fromJSON(std::u16string_view rJSON); + + // Tooling to handle + // - border correction/integration + // - apply StartStopIntensity to color stops + // - convert type from 'axial' to linear + // - apply Steps as 'hard' color stops + void tryToRecreateBorder(basegfx::BColorStops* pAssociatedTransparencyStops = nullptr); + void tryToApplyBorder(); + void tryToApplyStartEndIntensity(); + + // If a linear gradient is symmetrical it is converted to an axial gradient. + // Does nothing in other cases and for other gradient types. + void tryToConvertToAxial(); + void tryToApplyAxial(); + void tryToApplySteps(); +}; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/include/basegfx/utils/canvastools.hxx b/include/basegfx/utils/canvastools.hxx new file mode 100644 index 0000000000..4646609772 --- /dev/null +++ b/include/basegfx/utils/canvastools.hxx @@ -0,0 +1,167 @@ +/* -*- 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 . + */ + +#pragma once + +#include +#include +#include + + +namespace com::sun::star::geometry +{ + struct AffineMatrix2D; + struct AffineMatrix3D; + struct RealPoint2D; + struct RealSize2D; + struct RealRectangle2D; + struct RealRectangle3D; + struct IntegerSize2D; + struct IntegerRectangle2D; + struct RealBezierSegment2D; +} + +namespace com::sun::star::rendering +{ + class XGraphicDevice; + class XPolyPolygon2D; +} + +namespace com::sun::star::awt +{ + struct Rectangle; +} + +namespace basegfx +{ + class B2DHomMatrix; + class B3DHomMatrix; + class B2DVector; + class B2DPoint; + class B2DRange; + class B3DRange; + class B2IVector; + class B2IRange; + class B2DPolygon; + class B2DPolyPolygon; + class B2DSize; + class B2ISize; +} + +namespace basegfx::unotools +{ + // Polygon conversions + + + BASEGFX_DLLPUBLIC css::uno::Reference< css::rendering::XPolyPolygon2D > + xPolyPolygonFromB2DPolygon( const css::uno::Reference< css::rendering::XGraphicDevice >& xGraphicDevice, + const ::basegfx::B2DPolygon& rPoly ); + + BASEGFX_DLLPUBLIC css::uno::Reference< css::rendering::XPolyPolygon2D > + xPolyPolygonFromB2DPolyPolygon( const css::uno::Reference< css::rendering::XGraphicDevice >& xGraphicDevice, + const ::basegfx::B2DPolyPolygon& rPolyPoly ); + + + css::uno::Sequence< + css::uno::Sequence< css::geometry::RealBezierSegment2D > > + bezierSequenceSequenceFromB2DPolyPolygon( const ::basegfx::B2DPolyPolygon& rPolyPoly ); + + css::uno::Sequence< + css::uno::Sequence< css::geometry::RealPoint2D > > + pointSequenceSequenceFromB2DPolyPolygon( const ::basegfx::B2DPolyPolygon& rPolyPoly ); + + ::basegfx::B2DPolygon polygonFromPoint2DSequence( + const css::uno::Sequence< css::geometry::RealPoint2D >& rPoints ); + + BASEGFX_DLLPUBLIC ::basegfx::B2DPolyPolygon polyPolygonFromPoint2DSequenceSequence( + const css::uno::Sequence< css::uno::Sequence< css::geometry::RealPoint2D > >& rPoints ); + + ::basegfx::B2DPolygon polygonFromBezier2DSequence( + const css::uno::Sequence< css::geometry::RealBezierSegment2D >& rPoints ); + + BASEGFX_DLLPUBLIC ::basegfx::B2DPolyPolygon polyPolygonFromBezier2DSequenceSequence( + const css::uno::Sequence< css::uno::Sequence< css::geometry::RealBezierSegment2D > >& rPoints ); + + BASEGFX_DLLPUBLIC ::basegfx::B2DPolyPolygon b2DPolyPolygonFromXPolyPolygon2D( + const css::uno::Reference< css::rendering::XPolyPolygon2D >& rPoly ); + + // Matrix conversions + + + BASEGFX_DLLPUBLIC css::geometry::AffineMatrix2D& + affineMatrixFromHomMatrix( css::geometry::AffineMatrix2D& matrix, + const ::basegfx::B2DHomMatrix& transform); + + css::geometry::AffineMatrix3D& affineMatrixFromHomMatrix3D( + css::geometry::AffineMatrix3D& matrix, + const ::basegfx::B3DHomMatrix& transform); + + BASEGFX_DLLPUBLIC ::basegfx::B2DHomMatrix& + homMatrixFromAffineMatrix( ::basegfx::B2DHomMatrix& transform, + const css::geometry::AffineMatrix2D& matrix ); + + BASEGFX_DLLPUBLIC ::basegfx::B3DHomMatrix homMatrixFromAffineMatrix3D( const css::geometry::AffineMatrix3D& matrix ); + + // Geometry conversions + + + BASEGFX_DLLPUBLIC css::geometry::RealSize2D size2DFromB2DSize( const ::basegfx::B2DSize& ); + BASEGFX_DLLPUBLIC css::geometry::RealPoint2D point2DFromB2DPoint( const ::basegfx::B2DPoint& ); + BASEGFX_DLLPUBLIC css::geometry::RealRectangle2D rectangle2DFromB2DRectangle( const ::basegfx::B2DRange& ); + BASEGFX_DLLPUBLIC css::geometry::RealRectangle3D rectangle3DFromB3DRectangle( const ::basegfx::B3DRange& ); + + BASEGFX_DLLPUBLIC ::basegfx::B2DPoint b2DPointFromRealPoint2D( const css::geometry::RealPoint2D& ); + BASEGFX_DLLPUBLIC ::basegfx::B2DRange b2DRectangleFromRealRectangle2D( const css::geometry::RealRectangle2D& ); + ::basegfx::B3DRange b3DRectangleFromRealRectangle3D( const css::geometry::RealRectangle3D& ); + + BASEGFX_DLLPUBLIC css::geometry::IntegerSize2D integerSize2DFromB2ISize(basegfx::B2ISize const& rSize); + + BASEGFX_DLLPUBLIC ::basegfx::B2ISize b2ISizeFromIntegerSize2D( const css::geometry::IntegerSize2D& ); + BASEGFX_DLLPUBLIC ::basegfx::B2IRange b2IRectangleFromIntegerRectangle2D( const css::geometry::IntegerRectangle2D& ); + + BASEGFX_DLLPUBLIC ::basegfx::B2IRange b2IRectangleFromAwtRectangle( const css::awt::Rectangle& ); + + // Geometry comparisons + + + /** Return smalltest integer range, which completely contains + given floating point range. + + @param rRange + Input range. Values must be within the representable + bounds of sal_Int32 + + @return the closest integer range, which completely + contains rRange. + */ + BASEGFX_DLLPUBLIC ::basegfx::B2IRange b2ISurroundingRangeFromB2DRange( const ::basegfx::B2DRange& rRange ); + + /** Return smalltest B2DRange with integer values, which + completely contains given floating point range. + + @param rRange + Input range. + + @return the closest B2DRange with integer coordinates, + which completely contains rRange. + */ + BASEGFX_DLLPUBLIC ::basegfx::B2DRange b2DSurroundingIntegerRangeFromB2DRange( const ::basegfx::B2DRange& rRange ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/include/basegfx/utils/common.hxx b/include/basegfx/utils/common.hxx new file mode 100644 index 0000000000..1c11a8bf23 --- /dev/null +++ b/include/basegfx/utils/common.hxx @@ -0,0 +1,33 @@ +/* -*- 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 . + */ + +#pragma once + +namespace basegfx +{ +// The axis or dimension in a 2D coordinate system +enum class Axis2D +{ + X, + Y +}; + +} // end of namespace basegfx + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/include/basegfx/utils/gradienttools.hxx b/include/basegfx/utils/gradienttools.hxx new file mode 100644 index 0000000000..d56e73b90d --- /dev/null +++ b/include/basegfx/utils/gradienttools.hxx @@ -0,0 +1,526 @@ +/* -*- 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 . + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace basegfx { class B2DRange; } + +namespace +{ + /* Internal helper to convert ::Color from tools::color.hxx to BColor + without the need to link against tools library. Be on the + safe side by using the same union + */ + struct ColorToBColorConverter + { + union { + sal_uInt32 mValue; + struct { +#ifdef OSL_BIGENDIAN + sal_uInt8 T; + sal_uInt8 R; + sal_uInt8 G; + sal_uInt8 B; +#else + sal_uInt8 B; + sal_uInt8 G; + sal_uInt8 R; + sal_uInt8 T; +#endif + }; + }; + + ColorToBColorConverter GetRGBColor() const + { + return {R, G, B}; + } + + ColorToBColorConverter(sal_uInt32 nColor) + : mValue(nColor) + { T=0; } + + constexpr ColorToBColorConverter(sal_uInt8 nRed, sal_uInt8 nGreen, sal_uInt8 nBlue) + : mValue(sal_uInt32(nBlue) | (sal_uInt32(nGreen) << 8) | (sal_uInt32(nRed) << 16)) + {} + + explicit ColorToBColorConverter(const basegfx::BColor& rBColor) + : ColorToBColorConverter( + sal_uInt8(std::lround(rBColor.getRed() * 255.0)), + sal_uInt8(std::lround(rBColor.getGreen() * 255.0)), + sal_uInt8(std::lround(rBColor.getBlue() * 255.0))) + {} + + basegfx::BColor getBColor() const + { + return basegfx::BColor(R / 255.0, G / 255.0, B / 255.0); + } + + constexpr explicit operator sal_Int32() const + { + return sal_Int32(mValue); + } + + constexpr explicit operator sal_uInt32() const + { + return mValue; + } + }; +} + +namespace basegfx +{ + /** Gradient definition as used in ODF 1.2 + + This struct collects all data necessary for rendering ODF + 1.2-compatible gradients. Use the createXXXODFGradientInfo() + methods below for initializing from ODF attributes. + */ + class UNLESS_MERGELIBS(BASEGFX_DLLPUBLIC) ODFGradientInfo + { + private: + /** transformation mapping from [0,1]^2 texture coordinate + space to [0,1]^2 shape coordinate space + */ + B2DHomMatrix maTextureTransform; + + /** transformation mapping from [0,1]^2 shape coordinate space + to [0,1]^2 texture coordinate space. This is the + transformation commonly used to create gradients from a + scanline rasterizer (put shape u/v coordinates into it, get + texture s/t coordinates out of it) + */ + B2DHomMatrix maBackTextureTransform; + + /** Aspect ratio of the gradient. Only used in drawinglayer + for generating nested gradient polygons currently. Already + catered for in the transformations above. + */ + double mfAspectRatio; + + /** Requested gradient steps to render. See the + implementations of the getXXXGradientAlpha() methods below, + the semantic differs slightly for the different gradient + types. + */ + sal_uInt32 mnRequestedSteps; + + public: + ODFGradientInfo() + : mfAspectRatio(1.0), + mnRequestedSteps(0) + { + } + + ODFGradientInfo( + B2DHomMatrix aTextureTransform, + double fAspectRatio, + sal_uInt32 nRequestedSteps) + : maTextureTransform(std::move(aTextureTransform)), + mfAspectRatio(fAspectRatio), + mnRequestedSteps(nRequestedSteps) + { + } + + ODFGradientInfo(const ODFGradientInfo& rODFGradientInfo) + : maTextureTransform(rODFGradientInfo.getTextureTransform()), + maBackTextureTransform(rODFGradientInfo.maBackTextureTransform), + mfAspectRatio(rODFGradientInfo.getAspectRatio()), + mnRequestedSteps(rODFGradientInfo.getRequestedSteps()) + { + } + + ODFGradientInfo& operator=(const ODFGradientInfo& rODFGradientInfo) + { + maTextureTransform = rODFGradientInfo.getTextureTransform(); + maBackTextureTransform = rODFGradientInfo.maBackTextureTransform; + mfAspectRatio = rODFGradientInfo.getAspectRatio(); + mnRequestedSteps = rODFGradientInfo.getRequestedSteps(); + + return *this; + } + + // compare operator + bool operator==(const ODFGradientInfo& rGeoTexSvx) const; + + const B2DHomMatrix& getTextureTransform() const { return maTextureTransform; } + const B2DHomMatrix& getBackTextureTransform() const; + double getAspectRatio() const { return mfAspectRatio; } + sal_uInt32 getRequestedSteps() const { return mnRequestedSteps; } + + void setTextureTransform(const B2DHomMatrix& rNew) + { + maTextureTransform = rNew; + maBackTextureTransform.identity(); + } + }; + + namespace utils + { + /* Tooling method to extract data from given BGradient + to ColorStops, doing some corrections, partially based + on given SingleColor. + This is used for export preparations in case these exports + do neither support Start/EndIntensity nor Border settings, + both will be eliminated if possible (see below). + The BGradient rGradient and BColorStops& rColorStops + are both return parameters and may be changed. + This will do quite some preparations for the gradient + as follows: + - It will check for single color (resetting rSingleColor when + this is the case) and return with empty ColorStops + - It will blend ColorStops to Intensity if StartIntensity/ + EndIntensity != 100 is set in BGradient, so applying + that value(s) to the gradient directly + - It will adapt to Border if Border != 0 is set at the + given BGradient, so applying that value to the gradient + directly + */ + BASEGFX_DLLPUBLIC void prepareColorStops( + const basegfx::BGradient& rGradient, + BColorStops& rColorStops, + BColor& rSingleColor); + + /* Tooling method to synchronize the given ColorStops. + The intention is that a color GradientStops and an + alpha/transparence GradientStops gets synchronized + for export. + For the corrections the single values for color and + alpha may be used, e.g. when ColorStops is given + and not empty, but AlphaStops is empty, it will get + synchronized so that it will have the same number and + offsets in AlphaStops as in ColorStops, but with + the given SingleAlpha as value. + At return it guarantees that both have the same + number of entries with the same StopOffsets, so + that synchronized pair of ColorStops can e.g. be used + to export a Gradient with defined/adapted alpha + being 'coupled' indirectly using the + 'FillTransparenceGradient' method (at import time). + */ + BASEGFX_DLLPUBLIC void synchronizeColorStops( + BColorStops& rColorStops, + BColorStops& rAlphaStops, + const BColor& rSingleColor, + const BColor& rSingleAlpha); + + /* Helper to calculate numberOfSteps needed to represent + gradient for the given two colors: + - to define only based on color distance, give 0 == nRequestedSteps + as wanted value, so color distance will be used + - if a wanted value of nRequestedSteps is given, it gets synched + against the maximum number of steps defined by the color + distance of the two colors + - a minimum result of 1 is returned which means a single + step -> no real gradient + */ + BASEGFX_DLLPUBLIC sal_uInt32 calculateNumberOfSteps( + sal_uInt32 nRequestedSteps, + const BColor& rStart, + const BColor& rEnd); + + /** Create matrix for ODF's linear gradient definition + + Note that odf linear gradients are varying in y direction. + + @param o_rGradientInfo + Receives the calculated texture transformation matrix (for + use with standard [0,1]x[0,1] texture coordinates) + + @param rTargetArea + Output area, needed for aspect ratio calculations and + texture transformation + + @param nRequestedSteps + Number of gradient steps (from ODF) + + @param fBorder + Width of gradient border (from ODF) + + @param fAngle + Gradient angle (from ODF) + */ + BASEGFX_DLLPUBLIC ODFGradientInfo createLinearODFGradientInfo( + const B2DRange& rTargetArea, + sal_uInt32 nRequestedSteps, + double fBorder, + double fAngle); + + + /** Calculate linear gradient blend value + + This method generates you the lerp alpha value for + blending linearly between gradient start and end color, + according to the formula (startCol*(1.0-alpha) + endCol*alpha) + + @param rUV + Current uv coordinate. Values outside [0,1] will be + clamped. Assumes gradient color varies along the y axis. + + @param rGradInfo + Gradient info, for transformation and number of steps + */ + BASEGFX_DLLPUBLIC double getLinearGradientAlpha(const B2DPoint& rUV, + const ODFGradientInfo& rGradInfo); + + /** Create matrix for ODF's axial gradient definition + + Note that odf axial gradients are varying in y + direction. Note further that you can map the axial + gradient to a linear gradient (in case you want or need to + avoid an extra gradient renderer), by using + createLinearODFGradientInfo() instead, shifting the + resulting texture transformation by 0.5 to the top and + appending the same stop colors again, but mirrored. + + @param o_rGradientInfo + Receives the calculated texture transformation matrix (for + use with standard [0,1]x[0,1] texture coordinates) + + @param rTargetArea + Output area, needed for aspect ratio calculations and + texture transformation + + @param nRequestedSteps + Number of gradient steps (from ODF) + + @param fBorder + Width of gradient border (from ODF) + + @param fAngle + Gradient angle (from ODF) + */ + BASEGFX_DLLPUBLIC ODFGradientInfo createAxialODFGradientInfo( + const B2DRange& rTargetArea, + sal_uInt32 nRequestedSteps, + double fBorder, + double fAngle); + + + /** Calculate axial gradient blend value + + This method generates you the lerp alpha value for + blending linearly between gradient start and end color, + according to the formula (startCol*(1.0-alpha) + endCol*alpha) + + @param rUV + Current uv coordinate. Values outside [0,1] will be + clamped. Assumes gradient color varies along the y axis. + + @param rGradInfo + Gradient info, for transformation and number of steps + */ + BASEGFX_DLLPUBLIC double getAxialGradientAlpha(const B2DPoint& rUV, + const ODFGradientInfo& rGradInfo); + + /** Create matrix for ODF's radial gradient definition + + @param o_rGradientInfo + Receives the calculated texture transformation matrix (for + use with standard [0,1]x[0,1] texture coordinates) + + @param rTargetArea + Output area, needed for aspect ratio calculations and + texture transformation + + @param rOffset + Gradient offset value (from ODF) + + @param nRequestedSteps + Number of gradient steps (from ODF) + + @param fBorder + Width of gradient border (from ODF) + + @param fAngle + Gradient angle (from ODF) + */ + BASEGFX_DLLPUBLIC ODFGradientInfo createRadialODFGradientInfo( + const B2DRange& rTargetArea, + const B2DVector& rOffset, + sal_uInt32 nRequestedSteps, + double fBorder); + + + /** Calculate radial gradient blend value + + This method generates you the lerp alpha value for + blending linearly between gradient start and end color, + according to the formula (startCol*(1.0-alpha) + endCol*alpha) + + @param rUV + Current uv coordinate. Values outside [0,1] will be + clamped. + + @param rGradInfo + Gradient info, for transformation and number of steps + */ + BASEGFX_DLLPUBLIC double getRadialGradientAlpha(const B2DPoint& rUV, + const ODFGradientInfo& rGradInfo); + + /** Create matrix for ODF's elliptical gradient definition + + @param o_rGradientInfo + Receives the calculated texture transformation matrix (for + use with standard [0,1]x[0,1] texture coordinates) + + @param rTargetArea + Output area, needed for aspect ratio calculations and + texture transformation + + @param rOffset + Gradient offset value (from ODF) + + @param nRequestedSteps + Number of gradient steps (from ODF) + + @param fBorder + Width of gradient border (from ODF) + + @param fAngle + Gradient angle (from ODF) + */ + BASEGFX_DLLPUBLIC ODFGradientInfo createEllipticalODFGradientInfo( + const B2DRange& rTargetArea, + const B2DVector& rOffset, + sal_uInt32 nRequestedSteps, + double fBorder, + double fAngle); + + + /** Calculate elliptical gradient blend value + + This method generates you the lerp alpha value for + blending linearly between gradient start and end color, + according to the formula (startCol*(1.0-alpha) + endCol*alpha) + + @param rUV + Current uv coordinate. Values outside [0,1] will be + clamped. + + @param rGradInfo + Gradient info, for transformation and number of steps + */ + BASEGFX_DLLPUBLIC double getEllipticalGradientAlpha(const B2DPoint& rUV, + const ODFGradientInfo& rGradInfo); + + /** Create matrix for ODF's square gradient definition + + @param o_rGradientInfo + Receives the calculated texture transformation matrix (for + use with standard [0,1]x[0,1] texture coordinates) + + @param rTargetArea + Output area, needed for aspect ratio calculations and + texture transformation + + @param rOffset + Gradient offset value (from ODF) + + @param nRequestedSteps + Number of gradient steps (from ODF) + + @param fBorder + Width of gradient border (from ODF) + + @param fAngle + Gradient angle (from ODF) + */ + BASEGFX_DLLPUBLIC ODFGradientInfo createSquareODFGradientInfo( + const B2DRange& rTargetArea, + const B2DVector& rOffset, + sal_uInt32 nRequestedSteps, + double fBorder, + double fAngle); + + + /** Calculate square gradient blend value + + This method generates you the lerp alpha value for + blending linearly between gradient start and end color, + according to the formula (startCol*(1.0-alpha) + endCol*alpha) + + @param rUV + Current uv coordinate. Values outside [0,1] will be + clamped. + + @param rGradInfo + Gradient info, for transformation and number of steps + */ + BASEGFX_DLLPUBLIC double getSquareGradientAlpha(const B2DPoint& rUV, + const ODFGradientInfo& rGradInfo); + + /** Create matrix for ODF's rectangular gradient definition + + @param o_rGradientInfo + Receives the calculated texture transformation matrix (for + use with standard [0,1]x[0,1] texture coordinates) + + @param rTargetArea + Output area, needed for aspect ratio calculations and + texture transformation + + @param rOffset + Gradient offset value (from ODF) + + @param nRequestedSteps + Number of gradient steps (from ODF) + + @param fBorder + Width of gradient border (from ODF) + + @param fAngle + Gradient angle (from ODF) + */ + BASEGFX_DLLPUBLIC ODFGradientInfo createRectangularODFGradientInfo( + const B2DRange& rTargetArea, + const B2DVector& rOffset, + sal_uInt32 nRequestedSteps, + double fBorder, + double fAngle); + + + /** Calculate rectangular gradient blend value + + This method generates you the lerp alpha value for + blending linearly between gradient start and end color, + according to the formula (startCol*(1.0-alpha) + endCol*alpha) + + @param rUV + Current uv coordinate. Values outside [0,1] will be + clamped. + + @param rGradInfo + Gradient info, for transformation and number of steps + */ + BASEGFX_DLLPUBLIC double getRectangularGradientAlpha(const B2DPoint& rUV, + const ODFGradientInfo& rGradInfo); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/include/basegfx/utils/keystoplerp.hxx b/include/basegfx/utils/keystoplerp.hxx new file mode 100644 index 0000000000..f8a821e7a5 --- /dev/null +++ b/include/basegfx/utils/keystoplerp.hxx @@ -0,0 +1,85 @@ +/* -*- 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 . + */ + +#pragma once + +#include +#include + +namespace com::sun::star::uno { + template class Sequence; +} + +namespace basegfx::utils +{ + /** Lerp in a vector of key stops + + This class holds a key stop vector and provides the + functionality to lerp inside it. Useful e.g. for + multi-stop gradients, or the SMIL key time activity. + + For those, given a global [0,1] lerp alpha, one need to + find the suitable bucket index from key stop vector, and + then calculate the relative alpha between the two buckets + found. + */ + class BASEGFX_DLLPUBLIC KeyStopLerp + { + public: + typedef std::pair ResultType; + + /** Create lerper with given vector of stops + + @param rKeyStops + + Vector of stops, must contain at least two elements + (though preferably more, otherwise you probably don't + need key stop lerping in the first place). All + elements must be of monotonically increasing value. + */ + explicit KeyStopLerp( std::vector&& rKeyStops ); + + /** Create lerper with given sequence of stops + + @param rKeyStops + + Sequence of stops, must contain at least two elements + (though preferably more, otherwise you probably don't + need key stop lerping in the first place). All + elements must be of monotonically increasing value. + */ + explicit KeyStopLerp( const css::uno::Sequence& rKeyStops ); + + /** Find two nearest bucket index & interpolate + + @param fAlpha + Find bucket index i, with keyStops[i] < fAlpha <= + keyStops[i+1]. Return new alpha value in [0,1), + proportional to fAlpha's position between keyStops[i] + and keyStops[i+1] + */ + ResultType lerp(double fAlpha) const; + + private: + std::vector maKeyStops; + mutable std::ptrdiff_t mnLastIndex; + }; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/include/basegfx/utils/lerp.hxx b/include/basegfx/utils/lerp.hxx new file mode 100644 index 0000000000..e02b3b0fa5 --- /dev/null +++ b/include/basegfx/utils/lerp.hxx @@ -0,0 +1,43 @@ +/* -*- 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 . + */ + +#pragma once + +namespace basegfx::utils +{ + /** Generic linear interpolator + + @tpl ValueType + Must have operator+ and operator* defined, and should + have value semantics. + + @param t + As usual, t must be in the [0,1] range + */ + template< typename ValueType > ValueType lerp( const ValueType& rFrom, + const ValueType& rTo, + double t ) + { + // This is only to suppress a double->int warning. All other + // types should be okay here. + return static_cast( (1.0-t)*rFrom + t*rTo ); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/include/basegfx/utils/rectcliptools.hxx b/include/basegfx/utils/rectcliptools.hxx new file mode 100644 index 0000000000..af6be75bfc --- /dev/null +++ b/include/basegfx/utils/rectcliptools.hxx @@ -0,0 +1,72 @@ +/* -*- 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 . + */ + +#pragma once + +#include +#include + + +namespace basegfx::utils +{ + namespace RectClipFlags + { + const sal_uInt32 LEFT = sal_Int32(0x01); + const sal_uInt32 RIGHT = sal_Int32(0x02); + const sal_uInt32 TOP = sal_Int32(0x04); + const sal_uInt32 BOTTOM = sal_Int32(0x08); + } + + /** Calc clip mask for Cohen-Sutherland rectangle clip + + This function returns a clip mask used for the + Cohen-Sutherland rectangle clip method, where one or more + of the lower four bits are set, if the given point is + outside one or more of the four half planes defining the + rectangle (see RectClipFlags for possible values) + */ + template< class Point, class Rect > inline + sal_uInt32 getCohenSutherlandClipFlags( const Point& rP, + const Rect& rR ) + { + // maxY | minY | maxX | minX + sal_uInt32 clip; + clip = (rP.getX() < rR.getMinX()) << 0; + clip |= (rP.getX() > rR.getMaxX()) << 1; + clip |= (rP.getY() < rR.getMinY()) << 2; + clip |= (rP.getY() > rR.getMaxY()) << 3; + return clip; + } + + /// Cohen-Sutherland mask calculation - overload for boxes. + template< class Point > inline + sal_uInt32 getCohenSutherlandClipFlags( const Point& rP, + const B2IBox& rB ) + { + // maxY | minY | maxX | minX + sal_uInt32 clip; + clip = (rP.getX() < rB.getMinX()) << 0; + clip |= (rP.getX() >= rB.getMaxX()) << 1; + clip |= (rP.getY() < rB.getMinY()) << 2; + clip |= (rP.getY() >= rB.getMaxY()) << 3; + return clip; + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/include/basegfx/utils/systemdependentdata.hxx b/include/basegfx/utils/systemdependentdata.hxx new file mode 100644 index 0000000000..9304153c13 --- /dev/null +++ b/include/basegfx/utils/systemdependentdata.hxx @@ -0,0 +1,111 @@ +/* -*- 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/. + */ + +#pragma once + +#include +#include +#include +#include + +namespace basegfx +{ + class SystemDependentData; + typedef std::shared_ptr SystemDependentData_SharedPtr; + typedef std::weak_ptr SystemDependentData_WeakPtr; + + class BASEGFX_DLLPUBLIC SystemDependentDataManager + { + private: + // noncopyable + SystemDependentDataManager(const SystemDependentDataManager&) = delete; + SystemDependentDataManager& operator=(const SystemDependentDataManager&) = delete; + + public: + SystemDependentDataManager(); + virtual ~SystemDependentDataManager(); + + // call from (and with) SystemDependentData objects when start/end/touch + // usage is needed + virtual void startUsage(basegfx::SystemDependentData_SharedPtr& rData) = 0; + virtual void endUsage(basegfx::SystemDependentData_SharedPtr& rData) = 0; + virtual void touchUsage(basegfx::SystemDependentData_SharedPtr& rData) = 0; + + // flush all buffered data (e.g. cleanup/shutdown) + virtual void flushAll() = 0; + }; + + class BASEGFX_DLLPUBLIC SystemDependentData + { + private: + // noncopyable + SystemDependentData(const SystemDependentData&) = delete; + SystemDependentData& operator=(const SystemDependentData&) = delete; + + // reference to a SystemDependentDataManager, probably + // a single, globally used one, but not necessarily + SystemDependentDataManager& mrSystemDependentDataManager; + + // Buffered CalculatedCycles, result of estimations using + // getHoldCyclesInSeconds and estimateUsageInBytes, executed + // using getHoldCyclesInSeconds. StartValue is 0 to detect + // not-yet-calculated state + sal_uInt32 mnCalculatedCycles; + + public: + SystemDependentData( + SystemDependentDataManager& rSystemDependentDataManager); + + // CAUTION! It is VERY important to keep this base class + // virtual, else typeid(class).hash_code() from derived classes + // will NOT work what is ESSENTIAL for the SystemDependentData + // mechanism to work properly. So DO NOT REMOVE virtual here, please. + virtual ~SystemDependentData(); + + // allow access to call startUsage/endUsage/touchUsage + // using getSystemDependentDataManager() + SystemDependentDataManager& getSystemDependentDataManager() { return mrSystemDependentDataManager; } + + // Calculate HoldCyclesInSeconds based on using + // getHoldCyclesInSeconds and estimateUsageInBytes, the + // result is created once on-demand and buffered in + // mnCalculatedCycles + sal_uInt32 calculateCombinedHoldCyclesInSeconds() const; + + // Allow read access to the calculated cycles in seconds, this + // can be e.g. used to determine if this instance got added + sal_uInt32 getCombinedHoldCyclesInSeconds() const { return mnCalculatedCycles; } + + // Size estimation of the entry in bytes - does not have to + // be used, but should be. Default returns zero what + // means there is no size estimation available. Override to + // offer useful data if you want to have better caching. + virtual sal_Int64 estimateUsageInBytes() const; + }; + + class BASEGFX_DLLPUBLIC SystemDependentDataHolder + { + private: + // Possibility to hold System-Dependent B2DPolygon-Representations + std::map< size_t, SystemDependentData_WeakPtr > maSystemDependentReferences; + + // noncopyable + SystemDependentDataHolder(const SystemDependentDataHolder&) = delete; + SystemDependentDataHolder& operator=(const SystemDependentDataHolder&) = delete; + + public: + SystemDependentDataHolder(); + virtual ~SystemDependentDataHolder(); + + void addOrReplaceSystemDependentData(SystemDependentData_SharedPtr& rData); + SystemDependentData_SharedPtr getSystemDependentData(size_t hash_code) const; + }; +} // end of namespace basegfx + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/include/basegfx/utils/tools.hxx b/include/basegfx/utils/tools.hxx new file mode 100644 index 0000000000..f8fc619995 --- /dev/null +++ b/include/basegfx/utils/tools.hxx @@ -0,0 +1,124 @@ +/* -*- 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 . + */ + +#pragma once + +#include +#include + +namespace basegfx +{ + class B2DPoint; + class B2DRange; + class B2DPolyPolygon; +} + +namespace basegfx::utils +{ + /** Expand given parallelogram, such that it extends beyond + bound rect in a given direction. + + This method is useful when e.g. generating one-dimensional + gradients, such as linear or axial gradients: those + gradients vary only in one direction, the other has + constant color. Most of the time, those gradients extends + infinitely in the direction with the constant color, but + practically, one always has a limiting bound rect into + which the gradient is painted. The method at hand now + extends a given parallelogram (e.g. the transformed + bounding box of a gradient) virtually into infinity to the + top and to the bottom (i.e. normal to the line io_rLeftTop + io_rRightTop), such that the given rectangle is guaranteed + to be covered in that direction. + + @attention There might be some peculiarities with this + method, that might limit its usage to the described + gradients. One of them is the fact that when determining + how far the parallelogram has to be extended to the top or + the bottom, the upper and lower border are assumed to be + infinite lines. + + @param io_rLeftTop + Left, top edge of the parallelogramm. Note that this need + not be the left, top edge geometrically, it's just used + when determining the extension direction. Thus, it's + perfectly legal to affine-transform a rectangle, and given + the transformed point here. On method return, this + parameter will contain the adapted output. + + @param io_rLeftBottom + Left, bottom edge of the parallelogramm. Note that this need + not be the left, bottom edge geometrically, it's just used + when determining the extension direction. Thus, it's + perfectly legal to affine-transform a rectangle, and given + the transformed point here. On method return, this + parameter will contain the adapted output. + + @param io_rRightTop + Right, top edge of the parallelogramm. Note that this need + not be the right, top edge geometrically, it's just used + when determining the extension direction. Thus, it's + perfectly legal to affine-transform a rectangle, and given + the transformed point here. On method return, this + parameter will contain the adapted output. + + @param io_rRightBottom + Right, bottom edge of the parallelogramm. Note that this need + not be the right, bottom edge geometrically, it's just used + when determining the extension direction. Thus, it's + perfectly legal to affine-transform a rectangle, and given + the transformed point here. On method return, this + parameter will contain the adapted output. + + @param rFitTarget + The rectangle to fit the parallelogram into. + */ + BASEGFX_DLLPUBLIC void infiniteLineFromParallelogram( ::basegfx::B2DPoint& io_rLeftTop, + ::basegfx::B2DPoint& io_rLeftBottom, + ::basegfx::B2DPoint& io_rRightTop, + ::basegfx::B2DPoint& io_rRightBottom, + const ::basegfx::B2DRange& rFitTarget ); + + /** Creates polypolygon with the given number as seven-segment + digits + + @param fVal + Value to convert + + @param nTotalDigits + Total number of digits to display. If less is needed for + given number, fill space with blanks. + + @param nDecPlaces + Decimal places to show. When 0, display as integer. When + negative, fill given number of before-the-decimal point + with zero. + + @param bLitSegments + When true, return a polygon containing the segments that + are 'lit' for the given number. Return un-lit segments + otherwise. + */ + BASEGFX_DLLPUBLIC B2DPolyPolygon number2PolyPolygon(double fVal, + sal_Int32 nTotalDigits, + sal_Int32 nDecPlaces, + bool bLitSegments=true); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/include/basegfx/utils/unopolypolygon.hxx b/include/basegfx/utils/unopolypolygon.hxx new file mode 100644 index 0000000000..48788b074e --- /dev/null +++ b/include/basegfx/utils/unopolypolygon.hxx @@ -0,0 +1,104 @@ +/* -*- 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 . + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace basegfx::unotools +{ + typedef comphelper::WeakComponentImplHelper< + css::rendering::XLinePolyPolygon2D, + css::rendering::XBezierPolyPolygon2D, + css::lang::XServiceInfo > UnoPolyPolygonBase; + + class BASEGFX_DLLPUBLIC UnoPolyPolygon + : public UnoPolyPolygonBase + { + public: + explicit UnoPolyPolygon( B2DPolyPolygon ); + + // XPolyPolygon2D + SAL_DLLPRIVATE virtual void SAL_CALL addPolyPolygon( const css::geometry::RealPoint2D& position, const css::uno::Reference< css::rendering::XPolyPolygon2D >& polyPolygon ) override; + SAL_DLLPRIVATE virtual ::sal_Int32 SAL_CALL getNumberOfPolygons( ) override; + SAL_DLLPRIVATE virtual ::sal_Int32 SAL_CALL getNumberOfPolygonPoints( ::sal_Int32 polygon ) override; + SAL_DLLPRIVATE virtual css::rendering::FillRule SAL_CALL getFillRule( ) override; + SAL_DLLPRIVATE virtual void SAL_CALL setFillRule( css::rendering::FillRule fillRule ) override; + SAL_DLLPRIVATE virtual sal_Bool SAL_CALL isClosed( ::sal_Int32 index ) override; + SAL_DLLPRIVATE virtual void SAL_CALL setClosed( ::sal_Int32 index, sal_Bool closedState ) override; + + // XLinePolyPolygon2D + SAL_DLLPRIVATE virtual css::uno::Sequence< css::uno::Sequence< css::geometry::RealPoint2D > > SAL_CALL getPoints( ::sal_Int32 nPolygonIndex, ::sal_Int32 nNumberOfPolygons, ::sal_Int32 nPointIndex, ::sal_Int32 nNumberOfPoints ) override; + SAL_DLLPRIVATE virtual void SAL_CALL setPoints( const css::uno::Sequence< css::uno::Sequence< css::geometry::RealPoint2D > >& points, ::sal_Int32 nPolygonIndex ) override; + SAL_DLLPRIVATE virtual css::geometry::RealPoint2D SAL_CALL getPoint( ::sal_Int32 nPolygonIndex, ::sal_Int32 nPointIndex ) override; + SAL_DLLPRIVATE virtual void SAL_CALL setPoint( const css::geometry::RealPoint2D& point, ::sal_Int32 nPolygonIndex, ::sal_Int32 nPointIndex ) override; + + // XBezierPolyPolygon2D + SAL_DLLPRIVATE virtual css::uno::Sequence< css::uno::Sequence< css::geometry::RealBezierSegment2D > > SAL_CALL getBezierSegments( ::sal_Int32 nPolygonIndex, ::sal_Int32 nNumberOfPolygons, ::sal_Int32 nPointIndex, ::sal_Int32 nNumberOfPoints ) override; + SAL_DLLPRIVATE virtual void SAL_CALL setBezierSegments( const css::uno::Sequence< css::uno::Sequence< css::geometry::RealBezierSegment2D > >& points, ::sal_Int32 nPolygonIndex ) override; + SAL_DLLPRIVATE virtual css::geometry::RealBezierSegment2D SAL_CALL getBezierSegment( ::sal_Int32 nPolygonIndex, ::sal_Int32 nPointIndex ) override; + SAL_DLLPRIVATE virtual void SAL_CALL setBezierSegment( const css::geometry::RealBezierSegment2D& point, ::sal_Int32 nPolygonIndex, ::sal_Int32 nPointIndex ) override; + + // XServiceInfo + SAL_DLLPRIVATE virtual OUString SAL_CALL getImplementationName() override; + SAL_DLLPRIVATE virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + SAL_DLLPRIVATE virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + + SAL_DLLPRIVATE B2DPolyPolygon getPolyPolygon() const; + + protected: + /// Check whether index is a valid polygon index + void checkIndex( sal_Int32 nIndex ) const // throw (css::lang::IndexOutOfBoundsException); + { + if( nIndex < 0 || o3tl::make_unsigned(nIndex) >= maPolyPoly.count() ) + throw css::lang::IndexOutOfBoundsException(); + } + + SAL_DLLPRIVATE B2DPolyPolygon getSubsetPolyPolygon( sal_Int32 nPolygonIndex, + sal_Int32 nNumberOfPolygons, + sal_Int32 nPointIndex, + sal_Int32 nNumberOfPoints ) const; + + /// Get cow copy of internal polygon. not thread-safe outside this object. + const B2DPolyPolygon& getPolyPolygonUnsafe() const + { + return maPolyPoly; + } + + /// Called whenever internal polypolygon gets modified + virtual void modifying() const {} + + private: + UnoPolyPolygon(const UnoPolyPolygon&) = delete; + UnoPolyPolygon& operator=(const UnoPolyPolygon&) = delete; + + B2DPolyPolygon maPolyPoly; + css::rendering::FillRule meFillRule; + }; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/include/basegfx/utils/zoomtools.hxx b/include/basegfx/utils/zoomtools.hxx new file mode 100644 index 0000000000..16a36448af --- /dev/null +++ b/include/basegfx/utils/zoomtools.hxx @@ -0,0 +1,22 @@ +/* -*- 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/. + */ + +#pragma once + +#include + +namespace basegfx::zoomtools +{ +/** This namespace provides functions for optimized geometric zooming +*/ +BASEGFX_DLLPUBLIC sal_uInt16 zoomOut(sal_uInt16 nCurrent); +BASEGFX_DLLPUBLIC sal_uInt16 zoomIn(sal_uInt16 nCurrent); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/include/basegfx/vector/b2dsize.hxx b/include/basegfx/vector/b2dsize.hxx new file mode 100644 index 0000000000..08793ef136 --- /dev/null +++ b/include/basegfx/vector/b2dsize.hxx @@ -0,0 +1,99 @@ +/* -*- 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 . + */ + +#pragma once + +#include +#include +#include +#include + +namespace basegfx +{ +class B2DSize : public Size2D +{ +public: + B2DSize() + : Size2D(0.0, 0.0) + { + } + + B2DSize(double fX, double fY) + : Size2D(fX, fY) + { + } + + B2DSize(Size2D const& rSize) + : Size2D(rSize) + { + } + + explicit B2DSize(B2ISize const& rSize) + : Size2D(rSize.getWidth(), rSize.getHeight()) + { + } + + /** Transform size by given transformation matrix. */ + B2DSize& operator*=(const B2DHomMatrix& rMatrix) + { + const double fTempX(rMatrix.get(0, 0) * getWidth() + rMatrix.get(0, 1) * getHeight()); + const double fTempY(rMatrix.get(1, 0) * getWidth() + rMatrix.get(1, 1) * getHeight()); + setWidth(fTempX); + setHeight(fTempY); + return *this; + } + + using Size2D::operator+=; + using Size2D::operator-=; + using Size2D::operator*=; + using Size2D::operator/=; + using Size2D::operator-; + + double getLength() const + { + if (fTools::equalZero(getWidth())) + { + return fabs(getHeight()); + } + else if (fTools::equalZero(getHeight())) + { + return fabs(getWidth()); + } + + return hypot(getWidth(), getHeight()); + } +}; + +template +inline std::basic_ostream& operator<<(std::basic_ostream& stream, + const B2DSize& size) +{ + return stream << "(" << size.getWidth() << "," << size.getHeight() << ")"; +} + +inline B2DSize operator*(B2DHomMatrix const& rMatrix, B2DSize const& rSize) +{ + B2DSize aRes(rSize); + aRes *= rMatrix; + return aRes; +} + +} // end basegfx + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/include/basegfx/vector/b2dvector.hxx b/include/basegfx/vector/b2dvector.hxx new file mode 100644 index 0000000000..b698ccffe6 --- /dev/null +++ b/include/basegfx/vector/b2dvector.hxx @@ -0,0 +1,242 @@ +/* -*- 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 . + */ + +#pragma once + +#include +#include +#include +#include + +namespace basegfx +{ + class B2DHomMatrix; + + /** Base Point class with two double values + + This class derives all operators and common handling for + a 2D data class from B2DTuple. All necessary extensions + which are special for 2D Vectors are added here. + + @see B2DTuple + */ + class SAL_WARN_UNUSED BASEGFX_DLLPUBLIC B2DVector : public ::basegfx::B2DTuple + { + public: + /** Create a 2D Vector + + The vector is initialized to (0.0, 0.0) + */ + B2DVector() + {} + + /** Create a 2D Vector + + @param fX + This parameter is used to initialize the X-coordinate + of the 2D Vector. + + @param fY + This parameter is used to initialize the Y-coordinate + of the 2D Vector. + */ + B2DVector(double fX, double fY) + : B2DTuple(fX, fY) + {} + + /** Create a copy of a 2D Vector + + @param rVec + The 2D Vector which will be copied. + */ + explicit B2DVector(const ::basegfx::B2IVector& rVec) + : B2DTuple(rVec) + {} + + /** constructor with tuple to allow copy-constructing + from B2DTuple-based classes + */ + B2DVector(Tuple2D const& rTuple) + : B2DTuple(rTuple) + {} + + /** *=operator to allow usage from B2DVector, too + */ + B2DVector& operator*=( const B2DVector& rPnt ) + { + mnX *= rPnt.mnX; + mnY *= rPnt.mnY; + return *this; + } + + /** *=operator to allow usage from B2DVector, too + */ + B2DVector& operator*=(double t) + { + mnX *= t; + mnY *= t; + return *this; + } + + /** assignment operator to allow assigning the results + of B2DTuple calculations + */ + B2DVector& operator=(Tuple2D const& rVector) + { + mnX = rVector.getX(); + mnY = rVector.getY(); + return *this; + } + + /** Calculate the length of this 2D Vector + + @return The Length of the 2D Vector + */ + double getLength() const; + + /** Set the length of this 2D Vector + + @param fLen + The to be achieved length of the 2D Vector + */ + B2DVector& setLength(double fLen); + + /** Normalize this 2D Vector + + The length of the 2D Vector is set to 1.0 + */ + B2DVector& normalize(); + + /** Calculate the Scalar with another 2D Vector + + @param rVec + The second 2D Vector + + @return + The Scalar value of the two involved 2D Vectors + */ + double scalar( const B2DVector& rVec ) const { return((mnX * rVec.mnX) + (mnY * rVec.mnY)); } + + /** Calculate the length of the cross product with another 2D Vector + + In 2D, returning an actual vector does not make much + sense here. The magnitude, although, can be readily + used for tasks such as angle calculations, since for + the returned value, the following equation holds: + retVal = getLength(this)*getLength(rVec)*sin(theta), + with theta being the angle between the two vectors. + + @param rVec + The second 2D Vector + + @return + The length of the cross product of the two involved 2D Vectors + */ + double cross( const B2DVector& rVec ) const { return(mnX * rVec.getY() - mnY * rVec.getX()); } + + /** Calculate the Angle with another 2D Vector + + @param rVec + The second 2D Vector + + @return + The Angle value of the two involved 2D Vectors ranging from -pi to +pi + */ + double angle( const B2DVector& rVec ) const; + + /** Transform vector by given transformation matrix. + + Since this is a vector, translational components of the + matrix are disregarded. + */ + B2DVector& operator*=( const B2DHomMatrix& rMat ); + + static const B2DVector& getEmptyVector(); + }; + + // external operators + + + /** Calculate the orientation to another 2D Vector + + @param rVecA + The first 2D Vector + + @param rVecB + The second 2D Vector + + @return + The mathematical Orientation of the two involved 2D Vectors + */ + BASEGFX_DLLPUBLIC B2VectorOrientation getOrientation( const B2DVector& rVecA, const B2DVector& rVecB ); + + /** Calculate a perpendicular 2D Vector to the given one + + @param rVec + The source 2D Vector + + @attention This only works if the given 2D Vector is normalized. + + @return + A 2D Vector perpendicular to the one given in parameter rVec + */ + BASEGFX_DLLPUBLIC B2DVector getPerpendicular( const B2DVector& rNormalizedVec ); + + /** Calculate a perpendicular 2D Vector to the given one, + normalize the given one as preparation + + @param rVec + The source 2D Vector + + @return + A normalized 2D Vector perpendicular to the one given in parameter rVec + */ + BASEGFX_DLLPUBLIC B2DVector getNormalizedPerpendicular( const B2DVector& rVec ); + + /** Test two vectors which need not to be normalized for parallelism + + @param rVecA + The first 2D Vector + + @param rVecB + The second 2D Vector + + @return + bool if the two values are parallel. Also true if + one of the vectors is empty. + */ + BASEGFX_DLLPUBLIC bool areParallel( const B2DVector& rVecA, const B2DVector& rVecB ); + + /** Transform vector by given transformation matrix. + + Since this is a vector, translational components of the + matrix are disregarded. + */ + BASEGFX_DLLPUBLIC B2DVector operator*( const B2DHomMatrix& rMat, const B2DVector& rVec ); + + /** Test continuity between given vectors. + + The two given vectors are assumed to describe control points on a + common point. Calculate if there is a continuity between them. + */ + BASEGFX_DLLPUBLIC B2VectorContinuity getContinuity( const B2DVector& rBackVector, const B2DVector& rForwardVector ); + +} // end of namespace basegfx + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/include/basegfx/vector/b2enums.hxx b/include/basegfx/vector/b2enums.hxx new file mode 100644 index 0000000000..3e81d27d68 --- /dev/null +++ b/include/basegfx/vector/b2enums.hxx @@ -0,0 +1,68 @@ +/* -*- 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 . + */ + +#pragma once + +namespace basegfx +{ + /** Descriptor for the mathematical orientations of two 2D Vectors + */ + enum class B2VectorOrientation + { + /// mathematically positive oriented + Positive = 0, + + /// mathematically negative oriented + Negative, + + /// mathematically neutral, thus parallel + Neutral + }; + + /** Descriptor for the mathematical continuity of two 2D Vectors + */ + enum class B2VectorContinuity + { + /// none + NONE = 0, + + /// mathematically negative oriented + C1, + + /// mathematically neutral, thus parallel + C2 + }; + + /** Descriptor for possible line joins between two line segments + * + * Note: WriteLineInfo/ReadLineInfo stream these values for svm + * file format + */ + enum class B2DLineJoin + { + NONE = 0, // no rounding + // removed unused Middle join type + Bevel = 2, // join edges with line + Miter = 3, // extend till cut + Round = 4 // create arc + }; + +} // end of namespace basegfx + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/include/basegfx/vector/b2isize.hxx b/include/basegfx/vector/b2isize.hxx new file mode 100644 index 0000000000..8d035bcc16 --- /dev/null +++ b/include/basegfx/vector/b2isize.hxx @@ -0,0 +1,60 @@ +/* -*- 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 . + */ + +#pragma once + +#include + +namespace basegfx +{ +class B2ISize : public Size2D +{ +public: + B2ISize() + : Size2D(0, 0) + { + } + + B2ISize(sal_Int32 nX, sal_Int32 nY) + : Size2D(nX, nY) + { + } + + B2ISize(Size2D const& rSize) + : Size2D(rSize) + { + } + + using Size2D::operator+=; + using Size2D::operator-=; + using Size2D::operator*=; + using Size2D::operator/=; + using Size2D::operator-; +}; + +template +inline std::basic_ostream& operator<<(std::basic_ostream& stream, + const B2ISize& size) +{ + return stream << "(" << size.getWidth() << "," << size.getHeight() << ")"; +} + +} // end basegfx + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/include/basegfx/vector/b2ivector.hxx b/include/basegfx/vector/b2ivector.hxx new file mode 100644 index 0000000000..b542fe880e --- /dev/null +++ b/include/basegfx/vector/b2ivector.hxx @@ -0,0 +1,129 @@ +/* -*- 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 . + */ + +#pragma once + +#include + +#include +#include + +namespace basegfx +{ + class B2DHomMatrix; + + /** Base Point class with two sal_Int32 values + + This class derives all operators and common handling for + a 2D data class from B2ITuple. All necessary extensions + which are special for 2D Vectors are added here. + + @see B2ITuple + */ + class BASEGFX_DLLPUBLIC B2IVector : public ::basegfx::B2ITuple + { + public: + /** Create a 2D Vector + + The vector is initialized to (0, 0) + */ + B2IVector() + {} + + /** Create a 2D Vector + + @param nX + This parameter is used to initialize the X-coordinate + of the 2D Vector. + + @param nY + This parameter is used to initialize the Y-coordinate + of the 2D Vector. + */ + B2IVector(sal_Int32 nX, sal_Int32 nY) + : B2ITuple(nX, nY) + {} + + /** constructor with tuple to allow copy-constructing + from B2ITuple-based classes + */ + B2IVector(const ::basegfx::B2ITuple& rTuple) + : B2ITuple(rTuple) + {} + + /** *=operator to allow usage from B2IVector, too + */ + B2IVector& operator*=( const B2IVector& rPnt ) + { + mnX *= rPnt.mnX; + mnY *= rPnt.mnY; + return *this; + } + + /** *=operator to allow usage from B2IVector, too + */ + B2IVector& operator*=(sal_Int32 t) + { + mnX *= t; + mnY *= t; + return *this; + } + + /** assignment operator to allow assigning the results + of B2ITuple calculations + */ + B2IVector& operator=( const ::basegfx::B2ITuple& rVec ); + + /** Set the length of this 2D Vector + + @param fLen + The to be achieved length of the 2D Vector + */ + B2IVector& setLength(double fLen); + + /** Calculate the Scalar with another 2D Vector + + @param rVec + The second 2D Vector + + @return + The Scalar value of the two involved 2D Vectors + */ + double scalar( const B2IVector& rVec ) const { return((mnX * rVec.mnX) + (mnY * rVec.mnY)); } + + /** Transform vector by given transformation matrix. + + Since this is a vector, translational components of the + matrix are disregarded. + */ + B2IVector& operator*=( const B2DHomMatrix& rMat ); + }; + + // external operators + + template< typename charT, typename traits > + inline std::basic_ostream & operator <<( + std::basic_ostream & stream, const basegfx::B2IVector& vector ) + { + return stream << "(" << vector.getX() << "," << vector.getY() << ")"; + } + +} // end of namespace basegfx + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/include/basegfx/vector/b3dvector.hxx b/include/basegfx/vector/b3dvector.hxx new file mode 100644 index 0000000000..44c926e805 --- /dev/null +++ b/include/basegfx/vector/b3dvector.hxx @@ -0,0 +1,258 @@ +/* -*- 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 . + */ + +#pragma once + +#include +#include + +namespace basegfx +{ + class B3DHomMatrix; + + /** Base Point class with three double values + + This class derives all operators and common handling for + a 3D data class from B3DTuple. All necessary extensions + which are special for 3D Vectors are added here. + + @see B3DTuple + */ + class SAL_WARN_UNUSED BASEGFX_DLLPUBLIC B3DVector : public ::basegfx::B3DTuple + { + public: + /** Create a 3D Vector + + The vector is initialized to (0.0, 0.0, 0.0) + */ + B3DVector() + {} + + /** Create a 3D Vector + + @param fX + This parameter is used to initialize the X-coordinate + of the 3D Vector. + + @param fY + This parameter is used to initialize the Y-coordinate + of the 3D Vector. + + @param fZ + This parameter is used to initialize the Z-coordinate + of the 3D Vector. + */ + B3DVector(double fX, double fY, double fZ) + : B3DTuple(fX, fY, fZ) + {} + + /** constructor with tuple to allow copy-constructing + from B3DTuple-based classes + */ + B3DVector(const ::basegfx::B3DTuple& rTuple) + : B3DTuple(rTuple) + {} + + /** *=operator to allow usage from B3DVector, too + */ + B3DVector& operator*=( const B3DVector& rPnt ) + { + mnX *= rPnt.mnX; + mnY *= rPnt.mnY; + mnZ *= rPnt.mnZ; + return *this; + } + + /** *=operator to allow usage from B3DVector, too + */ + B3DVector& operator*=(double t) + { + mnX *= t; + mnY *= t; + mnZ *= t; + return *this; + } + + /** assignment operator to allow assigning the results + of B3DTuple calculations + */ + B3DVector& operator=( const ::basegfx::B3DTuple& rVec ) + { + mnX = rVec.getX(); + mnY = rVec.getY(); + mnZ = rVec.getZ(); + return *this; + } + + /** Calculate the length of this 3D Vector + + @return The Length of the 3D Vector + */ + double getLength() const + { + double fLen(scalar(*this)); + if((0.0 == fLen) || (1.0 == fLen)) + return fLen; + return sqrt(fLen); + } + + /** Calculate the length in the XZ-Plane for this 3D Vector + + @return The XZ-Plane Length of the 3D Vector + */ + double getXZLength() const + { + double fLen((mnX * mnX) + (mnZ * mnZ)); // #i73040# + if((0.0 == fLen) || (1.0 == fLen)) + return fLen; + return sqrt(fLen); + } + + /** Calculate the length in the YZ-Plane for this 3D Vector + + @return The YZ-Plane Length of the 3D Vector + */ + double getYZLength() const + { + double fLen((mnY * mnY) + (mnZ * mnZ)); + if((0.0 == fLen) || (1.0 == fLen)) + return fLen; + return sqrt(fLen); + } + + /** Set the length of this 3D Vector + + @param fLen + The to be achieved length of the 3D Vector + */ + B3DVector& setLength(double fLen) + { + double fLenNow(scalar(*this)); + + if(!::basegfx::fTools::equalZero(fLenNow)) + { + const double fOne(1.0); + + if(!::basegfx::fTools::equal(fOne, fLenNow)) + { + fLen /= sqrt(fLenNow); + } + + mnX *= fLen; + mnY *= fLen; + mnZ *= fLen; + } + + return *this; + } + + /** Normalize this 3D Vector + + The length of the 3D Vector is set to 1.0 + */ + B3DVector& normalize(); + + /** get a 3D Vector which is perpendicular to this and a given 3D Vector + + @attention This only works if this and the given 3D Vector are + both normalized. + + @param rNormalizedVec + A normalized 3D Vector. + + @return + A 3D Vector perpendicular to this and the given one + */ + B3DVector getPerpendicular(const B3DVector& rNormalizedVec) const; + + /** Calculate the Scalar product + + This method calculates the Scalar product between this + and the given 3D Vector. + + @param rVec + A second 3D Vector. + + @return + The Scalar Product of two 3D Vectors + */ + double scalar(const B3DVector& rVec) const + { + return ((mnX * rVec.mnX) + (mnY * rVec.mnY) + (mnZ * rVec.mnZ)); + } + + /** Transform vector by given transformation matrix. + + Since this is a vector, translational components of the + matrix are disregarded. + */ + B3DVector& operator*=( const B3DHomMatrix& rMat ); + + static const B3DVector& getEmptyVector() + { + return static_cast( ::basegfx::B3DTuple::getEmptyTuple() ); + } + }; + + // external operators + + + /** Test two vectors which need not to be normalized for parallelism + + @param rVecA + The first 3D Vector + + @param rVecB + The second 3D Vector + + @return + bool if the two values are parallel. Also true if + one of the vectors is empty. + */ + BASEGFX_DLLPUBLIC bool areParallel( const B3DVector& rVecA, const B3DVector& rVecB ); + + /** Transform vector by given transformation matrix. + + Since this is a vector, translational components of the + matrix are disregarded. + */ + BASEGFX_DLLPUBLIC B3DVector operator*( const B3DHomMatrix& rMat, const B3DVector& rVec ); + + /** Calculate the Cross Product of two 3D Vectors + + @param rVecA + A first 3D Vector. + + @param rVecB + A second 3D Vector. + + @return + The Cross Product of both 3D Vectors + */ + inline B3DVector cross(const B3DVector& rVecA, const B3DVector& rVecB) + { + B3DVector aVec( + rVecA.getY() * rVecB.getZ() - rVecA.getZ() * rVecB.getY(), + rVecA.getZ() * rVecB.getX() - rVecA.getX() * rVecB.getZ(), + rVecA.getX() * rVecB.getY() - rVecA.getY() * rVecB.getX()); + return aVec; + } +} // end of namespace basegfx + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ -- cgit v1.2.3