Mercurial > projects > doodle
diff import/geometry.d @ 0:e907d2c54ec3
Initial import
author | David Bryant <daveb@acres.com.au> |
---|---|
date | Wed, 13 May 2009 15:42:39 +0930 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/import/geometry.d Wed May 13 15:42:39 2009 +0930 @@ -0,0 +1,220 @@ +module interaction.geometry; + +private import std.math; + +private const double EPSILON = 1e-20; + +final class Point { + this() { + this(0.0, 0.0); + } + + this(double x, double y) { + _x = x; + _y = y; + } + + char[] toString() { + return "(" ~ std.string.toString(_x) ~ ", " ~ std.string.toString(_y) ~ ")"; + } + + Point opAdd(in Vector v) { + return new Point(_x + v._x, _y + v._y); + } + + Vector opSub(in Point p) { + return new Vector(_x - p._x, _y - p._y); + } + + double x() { return _x; } + double y() { return _y; } + + private { + double _x; + double _y; + } +} + +// + +final class Vector { + this() { + this(0.0, 0.0); + } + + this(double x, double y) { + _x = x; + _y = y; + } + + char[] toString() { + return "[" ~ std.string.toString(_x) ~ ", " ~ std.string.toString(_y) ~ "]"; + } + + Vector opAdd(in Vector v) { + return new Vector(_x + v._x, _y + v._y); + } + + Vector opSub(in Vector v) { + return new Vector(_x - v._x, _y - v._y); + } + + Vector opNeg() { + return new Vector(-_x, -_y); + } + + Vector opMul_r(double d) { + return new Vector(d * _x, d * _y); + } + + double length() { + return sqrt(_x * _x + _y * _y); + } + + bool has_length() { + return _x * _x + _y * _y > EPSILON * EPSILON; + } + + double x() { return _x; } + double y() { return _y; } + + private { + double _x; + double _y; + } +} + +// + +final class Segment { + this() { + } + + this(Point start, Point end) { + _start = start; + _end = end; + } + + Point start() { return _start; } + Point end() { return _end; } + + private { + Point _start; + Point _end; + } +} + +// + +final class Line { + this() { + } + + this(Point point, Vector vector) { + assert(vector.has_length); + _point = point; + _vector = vector; + } + + this(Point point1, Point point2) { + _point = point1; + _vector = point2 - point1; + assert(_vector.has_length); + } + + private { + Point _point; + Vector _vector; + } +} + +// + +final class Rectangle { + this() { + this(0.0, 0.0, 0.0, 0.0); + } + + this(double x, double y, double w, double h) { + assert(w >= 0.0); + assert(h >= 0.0); + _x = x; + _y = y; + _w = w; + _h = h; + } + + double x() { return _x; } + double y() { return _y; } + double w() { return _w; } + double h() { return _h; } + double xw() { return _x + _w; } + double yh() { return _y + _h; } + + /* + Point corner00() { return new Point(_x, _y ); } + Point corner10() { return new Point(_x + _w, _y ); } + Point corner11() { return new Point(_x + _w, _y + _h); } + Point corner01() { return new Point(_x, _y + _h); } + + Point centre() { return new Point(_x + _w / 2.0, _y + _h / 2.0); } + */ + + double area() { + return _w * _h; + } + + bool has_area() { + return area > 0.0; + } + + bool contains(Point point) { + return point.x > x && point.x < xw & point.y > y && point.y < xy; + } + + bool contains(Segment segment) { + return contains(segment.start, segment.end); + } + + private double _x, _y, _w, _h; +} + +unittest { + const double absdiff = 1e-20, reldiff= 1e-20; + + bool cmpdouble(in double lhs, in double rhs) { + double adiff = fabs(rhs - lhs); + + if (adiff < absdiff && adiff > -absdiff) { + return true; + } + + if (fabs(lhs) > absdiff && fabs(rhs) > absdiff) { + double rdiff = rhs / lhs; + + if (rdiff < (1.0 + reldiff) && rdiff > 1.0 / (1.0 + reldiff)) { + return true; + } + } + + // They must differ significantly + + return false; + } + + bool cmpvector(in Vector lhs, in Vector rhs) { + return cmpdouble(lhs._x, rhs._x) && cmpdouble(lhs._y, rhs._y); + } + + bool cmppoint(in Point lhs, in Point rhs) { + return cmpdouble(lhs._x, rhs._x) && cmpdouble(lhs._y, rhs._y); + } + + assert(cmpvector(new Vector(0.0, 0.0), new Vector)); + assert(!cmpvector(new Vector(0.0, 1e-10), new Vector)); + assert(cmpvector(new Vector(1.0, 2.0) + new Vector(3.0, 4.0), new Vector(4.0, 6.0))); + assert(cmpvector(new Vector(1.0, 2.0) - new Vector(3.0, 4.0), new Vector(-2.0, -2.0))); + assert(cmpvector(-(new Vector(1.0, 2.0)), new Vector(-1.0, -2.0))); + assert(cmpdouble((new Vector(3.0, 4.0)).length(), 5.0)); + assert(cmpvector(3.0 * (new Vector(3.0, 4.0)), new Vector(9.0, 12.0))); +}