Commits

Jason McKesson committed 5904630

Added most of Tutorial 7's images.

Comments (0)

Files changed (8)

Documents/Positioning/GenTriangleClipping.lua

+require "SvgWriter"
+require "vmath"
+require "Viewport"
+require "SubImage"
+
+local subImageSize = 250;
+
+local subImages = SubImage.SubImage(2, 2, subImageSize, subImageSize, 50, 50);
+
+local coordSize = 2;
+
+local vp = Viewport.Viewport(subImages:SubSize(), {0, 0}, coordSize)
+local trans2 = Viewport.Transform2D()
+vp:SetTransform(trans2);
+
+-- Styles
+local styleLib = SvgWriter.StyleLibrary();
+local pointSize = 9;
+
+local coordAxisWidth = "2px";
+local xCoordAxisColor = "green";
+local yCoordAxisColor = "red";
+local objectColor = "#E0E0FF";
+
+styleLib:AddStyle(nil, "border",
+	SvgWriter.Style():stroke("black"):fill("none"));
+	
+styleLib:AddStyle(nil, "clip_line",
+	SvgWriter.Style():stroke("black"):stroke_width("2px"):fill("none"));
+	
+styleLib:AddStyle(nil, "clip_region",
+	SvgWriter.Style():stroke("none"):fill(objectColor));
+	
+styleLib:AddStyle(nil, "main_triangle",
+	SvgWriter.Style():stroke("black"):stroke_width("1px"):fill("none"));
+	
+styleLib:AddStyle(nil, "new_point",
+	SvgWriter.Style():stroke("none"):fill("red"));
+	
+styleLib:AddStyle(nil, "new_edge",
+	SvgWriter.Style():stroke("red"):stroke_width("4px"):fill("none"):stroke_opacity(0.4):stroke_linejoin("round"):stroke_linecap("round"));
+	
+	
+
+local arrowheadPath = SvgWriter.Path();
+arrowheadPath:M{10, 4}:L{0, 0}:L{0, 8}:Z();
+
+local bigArrowheadPath = SvgWriter.Path();
+bigArrowheadPath:M{0, 0}:L{10, 10}:L{0, 20};
+
+--Cell Border
+local borderPath = SvgWriter.Path();
+borderPath:M(vp:Transform(vmath.vec2(1, 1)));
+borderPath:L(vp:Transform(vmath.vec2(1, -1)));
+borderPath:L(vp:Transform(vmath.vec2(-1, -1)));
+borderPath:L(vp:Transform(vmath.vec2(-1, 1)));
+borderPath:Z();
+
+--Clipping Region
+local leftClipExtent = -0.5;
+local bottomClipExtent = -0.25;
+
+local clipLines = SvgWriter.Path();
+clipLines:M(vp:Transform(vmath.vec2(leftClipExtent, 1)));
+clipLines:L(vp:Transform(vmath.vec2(leftClipExtent, bottomClipExtent)));
+clipLines:L(vp:Transform(vmath.vec2(1, bottomClipExtent)));
+
+local clipRegion = SvgWriter.Path();
+clipRegion:M(vp:Transform(vmath.vec2(leftClipExtent, 1)));
+clipRegion:L(vp:Transform(vmath.vec2(leftClipExtent, bottomClipExtent)));
+clipRegion:L(vp:Transform(vmath.vec2(1, bottomClipExtent)));
+clipRegion:L(vp:Transform(vmath.vec2(1, 1)));
+clipRegion:Z();
+
+--Triangles
+local triangles = {}
+triangles[1] =
+{
+	vmath.vec2(0, 0),
+	vmath.vec2(0.4, 0.8),
+	vmath.vec2(0.75, -0.1),
+}
+
+triangles[2] =
+{
+	vmath.vec2(0.25, 0.25),
+	vmath.vec2(-0.25, -0.75),
+	vmath.vec2(0.5, -0.5),
+}
+
+triangles[3] =
+{
+	vmath.vec2(-0.25, 0.0),
+	vmath.vec2(0.25, -0.75),
+	vmath.vec2(0.75, 0.5),
+}
+
+triangles[4] =
+{
+	vmath.vec2(-0.75, 0.5),
+	vmath.vec2(0.75, -0.75),
+	vmath.vec2(0.5, 0.75),
+}
+
+--New Triangles
+local newPoints = {}
+newPoints[1] = {}
+
+newPoints[2] =
+{
+	vmath.vec2(0.0, -0.25),
+	vmath.vec2(0.41666, -0.25),
+}
+
+newPoints[3] =
+{
+	vmath.vec2(-0.08333, -0.25),
+	vmath.vec2(0.45, -0.25),
+}
+
+newPoints[4] =
+{
+	vmath.vec2(-0.5, 0.291667),
+	vmath.vec2(-0.5, 0.55),
+	vmath.vec2(0.15, -0.25),
+	vmath.vec2(0.6667, -0.25),
+}
+
+
+local writer = SvgWriter.SvgWriter("TriangleClipping.svg", {subImages:Size().x .."px", subImages:Size().y .. "px"});
+	writer:StyleLibrary(styleLib);
+	writer:BeginDefinitions();
+		writer:BeginMarker({pointSize, pointSize}, {pointSize/2, pointSize/2}, "auto", true, nil, "m_point");
+			writer:Circle({pointSize/2, pointSize/2}, pointSize/2, {"point"});
+		writer:EndMarker();
+		writer:BeginMarker({10, 8}, {10, 4}, "auto", true, nil, "arrow");
+			writer:Path(arrowheadPath, {"fill_black", "thin"});
+		writer:EndMarker();
+		writer:BeginMarker({10, 20}, {10, 10}, "auto", true, nil, "big_arrow_y_axis");
+			writer:Path(bigArrowheadPath, {"y_axis_marker"});
+		writer:EndMarker();
+		writer:BeginMarker({10, 20}, {10, 10}, "auto", true, nil, "big_arrow_x_axis");
+			writer:Path(bigArrowheadPath, {"x_axis_marker"});
+		writer:EndMarker();
+		writer:BeginGroup(nil, "g_background");
+			writer:Path(clipRegion, {"clip_region"});
+			writer:Path(borderPath, {"border"});
+			writer:Path(clipLines, {"clip_line"});
+		writer:EndGroup();
+		writer:BeginGroup(nil, "g_new_point");
+			writer:Circle({0, 0}, pointSize/2, {"new_point"});
+		writer:EndGroup();
+	writer:EndDefinitions();
+	
+	local xpoints = nil;
+	--TopLeft
+	writer:Use("g_background", subImages:Offset(1, 1), subImages:SubSize());
+	
+	xpoints = subImages:Transform({1, 1}, vp:Transform(triangles[1]));
+	writer:Polygon(xpoints, {"main_triangle"});
+	
+	if(#newPoints[1] > 0) then
+		local xform = subImages:Transform({1, 1}, vp:Transform(newPoints[1]));
+		for i, point in ipairs(xform) do
+			writer:Use("g_new_point", point);
+		end
+	end
+	
+	--TopRight
+	writer:Use("g_background", subImages:Offset(2, 1), subImages:SubSize());
+
+	xpoints = subImages:Transform({2, 1}, vp:Transform(triangles[2]));
+	writer:Polygon(xpoints, {"main_triangle"});
+	
+	if(#newPoints[2] > 0) then
+		local xform = subImages:Transform({2, 1}, vp:Transform(newPoints[2]));
+		for i, point in ipairs(xform) do
+			writer:Use("g_new_point", point);
+		end
+		
+		writer:Polyline({xpoints[1], xform[2], xform[1], xpoints[1]}, {"new_edge"});
+	end
+	
+	--BottomLeft
+	writer:Use("g_background", subImages:Offset(1, 2), subImages:SubSize());
+
+	xpoints = subImages:Transform({1, 2}, vp:Transform(triangles[3]));
+	writer:Polygon(xpoints, {"main_triangle"});
+
+	if(#newPoints[3] > 0) then
+		local xform = subImages:Transform({1, 2}, vp:Transform(newPoints[3]));
+		for i, point in ipairs(xform) do
+			writer:Use("g_new_point", point);
+		end
+
+		writer:Polyline(
+			{
+				xform[1],
+				xform[2],
+				xpoints[3],
+				xform[1],
+				xpoints[1],
+				xpoints[3],
+			},
+			{"new_edge"});
+	end
+	
+	--BottomRight
+	writer:Use("g_background", subImages:Offset(2, 2), subImages:SubSize());
+
+	xpoints = subImages:Transform({2, 2}, vp:Transform(triangles[4]));
+	writer:Polygon(xpoints, {"main_triangle"});
+	
+	if(#newPoints[4] > 0) then
+		local xform = subImages:Transform({2, 2}, vp:Transform(newPoints[4]));
+		for i, point in ipairs(xform) do
+			writer:Use("g_new_point", point);
+		end
+		
+		writer:Polyline(
+			{
+				xform[1],
+				xform[2],
+				xpoints[3],
+				xform[1],
+				xform[3],
+				xpoints[3],
+				xform[4],
+				xform[3],
+			},
+			{"new_edge"});
+	end
+	
+
+writer:Close();

Documents/Positioning/GenTriangleFan.lua

+require "SvgWriter"
+require "vmath"
+require "Viewport"
+require "SubImage"
+
+local subImageSize = 350;
+
+local subImages = SubImage.SubImage(1, 1, subImageSize, subImageSize, 50, 50);
+
+--Gives a [-1, 1] range.
+local coordSize = 2;
+
+local vp = Viewport.Viewport(subImages:SubSize(), {0, 0}, coordSize)
+local trans2 = Viewport.Transform2D()
+vp:SetTransform(trans2);
+
+-- Styles
+local styleLib = SvgWriter.StyleLibrary();
+local pointSize = 9;
+
+local coordAxisWidth = "2px";
+local xCoordAxisColor = "green";
+local yCoordAxisColor = "red";
+local objectColor = "#E0E0FF";
+local textSize = 20;
+
+styleLib:AddStyle(nil, "border",
+	SvgWriter.Style():stroke("black"):fill("none"));
+	
+styleLib:AddStyle(nil, "main_triangle",
+	SvgWriter.Style():stroke("black"):stroke_width("1px"):fill("none"));
+	
+styleLib:AddStyle(nil, "text",
+	SvgWriter.Style():stroke("black"):stroke_width("1px"):font_size(textSize .. "px")
+		:font_family("monospace"):text_anchor("middle"));
+	
+styleLib:AddStyle(nil, "stream_edge",
+	SvgWriter.Style():stroke("red"):stroke_width("4px"):fill("none"):stroke_opacity(0.5)
+		:stroke_linejoin("round"):stroke_linecap("round"));
+
+local arrowheadPath = SvgWriter.Path();
+arrowheadPath:M{10, 4}:L{0, 0}:L{0, 8}:Z();
+
+local bigArrowheadPath = SvgWriter.Path();
+bigArrowheadPath:M{0, 0}:L{10, 10}:L{0, 20};
+
+
+--Triangle points.
+--local distance = 1.3;
+local rotTrans = Viewport.Transform2D()
+
+local trianglePoints = 
+{
+	vmath.vec2(0.5, 0.8),
+}
+
+local distances = {1.3, 1.5, 0.9, 1.4, 1.2}
+local angles = {20, 25, 20, 25, 5}
+
+rotTrans:Rotate(-13)
+
+for i, distance in ipairs(distances) do
+	local offset = vmath.vec2(0, -distance);
+	trianglePoints[#trianglePoints + 1] = rotTrans:Matrix():Transform(offset) + trianglePoints[1];
+	rotTrans:Rotate(angles[i]);
+end
+
+
+local worldPoints = vp:Transform(trianglePoints);
+
+local writer = SvgWriter.SvgWriter("TriangleFan.svg", {subImages:Size().x .."px", subImages:Size().y .. "px"});
+	writer:StyleLibrary(styleLib);
+	writer:BeginDefinitions();
+		writer:BeginGroup(nil, "g_point");
+			writer:Circle({0, 0}, pointSize/2, {"point"});
+		writer:EndGroup();
+	writer:EndDefinitions();
+	
+	for i, point in ipairs(worldPoints) do
+		writer:Use("g_point", point);
+	end
+	
+	for i = 2, (#worldPoints - 1) do
+		writer:Polygon({worldPoints[1], worldPoints[i], worldPoints[i + 1]}, {"main_triangle"});
+	end
+	
+	writer:Polyline(worldPoints, {"stream_edge"});
+	
+	--Draw the numbers.
+	writer:Text("0", worldPoints[1] - vmath.vec2(-8, 8), {"text"});
+	
+	local textDisplacement = 25;
+	for i = 2, #worldPoints do
+		local direction = vmath.norm(worldPoints[i] - worldPoints[1]);
+		writer:Text(tonumber(i - 1), worldPoints[i] + (direction * 25), {"text"});
+	end
+	
+writer:Close();

Documents/Positioning/GenTriangleStrip.lua

+require "SvgWriter"
+require "vmath"
+require "Viewport"
+require "SubImage"
+
+--local subImageSize = 350;
+
+local subImages = SubImage.SubImage(1, 1, 700, 300, 50, 50);
+
+local viewportWidth = 10;
+local subSize = subImages:SubSize();
+local viewportSize = {viewportWidth, viewportWidth * subSize[2] / subSize[1]};
+
+local vp = Viewport.Viewport(subImages:SubSize(), {0, 0}, viewportSize)
+local trans2 = Viewport.Transform2D()
+--vp:SetTransform(trans2);
+
+-- Styles
+local styleLib = SvgWriter.StyleLibrary();
+local pointSize = 9;
+
+local coordAxisWidth = "2px";
+local xCoordAxisColor = "green";
+local yCoordAxisColor = "red";
+local objectColor = "#E0E0FF";
+local textSize = 20;
+
+styleLib:AddStyle(nil, "border",
+	SvgWriter.Style():stroke("black"):fill("none"));
+	
+styleLib:AddStyle(nil, "main_triangle",
+	SvgWriter.Style():stroke("black"):stroke_width("1px"):fill("none"));
+	
+styleLib:AddStyle(nil, "text",
+	SvgWriter.Style():stroke("black"):stroke_width("1px"):font_size(textSize .. "px")
+		:font_family("monospace"):text_anchor("middle"));
+	
+styleLib:AddStyle(nil, "stream_edge",
+	SvgWriter.Style():stroke("red"):stroke_width("4px"):fill("none"):stroke_opacity(0.5)
+		:stroke_linejoin("round"):stroke_linecap("round"));
+
+styleLib:AddStyle(nil, "ccw_wind_order",
+	SvgWriter.Style():stroke("red"):stroke_width("1px"):fill("none")
+		:marker_mid(SvgWriter.uriLocalElement("m_ccw_arrow"))
+		:marker_end(SvgWriter.uriLocalElement("m_ccw_arrow")));
+	
+styleLib:AddStyle(nil, "ccw_arrow",
+	SvgWriter.Style():stroke("none"):stroke_width("1px"):fill("red"));
+	
+styleLib:AddStyle(nil, "cw_wind_order",
+	SvgWriter.Style():stroke("blue"):stroke_width("1px"):fill("none")
+		:marker_mid(SvgWriter.uriLocalElement("m_cw_arrow"))
+		:marker_end(SvgWriter.uriLocalElement("m_cw_arrow")));
+	
+styleLib:AddStyle(nil, "cw_arrow",
+	SvgWriter.Style():stroke("none"):stroke_width("1px"):fill("blue"));
+	
+
+
+local arrowheadPath = SvgWriter.Path();
+arrowheadPath:M{10, 4}:L{0, 0}:L{0, 8}:Z();
+
+local bigArrowheadPath = SvgWriter.Path();
+bigArrowheadPath:M{0, 0}:L{10, 10}:L{0, 20};
+
+
+--Triangle points.
+local triangleWidth = 1;
+local triangleHeight = triangleWidth * math.sin(math.rad(60));
+
+local triangleScale = 2.5;
+triangleWidth = triangleWidth * triangleScale;
+triangleHeight = triangleHeight * triangleScale;
+
+local numTris = 6;
+
+local trianglePoints =
+{
+	vmath.vec2(-4, -triangleHeight / 2),
+	vmath.vec2(-4 + (triangleWidth / 2), triangleHeight / 2),
+}
+
+for i = 1, numTris do
+	local offsetTri = trianglePoints[math.mod(i, 2)];
+	offsetTri = offsetTri or trianglePoints[2];
+
+	trianglePoints[#trianglePoints + 1] = offsetTri + vmath.vec2((1 + math.floor((i - 1)/2)) * triangleWidth, 0);
+end
+
+local worldPoints = vp:Transform(trianglePoints);
+
+--Write regular
+local writer = SvgWriter.SvgWriter("TriangleStrip.svg", {subImages:Size().x .."px", subImages:Size().y .. "px"});
+	writer:StyleLibrary(styleLib);
+	writer:BeginDefinitions();
+		writer:BeginGroup(nil, "g_point");
+			writer:Circle({0, 0}, pointSize/2, {"point"});
+		writer:EndGroup();
+	writer:EndDefinitions();
+	
+	for i, point in ipairs(worldPoints) do
+		writer:Use("g_point", point);
+	end
+
+	for i = 3, #worldPoints do
+		writer:Polygon({worldPoints[i - 2], worldPoints[i - 1], worldPoints[i]}, {"main_triangle"});
+	end
+	
+	local heightOffset = {25, -13};
+	
+	writer:Polyline(worldPoints, {"stream_edge"});
+
+	--Draw the numbers.
+	local textDisplacement = 25;
+	for i = 1, #worldPoints do
+		local offset = heightOffset[math.mod(i, 2)];
+		offset = offset or heightOffset[2];
+		writer:Text(tonumber(i - 1), worldPoints[i] + vmath.vec2(0, offset), {"text"});
+	end
+writer:Close();
+
+local unitCWCirclePoints =
+{
+	vmath.vec2{0.0, 1.0},
+	vmath.vec2{-0.866, -0.5},
+	vmath.vec2{0.866, -0.5},
+}
+
+local circleCwPath = SvgWriter.Path();
+local circleCcwPath = SvgWriter.Path();
+
+do
+	local circleHeight = vp:Length(triangleHeight / 2);
+	local circleRadius = circleHeight / 2;
+	local xform = Viewport:Transform2D();
+	xform:Scale({circleRadius, circleRadius});
+	
+
+	centerCwTriPoints = xform:Transform(unitCWCirclePoints);
+	xform:Scale({1.0, -1.0});
+	centerCcwTriPoints = xform:Transform(unitCWCirclePoints)
+
+	circleCwPath:M(centerCwTriPoints[#centerCwTriPoints])
+	circleCcwPath:M(centerCcwTriPoints[#centerCcwTriPoints])
+
+	for i = 1, #centerCwTriPoints do
+		circleCwPath:A({circleRadius, circleRadius}, 0, 0, 1, centerCwTriPoints[i])
+		circleCcwPath:A({circleRadius, circleRadius}, 0, 0, 0, centerCcwTriPoints[i])
+	end
+end
+
+
+--Write winding order.
+writer = SvgWriter.SvgWriter("StripWindingOrder.svg", {subImages:Size().x .."px", subImages:Size().y .. "px"});
+	writer:StyleLibrary(styleLib);
+	writer:BeginDefinitions();
+		writer:BeginGroup(nil, "g_point");
+			writer:Circle({0, 0}, pointSize/2, {"point"});
+		writer:EndGroup();
+		writer:BeginMarker({10, 8}, {0, 4}, "auto", true, nil, "m_cw_arrow");
+			writer:Path(arrowheadPath, {"cw_arrow"});
+		writer:EndMarker();
+		writer:BeginMarker({10, 8}, {0, 4}, "auto", true, nil, "m_ccw_arrow");
+			writer:Path(arrowheadPath, {"ccw_arrow"});
+		writer:EndMarker();
+		writer:BeginGroup(nil, "g_cwCircle");
+			writer:Path(circleCwPath, "cw_wind_order");
+		writer:EndGroup();
+		writer:BeginGroup(nil, "g_ccwCircle");
+			writer:Path(circleCcwPath, "ccw_wind_order");
+		writer:EndGroup();
+	writer:EndDefinitions();
+	
+	for i, point in ipairs(worldPoints) do
+		writer:Use("g_point", point);
+	end
+
+	for i = 3, #worldPoints do
+		writer:Polygon({worldPoints[i - 2], worldPoints[i - 1], worldPoints[i]}, {"main_triangle"});
+	end
+	
+	local circleSelector = {"g_cwCircle", "g_ccwCircle"}
+	local signSelector = {1, -1};
+	
+	for i = 2, #worldPoints - 1 do
+		local winding = math.mod(i, 2) + 1;
+		local loc = vmath.vec2(trianglePoints[i]);
+		loc[2] = trianglePoints[i - 1][2] +
+			signSelector[winding] *(math.tan(math.rad(30)) * triangleWidth / 2);
+		writer:Use(circleSelector[winding], vp:Transform(loc));
+	end
+
+	--Draw the numbers.
+	local textOffset = {25, -13};
+	for i = 1, #worldPoints do
+		local offset = textOffset[math.mod(i, 2)];
+		offset = offset or textOffset[2];
+		writer:Text(tonumber(i - 1), worldPoints[i] + vmath.vec2(0, offset), {"text"});
+	end
+writer:Close();
+

Documents/Positioning/StripWindingOrder.svg

+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" height="300px" width="700px" >
+	<style type="text/css" ><![CDATA[.stream_edge
+{
+	stroke-opacity: 0.5;
+	stroke-width: 4px;
+	stroke-linejoin: round;
+	stroke: red;
+	stroke-linecap: round;
+	fill: none;
+}
+
+.ccw_wind_order
+{
+	marker-end: url(#m_ccw_arrow);
+	stroke-width: 1px;
+	stroke: red;
+	marker-mid: url(#m_ccw_arrow);
+	fill: none;
+}
+
+.ccw_arrow
+{
+	stroke: none;
+	stroke-width: 1px;
+	fill: red;
+}
+
+.cw_wind_order
+{
+	marker-end: url(#m_cw_arrow);
+	stroke-width: 1px;
+	stroke: blue;
+	marker-mid: url(#m_cw_arrow);
+	fill: none;
+}
+
+.cw_arrow
+{
+	stroke: none;
+	stroke-width: 1px;
+	fill: blue;
+}
+
+.text
+{
+	font-family: monospace;
+	stroke-width: 1px;
+	stroke: black;
+	text-anchor: middle;
+	font-size: 20px;
+}
+
+.border
+{
+	fill: none;
+	stroke: black;
+}
+
+.main_triangle
+{
+	stroke: black;
+	stroke-width: 1px;
+	fill: none;
+}]]></style>
+	<defs >
+		<g id="g_point" >
+			<circle r="4.5" cy="0" cx="0" class="point" />
+		</g>
+		<marker markerWidth="10" markerHeight="8" refX="0" refY="4" markerUnits="userSpaceOnUse" orient="auto" id="m_cw_arrow" >
+			<path d="M 10 4 L 0 0 L 0 8 Z" class="cw_arrow" />
+		</marker>
+		<marker markerWidth="10" markerHeight="8" refX="0" refY="4" markerUnits="userSpaceOnUse" orient="auto" id="m_ccw_arrow" >
+			<path d="M 10 4 L 0 0 L 0 8 Z" class="ccw_arrow" />
+		</marker>
+		<g id="g_cwCircle" >
+			<path d="M 32.811537485883 -18.944305707785 A 37.888611415569 37.888611415569 0 0 1 0 37.888611415569 A 37.888611415569 37.888611415569 0 0 1 -32.811537485883 -18.944305707785 A 37.888611415569 37.888611415569 0 0 1 32.811537485883 -18.944305707785" class="cw_wind_order" />
+		</g>
+		<g id="g_ccwCircle" >
+			<path d="M 32.811537485883 18.944305707785 A 37.888611415569 37.888611415569 0 0 0 0 -37.888611415569 A 37.888611415569 37.888611415569 0 0 0 -32.811537485883 18.944305707785 A 37.888611415569 37.888611415569 0 0 0 32.811537485883 18.944305707785" class="ccw_wind_order" />
+		</g>
+	</defs>
+	<use xlink:href="#g_point" y="225.77722283114" x="70" />
+	<use xlink:href="#g_point" y="74.222777168862" x="157.5" />
+	<use xlink:href="#g_point" y="225.77722283114" x="245" />
+	<use xlink:href="#g_point" y="74.222777168862" x="332.5" />
+	<use xlink:href="#g_point" y="225.77722283114" x="420" />
+	<use xlink:href="#g_point" y="74.222777168862" x="507.5" />
+	<use xlink:href="#g_point" y="225.77722283114" x="595" />
+	<use xlink:href="#g_point" y="74.222777168862" x="682.5" />
+	<polygon points="70,225.77722283114 157.5,74.222777168862 245,225.77722283114" class="main_triangle" />
+	<polygon points="157.5,74.222777168862 245,225.77722283114 332.5,74.222777168862" class="main_triangle" />
+	<polygon points="245,225.77722283114 332.5,74.222777168862 420,225.77722283114" class="main_triangle" />
+	<polygon points="332.5,74.222777168862 420,225.77722283114 507.5,74.222777168862" class="main_triangle" />
+	<polygon points="420,225.77722283114 507.5,74.222777168862 595,225.77722283114" class="main_triangle" />
+	<polygon points="507.5,74.222777168862 595,225.77722283114 682.5,74.222777168862" class="main_triangle" />
+	<use xlink:href="#g_cwCircle" y="175.25907427705" x="157.5" />
+	<use xlink:href="#g_ccwCircle" y="124.74092572295" x="245" />
+	<use xlink:href="#g_cwCircle" y="175.25907427705" x="332.5" />
+	<use xlink:href="#g_ccwCircle" y="124.74092572295" x="420" />
+	<use xlink:href="#g_cwCircle" y="175.25907427705" x="507.5" />
+	<use xlink:href="#g_ccwCircle" y="124.74092572295" x="595" />
+	<text y="250.77722283114" x="70" class="text" >0</text>
+	<text y="61.222777168862" x="157.5" class="text" >1</text>
+	<text y="250.77722283114" x="245" class="text" >2</text>
+	<text y="61.222777168862" x="332.5" class="text" >3</text>
+	<text y="250.77722283114" x="420" class="text" >4</text>
+	<text y="61.222777168862" x="507.5" class="text" >5</text>
+	<text y="250.77722283114" x="595" class="text" >6</text>
+	<text y="61.222777168862" x="682.5" class="text" >7</text>
+</svg>

Documents/Positioning/TriangleClipping.svg

+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" height="550px" width="550px" >
+	<style type="text/css" ><![CDATA[.clip_line
+{
+	stroke: black;
+	stroke-width: 2px;
+	fill: none;
+}
+
+.main_triangle
+{
+	stroke: black;
+	stroke-width: 1px;
+	fill: none;
+}
+
+.new_point
+{
+	fill: red;
+	stroke: none;
+}
+
+.border
+{
+	fill: none;
+	stroke: black;
+}
+
+.new_edge
+{
+	stroke-opacity: 0.4;
+	stroke-width: 4px;
+	stroke-linejoin: round;
+	stroke: red;
+	stroke-linecap: round;
+	fill: none;
+}
+
+.clip_region
+{
+	fill: #E0E0FF;
+	stroke: none;
+}]]></style>
+	<defs >
+		<marker markerWidth="9" markerHeight="9" refX="4.5" refY="4.5" markerUnits="userSpaceOnUse" orient="auto" id="m_point" >
+			<circle r="4.5" cy="4.5" cx="4.5" class="point" />
+		</marker>
+		<marker markerWidth="10" markerHeight="8" refX="10" refY="4" markerUnits="userSpaceOnUse" orient="auto" id="arrow" >
+			<path d="M 10 4 L 0 0 L 0 8 Z" class="fill_black thin" />
+		</marker>
+		<marker markerWidth="10" markerHeight="20" refX="10" refY="10" markerUnits="userSpaceOnUse" orient="auto" id="big_arrow_y_axis" >
+			<path d="M 0 0 L 10 10 L 0 20" class="y_axis_marker" />
+		</marker>
+		<marker markerWidth="10" markerHeight="20" refX="10" refY="10" markerUnits="userSpaceOnUse" orient="auto" id="big_arrow_x_axis" >
+			<path d="M 0 0 L 10 10 L 0 20" class="x_axis_marker" />
+		</marker>
+		<g id="g_background" >
+			<path d="M 62.5 0 L 62.5 156.25 L 250 156.25 L 250 0 Z" class="clip_region" />
+			<path d="M 250 0 L 250 250 L 0 250 L 0 0 Z" class="border" />
+			<path d="M 62.5 0 L 62.5 156.25 L 250 156.25" class="clip_line" />
+		</g>
+		<g id="g_new_point" >
+			<circle r="4.5" cy="0" cx="0" class="new_point" />
+		</g>
+	</defs>
+	<use xlink:href="#g_background" y="0" x="0" height="250" width="250" />
+	<polygon points="125,125 175,25 218.75,137.5" class="main_triangle" />
+	<use xlink:href="#g_background" y="0" x="300" height="250" width="250" />
+	<polygon points="456.25,93.75 393.75,218.75 487.5,187.5" class="main_triangle" />
+	<use xlink:href="#g_new_point" y="156.25" x="425" />
+	<use xlink:href="#g_new_point" y="156.25" x="477.0825" />
+	<polyline points="456.25,93.75 477.0825,156.25 425,156.25 456.25,93.75" class="new_edge" />
+	<use xlink:href="#g_background" y="300" x="0" height="250" width="250" />
+	<polygon points="93.75,425 156.25,518.75 218.75,362.5" class="main_triangle" />
+	<use xlink:href="#g_new_point" y="456.25" x="114.58375" />
+	<use xlink:href="#g_new_point" y="456.25" x="181.25" />
+	<polyline points="114.58375,456.25 181.25,456.25 218.75,362.5 114.58375,456.25 93.75,425 218.75,362.5" class="new_edge" />
+	<use xlink:href="#g_background" y="300" x="300" height="250" width="250" />
+	<polygon points="331.25,362.5 518.75,518.75 487.5,331.25" class="main_triangle" />
+	<use xlink:href="#g_new_point" y="388.541625" x="362.5" />
+	<use xlink:href="#g_new_point" y="356.25" x="362.5" />
+	<use xlink:href="#g_new_point" y="456.25" x="443.75" />
+	<use xlink:href="#g_new_point" y="456.25" x="508.3375" />
+	<polyline points="362.5,388.541625 362.5,356.25 487.5,331.25 362.5,388.541625 443.75,456.25 487.5,331.25 508.3375,456.25 443.75,456.25" class="new_edge" />
+</svg>

Documents/Positioning/TriangleFan.svg

+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" height="350px" width="350px" >
+	<style type="text/css" ><![CDATA[.main_triangle
+{
+	stroke: black;
+	stroke-width: 1px;
+	fill: none;
+}
+
+.stream_edge
+{
+	stroke-opacity: 0.5;
+	stroke-width: 4px;
+	stroke-linejoin: round;
+	stroke: red;
+	stroke-linecap: round;
+	fill: none;
+}
+
+.border
+{
+	fill: none;
+	stroke: black;
+}
+
+.text
+{
+	font-family: monospace;
+	stroke-width: 1px;
+	stroke: black;
+	text-anchor: middle;
+	font-size: 20px;
+}]]></style>
+	<defs >
+		<g id="g_point" >
+			<circle r="4.5" cy="0" cx="0" class="point" />
+		</g>
+	</defs>
+	<use xlink:href="#g_point" y="35" x="262.5" />
+	<use xlink:href="#g_point" y="256.66918973864" x="313.67636486323" />
+	<use xlink:href="#g_point" y="295.54336480585" x="230.50929735615" />
+	<use xlink:href="#g_point" y="168.56757514464" x="179.03771588327" />
+	<use xlink:href="#g_point" y="185.83706145479" x="69.437365366353" />
+	<use xlink:href="#g_point" y="82.239721412212" x="57.882286395101" />
+	<polygon points="262.5,35 313.67636486323,256.66918973864 230.50929735615,295.54336480585" class="main_triangle" />
+	<polygon points="262.5,35 230.50929735615,295.54336480585 179.03771588327,168.56757514464" class="main_triangle" />
+	<polygon points="262.5,35 179.03771588327,168.56757514464 69.437365366353,185.83706145479" class="main_triangle" />
+	<polygon points="262.5,35 69.437365366353,185.83706145479 57.882286395101,82.239721412212" class="main_triangle" />
+	<polyline points="262.5,35 313.67636486323,256.66918973864 230.50929735615,295.54336480585 179.03771588327,168.56757514464 69.437365366353,185.83706145479 57.882286395101,82.239721412212" class="stream_edge" />
+	<text y="27" x="270.5" class="text" >0</text>
+	<text y="281.02844135827" x="319.30014122183" class="text" >1</text>
+	<text y="320.35701859688" x="227.46256377102" class="text" >2</text>
+	<text y="189.76877754855" x="165.78973427744" class="text" >3</text>
+	<text y="201.22859833793" x="49.737096526185" class="text" >4</text>
+	<text y="87.863497770808" x="33.52303477547" class="text" >5</text>
+</svg>

Documents/Positioning/TriangleStrip.svg

+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" height="300px" width="700px" >
+	<style type="text/css" ><![CDATA[.stream_edge
+{
+	stroke-opacity: 0.5;
+	stroke-width: 4px;
+	stroke-linejoin: round;
+	stroke: red;
+	stroke-linecap: round;
+	fill: none;
+}
+
+.ccw_wind_order
+{
+	marker-end: url(#m_ccw_arrow);
+	stroke-width: 1px;
+	stroke: red;
+	marker-mid: url(#m_ccw_arrow);
+	fill: none;
+}
+
+.ccw_arrow
+{
+	stroke: none;
+	stroke-width: 1px;
+	fill: red;
+}
+
+.cw_wind_order
+{
+	marker-end: url(#m_cw_arrow);
+	stroke-width: 1px;
+	stroke: blue;
+	marker-mid: url(#m_cw_arrow);
+	fill: none;
+}
+
+.cw_arrow
+{
+	stroke: none;
+	stroke-width: 1px;
+	fill: blue;
+}
+
+.text
+{
+	font-family: monospace;
+	stroke-width: 1px;
+	stroke: black;
+	text-anchor: middle;
+	font-size: 20px;
+}
+
+.border
+{
+	fill: none;
+	stroke: black;
+}
+
+.main_triangle
+{
+	stroke: black;
+	stroke-width: 1px;
+	fill: none;
+}]]></style>
+	<defs >
+		<g id="g_point" >
+			<circle r="4.5" cy="0" cx="0" class="point" />
+		</g>
+	</defs>
+	<use xlink:href="#g_point" y="225.77722283114" x="70" />
+	<use xlink:href="#g_point" y="74.222777168862" x="157.5" />
+	<use xlink:href="#g_point" y="225.77722283114" x="245" />
+	<use xlink:href="#g_point" y="74.222777168862" x="332.5" />
+	<use xlink:href="#g_point" y="225.77722283114" x="420" />
+	<use xlink:href="#g_point" y="74.222777168862" x="507.5" />
+	<use xlink:href="#g_point" y="225.77722283114" x="595" />
+	<use xlink:href="#g_point" y="74.222777168862" x="682.5" />
+	<polygon points="70,225.77722283114 157.5,74.222777168862 245,225.77722283114" class="main_triangle" />
+	<polygon points="157.5,74.222777168862 245,225.77722283114 332.5,74.222777168862" class="main_triangle" />
+	<polygon points="245,225.77722283114 332.5,74.222777168862 420,225.77722283114" class="main_triangle" />
+	<polygon points="332.5,74.222777168862 420,225.77722283114 507.5,74.222777168862" class="main_triangle" />
+	<polygon points="420,225.77722283114 507.5,74.222777168862 595,225.77722283114" class="main_triangle" />
+	<polygon points="507.5,74.222777168862 595,225.77722283114 682.5,74.222777168862" class="main_triangle" />
+	<polyline points="70,225.77722283114 157.5,74.222777168862 245,225.77722283114 332.5,74.222777168862 420,225.77722283114 507.5,74.222777168862 595,225.77722283114 682.5,74.222777168862" class="stream_edge" />
+	<text y="250.77722283114" x="70" class="text" >0</text>
+	<text y="61.222777168862" x="157.5" class="text" >1</text>
+	<text y="250.77722283114" x="245" class="text" >2</text>
+	<text y="61.222777168862" x="332.5" class="text" >3</text>
+	<text y="250.77722283114" x="420" class="text" >4</text>
+	<text y="61.222777168862" x="507.5" class="text" >5</text>
+	<text y="250.77722283114" x="595" class="text" >6</text>
+	<text y="61.222777168862" x="682.5" class="text" >7</text>
+</svg>

Documents/Tools/Viewport.lua

 	self.transform = transform;
 end
 
---Returns the top-right and bottom-left corners of the viewport.
+--Returns the top-right and bottom-left corners of the viewport in viewport space.
 function View:Extents()
 	local halfSize = self.vpSize / 2;
 	local upperBound = self.vpOrigin + halfSize;
 	return upperBound, lowerBound;
 end
 
+--Computes what the given viewport length will be in pixel coordinates.
+function View:Length(testVal)
+	local originVec = vmath.vec2(0, 0);
+	local testVec = vmath.vec2(testVal, 0);
+	local test1 = self:Transform(originVec);
+	local test2 = self:Transform(testVec);
+	return vmath.length(test2 - test1);
+end
+
 function Viewport(pixelSize, vpOrigin, vpSize)
 	local viewport = {};
 	
 	return vmath.vec2(point);
 end
 
+function Trans2D:Transform(points)
+	if(vmath.vtype(points) == "table") then
+		local ret = {};
+		for i, realPoint in ipairs(points) do
+			ret[i] = self:Transform(realPoint);
+		end
+		return ret;
+	end
+	
+	return self.currMatrix:Transform(points);
+end
+
 function Transform2D()
 	local transform = {};
 	transform.currMatrix = Identity3();
 end
 
 Trans3D.MultMatrix = Trans2D.MultMatrix;
+Trans3D.Transform = Trans2D.Transform
+
 
 function Trans3D:Identity()
 	self.currMatrix = Identity4();