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)));
}