001: package prefuse.util.force;
002:
003: import java.util.ArrayList;
004: import java.util.Iterator;
005:
006: /**
007: * Manages a simulation of physical forces acting on bodies. To create a
008: * custom ForceSimulator, add the desired {@link Force} functions and choose an
009: * appropriate {@link Integrator}.
010: *
011: * @author <a href="http://jheer.org">jeffrey heer</a>
012: */
013: public class ForceSimulator {
014:
015: private ArrayList items;
016: private ArrayList springs;
017: private Force[] iforces;
018: private Force[] sforces;
019: private int iflen, sflen;
020: private Integrator integrator;
021: private float speedLimit = 1.0f;
022:
023: /**
024: * Create a new, empty ForceSimulator. A RungeKuttaIntegrator is used
025: * by default.
026: */
027: public ForceSimulator() {
028: this (new RungeKuttaIntegrator());
029: }
030:
031: /**
032: * Create a new, empty ForceSimulator.
033: * @param integr the Integrator to use
034: */
035: public ForceSimulator(Integrator integr) {
036: integrator = integr;
037: iforces = new Force[5];
038: sforces = new Force[5];
039: iflen = 0;
040: sflen = 0;
041: items = new ArrayList();
042: springs = new ArrayList();
043: }
044:
045: /**
046: * Get the speed limit, or maximum velocity value allowed by this
047: * simulator.
048: * @return the "speed limit" maximum velocity value
049: */
050: public float getSpeedLimit() {
051: return speedLimit;
052: }
053:
054: /**
055: * Set the speed limit, or maximum velocity value allowed by this
056: * simulator.
057: * @param limit the "speed limit" maximum velocity value to use
058: */
059: public void setSpeedLimit(float limit) {
060: speedLimit = limit;
061: }
062:
063: /**
064: * Get the Integrator used by this simulator.
065: * @return the Integrator
066: */
067: public Integrator getIntegrator() {
068: return integrator;
069: }
070:
071: /**
072: * Set the Integrator used by this simulator.
073: * @param intgr the Integrator to use
074: */
075: public void setIntegrator(Integrator intgr) {
076: integrator = intgr;
077: }
078:
079: /**
080: * Clear this simulator, removing all ForceItem and Spring instances
081: * for the simulator.
082: */
083: public void clear() {
084: items.clear();
085: Iterator siter = springs.iterator();
086: Spring.SpringFactory f = Spring.getFactory();
087: while (siter.hasNext())
088: f.reclaim((Spring) siter.next());
089: springs.clear();
090: }
091:
092: /**
093: * Add a new Force function to the simulator.
094: * @param f the Force function to add
095: */
096: public void addForce(Force f) {
097: if (f.isItemForce()) {
098: if (iforces.length == iflen) {
099: // resize necessary
100: Force[] newf = new Force[iflen + 10];
101: System.arraycopy(iforces, 0, newf, 0, iforces.length);
102: iforces = newf;
103: }
104: iforces[iflen++] = f;
105: }
106: if (f.isSpringForce()) {
107: if (sforces.length == sflen) {
108: // resize necessary
109: Force[] newf = new Force[sflen + 10];
110: System.arraycopy(sforces, 0, newf, 0, sforces.length);
111: sforces = newf;
112: }
113: sforces[sflen++] = f;
114: }
115: }
116:
117: /**
118: * Get an array of all the Force functions used in this simulator.
119: * @return an array of Force functions
120: */
121: public Force[] getForces() {
122: Force[] rv = new Force[iflen + sflen];
123: System.arraycopy(iforces, 0, rv, 0, iflen);
124: System.arraycopy(sforces, 0, rv, iflen, sflen);
125: return rv;
126: }
127:
128: /**
129: * Add a ForceItem to the simulation.
130: * @param item the ForceItem to add
131: */
132: public void addItem(ForceItem item) {
133: items.add(item);
134: }
135:
136: /**
137: * Remove a ForceItem to the simulation.
138: * @param item the ForceItem to remove
139: */
140: public boolean removeItem(ForceItem item) {
141: return items.remove(item);
142: }
143:
144: /**
145: * Get an iterator over all registered ForceItems.
146: * @return an iterator over the ForceItems.
147: */
148: public Iterator getItems() {
149: return items.iterator();
150: }
151:
152: /**
153: * Add a Spring to the simulation.
154: * @param item1 the first endpoint of the spring
155: * @param item2 the second endpoint of the spring
156: * @return the Spring added to the simulation
157: */
158: public Spring addSpring(ForceItem item1, ForceItem item2) {
159: return addSpring(item1, item2, -1.f, -1.f);
160: }
161:
162: /**
163: * Add a Spring to the simulation.
164: * @param item1 the first endpoint of the spring
165: * @param item2 the second endpoint of the spring
166: * @param length the spring length
167: * @return the Spring added to the simulation
168: */
169: public Spring addSpring(ForceItem item1, ForceItem item2,
170: float length) {
171: return addSpring(item1, item2, -1.f, length);
172: }
173:
174: /**
175: * Add a Spring to the simulation.
176: * @param item1 the first endpoint of the spring
177: * @param item2 the second endpoint of the spring
178: * @param coeff the spring coefficient
179: * @param length the spring length
180: * @return the Spring added to the simulation
181: */
182: public Spring addSpring(ForceItem item1, ForceItem item2,
183: float coeff, float length) {
184: if (item1 == null || item2 == null)
185: throw new IllegalArgumentException(
186: "ForceItems must be non-null");
187: Spring s = Spring.getFactory().getSpring(item1, item2, coeff,
188: length);
189: springs.add(s);
190: return s;
191: }
192:
193: /**
194: * Get an iterator over all registered Springs.
195: * @return an iterator over the Springs.
196: */
197: public Iterator getSprings() {
198: return springs.iterator();
199: }
200:
201: /**
202: * Run the simulator for one timestep.
203: * @param timestep the span of the timestep for which to run the simulator
204: */
205: public void runSimulator(long timestep) {
206: accumulate();
207: integrator.integrate(this , timestep);
208: }
209:
210: /**
211: * Accumulate all forces acting on the items in this simulation
212: */
213: public void accumulate() {
214: for (int i = 0; i < iflen; i++)
215: iforces[i].init(this );
216: for (int i = 0; i < sflen; i++)
217: sforces[i].init(this );
218: Iterator itemIter = items.iterator();
219: while (itemIter.hasNext()) {
220: ForceItem item = (ForceItem) itemIter.next();
221: item.force[0] = 0.0f;
222: item.force[1] = 0.0f;
223: for (int i = 0; i < iflen; i++)
224: iforces[i].getForce(item);
225: }
226: Iterator springIter = springs.iterator();
227: while (springIter.hasNext()) {
228: Spring s = (Spring) springIter.next();
229: for (int i = 0; i < sflen; i++) {
230: sforces[i].getForce(s);
231: }
232: }
233: }
234:
235: } // end of class ForceSimulator
|