<--implementation ^--systems--^ 2D implementation-->

Masses and Springs

1D

One dimension. We don't hear about it often, but single dimensions exist all around us. Time and length are both one-dimensional ideas (unless you're a theoretical physicist I guess). But do we ever want to visualize anything in one dimension?

Maybe not. It does, though, provide a simple way of testing our framework. It's also necessary, because in this implementation of my masses-and-springs system, I've decided that higher dimensionality inherits from lower dimensionality. Why? It just seemed right. If you have a one-dimensional universe, measured on, say, an X axis, then why wouldn't you extend that to include a Y axis, and a Z axis? Why re-invent everything? Also, while I haven't done this yet, it allows you to combine objects of different dimensionalities and still have them affect each other as you would expect. Why can't I tether a three-dimensional object to a one dimensional rod?

Extended classes

The nice thing about this system, so far, is that most of the classes don't need to be reimplemented. This was a big failing in previous versions. I had Mass1d, Spring2d, etc., and they're really not necessary. The important difference between objects and relationships in the different dimensions is their location and how that might affect their interaction. Following is the single required extension into 1D space, as well as some examples of implementations of the three "workers" in the system - Collector, Physics and Viewer.

Vector1d

The biggest thing affected by dimensionality is location, and that's all represented in our Vector class and its 1D representation, Vector1d. Unlike its predecessor, which defined the interface of a Vector and came mostly abstracted, Vector1d implements all the useful mathematical operations you might need in 1d Cartesian space.

One thing to note: there's no reason you must use Cartesian coordinates. You could use a parametric view, polar coordinates or any other that I've probably never heard of. It might very well be possible to do the hyperbolic mapping in this way, but I don't know enough about the mathematics to say. Just note that while I use Cartesian coordinates here, it's by no means required.

RandomCollector1d

A good source of testing data is always a random number generator. This class picks a number between 1 and 100, puts a Mass at that location in 1D space, and attaches it with a Spring to a randomly chosen Mass already in the system.

SimplePhysics1d

The "simple" part of SimplePhysics1d relates to the fact that we have no momentum and fake friction in this physics model. Force is applied as an instantaneous event, and the friction is really more of a threshold to return a stable environment in a reasonable period of time.

TextViewer1d

The best way to see if your Collector is collecting and your Physics is physicating (I made that up) is to see it happen. Instead of putting pixels on a screen, TextViewer1d plots out the Masses using dots and asterisks (the springs aren't drawn). Every tick of the clock it redraws the current state of affairs. It even zooms in and out to show the range of the values as they stabilize.
Really, there's nothing that useful to a 1D implementation, but it does let us see how easily we can throw together a system -- here is the code that ties the above objects together.
import org.crwth.systems.*;
import org.crwth.systems.systems1d.*;

/**
 *      A test class for a TextViewer, a RandomCollector1d and a SimplePhysics1d operating 
 *      on a Space with Masses and Springs in 1d.
 */
public class TextRandomSimple1d {
  public static void main(String args[]) {
    Space space=new Space();
    TextViewer1d tv1=new TextViewer1d(space);
    RandomCollector1d rc1=new RandomCollector1d(space,250);
    SimplePhysics1d sp1=new SimplePhysics1d(space);

    tv1.start();
    rc1.start();
    sp1.start();

    Thread t=Thread.currentThread();

    while (t.activeCount()>1) {
      try {
        Thread.sleep(1000);
      } catch (Exception e) {
	  e.printStackTrace();
	}
    }
  }
}
Here's an example of the output from the above:
*.............................*....................................*....................................................*
min=5.55715066335366 max=273.8916481235415 width=268.33449746018783
*.........*...........*.............*...............*................*.....................*............................*
min=5.55715066335366 max=441.06960447091024 width=435.5124538075566
*......*.....*.....*.....*......*.......*........*.........*..........*............*...............*....................*
min=5.55715066335366 max=531.0420767710795 width=525.4849261077258
*...*....*....*.....*.....*.....*.....*......*......*.......*.......*........*.........*..........*.........*...........*
min=5.55715066335366 max=603.1179150826599 width=597.5607644193062
*..*...*...*....*...*....*....*....*....*....*.....*.....*......*......*......*........*........*..........*............*
min=5.55715066335366 max=664.9990049684368 width=659.4418543050831
*..*...*....*...*....*....*....*.....*....*.....*.....*.....*.....*......*......*.......*........*.........*............*
min=5.55715066335366 max=714.2685426255796 width=708.7113919622259
The asterisks each represent a Mass, as mentioned. The min/max/width are there to see that the Viewer scales to fit in all the data. Even without the Springs being drawn, you can get the sense of the Masses settling into place once they're all added in. Note that the output would continue on indefinitely, hopefully resulting in the min/max/width values not changing when the system finally hit equilibrium.

Here's a JAR with the above-mentioned classes, including the test program above.
<--implementation ^--systems--^ 2D implementation-->

©2002-2017 Wayne Pearson