Commit 3dbb309c authored by Philip Levis's avatar Philip Levis
Browse files

Significant resdesign of the data model to allow wings to move.

This was necessary to be able to support moving the wings
The prior approach was relying on static variables in order to
invoke the super() constructor of LXModel in LXModel subclasses.
The constructor takes the sub-models. This is a problem if you want
to build top down (create a Flight, whcih creates Flyers, which
creates Wings, which creates Points), as the lower level has to
exist when you instantiated the higher one. That is, to call

super(LXModel[] children)

in the WingModel, for example, you need all of the children
models created already. But you are in the first line of the
constructor, so it is hard to do so. The prior design relied
on static variables to achieve this, but this as the problem
that then every Flyer has the same wings -- you can't move them
individually (since Wings are static variables).

This PR refactors the data model so it's built bottom up. THis
happens in Model. First it builds the LightPoints, then the
Wings, then the Flyers, then the Flight.

The Fade test pattern now also moves the wings. Take a look.
parent 7fa1c7a6
......@@ -6,11 +6,7 @@ class UIFlightDrawer extends UI3dComponent implements GeometryConstants {
FlightModel model;
<<<<<<< HEAD:software/FlightGui/Drawing.pde
UIFlightDrawer() {
=======
UIFlightDisplay(FlightModel model) {
>>>>>>> b27e4cf91ccedb8556428b0d6ff1aa22be3844c7:software/FlightGui/UIDrawer.pde
UIFlightDrawer(FlightModel model) {
super();
this.model = model;
......@@ -55,6 +51,7 @@ class UIFlightDrawer extends UI3dComponent implements GeometryConstants {
// drawing it, then popping the tranformation. This allows the
// draw code to just operate in a normalized coordinate space. -pal
for (Flyer flyer : model.getFlyers()) {
try {
pg.pushMatrix();
float x = flyer.getX();
float y = flyer.getY();
......@@ -64,6 +61,10 @@ class UIFlightDrawer extends UI3dComponent implements GeometryConstants {
rotateZ(-flyer.getTilt() * (float)Math.PI / 180);
drawFlyer(pg, flyer);
pg.popMatrix();
} catch (Exception e) {
e.printStackTrace();
throw e;
}
}
}
......@@ -82,23 +83,37 @@ class UIFlightDrawer extends UI3dComponent implements GeometryConstants {
pg.endShape(CLOSE);
// Left wing
List<LightSamplePoint> leftLights = model.getFlyerLeftWingLights(flyer.getIndex());
Wing leftWing = flyer.getLeftWing();
List<LightSamplePoint> leftLights = leftWing.getLightPoints();
pg.fill(leftLights.get(0).getColor()); // Just use point 0 for the wing for now
pg.pushMatrix();
pg.translate(4.01, 0, 4.96);
pg.rotateY(PI/18); // The wing edge is 10 degrees from centerline
float langle = (float)leftWing.getSkew() / 90f * PI / 2f;
pg.rotateX(langle);
pg.beginShape();
pg.vertex(4.01, 0, 4.96);
pg.vertex(9.12, 0, 11.17);
pg.vertex(26.74, 0, 0.987);
pg.vertex(0, 0, 0);
pg.vertex(cos(PI/3f) * 7.87f, 0, sin(PI/3f) * 7.87f);
pg.vertex(23.036, 0, 0);
pg.endShape(CLOSE);
pg.popMatrix();
// Right wing
List<LightSamplePoint> rightLights = model.getFlyerRightWingLights(flyer.getIndex());
Wing rightWing = flyer.getRightWing();
List<LightSamplePoint> rightLights = rightWing.getLightPoints();
pg.fill(rightLights.get(0).getColor()); // Just use point 0 for the wing for now
pg.pushMatrix();
pg.translate(4.01, 0, -4.96);
pg.rotateY(- PI/18); // The wing edge is 10 degrees from centerline
float rangle = (float)rightWing.getSkew() / 90f * PI / 2f;
pg.rotateX(-rangle);
pg.beginShape();
pg.vertex(4.01, 0, -4.96);
pg.vertex(9.12, 0, -11.17);
pg.vertex(26.74, 0, -0.987);
pg.vertex(0, 0, 0);
pg.vertex(cos(PI/3f) * 7.87f, 0, - sin(PI/3f) * 7.87f);
pg.vertex(23.036, 0, 0);
pg.endShape(CLOSE);
pg.popMatrix();
// Body shell
LightSamplePoint bodyLight = model.getFlyerBodyLight(flyer.getIndex());
pg.fill(bodyLight.getColor());
......@@ -129,15 +144,6 @@ class UIFlightDrawer extends UI3dComponent implements GeometryConstants {
}
private void computeFlyerLightsAndWings() {
//Wing[] wings = (Wing[]) model.getAllWings().toArray();
for (LightSamplePoint l: model.getAllWingsLights()) {
//l.setColor(LXColor.RED);
}
for (LightSamplePoint l: model.getAllBodyLights()) {
//l.setColor(LXColor.BLUE);
}
for (LXAbstractChannel channel: pengine.getChannels()) {
/* if (channel.hasLights()) {
channel.getFaderTransition().blend(lights, channel.getLights(), 1);
......
......@@ -67,17 +67,22 @@ void settings() {
// Starts wings as Red and bodies as Blue, why not.
void initializeModel() {
model = new Model(flyerConfigurations).getFlightModel();
List<LightSamplePoint> wingLights = model.getAllWingsLights();
for (LightSamplePoint light: wingLights) {
light.setColor(LXColor.hsb(0, 0.5, 0.8));
}
List<LightSamplePoint> bodyLights = model.getAllBodyLights();
for (LightSamplePoint light: bodyLights) {
light.setColor(LXColor.hsb(0.7, 0.5, 0.8));
}
try {
model = new Model(flyerConfigurations).getFlightModel();
List<LightSamplePoint> wingLights = model.getAllWingsLights();
for (LightSamplePoint light: wingLights) {
light.setColor(LXColor.hsb(0, 0.5, 0.8));
}
List<LightSamplePoint> bodyLights = model.getAllBodyLights();
for (LightSamplePoint light: bodyLights) {
System.out.println(light);
light.setColor(LXColor.hsb(0.7, 0.5, 0.8));
}
} catch (Exception e) {
e.printStackTrace();
throw e;
}
}
......@@ -93,7 +98,7 @@ void setup() {
void initializeUI(LXStudio lx, LXStudio.UI ui) {
pengine = new ProcessingEngine(sketchPath(), model, lx);
lx.engine.setThreaded(true);
lx.engine.addLoopTask(new BlackPinkTest(lx));
//lx.engine.addLoopTask(new BlackPinkTest(lx));
}
public void onUIReady(LXStudio lx, LXStudio.UI ui) {
......@@ -140,7 +145,7 @@ void configureUI(LXStudio.UI ui) {
viewContext.setInteractionMode(UI3dContext.InteractionMode.ZOOM);
viewContext.setRadius(85 * GeometryConstants.FEET);
viewContext.addComponent(new UIFlightDrawer());
viewContext.addComponent(new UIFlightDrawer(model));
// Adds the control panel for selecting and moving Flyers
ui.addLayer(viewContext);
ui.addLayer(new UIFlyerConfiguration(ui));
......
......@@ -70,7 +70,6 @@ class UIFlyerConfiguration extends UIWindow {
makePipeToggle();
makeMountingSlider();
name = new UILabel(0, 0, 0, 16);
name.setLabel("?");
......@@ -94,18 +93,7 @@ class UIFlyerConfiguration extends UIWindow {
yPos = labelRow(yPos, "PIPE", pipeToggle);
yPos = labelRow(yPos, "MOUNT", mountPointSlider);
new UIButton(4, yPos, this.width-8, 20) {
void onToggle(boolean active) {
if (active) {
String backupFileName = Config.FLYER_CONFIG_FILE + ".backup." + month() + "." + day() + "." + hour() + "." + minute() + "." + second();
saveStream(backupFileName, Config.FLYER_CONFIG_FILE);
FlyerConfig[] configs = model.getFlyerConfigs();
System.out.println(configs[0]);
pengine.saveJSONToFile(Config.FLYER_CONFIG_FILE, flyerConfigurations);
setLabel("Saved. Restart needed.");
}
}
}.setMomentary(true).setLabel("Save Changes").addToContainer(this);
makeSaveButton(yPos);
setFlyer();
updateEditableParameters();
......@@ -262,6 +250,21 @@ class UIFlyerConfiguration extends UIWindow {
return yPos;
}
void makeSaveButton(float yPos) {
new UIButton(4, yPos, this.width-8, 20) {
public void onToggle(boolean active) {
if (active) {
String backupFileName = Config.FLYER_CONFIG_FILE + ".backup." + month() + "." + day() + "." + hour() + "." + minute() + "." + second();
saveStream(backupFileName, Config.FLYER_CONFIG_FILE);
FlyerConfig[] configs = model.getFlyerConfigs();
System.out.println(configs[0]);
pengine.saveJSONToFile(Config.FLYER_CONFIG_FILE, flyerConfigurations);
setLabel("Saved. Restart needed.");
}
}
}.setMomentary(true).setLabel("Save Changes").addToContainer(this);
}
void setFlyer() {
FlyerConfig config = flyerConfigurations[flyerHighlighter.flyerIndex.getValuei()];
xSlider.getParameter().setValue(config.faceConfig().x);
......
......@@ -64,7 +64,7 @@ abstract class FlightEngine {
configureAutomation();
/** For testing **/
//lx.engine.addLoopTask(new FadeTest(lx));
lx.engine.addLoopTask(new FadeTest(lx));
// io.saveConfigFile(model.getFlyerConfigs(), Config.FLYER_CONFIG_FILE);
// String testPlaylistFilename = "data/playlist.json";
......
......@@ -5,7 +5,7 @@ import heronarts.lx.model.LXPoint;
abstract interface Flyer extends GeometryConstants {
public final static int PIXELS_PER_BODY =
LightSamplePoint.LightCorners.BODY.numPixels;
NUM_LIGHT_POINTS_PER_FLYER;
int getIndex();
......@@ -27,7 +27,7 @@ abstract interface Flyer extends GeometryConstants {
LXPoint getBodyLightPoint();
List<? extends LXPoint> getLightPoints();
List<LightSamplePoint> getLightPoints();
FlyerConfig getConfig();
......
......@@ -37,7 +37,8 @@ class FlyerHighlighter extends Effect {
}
void reloadModel() {
lx.setModel(new FlightModel(flyerConfigurations));
Model m = new Model(flyerConfigurations);
lx.setModel(m.getFlightModel());
}
void trigger() {
......
......@@ -40,10 +40,10 @@ public class Generator extends LXOutput implements GeometryConstants {
this.out = outSockets;
}
private Color[] getRGBColors(List<? extends LXPoint> points) {
private Color[] getRGBColors(List<LightSamplePoint> points) {
Color[] ledColors = new Color[points.size()];
for (int i = 0; i < points.size(); i++) {
ledColors[i] = new Color(((LightSamplePoint) points.get(i)).getColor());
ledColors[i] = new Color((points.get(i)).getColor());
}
return ledColors;
}
......@@ -77,8 +77,8 @@ public class Generator extends LXOutput implements GeometryConstants {
int rightWingPos = rWing.getSkew();
LXPoint bodyLightPoint = flyer.getBodyLightPoint();
List<? extends LXPoint> leftLEDs = lWing.getLightPoints();
List<? extends LXPoint> rightLEDs = rWing.getLightPoints();
List<LightSamplePoint> leftLEDs = lWing.getLightPoints();
List<LightSamplePoint> rightLEDs = rWing.getLightPoints();
ArrayList<String> commands = new ArrayList<String>();
......
......@@ -66,6 +66,17 @@ interface GeometryConstants {
final static int NUM_LIGHT_POINTS_PER_BODY = 1;
final static int NUM_LIGHT_POINTS_PER_FLYER = NUM_WINGS_PER_FLYER * NUM_LIGHT_POINTS_PER_WING + NUM_LIGHT_POINTS_PER_BODY;
default int bodyLightIndex(int flyer) {
return flyer * NUM_LIGHT_POINTS_PER_FLYER;
}
default int wingLightIndex(int flyer, boolean right, int which) {
return 1 + (flyer * NUM_LIGHT_POINTS_PER_FLYER) + (right? NUM_LIGHT_POINTS_PER_WING: 0) + which;
}
default int wingIndex(int flyer, boolean right) {
return (flyer * NUM_WINGS_PER_FLYER) + (right? 1: 0);
}
/**
* indexing scheme constants
*/
......
import heronarts.lx.model.LXPoint;
abstract interface LightSamplePoint extends GeometryConstants {
enum LightCorners {
HEAD(0, 24), // half short (.09) + half long (.27) + .03 = .39 , 23.4 LEDS
SIDE(1, 21), // half short (.09) + half medium (.23) + .03 = .35, 21 LEDS
TAIL(2, 31), // half medium (.23) + half long (.26) + .03 = .52, 31.2 LEDs
BODY(6, 99);
// The long edge of a wing is 20.69 inches. (.53m)
// The medium edge is 18.04 edges. (.46m)
// The short edge is 7.06 inches. (.18m)
// corners are .03 m each
public final int position;
public final int numPixels;
private LightCorners(int position, int numPixels) {
this.position = position;
this.numPixels = numPixels;
}
}
Integer getWingIndex();
int getBodyIndex();
LightCorners getLocation();
/**
* Index of this lightPoint in color buffer, colors[lightPoint.getIndex()]
*/
// TODO (achen) make this cleaner
default int getIndex() {
Integer wingIndex = getWingIndex();
if (wingIndex != null) {
return getBodyIndex() * NUM_LIGHT_POINTS_PER_FLYER +
(wingIndex % NUM_WINGS_PER_FLYER) * NUM_LIGHT_POINTS_PER_WING +
getLocation().position;
}
return getBodyIndex() * NUM_LIGHT_POINTS_PER_FLYER + getLocation().position;
}
default LXPoint getXYZ() {
Integer wingIndex = getWingIndex();
if (wingIndex != null) {
return lightGeometryPoints.get((wingIndex % NUM_WINGS_PER_FLYER) * NUM_LIGHT_POINTS_PER_WING + getLocation().position);
}
return lightGeometryPoints.get(getLocation().position);
}
int getIndex();
// Uses the color representation of LXStudio
void setColor(int color);
......@@ -51,5 +13,5 @@ abstract interface LightSamplePoint extends GeometryConstants {
// What range is this value? -pal
// TODO (achen) define brightness range. Very likely 0 - 100
void setBrightness(int brightness);
int getBrightness();
}
This diff is collapsed.
......@@ -23,12 +23,18 @@ class FadeTest extends LXPattern {
@Override
public void run(double deltaMs) {
float hue = color.getValuef();
int val = lx.hsb(hue, 100, 100);
int skew = (int)((hue - 180f) / 2);
for (Wing wing: model.getAllWings()) {
wing.setSkew(skew);
}
for (LightSamplePoint bodyPoint : model.getAllBodyLights()) {
bodyPoint.setColor(lx.hsb(0, 0, 20));
}
for (LightSamplePoint wingPoint : model.getAllWingsLights()) {
float hue = color.getValuef();
wingPoint.setColor(lx.hsb(hue, 100, 100));
wingPoint.setColor(val);
}
}
}
......@@ -54,25 +60,20 @@ class BlackPinkTest extends LXPattern {
@Override
public void run(double deltaMs) {
List<LightSamplePoint> allLights = model.getAllLights();
for (LightSamplePoint lightPoint : allLights) {
if (lightPoint.getBodyIndex() == (int) flyerIndex.getValue()) {
lightPoint.setColor(lx.hsb(330, 70, 70));
} else {
lightPoint.setColor(lx.hsb(0, 0, 20));
}
for (LightSamplePoint bodyPoint : model.getAllBodyLights()) {
bodyPoint.setColor(lx.hsb(330, 70, 70));
}
for (LightSamplePoint wingPoint: model.getAllWingsLights()) {
wingPoint.setColor(lx.hsb(0, 0, 20));
}
for (Wing wing : model.getAllWings()) {
if (wing.getFlyerIndex() == (int) flyerIndex.getValue()) {
wing.setSkew(180);
// wing.setSkew(180);
} else {
wing.setSkew(0);
// wing.setSkew(0);
}
}
}
}
......@@ -10,7 +10,7 @@ abstract interface Wing extends GeometryConstants {
int getFlyerIndex();
boolean getIsRight();
List<? extends LXPoint> getLightPoints();
List<LightSamplePoint> getLightPoints();
static int getIndex(int flyerIndex, boolean isRight) {
return flyerIndex * NUM_WINGS_PER_FLYER + isRightAsInt(isRight);
......@@ -35,4 +35,4 @@ abstract interface Wing extends GeometryConstants {
// List<? extends LXPoint> lightPointList = new ArrayList<>();
}
\ No newline at end of file
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment