teslaworksumn / proton-cli

Command line interface to manipulate ProtonLights projects.
MIT License
1 stars 1 forks source link

Layout format #3

Closed bookdude13 closed 8 years ago

bookdude13 commented 8 years ago

How should we store the layout? Probably using Fixtures, where a Fixture contains channels (with data over time), a name, location (x, y, z=0), rotation (r, s=0, t=0), and size. This Fixture struct will also be used when (re)sectioning.

bookdude13 commented 8 years ago

It will also need to have the internal channel number(s) it is using, not just the channel data

alexkafer commented 8 years ago

Would it be easiest to import the data as a sort of Enum? In practice, it would look something like this:

Layout team gives us a list of fixtures.

{
    [
        { 
         "name": "railing-red-lights", // Some name that the sequencer would see
         "location": 24234 // Some number or string that represents a location on the building
        }
    ]
}

Being an array, there would just be a whole bunch of names and locations. When it comes time to export and channels have been finalized, we (software) get another file from layout:

{
    [
        { 
         "name": "railing-red-lights", // Some name that the sequencer would see
         "channel": 2 
        }
    ]
}

Channels are never used internally until the very end during the export sequency. That way, if a channel changes 5 minutes before the show, we just re-export with the new channel list. The name property is maintained and used as the "internal number".

computergeek125 commented 8 years ago

I like the idea. This is going to end up being a database of sorts, so it's OK to use that terminology.

The primary key (you called it the "internal number") of the fixtures relation (table, data structure) is its name. We already have a constraint on that field in the original paper versions for it to be unique. The foreign key location would refer to another structure that contained the human-readable location and whatever else we want (perhaps a setup for the visualizer?).

{
    "fixtures": [
        { 
            "name": "railing-red-lights",
            "location": 24234
        }
    ]
}

Location structure:

{
    "locations": {
        "24234": {
            "hr-string": "Handicap rail block 1",
            "visualizer2d": {
                "x": 400,
                "y": 200,
                "size-x": 30,
                "size-y": 5,
                "layer": 0,
            }
        }
    }
}

As for channels, we might want to keep the output channels and DMX channels in the same data structure. Fewer tables mean that the computer would only need to perform one large-scale lookup (versus two). That cuts the program run time in (about) half in that stage. Additionally, because we are using long strings ("railing-red-lights") as the primary key, we reduce the amount of data we have to store by collapsing the two tables to one by a lot.

Side note: I assumed that this was JSON, but it doesn't quite fit. What markup language did you use?

alexkafer commented 8 years ago

So the location structure was a little different than I originally thought of. In my plan, location some scheme/address/coordinates that we would create to give every location a unique name. Inspired by the what3works map that uses 3 unique words to map the entire world. Instead of the entire world, we would just have the map of the location we are using. The visuallizer would be able to automatically construct a visual representative of the map using whatever location value we used, all from this location tag. For example: https://map.what3words.com/puns.nuns.banana

{
    "fixtures": [
        { 
            "name": "railing-red-lights",
            "location": "puns.nuns.banana"
        }
    ]
}

And from the puns.nuns.banana, we could derive the specific location both on a screen for the sequencers and in the real-world for the set up crew.

It was JSON, but I was using my phone so I forgot the key for the array. My bad.

ianlsmith commented 8 years ago

As a quick FYI, this is what the layout spreadsheet will look like. Being able to easily transfer data from that should probably be a priority, but it's your call on how you want to handle that.

EDIT: Also, if you have changes to that sheet (things you'd want to see on there, that you think are unnecessary, etc) let me know.

alexkafer commented 8 years ago

Might be a stupid question, but from a software point of view, are we concerned with the box and the box channel? Am I incorrect in assuming that we just interface with the DMXs?

As for the spreadsheet to the JSON file, any number of scripts could easily convert from the spreadsheet to JSON. I'm currently experimenting with Google App Scripts that would allow the JSON to be pulled automatically from the google sheet linked above. Give me a few minutes.

ianlsmith commented 8 years ago

I don't believe you should be concerned with boxes. The goal is just to have all the data about layout in one easily accessible and organized place, to avoid some of the issues we've had in past years. That's great! Thanks. Just wanted to make sure you guys were aware that this was/will be available to you.

bookdude13 commented 8 years ago

With 16 channels per box, the "global" DMX channel is box_number * 16 + box_channel. All we need for the DMX patching is this global channel. The way we interface with DMX is something like this (in something C-like):

byte[] channel_values = new byte[num_channels];
// ... Set channel values ...
sendDmx(channel_values);
alexkafer commented 8 years ago

So does exporting a JSON like this work?

https://script.google.com/macros/s/AKfycbw1UFeW1FrbuabXKswQXm_auCyQOFAZUmmkF1IdTGE3rel2--M/exec

It is pulling from a copy of Ian's spreadsheet: https://docs.google.com/a/umn.edu/spreadsheets/d/1hN_tx5IVVGJHbEhdKWgBowHwgeVTEQbl9h046ZJNyiE/edit?usp=sharing

If you are using your UMN Google account, you can edit the sheet and see it populate live whenever you refresh the script above. (Well thats the intention, at least. I've never used Google Script as a web service before, so bare with me)

bookdude13 commented 8 years ago

It does update. That should do the trick. Nice! Will still need the locations mapping @computergeek125 mentioned for the visualizer, but this is a great start.

alexkafer commented 8 years ago

So whenever a sequencer starts a new project, one of the buttons is download layout and it pulls the JSON from the Google Script that in turn pulls the latest data from the Google Sheet.

Heres the gist: https://gist.github.com/alexkafer/176ec799dad60d3206b6c1404b55a389

alexkafer commented 8 years ago

Would it be possible to make universal location guide for both the layout team as well as us?

For example (and it doesn't have to be this specifically):

Take a satelight picture of the Civ building. Along the top write A-Z, and on the left 1-26 or something like that. Then, the location for, lets say, railing-red-lights would be Y6.

That string is stored in the location, the visualizer can do some math automatically without having to store the coordinates. Written out, that would be the following.

A-Z = 100% so Y, being the 25th letter of the alphabet, is 25/26 or 96.1%. (M is 13th, so 50%, etc). 1-26, so 6 would be 6/26 or 23%. There are some slight math issues, but in general its good enough...

Doing this would allow the visualizer to create it's own output. It knows its displaying on a 500px by 500px screen, so Y6 would be the equivalent to (x, y): (96.1% x 500, 23% x 500) or (x, y): (480, 115) from a top left origin.

alexkafer commented 8 years ago

This should be relatively easy to implement for the layout team (@smit7356, thoughts?), easy to understand for any sequencers, and saves a lot of JSON formatting/nightmares and extra object creation.

computergeek125 commented 8 years ago

Don't forget that the data rows start at 2.

>>> for i in range(0,9):
...  print(i,j['fixtures'][i])
... 
0 {'location': 'Location', 'name': 'Object', 'channel': 'DMX Channel'}
1 {'location': '', 'name': '', 'channel': 1}
2 {'location': '', 'name': '', 'channel': 2}
3 {'location': '', 'name': '', 'channel': 3}
4 {'location': '', 'name': '', 'channel': 4}
5 {'location': '', 'name': 'Tesla', 'channel': 5}
6 {'location': '', 'name': '', 'channel': 6}
7 {'location': '', 'name': '', 'channel': 7}
8 {'location': '', 'name': '', 'channel': 8}

My javascript is a bit rusty and my Google Script is rustier, so I can't figure out how to view the return document when it gets executed.

bookdude13 commented 8 years ago

We could also use a set width/height on the visualizer, which could make some stuff easier (like size of elements)

alexkafer commented 8 years ago

@computergeek125 Fixed, thank you.

I don't think you can view the code itself like you can with client side javascript. It would be like trying to view a PHP script or Node script by accessing its API. The source code was posted in the gist above.

ianlsmith commented 8 years ago

I'll talk to Katie about that idea. I think it sounds good. We'll probably have to refine the details later, but it's a great starting place.

computergeek125 commented 8 years ago

@alexkafer I copied the script in the Gist into a new Google Script project. It can execute, I just couldn't find the results.

alexkafer commented 8 years ago

And we don't need to be limited to A-Z. We could use a dash as a separator and have 1-100 for the top and 1-100000 for the side if needed.

For example: 23-12312. We could also implement a multiplier for larger things.

5x12-3x2 with the 5x producing a 5 unit by 3 long element centered around whatever 12-2 would produce.

alexkafer commented 8 years ago

@computergeek125

doGet() will automatically respond to GET requests. You will need to do Publish => Deploy as Web App. Logger.log(), however, will show up in View => Logs.

computergeek125 commented 8 years ago

You could just use ordered pair coordinates, or continue with AA after Z like Excel does (and AAA after ZZ). So then you could have AA29

computergeek125 commented 8 years ago
for (var y = 0; y < values.length; y++) {

could be

for (var y = 1; y < values.length; y++) {

as a possible solution

alexkafer commented 8 years ago

That works, but then you are just ignoring some data.

Instead, I just changed the getSheetValues from getSheetValues(1,1, sheet.getLastRow(), 9) to getSheetValues(2,1, sheet.getLastRow() ,9). Just ignored the first row from the getgo.

EDIT: Cleaned up a few things

computergeek125 commented 8 years ago

Fair enough. Mine was kind of a quick and dirty solution anyways :P

bookdude13 commented 8 years ago

Implemented with more columns and added to TW Github. See https://github.com/teslaworksumn/proton-layout-grabber