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