Files
MagicSetEditor2/src/gfx/bezier.hpp
T
twanvl ce906e83f8 Cleaned up the calculation of bounds of symbols, this fixes bounds calculation with symmetries.
git-svn-id: svn://svn.code.sf.net/p/magicseteditor/code/trunk@1178 0fc631ac-6414-0410-93d0-97cfa31319b6
2008-08-27 23:46:31 +00:00

127 lines
5.9 KiB
C++

//+----------------------------------------------------------------------------+
//| Description: Magic Set Editor - Program to make Magic (tm) cards |
//| Copyright: (C) 2001 - 2008 Twan van Laarhoven and "coppro" |
//| License: GNU General Public License 2 or later (see file COPYING) |
//+----------------------------------------------------------------------------+
#ifndef HEADER_GFX_BEZIER
#define HEADER_GFX_BEZIER
/** @file gfx/bezier.hpp
*
* Bezier curve and line related functions
*/
// ----------------------------------------------------------------------------- : Includes
#include <util/prec.hpp>
#include <util/vector2d.hpp>
#include <data/symbol.hpp>
class Rotation;
// ----------------------------------------------------------------------------- : Evaluation
/// A bezier curve for evaluation
class BezierCurve {
public:
/// coefficients of the equation (x,y) = at^3 + bt^2 + ct + d
Vector2D a, b, c, d;
/// Construct a bezier curve evaluator given the 4 handles
BezierCurve(const Vector2D& p0, const Vector2D& p1, const Vector2D& p2, const Vector2D& p3);
/// Construct a bezier curve evaluator given two ControlPoints at the ends
BezierCurve(const ControlPoint& p0, const ControlPoint& p3);
/// Return the point on this curve at time t in [0...1)
inline Vector2D pointAt(double t) const {
return d + (c + (b + a * t) * t) * t;
}
/// Return the tangent on this curve at time t in [0...1)
inline Vector2D tangentAt(double t) const {
return c + ((b * 2) + (a * 3) * t) * t;
}
};
/// Subdivide a curve from a to b, store the result in a control point
/** Also modifies the handles of the points to accomodate the inserted point
* Direct version, using input curve a1,a2,a3,a4 and output curves a1,b2,b3,b4 and c1,c2,c3,a4
*/
void deCasteljau(Vector2D a1, Vector2D a2, Vector2D a3, Vector2D a4,
Vector2D& b2, Vector2D& b3, Vector2D& b4c1,
Vector2D& c2, Vector2D& c3, double t);
/// Subdivide a curve from a to b at time t
/** Stores the point at time t in mid, updates the handles of a and b!
*/
void deCasteljau(ControlPoint& a, ControlPoint& b, double t, ControlPoint& mid);
/// Subdivide a curve from a to b, store the result in a control point
/** Also modifies the handles of the points to accomodate the inserted point!
*/
void deCasteljau(const Vector2D& a1, Vector2D& a21, Vector2D& a34, const Vector2D& a4, double t, ControlPoint& out);
// ----------------------------------------------------------------------------- : Drawing
/// Devide a segment into a number of straight lines for display purposes
/** Adds the resulting corner points of those lines to out, the last point is not added.
* All points are converted to display coordinates by multiplying with m and adding origin
*/
void segment_subdivide(const ControlPoint& p0, const ControlPoint& p1, const Vector2D& origin, const Matrix2D& m, vector<wxPoint>& out);
// ----------------------------------------------------------------------------- : Bounds
/// Find a bounding box that fits a segment (either a line or a bezier curve) between p1 and p2.
/** stores the results in min and max.
* min is only changed if the minimum is smaller then the current value in min,
* max only if the maximum is larger.
*/
Bounds segment_bounds(const Vector2D& origin, const Matrix2D& m, const ControlPoint& p1, const ControlPoint& p2);
/// Find a bounding box that fits a curve between p1 and p2, stores the results in min and max.
/** min is only changed if the minimum is smaller then the current value in min,
* max only if the maximum is larger
*/
Bounds bezier_bounds(const Vector2D& origin, const Matrix2D& m, const ControlPoint& p1, const ControlPoint& p2);
/// Find a bounding box that fits around p1 and p2, stores the result in min and max
/** min is only changed if the minimum is smaller then the current value in min,
* max only if the maximum is larger
*/
Bounds line_bounds(const Vector2D& origin, const Matrix2D& m, const Vector2D& p1, const Vector2D& p2);
// ----------------------------------------------------------------------------- : Point tests
/// Is a point inside the given shape?
bool point_in_shape(const Vector2D& p, const SymbolShape& part);
// ----------------------------------------------------------------------------- : Finding points
/// Finds the position of p0 on the line between p1 and p2, returns true if the point is on (or near) the line
/// the line between p1 and p2 can also be a bezier curve
/** Returns the time on the segment in tOut, and the point on the segment in pOut
*/
bool pos_on_segment(const Vector2D& pos, double range, const ControlPoint& p1, const ControlPoint& p2, Vector2D& pOut, double& tOut);
/// Finds the position of p0 on the line between p1 and p2, returns true if the point is on (or near)
/// the bezier curve between p1 and p2
bool pos_on_bezier (const Vector2D& pos, double range, const ControlPoint& p1, const ControlPoint& p2, Vector2D& pOut, double& tOut);
/// Finds the position of p0 on the line p1-p2, returns true if the point is withing range of the line
/// if that is the case then (x,y) = p1 + (p2-p1) * out
bool pos_on_line (const Vector2D& pos, double range, const Vector2D& p1, const Vector2D& p2, Vector2D& pOut, double& tOut);
// ----------------------------------------------------------------------------- : Intersection
/// Counts the number of intersections between the ray/halfline from (-inf, pos.y) to pos
/// and the bezier curve between p1 and p2.
UInt intersect_bezier_ray(const ControlPoint& p1, const ControlPoint& p2, const Vector2D& pos);
// Does the line between p1 and p2 intersect the ray (half line) from (-inf, pos.y) to pos?
bool intersect_line_ray(const Vector2D& p1, const Vector2D& p2, const Vector2D& pos);
// ----------------------------------------------------------------------------- : EOF
#endif