Notion - Update docs

This commit is contained in:
shiffman 2023-04-04 18:03:07 +00:00 committed by GitHub
parent c5d0c350c9
commit 9c156c0b1c
39 changed files with 54 additions and 67 deletions

View file

@ -639,10 +639,6 @@ let part2 = Bodies.circle(x, y - offset, r);</pre>
<p>Make your own little alien being using multiple shapes attached to a single body. Remember, you arent limited to using the shape drawing functions in p5.js; you can use images, colors, add hair with lines, and more. Think of the matter.js shapes as skeletons for your original fantastical design!</p>
</div>
<h2 id="69-feeling-attachedmatterjs-constraints">6.9 Feeling Attached—Matter.js Constraints</h2>
<figure class="half-width-right">
<img src="images/06_libraries/06_libraries_10.png" alt="Figure 6.8: A Constraint is a connection between two bodies at an anchor point for each body.">
<figcaption>Figure 6.8: A Constraint is a connection between two bodies at an anchor point for each body.</figcaption>
</figure>
<p>Matter.js constraints are a mechanism to connect one body to another, enabling simulations of swinging pendulums, elastic bridges, squishy characters, wheels spinning on an axle, and more. There are two kinds of matter.js constraints: <code>MouseConstraint</code> and <code>Constraint</code>.</p>
<h3 id="distance-constraint">“Distance” Constraint</h3>
<p>Lets begin with <code>Constraint</code>, a connection of fixed length between two bodies. A constraint is attached to each body at a specified anchor point (a point relative to the bodys center). Defining a constraint is similar to the methodology used to create bodies, only you need to have two bodies ready to go.</p>
@ -743,7 +739,7 @@ Composite.add(engine.world, constraint);</pre>
</div>
<h3 id="revolute-constraint">“Revolute” Constraint</h3>
<figure class="half-width-right">
<img src="images/06_libraries/06_libraries_11.png" alt="Figure 6.9: A “Revolute” constraint is a connection between two bodies at a single “hinge” point.">
<img src="images/06_libraries/06_libraries_10.png" alt="Figure 6.9: A “Revolute” constraint is a connection between two bodies at a single “hinge” point.">
<figcaption>Figure 6.9: A “Revolute” constraint is a connection between two bodies at a single “hinge” point.</figcaption>
</figure>
<p>Another type of connection between bodies common to physics engine is a “revolute” joint. A revolute joint connects two bodies at a common anchor point, also known as a “hinge.” While there is no specific “revolute” constraint in matter.js, you can achieve the same effect by setting a constraints length to zero, allowing the bodies to rotate around a common anchor point.</p>
@ -809,12 +805,12 @@ Composite.add(engine.world, constraint);Step 4: Create the joint.</pre>
<div data-type="exercise">
<h3 id="exercise-66">Exercise 6.6</h3>
<figure>
<img src="images/06_libraries/06_libraries_12.png" alt="">
<img src="images/06_libraries/06_libraries_11.png" alt="">
<figcaption></figcaption>
</figure>
<p>Use a revolute joint for the wheels of a car. [some creative prompts about the design of the vehicle/car]</p>
<figure>
<img src="images/06_libraries/06_libraries_13.png" alt=" ">
<img src="images/06_libraries/06_libraries_12.png" alt=" ">
<figcaption> </figcaption>
</figure>
</div>
@ -1022,7 +1018,7 @@ function mousePressed() {
location.add(velocity);</pre>
<p>The above methodology is known as Euler integration (named for the mathematician Leonhard Euler, pronounced “Oiler”) or the Euler method. Its essentially the simplest form of integration and very easy to implement in code (see the two lines above!) However, it is not necessarily the most efficient form, nor is it close to being the most accurate. Why is Euler inaccurate? Lets think about it this way. When you bounce on a pogo stick down the sidewalk, does the pogo stick sit in one position at time equals one second, then disappear and suddenly reappear in a new position at time equals two seconds, and do the same thing for three seconds, and four, and five? No, of course not. The pogo stick bounces continuously down the sidewalk. But whats happening in a p5.js sketch? A circle is at one position at frame 0, another at frame 1, another at frame 2. Sure, at thirty frames per second, you see the illusion of motion. But a new position is only computed every <span data-type="equation">N</span> units of time, whereas the real world is perfectly continuous. This results in some inaccuracies, as shown in the diagram below:</p>
<figure>
<img src="images/06_libraries/06_libraries_14.png" alt="Figure 6.10: Euler approximation of a curve">
<img src="images/06_libraries/06_libraries_13.png" alt="Figure 6.10: Euler approximation of a curve">
<figcaption>Figure 6.10: Euler approximation of a curve</figcaption>
</figure>
<p>The “real world” is the curve; Euler simulation is the series of line segments.</p>
@ -1033,8 +1029,9 @@ location.add(velocity);</pre>
<blockquote data-type="epigraph">
<p><em>toxiclibs is an independent, open source library collection for computational design tasks with Java &#x26; Processing developed by Karsten “toxi” Schmidt. The classes are purposefully kept fairly generic in order to maximize re-use in different contexts ranging from generative design, animation, interaction/interface design, data visualization to architecture and digital fabrication, use as teaching tool and more. — </em><a href="http://toxiclibs.org"><em>toxiclibs.org</em></a><em> (last seen October 2021).</em></p>
</blockquote>
<p>Around 2005, Karsten Schmidt began work on toxiclibs, a sweeping and pioneering open source library for computational design, specifically built for the Java version of Processing. Though it hasnt been actively maintained in over 10 years, the concepts and techniques demonstrated by the library can be found in countless creative coding projects today. I continue to use a version of the library compatible with the latest version of Processing (4.1 as of the time of this writing) today.</p>
<p>For this book, we should thank our lucky starts for toxiclibs.js, a JavaScript adaptation of the library, created by Kyle Phillips (”hapticdata”). I am only going to cover on a few examples related to Verlet physics, but toxiclibs.js includes a suite of other packages with functionality related to with, color, geometry, math, and more.</p>
<p>Around 2005, Karsten Schmidt began work on toxiclibs, a sweeping and pioneering open source library for computational design, specifically built for the Java version of Processing. Though it hasnt been actively maintained in over 10 years, the concepts and techniques demonstrated by the library can be found in countless creative coding projects today.</p>
<p>Karsten Schmidt continues to contribute to the creative coding field today through his recent project, <a href="https://thi.ng/umbrella"><strong>thi.ng/umbrella</strong></a><strong>.</strong> This work can be considered an indirect successor to toxiclibs, but with a much greater scope, detail, and extent. If you like this book, you might specifically enjoy ou can exploring <a href="https://thi.ng/vectors"><strong>thi.ng/vectors</strong></a>, which provides over 800 vector algebra functions using plain vanilla JavaScript arrays.</p>
<p>While <a href="http://thi.ng/umbrella">thi.ng/umbrella</a> may be a more modern and sophisticated approach, I find that toxiclibs remains a versatile tool, and I continue to use a version compatible with the latest version of Processing (4.1 as of the time of this writing) today. For this book, we should thank our lucky starts for toxiclibs.js, a JavaScript adaptation of the library, created by Kyle Phillips (”hapticdata”). I am only going to cover on a few examples related to Verlet physics, but toxiclibs.js includes a suite of other packages with functionality related to with, color, geometry, math, and more.</p>
<p>The examples I'm about to demonstrate in this chapter could also be created using matter.js, which I've spent the bulk of this chapter covering in depth. However, I've decided to move to toxiclibs for several reasons. The library holds a special place in my heart as a personal favorite, and is historically significant. I also believe that showing more than one physics library is important for providing a broader understanding of the tools and approaches available.</p>
<p>So how do you decide which library you should use? Matter.js or toxiclibs? Or something else? If you fall into one of the following two categories, your decision is a bit easier:</p>
<p><strong>1. My project involves collisions. I have circles, squares, and other strangely shaped objects that knock each other around and bounce off each other.</strong></p>
@ -1078,6 +1075,10 @@ location.add(velocity);</pre>
</tr>
</tbody>
</table>
<figure class="half-width-right">
<img src="images/06_libraries/06_libraries_14.png" alt="Figure 6.8: A Constraint is a connection between two bodies at an anchor point for each body.">
<figcaption>Figure 6.8: A Constraint is a connection between two bodies at an anchor point for each body.</figcaption>
</figure>
<p>All of the documentation and downloads for the library files can be found at the toxiclibs.js website: <a href="http://haptic-data.com/toxiclibsjs">haptic-data.com/toxiclibsjs</a>. For the examples in this book, Ill be working with a hosted “CDN” version of the library referenced <code>index.html</code> in the same way I demonstrated in Section 6.2 with matter.js.</p>
<pre class="codesplit" data-code-language="html">&#x3C;script src="<a href="https://cdn.jsdelivr.net/gh/hapticdata/toxiclibsjs@0.3.2/build/toxiclibs.js">https://cdn.jsdelivr.net/gh/hapticdata/toxiclibsjs@0.3.2/build/toxiclibs.js</a>">&#x3C;/script></pre>
<p>The bulk of this chapter focused on the core elements of a matter.js sketch: world, vector, body, constraint. This will give you a head start on understanding toxiclibs.js, since it follows a similar structure.</p>
@ -1335,7 +1336,7 @@ class Particle extends VerletParticle2D {
<img src="images/06_libraries/06_libraries_15.png" alt="Figure 6.11: Soft body simulation designs">
<figcaption>Figure 6.11: Soft body simulation designs</figcaption>
</figure>
<p>Lets begin by simulating a “soft pendulum”—a bob hanging from a string, instead of a rigid arm—and use the design from Figure 6.14 as the basis.</p>
<p>Let's begin by simulating a "soft pendulum"—a bob hanging from a string, instead of a rigid arm—and use the design from Figure 6.14 as the basis. Toxiclibs.js does offer a convenient <code><strong>ParticleString2D</strong></code> class that creates a string of connected particles in a single constructor call. However, for demonstration purposes, I will create my own array using a <code><strong>for</strong></code> loop with the goal of giving you a deeper understanding of the system and enabling you to create your own custom designs beyond a single string in the future.</p>
<p>First, Il need an array of particles (lets use the same <code>Particle</code> class built in the previous example).</p>
<pre class="codesplit" data-code-language="javascript">let particles = [];</pre>
<p>Now, lets say I want to have 20 particles, all spaced 10 pixels apart.</p>
@ -1567,6 +1568,7 @@ let behavior = new AttractionBehavior(particle, distance, strength);</pre>
circle(this.x, this.y, this.r * 2);
}
}</pre>
<p>Just as discussed in Chapter 5s section on spatial subdivision and “binning”, toxiclibs.js projects with large numbers of particles can run very slow due to <span data-type="equation">N^2</span> nature of the algorithm (every particle checking every other particle). Toxiclibs.js offers a built-in spatial indexing feature (The<code><strong>SpatialBins</strong></code> class) and <code><strong>physics.setIndex()</strong></code>that can significantly speed up these simulations. For more, check the additional examples offered on the books website.</p>
<div data-type="exercise">
<h3 id="exercise-613">Exercise 6.13</h3>
<p>Use <code>AttractionBehavior</code> in conjunction with spring forces.</p>

View file

@ -84,35 +84,39 @@
<figcaption>Figure 7.12: 0 translates to a white cell, 1 to a black cell.</figcaption>
</figure>
<p>In Figure 7.12, I'm transitioning from representing cells with 0s or 1s to using visual cues—white for 0 and black for 1. Although this might seem counterintuitive, as 0 usually signifies "black" in computer graphics, I'm using this convention because the examples in this book have a white background, so "turning on" a cell corresponds to switching its color to black.</p>
<figure>
<img src="images/07_ca/07_ca_13.png" alt="">
<figcaption></figcaption>
</figure>
<p>Through converting the numerical representations into visual forms, the fascinating dynamics and patterns of cellular automata will come into view! Lets move past just one generation to stacking, with each new generation appearing below the previous one.</p>
<figure>
<img src="images/07_ca/07_ca_13.png" alt="Figure 7.13: Wolfram Elementary CA: Rule 90 ">
<img src="images/07_ca/07_ca_14.png" alt="Figure 7.13: Wolfram Elementary CA: Rule 90 ">
<figcaption>Figure 7.13: Wolfram Elementary CA: Rule 90 </figcaption>
</figure>
<p>The low-resolution shape depicted above is the “Sierpiński triangle.” Named after the Polish mathematician Wacław Sierpiński, its a fractal pattern that Ill examine more closely in the next chapter. Thats right: this incredibly simple system of 0s and 1s, with little neighborhoods of three cells, can generate a shape as sophisticated and detailed as the Sierpiński triangle. Lets look at it again, only with each cell a single pixel wide so that the resolution is much higher.</p>
<figure>
<img src="images/07_ca/07_ca_14.png" alt="Figure 7.14: Wolfram Elementary CA: Rule 90 at higher resolution">
<img src="images/07_ca/07_ca_15.png" alt="Figure 7.14: Wolfram Elementary CA: Rule 90 at higher resolution">
<figcaption>Figure 7.14: Wolfram Elementary CA: Rule 90 at higher resolution</figcaption>
</figure>
<p>This particular result didnt happen by accident. I picked this set of rules because of the pattern it generates. Take a look at Figure 7.8 one more time. Notice how there are eight possible neighborhood configurations. A “ruleset” is defined a list of 8 bits. Figure 7.9 showed that ruleset with 0s and 1s. Here is the same ruleset now visualized with white and black squares.</p>
<figure>
<img src="images/07_ca/07_ca_15.png" alt="Figure 7.15 Looking at same ruleset (from Figure 7.9) with white and black squares.">
<img src="images/07_ca/07_ca_16.png" alt="Figure 7.15 Looking at same ruleset (from Figure 7.9) with white and black squares.">
<figcaption>Figure 7.15 Looking at same ruleset (from Figure 7.9) with white and black squares.</figcaption>
</figure>
<p>Notice again how there are 8 possible configurations of three cells, 8 outcomes that can vary. A ruleset is therefore defined as a sequence of eight 0s or 1s. If you visit Wolframs website, youll see the convention of displayed any given rule as in Figure 7.16.</p>
<figure>
<img src="images/07_ca/07_ca_16.png" alt="Figure 7.16: How the Wolfram website represents a ruleset">
<img src="images/07_ca/07_ca_17.png" alt="Figure 7.16: How the Wolfram website represents a ruleset">
<figcaption>Figure 7.16: How the Wolfram website represents a ruleset</figcaption>
</figure>
<p>Eight 0s and 1s means an 8-bit number. How many combinations of eight 0s and 1s are there? 256. You might remember this from when you first learned about RGB color in p5.js. When you write <code>background(r, g, b)</code>, each color component (red, green, and blue) is represented by an 8-bit number ranging from 0 to 255.</p>
<p>Now, let's explore how to convert the visual representation of white and black squares in a ruleset to binary and decimal numbers. Lets work with the binary number 01011010. Binary numbers use “base 2,” meaning they are represented with only two possible digits (0 and 1). Any binary number can be converted to decimal (or base 10, digits between 0-9). In the case of “01011010” the resulting base 10 value is 90. “Rule 01011010” is therefore more commonly known as “Rule 90.”</p>
<p>Since there are 256 possible combinations of eight 0s and 1s, there are also 256 unique rulesets. Lets try looking at the results of another ruleset, how about “Rule 11011110” or more commonly “Rule 222.”</p>
<figure>
<img src="images/07_ca/07_ca_17.png" alt="Figure 7.17: Wolfram CA: Rule 222 ">
<img src="images/07_ca/07_ca_18.png" alt="Figure 7.17: Wolfram CA: Rule 222 ">
<figcaption>Figure 7.17: Wolfram CA: Rule 222 </figcaption>
</figure>
<figure class="half-width-right">
<img src="images/07_ca/07_ca_18.jpg" alt="Figure 7.18: A Textile Cone Snail (Conus textile), Cod Hole, Great Barrier Reef, Australia, 7 August 2005. Photographer: Richard Ling richard@research.canon.com.au ">
<img src="images/07_ca/07_ca_19.jpg" alt="Figure 7.18: A Textile Cone Snail (Conus textile), Cod Hole, Great Barrier Reef, Australia, 7 August 2005. Photographer: Richard Ling richard@research.canon.com.au ">
<figcaption>Figure 7.18: A Textile Cone Snail (Conus textile), Cod Hole, Great Barrier Reef, Australia, 7 August 2005. Photographer: Richard Ling richard@research.canon.com.au </figcaption>
</figure>
<p>As you can now see, the simple act of creating a CA and defining a ruleset does not guarantee visually exciting results. Out of all 256 rulesets, only a handful produce compelling outcomes. However, its quite incredible that even one of these rulesets with only two possible states can produce the patterns seen every day in nature (see Figure 7.18), and it demonstrates how valuable these systems can be in simulation and pattern generation.</p>
@ -124,7 +128,7 @@
}</pre>
<p>This line of thinking, however, is not the road I will first travel. Later in this chapter, I will discuss why an object-oriented approach could prove valuable in developing a CA simulation, but to begin, its easier to work with a more elementary data structure. After all, what is an elementary CA but a list of 0s and 1s? Certainly, a generation of a one-dimensional CA could be described using an array:</p>
<figure>
<img src="images/07_ca/07_ca_19.png" alt="Figure 7.19: One generation of a 1D cellular automata">
<img src="images/07_ca/07_ca_20.png" alt="Figure 7.19: One generation of a 1D cellular automata">
<figcaption>Figure 7.19: One generation of a 1D cellular automata</figcaption>
</figure>
<pre class="codesplit" data-code-language="javascript">let cells = [1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0];</pre>
@ -210,7 +214,7 @@ cells = newcells;</pre>
<p>Now, there are many ways to write this function, but Id like to start with a long-winded one that will hopefully provide a clear illustration of what is happening.</p>
<p>Lets first establish how I will store the ruleset. The ruleset, if you remember from the previous section, is a series of 8 bits (0 or 1) that defines that outcome for every possible neighborhood configuration. Lets bring back the visual representation of a ruleset and add back the numeric encoding.</p>
<figure>
<img src="images/07_ca/07_ca_20.png" alt="Figure 7.20 Visual representation of a Wolfram ruleset with numeric encoding ">
<img src="images/07_ca/07_ca_21.png" alt="Figure 7.20 Visual representation of a Wolfram ruleset with numeric encoding ">
<figcaption>Figure 7.20 Visual representation of a Wolfram ruleset with numeric encoding </figcaption>
</figure>
<p>I can store this ruleset in an array.</p>
@ -283,7 +287,7 @@ function rules(a, b, c) {
<h2 id="74-drawing-an-elementary-ca">7.4 Drawing an Elementary CA</h2>
<p>Whats missing? Presumably, the point here is to draw the cells. As you saw earlier, the standard technique for doing this is to stack the generations one on top of each other and draw a rectangle that is black (for state 1) or white (for state 0).</p>
<figure>
<img src="images/07_ca/07_ca_21.png" alt="Figure 7.21 Ruleset 90 visualized as a stack of generations">
<img src="images/07_ca/07_ca_22.png" alt="Figure 7.21 Ruleset 90 visualized as a stack of generations">
<figcaption>Figure 7.21 Ruleset 90 visualized as a stack of generations</figcaption>
</figure>
<p>Before implementing this particular visualization, Id like to point out two things.</p>
@ -380,22 +384,22 @@ function rules(a, b, c) {
<h2 id="75-wolfram-classification">7.5 Wolfram Classification</h2>
<p>Before moving on to looking at CA in two dimensions, its worth taking a brief look at Wolframs classification for cellular automata. As we noted earlier, the vast majority of elementary CA rulesets produce uninspiring results, while some result in wondrously complex patterns like those found in nature. Wolfram has divided up the range of outcomes into four classes:</p>
<figure>
<img src="images/07_ca/07_ca_22.png" alt="Figure 7.22: Rule 222 ">
<img src="images/07_ca/07_ca_23.png" alt="Figure 7.22: Rule 222 ">
<figcaption>Figure 7.22: Rule 222 </figcaption>
</figure>
<p><strong><em>Class 1: Uniformity.</em></strong> Class 1 CAs end up, after some number of generations, with every cell constant. This is not terribly exciting to watch. Rule 222 (above) is a class 1 CA; if you run it for enough generations, every cell will eventually become and remain black.</p>
<figure>
<img src="images/07_ca/07_ca_23.png" alt="Figure 7.23: Rule 190 ">
<img src="images/07_ca/07_ca_24.png" alt="Figure 7.23: Rule 190 ">
<figcaption>Figure 7.23: Rule 190 </figcaption>
</figure>
<p><strong><em>Class 2: Repetition.</em></strong> Like class 1 CAs, class 2 CAs remain stable, but the cell states are not constant. Rather, they oscillate in some repeating pattern of 0s and 1s. In rule 190 (above), each cell follows the sequence <code>11101110111011101110</code>.</p>
<figure>
<img src="images/07_ca/07_ca_24.png" alt="Figure 7.24: Rule 30 ">
<img src="images/07_ca/07_ca_25.png" alt="Figure 7.24: Rule 30 ">
<figcaption>Figure 7.24: Rule 30 </figcaption>
</figure>
<p><strong><em>Class 3: Random.</em></strong> Class 3 CAs appear random and have no easily discernible pattern. In fact, rule 30 (above) is used as a random number generator in Wolframs Mathematica software. Again, this is a moment where we can feel amazed that such a simple system with simple rules can descend into a chaotic and random pattern.</p>
<figure>
<img src="images/07_ca/07_ca_25.png" alt="Figure 7.25: Rule 110 ">
<img src="images/07_ca/07_ca_26.png" alt="Figure 7.25: Rule 110 ">
<figcaption>Figure 7.25: Rule 110 </figcaption>
</figure>
<p><strong><em>Class 4: Complexity.</em></strong> Class 4 CAs can be thought of as a mix between class 2 and class 3. One can find repetitive, oscillating patterns inside the CA, but where and when these patterns appear is unpredictable and seemingly random. Class 4 CAs exhibit the properties of complex systems described earlier in this chapter and in Chapter 5. If a class 3 CA wowed you, then a class 4 like Rule 110 should really blow your mind.</p>
@ -413,7 +417,7 @@ function rules(a, b, c) {
<p>The above might sound cryptic, but it essentially describes a Wolfram class 4 CA. The CA should be patterned but unpredictable over time, eventually settling into a uniform or oscillating state. In other words, though Conway didnt use this terminology, it should have all those properties of a <em>complex system</em>.</p>
<p>Lets look at how the Game of Life works. It wont take up too much time or space, since I ca build on everything from the Wolfram Elementary CA.</p>
<figure class="half-width-right">
<img src="images/07_ca/07_ca_26.png" alt="Figure 7.26: A two-dimensional CA showing the neighborhood of 9 cells.">
<img src="images/07_ca/07_ca_27.png" alt="Figure 7.26: A two-dimensional CA showing the neighborhood of 9 cells.">
<figcaption>Figure 7.26: A two-dimensional CA showing the neighborhood of 9 cells.</figcaption>
</figure>
<p>First, instead of a line of cells, there is now a two-dimensional matrix of cells. As with the elementary CA, the possible states are 0 or 1. Only in this case, since the system is about “life," 0 means dead and 1 means alive.</p>
@ -436,23 +440,23 @@ function rules(a, b, c) {
</ol>
<p>Lets look at a few examples, focussing on the center cell.</p>
<figure>
<img src="images/07_ca/07_ca_27.png" alt="Figure 7.27: Example scenarios for “death” and “birth” in the Game of Life.">
<img src="images/07_ca/07_ca_28.png" alt="Figure 7.27: Example scenarios for “death” and “birth” in the Game of Life.">
<figcaption>Figure 7.27: Example scenarios for “death” and “birth” in the Game of Life.</figcaption>
</figure>
<p>With the elementary CA, I visualized the generations next to each other, stacked as rows in a 2D grid. With the Game of Life, however, the CA itself is in two dimensions. I could try to create an elaborate 3D visualization of the results and stack all the generations in a cube structure (and in fact, you might want to try this as an exercise). Nevertheless, the typical way the Game of Life is displayed is to treat each generation as a single frame in an animation. So instead of viewing all the generations at once, you see them one at a time, and the result resembles rapidly growing bacteria in a Petri dish.</p>
<p>One of the exciting aspects of the Game of Life is that there are known initial patterns that yield intriguing results. For example, some remain static and never change.</p>
<figure>
<img src="images/07_ca/07_ca_28.png" alt="Figure 7.28: Initial configurations of cells that remain stable.">
<img src="images/07_ca/07_ca_29.png" alt="Figure 7.28: Initial configurations of cells that remain stable.">
<figcaption>Figure 7.28: Initial configurations of cells that remain stable.</figcaption>
</figure>
<p>There are patterns that oscillate back and forth between two states.</p>
<figure>
<img src="images/07_ca/07_ca_29.png" alt="Figure 7.29: Initial configurations of cells that oscillate between two states.">
<img src="images/07_ca/07_ca_30.png" alt="Figure 7.29: Initial configurations of cells that oscillate between two states.">
<figcaption>Figure 7.29: Initial configurations of cells that oscillate between two states.</figcaption>
</figure>
<p>And there are also patterns that from generation to generation appear to move about the grid. (Its important to note that the cells themselves arent actually moving, rather you see the illusion of motion in the result as the cells turn on and off.)</p>
<figure>
<img src="images/07_ca/07_ca_30.png" alt="Figure 7.30: Initial configurations of cells that appear to move.">
<img src="images/07_ca/07_ca_31.png" alt="Figure 7.30: Initial configurations of cells that appear to move.">
<figcaption>Figure 7.30: Initial configurations of cells that appear to move.</figcaption>
</figure>
<p>If you are interested in these patterns, there are several good “out of the box” Game of Life demonstrations online that allow you to configure the CAs initial state and watch it run at varying speeds. Two examples such examples are:</p>
@ -498,7 +502,7 @@ for (let i = 0; i &#x3C; columns; i++) {
}
}</pre>
<figure class="half-width-right">
<img src="images/07_ca/07_ca_31.png" alt="Figure 7.31: The index values for the neighborhood of cells.">
<img src="images/07_ca/07_ca_32.png" alt="Figure 7.31: The index values for the neighborhood of cells.">
<figcaption>Figure 7.31: The index values for the neighborhood of cells.</figcaption>
</figure>
<p>OK. Before I can sort out how to actually calculate the new state, I need to determine how to reference the cells neighbors. In the case of a 1D CA, this was simple: if a cell index was <code>i</code>, its neighbors were <code>i-1</code> and <code>i+1</code>. Here each cell doesnt have a single index, but rather a column and row index: <code>i,j</code>. As shown in Figure 7.27, the neighbors are <code>i-1,j-1</code> , <code>i,j-1</code>, <code>i+1,j-1</code>, <code>i-1,j</code>, <code>i+1,j</code>, <code>i-1,j+1</code>, <code>i,j+1</code>, and <code>i+1,j+1</code>.</p>
@ -679,7 +683,7 @@ board = next;</pre>
<h3 id="exercise-79">Exercise 7.9</h3>
<p>Create a CA using a grid of hexagons (as below), each with six neighbors.</p>
<figure>
<img src="images/07_ca/07_ca_32.png" alt="">
<img src="images/07_ca/07_ca_33.png" alt="">
<figcaption></figcaption>
</figure>
</div>

View file

@ -49,7 +49,7 @@
<img src="images/08_fractals/08_fractals_7.png" alt="Figure 8.7">
<figcaption>Figure 8.7</figcaption>
</figure>
<p>This is an example of a <strong><em>stochastic</em></strong> fractal, meaning that it is built out of probabilities and randomness. Unlike the deterministic tree-branching structure, it is statistically self-similar. As I go through the examples in this chapter, I will explore both deterministic and stochastic techniques for generating fractal patterns.</p>
<p>This is an example of a <strong><em>stochastic</em></strong> fractal, meaning that it is built out of probabilities and randomness. Unlike the deterministic (or predictable) tree-branching structure, it is statistically self-similar. As I go through the examples in this chapter, I will explore both deterministic and stochastic techniques for generating fractal patterns.</p>
<p>While self-similarity is a key trait of fractals, its important to realize that self-similarity alone does not make a fractal. After all, a straight line is self-similar. A straight line looks the same at any scale, and can be thought of as comprising lots of little lines. But its not a fractal. Fractals are characterized by having a fine structure at small scales (keep zooming into the stock market graph and youll continue to find fluctuations) and cannot be described with Euclidean geometry. If you can say “Its a line!” then its not a fractal.</p>
<p>Another fundamental component of fractal geometry is recursion. Fractals all have a recursive definition. Lets start with recursion before developing techniques and code examples for building fractal patterns in p5.js.</p>
<h2 id="82-recursion">8.2 Recursion</h2>
@ -955,7 +955,7 @@ function draw() {
</div>
<div data-type="exercise">
<h3 id="exercise-812">Exercise 8.12</h3>
<p>The seminal work in L-systems and plant structures, <em>The Algorithmic Beauty of Plants</em> by Przemysław Prusinkiewicz and Aristid Lindenmayer, was published in 1990. It is available for free in its entirety online. Chapter 1 describes many sophisticated L-systems with additional drawing rules and available alphabet characters. In addition, it describes several methods for generating stochastic L-systems. Expand the L-system example to include one or more additional features described by Prusinkiewicz and Lindenmayer.</p>
<p>The seminal work in L-systems and plant structures, <a href="http://algorithmicbotany.org/papers/abop/abop.pdf"><em>The Algorithmic Beauty of Plants</em></a> by Przemysław Prusinkiewicz and Aristid Lindenmayer, was published in 1990. Chapter 1 describes many sophisticated L-systems with additional drawing rules and available alphabet characters. In addition, it describes several methods for generating stochastic L-systems. Expand the L-system example to include one or more additional features described by Prusinkiewicz and Lindenmayer.</p>
</div>
<div data-type="exercise">
<h3 id="exercise-813">Exercise 8.13</h3>

View file

@ -1,52 +1,33 @@
// The Nature of Code
// Daniel Shiffman
// http://natureofcode.com
// L-System
// Just demonstrating working with L-System strings
// No drawing
// Start with 'A'
//{!1} Start with an axiom.
let current = "A";
// Number of generations
let count = 0;
let y = 12;
function setup() {
createCanvas(640, 240);
createCanvas(640, 160);
background(255);
noLoop();
}
function mousePressed() {
generate();
redraw();
y += 12;
}
function draw() {
fill(0);
noStroke();
text(current, 0, y);
// 9 generations
for (let i = 0; i < 9; i++) {
generate();
// Render text to canvas
textSize(16);
textFont("courier");
text(i + ": " + current, 4, 20 + i * 16);
}
}
function generate() {
// A new StringBuffer for the next generation
let next = "";
// Look through the current String to replace according to L-System rules
for (let i = 0; i < current.length; i++) {
// For every character of the current sentence
let c = current.charAt(i);
if (c === "A") {
// If we find A replace with AB
//{!5} Apply the production rules A->AB, B->A
if (c == "A") {
next += "AB";
} else if (c === "B") {
// If we find B replace with A
} else if (c == "B") {
next += "A";
} else {
}
}
// The current String is now the next one
// Save the next generation
current = next;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 112 KiB

After

Width:  |  Height:  |  Size: 190 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 60 KiB

After

Width:  |  Height:  |  Size: 130 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 69 KiB

After

Width:  |  Height:  |  Size: 483 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 97 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 132 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 75 KiB

After

Width:  |  Height:  |  Size: 98 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 262 KiB

After

Width:  |  Height:  |  Size: 641 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 59 KiB

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 93 KiB

After

Width:  |  Height:  |  Size: 200 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 116 KiB

After

Width:  |  Height:  |  Size: 120 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 72 KiB

After

Width:  |  Height:  |  Size: 110 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 70 KiB

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 89 KiB

After

Width:  |  Height:  |  Size: 98 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 277 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 65 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 105 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 140 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 144 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.5 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.9 KiB

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 168 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 296 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 82 KiB

After

Width:  |  Height:  |  Size: 211 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 67 KiB

After

Width:  |  Height:  |  Size: 221 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 60 KiB

After

Width:  |  Height:  |  Size: 185 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 92 KiB

After

Width:  |  Height:  |  Size: 171 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 161 KiB