multiple-art-days
clone your own copy | download snapshot

Snapshots | iceberg

Inside this repository

geom.js
application/javascript

Download raw (3.1 KB)

'use strict';

var Geom, Point, Path, Segment;

Math.rad2deg = function rad2deg(rad){
	return rad * (180 / Math.PI);
}

Math.deg2rad = function deg2rad(deg){
	return deg * (Math.PI / 180);
}

Geom = {
	distance: function distance (a, b) {
		var dx, dy;
		dx = a.x - b.x;
		dy = a.y - b.y
		return Math.sqrt(dx*dx + dy*dy);
	},
	
	_at: function (p1, p2, t) {
		return (1 - t) * p1 + t * p2;
	},
	
	at: function (p1, p2, t) {
		return new Point(
			Geom._at(p1.x, p2.x, t),
			Geom._at(p1.y, p2.y, t)
		);
	},
};

Point = function (x,y) {
	if (arguments.length == 2) {
		this.x = x;
		this.y = y;
	} else if (x && 'x' in x) {
		this.x = x.x;
		this.y = x.y;
	} else if (x && x.length > 1) {
		this.x = x[0];
		this.y = x[1];
	}
	
	return this;
};
	
Path = function (points) {
	this._segments = [];
	if (points) this.add(points);
	return this;
};

_.extend(Path.prototype, {
	add: function (point) {
		if (_.isArray(point)) {
			var points = point;
			for (var i=0;i<points.length;i++){
				this.add(points[i]); 
			}
		} else {
			if (this._segments.length == 0) {
				this._segments.push({
					start: -1,
					end: -1,
					segment: new Segment(point),
				});
			} else {
				if (this._segments.length == 1
					&& !this._segments[0].segment.p2) {
					this._segments[0].segment.p2 = point;
					this._length = this._segments[0].segment.length();
					this._updateIndex();
				} else {
					var p1 = _.last(this._segments).segment.p2;
					var segment = new Segment(p1, point);
					this._segments.push({start: -1, end: -1, segment: segment});
					this._length += segment.length();
					this._updateIndex();
				}
			}
		}
	},
	
	_updateIndex: function () {
		var offset = 0;
		
		_.each(this._segments, function (segment) {
			segment.start = offset;
			offset += (segment.segment.length() / this.length());
			segment.end = offset;
		}, this);
	},
	
	// calculates the lenght of the path
	length: function () {
		return this._length;
	},
	
	// Calculates point on line, goes live through all segments
	// so might be a bit slow
	at: function (t) {
		var segment = this._at(t);
		return segment.segment.at((t - segment.start) / (segment.end - segment.start));
	},
	
	angle: function (t) {
		return this.segment(t).angle();
	},
	
	segment: function (t) {
		return this._at(t).segment;
	},
	
	_at: function (t) {
		var at;
		
		_.each(this._segments, function(segment) {
			if (segment.start <= t 
				&& segment.end > t) {
				at = segment;
			}
		});
		
		if (!at) at = _.last(this._segments);
		
		return at;
	},
});

Segment = function (p1,p2) {
	var p1, p2;
	
	this.p1 = p1;
	this.p2 = p2;
	
	if (p1) {
		this.p1 = new Point(p1);
		
		if (p2) {
			this.p2 = new Point(p2);
		}
	}
	
	return this;
};

_.extend(Segment.prototype, {
	length: function () {
		return Geom.distance(this.p1, this.p2);
	},
		
	at: function (t) {
		return Geom.at(this.p1, this.p2, t);
	},
	
	angle: function () {
		if (this.p2.x < this.p1.x) {
			return Math.PI + Math.atan((this.p2.y - this.p1.y) / (this.p2.x - this.p1.x));
		} else {
			return Math.atan((this.p2.y - this.p1.y) / (this.p2.x - this.p1.x));
		}
	},
});


var point = function (x,y) {
	return new Point(x, y);
};