1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 #ifndef _BGFX_CURVE_B2DCUBICBEZIER_HXX
25 #define _BGFX_CURVE_B2DCUBICBEZIER_HXX
26 
27 #include <basegfx/point/b2dpoint.hxx>
28 #include <basegfx/range/b2drange.hxx>
29 
30 //////////////////////////////////////////////////////////////////////////////
31 // predeclarations
32 
33 namespace basegfx
34 {
35 	class B2DPolygon;
36 } // end of namespace basegfx
37 
38 //////////////////////////////////////////////////////////////////////////////
39 
40 namespace basegfx
41 {
42 	class B2DCubicBezier
43 	{
44 		B2DPoint										maStartPoint;
45 		B2DPoint										maEndPoint;
46 		B2DPoint										maControlPointA;
47 		B2DPoint										maControlPointB;
48 
49 	public:
50 		B2DCubicBezier();
51 		B2DCubicBezier(const B2DCubicBezier& rBezier);
52 		B2DCubicBezier(const B2DPoint& rStart, const B2DPoint& rEnd);
53 		B2DCubicBezier(const B2DPoint& rStart, const B2DPoint& rControlPointA, const B2DPoint& rControlPointB, const B2DPoint& rEnd);
54 		~B2DCubicBezier();
55 
56 		// assignment operator
57 		B2DCubicBezier& operator=(const B2DCubicBezier& rBezier);
58 
59 		// compare operators
60 		bool operator==(const B2DCubicBezier& rBezier) const;
61 		bool operator!=(const B2DCubicBezier& rBezier) const;
62         bool equal(const B2DCubicBezier& rBezier) const;
63 
64 		// test if vectors are used
65 		bool isBezier() const;
66 
67 		// test if contained bezier is trivial and reset vectors accordingly
68 		void testAndSolveTrivialBezier();
69 
70 		/** get length of edge
71 
72             This method handles beziers and simple edges. For
73             beziers, the deviation describes the maximum allowed
74             deviation from the real edge length. The default
75             allows a deviation of 1% from the correct length.
76 
77             For beziers, there is no direct way to get the length,
78             thus this method may subdivide the bezier edge and may
79             not be cheap.
80 
81             @param fDeviation
82             The maximal allowed deviation between correct length
83             and bezier edge length
84 
85             @return
86             The length of the edge
87         */
88 		double getLength(double fDeviation = 0.01) const;
89 
90         // get distance between start and end point
91 		double getEdgeLength() const;
92 
93 		// get length of control polygon
94 		double getControlPolygonLength() const;
95 
96 		// data interface
getStartPoint() const97 		B2DPoint getStartPoint() const { return maStartPoint; }
setStartPoint(const B2DPoint & rValue)98 		void setStartPoint(const B2DPoint& rValue) { maStartPoint = rValue; }
99 
getEndPoint() const100 		B2DPoint getEndPoint() const { return maEndPoint; }
setEndPoint(const B2DPoint & rValue)101 		void setEndPoint(const B2DPoint& rValue) { maEndPoint = rValue; }
102 
getControlPointA() const103 		B2DPoint getControlPointA() const { return maControlPointA; }
setControlPointA(const B2DPoint & rValue)104 		void setControlPointA(const B2DPoint& rValue) { maControlPointA = rValue; }
105 
getControlPointB() const106 		B2DPoint getControlPointB() const { return maControlPointB; }
setControlPointB(const B2DPoint & rValue)107 		void setControlPointB(const B2DPoint& rValue) { maControlPointB = rValue; }
108 
109         /** get the tangent in point t
110 
111             This method handles all the exceptions, e.g. when control point
112             A is equal to start point and/or control point B is equal to end
113             point
114 
115             @param t
116             The bezier index in the range [0.0 .. 1.0]. It will be truncated.
117 
118             @return
119             The tangent vector in point t
120         */
121         B2DVector getTangent(double t) const;
122 
123 		/** adaptive subdivide by angle criteria
124 		    no start point is added, but all necessary created edges
125             and the end point
126 		    #i37443# allow the criteria to get unsharp in recursions
127         */
128 		void adaptiveSubdivideByAngle(B2DPolygon& rTarget, double fAngleBound, bool bAllowUnsharpen) const;
129 
130 		/** #i37443# adaptive subdivide by nCount subdivisions
131 		    no start point is added, but all necessary created edges
132             and the end point
133         */
134 		void adaptiveSubdivideByCount(B2DPolygon& rTarget, sal_uInt32 nCount) const;
135 
136 		/** Subdivide cubic bezier segment.
137 
138 			This function adaptively subdivides the bezier
139 			segment into as much straight line segments as necessary,
140 			such that the maximal orthogonal distance from any of the
141 			segments to the true curve is less than the given error
142 			value.
143 			No start point is added, but all necessary created edges
144             and the end point
145 
146 			@param rPoly
147 			Output polygon. The subdivided bezier segment is added to
148 			this polygon via B2DPolygon::append().
149 
150 			@param rCurve
151 			The cubic bezier curve to subdivide
152 
153 			@param fDistanceBound
154 			Bound on the maximal distance of the approximation to the
155 			true curve.
156 		*/
157 		void adaptiveSubdivideByDistance(B2DPolygon& rTarget, double fDistanceBound) const;
158 
159 		// get point at given relative position
160 		B2DPoint interpolatePoint(double t) const;
161 
162 		// calculate the smallest distance from given point to this cubic bezier segment
163 		// and return the value. The relative position on the segment is returned in rCut.
164 		double getSmallestDistancePointToBezierSegment(const B2DPoint& rTestPoint, double& rCut) const;
165 
166 		// do a split at position t and fill both resulting segments
167 		void split(double t, B2DCubicBezier* pBezierA, B2DCubicBezier* pBezierB) const;
168 
169 		// extract snippet from fStart to fEnd from this bezier
170 		B2DCubicBezier snippet(double fStart, double fEnd) const;
171 
172 		// get range including conrol points
173 		B2DRange getRange() const;
174 
175 		/** Get the minimum extremum position t
176 
177 			@param rfResult
178 			Will be changed and set to a eventually found split value which should be in the
179 			range [0.0 .. 1.0]. It will be the smallest current extremum; there may be more
180 
181 			@return
182 			Returns true if there was at least one extremum found
183 		*/
184 		bool getMinimumExtremumPosition(double& rfResult) const;
185 
186 		/** Get all extremum pos of this segment
187 
188 			This method will calculate all extremum positions of the segment
189 			and add them to rResults if they are in the range ]0.0 .. 1.0[
190 
191 			@param rResults
192 			The vector of doubles where the results will be added. Evtl.
193 			existing contents will be removed since an empty vector is a
194 			necessary result to express that there are no extreme positions
195 			anymore. Since there is an upper maximum of 4 values, it makes
196 			sense to use reserve(4) at the vector as preparation.
197 		*/
198 		void getAllExtremumPositions(::std::vector< double >& rResults) const;
199 
200 		/** Get optimum-split position on this segment
201 
202 			This method calculates the positions of all points of the segment
203 			that have the maximimum distance to the corresponding line from
204 			startpoint-endpoint. This helps to approximate the bezier curve
205 			with a minimum number of line segments
206 
207 			@param fResults
208  			Result positions are in the range ]0.0 .. 1.0[
209 			Cubic beziers have at most two of these positions
210 
211 			@return
212 			Returns the number of split positions found
213 		*/
214 		int getMaxDistancePositions( double fResults[2]) const;
215 	};
216 } // end of namespace basegfx
217 
218 #endif /* _BGFX_CURVE_B2DCUBICBEZIER_HXX */
219