08
for starters, we have to be able to communicate exactly what numbers a range may include or exclude.
fortunately, mathematicians have worked this out for us. they call it interval notation. it uses brackets
([ ]), parentheses (( )) and two numbers separated by a comma.
the numbers are the edges of the range (a.k.a. interval), and the smaller one comes first. if it's part of the range, it is enclosed
in a square bracket ([—inclusive). if the range starts immediately after the number,
it is enclosed in a parenthesis ((—exclusive). the same goes for the larger number,
if it's included in the range, it is enclosed in a square bracket (]—inclusive).
if the range ends immediately before the second number, it is enclosed in a parenthesis
()—exclusive). some examples:
[0,1) includes all numbers ≥ 0 and < 1[-1,1] includes all numbers ≥ -1 and ≤ 1(0,10] includes all numbers > 0 and ≤ 10
also, we can say a variable is in a range with the ‘element of’ operator: ∈,
e.g.: x ∈ [0,1).
so how can we map one range to another? it all boils down to a combination of sliding the brackets along the
number line with the + or - operators, and changing the distance between the brackets
with the * and / operators.
even though there are an infinite number of values contained in any given range, by the very definition of the number line we know that all those values will always be between the ends of the range. so if we just concentrate on operations that put the ends where we need them, we can rest assured that the values in between will follow. let's look at some examples:
[5,10] → [7,12] x// x ∈ [5,10]x += 2;// x ∈ [7,12]
[5,10] → [25,45] x// x ∈ [5,10]x *= 4;// x ∈ [20,40]x += 5;// x ∈ [25,45]
[50,99] → [-5,3] x// x ∈ [50,99]x -= 50;// x ∈ [0,49]x /= 49;// x ∈ [0,1]x *= 8;// x ∈ [0,8]x -= 5;// x ∈ [-5,3]
the range [0,1] is a special and very handy one. because of the unique multiplicative properties
of zero, the low end becomes an anchor point for multiplication and division operations.
only the high end bracket moves. this makes it the perfect intermediate range, as it can easily be stretched to
the correct magnitude, and then slid to the correct position on the numberline.
by mastering simple transformations of the numberline, we gain control over visual transformations as well.
import flash.display.Graphics;
var P1:Point = new Point(.4, .2);
var P2:Point = new Point(.4, .8);
var shift:Number = .15;
function drawLine(g:Graphics, p1:Point, p2:Point, weight:Number=1, alpha:Number=1, color:uint=0x000000):void {
var w:Number = stage.stageWidth;
var h:Number = stage.stageHeight;
g.lineStyle(weight, color, alpha);
g.moveTo(P1.x*w, P1.y*h);
g.lineTo(P2.x*w, P2.y*h);
}
// original
drawLine(graphics, P1, P2, 4, .3);
one coordinate of one endpoint
// shift P1 x P1.x += shift; drawLine(graphics, P1, P2, 4, .6);same coordinate of both endpoints
// P1 x and P2 x both shifted P2.x += shift; drawLine(graphics, P1, P2, 4, 1);
(0, 0).
(x * .5) == (x / 2) (x * 0) == 0some initial setup (set your canvas to a square dimension to make the results more intuitive)
import flash.display.Graphics;
var P1:Point = new Point(.2, .6);
var P2:Point = new Point(.6, .2);
var scale:Number;
function drawLine(g:Graphics, p1:Point, p2:Point, weight:Number=1, alpha:Number=1, color:uint=0x000000):void {
var w:Number = stage.stageWidth;
var h:Number = stage.stageHeight;
g.lineStyle(weight, color, alpha);
g.moveTo(P1.x*w, P1.y*h);
g.lineTo(P2.x*w, P2.y*h);
}
// original
drawLine(graphics, P1, P2, 4, .3);
scaling
// scale down (towards origin) scale = .5; P1.x *= scale; P1.y *= scale; P2.x *= scale; P2.y *= scale; drawLine(graphics, P1, P2, 4, .6); // scale up (away from origin) scale = 3; P1.x *= scale; P1.y *= scale; P2.x *= scale; P2.y *= scale; drawLine(graphics, P1, P2, 4, 1);
there isn't a good analogy on the number line for rotation, since it's a two dimensional transformation, and the number line is one-dimensional. but intuitively, we can imagine sliding each endpoint along a circle that is centered at the origin and has a radius equal to the distance of the endpoint from the origin.
import flash.display.Graphics; import flash.geom.Point; function drawLine(g:Graphics, p1:Point, p2:Point, weight:Number=3, alpha:Number=1, color:uint=0x000000):void { var w:Number = stage.stageWidth; var h:Number = stage.stageHeight; g.lineStyle(weight, color, alpha); g.moveTo(P1.x*w, P1.y*h); g.lineTo(P2.x*w, P2.y*h); } function drawRegion(g:Graphics, points:Array, weight:Number=3, alpha:Number=1, color:uint=0x000000):void { var w:Number = stage.stageWidth; var h:Number = stage.stageHeight; g.lineStyle(weight, color, alpha); g.moveTo(points[0].x*w, points[0].y*h); for (var i:Number = 1; i < points.length; i++) { g.lineTo(points[i].x*w, points[i].y*h); } g.lineTo(points[0].x*w, points[0].y*h); } function scale(P:Point, factor:Number, C:Point):void { P.offset(-C.x, -C.y); P.x *= factor; P.y *= factor; P.offset(C.x, C.y); } function rotate(P:Point, theta:Number, C:Point):void { var cosTheta:Number = Math.cos(theta); var sinTheta:Number = Math.sin(theta); var centered_x:Number = P.x - C.x; var centered_y:Number = P.y - C.y; P.x = (cosTheta*centered_x - sinTheta*centered_y) + C.x; P.y = (sinTheta*centered_x + cosTheta*centered_y) + C.y; }
var P1:Point = new Point(0, 0);
var P2:Point = new Point(1, 0);
var shift:Number = .005;
while (P1.y <= 1) {
drawLine(graphics, P1, P2);
P1.offset(0, shift);
P2.offset(0, shift);
shift *= 1.25;
}
line mesh
var P1:Point = new Point(0, 0);
var P2:Point = new Point(0, 1);
var shift:Number = .05;
while (P1.y <= 1) {
drawLine(graphics, P1, P2);
P1.offset(0, shift);
P2.offset(shift, 0);
}
var P1:Point = new Point(0, 0);
var P2:Point = new Point(1, 0);
var P3:Point = new Point(1, 1);
var P4:Point = new Point(0, 1);
var R:Array = [P1, P2, P3, P4];
var C:Point = new Point(.5, .5);
var factor:Number = .85;
while (P2.x - P1.x > .15) {
drawRegion(graphics, R);
for (var p:Number = 0; p < R.length; p++) {
var point:Point = R[p];
scale(point, factor, C);
}
}
var P1:Point = new Point(.25, .25);
var P2:Point = new Point(.75, .25);
var P3:Point = new Point(.75, .75);
var P4:Point = new Point(.25, .75);
var R:Array = [P1, P2, P3, P4];
var C:Point = new Point(.5, .5);
var angle:Number = .2;
for (var i:Number = 0; i < Math.PI/2/angle; i++) {
drawRegion(graphics, R);
for (var p:Number = 0; p < R.length; p++) {
var point:Point = R[p];
rotate(point, angle, C);
}
}