Browse Source

Improved matrix transform

tentone 6 năm trước cách đây
mục cha
commit
4166d7bef6

+ 19 - 37
index.html

@@ -9,9 +9,17 @@
 	<script type="text/javascript" src="source/Object2D.js"></script>
 	<script type="text/javascript" src="source/Viewport.js"></script>
 	<script type="text/javascript" src="source/Renderer.js"></script>
-	<script type="text/javascript" src="source/Image.js"></script>
+
+	<script type="text/javascript" src="source/controls/ViewportControls.js"></script>
+
+	<script type="text/javascript" src="source/objects/Image.js"></script>
+	<script type="text/javascript" src="source/objects/Rect.js"></script>
+	<script type="text/javascript" src="source/objects/Text.js"></script>
+	<script type="text/javascript" src="source/objects/Box.js"></script>
+	<script type="text/javascript" src="source/objects/ConnectionLine.js"></script>
 
 	<script type="text/javascript" src="source/math/Vector2.js"></script>
+	<script type="text/javascript" src="source/math/Box2.js"></script>
 	<script type="text/javascript" src="source/math/UUID.js"></script>
 	<script type="text/javascript" src="source/math/Matrix.js"></script>
 
@@ -29,52 +37,26 @@
 		i.scale.set(1, 2);
 		o.add(i);
 
-		//var re = new Rect();
-		//o.add(re);
-
-		var v = new Viewport();
-
-		var pressed = false;
-		var x, y;
-		var dx, dy;
+		var re = new Box();
+		re.position.set(50, 50);
+		o.add(re);
 
-		var m = new EventManager();
-		m.add(canvas, "mousedown", function(event)
-		{
-			pressed = true;
-		});
-		m.add(canvas, "mouseup", function(event)
-		{
-			pressed = false;
-		});
-		m.add(canvas, "mousemove", function(event)
-		{
-			dx = event.clientX - x;
-			dy = event.clientY - y;
-			x = event.clientX;
-			y = event.clientY;
+		var rb = new Box();
+		rb.position.set(50, 300);
+		o.add(rb);
 
-			if(pressed)
-			{
-				v.position.x += dx;
-				v.position.y += dy;
-			}
-		});
-		m.add(canvas, "wheel", function(event)
-		{
-			v.scale -= (event.deltaY * 0.001) * v.scale;
-		});
-		m.create();
+		var v = new Viewport();
 
+		var c = new ViewportControls(v);
+		c.create();
 
 		var r = new Renderer(canvas);
 
 		function loop()
 		{
 			i.rotation += 0.01;
-			//re.rotation -= 0.005;
+			re.rotation -= 0.005;
 
-			//o.draw(context, canvas);
 			r.render(o, v)
 			requestAnimationFrame(loop);
 		}

+ 5 - 1
source/Object2D.js

@@ -98,10 +98,14 @@ Object2D.prototype.remove = function(object)
 	}
 };
 
+Object2D.prototype.onPressDown = function(point){};
+Object2D.prototype.onPressUp = function(point){};
+Object2D.prototype.onOver = function(point){};
+
 /**
  * Check if a point is inside of the object.
  */
-Object2D.prototype.isInside = function(point)
+Object2D.prototype.inside = function(point)
 {
 	return false;
 };

+ 60 - 0
source/controls/ViewportControls.js

@@ -0,0 +1,60 @@
+"use strict";
+
+function ViewportControls(viewport)
+{
+	this.viewport = viewport;
+
+	var pressed = -1;
+	var x = 0, y = 0;
+	var dx = 0, dy = 0;
+
+	var self = this;
+	
+	this.manager = new EventManager();
+
+	this.manager.add(canvas, "contextmenu", function(event)
+	{
+		event.preventDefault();
+		return false;
+	});
+
+	this.manager.add(canvas, "mousedown", function(event)
+	{
+		pressed = event.which;
+	});
+
+	this.manager.add(canvas, "mouseup", function(event)
+	{
+		pressed = -1;
+	});
+	
+	this.manager.add(canvas, "mousemove", function(event)
+	{
+		dx = event.clientX - x;
+		dy = event.clientY - y;
+		x = event.clientX;
+		y = event.clientY;
+
+		// Mouse
+		if(pressed === 3)
+		{
+			self.viewport.position.x += dx;
+			self.viewport.position.y += dy;
+		}
+	});
+
+	this.manager.add(canvas, "wheel", function(event)
+	{
+		self.viewport.scale -= (event.deltaY * 0.001) * self.viewport.scale;
+	});
+}
+
+ViewportControls.prototype.create = function()
+{
+	this.manager.create();
+};
+
+ViewportControls.prototype.destroy = function()
+{
+	this.manager.destroy();
+};

+ 175 - 0
source/math/Box2.js

@@ -0,0 +1,175 @@
+"use strict";
+
+function Box2(min, max)
+{
+	this.min = (min !== undefined) ? min : new Vector2();
+	this.max = (max !== undefined) ? max : new Vector2();
+}
+
+Object.assign(Box2.prototype,
+{
+	set: function(min, max)
+	{
+		this.min.copy(min);
+		this.max.copy(max);
+
+		return this;
+	},
+
+	setFromPoints: function(points)
+	{
+		this.min = new Vector2(+Infinity, +Infinity);
+		this.max = new Vector2(-Infinity, -Infinity);
+
+		for(var i = 0, il = points.length; i < il; i++)
+		{
+			this.expandByPoint(points[i]);
+		}
+
+		return this;
+	},
+
+	setFromCenterAndSize: function()
+	{
+		var v1 = new Vector2();
+
+		return function setFromCenterAndSize(center, size)
+		{
+			var halfSize = v1.copy(size).multiplyScalar(0.5);
+			this.min.copy(center).sub(halfSize);
+			this.max.copy(center).add(halfSize);
+
+			return this;
+		};
+	}(),
+
+	clone: function()
+	{
+		var box = new Box2();
+		box.copy(this);
+		return box;
+	},
+
+	copy: function(box)
+	{
+		this.min.copy(box.min);
+		this.max.copy(box.max);
+
+		return this;
+	},
+
+
+	isEmpty: function()
+	{
+		// this is a more robust check for empty than ( volume <= 0 ) because volume can get positive with two negative axes
+		return (this.max.x < this.min.x) || (this.max.y < this.min.y);
+	},
+
+	getCenter: function(target)
+	{
+		return this.isEmpty() ? target.set(0, 0) : target.addVectors(this.min, this.max).multiplyScalar(0.5);
+	},
+
+	getSize: function(target)
+	{
+		return this.isEmpty() ? target.set(0, 0) : target.subVectors(this.max, this.min);
+	},
+
+	expandByPoint: function(point)
+	{
+		this.min.min(point);
+		this.max.max(point);
+
+		return this;
+	},
+
+	expandByVector: function(vector)
+	{
+		this.min.sub(vector);
+		this.max.add(vector);
+
+		return this;
+	},
+
+	expandByScalar: function(scalar)
+	{
+		this.min.addScalar(-scalar);
+		this.max.addScalar(scalar);
+
+		return this;
+	},
+
+	containsPoint: function(point)
+	{
+		return point.x < this.min.x || point.x > this.max.x || point.y < this.min.y || point.y > this.max.y ? false : true;
+	},
+
+	containsBox: function(box)
+	{
+		return this.min.x <= box.min.x && box.max.x <= this.max.x && this.min.y <= box.min.y && box.max.y <= this.max.y;
+	},
+
+	getParameter: function(point, target)
+	{
+		// This can potentially have a divide by zero if the box
+		// has a size dimension of 0.
+
+		return target.set(
+			(point.x - this.min.x) / (this.max.x - this.min.x),
+			(point.y - this.min.y) / (this.max.y - this.min.y)
+		);
+	},
+
+	intersectsBox: function(box)
+	{
+		// using 4 splitting planes to rule out intersections
+		return box.max.x < this.min.x || box.min.x > this.max.x || box.max.y < this.min.y || box.min.y > this.max.y ? false : true;
+	},
+
+	clampPoint: function(point, target)
+	{
+		return target.copy(point).clamp(this.min, this.max);
+	},
+
+	distanceToPoint: function()
+	{
+		var v1 = new Vector2();
+
+		return function distanceToPoint(point)
+		{
+			var clampedPoint = v1.copy(point).clamp(this.min, this.max);
+			return clampedPoint.sub(point).length();
+		};
+	}(),
+
+	intersect: function(box)
+	{
+		this.min.max(box.min);
+		this.max.min(box.max);
+
+		return this;
+	},
+
+	union: function(box)
+	{
+		this.min.min(box.min);
+		this.max.max(box.max);
+
+		return this;
+	},
+
+	translate: function(offset)
+	{
+		this.min.add(offset);
+		this.max.add(offset);
+
+		return this;
+	},
+
+	equals: function(box)
+	{
+		return box.min.equals(this.min) && box.max.equals(this.max);
+	}
+});
+
+//export {Box2};

+ 47 - 23
source/math/Matrix.js

@@ -33,12 +33,12 @@ Matrix.prototype.reset = function()
  */
 Matrix.prototype.multiply = function(mat)
 {
-	var m0 = this.m[0] * mat[0] + this.m[2] * mat[1];
-	var m1 = this.m[1] * mat[0] + this.m[3] * mat[1];
-	var m2 = this.m[0] * mat[2] + this.m[2] * mat[3];
-	var m3 = this.m[1] * mat[2] + this.m[3] * mat[3];
-	var m4 = this.m[0] * mat[4] + this.m[2] * mat[5] + this.m[4];
-	var m5 = this.m[1] * mat[4] + this.m[3] * mat[5] + this.m[5];
+	var m0 = this.m[0] * mat.m[0] + this.m[2] * mat.m[1];
+	var m1 = this.m[1] * mat.m[0] + this.m[3] * mat.m[1];
+	var m2 = this.m[0] * mat.m[2] + this.m[2] * mat.m[3];
+	var m3 = this.m[1] * mat.m[2] + this.m[3] * mat.m[3];
+	var m4 = this.m[0] * mat.m[4] + this.m[2] * mat.m[5] + this.m[4];
+	var m5 = this.m[1] * mat.m[4] + this.m[3] * mat.m[5] + this.m[5];
 	
 	this.m = [m0, m1, m2, m3, m4, m5];
 };
@@ -50,12 +50,12 @@ Matrix.prototype.multiply = function(mat)
  */
 Matrix.prototype.premultiply = function(mat)
 {
-	var m0 = mat[0] * this.m[0] + mat[2] * this.m[1];
-	var m1 = mat[1] * this.m[0] + mat[3] * this.m[1];
-	var m2 = mat[0] * this.m[2] + mat[2] * this.m[3];
-	var m3 = mat[1] * this.m[2] + mat[3] * this.m[3];
-	var m4 = mat[0] * this.m[4] + mat[2] * this.m[5] + mat[4];
-	var m5 = mat[1] * this.m[4] + mat[3] * this.m[5] + mat[5];
+	var m0 = mat.m[0] * this.m[0] + mat.m[2] * this.m[1];
+	var m1 = mat.m[1] * this.m[0] + mat.m[3] * this.m[1];
+	var m2 = mat.m[0] * this.m[2] + mat.m[2] * this.m[3];
+	var m3 = mat.m[1] * this.m[2] + mat.m[3] * this.m[3];
+	var m4 = mat.m[0] * this.m[4] + mat.m[2] * this.m[5] + mat.m[4];
+	var m5 = mat.m[1] * this.m[4] + mat.m[3] * this.m[5] + mat.m[5];
 	
 	this.m = [m0, m1, m2, m3, m4, m5];
 };
@@ -69,7 +69,7 @@ Matrix.prototype.compose = function(px, py, sx, sy, a)
 
 	var c = Math.cos(a);
 	var s = Math.sin(a);
-	this.multiply([c, s, -s, c, 0, 0]);
+	this.multiply(new Matrix([c, s, -s, c, 0, 0]));
 
 	this.scale(sx, sy);
 };
@@ -79,7 +79,8 @@ Matrix.prototype.compose = function(px, py, sx, sy, a)
  */
 Matrix.prototype.translate = function(x, y)
 {
-	this.multiply([1, 0, 0, 1, x, y]);
+	this.m[4] += this.m[0] * x + this.m[2] * y;
+	this.m[5] += this.m[1] * x + this.m[3] * y;
 };
 
 /**
@@ -87,21 +88,30 @@ Matrix.prototype.translate = function(x, y)
  *
  * @param angle Angle in radians.
  */
-Matrix.prototype.rotate = function(angle)
+Matrix.prototype.rotate = function(rad)
 {
-	var c = Math.cos(angle);
-	var s = Math.sin(angle);
-	var mat = [c, s, -s, c, 0, 0];
-
-	this.multiply(mat);
+	var c = Math.cos(rad);
+	var s = Math.sin(rad);
+
+	var m11 = this.m[0] * c + this.m[2] * s;
+	var m12 = this.m[1] * c + this.m[3] * s;
+	var m21 = this.m[0] * -s + this.m[2] * c;
+	var m22 = this.m[1] * -s + this.m[3] * c;
+	this.m[0] = m11;
+	this.m[1] = m12;
+	this.m[2] = m21;
+	this.m[3] = m22;
 };
 
 /**
  * Apply scale to this matrix.
  */
-Matrix.prototype.scale = function(x, y)
+Matrix.prototype.scale = function(sx, sy)
 {
-	this.multiply([x, 0, 0, y, 0, 0]);
+	this.m[0] *= sx;
+	this.m[1] *= sx;
+	this.m[2] *= sy;
+	this.m[3] *= sy;
 };
 
 /**
@@ -109,7 +119,7 @@ Matrix.prototype.scale = function(x, y)
  */
 Matrix.prototype.skew = function(radianX, radianY)
 {
-	this.multiply([1, Math.tan(radianY), Math.tan(radianX), 1, 0, 0]);
+	this.multiply(new Matrix([1, Math.tan(radianY), Math.tan(radianX), 1, 0, 0]));
 };
 
 /**
@@ -145,3 +155,17 @@ Matrix.prototype.tranformContext = function(context)
 {
 	context.transform(this.m[0], this.m[1], this.m[2], this.m[3], this.m[4], this.m[5]);
 };
+
+/**
+ * Transform a point using this matrix.
+ */
+Matrix.prototype.transformPoint = function(px, py)
+{
+	var x = px;
+	var y = py;
+
+	px = x * this.m[0] + y * this.m[2] + this.m[4];
+	py = x * this.m[1] + y * this.m[3] + this.m[5];
+
+	return new Vector2(px, py);
+};

+ 22 - 0
source/objects/Box.js

@@ -0,0 +1,22 @@
+"use strict";
+
+function Box(src)
+{
+	Object2D.call(this);
+
+	this.width = 100;
+
+	this.height = 70;
+}
+
+Box.prototype = Object.create(Object2D.prototype);
+
+Box.prototype.draw = function(context)
+{
+	var halfWidth = this.width / 2.0;
+	var halfHeight = this.height / 2.0;
+
+	context.lineWidth = 2;
+	context.strokeStyle = "#000000";
+	context.strokeRect(-halfWidth, -halfHeight, this.width, this.height);
+};

+ 13 - 0
source/objects/ConnectionLine.js

@@ -0,0 +1,13 @@
+"use strict";
+
+function ConnectionLine(src)
+{
+	Object2D.call(this);
+}
+
+ConnectionLine.prototype = Object.create(Object2D.prototype);
+
+ConnectionLine.prototype.draw = function(context)
+{
+	//TODO
+};

+ 0 - 0
source/Image.js → source/objects/Image.js


+ 0 - 0
source/Rect.js → source/objects/Rect.js


+ 0 - 0
source/Text.js → source/objects/Text.js