Mercurial > projects > doodle
view 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 source
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))); }