summaryrefslogtreecommitdiff
path: root/basegfx/inc/basegfx/curve/b2dcubicbezier.hxx
blob: ea58a0a50b805c50f1fc5b36f6c989d86fa58272 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2000, 2010 Oracle and/or its affiliates.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#ifndef _BGFX_CURVE_B2DCUBICBEZIER_HXX
#define _BGFX_CURVE_B2DCUBICBEZIER_HXX

#include <basegfx/point/b2dpoint.hxx>
#include <basegfx/range/b2drange.hxx>

//////////////////////////////////////////////////////////////////////////////
// predeclarations

namespace basegfx
{
    class B2DPolygon;
} // end of namespace basegfx

//////////////////////////////////////////////////////////////////////////////

namespace basegfx
{
    class B2DCubicBezier
    {
        B2DPoint                                        maStartPoint;
        B2DPoint                                        maEndPoint;
        B2DPoint                                        maControlPointA;
        B2DPoint                                        maControlPointB;

    public:
        B2DCubicBezier();
        B2DCubicBezier(const B2DCubicBezier& rBezier);
        B2DCubicBezier(const B2DPoint& rStart, const B2DPoint& rEnd);
        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
        B2DPoint getStartPoint() const { return maStartPoint; }
        void setStartPoint(const B2DPoint& rValue) { maStartPoint = rValue; }

        B2DPoint getEndPoint() const { return maEndPoint; }
        void setEndPoint(const B2DPoint& rValue) { maEndPoint = rValue; }

        B2DPoint getControlPointA() const { return maControlPointA; }
        void setControlPointA(const B2DPoint& rValue) { maControlPointA = rValue; }

        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, bool bAllowUnsharpen) 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 conrol points
        B2DRange getRange() const;

        /** Get the minimum extremum position t

            @param rfResult
            Will be changed and set to a eventually 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;

        /** Get optimum-split position on this segment

            This method calculates the positions of all points of the segment
            that have the maximimum distance to the corresponding line from
            startpoint-endpoint. This helps to approximate the bezier curve
            with a minimum number of line segments

            @param fResults
             Result positions are in the range ]0.0 .. 1.0[
            Cubic beziers have at most two of these positions

            @return
            Returns the number of split positions found
        */
        int getMaxDistancePositions( double fResults[2]) const;
    };
} // end of namespace basegfx

#endif /* _BGFX_CURVE_B2DCUBICBEZIER_HXX */