Revision: 955
Author: allain.lalonde
Date: Tue Jan 26 06:08:26 2010
Log: Fixing bug made evident by for each loop and also rewriting
performance tests. Eventually I want to move the Performance stuff into the
examples module.
http://code.google.com/p/piccolo2d/source/detail?r=955
Deleted:
/piccolo2d.java/branches/2.0-spike/core/src/test/java/org/piccolo2d/PerformanceLog.java
Modified:
/piccolo2d.java/branches/2.0-spike/core/src/main/java/org/piccolo2d/PNode.java
/piccolo2d.java/branches/2.0-spike/core/src/main/java/org/piccolo2d/activities/PActivityScheduler.java
/piccolo2d.java/branches/2.0-spike/core/src/test/java/org/piccolo2d/PerformanceTests.java
=======================================
---
/piccolo2d.java/branches/2.0-spike/core/src/test/java/org/piccolo2d/PerformanceLog.java
Tue Jan 19 12:39:24 2010
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Copyright (c) 2008-2010, Piccolo2D project, http://piccolo2d.org
- * Copyright (c) 1998-2008, University of Maryland
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
modification, are permitted provided
- * that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice,
this list of conditions
- * and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright
notice, this list of conditions
- * and the following disclaimer in the documentation and/or other
materials provided with the
- * distribution.
- *
- * None of the name of the University of Maryland, the name of the
Piccolo2D project, or the names of its
- * contributors may be used to endorse or promote products derived from
this software without specific
- * prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
IS" AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A
- * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR
- * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package org.piccolo2d;
-
-import java.util.ArrayList;
-import java.util.Iterator;
-
-/**
- * Performance log.
- */
-public class PerformanceLog {
-
- private final ArrayList log = new ArrayList();
- private long testTime;
-
-
- // heh, something tells me this was copied from Jazz :)
- public static class ZLogEntry {
- public String name;
- public long time;
-
- public ZLogEntry(final String aName, final long aTime) {
- name = aName;
- time = aTime;
- }
- }
-
- public void startTest() {
- Runtime.getRuntime().gc();
- testTime = System.currentTimeMillis();
- }
-
- public void endTest(final String name) {
- testTime = System.currentTimeMillis() - testTime;
- addEntry(name, testTime);
- System.gc();
- }
-
- public void addEntry(final String aName, final long aTime) {
- log.add(new ZLogEntry(aName, aTime));
- }
-
- public void clear() {
- log.clear();
- }
-
- public void writeLog() {
-
- System.out.println();
- System.out.println("Test data for input into spreadsheet:");
- System.out.println();
-
- Iterator i = log.iterator();
- while (i.hasNext()) {
- final ZLogEntry each = (ZLogEntry) i.next();
- System.out.println(each.time);
- }
-
- System.out.println();
- System.out.println("Labled test results, see above for simple
column \n of times for input into spreadsheet:");
- System.out.println();
-
- i = log.iterator();
- while (i.hasNext()) {
- final ZLogEntry each = (ZLogEntry) i.next();
- System.out.println(each.name + ", " + each.time);
- }
- }
-}
=======================================
---
/piccolo2d.java/branches/2.0-spike/core/src/main/java/org/piccolo2d/PNode.java
Sun Jan 24 19:06:03 2010
+++
/piccolo2d.java/branches/2.0-spike/core/src/main/java/org/piccolo2d/PNode.java
Tue Jan 26 06:08:26 2010
@@ -3090,6 +3090,10 @@
final boolean thisPickable = getPickable() &&
pickPath.acceptsNode(this);
+ // tests for 3 cases
+ // 1. try picking this node before its children
+ // 2. try picking a child recursively
+ // 3. try picking this node after its children
if ((thisPickable && pick(pickPath)) || (getChildrenPickable() &&
pickChild(pickPath))
|| (thisPickable && pickAfterChildren(pickPath))) {
return true;
=======================================
---
/piccolo2d.java/branches/2.0-spike/core/src/main/java/org/piccolo2d/activities/PActivityScheduler.java
Wed Jan 20 10:01:15 2010
+++
/piccolo2d.java/branches/2.0-spike/core/src/main/java/org/piccolo2d/activities/PActivityScheduler.java
Tue Jan 26 06:08:26 2010
@@ -168,11 +168,12 @@
* @param currentTime the current unix time in milliseconds.
*/
public void processActivities(final long currentTime) {
- final int size = activities.size();
- if (size > 0) {
+ if (!activities.isEmpty()) {
processingActivities.clear();
processingActivities.addAll(activities);
- for (PActivity each : reverse(processingActivities)) {
+
+ final List<PActivity> clonedActivities = new
ArrayList<PActivity>(processingActivities);
+ for (PActivity each : reverse(clonedActivities)) {
each.processStep(currentTime);
}
}
=======================================
---
/piccolo2d.java/branches/2.0-spike/core/src/test/java/org/piccolo2d/PerformanceTests.java
Tue Jan 19 12:39:24 2010
+++
/piccolo2d.java/branches/2.0-spike/core/src/test/java/org/piccolo2d/PerformanceTests.java
Tue Jan 26 06:08:26 2010
@@ -38,136 +38,147 @@
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
+import java.util.List;
import java.util.Random;
-import org.piccolo2d.PNode;
+import junit.framework.TestCase;
+
import org.piccolo2d.nodes.PPath;
import org.piccolo2d.util.PAffineTransform;
import org.piccolo2d.util.PBounds;
-import junit.framework.TestCase;
-
/**
* Performance tests.
*/
public class PerformanceTests extends TestCase {
- private static PerformanceLog log = new PerformanceLog();
- private static int NUMBER_NODES = 20000;
+ private static Measurements measurements = new Measurements();
+ private static int NUMBER_NODES = 10000;
+ private static int NUMBER_SETS = 10;
public PerformanceTests(final String name) {
super(name);
}
- public void testRunPerformanceTests() {
- if (1 == 1) {
- return;
- }
-
- // three times to warm up JVM
- for (int i = 0; i < 3; i++) {
+ public void testRunPerformanceTests() throws
NoninvertibleTransformException {
+ for (int i = 0; i < NUMBER_SETS; i++) {
addNodes();
copyNodes();
createNodes();
createPaths();
fullIntersectsNodes();
memorySizeOfNodes();
- // removeNodes();
+ removeNodes();
translateNodes();
costOfNoBoundsCache();
- // renderSpeed();
- if (i != 2) {
- log.clear();
- }
- }
- log.writeLog();
+ renderSpeed();
+ }
+
+ measurements.writeLog();
}
public void createNodes() {
final PNode[] nodes = new PNode[NUMBER_NODES];
- log.startTest();
- for (int i = 0; i < NUMBER_NODES; i++) {
- nodes[i] = new PNode();
- }
- log.endTest("Create " + NUMBER_NODES + " new nodes");
+ measurements.time("Create " + NUMBER_NODES + " new nodes", new
Runnable() {
+ public void run() {
+ for (int i = 0; i < NUMBER_NODES; i++) {
+ nodes[i] = new PNode();
+ }
+ }
+ });
+ ;
}
public void createPaths() {
final PNode[] nodes = new PNode[NUMBER_NODES];
-
- log.startTest();
- for (int i = 0; i < NUMBER_NODES; i++) {
- nodes[i] = PPath.createRectangle(0, 0, 100, 80);
- }
- log.endTest("Create " + NUMBER_NODES + " new rect paths");
-
final Random r = new Random();
- for (int i = 0; i < NUMBER_NODES; i++) {
- nodes[i].translate(r.nextFloat() * 300, r.nextFloat() * 300);
- }
+
+ measurements.time("Create " + NUMBER_NODES + " new rect paths with
random translations", new Runnable() {
+ public void run() {
+ for (int i = 0; i < NUMBER_NODES; i++) {
+ nodes[i] = PPath.createRectangle(0, 0, 100, 80);
+ nodes[i].translate(r.nextFloat() * 300, r.nextFloat()
* 300);
+ }
+ }
+ });
}
public void addNodes() {
final PNode parent = new PNode();
- final PNode[] nodes = new PNode[NUMBER_NODES];
-
- for (int i = 0; i < NUMBER_NODES; i++) {
- nodes[i] = new PNode();
- }
-
- log.startTest();
- for (int i = 0; i < NUMBER_NODES; i++) {
- parent.addChild(nodes[i]);
- }
- log.endTest("Add " + NUMBER_NODES + " nodes to a new parent");
+ final PNode[] nodes = createNodesArray();
+
+ measurements.time("Add " + NUMBER_NODES + " nodes to a new
parent", new Runnable() {
+ public void run() {
+ for (int i = 0; i < NUMBER_NODES; i++) {
+ parent.addChild(nodes[i]);
+ }
+ }
+ });
}
public void removeNodes() {
final PNode parent = new PNode();
- final PNode[] nodes = new PNode[NUMBER_NODES];
- final ArrayList list = new ArrayList();
-
- for (int i = 0; i < NUMBER_NODES; i++) {
- nodes[i] = new PNode();
- }
+ final PNode[] nodes = createNodesArray();
+
+ final List<PNode> list = new ArrayList<PNode>();
for (int i = 0; i < NUMBER_NODES; i++) {
parent.addChild(nodes[i]);
list.add(nodes[i]);
}
- log.startTest();
- for (int i = 0; i < NUMBER_NODES; i++) {
- parent.removeChild(nodes[i]);
- }
- log.endTest("Remove " + NUMBER_NODES + " nodes using removeChild()
front to back");
+ measurements.time("Remove " + NUMBER_NODES + " nodes using
removeChild() front to back", new Runnable() {
+ public void run() {
+ for (int i = 0; i < NUMBER_NODES; i++) {
+ parent.removeChild(nodes[i]);
+ }
+ }
+ });
parent.addChildren(list);
-
- log.startTest();
- for (int i = NUMBER_NODES - 1; i >= 0; i--) {
- parent.removeChild(i);
- }
- log.endTest("Remove " + NUMBER_NODES + " nodes using removeChild()
back to front by index");
-
- log.startTest();
- // for (int i = NUMBER_NODES - 1; i >= 0; i--) {
- // parent.removeChild(nodes[i]);
- // }
- log.endTest("Remove " + NUMBER_NODES + " nodes using removeChild()
back to front by object, TO_SLOW");
+ measurements.time("Remove " + NUMBER_NODES + " nodes using
removeChild() back to front by index",
+ new Runnable() {
+ public void run() {
+ for (int i = NUMBER_NODES - 1; i >= 0; i--) {
+ parent.removeChild(i);
+ }
+ }
+ });
+
+ parent.addChildren(list);
+ measurements.time("Remove " + NUMBER_NODES + " nodes using
removeChild() back to front by object, TO_SLOW",
+ new Runnable() {
+ public void run() {
+ for (int i = NUMBER_NODES - 1; i >= 0; i--) {
+ parent.removeChild(i);
+ }
+ }
+ });
parent.addChildren(list);
-
- log.startTest();
- parent.removeChildren(list);
- log.endTest("Remove " + NUMBER_NODES + " nodes using
removeChildren()");
+ measurements.time("Remove " + NUMBER_NODES + " nodes using
removeChildren()", new Runnable() {
+
+ public void run() {
+ parent.removeChildren(list);
+ }
+ });
parent.addChildren(list);
- log.startTest();
- parent.removeAllChildren();
- log.endTest("Remove " + NUMBER_NODES + " nodes using
removeAllChildren()");
+ measurements.time("Remove " + NUMBER_NODES + " nodes using
removeAllChildren()", new Runnable() {
+ public void run() {
+ parent.removeAllChildren();
+ }
+ });
+ }
+
+ private PNode[] createNodesArray() {
+ final PNode[] nodes = new PNode[NUMBER_NODES];
+ for (int i = 0; i < NUMBER_NODES; i++) {
+ nodes[i] = new PNode();
+ }
+ return nodes;
}
public void translateNodes() {
@@ -183,28 +194,40 @@
nodes[i].getFullBoundsReference();
}
- log.startTest();
- for (int i = 0; i < NUMBER_NODES; i++) {
- nodes[i].translate(1000 * r.nextFloat(), 1000 * r.nextFloat());
- nodes[i].scale(1000 * r.nextFloat());
- // nodes[i].translateBy(100.01, 100.2);
- // nodes[i].scaleBy(0.9);
- }
- log.endTest("Translate " + NUMBER_NODES + " nodes, not counting
repaint or validate layout");
-
- log.startTest();
- // parent.validateFullBounds(); now protected.
- parent.getFullBoundsReference(); // calls validateFullBounds as a
side
- // effect.
- log.endTest("Validate Layout after translate " + NUMBER_NODES + "
nodes");
-
- log.startTest();
- parent.validateFullPaint();
- log.endTest("Validate Paint after translate " + NUMBER_NODES + "
nodes");
-
- log.startTest();
- parent.computeFullBounds(b);
- log.endTest("Parent compute bounds of " + NUMBER_NODES + "
children nodes");
+ measurements.time("Translate " + NUMBER_NODES + " nodes, not
counting repaint or validate layout",
+ new Runnable() {
+
+ public void run() {
+ for (int i = 0; i < NUMBER_NODES; i++) {
+ nodes[i].translate(1000 * r.nextFloat(), 1000
* r.nextFloat());
+ nodes[i].scale(1000 * r.nextFloat());
+ // nodes[i].translateBy(100.01, 100.2);
+ // nodes[i].scaleBy(0.9);
+ }
+ }
+ });
+
+ measurements.time("Validate Layout after translate " +
NUMBER_NODES + " nodes", new Runnable() {
+ public void run() {
+ // Since parent.validateFullBounds(); now protected, we use
+ // getFullBoundsReference since it calls validateFullBounds
+ // indirectly.
+ parent.getFullBoundsReference();
+
+ }
+ });
+
+ measurements.time("Validate Paint after translate " + NUMBER_NODES
+ " nodes", new Runnable() {
+ public void run() {
+ parent.validateFullPaint();
+ }
+ });
+
+ measurements.time("Parent compute bounds of " + NUMBER_NODES + "
children nodes", new Runnable() {
+ public void run() {
+ parent.computeFullBounds(b);
+ }
+ });
}
public void fullIntersectsNodes() {
@@ -221,32 +244,25 @@
parent.getFullBoundsReference(); // calls validateFullBounds as a
side
// effect.
- log.startTest();
- for (int i = 0; i < NUMBER_NODES; i++) {
- nodes[i].fullIntersects(b);
- }
- log.endTest("Do fullIntersects test for " + NUMBER_NODES + "
nodes");
- }
-
+ measurements.time("fullIntersect on " + NUMBER_NODES + " nodes",
new Runnable() {
+ public void run() {
+ for (int i = 0; i < NUMBER_NODES; i++) {
+ nodes[i].fullIntersects(b);
+ }
+ }
+ });
+ }
+
public void memorySizeOfNodes() {
final PNode[] nodes = new PNode[NUMBER_NODES];
- Runtime.getRuntime().gc();
- final long startTotalMemory = Runtime.getRuntime().totalMemory();
- final long startFree = Runtime.getRuntime().freeMemory();
- long endFree;
- long endTotal;
-
- for (int i = 0; i < NUMBER_NODES; i++) {
- nodes[i] = new PNode();
- }
-
- Runtime.getRuntime().gc();
- endFree = Runtime.getRuntime().freeMemory();
- endTotal = Runtime.getRuntime().totalMemory();
-
- log.addEntry("Approximate k used by " + NUMBER_NODES + " nodes",
- (endTotal - startTotalMemory + startFree - endFree) /
1024);
- nodes[0].getPaint();
+
+ measurements.memory("Approximate k used by " + NUMBER_NODES + "
nodes", new Runnable() {
+ public void run() {
+ for (int i = 0; i < NUMBER_NODES; i++) {
+ nodes[i] = new PNode();
+ }
+ }
+ });
}
public void copyNodes() {
@@ -258,9 +274,11 @@
parent.addChild(nodes[i]);
}
- log.startTest();
- parent.clone();
- log.endTest("Copy/Serialize " + NUMBER_NODES + " nodes");
+ measurements.time("Copy/Serialize " + NUMBER_NODES + " nodes", new
Runnable() {
+ public void run() {
+ parent.clone();
+ }
+ });
}
public void costOfNoBoundsCache() {
@@ -276,58 +294,71 @@
bounds[i] = new PBounds(1000 * r.nextFloat(), 1000 *
r.nextFloat(), 100, 80);
}
- log.startTest();
- for (int i = 0; i < NUMBER_NODES; i++) {
- bounds[i].intersects(pickRect);
- }
- log.endTest("Do intersects test for " + NUMBER_NODES + " bounds");
-
- log.startTest();
- for (int i = 0; i < NUMBER_NODES; i++) {
- nodes[i].localToParent(bounds[i]);
- }
- log.endTest("Transform " + NUMBER_NODES + " bounds from local to
parent");
-
- log.startTest();
- for (int i = 0; i < NUMBER_NODES; i++) {
- pickRect.add(bounds[i]);
- }
- log.endTest("Sum " + NUMBER_NODES + " bounds");
+ measurements.time("Do intersects test for " + NUMBER_NODES + "
bounds", new Runnable() {
+ public void run() {
+ for (int i = 0; i < NUMBER_NODES; i++) {
+ bounds[i].intersects(pickRect);
+ }
+ }
+ });
+
+ measurements.time("Transform " + NUMBER_NODES + " bounds from
local to parent", new Runnable() {
+ public void run() {
+ for (int i = 0; i < NUMBER_NODES; i++) {
+ nodes[i].localToParent(bounds[i]);
+ }
+ }
+ });
+
+ measurements.time("Sum " + NUMBER_NODES + " bounds", new
Runnable() {
+ public void run() {
+ for (int i = 0; i < NUMBER_NODES; i++) {
+ pickRect.add(bounds[i]);
+ }
+ }
+ });
final PBounds b = new PBounds(r.nextDouble(), r.nextDouble(),
r.nextDouble(), r.nextDouble());
- log.startTest();
- for (int i = 0; i < NUMBER_NODES * 10; i++) {
- b.clone();
- }
- log.endTest("Clone " + NUMBER_NODES * 10 + " PBounds");
+
+ measurements.time("Clone " + NUMBER_NODES + " PBounds", new
Runnable() {
+ public void run() {
+ for (int i = 0; i < NUMBER_NODES; i++) {
+ b.clone();
+ }
+ }
+ });
}
- public void renderSpeed() throws NoninvertibleTransformException {
+ private void renderSpeed() throws NoninvertibleTransformException {
final Random r = new Random();
final PAffineTransform at = new PAffineTransform();
at.setScale(r.nextFloat());
- at.translate(r.nextFloat(), r.nextFloat());
-
- log.startTest();
- for (int i = 0; i < NUMBER_NODES; i++) {
- at.createInverse();
- }
- log.endTest("Create inverse transform " + NUMBER_NODES + " times");
+ at.translate(r.nextDouble(), r.nextDouble());
+
+ measurements.time("Create inverse transform " + NUMBER_NODES + "
times", new Runnable() {
+ public void run() {
+ try {
+ for (int i = 0; i < NUMBER_NODES; i++) {
+ at.createInverse();
+ }
+ }
+ catch (final NoninvertibleTransformException e) {
+ e.printStackTrace();
+ }
+ }
+ });
final int height = 400;
final int width = 400;
final double scale1 = 0.5;
final double scale2 = 2;
- boolean scaleFlip = true;
final PAffineTransform transorm1 = new PAffineTransform();
// transorm1.scale(0.5, 0.5);
transorm1.translate(0.5, 10.1);
- PAffineTransform transorm2 = null;
-
- transorm2 = new PAffineTransform(transorm1.createInverse());
+ final PAffineTransform transorm2 = new
PAffineTransform(transorm1.createInverse());
final GraphicsConfiguration graphicsConfiguration =
GraphicsEnvironment.getLocalGraphicsEnvironment()
.getDefaultScreenDevice().getDefaultConfiguration();
@@ -335,61 +366,70 @@
Transparency.TRANSLUCENT);
final Graphics2D g2 = result.createGraphics();
- log.startTest();
- for (int i = 0; i < NUMBER_NODES; i++) {
- if (scaleFlip) {
- g2.scale(scale2, scale2);
- scaleFlip = !scaleFlip;
- }
- else {
- g2.scale(scale1, scale1);
- scaleFlip = !scaleFlip;
- }
- }
- log.endTest("Scale graphics context " + NUMBER_NODES + " times");
+ measurements.time("Scale graphics context " + NUMBER_NODES + "
times", new Runnable() {
+ public void run() {
+ for (int i = 0; i < NUMBER_NODES; i++) {
+ if (i % 2 == 0) {
+ g2.scale(scale2, scale2);
+ }
+ else {
+ g2.scale(scale1, scale1);
+
+ }
+ }
+ }
+ });
g2.setTransform(new AffineTransform());
- log.startTest();
- for (int i = 0; i < NUMBER_NODES; i++) {
- g2.translate(0.5, 0.5);
- }
- log.endTest("Translate graphics context " + NUMBER_NODES + "
times");
+ measurements.time("Translate graphics context " + NUMBER_NODES + "
times", new Runnable() {
+ public void run() {
+ for (int i = 0; i < NUMBER_NODES; i++) {
+ g2.translate(0.5, 0.5);
+ }
+ }
+ });
g2.setTransform(new AffineTransform());
- log.startTest();
- for (int i = 0; i < NUMBER_NODES; i++) {
- if (scaleFlip) {
- g2.transform(transorm1);
- scaleFlip = !scaleFlip;
- }
- else {
- g2.transform(transorm2);
- scaleFlip = !scaleFlip;
- }
- }
- log.endTest("Transform graphics context " + NUMBER_NODES + "
times");
+ measurements.time("Transform graphics context " + NUMBER_NODES + "
times", new Runnable() {
+ public void run() {
+ for (int i = 0; i < NUMBER_NODES; i++) {
+ if (i % 2 == 0) {
+ g2.transform(transorm1);
+ }
+ else {
+ g2.transform(transorm2);
+ }
+ }
+ }
+ });
final Rectangle2D rect = new Rectangle2D.Double(0, 0, 100, 80);
final GeneralPath path = new GeneralPath(rect);
- log.startTest();
- for (int i = 0; i < NUMBER_NODES; i++) {
- g2.fill(rect);
- }
- log.endTest("Fill " + NUMBER_NODES + " rects");
-
- log.startTest();
- for (int i = 0; i < NUMBER_NODES; i++) {
- g2.getTransform().getScaleX();
- }
- log.endTest("Call g2.getTransform() " + NUMBER_NODES + " times");
-
- log.startTest();
- for (int i = 0; i < NUMBER_NODES; i++) {
- g2.fill(path);
- }
- log.endTest("Fill " + NUMBER_NODES + " paths");
+ measurements.time("Fill " + NUMBER_NODES + " rects", new
Runnable() {
+ public void run() {
+ for (int i = 0; i < NUMBER_NODES; i++) {
+ g2.fill(rect);
+ }
+ }
+ });
+
+ measurements.time("Call g2.getTransform() " + NUMBER_NODES + "
times", new Runnable() {
+ public void run() {
+ for (int i = 0; i < NUMBER_NODES; i++) {
+ g2.getTransform().getScaleX();
+ }
+ }
+ });
+
+ measurements.time("Fill " + NUMBER_NODES + " paths", new
Runnable() {
+ public void run() {
+ for (int i = 0; i < NUMBER_NODES; i++) {
+ g2.fill(path);
+ }
+ }
+ });
}
}
--
Piccolo2D Developers Group: http://groups.google.com/group/piccolo2d-dev?hl=en