# HG changeset patch # User David Bryant # Date 1251612132 -34200 # Node ID c2f11e1d7470782412c510db55c605b2fd1a4160 # Parent 157b4ad5615dd6f3fa4680e39f8ddf283471e933 Geometry cleanup and checkpoint. diff -r 157b4ad5615d -r c2f11e1d7470 doodle/dia/grid_layer.d --- a/doodle/dia/grid_layer.d Sun Aug 30 01:34:14 2009 +0930 +++ b/doodle/dia/grid_layer.d Sun Aug 30 15:32:12 2009 +0930 @@ -10,6 +10,7 @@ } interface Grid { + //void zoom_changed(); } class GridLayer : Layer, Grid { diff -r 157b4ad5615d -r c2f11e1d7470 doodle/dia/icanvas.d --- a/doodle/dia/icanvas.d Sun Aug 30 01:34:14 2009 +0930 +++ b/doodle/dia/icanvas.d Sun Aug 30 15:32:12 2009 +0930 @@ -17,6 +17,8 @@ void zoom_relative(in Point pixel_datum, in double factor); void pan_relative(in Vector pixel_displacement); void set_cursor(in Cursor cursor); + + // FIXME get rid of these and accumulate damage during event handling void damage_model(in Rectangle area); // FIXME could be an inout parameter of the event handling, or a special scope Damage object that supports growth only void damage_pixel(in Rectangle area); // FIXME as above diff -r 157b4ad5615d -r c2f11e1d7470 doodle/dia/standard_tools.d --- a/doodle/dia/standard_tools.d Sun Aug 30 01:34:14 2009 +0930 +++ b/doodle/dia/standard_tools.d Sun Aug 30 15:32:12 2009 +0930 @@ -105,7 +105,7 @@ override bool handle_button_release(scope Viewport viewport, in ButtonEvent event) { if (event.button_name == ButtonName.LEFT && mActive) { mActive = false; - viewport.damage_pixel(Rectangle(mAnchorPoint, mCurrentPoint).feathered(LINE_WIDTH / 2.0)); + viewport.damage_pixel(feather(Rectangle(mAnchorPoint, mCurrentPoint), LINE_WIDTH / 2.0)); viewport.set_cursor(Cursor.DEFAULT); return true; } @@ -116,9 +116,9 @@ override bool handle_motion(scope Viewport viewport, in MotionEvent event) { if (mActive) { - viewport.damage_pixel(Rectangle(mAnchorPoint, mCurrentPoint).feathered(LINE_WIDTH / 2.0)); + viewport.damage_pixel(feather(Rectangle(mAnchorPoint, mCurrentPoint), LINE_WIDTH / 2.0)); mCurrentPoint = event.pixel_point; - viewport.damage_pixel(Rectangle(mAnchorPoint, mCurrentPoint).feathered(LINE_WIDTH / 2.0)); + viewport.damage_pixel(feather(Rectangle(mAnchorPoint, mCurrentPoint), LINE_WIDTH / 2.0)); } return false; diff -r 157b4ad5615d -r c2f11e1d7470 doodle/gtk/canvas.d --- a/doodle/gtk/canvas.d Sun Aug 30 01:34:14 2009 +0930 +++ b/doodle/gtk/canvas.d Sun Aug 30 15:32:12 2009 +0930 @@ -191,7 +191,7 @@ assert(layer_bounds.valid); - mCanvasBounds = layer_bounds.moved(-layer_bounds.size).expanded(2.0 * layer_bounds.size); + mCanvasBounds = expand(move(layer_bounds, -layer_bounds.size), 2.0 * layer_bounds.size); mViewCentre = mCanvasBounds.centre; mHadConfigure = true; diff -r 157b4ad5615d -r c2f11e1d7470 doodle/tk/geometry.d --- 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; +} ++/