Mercurial > projects > doodle
diff doodle/tk/geometry.d @ 34:c2f11e1d7470
Geometry cleanup and checkpoint.
author | David Bryant <bagnose@gmail.com> |
---|---|
date | Sun, 30 Aug 2009 15:32:12 +0930 |
parents | 157b4ad5615d |
children | 1f97022e5c6d |
line wrap: on
line diff
--- a/doodle/tk/geometry.d Sun Aug 30 01:34:14 2009 +0930 +++ b/doodle/tk/geometry.d Sun Aug 30 15:32:12 2009 +0930 @@ -14,9 +14,13 @@ // // Explain how numerical instability is handled. The current policy // is to correct bad user input (eg a gradient with miniscule length) and -// print warnings rather than have assertions and cause crashes. +// print warnings rather than have assertions that cause crashes. +// +// There are no mutating operations other than opAssign +// // A location in 2D space +// struct Point { static immutable Point DEFAULT; @@ -62,7 +66,9 @@ return Point(max(a.x, b.x), max(a.y, b.y)); } +// // The displacement between two locations in 2D space +// struct Vector { static Vector DEFAULT; @@ -112,10 +118,24 @@ } } +Vector normalise(in Vector v) { + double l = v.length; + + if (l < 1e-9) { // TODO consolidate numerical stability constants + writefln("Warning: normalising tiny vector. Length: %f", l); + return Vector(1.0, 0.0); + } + else { + return v / l; + } +} + +// // A rectangle in 2D space. // Internally represented by: // a point defining the bottom left corner // a vector defining the displacement to the upper right corner +// struct Rectangle { static Rectangle DEFAULT; @@ -182,42 +202,10 @@ } } - // TODO review these functions. - // Want a clear and simple set. - // Consider making them free functions - - Rectangle moved(in Vector displacement) const { - return Rectangle(_position + displacement, _size); - } - - Rectangle repositioned(in Point new_position) const { - return Rectangle(new_position, _size); - } - - // Operations about the bottom left corner - - Rectangle expanded(in Vector expand_amount) const { - return Rectangle(_position, _size + expand_amount); - } - - Rectangle shrunk(in Vector shrink_amount) const { - return Rectangle(_position, _size - shrink_amount); - } - - // Operations about the centre - - Rectangle feathered(double amount) const { - assert(amount >= 0.0); - return Rectangle(Point(_position.x - amount, _position.y - amount), - Vector(_size.x + 2.0 * amount, _size.y + 2.0 * amount)); - } - - Rectangle resized(in Vector new_size) const { - return Rectangle(_position, new_size); - } - // + // FIXME this method is all about pixels. Not sure it belongs in + // this file, let alone this class. void get_quantised(out int x, out int y, out int w, out int h) const { x = cast(int)floor(_position.x); y = cast(int)floor(_position.y); @@ -246,15 +234,47 @@ } } +// TODO review these functions. +// Want a clear and simple set. + +Rectangle move(in Rectangle r, in Vector displacement) { + return Rectangle(r.position + displacement, r.size); +} + +Rectangle reposition(in Rectangle r, in Point new_position) { + return Rectangle(new_position, r.size); +} + +// Operations about the bottom left corner + +Rectangle expand(in Rectangle r, in Vector expand_amount) { + return Rectangle(r.position, r.size + expand_amount); +} + +Rectangle shrink(in Rectangle r, in Vector shrink_amount) { + return Rectangle(r.position, r.size - shrink_amount); +} + +// Operations about the centre + +Rectangle feather(in Rectangle r, double amount) { + assert(amount >= 0.0); + return Rectangle(Point(r.position.x - amount, r.position.y - amount), + Vector(r.size.x + 2.0 * amount, r.size.y + 2.0 * amount)); +} + +Rectangle resize(in Rectangle r, in Vector new_size) { + return Rectangle(r.position, new_size); +} + private { // This is a commmon building block for intersection of lines and segments - // Two lines "a" and "b" are defined by two points each - // "ua" and "ub" define the intersection as a fraction alone + // Two lines "a" and "b" are defined by two points each . + // "ua" and "ub" define the intersection as a fraction along // the two respetive line segments (FIXME this comment sucks) // Influenced by http://ozviz.wasp.uwa.edu.au/~pbourke/geometry/lineline2d/ bool compute_intersection(in Point pa1, in Point pa2, out double ua, in Point pb1, in Point pb2, out double ub) { - //writefln("pa1: %s, pa2: %s, pb1: %s, pb2: %s", pa1, pa2, pb1, pb2); double den = (pb2.y - pb1.y) * (pa2.x - pa1.x) - (pb2.x - pb1.x) * (pa2.y - pa1.y); if (abs(den) < 1e-9) { // TODO consolidate constants used for numerical stability @@ -270,29 +290,23 @@ ua = num_a / den; ub = num_b / den; - { - // FIXME remove this debugging stuff - //writefln("ua: %s, ub: %s", ua, ub); - Point pa = pa1 + ua * (pa2 - pa1); - Point pb = pb1 + ub * (pb2 - pb1); - //writefln("pa: %s, pb: %s", pa, pb); - assert(pa1 + ua * (pa2 - pa1) == pb1 + ub * (pb2 - pb1)); - } - return true; } } } +// // A line (notionally infinitely extending in both directions) in 2D space. // Internally represented by: // a point at an arbitrary location along the line // a vector defining the gradient of the line +// struct Line { this(in Point p, in Vector g) { _point = p; _gradient = g; + // FIXME should we normalise (make unit length) the gradient? assert(_gradient.length > 1e-6); // FIXME how to best deal with this } @@ -305,6 +319,10 @@ Point point() const { return _point; } Vector gradient() const { return _gradient; } + string toString() const { + return std.string.format("{%s %s}", _point, _gradient); + } + private { Point _point; // Arbitrary point along line Vector _gradient; @@ -317,6 +335,7 @@ Point pa = a.point; Vector va = a.gradient; double ua; + Point pb = b.point; Vector vb = b.gradient; double ub; @@ -332,7 +351,9 @@ } } +// // A line segment (has a beginning and an end) in 2D space. +// struct Segment { this(in Point a, in Point b) { @@ -343,15 +364,24 @@ Point begin() const { return _begin; } Point end() const { return _end; } + string toString() const { + return std.string.format("{%s %s}", _begin, _end); + } + private { Point _begin, _end; } } +Segment reverse(in Segment s) { + return Segment(s.end, s.begin); +} + bool intersection(in Segment a, in Segment b, out Point p) { Point pa1 = a.begin; Point pa2 = a.end; double ua; + Point pb1 = b.begin; Point pb2 = b.end; double ub; @@ -372,3 +402,45 @@ return false; } } + +bool intersection(in Segment a, in Line b, out Point p) { + Point pa1 = a.begin; + Point pa2 = a.end; + double ua; + + Point pb = b.point; + Vector vb = b.gradient; + double ub; + + if (compute_intersection(pa1, pa2, ua, pb, pb + vb, ub)) { + if (ua >= 0.0 && ua <= 1.0) { // inside of segment + // We could just have easily evaluated for line b... + p = pa1 + ua * (pa2 - pa1); + // p = pb + ub * vb; + return true; + } + else { + return false; + } + } + else { + return false; + } +} + +bool intersection(in Line a, in Segment b, out Point p) { + // Equivalent to intersection of segment and line. Just reverse the args. + return intersection(b, a, p); +} + +/+ +bool intersection(in Line l, in Rectangle r, out Point p1, out Point p2) { + // TODO + return false; +} + +bool intersection(in Segment s, in Rectangle r, out Point p1, out Point p2) { + // TODO + return false; +} ++/