{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Table of Contents\n", "* [1. Study in Spirographics](#1.-Study-in-Spirographics)\n", "\t* [1.1 Goal](#1.1-Goal)\n", "\t* [1.2 Preliminaries](#1.2-Preliminaries)\n", "\t\t* [1.2.1 Defining a function that returns a value](#1.2.1-Defining-a-function-that-returns-a-value)\n", "\t\t* [1.2.2 Loops](#1.2.2-Loops)\n", "\t* [1.3 Trigonometry](#1.3-Trigonometry)\n", "\t* [1.4 Rotating a line around the center](#1.4-Rotating-a-line-around-the-center)\n", "\t* [1.5 Rotating two lines](#1.5-Rotating-two-lines)\n", "\t* [1.6 Conclusion](#1.6-Conclusion)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# 1. Study in Spirographics" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 1.1 Goal" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "First, checkout this animated experiment called \"Orbits\" by Alexey Lebedev: \n", "\n", "http://explord.com/experiments/orbits/\n", "\n", "How would you describe, in the abstract, how these animations are made?\n", "\n", "_Insert insight here._\n", "\n", "This is very similar to a a toy many had named Spirograph:\n", "\n", " \n", "\n", "Our goal for Assignment #3 is to create art that can be seen as tracing the trajectory of an object through space and time. We'll look at two methods for making such art: Spirographics and Physics Simulations. This notebook looks at the first." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 1.2 Preliminaries" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 1.2.1 Defining a function that returns a value" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Before we begin, we need to learn a new technique in Processing: how to write a function that **returns** something. There are two things you need:\n", "\n", "1. A return type on the function definition (replace void with something like int or float).\n", "2. Use the return keyword in the function definition\n", "\n", "Example:\n", "\n", "Consider the concept distance from geometry. Do you remember the formula? \n", "\n", "It is simply stated as: _the square root of the sum of the squared differences of each dimension (eg, x and y)_. It comes from the relationship:\n", "\n", "$c^2 = a^2 + b^2$\n", "\n", "where a, b, and c are the lengths of a triangle with 90 degree angle:\n", "\n", " \n", "\n", "If we \"solve for c\" then we take the square root of each side, and get:\n", "\n", "$c = \\sqrt{ a^2 + b^2 }$\n", "\n", "The length $a$ is the distance between points B and C on the y axis. That is, you just take the difference of the y's of B and C. Likewise, the length $b$ is the distance between points $A$ and $C$ on the x axis.\n", "\n", "Let's break this down:\n", "\n", "First, consider that we have two points (x1, y1) and (x2, y2). We want to know how far apart they are. \n", "\n", "1. First, we find the differences of each dimension: x1 - x2 and y1 - y2\n", "2. Then we square each of those. That is, we raise those difference to the 2nd power. Or, more simply, we just multiply each times itself: (x1 - x2) * (x1 - x2) and (y1 - y2) * (y1 - y2)\n", "3. Finally, we take the square root of the sum of those, using the sqrt function\n", "\n", "Putting those all together looks like:\n", "\n", "java\n", "sqrt(((x1 - x2) * (x1 - x2)) + ((y1 - y2) * (y1 - y2)))\n", "" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The last thing we need to do is put that in a function definition:\n", "\n", "java\n", "float distance(float x1, float y1, float x2, float y2) {\n", " return sqrt(((x1 - x2) * (x1 - x2)) + ((y1 - y2) * (y1 - y2)));\n", "}\n", "\n", "\n", "or:\n", "\n", "java\n", "float distance(float x1, float y1, float x2, float y2) {\n", " return sqrt(sq(x1 - x2) + sq(y1 - y2));\n", "}\n", "" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note that we have defined a new function, called distance that takes 4 numbers (x1, y1, x2, y2) and returns the distance between those two points. To _call_ the function, we put parentheses after the function name, _pass in_ arguments, and save the returned value in $d$:\n", "\n", "java\n", "d = distance(50, 50, 10, 10);\n", "" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's try it:" ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "collapsed": false }, "outputs": [ { "data": { "application/javascript": [ "\n", " var component = document.getElementById(\"sketch_1\");\n", " if (component != undefined)\n", " component.remove();\n", " component = document.getElementById(\"state_1\");\n", " if (component != undefined)\n", " component.remove();\n", " component = document.getElementById(\"controls_div_1\");\n", " if (component != undefined)\n", " component.remove();\n", " require([window.location.protocol + \"//calysto.github.io/javascripts/processing/processing.js\"], function() {\n", " // FIXME: Stop all previously running versions (?)\n", " var processingInstance = Processing.getInstanceById(\"canvas_1\");\n", " if (processingInstance != undefined && processingInstance.isRunning())\n", " processingInstance.noLoop();\n", " });\n", "\n", "\n", " var output_area = this;\n", " // find my cell element\n", " var cell_element = output_area.element.parents('.cell');\n", " // which cell is it?\n", " var cell_idx = Jupyter.notebook.get_cell_elements().index(cell_element);\n", " // get the cell object\n", " var cell = Jupyter.notebook.get_cell(cell_idx);\n", "\n", " function jyp_print(cell, newline) {\n", " return function(message) {\n", " cell.get_callbacks().iopub.output({header: {\"msg_type\": \"stream\"},\n", " content: {text: message + newline,\n", " name: \"stdout\"}});\n", " }\n", " }\n", " window.jyp_println = jyp_print(cell, \"\\n\");\n", " window.jyp_print = jyp_print(cell, \"\");\n", "\n", " require([window.location.protocol + \"//calysto.github.io/javascripts/processing/processing.js\"], function() {\n", " Processing.logger.println = jyp_print(cell, \"\\n\");\n", " Processing.logger.print = jyp_print(cell, \"\");\n", " });\n", "\n", "\n", " " ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "\n", "
\n", " Sketch #1:
\n", "
\n", "
\n", "
\n", " \n", " \n", " \n", " \n", "
\n", "Sketch #1 state: Loading...
\n", "\n" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "34.79518272094424\n", "40.11833271074642\n", "24.297887928200606\n", "27.739883332534884\n", "44.54379378547192\n", "45.8600713784213\n", "35.51295640488337\n", "27.82787767222191\n", "27.313000567495326\n", "39.66106403010388\n", "43.829214001622255\n", "64.66065264130884\n", "15.652475842498529\n", "32.55764119219941\n", "23.345235059857504\n", "27.425407613587016\n", "41.73117387992335\n" ] } ], "source": [ "float distance(float x1, float y1, float x2, float y2) {\n", " return sqrt(((x1 - x2) * (x1 - x2)) + ((y1 - y2) * (y1 - y2)));\n", "}\n", "\n", "void setup() {\n", " background(200);\n", "}\n", "\n", "void draw() {\n", " stroke(0);\n", " line(50, 50 - 10, 50, 50 + 10);\n", " line(50 - 10, 50, 50 + 10, 50);\n", "}\n", "\n", "void mousePressed() {\n", " background(200);\n", " println( distance(50, 50, mouseX, mouseY));\n", " stroke(255, 0, 0);\n", " line(50, 50, mouseX, mouseY);\n", "}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 1.2.2 Loops" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "For this assignment, it would be handy if we had a method of doing something a specific number of times. For example, say we want to rotate a line about the origin 360 times, once for each degree.\n", "\n", "We could do this like:\n", "\n", "java\n", "drawLine(0);\n", "drawLine(1);\n", "drawLine(2);\n", "drawLine(3);\n", "drawLine(4);\n", "drawLine(5);\n", "...\n", "drawLine(359);\n", "" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "But that is a lot to type! Rather, we can use the for-loop in Processing to do this for us:\n", "\n", "java\n", "for (int i=0; i < 360; i++) {\n", " drawLine(i);\n", "}\n", "" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The two methods are exactly the same. Except one is a lot easier! The for-loop is a bit of a weird one: it looks like a function that has three arguments separated by semicolons. The meanings of the three parts are:\n", "\n", "java\n", "for (START_STATEMENT; CONTINUE_CRITERIA; INCREMENT_STATEMENT) {\n", "}\n", "" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To understand, it might we easier to see this as a while-loop:\n", "\n", "java\n", "START_STATEMENT;\n", "while (CONTINUE_CRITERIA) {\n", " INCREMENT_STATEMENT;\n", "}\n", "\n", "\n", "\n", "java\n", "int i=0;\n", "while (i < 360) {\n", " drawLine(i);\n", " i++;\n", "}\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**START_STATEMENT** - the Processing statement used to define and initialize the loop variable\n", "\n", "**CONTINUE_CRITERIA** - the Processing boolean expression used to signal that we should stop looping. The for-loop will continue until this boolean expression is no longer true\n", "\n", "**INCREMENT_STATEMENT** - the Processing statement used to increment the loop variable\n", "\n", "Examples:\n", "\n", "java\n", "for (int i=0; i < 360; i++) {\n", " drawLine(i);\n", "}\n", "\n", "int i=0; \n", "while (i < 360) {\n", " drawLine(i);\n", " i++;\n", "}\n", "" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 1.3 Trigonometry" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In order to replicate this experiment, we first need to be able to rotate a point around another point. We need just a touch of trig. For this explanation, we refer to the book [The Nature of Code](http://natureofcode.com/book/) Copyright © 2012 by Daniel Shiffman, licensed under a [Creative Commons Attribution-NonCommercial 3.0 Unported License](http://creativecommons.org/licenses/by-nc/3.0/).\n", "\n", " " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We see that there are functions named sin (sine) and cos (cosine) that define the relationships y/r and x/r of a right triangle. But we are interested in a triangle where we know $\\theta$ (theta) and $r$ but we want to find the $x$ and $y$. To find $x$ and $y$ we merely need to solve for each, by multiplying the given relationships by $r$:\n", "\n", "$sin(\\theta) = \\dfrac{y}{r}$\n", "\n", "$sin(\\theta) \\times r = \\dfrac{y}{r} \\times r$\n", "\n", "$y = sin(\\theta) \\times r$\n", "\n", "and likewise:\n", "\n", "$x = cos(\\theta) \\times r$\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 1.4 Rotating a line around the center" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To use this is in Processing, we will add the center position to the point, to make it rotate around the center. Notice to that we will add x + cos(angle) to go to the right, but we will subtract y - sin(angle) to go up." ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "collapsed": false }, "outputs": [ { "data": { "application/javascript": [ "\n", " var component = document.getElementById(\"sketch_3\");\n", " if (component != undefined)\n", " component.remove();\n", " component = document.getElementById(\"state_3\");\n", " if (component != undefined)\n", " component.remove();\n", " component = document.getElementById(\"controls_div_3\");\n", " if (component != undefined)\n", " component.remove();\n", " require([window.location.protocol + \"//calysto.github.io/javascripts/processing/processing.js\"], function() {\n", " // FIXME: Stop all previously running versions (?)\n", " var processingInstance = Processing.getInstanceById(\"canvas_3\");\n", " if (processingInstance != undefined && processingInstance.isRunning())\n", " processingInstance.noLoop();\n", " });\n", "\n", "\n", " var output_area = this;\n", " // find my cell element\n", " var cell_element = output_area.element.parents('.cell');\n", " // which cell is it?\n", " var cell_idx = Jupyter.notebook.get_cell_elements().index(cell_element);\n", " // get the cell object\n", " var cell = Jupyter.notebook.get_cell(cell_idx);\n", "\n", " function jyp_print(cell, newline) {\n", " return function(message) {\n", " cell.get_callbacks().iopub.output({header: {\"msg_type\": \"stream\"},\n", " content: {text: message + newline,\n", " name: \"stdout\"}});\n", " }\n", " }\n", " window.jyp_println = jyp_print(cell, \"\\n\");\n", " window.jyp_print = jyp_print(cell, \"\");\n", "\n", " require([window.location.protocol + \"//calysto.github.io/javascripts/processing/processing.js\"], function() {\n", " Processing.logger.println = jyp_print(cell, \"\\n\");\n", " Processing.logger.print = jyp_print(cell, \"\");\n", " });\n", "\n", "\n", " " ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "\n", "
\n", " Sketch #3:
\n", "
\n", "
\n", "
\n", " \n", " \n", " \n", " \n", "
\n", "Sketch #3 state: Loading...
\n", "\n" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "int cwidth = 200;\n", "int cheight = 200;\n", "\n", "void setup() {\n", " size(cwidth, cheight);\n", "}\n", "\n", "void draw() {\n", " float cx = cwidth/2;\n", " float cy = cheight/2;\n", " \n", " float length = cwidth/2 * 0.75;\n", " float x = cx + length;\n", " float y = cy;\n", " for (float angle = 0; angle < 2 * PI; angle = angle + PI/8) {\n", " line(cx, cy, x, y);\n", " x = cx + length * cos(angle);\n", " y = cy - length * sin(angle);\n", " }\n", " noLoop(); // this will make it so that draw() is not called anymore\n", "}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's move the cos and sin operations into functions called rotateAroundX and rotateAroundY, respectively." ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "collapsed": false }, "outputs": [ { "data": { "application/javascript": [ "\n", " var component = document.getElementById(\"sketch_4\");\n", " if (component != undefined)\n", " component.remove();\n", " component = document.getElementById(\"state_4\");\n", " if (component != undefined)\n", " component.remove();\n", " component = document.getElementById(\"controls_div_4\");\n", " if (component != undefined)\n", " component.remove();\n", " require([window.location.protocol + \"//calysto.github.io/javascripts/processing/processing.js\"], function() {\n", " // FIXME: Stop all previously running versions (?)\n", " var processingInstance = Processing.getInstanceById(\"canvas_4\");\n", " if (processingInstance != undefined && processingInstance.isRunning())\n", " processingInstance.noLoop();\n", " });\n", "\n", "\n", " var output_area = this;\n", " // find my cell element\n", " var cell_element = output_area.element.parents('.cell');\n", " // which cell is it?\n", " var cell_idx = Jupyter.notebook.get_cell_elements().index(cell_element);\n", " // get the cell object\n", " var cell = Jupyter.notebook.get_cell(cell_idx);\n", "\n", " function jyp_print(cell, newline) {\n", " return function(message) {\n", " cell.get_callbacks().iopub.output({header: {\"msg_type\": \"stream\"},\n", " content: {text: message + newline,\n", " name: \"stdout\"}});\n", " }\n", " }\n", " window.jyp_println = jyp_print(cell, \"\\n\");\n", " window.jyp_print = jyp_print(cell, \"\");\n", "\n", " require([window.location.protocol + \"//calysto.github.io/javascripts/processing/processing.js\"], function() {\n", " Processing.logger.println = jyp_print(cell, \"\\n\");\n", " Processing.logger.print = jyp_print(cell, \"\");\n", " });\n", "\n", "\n", " " ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "\n", "
\n", " Sketch #4:
\n", "
\n", "
\n", "
\n", " \n", " \n", " \n", " \n", "
\n", "Sketch #4 state: Loading...
\n", "\n" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "\n", "int cwidth = 200;\n", "int cheight = 200;\n", "\n", "void setup() {\n", " size(cwidth, cheight);\n", "}\n", "\n", "float rotateAroundX(float x1, float y1, float length, float angle) {\n", " return x1 + length * cos(angle);\n", "}\n", "\n", "float rotateAroundY(float x1, float y1, float length, float angle) {\n", " return y1 - length * sin(angle);\n", "}\n", "\n", "float distance(float x1, float y1, float x2, float y2) {\n", " return sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));\n", "}\n", "\n", "void draw() {\n", " float cx = cwidth/2;\n", " float cy = cheight/2;\n", " \n", " float length = cwidth/2 * 3/4;\n", " float x = cx + length;\n", " float y = cy;\n", " for (float angle = 0; angle < 2 * PI; angle = angle + PI/50) {\n", " line(cx, cy, x, y);\n", " float ox = x; // original x\n", " float oy = y; // original x\n", " x = rotateAroundX(cx, cy, distance(cx, cy, ox, oy), angle);\n", " y = rotateAroundY(cx, cy, distance(cx, cy, ox, oy), angle);\n", " }\n", " noLoop(); // this will make it so that draw() is not called anymore\n", "}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 1.5 Rotating two lines" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To replicate this experiment, we want to rotate one line around the origin, and a second line around the end of the first line. In the following diagram, we rotate $r$ around the center, and we rotate $\\rho$ (rho) around the end point of $r$:" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ " \n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We will have two rotating lines:\n", "\n", "1. from the center (cx, cy) to (x, y) [blue lines]\n", "2. from (x, y) to (ex, ey) [red lines]\n", "\n", "We will also draw a black line that connects (ex, ey) through time:\n" ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "collapsed": false }, "outputs": [ { "data": { "application/javascript": [ "\n", " var component = document.getElementById(\"sketch_4\");\n", " if (component != undefined)\n", " component.remove();\n", " component = document.getElementById(\"state_4\");\n", " if (component != undefined)\n", " component.remove();\n", " component = document.getElementById(\"controls_div_4\");\n", " if (component != undefined)\n", " component.remove();\n", " require([window.location.protocol + \"//calysto.github.io/javascripts/processing/processing.js\"], function() {\n", " // FIXME: Stop all previously running versions (?)\n", " var processingInstance = Processing.getInstanceById(\"canvas_4\");\n", " if (processingInstance != undefined && processingInstance.isRunning())\n", " processingInstance.noLoop();\n", " });\n", " " ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "\n", "
\n", " Sketch #4:
\n", "
\n", "
\n", "
\n", " \n", " \n", " \n", " \n", "
\n", "Sketch #4 state: Loading...
\n", "\n" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "int cwidth = 200;\n", "int cheight = 200;\n", "\n", "void setup() {\n", " size(cwidth, cheight);\n", "}\n", "\n", "float rotateAroundX(float x1, float y1, float length, float angle) {\n", " return x1 + length * cos(angle);\n", "}\n", "\n", "float rotateAroundY(float x1, float y1, float length, float angle) {\n", " return y1 - length * sin(angle);\n", "}\n", "\n", "void draw() {\n", " float cx = cwidth/2;\n", " float cy = cheight/2;\n", " \n", " float length = 50;\n", " float x = cx + length;\n", " float y = cy;\n", " \n", " float ex = cx + length + 20;\n", " float ey = cy;\n", "\n", " float pex = ex;\n", " float pey = ey;\n", " \n", " for (float angle = 0; angle <= PI * 2; angle += PI/50) {\n", " stroke(0, 0, 255);\n", " line(cx, cy, x, y);\n", " stroke(255, 0, 0);\n", " line(x, y, ex, ey);\n", " stroke(0);\n", " x = rotateAroundX(cx, cy, length, angle);\n", " y = rotateAroundY(cx, cy, length, angle);\n", " ex = rotateAroundX(x, y, 20, angle);\n", " ey = rotateAroundY(x, y, 20, angle);\n", " line(pex, pey, ex, ey);\n", " pex = ex;\n", " pey = ey;\n", " }\n", " noLoop(); // this will make it so that draw() is not called anymore\n", "}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "That is weird... it looks just like the circle we drew earlier. Why? Oh, it is because we are rotating the second line at exactly the same amount at the same rate as the first line. If change lines 38 and 39:\n", "\n", "java\n", "ex = rotateAroundX(x, y, 20, angle);\n", "ey = rotateAroundY(x, y, 20, angle);\n", "" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "to\n", "\n", "java\n", "ex = rotateAroundX(x, y, 20, angle * 2);\n", "ey = rotateAroundY(x, y, 20, angle * 2);\n", "" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "then the second line will go around the first at twice the rate:" ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "collapsed": false }, "outputs": [ { "data": { "application/javascript": [ "\n", " var component = document.getElementById(\"sketch_5\");\n", " if (component != undefined)\n", " component.remove();\n", " component = document.getElementById(\"state_5\");\n", " if (component != undefined)\n", " component.remove();\n", " component = document.getElementById(\"controls_div_5\");\n", " if (component != undefined)\n", " component.remove();\n", " require([window.location.protocol + \"//calysto.github.io/javascripts/processing/processing.js\"], function() {\n", " // FIXME: Stop all previously running versions (?)\n", " var processingInstance = Processing.getInstanceById(\"canvas_5\");\n", " if (processingInstance != undefined && processingInstance.isRunning())\n", " processingInstance.noLoop();\n", " });\n", " " ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "\n", "
\n", " Sketch #5:
\n", "
\n", "
\n", "
\n", " \n", " \n", " \n", " \n", "
\n", "Sketch #5 state: Loading...
\n", "\n" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "int cwidth = 200;\n", "int cheight = 200;\n", "\n", "void setup() {\n", " size(cwidth, cheight);\n", "}\n", "\n", "float rotateAroundX(float x1, float y1, float length, float angle) {\n", " return x1 + length * cos(angle);\n", "}\n", "\n", "float rotateAroundY(float x1, float y1, float length, float angle) {\n", " return y1 - length * sin(angle);\n", "}\n", "\n", "void draw() {\n", " float cx = cwidth/2;\n", " float cy = cheight/2;\n", " \n", " float length = 50;\n", " float x = cx + length;\n", " float y = cy;\n", " \n", " float ex = cx + length + 20;\n", " float ey = cy;\n", "\n", " float pex = ex;\n", " float pey = ey;\n", " \n", " for (float angle = 0; angle <= PI * 2; angle += PI/50) {\n", " stroke(0, 0, 255);\n", " line(cx, cy, x, y);\n", " stroke(255, 0, 0);\n", " line(x, y, ex, ey);\n", " stroke(0);\n", " x = rotateAroundX(cx, cy, length, angle);\n", " y = rotateAroundY(cx, cy, length, angle);\n", " ex = rotateAroundX(x, y, 20, angle * 2);\n", " ey = rotateAroundY(x, y, 20, angle * 2);\n", " line(pex, pey, ex, ey);\n", " pex = ex;\n", " pey = ey;\n", " }\n", " noLoop(); // this will make it so that draw() is not called anymore\n", "}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's try the same thing, but make the second line rotate 6 times faster:" ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "collapsed": false }, "outputs": [ { "data": { "application/javascript": [ "\n", " var component = document.getElementById(\"sketch_6\");\n", " if (component != undefined)\n", " component.remove();\n", " component = document.getElementById(\"state_6\");\n", " if (component != undefined)\n", " component.remove();\n", " component = document.getElementById(\"controls_div_6\");\n", " if (component != undefined)\n", " component.remove();\n", " require([window.location.protocol + \"//calysto.github.io/javascripts/processing/processing.js\"], function() {\n", " // FIXME: Stop all previously running versions (?)\n", " var processingInstance = Processing.getInstanceById(\"canvas_6\");\n", " if (processingInstance != undefined && processingInstance.isRunning())\n", " processingInstance.noLoop();\n", " });\n", " " ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "\n", "
\n", " Sketch #6:
\n", "
\n", "
\n", "
\n", " \n", " \n", " \n", " \n", "
\n", "Sketch #6 state: Loading...
\n", "\n" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "int cwidth = 200;\n", "int cheight = 200;\n", "\n", "void setup() {\n", " size(cwidth, cheight);\n", "}\n", "\n", "float rotateAroundX(float x1, float y1, float length, float angle) {\n", " return x1 + length * cos(angle);\n", "}\n", "\n", "float rotateAroundY(float x1, float y1, float length, float angle) {\n", " return y1 - length * sin(angle);\n", "}\n", "\n", "void draw() {\n", " float cx = cwidth/2;\n", " float cy = cheight/2;\n", " \n", " float length = 50;\n", " float x = cx + length;\n", " float y = cy;\n", " \n", " float ex = cx + length + 20;\n", " float ey = cy;\n", "\n", " float pex = ex;\n", " float pey = ey;\n", " \n", " for (float angle = 0; angle <= PI * 2; angle += PI/50) {\n", " stroke(0, 0, 255);\n", " line(cx, cy, x, y);\n", " stroke(255, 0, 0);\n", " line(x, y, ex, ey);\n", " stroke(0);\n", " x = rotateAroundX(cx, cy, length, angle);\n", " y = rotateAroundY(cx, cy, length, angle);\n", " ex = rotateAroundX(x, y, 20, angle * 6);\n", " ey = rotateAroundY(x, y, 20, angle * 6);\n", " line(pex, pey, ex, ey);\n", " pex = ex;\n", " pey = ey;\n", " }\n", " noLoop(); // this will make it so that draw() is not called anymore\n", "}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Finally, let's make it so that we get rid of the for-loop. In order to do this we:\n", "\n", "* Move all variables in for() code block to global variables\n", "* Initialize them in the setup() function\n", "* Replace the for-loop with a draw() funtion\n", "\n", "Now you can restart the drawing interactively." ] }, { "cell_type": "code", "execution_count": 13, "metadata": { "collapsed": false }, "outputs": [ { "data": { "application/javascript": [ "\n", " var component = document.getElementById(\"sketch_12\");\n", " if (component != undefined)\n", " component.remove();\n", " component = document.getElementById(\"state_12\");\n", " if (component != undefined)\n", " component.remove();\n", " component = document.getElementById(\"controls_div_12\");\n", " if (component != undefined)\n", " component.remove();\n", " require([window.location.protocol + \"//calysto.github.io/javascripts/processing/processing.js\"], function() {\n", " // FIXME: Stop all previously running versions (?)\n", " var processingInstance = Processing.getInstanceById(\"canvas_12\");\n", " if (processingInstance != undefined && processingInstance.isRunning())\n", " processingInstance.noLoop();\n", " });\n", "\n", "\n", " var output_area = this;\n", " // find my cell element\n", " var cell_element = output_area.element.parents('.cell');\n", " // which cell is it?\n", " var cell_idx = Jupyter.notebook.get_cell_elements().index(cell_element);\n", " // get the cell object\n", " var cell = Jupyter.notebook.get_cell(cell_idx);\n", "\n", " function jyp_print(cell, newline) {\n", " return function(message) {\n", " cell.get_callbacks().iopub.output({header: {\"msg_type\": \"stream\"},\n", " content: {text: message + newline,\n", " name: \"stdout\"}});\n", " }\n", " }\n", " window.jyp_println = jyp_print(cell, \"\\n\");\n", " window.jyp_print = jyp_print(cell, \"\");\n", "\n", " require([window.location.protocol + \"//calysto.github.io/javascripts/processing/processing.js\"], function() {\n", " Processing.logger.println = jyp_print(cell, \"\\n\");\n", " Processing.logger.print = jyp_print(cell, \"\");\n", " });\n", "\n", "\n", " " ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "\n", "
\n", " Sketch #12:
\n", "
\n", "
\n", "
\n", " \n", " \n", " \n", " \n", "
\n", "Sketch #12 state: Loading...
\n", "\n" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "int cwidth = 200;\n", "int cheight = 200;\n", "float cx; \n", "float cy; \n", "float length; \n", "float x; \n", "float y; \n", "float ex; \n", "float ey; \n", "float pex;\n", "float pey;\n", "float angle;\n", "\n", "void setup() {\n", " size(cwidth, cheight);\n", " background(200);\n", " cx = cwidth/2;\n", " cy = cheight/2;\n", " length = 50;\n", " x = cx + length;\n", " y = cy;\n", " ex = cx + length + 20;\n", " ey = cy;\n", " pex = ex;\n", " pey = ey; \n", " angle = 0;\n", "}\n", "\n", "float rotateAroundX(float x1, float y1, float length, float angle) {\n", " return x1 + length * cos(angle);\n", "}\n", "\n", "float rotateAroundY(float x1, float y1, float length, float angle) {\n", " return y1 - length * sin(angle);\n", "}\n", "\n", "void draw() {\n", " stroke(0, 0, 255);\n", " line(cx, cy, x, y);\n", " stroke(255, 0, 0);\n", " line(x, y, ex, ey);\n", " stroke(0);\n", " x = rotateAroundX(cx, cy, length, angle);\n", " y = rotateAroundY(cx, cy, length, angle);\n", " ex = rotateAroundX(x, y, 20, angle * 11.2);\n", " ey = rotateAroundY(x, y, 20, angle * 11.2);\n", " line(pex, pey, ex, ey);\n", " pex = ex; // previous ex\n", " pey = ey; // previous ey\n", " angle += PI/50;\n", " //delay(100);\n", "}\n", "\n", "void delay(int delay) {\n", " int start_time = millis();\n", " while(millis() - start_time <= delay);\n", "}" ] }, { "cell_type": "markdown", "metadata": { "collapsed": true }, "source": [ "## 1.6 Conclusion" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In this notebook we have seen how you can rotate a point about the origin, rotate a line about a point, and rotate a line around a moving point. There are many variations you can try:\n", "\n", "* don't draw line 1 and line 2\n", "* change the lengths of line 1 and line 2\n", "* change the rotation speeds (even go negative)\n", "* try different colors\n", "* more rotating lines\n", "* rotate planets around the sun; moon around planet\n", "* something completely different!" ] } ], "metadata": { "kernelspec": { "display_name": "Calysto Processing", "language": "java", "name": "calysto_processing" }, "language_info": { "codemirror_mode": { "name": "text/x-java", "version": 2 }, "file_extension": ".java", "mimetype": "text/x-java", "name": "java" } }, "nbformat": 4, "nbformat_minor": 0 }