geom.cpp revision 8ee4f34788f4faaaaae308114790838980a91e3a
01d27eab5fca2dcb8e883011f8be77ae6b78a11cTed Gould * Specific geometry functions for Inkscape, not provided my lib2geom.
981b809bc6ed10a21e89444d9447e5475801874fjohanengelen * Johan Engelen <goejendaagh@zonnet.nl>
981b809bc6ed10a21e89444d9447e5475801874fjohanengelen * Copyright (C) 2008 Johan Engelen
981b809bc6ed10a21e89444d9447e5475801874fjohanengelen * Released under GNU GPL
981b809bc6ed10a21e89444d9447e5475801874fjohanengelen//#################################################################################
981b809bc6ed10a21e89444d9447e5475801874fjohanengelen// BOUNDING BOX CALCULATIONS
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński/* Fast bbox calculation */
981b809bc6ed10a21e89444d9447e5475801874fjohanengelen/* Thanks to Nathan Hurst for suggesting it */
8001ba81cb851b38d86650a2fef5817facffb763johanengelencubic_bbox (Geom::Coord x000, Geom::Coord y000, Geom::Coord x001, Geom::Coord y001, Geom::Coord x011, Geom::Coord y011, Geom::Coord x111, Geom::Coord y111, Geom::Rect &bbox)
e4369b05aaa20df73a37f4d319ce456865cc74f3Krzysztof Kosiński // It already contains (x000,y000) and (x111,y111)
981b809bc6ed10a21e89444d9447e5475801874fjohanengelen // All points of the Bezier lie in the convex hull of (x000,y000), (x001,y001), (x011,y011) and (x111,y111)
981b809bc6ed10a21e89444d9447e5475801874fjohanengelen // So, if it also contains (x001,y001) and (x011,y011) we don't have to compute anything else!
981b809bc6ed10a21e89444d9447e5475801874fjohanengelen // Note that we compute it for the X and Y range separately to make it easier to use them below
981b809bc6ed10a21e89444d9447e5475801874fjohanengelen bool containsXrange = bbox[0].contains(x001) && bbox[0].contains(x011);
981b809bc6ed10a21e89444d9447e5475801874fjohanengelen bool containsYrange = bbox[1].contains(y001) && bbox[1].contains(y011);
6c3e745a94ef6b25a4ef9f018d350a7535aa45afTed Gould * xttt = s * (s * (s * x000 + t * x001) + t * (s * x001 + t * x011)) + t * (s * (s * x001 + t * x011) + t * (s * x011 + t * x111))
981b809bc6ed10a21e89444d9447e5475801874fjohanengelen * xttt = s * (s2 * x000 + s * t * x001 + t * s * x001 + t2 * x011) + t * (s2 * x001 + s * t * x011 + t * s * x011 + t2 * x111)
981b809bc6ed10a21e89444d9447e5475801874fjohanengelen * xttt = s * (s2 * x000 + 2 * st * x001 + t2 * x011) + t * (s2 * x001 + 2 * st * x011 + t2 * x111)
981b809bc6ed10a21e89444d9447e5475801874fjohanengelen * xttt = s3 * x000 + 2 * s2t * x001 + st2 * x011 + s2t * x001 + 2st2 * x011 + t3 * x111
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński * xttt = s3 * x000 + 3s2t * x001 + 3st2 * x011 + t3 * x111
6c3e745a94ef6b25a4ef9f018d350a7535aa45afTed Gould * xttt = s3 * x000 + (1 - s) 3s2 * x001 + (1 - s) * (1 - s) * 3s * x011 + (1 - s) * (1 - s) * (1 - s) * x111
981b809bc6ed10a21e89444d9447e5475801874fjohanengelen * xttt = s3 * x000 + (3s2 - 3s3) * x001 + (3s - 6s2 + 3s3) * x011 + (1 - 2s + s2 - s + 2s2 - s3) * x111
981b809bc6ed10a21e89444d9447e5475801874fjohanengelen * xttt = (x000 - 3 * x001 + 3 * x011 - x111) * s3 +
981b809bc6ed10a21e89444d9447e5475801874fjohanengelen * ( 3 * x001 - 6 * x011 + 3 * x111) * s2 +
981b809bc6ed10a21e89444d9447e5475801874fjohanengelen * ( 3 * x011 - 3 * x111) * s +
981b809bc6ed10a21e89444d9447e5475801874fjohanengelen * xttt' = (3 * x000 - 9 * x001 + 9 * x011 - 3 * x111) * s2 +
981b809bc6ed10a21e89444d9447e5475801874fjohanengelen * ( 6 * x001 - 12 * x011 + 6 * x111) * s +
981b809bc6ed10a21e89444d9447e5475801874fjohanengelen * ( 3 * x011 - 3 * x111)
29684a16b6c92bee28a94fdc2607bcc143950fa8johanengelen * s = (-b +/- sqrt (b * b - 4 * a * c)) / 2 * a;
981b809bc6ed10a21e89444d9447e5475801874fjohanengelen /* s = -c / b */
981b809bc6ed10a21e89444d9447e5475801874fjohanengelen double t = 1.0 - s;
76addc201c409e81eaaa73fe27cc0f79c4db097cKrzysztof Kosiński double xttt = s * s * s * x000 + 3 * s * s * t * x001 + 3 * s * t * t * x011 + t * t * t * x111;
e4369b05aaa20df73a37f4d319ce456865cc74f3Krzysztof Kosiński /* s = (-b +/- sqrt (b * b - 4 * a * c)) / 2 * a; */
e4369b05aaa20df73a37f4d319ce456865cc74f3Krzysztof Kosiński D = b * b - 4 * a * c;
29684a16b6c92bee28a94fdc2607bcc143950fa8johanengelen if (D >= 0.0) {
981b809bc6ed10a21e89444d9447e5475801874fjohanengelen /* Have solution */
981b809bc6ed10a21e89444d9447e5475801874fjohanengelen s = (-b + d) / (2 * a);
981b809bc6ed10a21e89444d9447e5475801874fjohanengelen t = 1.0 - s;
981b809bc6ed10a21e89444d9447e5475801874fjohanengelen xttt = s * s * s * x000 + 3 * s * s * t * x001 + 3 * s * t * t * x011 + t * t * t * x111;
981b809bc6ed10a21e89444d9447e5475801874fjohanengelen s = (-b - d) / (2 * a);
981b809bc6ed10a21e89444d9447e5475801874fjohanengelen t = 1.0 - s;
981b809bc6ed10a21e89444d9447e5475801874fjohanengelen xttt = s * s * s * x000 + 3 * s * s * t * x001 + 3 * s * t * t * x011 + t * t * t * x111;
76addc201c409e81eaaa73fe27cc0f79c4db097cKrzysztof Kosiński a = 3 * y000 - 9 * y001 + 9 * y011 - 3 * y111;
76addc201c409e81eaaa73fe27cc0f79c4db097cKrzysztof Kosiński /* s = -c / b */
76addc201c409e81eaaa73fe27cc0f79c4db097cKrzysztof Kosiński double t = 1.0 - s;
76addc201c409e81eaaa73fe27cc0f79c4db097cKrzysztof Kosiński double yttt = s * s * s * y000 + 3 * s * s * t * y001 + 3 * s * t * t * y011 + t * t * t * y111;
e4369b05aaa20df73a37f4d319ce456865cc74f3Krzysztof Kosiński /* s = (-b +/- sqrt (b * b - 4 * a * c)) / 2 * a; */
76addc201c409e81eaaa73fe27cc0f79c4db097cKrzysztof Kosiński D = b * b - 4 * a * c;
76addc201c409e81eaaa73fe27cc0f79c4db097cKrzysztof Kosiński if (D >= 0.0) {
e4369b05aaa20df73a37f4d319ce456865cc74f3Krzysztof Kosiński /* Have solution */
e4369b05aaa20df73a37f4d319ce456865cc74f3Krzysztof Kosiński s = (-b + d) / (2 * a);
76addc201c409e81eaaa73fe27cc0f79c4db097cKrzysztof Kosiński yttt = s * s * s * y000 + 3 * s * s * t * y001 + 3 * s * t * t * y011 + t * t * t * y111;
981b809bc6ed10a21e89444d9447e5475801874fjohanengelen s = (-b - d) / (2 * a);
00f9ca0b3aa57e09f3c3f3632c5427fc03499df5Krzysztof Kosiński yttt = s * s * s * y000 + 3 * s * s * t * y001 + 3 * s * t * t * y011 + t * t * t * y111;
981b809bc6ed10a21e89444d9447e5475801874fjohanengelenbounds_fast_transformed(Geom::PathVector const & pv, Geom::Affine const & t)
981b809bc6ed10a21e89444d9447e5475801874fjohanengelen return bounds_exact_transformed(pv, t); //use this as it is faster for now! :)
981b809bc6ed10a21e89444d9447e5475801874fjohanengelen// return Geom::bounds_fast(pv * t);
981b809bc6ed10a21e89444d9447e5475801874fjohanengelenbounds_exact_transformed(Geom::PathVector const & pv, Geom::Affine const & t)
981b809bc6ed10a21e89444d9447e5475801874fjohanengelen Geom::Point initial = pv.front().initialPoint() * t;
981b809bc6ed10a21e89444d9447e5475801874fjohanengelen Geom::Rect bbox(initial, initial); // obtain well defined bbox as starting point to unionWith
981b809bc6ed10a21e89444d9447e5475801874fjohanengelen for (Geom::PathVector::const_iterator it = pv.begin(); it != pv.end(); ++it) {
981b809bc6ed10a21e89444d9447e5475801874fjohanengelen // don't loop including closing segment, since that segment can never increase the bbox
981b809bc6ed10a21e89444d9447e5475801874fjohanengelen for (Geom::Path::const_iterator cit = it->begin(); cit != it->end_open(); ++cit) {
981b809bc6ed10a21e89444d9447e5475801874fjohanengelen unsigned order = 0;
981b809bc6ed10a21e89444d9447e5475801874fjohanengelen if (Geom::BezierCurve const* b = dynamic_cast<Geom::BezierCurve const*>(&c)) {
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński // TODO: we can make the case for quadratics faster by degree elevating them to
981b809bc6ed10a21e89444d9447e5475801874fjohanengelen // cubic and then taking the bbox of that.
981b809bc6ed10a21e89444d9447e5475801874fjohanengelen Geom::CubicBezier const &cubic_bezier = static_cast<Geom::CubicBezier const&>(c);
40742313779ee5e43be93a9191f1c86412cf183bKrzysztof Kosiński cubic_bbox(c0[0], c0[1], c1[0], c1[1], c2[0], c2[1], c3[0], c3[1], bbox);
981b809bc6ed10a21e89444d9447e5475801874fjohanengelen // should handle all not-so-easy curves:
981b809bc6ed10a21e89444d9447e5475801874fjohanengelen //return Geom::bounds_exact(pv * t);
63267518b4ce196caab66ef8cbdcfc0921206b3djohanengelengeom_line_wind_distance (Geom::Coord x0, Geom::Coord y0, Geom::Coord x1, Geom::Coord y1, Geom::Point const &pt, int *wind, Geom::Coord *best)
a4030d5ca449e7e384bc699cd249ee704faaeab0Chris Morgan /* Find distance */
if (best) {
if (wind) {
needdist = 0;
needwind = 0;
needline = 0;
if (best) {
geom_cubic_bbox_wind_distance (x000, y000, x00t, y00t, x0tt, y0tt, xttt, yttt, pt, NULL, wind, best, tolerance);
geom_cubic_bbox_wind_distance (xttt, yttt, x1tt, y1tt, x11t, y11t, x111, y111, pt, NULL, wind, best, tolerance);
Geom::Point &p0) // pass p0 through as it represents the last endpoint added (the finalPoint of last curve)
unsigned order = 0;
if (bbox) {
pt,
pathv_matrix_point_bbox_wind_distance (Geom::PathVector const & pathv, Geom::Affine const &m, Geom::Point const &pt,
bool start_set = false;
start_set = true;
if (bbox) {
if (start_set) {
return output;
return output;
// The next routine is modified from curv4_div::recursive_bezier from file agg_curves.cpp
int level)
#define calc_sq_distance(A,B,C,D) ((A-C)*(A-C) + (B-D)*(B-D))
namespace Geom {