changeset 34:c2f11e1d7470

Geometry cleanup and checkpoint.
author David Bryant <bagnose@gmail.com>
date Sun, 30 Aug 2009 15:32:12 +0930
parents 157b4ad5615d
children 3f6bb0bb22dc
files doodle/dia/grid_layer.d doodle/dia/icanvas.d doodle/dia/standard_tools.d doodle/gtk/canvas.d doodle/tk/geometry.d
diffstat 5 files changed, 126 insertions(+), 51 deletions(-) [+]
line wrap: on
line diff
--- 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 {
--- 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
 
--- 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;
--- 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;
--- 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;
+}
++/