diff options
Diffstat (limited to 'include/basegfx')
67 files changed, 10372 insertions, 0 deletions
diff --git a/include/basegfx/DrawCommands.hxx b/include/basegfx/DrawCommands.hxx new file mode 100644 index 000000000..e9e3b935b --- /dev/null +++ b/include/basegfx/DrawCommands.hxx @@ -0,0 +1,157 @@ +/* -*- 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 <memory> +#include <vector> + +#include <basegfx/color/bcolor.hxx> +#include <basegfx/polygon/b2dpolypolygon.hxx> +#include <basegfx/range/b2drange.hxx> +#include <basegfx/matrix/b2dhommatrix.hxx> + +namespace gfx +{ +class DrawBase; + +class DrawCommand +{ +public: + std::vector<std::shared_ptr<DrawBase>> maChildren; +}; + +enum class DrawCommandType +{ + Root, + Rectangle, + Path +}; + +enum class GradientType +{ + Linear +}; + +class GradientStop +{ +public: + float mfOffset; + basegfx::BColor maColor; + float mfOpacity; +}; + +class GradientInfo +{ +public: + GradientType meType; + + std::vector<GradientStop> 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<basegfx::BColor> mpFillColor; + std::shared_ptr<basegfx::BColor> mpStrokeColor; + std::shared_ptr<GradientInfo> 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<basegfx::BColor> mpFillColor; + std::shared_ptr<basegfx::BColor> mpStrokeColor; + std::shared_ptr<GradientInfo> mpFillGradient; + + DrawPath(basegfx::B2DPolyPolygon const& rPolyPolygon) + : DrawBase(DrawCommandType::Path) + , maPolyPolygon(rPolyPolygon) + , 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 000000000..2aadbc3a4 --- /dev/null +++ b/include/basegfx/basegfxdllapi.h @@ -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 . + */ + +#ifndef INCLUDED_BASEGFX_BASEGFXDLLAPI_H +#define INCLUDED_BASEGFX_BASEGFXDLLAPI_H + +#include <sal/types.h> + +#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 000000000..414a815b3 --- /dev/null +++ b/include/basegfx/color/bcolor.hxx @@ -0,0 +1,186 @@ +/* -*- 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 <sal/config.h> + +#include <algorithm> +#include <ostream> + +#include <basegfx/tuple/b3dtuple.hxx> +#include <basegfx/basegfxdllapi.h> + +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() + : B3DTuple() + {} + + /** 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 mfX; } + double getGreen() const { return mfY; } + double getBlue() const { return mfZ; } + + // data access write + void setRed(double fNew) { mfX = fNew; } + void setGreen(double fNew) { mfY = fNew; } + void setBlue(double fNew) { mfZ = fNew; } + + /** *=operator to allow usage from BColor, too + */ + BColor& operator*=( const BColor& rPnt ) + { + mfX *= rPnt.mfX; + mfY *= rPnt.mfY; + mfZ *= rPnt.mfZ; + return *this; + } + + /** *=operator to allow usage from BColor, too + */ + BColor& operator*=(double t) + { + mfX *= t; + mfY *= t; + mfZ *= t; + return *this; + } + + /** assignment operator to allow assigning the results + of B3DTuple calculations + */ + BColor& operator=( const ::basegfx::B3DTuple& rVec ) + { + mfX = rVec.getX(); + mfY = rVec.getY(); + mfZ = 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 (mfX * fRedWeight + mfY * fGreenWeight + mfZ * 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 sqrt(fDistR * fDistR + fDistG * fDistG + fDistB * 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() + { + mfX = std::clamp(mfX, 0.0, 1.0); + mfY = std::clamp(mfY, 0.0, 1.0); + mfZ = std::clamp(mfZ, 0.0, 1.0); + return *this; + } + + void invert() + { + mfX = 1.0 - mfX; + mfY = 1.0 - mfY; + mfZ = 1.0 - mfZ; + } + + static const BColor& getEmptyBColor() + { + return static_cast<const BColor&>( ::basegfx::B3DTuple::getEmptyTuple() ); + } + + }; + + template<typename charT, typename traits> + std::basic_ostream<charT, traits> & operator <<( + std::basic_ostream<charT, traits> & 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 000000000..5e6fe8ebf --- /dev/null +++ b/include/basegfx/color/bcolormodifier.hxx @@ -0,0 +1,342 @@ +/* -*- 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 <config_options.h> +#include <basegfx/basegfxdllapi.h> +#include <basegfx/color/bcolor.hxx> + +#include <osl/diagnose.h> + +#include <memory> +#include <vector> + +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; + }; + + /** convert color to gray + */ + class SAL_WARN_UNUSED UNLESS_MERGELIBS(BASEGFX_DLLPUBLIC) BColorModifier_gray final : public BColorModifier + { + public: + BColorModifier_gray() + : BColorModifier() + { + } + + virtual ~BColorModifier_gray() override; + + // compare operator + virtual bool operator==(const BColorModifier& rCompare) const override; + + // compute modified color + virtual ::basegfx::BColor getModifiedColor(const ::basegfx::BColor& aSourceColor) const override; + }; + + /** invert color + + returns a color where red green and blue are inverted using 1.0 - n + */ + class SAL_WARN_UNUSED UNLESS_MERGELIBS(BASEGFX_DLLPUBLIC) BColorModifier_invert final : public BColorModifier + { + public: + BColorModifier_invert() + : BColorModifier() + { + } + + virtual ~BColorModifier_invert() override; + + // compare operator + virtual bool operator==(const BColorModifier& rCompare) const override; + + // compute modified color + virtual ::basegfx::BColor getModifiedColor(const ::basegfx::BColor& aSourceColor) 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() + : BColorModifier() + { + } + + virtual ~BColorModifier_luminance_to_alpha() override; + + // compare operator + virtual bool operator==(const BColorModifier& rCompare) const override; + + // compute modified color + virtual ::basegfx::BColor getModifiedColor(const ::basegfx::BColor& aSourceColor) 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 UNLESS_MERGELIBS(BASEGFX_DLLPUBLIC) BColorModifier_replace final : public BColorModifier + { + private: + ::basegfx::BColor maBColor; + + public: + BColorModifier_replace(const ::basegfx::BColor& rBColor) + : BColorModifier(), + maBColor(rBColor) + { + } + + virtual ~BColorModifier_replace() override; + + // data access + const ::basegfx::BColor& getBColor() const { return maBColor; } + + // compare operator + virtual bool operator==(const BColorModifier& rCompare) const override; + + // compute modified color + virtual ::basegfx::BColor getModifiedColor(const ::basegfx::BColor& aSourceColor) 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) + : BColorModifier(), + maBColor(rBColor), + mfValue(fValue) + { + } + + virtual ~BColorModifier_interpolate() override; + + // compare operator + virtual bool operator==(const BColorModifier& rCompare) const override; + + // compute modified color + virtual ::basegfx::BColor getModifiedColor(const ::basegfx::BColor& aSourceColor) 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 UNLESS_MERGELIBS(BASEGFX_DLLPUBLIC) BColorModifier_black_and_white final : public BColorModifier + { + private: + double mfValue; + + public: + BColorModifier_black_and_white(double fValue) + : BColorModifier(), + mfValue(fValue) + { + } + + virtual ~BColorModifier_black_and_white() override; + + // compare operator + virtual bool operator==(const BColorModifier& rCompare) const override; + + // compute modified color + virtual ::basegfx::BColor getModifiedColor(const ::basegfx::BColor& aSourceColor) 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 + virtual bool operator==(const BColorModifier& rCompare) const override; + + // compute modified color + virtual ::basegfx::BColor getModifiedColor(const ::basegfx::BColor& aSourceColor) 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 + virtual bool operator==(const BColorModifier& rCompare) const override; + + // compute modified color + virtual ::basegfx::BColor getModifiedColor(const ::basegfx::BColor& aSourceColor) 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 UNLESS_MERGELIBS(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 000000000..5c16802cf --- /dev/null +++ b/include/basegfx/color/bcolortools.hxx @@ -0,0 +1,41 @@ +/* -*- 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 <basegfx/basegfxdllapi.h> + +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 000000000..b9c91fac0 --- /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 <sal/types.h> +#include <vector> +#include <basegfx/basegfxdllapi.h> + + +// 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 000000000..019973147 --- /dev/null +++ b/include/basegfx/curve/b2dcubicbezier.hxx @@ -0,0 +1,199 @@ +/* -*- 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 <basegfx/point/b2dpoint.hxx> +#include <basegfx/range/b2drange.hxx> +#include <basegfx/basegfxdllapi.h> + +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); + ~B2DCubicBezier(); + + // 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 + double getEdgeLength() const; + + // get length of control polygon + 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 + */ + 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 + */ + 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. + */ + void adaptiveSubdivideByDistance(B2DPolygon& rTarget, double fDistanceBound) 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. + 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 + 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 + */ + 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. + */ + void getAllExtremumPositions(::std::vector< double >& rResults) const; + + /// apply transformation given in matrix form + void transform(const basegfx::B2DHomMatrix& rMatrix); + + /// fround content + 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 000000000..60b32fb09 --- /dev/null +++ b/include/basegfx/matrix/b2dhommatrix.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 <sal/config.h> + +#include <ostream> + +#include <sal/types.h> +#include <o3tl/cow_wrapper.hxx> +#include <basegfx/basegfxdllapi.h> + +namespace basegfx +{ + class B2DTuple; + class Impl2DHomMatrix; + + class SAL_WARN_UNUSED BASEGFX_DLLPUBLIC B2DHomMatrix + { + public: + typedef o3tl::cow_wrapper< Impl2DHomMatrix > ImplType; + + private: + ImplType mpImpl; + + public: + B2DHomMatrix(); + B2DHomMatrix(const B2DHomMatrix& rMat); + B2DHomMatrix(B2DHomMatrix&& rMat); + ~B2DHomMatrix(); + + /** 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() { return get(0,0); } + // Convenience accessor for value at 1,0 position in the matrix + double b() { return get(1,0); } + // Convenience accessor for value at 0,1 position in the matrix + double c() { return get(0,1); } + // Convenience accessor for value at 1,1 position in the matrix + double d() { return get(1,1); } + // Convenience accessor for value at 0,2 position in the matrix + double e() { return get(0,2); } + // Convenience accessor for value at 1,2 position in the matrix + double f() { return get(1,2); } + + /** 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) + */ + B2DHomMatrix(double f_0x0, double f_0x1, double f_0x2, double f_1x0, double f_1x1, double f_1x2); + + double get(sal_uInt16 nRow, sal_uInt16 nColumn) const; + void set(sal_uInt16 nRow, sal_uInt16 nColumn, double 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); + + // test if last line is default to see if last line needs to be + // involved in calculations + bool isLastLineDefault() const; + + // 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); + + B2DHomMatrix& operator+=(const B2DHomMatrix& rMat); + B2DHomMatrix& operator-=(const B2DHomMatrix& rMat); + + bool operator==(const B2DHomMatrix& rMat) const; + bool operator!=(const B2DHomMatrix& rMat) const; + + B2DHomMatrix& operator*=(double fValue); + B2DHomMatrix& operator/=(double fValue); + + // matrix multiplication from the left to the local + B2DHomMatrix& operator*=(const B2DHomMatrix& rMat); + + // assignment operator + B2DHomMatrix& operator=(const B2DHomMatrix& rMat); + B2DHomMatrix& operator=(B2DHomMatrix&& rMat); + + // Help routine to decompose given homogen 3x3 matrix to components. A correction of + // the components is done to avoid inaccuracies. + bool decompose(B2DTuple& rScale, B2DTuple& rTranslate, double& rRotate, double& rShearX) const; + }; + + inline B2DHomMatrix operator*(const B2DHomMatrix& rMatA, const B2DHomMatrix& rMatB) + { + B2DHomMatrix aMul(rMatB); + aMul *= rMatA; + return aMul; + } + + template<typename charT, typename traits> + std::basic_ostream<charT, traits> & operator <<( + std::basic_ostream<charT, traits> & 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) << "; " + << matrix.get(2, 0) << ' ' << matrix.get(2, 1) << ' ' + << matrix.get(2, 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 000000000..b7159aef6 --- /dev/null +++ b/include/basegfx/matrix/b2dhommatrixtools.hxx @@ -0,0 +1,221 @@ +/* -*- 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 <sal/types.h> +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <basegfx/vector/b2dvector.hxx> +#include <basegfx/point/b2dpoint.hxx> +#include <basegfx/tuple/b2dtuple.hxx> +#include <basegfx/basegfxdllapi.h> + +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) + */ + BASEGFX_DLLPUBLIC 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) + BASEGFX_DLLPUBLIC 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()) + : maScale(), + maTranslate(), + 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(const B2DHomMatrix& rB2DHomMatrix = B2DHomMatrix()) + : maB2DHomMatrix(rB2DHomMatrix), + maScale(), + maTranslate(), + 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 000000000..29603f88e --- /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 <sal/types.h> +#include <basegfx/point/b3dpoint.hxx> +#include <basegfx/vector/b3dvector.hxx> +#include <o3tl/cow_wrapper.hxx> +#include <basegfx/basegfxdllapi.h> + +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 000000000..6b65d2460 --- /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 <basegfx/basegfxdllapi.h> +#include <basegfx/matrix/b3dhommatrix.hxx> + +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/numeric/ftools.hxx b/include/basegfx/numeric/ftools.hxx new file mode 100644 index 000000000..78f4eb1e7 --- /dev/null +++ b/include/basegfx/numeric/ftools.hxx @@ -0,0 +1,235 @@ +/* -*- 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 <rtl/math.h> +#include <cmath> +#include <math.h> +#include <basegfx/basegfxdllapi.h> +#include <limits> +#include <algorithm> + +// standard PI defines from solar.h, but we do not want to link against tools + +#ifndef F_PI +#define F_PI M_PI +#endif +#ifndef F_PI2 +#define F_PI2 M_PI_2 +#endif +#ifndef F_PI4 +#define F_PI4 M_PI_4 +#endif +#ifndef F_PI180 +#define F_PI180 (M_PI/180.0) +#endif +#ifndef F_PI1800 +#define F_PI1800 (M_PI/1800.0) +#endif +#ifndef F_PI18000 +#define F_PI18000 (M_PI/18000.0) +#endif +#ifndef F_2PI +#define F_2PI (2.0*M_PI) +#endif + + +// fTools defines + +namespace basegfx +{ + /** Round double to nearest integer + + @return the nearest integer + */ + inline sal_Int32 fround( double fVal ) + { + if (fVal >= std::numeric_limits<sal_Int32>::max() - .5) + return std::numeric_limits<sal_Int32>::max(); + else if (fVal <= std::numeric_limits<sal_Int32>::min() + .5) + return std::numeric_limits<sal_Int32>::min(); + return fVal > 0.0 ? static_cast<sal_Int32>( fVal + .5 ) : static_cast<sal_Int32>( 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<sal_Int64>( fVal + .5 ) : -static_cast<sal_Int64>( -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 ) + { + // old version used ::std::min/max, but this collides if min is defined as preprocessor + // macro which is the case e.g with windows.h headers. The simplest way to avoid this is to + // just use the full comparison. I keep the original here, maybe there will be a better + // solution some day. + + //return fVal < 0.0 ? + // (::std::min(fVal,-0.00001)) : + // (::std::max(fVal,0.00001)); + + if(fVal < 0.0) + return std::min(fVal, -0.00001); + else + return std::max(fVal, 0.00001); + } + + /** Convert value from degrees to radians + */ + constexpr double deg2rad( double v ) + { + // divide first, to get exact values for v being a multiple of + // 90 degrees + return v / 90.0 * M_PI_2; + } + + /** Convert value radians to degrees + */ + 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; + } + + /** 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 + */ + 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); + + class BASEGFX_DLLPUBLIC fTools + { + public: + /// Get threshold value for equalZero and friends + static double getSmallValue() { return 0.000000001f; } + + /// Compare against small value + static bool equalZero(const double& rfVal) + { + return (fabs(rfVal) <= getSmallValue()); + } + + /// Compare against given small value + static bool equalZero(const double& rfVal, const double& rfSmallValue) + { + return (fabs(rfVal) <= rfSmallValue); + } + + static bool equal(const double& rfValA, const double& rfValB) + { + // changed to approxEqual usage for better numerical correctness + return rtl_math_approxEqual(rfValA, rfValB); + } + + static bool equal(const double& rfValA, const double& rfValB, const double& rfSmallValue) + { + return (fabs(rfValA - rfValB) <= rfSmallValue); + } + + static bool less(const double& rfValA, const double& rfValB) + { + return (rfValA < rfValB && !equal(rfValA, rfValB)); + } + + static bool lessOrEqual(const double& rfValA, const double& rfValB) + { + return (rfValA < rfValB || equal(rfValA, rfValB)); + } + + static bool more(const double& rfValA, const double& rfValB) + { + return (rfValA > rfValB && !equal(rfValA, rfValB)); + } + + static bool moreOrEqual(const double& rfValA, const double& rfValB) + { + return (rfValA > rfValB || equal(rfValA, rfValB)); + } + + static bool betweenOrEqualEither(const double& rfValA, const double& rfValB, const double& 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 000000000..ee42f29c6 --- /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 <sal/types.h> +#include <basegfx/color/bcolor.hxx> + +namespace basegfx +{ + class BPixel final + { + union + { + struct + { + unsigned mnR : 8; // red intensity + unsigned mnG : 8; // green intensity + unsigned mnB : 8; // blue intensity + unsigned mnO : 8; // opacity, 0 == full transparence + } maRGBO; + + struct + { + unsigned mnValue : 32; // all values + } maCombinedRGBO; + } maPixelUnion; + + public: + BPixel() + { + maPixelUnion.maCombinedRGBO.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 nOpacity) + { + maPixelUnion.maRGBO.mnR = nRed; + maPixelUnion.maRGBO.mnG = nGreen; + maPixelUnion.maRGBO.mnB = nBlue; + maPixelUnion.maRGBO.mnO = nOpacity; + } + + // 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 nOpacity) + { + maPixelUnion.maRGBO.mnR = sal_uInt8((rColor.getRed() * 255.0) + 0.5); + maPixelUnion.maRGBO.mnG = sal_uInt8((rColor.getGreen() * 255.0) + 0.5); + maPixelUnion.maRGBO.mnB = sal_uInt8((rColor.getBlue() * 255.0) + 0.5); + maPixelUnion.maRGBO.mnO = nOpacity; + } + + // data access read + sal_uInt8 getRed() const { return maPixelUnion.maRGBO.mnR; } + sal_uInt8 getGreen() const { return maPixelUnion.maRGBO.mnG; } + sal_uInt8 getBlue() const { return maPixelUnion.maRGBO.mnB; } + sal_uInt8 getOpacity() const { return maPixelUnion.maRGBO.mnO; } + + // data access write + void setRed(sal_uInt8 nNew) { maPixelUnion.maRGBO.mnR = nNew; } + void setGreen(sal_uInt8 nNew) { maPixelUnion.maRGBO.mnG = nNew; } + void setBlue(sal_uInt8 nNew) { maPixelUnion.maRGBO.mnB = nNew; } + void setOpacity(sal_uInt8 nNew) { maPixelUnion.maRGBO.mnO = nNew; } + + // comparators + bool operator==( const BPixel& rPixel ) const + { + return (rPixel.maPixelUnion.maCombinedRGBO.mnValue == maPixelUnion.maCombinedRGBO.mnValue); + } + + bool operator!=( const BPixel& rPixel ) const + { + return (rPixel.maPixelUnion.maCombinedRGBO.mnValue != maPixelUnion.maCombinedRGBO.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 000000000..413aa00e4 --- /dev/null +++ b/include/basegfx/point/b2dpoint.hxx @@ -0,0 +1,135 @@ +/* -*- 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 <ostream> + +#include <basegfx/tuple/b2dtuple.hxx> +#include <basegfx/point/b2ipoint.hxx> +#include <basegfx/basegfxdllapi.h> + +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() + : B2DTuple() + {} + + /** 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(const ::basegfx::B2DTuple& rTuple) + : B2DTuple(rTuple) + {} + + /** *=operator to allow usage from B2DPoint, too + */ + B2DPoint& operator*=( const B2DPoint& rPnt ) + { + mfX *= rPnt.mfX; + mfY *= rPnt.mfY; + return *this; + } + + /** *=operator to allow usage from B2DPoint, too + */ + B2DPoint& operator*=(double t) + { + mfX *= t; + mfY *= t; + return *this; + } + + /** assignment operator to allow assigning the results + of B2DTuple calculations + */ + BASEGFX_DLLPUBLIC B2DPoint& operator=( const ::basegfx::B2DTuple& rPoint ); + + /** 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<const B2DPoint&>( ::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<charT, traits> & operator <<( + std::basic_ostream<charT, traits> & 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 000000000..171fcbc9c --- /dev/null +++ b/include/basegfx/point/b2ipoint.hxx @@ -0,0 +1,101 @@ +/* -*- 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 <basegfx/tuple/b2ituple.hxx> +#include <basegfx/basegfxdllapi.h> + +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() + : B2ITuple() + {} + + /** 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 000000000..2cb8acf9b --- /dev/null +++ b/include/basegfx/point/b3dpoint.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 <basegfx/tuple/b3dtuple.hxx> +#include <basegfx/basegfxdllapi.h> + +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() + : B3DTuple() + {} + + /** 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 ) + { + mfX *= rPnt.mfX; + mfY *= rPnt.mfY; + mfZ *= rPnt.mfZ; + return *this; + } + + /** *=operator to allow usage from B3DPoint, too + */ + B3DPoint& operator*=(double t) + { + mfX *= t; + mfY *= t; + mfZ *= t; + return *this; + } + + /** assignment operator to allow assigning the results + of B3DTuple calculations + */ + B3DPoint& operator=( const ::basegfx::B3DTuple& rVec ) + { + mfX = rVec.getX(); + mfY = rVec.getY(); + mfZ = 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 000000000..b839c7519 --- /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 <basegfx/basegfxdllapi.h> +#include <basegfx/polygon/b2dpolygon.hxx> +#include <basegfx/range/b2drectangle.hxx> + +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 000000000..0e9f5241b --- /dev/null +++ b/include/basegfx/polygon/b2dlinegeometry.hxx @@ -0,0 +1,147 @@ +/* -*- 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 <basegfx/numeric/ftools.hxx> +#include <basegfx/polygon/b2dpolypolygon.hxx> +#include <basegfx/polygon/b2dpolygon.hxx> +#include <com/sun/star/drawing/LineCap.hpp> +#include <basegfx/basegfxdllapi.h> +#include <basegfx/polygon/b2dpolygontriangulator.hxx> + +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 + [F_PI2 .. 0.01 * F_PI2]. + + @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 [F_PI .. 0.01 * F_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), + basegfx::triangulator::B2DTriangleVector* pTriangles = nullptr); + +} // 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 000000000..997a669bc --- /dev/null +++ b/include/basegfx/polygon/b2dpolygon.hxx @@ -0,0 +1,278 @@ +/* -*- 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 <ostream> +#include <vector> + +#include <sal/types.h> +#include <o3tl/cow_wrapper.hxx> +#include <basegfx/vector/b2enums.hxx> +#include <basegfx/basegfxdllapi.h> + +class ImplB2DPolygon; + +namespace basegfx +{ + class B2DPoint; + class B2DRange; + class B2DHomMatrix; + class B2DCubicBezier; + class SystemDependentData; + class SystemDependentDataManager; + typedef std::shared_ptr<SystemDependentData> 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<basegfx::B2DPoint> 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; + 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 possibel 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<class T> + std::shared_ptr<T> getSystemDependentData() const + { + return std::static_pointer_cast<T>(getSystemDependantDataInternal(typeid(T).hash_code())); + } + + template<class T, class... Args> + std::shared_ptr<T> addOrReplaceSystemDependentData(SystemDependentDataManager& manager, Args&&... args) const + { + std::shared_ptr<T> r = std::make_shared<T>(manager, std::forward<Args>(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 B2DPolygons + typedef ::std::vector< B2DPolygon > B2DPolygonVector; + + template< typename charT, typename traits > + inline std::basic_ostream<charT, traits> & operator <<( + std::basic_ostream<charT, traits> & 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 000000000..b080fdcb5 --- /dev/null +++ b/include/basegfx/polygon/b2dpolygonclipper.hxx @@ -0,0 +1,64 @@ +/* -*- 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 <basegfx/polygon/b2dpolypolygon.hxx> +#include <basegfx/polygon/b2dpolygon.hxx> +#include <basegfx/basegfxdllapi.h> + +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). + BASEGFX_DLLPUBLIC 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); + 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 000000000..24f8e1a9f --- /dev/null +++ b/include/basegfx/polygon/b2dpolygoncutandtouch.hxx @@ -0,0 +1,48 @@ +/* -*- 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 <basegfx/polygon/b2dpolygon.hxx> +#include <basegfx/polygon/b2dpolypolygon.hxx> +#include <basegfx/basegfxdllapi.h> + +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 +BASEGFX_DLLPUBLIC B2DPolygon addPointsAtCutsAndTouches(const B2DPolygon& rCandidate); + +// 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. +BASEGFX_DLLPUBLIC B2DPolyPolygon addPointsAtCutsAndTouches(const B2DPolyPolygon& rCandidate); + +// 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. +BASEGFX_DLLPUBLIC 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. +BASEGFX_DLLPUBLIC 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 000000000..40a4027a5 --- /dev/null +++ b/include/basegfx/polygon/b2dpolygontools.hxx @@ -0,0 +1,529 @@ +/* -*- 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 <vector> +#include <functional> + +#include <basegfx/point/b2dpoint.hxx> +#include <basegfx/vector/b2dvector.hxx> +#include <basegfx/range/b2drectangle.hxx> +#include <basegfx/polygon/b3dpolygon.hxx> +#include <basegfx/polygon/b2dpolygontriangulator.hxx> +#include <com/sun/star/drawing/PointSequence.hpp> +#include <com/sun/star/drawing/FlagSequence.hpp> +#include <basegfx/basegfxdllapi.h> +#include <o3tl/typed_flags_set.hxx> + + +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<CutFlagValue> : is_typed_flags<CutFlagValue, 0x1f> {}; +} + +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); + + // 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); + + // 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<double>& rDotDashArray, + std::function<void(const basegfx::B2DPolygon& rSnippet)> aLineTargetCallback, + std::function<void(const basegfx::B2DPolygon& rSnippet)> aGapTargetCallback = std::function<void(const basegfx::B2DPolygon&)>(), + double fDotDashLength = 0.0); + BASEGFX_DLLPUBLIC void applyLineDashing( + const B2DPolygon& rCandidate, + const ::std::vector<double>& 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 .. F_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 + BASEGFX_DLLPUBLIC 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. + BASEGFX_DLLPUBLIC 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 + */ + BASEGFX_DLLPUBLIC 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, + const OUString& 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 ); + +} // 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 000000000..1fb2c9d54 --- /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 <basegfx/polygon/b2dpolygon.hxx> +#include <basegfx/point/b2dpoint.hxx> +#include <basegfx/basegfxdllapi.h> + +#include <vector> + +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 000000000..010815c87 --- /dev/null +++ b/include/basegfx/polygon/b2dpolypolygon.hxx @@ -0,0 +1,177 @@ +/* -*- 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 <ostream> +#include <vector> + +#include <sal/types.h> +#include <o3tl/cow_wrapper.hxx> +#include <basegfx/range/b2drange.hxx> +#include <basegfx/basegfxdllapi.h> +#include <basegfx/polygon/b2dpolygon.hxx> + +class ImplB2DPolyPolygon; + +namespace basegfx +{ + class B2DHomMatrix; +} + +namespace basegfx +{ + class BASEGFX_DLLPUBLIC B2DPolyPolygon + { + public: + typedef o3tl::cow_wrapper< ImplB2DPolyPolygon > ImplType; + + private: + ImplType 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); + + /** 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<class T> + std::shared_ptr<T> getSystemDependentData() const + { + return std::static_pointer_cast<T>(getSystemDependantDataInternal(typeid(T).hash_code())); + } + + template<class T, class... Args> + std::shared_ptr<T> addOrReplaceSystemDependentData(SystemDependentDataManager& manager, Args&&... args) const + { + std::shared_ptr<T> r = std::make_shared<T>(manager, std::forward<Args>(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<charT, traits> & operator <<( + std::basic_ostream<charT, traits> & 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 000000000..a5f4ba662 --- /dev/null +++ b/include/basegfx/polygon/b2dpolypolygoncutter.hxx @@ -0,0 +1,143 @@ +/* -*- 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 <basegfx/polygon/b2dpolypolygon.hxx> +#include <basegfx/basegfxdllapi.h> + + +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); + + /** 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 000000000..9a83ab454 --- /dev/null +++ b/include/basegfx/polygon/b2dpolypolygontools.hxx @@ -0,0 +1,298 @@ +/* -*- 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 <basegfx/point/b2dpoint.hxx> +#include <basegfx/polygon/b3dpolypolygon.hxx> +#include <com/sun/star/drawing/PointSequenceSequence.hpp> +#include <vector> +#include <set> +#include <basegfx/basegfxdllapi.h> + + +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); + + // 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<double>& 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 std::set< 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, + const OUString& 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 "<path ...>" 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 000000000..abe0c5c4e --- /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 <config_options.h> +#include <basegfx/polygon/b2dpolygon.hxx> +#include <vector> +#include <basegfx/basegfxdllapi.h> + + +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 + BASEGFX_DLLPUBLIC 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. + BASEGFX_DLLPUBLIC 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 000000000..ea9ea2fde --- /dev/null +++ b/include/basegfx/polygon/b3dpolygon.hxx @@ -0,0 +1,121 @@ +/* -*- 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 <sal/types.h> +#include <o3tl/cow_wrapper.hxx> +#include <basegfx/basegfxdllapi.h> + +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; + 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 000000000..67ff859b6 --- /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 <vector> +#include <functional> + +#include <basegfx/point/b3dpoint.hxx> +#include <basegfx/vector/b3dvector.hxx> +#include <basegfx/basegfxdllapi.h> + +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 + */ + BASEGFX_DLLPUBLIC void applyLineDashing( + const B3DPolygon& rCandidate, + const std::vector<double>& rDotDashArray, + std::function<void(const basegfx::B3DPolygon& rSnippet)> aLineTargetCallback, + double fDotDashLength = 0.0); + BASEGFX_DLLPUBLIC void applyLineDashing( + const B3DPolygon& rCandidate, + const ::std::vector<double>& 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 + */ + BASEGFX_DLLPUBLIC 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. + */ + BASEGFX_DLLPUBLIC 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. + */ + BASEGFX_DLLPUBLIC 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 000000000..14a062c08 --- /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 <sal/types.h> +#include <o3tl/cow_wrapper.hxx> +#include <basegfx/basegfxdllapi.h> + +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 000000000..cd51ac9e6 --- /dev/null +++ b/include/basegfx/polygon/b3dpolypolygontools.hxx @@ -0,0 +1,133 @@ +/* -*- 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 <basegfx/numeric/ftools.hxx> +#include <basegfx/point/b3dpoint.hxx> +#include <basegfx/basegfxdllapi.h> + +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. + */ + BASEGFX_DLLPUBLIC B3DPolyPolygon const & createUnitCubePolyPolygon(); + + /** Create a unit 3D fill polyPolygon which defines a cube. + */ + BASEGFX_DLLPUBLIC 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. + */ + BASEGFX_DLLPUBLIC B3DPolyPolygon createUnitSpherePolyPolygon( + sal_uInt32 nHorSeg, sal_uInt32 nVerSeg, + double fVerStart = F_PI2, double fVerStop = -F_PI2, + double fHorStart = 0.0, double fHorStop = F_2PI); + + /** 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 = F_PI2, double fVerStop = -F_PI2, + double fHorStart = 0.0, double fHorStop = F_2PI); + + /** 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 = F_PI2, double fVerStop = -F_PI2, + double fHorStart = 0.0, double fHorStop = F_2PI); + + /** 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 = F_PI2, double fVerStop = -F_PI2, + double fHorStart = 0.0, double fHorStop = F_2PI); + + /** 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/b1drange.hxx b/include/basegfx/range/b1drange.hxx new file mode 100644 index 000000000..0db585558 --- /dev/null +++ b/include/basegfx/range/b1drange.hxx @@ -0,0 +1,151 @@ +/* -*- 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 <basegfx/range/basicrange.hxx> + + +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); + } + }; + +} // 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 000000000..0d7a81481 --- /dev/null +++ b/include/basegfx/range/b2dconnectedranges.hxx @@ -0,0 +1,240 @@ +/* -*- 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 <osl/diagnose.h> +#include <basegfx/range/b2drange.hxx> +#include <list> +#include <utility> +#include <algorithm> + + +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: + <code> + ------------------- + | -------| + | | || + | --- | || + | | | -------| -------- + | | +--------- | | | + | --+ | | | | + | | | | -------- + | ---------- | + ------------------- + </code + + Here, the outer rectangles represent the output + ranges. Contained are the input rectangles that comprise these + output ranges. + + @tpl UserData + User data to be stored along with the range, to later identify + which range went into which connected component. Must be + assignable, default- and copy-constructible. + */ + template< typename UserData > 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(), + maTotalBounds() + { + } + + /** 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 000000000..9a366956c --- /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 <o3tl/cow_wrapper.hxx> +#include <tuple> +#include <basegfx/vector/b2enums.hxx> +#include <basegfx/basegfxdllapi.h> + +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<B2DRange, B2VectorOrientation> 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 000000000..f6aa7f311 --- /dev/null +++ b/include/basegfx/range/b2drange.hxx @@ -0,0 +1,348 @@ +/* -*- 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 <ostream> +#include <vector> + +#include <basegfx/vector/b2dvector.hxx> +#include <basegfx/point/b2dpoint.hxx> +#include <basegfx/tuple/b2dtuple.hxx> +#include <basegfx/range/basicrange.hxx> +#include <basegfx/basegfxdllapi.h> + +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: + typedef double ValueType; + typedef DoubleTraits TraitsType; + + B2DRange() {} + + /// Create degenerate interval consisting of a single point + explicit B2DRange(const B2DTuple& rTuple) + : maRangeX(rTuple.getX()), + maRangeY(rTuple.getY()) + { + } + + /// Create proper interval between the two given double pairs + B2DRange(double x1, + double y1, + double x2, + double y2) + : maRangeX(x1), + maRangeY(y1) + { + maRangeX.expand(x2); + maRangeY.expand(y2); + } + + /// Create proper interval between the two given points + B2DRange(const B2DTuple& rTuple1, + const B2DTuple& rTuple2) + : maRangeX(rTuple1.getX()), + maRangeY(rTuple1.getY()) + { + expand( rTuple2 ); + } + + BASEGFX_DLLPUBLIC explicit B2DRange(const B2IRange& rRange); + + /** 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 B2DRange& rRange ) const + { + return (maRangeX == rRange.maRangeX + && maRangeY == rRange.maRangeY); + } + + bool operator!=( const B2DRange& rRange ) const + { + return (maRangeX != rRange.maRangeX + || maRangeY != rRange.maRangeY); + } + + bool equal(const B2DRange& rRange) const + { + return (maRangeX.equal(rRange.maRangeX) + && maRangeY.equal(rRange.maRangeY)); + } + + /// get lower bound of the set. returns arbitrary values for empty sets. + double getMinX() const + { + return maRangeX.getMinimum(); + } + + /// get lower bound of the set. returns arbitrary values for empty sets. + double getMinY() const + { + return maRangeY.getMinimum(); + } + + /// get upper bound of the set. returns arbitrary values for empty sets. + double getMaxX() const + { + return maRangeX.getMaximum(); + } + + /// get upper bound of the set. returns arbitrary values for empty sets. + double getMaxY() const + { + return maRangeY.getMaximum(); + } + + /// return difference between upper and lower X value. returns 0 for empty sets. + double getWidth() const + { + return maRangeX.getRange(); + } + + /// return difference between upper and lower Y value. returns 0 for empty sets. + double getHeight() const + { + return maRangeY.getRange(); + } + + /// 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() + ); + } + + /// 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 B2DTuple& rTuple) const + { + return ( + maRangeX.isInside(rTuple.getX()) + && maRangeY.isInside(rTuple.getY()) + ); + } + + /// yields true if rRange is inside, or equal to set + bool isInside(const B2DRange& rRange) const + { + return ( + maRangeX.isInside(rRange.maRangeX) + && maRangeY.isInside(rRange.maRangeY) + ); + } + + /// yields true if rRange at least partly inside set + bool overlaps(const B2DRange& 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 B2DRange& rRange) const + { + return ( + maRangeX.overlapsMore(rRange.maRangeX) + && maRangeY.overlapsMore(rRange.maRangeY) + ); + } + + /// add point to the set, expanding as necessary + void expand(const B2DTuple& rTuple) + { + maRangeX.expand(rTuple.getX()); + maRangeY.expand(rTuple.getY()); + } + + /// add rRange to the set, expanding as necessary + void expand(const B2DRange& rRange) + { + maRangeX.expand(rRange.maRangeX); + maRangeY.expand(rRange.maRangeY); + } + + /// calc set intersection + void intersect(const B2DRange& rRange) + { + maRangeX.intersect(rRange.maRangeX); + maRangeY.intersect(rRange.maRangeY); + } + + /// grow set by fValue on all sides + void grow(double fValue) + { + maRangeX.grow(fValue); + maRangeY.grow(fValue); + } + + /// clamp value on range + B2DTuple clamp(const B2DTuple& rTuple) const + { + return B2DTuple( + maRangeX.clamp(rTuple.getX()), + maRangeY.clamp(rTuple.getY())); + } + + /** 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) */ + static const B2DRange& getUnitB2DRange(); + + private: + typedef ::basegfx::BasicRange< ValueType, TraitsType > MyBasicRange; + + MyBasicRange maRangeX; + MyBasicRange maRangeY; + }; + + /** 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< B2DRange >& computeSetDifference( ::std::vector< B2DRange >& o_rResult, + const B2DRange& rFirst, + const B2DRange& rSecond ); + + template< typename charT, typename traits > + inline std::basic_ostream<charT, traits> & operator <<( + std::basic_ostream<charT, traits> & 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 000000000..63e8f05c2 --- /dev/null +++ b/include/basegfx/range/b2drangeclipper.hxx @@ -0,0 +1,42 @@ +/* -*- 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 <basegfx/range/b2dpolyrange.hxx> +#include <vector> +#include <basegfx/basegfxdllapi.h> + +namespace basegfx +{ + namespace 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<B2DRange>& rRanges, + const std::vector<B2VectorOrientation>& 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 000000000..9c1ad86c0 --- /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 <basegfx/range/b2drange.hxx> + +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 000000000..2be733b93 --- /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 <ostream> + +#include <basegfx/tuple/b2ituple.hxx> +#include <basegfx/range/basicbox.hxx> + +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<charT, traits> & operator <<( + std::basic_ostream<charT, traits> & 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 000000000..f24526880 --- /dev/null +++ b/include/basegfx/range/b2irange.hxx @@ -0,0 +1,259 @@ +/* -*- 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 <ostream> +#include <vector> + +#include <basegfx/point/b2ipoint.hxx> +#include <basegfx/tuple/b2ituple.hxx> +#include <basegfx/tuple/b2i64tuple.hxx> +#include <basegfx/range/basicrange.hxx> +#include <basegfx/basegfxdllapi.h> + +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: + typedef sal_Int32 ValueType; + typedef Int32Traits TraitsType; + + B2IRange() {} + + /// Create degenerate interval consisting of a single point + explicit B2IRange(const B2ITuple& rTuple) + : maRangeX(rTuple.getX()), + maRangeY(rTuple.getY()) + { + } + + /// Create proper interval between the two given integer pairs + B2IRange(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 + B2IRange(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 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 B2IRange& rRange ) const + { + return (maRangeX == rRange.maRangeX + && maRangeY == rRange.maRangeY); + } + + bool operator!=( const B2IRange& rRange ) const + { + return (maRangeX != rRange.maRangeX + || maRangeY != rRange.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(); + } + + /// 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() + ); + } + + /// yields true if given 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()); + } + + /// add rRange to the set, expanding as necessary + void expand(const B2IRange& rRange) + { + maRangeX.expand(rRange.maRangeX); + maRangeY.expand(rRange.maRangeY); + } + + /// calc set intersection + void intersect(const B2IRange& rRange) + { + maRangeX.intersect(rRange.maRangeX); + maRangeY.intersect(rRange.maRangeY); + } + + B2ITuple clamp(const B2ITuple& rTuple) const + { + return B2ITuple( + maRangeX.clamp(rTuple.getX()), + maRangeY.clamp(rTuple.getY())); + } + + private: + typedef ::basegfx::BasicRange< ValueType, TraitsType > MyBasicRange; + + MyBasicRange maRangeX; + MyBasicRange maRangeY; + }; + + /** 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< B2IRange >& computeSetDifference( ::std::vector< B2IRange >& o_rResult, + const B2IRange& rFirst, + const B2IRange& rSecond ); + + template< typename charT, typename traits > + inline std::basic_ostream<charT, traits> & operator <<( + std::basic_ostream<charT, traits> & stream, const B2IRange& range ) + { + if (range.isEmpty()) + return stream << "EMPTY"; + else + return stream << range.getWidth() << 'x' << range.getHeight() + << "@(" << range.getMinX() << "," << range.getMinY() << ")"; + } + +} // 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 000000000..2c6a932a2 --- /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 <basegfx/range/b2irange.hxx> + +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 000000000..338c4f54a --- /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 <basegfx/vector/b3dvector.hxx> +#include <basegfx/point/b3dpoint.hxx> +#include <basegfx/tuple/b3dtuple.hxx> +#include <basegfx/range/basicrange.hxx> +#include <basegfx/basegfxdllapi.h> + +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 000000000..123d2b1b3 --- /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 <basegfx/range/basicrange.hxx> + + +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 000000000..429f31957 --- /dev/null +++ b/include/basegfx/range/basicrange.hxx @@ -0,0 +1,306 @@ +/* -*- 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 <sal/types.h> +#include <float.h> +#include <basegfx/numeric/ftools.hxx> + + +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()) + { + 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; + } + } + + typename Traits::DifferenceType getRange() const + { + if(isEmpty()) + { + return Traits::neutral(); + } + else + { + return (mnMaximum - mnMinimum); + } + } + }; + + // some pre-fabricated traits + struct DoubleTraits + { + static double minVal() { return DBL_MIN; }; + static double maxVal() { return DBL_MAX; }; + static double neutral() { return 0.0; }; + + typedef double DifferenceType; + }; + + struct Int32Traits + { + static sal_Int32 minVal() { return SAL_MIN_INT32; }; + static sal_Int32 maxVal() { return SAL_MAX_INT32; }; + static 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 000000000..d1b166fb0 --- /dev/null +++ b/include/basegfx/raster/bzpixelraster.hxx @@ -0,0 +1,90 @@ +/* -*- 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 <basegfx/pixel/bpixel.hxx> +#include <sal/types.h> +#include <memory> +#include <string.h> + +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<BPixel[]> mpContent; + std::unique_ptr<sal_uInt16[]> 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 000000000..59a309c86 --- /dev/null +++ b/include/basegfx/raster/rasterconvert3d.hxx @@ -0,0 +1,426 @@ +/* -*- 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 <config_options.h> +#include <sal/types.h> +#include <vector> + +#include <osl/diagnose.h> + +#include <basegfx/color/bcolor.hxx> +#include <basegfx/vector/b3dvector.hxx> +#include <basegfx/point/b2dpoint.hxx> +#include <basegfx/basegfxdllapi.h> + +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() + : maX(), + maY() + {} + + 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() + : maX(), + maY(), + maZ() + {} + + 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<double>(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(); + } + }; + + void addArea(const B3DPolygon& rFill, const B3DHomMatrix* pViewToEye); + void addArea(const B3DPolyPolygon& rFill, const B3DHomMatrix* pViewToEye); + void addEdge(const B3DPolygon& rFill, sal_uInt32 a, sal_uInt32 b, const B3DHomMatrix* pViewToEye); + + void rasterconvertB3DArea(sal_Int32 nStartLine, sal_Int32 nStopLine); + 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/b2dtuple.hxx b/include/basegfx/tuple/b2dtuple.hxx new file mode 100644 index 000000000..0c7b7f463 --- /dev/null +++ b/include/basegfx/tuple/b2dtuple.hxx @@ -0,0 +1,291 @@ +/* -*- 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 <sal/types.h> +#include <basegfx/numeric/ftools.hxx> +#include <basegfx/basegfxdllapi.h> +#include <basegfx/utils/common.hxx> + +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 + { + protected: + double mfX; + double mfY; + + public: + + /** Create a 2D Tuple + + The tuple is initialized to (0.0, 0.0) + */ + B2DTuple() + : mfX(0.0), + mfY(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) + : mfX( fX ), + mfY( fY ) + {} + + /** Create a copy of a 2D integer Tuple + + @param rTup + The 2D Tuple which will be copied. + */ + BASEGFX_DLLPUBLIC explicit B2DTuple(const B2ITuple& rTup); + + /// Get X-Coordinate of 2D Tuple + double getX() const + { + return mfX; + } + + /// Get Y-Coordinate of 2D Tuple + double getY() const + { + return mfY; + } + + /// Set X-Coordinate of 2D Tuple + void setX(double fX) + { + mfX = fX; + } + + /// Set Y-Coordinate of 2D Tuple + void setY(double fY) + { + mfY = fY; + } + + double get(Axis2D eAxis) + { + return eAxis == Axis2D::X ? getX() : getY(); + } + + void set(Axis2D eAxis, double fValue) + { + if (eAxis == Axis2D::X) + setX(fValue); + else + setY(fValue); + } + + // comparators with tolerance + + bool equalZero() const + { + return (this == &getEmptyTuple() || + (fTools::equalZero(mfX) && fTools::equalZero(mfY))); + } + + bool equal(const B2DTuple& rTup) const + { + return ( + this == &rTup || + (fTools::equal(mfX, rTup.mfX) && + fTools::equal(mfY, rTup.mfY))); + } + + // operators + + + B2DTuple& operator+=( const B2DTuple& rTup ) + { + mfX += rTup.mfX; + mfY += rTup.mfY; + return *this; + } + + B2DTuple& operator-=( const B2DTuple& rTup ) + { + mfX -= rTup.mfX; + mfY -= rTup.mfY; + return *this; + } + + B2DTuple& operator/=( const B2DTuple& rTup ) + { + mfX /= rTup.mfX; + mfY /= rTup.mfY; + return *this; + } + + B2DTuple& operator*=( const B2DTuple& rTup ) + { + mfX *= rTup.mfX; + mfY *= rTup.mfY; + return *this; + } + + B2DTuple& operator*=(double t) + { + mfX *= t; + mfY *= t; + return *this; + } + + B2DTuple& operator/=(double t) + { + const double fVal(1.0 / t); + mfX *= fVal; + mfY *= fVal; + return *this; + } + + B2DTuple operator-(void) const + { + return B2DTuple(-mfX, -mfY); + } + + bool operator==( const B2DTuple& rTup ) const + { + return mfX == rTup.mfX && mfY == rTup.mfY; + } + + bool operator!=( const B2DTuple& rTup ) const + { + return mfX != rTup.mfX || mfY != rTup.mfY; + } + + 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& rTupA, const B2DTuple& rTupB) + { + B2DTuple aSum(rTupA); + aSum += rTupB; + return aSum; + } + + inline B2DTuple operator-(const B2DTuple& rTupA, const B2DTuple& rTupB) + { + B2DTuple aSub(rTupA); + aSub -= rTupB; + return aSub; + } + + inline B2DTuple operator/(const B2DTuple& rTupA, const B2DTuple& rTupB) + { + B2DTuple aDiv(rTupA); + aDiv /= rTupB; + return aDiv; + } + + inline B2DTuple operator*(const B2DTuple& rTupA, const B2DTuple& rTupB) + { + B2DTuple aMul(rTupA); + aMul *= rTupB; + return aMul; + } + + 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 000000000..5f2350b66 --- /dev/null +++ b/include/basegfx/tuple/b2i64tuple.hxx @@ -0,0 +1,176 @@ +/* -*- 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 <sal/types.h> +#include <basegfx/basegfxdllapi.h> + + +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 final + { + sal_Int64 mnX; + sal_Int64 mnY; + + public: + /** Create a 2D Tuple + + The tuple is initialized to (0, 0) + */ + B2I64Tuple() + : mnX(0), + mnY(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. + */ + B2I64Tuple(sal_Int64 fX, sal_Int64 fY) + : mnX( fX ), + mnY( fY ) + {} + + /** Create a copy of a 2D Tuple + + @param rTup + The 2D Tuple which will be copied. + */ + B2I64Tuple(const B2I64Tuple& rTup) + : mnX( rTup.mnX ), + mnY( rTup.mnY ) + {} + + /// Get X-Coordinate of 2D Tuple + sal_Int64 getX() const + { + return mnX; + } + + /// Get Y-Coordinate of 2D Tuple + sal_Int64 getY() const + { + return mnY; + } + + /// Array-access to 2D Tuple + const sal_Int64& operator[] (int nPos) const + { + // Here, normally one if(...) should be used. In the assumption that + // both sal_Int64 members can be accessed as an array a shortcut is used here. + // if(0 == nPos) return mnX; return mnY; + return *((&mnX) + nPos); + } + + /// Array-access to 2D Tuple + sal_Int64& operator[] (int nPos) + { + // Here, normally one if(...) should be used. In the assumption that + // both sal_Int64 members can be accessed as an array a shortcut is used here. + // if(0 == nPos) return mnX; return mnY; + return *((&mnX) + nPos); + } + + // operators + + + B2I64Tuple& operator+=( const B2I64Tuple& rTup ) + { + mnX += rTup.mnX; + mnY += rTup.mnY; + return *this; + } + + B2I64Tuple& operator-=( const B2I64Tuple& rTup ) + { + mnX -= rTup.mnX; + mnY -= rTup.mnY; + return *this; + } + + B2I64Tuple& operator/=( const B2I64Tuple& rTup ) + { + mnX /= rTup.mnX; + mnY /= rTup.mnY; + return *this; + } + + B2I64Tuple& operator*=( const B2I64Tuple& rTup ) + { + mnX *= rTup.mnX; + mnY *= rTup.mnY; + return *this; + } + + B2I64Tuple& operator*=(sal_Int64 t) + { + mnX *= t; + mnY *= t; + return *this; + } + + B2I64Tuple& operator/=(sal_Int64 t) + { + mnX /= t; + mnY /= t; + return *this; + } + + B2I64Tuple operator-(void) const + { + return B2I64Tuple(-mnX, -mnY); + } + + bool operator==( const B2I64Tuple& rTup ) const + { + return this == &rTup || (rTup.mnX == mnX && rTup.mnY == mnY); + } + + bool operator!=( const B2I64Tuple& rTup ) const + { + return !(*this == rTup); + } + + 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 000000000..b8f6c3e96 --- /dev/null +++ b/include/basegfx/tuple/b2ituple.hxx @@ -0,0 +1,200 @@ +/* -*- 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 <sal/types.h> +#include <basegfx/basegfxdllapi.h> + +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 + { + protected: + sal_Int32 mnX; + sal_Int32 mnY; + + public: + /** Create a 2D Tuple + + The tuple is initialized to (0, 0) + */ + B2ITuple() + : mnX(0), + mnY(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. + */ + B2ITuple(sal_Int32 fX, sal_Int32 fY) + : mnX( fX ), + mnY( fY ) + {} + + /// Get X-Coordinate of 2D Tuple + sal_Int32 getX() const + { + return mnX; + } + + /// Get Y-Coordinate of 2D Tuple + sal_Int32 getY() const + { + return mnY; + } + + /// Set X-Coordinate of 2D Tuple + void setX(sal_Int32 fX) + { + mnX = fX; + } + + /// Set Y-Coordinate of 2D Tuple + void setY(sal_Int32 fY) + { + mnY = fY; + } + + /// Array-access to 2D Tuple + const sal_Int32& operator[] (int nPos) const + { + // Here, normally one if(...) 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; return mnY; + return *((&mnX) + nPos); + } + + /// Array-access to 2D Tuple + sal_Int32& operator[] (int nPos) + { + // Here, normally one if(...) 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; return mnY; + return *((&mnX) + nPos); + } + + // operators + + + B2ITuple& operator+=( const B2ITuple& rTup ) + { + mnX += rTup.mnX; + mnY += rTup.mnY; + return *this; + } + + B2ITuple& operator-=( const B2ITuple& rTup ) + { + mnX -= rTup.mnX; + mnY -= rTup.mnY; + return *this; + } + + B2ITuple& operator/=( const B2ITuple& rTup ) + { + mnX /= rTup.mnX; + mnY /= rTup.mnY; + return *this; + } + + B2ITuple& operator*=( const B2ITuple& rTup ) + { + mnX *= rTup.mnX; + mnY *= rTup.mnY; + return *this; + } + + B2ITuple& operator*=(sal_Int32 t) + { + mnX *= t; + mnY *= t; + return *this; + } + + B2ITuple& operator/=(sal_Int32 t) + { + mnX /= t; + mnY /= t; + return *this; + } + + B2ITuple operator-(void) const + { + return B2ITuple(-mnX, -mnY); + } + + bool equalZero() const + { + return mnX == 0 && mnY == 0; + } + + bool operator==( const B2ITuple& rTup ) const + { + return this == &rTup || (rTup.mnX == mnX && rTup.mnY == mnY); + } + + bool operator!=( const B2ITuple& rTup ) const + { + return !(*this == rTup); + } + }; + + // 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 000000000..791cc5f3e --- /dev/null +++ b/include/basegfx/tuple/b3dtuple.hxx @@ -0,0 +1,335 @@ +/* -*- 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 <config_options.h> +#include <sal/types.h> +#include <basegfx/numeric/ftools.hxx> +#include <basegfx/basegfxdllapi.h> + +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 UNLESS_MERGELIBS(BASEGFX_DLLPUBLIC) B3DTuple + { + protected: + double mfX; + double mfY; + double mfZ; + + public: + /** Create a 3D Tuple + + The tuple is initialized to (0.0, 0.0, 0.0) + */ + B3DTuple() + : mfX(0.0), + mfY(0.0), + mfZ(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) + : mfX(fX), + mfY(fY), + mfZ(fZ) + {} + + /// get X-Coordinate of 3D Tuple + double getX() const + { + return mfX; + } + + /// get Y-Coordinate of 3D Tuple + double getY() const + { + return mfY; + } + + /// get Z-Coordinate of 3D Tuple + double getZ() const + { + return mfZ; + } + + /// set X-Coordinate of 3D Tuple + void setX(double fX) + { + mfX = fX; + } + + /// set Y-Coordinate of 3D Tuple + void setY(double fY) + { + mfY = fY; + } + + /// set Z-Coordinate of 3D Tuple + void setZ(double fZ) + { + mfZ = 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 mfX; if(1 == nPos) return mfY; return mfZ; + return *((&mfX) + 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 mfX; if(1 == nPos) return mfY; return mfZ; + return *((&mfX) + nPos); + } + + // comparators with tolerance + + + bool equalZero() const + { + return (this == &getEmptyTuple() || + (::basegfx::fTools::equalZero(mfX) + && ::basegfx::fTools::equalZero(mfY) + && ::basegfx::fTools::equalZero(mfZ))); + } + + bool equal(const B3DTuple& rTup) const + { + return ( + this == &rTup || + (::basegfx::fTools::equal(mfX, rTup.mfX) && + ::basegfx::fTools::equal(mfY, rTup.mfY) && + ::basegfx::fTools::equal(mfZ, rTup.mfZ))); + } + + // operators + + + B3DTuple& operator+=( const B3DTuple& rTup ) + { + mfX += rTup.mfX; + mfY += rTup.mfY; + mfZ += rTup.mfZ; + return *this; + } + + B3DTuple& operator-=( const B3DTuple& rTup ) + { + mfX -= rTup.mfX; + mfY -= rTup.mfY; + mfZ -= rTup.mfZ; + return *this; + } + + B3DTuple& operator/=( const B3DTuple& rTup ) + { + mfX /= rTup.mfX; + mfY /= rTup.mfY; + mfZ /= rTup.mfZ; + return *this; + } + + B3DTuple& operator*=( const B3DTuple& rTup ) + { + mfX *= rTup.mfX; + mfY *= rTup.mfY; + mfZ *= rTup.mfZ; + return *this; + } + + B3DTuple& operator*=(double t) + { + mfX *= t; + mfY *= t; + mfZ *= t; + return *this; + } + + B3DTuple& operator/=(double t) + { + const double fVal(1.0 / t); + mfX *= fVal; + mfY *= fVal; + mfZ *= fVal; + return *this; + } + + B3DTuple operator-(void) const + { + return B3DTuple(-mfX, -mfY, -mfZ); + } + + bool operator==( const B3DTuple& rTup ) const + { + return mfX == rTup.mfX && mfY == rTup.mfY && mfZ == rTup.mfZ; + } + + bool operator!=( const B3DTuple& rTup ) const + { + return mfX != rTup.mfX || mfY != rTup.mfY || mfZ != rTup.mfZ; + } + + void correctValues(const double fCompareValue = 0.0) + { + if(0.0 == fCompareValue) + { + if(::basegfx::fTools::equalZero(mfX)) + { + mfX = 0.0; + } + + if(::basegfx::fTools::equalZero(mfY)) + { + mfY = 0.0; + } + + if(::basegfx::fTools::equalZero(mfZ)) + { + mfZ = 0.0; + } + } + else + { + if(::basegfx::fTools::equal(mfX, fCompareValue)) + { + mfX = fCompareValue; + } + + if(::basegfx::fTools::equal(mfY, fCompareValue)) + { + mfY = fCompareValue; + } + + if(::basegfx::fTools::equal(mfZ, fCompareValue)) + { + mfZ = 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 000000000..7fe49ea92 --- /dev/null +++ b/include/basegfx/tuple/b3ituple.hxx @@ -0,0 +1,172 @@ +/* -*- 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 <sal/types.h> +#include <basegfx/basegfxdllapi.h> + +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 + { + protected: + sal_Int32 mnX; + sal_Int32 mnY; + sal_Int32 mnZ; + + public: + /** Create a 3D Tuple + + The tuple is initialized to (0, 0, 0) + */ + B3ITuple() + : mnX(0), + mnY(0), + mnZ(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) + : mnX(nX), + mnY(nY), + mnZ(nZ) + {} + + /// get X-Coordinate of 3D Tuple + sal_Int32 getX() const + { + return mnX; + } + + /// get Y-Coordinate of 3D Tuple + sal_Int32 getY() const + { + return mnY; + } + + /// 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+=( const B3ITuple& rTup ) + { + mnX += rTup.mnX; + mnY += rTup.mnY; + mnZ += rTup.mnZ; + return *this; + } + + B3ITuple& operator-=( const B3ITuple& rTup ) + { + mnX -= rTup.mnX; + mnY -= rTup.mnY; + mnZ -= rTup.mnZ; + return *this; + } + + B3ITuple& operator/=( const B3ITuple& rTup ) + { + mnX /= rTup.mnX; + mnY /= rTup.mnY; + mnZ /= rTup.mnZ; + return *this; + } + + B3ITuple& operator*=( const B3ITuple& rTup ) + { + mnX *= rTup.mnX; + mnY *= rTup.mnY; + mnZ *= rTup.mnZ; + return *this; + } + + B3ITuple& operator*=(sal_Int32 t) + { + mnX *= t; + mnY *= t; + mnZ *= t; + return *this; + } + + B3ITuple& operator/=(sal_Int32 t) + { + mnX /= t; + mnY /= t; + mnZ /= t; + return *this; + } + + B3ITuple operator-(void) const + { + return B3ITuple(-mnX, -mnY, -mnZ); + } + + bool operator==( const B3ITuple& rTup ) const + { + return this == &rTup || (rTup.mnX == mnX && rTup.mnY == mnY && rTup.mnZ == mnZ); + } + + bool operator!=( const B3ITuple& rTup ) const + { + return !(*this == rTup); + } + }; + +} // 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 000000000..f4d9d9e7d --- /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 <o3tl/cow_wrapper.hxx> +#include <basegfx/basegfxdllapi.h> + + +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/canvastools.hxx b/include/basegfx/utils/canvastools.hxx new file mode 100644 index 000000000..d4cfa0a5c --- /dev/null +++ b/include/basegfx/utils/canvastools.hxx @@ -0,0 +1,165 @@ +/* -*- 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 <com/sun/star/uno/Reference.hxx> +#include <com/sun/star/uno/Sequence.hxx> +#include <basegfx/basegfxdllapi.h> + + +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; +} + +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 ); + + + BASEGFX_DLLPUBLIC css::uno::Sequence< + css::uno::Sequence< css::geometry::RealBezierSegment2D > > + bezierSequenceSequenceFromB2DPolyPolygon( const ::basegfx::B2DPolyPolygon& rPolyPoly ); + + BASEGFX_DLLPUBLIC css::uno::Sequence< + css::uno::Sequence< css::geometry::RealPoint2D > > + pointSequenceSequenceFromB2DPolyPolygon( const ::basegfx::B2DPolyPolygon& rPolyPoly ); + + BASEGFX_DLLPUBLIC ::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_DLLPUBLIC ::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); + + BASEGFX_DLLPUBLIC 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::B2DVector& ); + 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_DLLPUBLIC ::basegfx::B3DRange b3DRectangleFromRealRectangle3D( const css::geometry::RealRectangle3D& ); + + BASEGFX_DLLPUBLIC css::geometry::IntegerSize2D integerSize2DFromB2ISize( const ::basegfx::B2IVector& ); + + BASEGFX_DLLPUBLIC ::basegfx::B2IVector 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 000000000..1c11a8bf2 --- /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 000000000..331e2998b --- /dev/null +++ b/include/basegfx/utils/gradienttools.hxx @@ -0,0 +1,401 @@ +/* -*- 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 <config_options.h> +#include <basegfx/point/b2dpoint.hxx> +#include <basegfx/vector/b2dvector.hxx> +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <basegfx/basegfxdllapi.h> + +namespace basegfx { class B2DRange; } + +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 mnSteps; + + public: + ODFGradientInfo() + : maTextureTransform(), + maBackTextureTransform(), + mfAspectRatio(1.0), + mnSteps(0) + { + } + + ODFGradientInfo( + const B2DHomMatrix& rTextureTransform, + double fAspectRatio, + sal_uInt32 nSteps) + : maTextureTransform(rTextureTransform), + maBackTextureTransform(), + mfAspectRatio(fAspectRatio), + mnSteps(nSteps) + { + } + + ODFGradientInfo(const ODFGradientInfo& rODFGradientInfo) + : maTextureTransform(rODFGradientInfo.getTextureTransform()), + maBackTextureTransform(rODFGradientInfo.maBackTextureTransform), + mfAspectRatio(rODFGradientInfo.getAspectRatio()), + mnSteps(rODFGradientInfo.getSteps()) + { + } + + ODFGradientInfo& operator=(const ODFGradientInfo& rODFGradientInfo) + { + maTextureTransform = rODFGradientInfo.getTextureTransform(); + maBackTextureTransform = rODFGradientInfo.maBackTextureTransform; + mfAspectRatio = rODFGradientInfo.getAspectRatio(); + mnSteps = rODFGradientInfo.getSteps(); + + 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 getSteps() const { return mnSteps; } + + void setTextureTransform(const B2DHomMatrix& rNew) + { + maTextureTransform = rNew; + maBackTextureTransform.identity(); + } + }; + + namespace utils + { + /** 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 nSteps + 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 nSteps, + 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 nSteps + 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 nSteps, + 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 nSteps + 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 nSteps, + 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 nSteps + 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 nSteps, + 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 nSteps + 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 nSteps, + 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 nSteps + 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 nSteps, + 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 000000000..302020ac3 --- /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 <vector> +#include <basegfx/basegfxdllapi.h> + +namespace com::sun::star::uno { + template<typename T> 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<std::ptrdiff_t,double> 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( const std::vector<double>& 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<double>& 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<double> 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 000000000..e02b3b0fa --- /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<ValueType>( (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 000000000..b1354a6ca --- /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 <sal/types.h> +#include <basegfx/range/b2ibox.hxx> + + +namespace basegfx::utils +{ + namespace RectClipFlags + { + static const sal_uInt32 LEFT = sal_Int32(0x01); + static const sal_uInt32 RIGHT = sal_Int32(0x02); + static const sal_uInt32 TOP = sal_Int32(0x04); + static 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 000000000..120e39a0e --- /dev/null +++ b/include/basegfx/utils/systemdependentdata.hxx @@ -0,0 +1,134 @@ +/* -*- 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 <sal/types.h> +#include <basegfx/basegfxdllapi.h> +#include <memory> +#include <map> +#include <set> + +namespace basegfx +{ + class SystemDependentData; + typedef std::shared_ptr<SystemDependentData> SystemDependentData_SharedPtr; + typedef std::weak_ptr<SystemDependentData> 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 MinimalSystemDependentDataManager final : public SystemDependentDataManager + { + private: + // example of a minimal SystemDependentDataManager. It *needs to hold* + // a SystemDependentData_SharedPtr while SystemDependentDataHolder's will + // use a SystemDependentData_WeakPtr. When the held SystemDependentData_SharedPtr + // is deleted, the corresponding SystemDependentData_WeakPtr will get void. + // To make this work, a minimal SystemDependentDataManager *has* to hold at + // least that one SystemDependentData_SharedPtr. + // That SystemDependentData_SharedPtr may be (e.g. Timer-based or resource-based) + // be freed then. This minimal implementation does never free it, so all stay valid. + // The instances may still be removed by endUsage calls, but there is no + // caching/buffering mechanism involved here at all. It's an example, but + // not used - better use an advanced derivation of SystemDependentDataManager + std::set< SystemDependentData_SharedPtr > maSystemDependentDataReferences; + + public: + MinimalSystemDependentDataManager(); + virtual ~MinimalSystemDependentDataManager() override; + + virtual void startUsage(basegfx::SystemDependentData_SharedPtr& rData) override; + virtual void endUsage(basegfx::SystemDependentData_SharedPtr& rData) override; + virtual void touchUsage(basegfx::SystemDependentData_SharedPtr& rData) override; + virtual void flushAll() override; + }; + + 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; + + // 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 000000000..f8fc61999 --- /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 <sal/types.h> +#include <basegfx/basegfxdllapi.h> + +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 000000000..da95ebff2 --- /dev/null +++ b/include/basegfx/utils/unopolypolygon.hxx @@ -0,0 +1,105 @@ +/* -*- 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 <cppuhelper/basemutex.hxx> +#include <cppuhelper/compbase.hxx> +#include <com/sun/star/lang/IndexOutOfBoundsException.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/rendering/FillRule.hpp> +#include <com/sun/star/rendering/XLinePolyPolygon2D.hpp> +#include <com/sun/star/rendering/XBezierPolyPolygon2D.hpp> +#include <basegfx/polygon/b2dpolypolygon.hxx> +#include <basegfx/basegfxdllapi.h> + +namespace basegfx::unotools +{ + typedef cppu::WeakComponentImplHelper< + css::rendering::XLinePolyPolygon2D, + css::rendering::XBezierPolyPolygon2D, + css::lang::XServiceInfo > UnoPolyPolygonBase; + + class BASEGFX_DLLPUBLIC UnoPolyPolygon + : private cppu::BaseMutex + , public UnoPolyPolygonBase + { + public: + explicit UnoPolyPolygon( const B2DPolyPolygon& ); + + // XPolyPolygon2D + virtual void SAL_CALL addPolyPolygon( const css::geometry::RealPoint2D& position, const css::uno::Reference< css::rendering::XPolyPolygon2D >& polyPolygon ) override; + virtual ::sal_Int32 SAL_CALL getNumberOfPolygons( ) override; + virtual ::sal_Int32 SAL_CALL getNumberOfPolygonPoints( ::sal_Int32 polygon ) override; + virtual css::rendering::FillRule SAL_CALL getFillRule( ) override; + virtual void SAL_CALL setFillRule( css::rendering::FillRule fillRule ) override; + virtual sal_Bool SAL_CALL isClosed( ::sal_Int32 index ) override; + virtual void SAL_CALL setClosed( ::sal_Int32 index, sal_Bool closedState ) override; + + // XLinePolyPolygon2D + 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; + virtual void SAL_CALL setPoints( const css::uno::Sequence< css::uno::Sequence< css::geometry::RealPoint2D > >& points, ::sal_Int32 nPolygonIndex ) override; + virtual css::geometry::RealPoint2D SAL_CALL getPoint( ::sal_Int32 nPolygonIndex, ::sal_Int32 nPointIndex ) override; + virtual void SAL_CALL setPoint( const css::geometry::RealPoint2D& point, ::sal_Int32 nPolygonIndex, ::sal_Int32 nPointIndex ) override; + + // XBezierPolyPolygon2D + 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; + virtual void SAL_CALL setBezierSegments( const css::uno::Sequence< css::uno::Sequence< css::geometry::RealBezierSegment2D > >& points, ::sal_Int32 nPolygonIndex ) override; + virtual css::geometry::RealBezierSegment2D SAL_CALL getBezierSegment( ::sal_Int32 nPolygonIndex, ::sal_Int32 nPointIndex ) override; + virtual void SAL_CALL setBezierSegment( const css::geometry::RealBezierSegment2D& point, ::sal_Int32 nPolygonIndex, ::sal_Int32 nPointIndex ) override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + + 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 || nIndex >= static_cast<sal_Int32>(maPolyPoly.count()) ) + throw css::lang::IndexOutOfBoundsException(); + } + + 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 000000000..4d85e5dec --- /dev/null +++ b/include/basegfx/utils/zoomtools.hxx @@ -0,0 +1,24 @@ +/* -*- 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 <basegfx/basegfxdllapi.h> + +namespace basegfx::zoomtools +{ + +/** This namespace provides functions for optimized geometric zooming +*/ +BASEGFX_DLLPUBLIC long zoomOut(long nCurrent); +BASEGFX_DLLPUBLIC long zoomIn(long 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 000000000..6ae6de5e8 --- /dev/null +++ b/include/basegfx/vector/b2dsize.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 <basegfx/vector/b2dvector.hxx> + +namespace basegfx +{ + // syntactic sugar: a B2DVector exactly models a Size object, + // thus, for interface clarity, we provide an alias name + + /// Alias name for interface clarity (not everybody is aware of the identity) + typedef B2DVector B2DSize; +} + +/* 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 000000000..cfb1e58d1 --- /dev/null +++ b/include/basegfx/vector/b2dvector.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 <basegfx/tuple/b2dtuple.hxx> +#include <basegfx/vector/b2ivector.hxx> +#include <basegfx/vector/b2enums.hxx> +#include <basegfx/basegfxdllapi.h> + +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() + : B2DTuple() + {} + + /** 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(const ::basegfx::B2DTuple& rTuple) + : B2DTuple(rTuple) + {} + + /** *=operator to allow usage from B2DVector, too + */ + B2DVector& operator*=( const B2DVector& rPnt ) + { + mfX *= rPnt.mfX; + mfY *= rPnt.mfY; + return *this; + } + + /** *=operator to allow usage from B2DVector, too + */ + B2DVector& operator*=(double t) + { + mfX *= t; + mfY *= t; + return *this; + } + + /** assignment operator to allow assigning the results + of B2DTuple calculations + */ + B2DVector& operator=( const ::basegfx::B2DTuple& rVec ); + + /** 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((mfX * rVec.mfX) + (mfY * rVec.mfY)); } + + /** 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(mfX * rVec.getY() - mfY * 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 000000000..803902370 --- /dev/null +++ b/include/basegfx/vector/b2enums.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 + +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 + */ + 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 000000000..5d299f4fd --- /dev/null +++ b/include/basegfx/vector/b2isize.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 <basegfx/vector/b2ivector.hxx> + +namespace basegfx +{ + // syntactic sugar: a B2IVector exactly models a Size object, + // thus, for interface clarity, we provide an alias name + + /// Alias name for interface clarity (not everybody is aware of the identity) + typedef B2IVector B2ISize; +} + +/* 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 000000000..fbb1c6422 --- /dev/null +++ b/include/basegfx/vector/b2ivector.hxx @@ -0,0 +1,130 @@ +/* -*- 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 <ostream> + +#include <basegfx/tuple/b2ituple.hxx> +#include <basegfx/basegfxdllapi.h> + +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() + : B2ITuple() + {} + + /** 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<charT, traits> & operator <<( + std::basic_ostream<charT, traits> & 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 000000000..1f38d5dd7 --- /dev/null +++ b/include/basegfx/vector/b3dvector.hxx @@ -0,0 +1,259 @@ +/* -*- 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 <basegfx/tuple/b3dtuple.hxx> +#include <basegfx/basegfxdllapi.h> + +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() + : B3DTuple() + {} + + /** 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 ) + { + mfX *= rPnt.mfX; + mfY *= rPnt.mfY; + mfZ *= rPnt.mfZ; + return *this; + } + + /** *=operator to allow usage from B3DVector, too + */ + B3DVector& operator*=(double t) + { + mfX *= t; + mfY *= t; + mfZ *= t; + return *this; + } + + /** assignment operator to allow assigning the results + of B3DTuple calculations + */ + B3DVector& operator=( const ::basegfx::B3DTuple& rVec ) + { + mfX = rVec.getX(); + mfY = rVec.getY(); + mfZ = 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((mfX * mfX) + (mfZ * mfZ)); // #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((mfY * mfY) + (mfZ * mfZ)); + 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); + } + + mfX *= fLen; + mfY *= fLen; + mfZ *= 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 ((mfX * rVec.mfX) + (mfY * rVec.mfY) + (mfZ * rVec.mfZ)); + } + + /** 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<const B3DVector&>( ::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: */ |