Jump to content

Myke

Member
  • Posts

    27
  • Joined

  • Last visited

Posts posted by Myke

  1. One last thing, this script looks like it works, I just need to refresh the view of the lights that are getting edited. Does vs.LDevice_Reset work like the Refresh Lighting Devices menu button?

    Thanks for the help. Cheers
     

    Here is the current version of the script for anyone interested:

    import vs
    import http.client
    import json
    
    instrumentType = None
    # fixtureMode = None
    # wattage = None
    # weight = None
    frameSize = None		
    position = None
    purpose = None 	
    channel = None
    unitNumber = None	
    universeAddress = None
    circuitNumber = None
    circuitName = None
    dmxLine = None
    dmxFootprint = None
    # deviceType = None
    color = None
    template1 = None	
    template2 = None	
    user1 = None
    user2 = None
    user3 = None
    user4 = None
    user5 = None
    user6 = None
    coordinates = None
    __UID = None
    __class = None
    layer = None
    
    def eachLight(h):
        # vs.SetRField(h, "Lighting Device", "Wattage", wattage)
        vs.SetRField(h, "Lighting Device", "Postion", position)
        vs.SetRField(h, "Lighting Device", "Channel", channel)
        vs.SetRField(h, "Lighting Device", "Purpose", purpose)
        # vs.SetRField(h, "Lighting Device", "Weight", weight)
        vs.SetRField(h, "Lighting Device", "Unit Number", unitNumber)
        vs.SetRField(h, "Lighting Device", "UniverseAddress", universeAddress)
        vs.SetRField(h, "Lighting Device", "Circuit Number", circuitNumber)
        vs.SetRField(h, "Lighting Device", "Circuit Name", circuitName)
        vs.SetRField(h, "Lighting Device", "Inst Type", instrumentType)
        # vs.SetRField(h, "Lighting Device", "Fixture Mode", instrMode)
        vs.SetRField(h, "Lighting Device", "DMX Line", dmxLine)
        vs.SetRField(h, "Lighting Device", "num channels", dmxFootprint)
        # vs.SetRField(h, "Lighting Device", "Device Type", deviceType)
        vs.SetRField(h, "Lighting Device", "Color", color)
        vs.SetRField(h, "Lighting Device", "Gobo 1", template1)
        vs.SetRField(h, "Lighting Device", "Gobo 2", template2)
        vs.SetRField(h, "Lighting Device", "User Field 1", user1)
        vs.SetRField(h, "Lighting Device", "User Field 2", user2)
        vs.SetRField(h, "Lighting Device", "User Field 3", user3)
        vs.SetRField(h, "Lighting Device", "User Field 4", user4)
        vs.SetRField(h, "Lighting Device", "User Field 5", user5)
        vs.SetRField(h, "Lighting Device", "User Field 6", user6)
        vs.SetClass(h, __class)
    
    
    try: 
        connection = http.client.HTTPConnection("localhost:8000")
        connection.request("GET", "/Test")
        response = connection.getresponse()
        rawData = response.read().decode('utf-8')
        lxdata = json.loads(rawData)
        isAvailable = True;
        connection.close()
    
    except Exception:
        print(Exception.__traceback__)
        isAvailable = False;
        
        
    if isAvailable: 
        lights = [] #name, handle
        def get_lights(handle):
            name = vs.GetName(handle)
            lights.append([name,handle])
        # I think c means criteria?
        criteria = "((PON='Lighting Device'))" 
        vs.ForEachObject(get_lights, criteria)
        
    
        for light in lxdata:
            uid = light['__UID']
            
            for light_name, handle in lights:
                if light_name == light['__UID']:
                   
            
                    for key, val, in light.items():
                        if key in globals():
                            globals()[key] = val
                            # print(val)
                            print(key)
                            eachLight(handle)
    else:
        pass
    # print(instrumentType)

     

  2. @DomC

    That definitely works and it's much faster that the original. I was actually going to test using another method.

     

    The idea was to create a lookup table on the app that imports the data from Vectorworks, it would track all of the changes and then send them to VW. The only information that would be contained is the UID and any fields that got changed. That would be the minimum amount of data to import into VW reducing the time complexity significantly.



    I'm still in the process of understanding your script but Im also very interested in merging both together to get something very performant. 
    It looks something like this, basically I took your set of values and found them in the global scope to just loop over them. Unfortunately that means there are 3 loops nested inside of each other. I think I can get rid of the outer most one by removing the JSON name when I send it, but as for the loop over the keys and values I really want to know if there are ways I can condense the two
     

    if isAvailable: 
        lights = [] #name, handle
        def get_lights(handle):
            name = vs.GetName(handle)
            lights.append([name,handle])
        # I think c means criteria?
        criteria = "((PON='Lighting Device'))" 
        vs.ForEachObject(get_lights, criteria)
        
    
        for light in lxdata["LightingDevices"]:
            uid = light['__UID']
            for light_name, handle in lights:
                if light_name == uid:
                   
            
                    for key, val, in light.items():
                        if key in globals():
                            globals()[key] = val
                            # print(val)
                            print(key)
                            eachLight(handle)

     

     

  3. I might have figured out a couple of things.

    Json.loads() has a maximum so I am overfilling the buffer and will need to implement a stream of some kind. The other thing I've learned is that the math for the time is something like n^2 so it scales terribly. Basically I need to remove a loop, and parse as few parameters as possible.

     

    I do have some questions about updating objects with either vs.SetRField or vs.ForEachObject.
    - Where does the symbol UID come into play? If I only wanted to update one symbol I should use the UID generated to specifically point to it?

    - Are they're any other attributes that are mandatory to effectively update a symbol such as a Layer and Class.

     

    Thanks

  4. For the number of lights, I would like it to scale near infinitely the current limit is 200 as far as I've tested. That's nowhere near enough. It does indeed loop for every light, but there is no change to the fields when above the 200 fixture limit. To solve this I could simply limit the loop so that it updates the first 200 fixtures and then the next 200 and so on. But that increases the time problem that Im having. 

    The Json loads fine there is no issue with that its just that there isn't an update at all

     

    Hope this sheds some more light

  5. Hello,

    I was using this script to import json data and update the lights on a plot, and it works. But very slowly VW is unresponsive since the script is still running. Is there a way to optimize this so that the performance is better.

    If im not mistaken the ForEach function should be similar to a standard for loop and shouldn't be that bad in terms of time.

     

    Also there seems to be an object limit that I've hit, were this script tries to run but then quits with nothing being updated. 200 looks like the limit anything above that and the script just quits.

     

    I would appreciate any suggestions.

     

    Thanks

    import vs
    import json
    import http.client
    
    instrType = ""
    instrMode = ""
    wattage = ""
    weight = ""		#Added
    position = ""
    purpose = ""	#Added
    channel = ""
    unitNumber = ""	#Added
    universeAdress = ""
    circuitNumber = ""
    circuitName = ""
    uid = ""
    fixtureMode = ""
    dmxLine = ""
    dmxFootprint = ""
    deviceType = ""
    color = ""
    template1 = ""	#Added
    template2 = ""	#Added
    user1 = ""
    user2 = ""
    user3 = ""
    user4 = ""
    user5 = ""
    user6 = ""
    className = ""
    
    
    def eachLight(h):
        vs.SetRField(h, "Lighting Device", "Wattage", wattage)
        vs.SetRField(h, "Lighting Device", "Postion", position)
        vs.SetRField(h, "Lighting Device", "Channel", channel)
        vs.SetRField(h, "Lighting Device", "Purpose", purpose)
        vs.SetRField(h, "Lighting Device", "Weight", weight)
        vs.SetRField(h, "Lighting Device", "Unit Number", unitNumber)
        vs.SetRField(h, "Lighting Device", "UniverseAddress", universeAdress)
        vs.SetRField(h, "Lighting Device", "Circuit Number", circuitNumber)
        vs.SetRField(h, "Lighting Device", "Circuit Name", circuitName)
        vs.SetRField(h, "Lighting Device", "Inst Type", instrType)
        vs.SetRField(h, "Lighting Device", "Fixture Mode", instrMode)
        vs.SetRField(h, "Lighting Device", "DMX Line", dmxLine)
        vs.SetRField(h, "Lighting Device", "num channels", dmxFootprint)
        vs.SetRField(h, "Lighting Device", "Device Type", deviceType)
        vs.SetRField(h, "Lighting Device", "Color", color)
        vs.SetRField(h, "Lighting Device", "Gobo 1", template1)
        vs.SetRField(h, "Lighting Device", "Gobo 2", template2)
        vs.SetRField(h, "Lighting Device", "User Field 1", user1)
        vs.SetRField(h, "Lighting Device", "User Field 2", user2)
        vs.SetRField(h, "Lighting Device", "User Field 3", user3)
        vs.SetRField(h, "Lighting Device", "User Field 4", user4)
        vs.SetRField(h, "Lighting Device", "User Field 5", user5)
        vs.SetRField(h, "Lighting Device", "User Field 6", user6)
        vs.SetClass(h, className)
    
    # Substitute open(path) for GET request with a json.load
    try: 
        connection = http.client.HTTPConnection("localhost:29212")
        connection.request("GET", "/VectorworksGet")
        response = connection.getresponse()
        rawData = response.read().decode('utf-8')
        data = json.loads(rawData)
        isAvailable = True;
        connection.close()
    
    except Exception:
        print(Exception.__traceback__)
        isAvailable = False;
    
    if (isAvailable):
        for p in data['LightingDevices']:
            instrType = p['instrumentType']
            instrMode = p['fixtureMode']
            wattage = p['wattage']
            weight = p['weight']
            position = p['position']
            purpose = p['purpose']
            channel = p['channel']
            unitNumber = p['unitNumber']
            universeAdress = p['patch']
            circuitNumber = p['circuitNumber']
            circuitName = p['circuitName']
            dmxLine = p['dmxLine']
            dmxFootprint = p['dmxFootprint']
            deviceType = p['deviceType']
            color = p['color']
            template1 = p['template1']
            template2 = p['template2']
            user1 = p['userField1']
            user2 = p['userField2']
            user3 = p['userField3']
            user4 = p['userField4']
            user5 = p['userField5']
            user6 = p['userField6']
            className = p["class"]
            uid = p['__UID']
            criteria = "(N='" + uid + "')"
            vs.ForEachObject(eachLight, criteria)

     

  6. Yes! This does run menu commands, apple script is surprisingly competent. I will need to make something similar in Windows, probably using PowerShell or similar. I'll add a similar template when that's good and ready.

     And for anyone who tries this out, I would first recommend removing the repeat syntax. The idea of this script is to have some automation of VW commands outside of the program, but it needs to constantly be checking if the app is open.

     

    @michaelk That was the same post that pushed me to automating my python scripts
     

    • Laugh 1
  7. Hullo,

     

    I want to make sure I understand this process properly, but VW uses a .vsm file type to represent plugin functionality in python and vectorscript. That reminds me of the SDK build where functionality was turned into a DLL to be read by Vectorworks. Is this a similar case

    Aside from that I've struggled to find the process of converting a working python script into that .vsm any help would be appreciated!

  8. For anyone who is interested in similar functionality I have a base template as a starting point

    on run {input, parameters}
    	
    	repeat 
    	
    	tell application "System Events"
    		tell process "Vectorworks 2022"
    			name of every menu of menu bar 1
    			click menu item "menuItem" of menu "menuBarItem" of menu bar 1
    		end tell
    	end tell
    	
    	end repeat
    	
    	return input
    end run

    Cheers!

    • Like 1
  9. Hello,

     

    I was wondering if there was a good way to trigger a Python script in VW using AppleScript? There are some scripts that can be "installed"? if im not mistaken. Is it possible to have VW run that command when the AppleScript ask it too? I got a bit interested in this kind of workflow when Pat Standford mentioned it. 

     

    If the answer is yes, then my follow up question would be: do I need to use an installation script ie. install.py to add the functionality?

    Thanks

  10. I'm a bit familiar I've been learning as I went this project. Using the example in the ForEachObject documentation I've gotten this far in terms of code.

    Do I now need to attach this to ModuleMain?

     

    I've attempted to follow the templates but I know that this doesn't quite work.
    REGISTER_Extension<DataExchange::TraverseFunction>( GROUPID_ExtensionVSFunctions, action, pInfo, ioData, cbp, reply );

     

    To make things clear I am looking to

    1) get / set all lighting devices.  

    2) place them in a list<lightingDevice>

    3) Turn it into a Json String 

    4) Send over the network

     

    I can take care of 2-4 #1 is the most pressing.

     


    Thanks,

    class DataExchange{
        
        
    	// I've changed this to be static otherwise I can't refenence it in the (gSDK->ForEachObject( allSymbolDefs, MyCallBack, & data );)
        static void MyCallBack(Handle h, CallBackPtr cbp, void *env)
        {
           lightingDevice* pEnv = (lightingDevice*) env;
    
        }
    
        void TraverseFunction()
        {
            lightingDevice data;
    
           //I presume this fetches all defined symbols. I'm only interested in Lighting Devices is there something I can do or is there no need for concern? 
           gSDK->ForEachObject( allSymbolDefs, MyCallBack, & data );
    
          //Attempting to write to a file for inspection. Let me know if there is a better way
            ofstream MyFile("filename.txt");
            // Write to the file
            MyFile << data.instrument_type;
            // Close the file
            MyFile.close();
        }
    };
    
    // Object to format the data with.
    struct lightingDevice {
        string instrument_type;
        string fixture_mode;
        string wattage;
        string position;
        string channel;
        string patch;
        string circuit_number;
        string circuit_name;
      ...
      };

     

  11. I am on Mac, but I'm looking to make things cross platform.

     

    Unfortunately the SDK seems like the simplest option given the constraints. And since I have the python script flushed out I should only need to create a class and create the same functionality in C++

     

    That being said, what are the equivalent methods for these vs:functions:

    - vs.GetRField(h,"Lighting Device","Inst Type")

    - vs.GetName(h)

    - vs.GetClass(h)

    - vs.GetLName(vs.GetLayer(h))

    - vs.GetSymLoc(h),
    - vs.GetSymRot(h),

    - vs.Count(lightingInstrumentCriteria)

    Also can I assume that the set methods are similar but need a method name change? ie VCOM::GetRField(h, "Lighting Device", "Inst Type") => VCOM::SetRField(...) I don't know if that's the correct syntax just an example

     

    Also I've been using these scripts for referencing:

    https://github.com/brageiversen/vectorworksPlugins/blob/main/ImportExport/ImportLightingInstrumentsJSON.py

    https://github.com/brageiversen/vectorworksPlugins/blob/main/ImportExport/ExportLightingInstrumentsJSON.py

     

     

    Thanks

  12. That solves the Sending side, but I'm having a hard time figuring out the receive. Creating the script isn't an issue, but figuring out how to run it without user intervention is since it would be annoying to need to press a button each time you want to get your data.

     

    Can anything be done externally, where VW gets a message (localhost network) and that can be used to run a script?

     

    If not then I'll probably need to look into the SDK

  13. Well that scraps the first plan I had. And I'm not quite ready to take the C++ red pill yet.

     

    Is is possible to execute a script with a button push? I believe we can make buttons in python my next idea is to execute a similar script with button pushes and keybindings. 

     

    The idea would be every time a user saves this script runs.

     

    Thoughts?

  14. Hello again, I'm getting to the point where I'm putting my VectorWorks script together. For context the idea is that I can send information over the localhost network from Vectorworks to wherever I would like. After testing the code in a VW script it does run, but its runtime overrides VW and the only way to escape is by force quitting the app. 

     

    From a practical standpoint I don't really want the server to close with the exception of user intervention like a menu button. Is there a way to have this script running in the background as long as possible (with certain close conditions both manual and automatic) but it doesn't compromise the functionality of VW?

    Attached below is the code for the server.

     

    Thanks

    VW_Server_Script.rtf

  15. Hello, I have a quick question in hopes of not doing any unnecessary work. I've been playing around in Python with the 3.9 version but want to make sure that VW supports it. From what I've gathered from the developer forum VW 2015 supports 3.4, does anyone know if this has changed in the more recent VW versions? If there is a break down of Python version supported for each VW version I would greatly appreciate that.

     

    Thanks!

  16.  

    I may have come across a better solution to my data transfer requirement. 

    Using two Json files where VW plugin writes a files with the lighting device data, to be read by my program.
    And my program reads the data edits it and then writes to a different Json file to be read by the VW plugin. 

    I am trying to think of some automatic triggers that could be used to know when to send the changed data out again. Are there some smart ways of doing it. Or should I take a simpler approach and use a timer to send changes from VW and my program while also checking for changes from the other?

  17. Yes I am looking to have the on an automatic trigger hence the use of the SDK. To be clear I specifically want to know how to send lighting information out of VW, edit it (within reason), and then send it back in dynamically. I am hoping to reduce complexity while still affording those three conditions. 

     

    I will definitely look at the Debug List view since I'll get a better idea of how the data is structured. Thank you very much for that.

     

    I'll do more research and testing.

     

    Thanks a lot!

     

  18.  

    I think I managed to figure something out regarding the testing, although there are some kinks to workout. Building the plugin for data exchange is my next move and I have some more questions.

     

    I took a bit of deep dive into some of the SDK files looking for method(s) that would allow me to build a plugin that can dynamically send LightFixtureSymbol data (Symbol_Name, Channel_Num, etc) to an external program that I would build and then send that data back.

     

    If you know of a specific method in the SDK I would very much like to know.

     

    Some methods/functions I have questions about:

     

    ForEachObject()
    The documentation seems to be clearer on this method but the return type is virtual void. Is this to be overridden in a user created derived class and then specified with a return type?  If a user is going to implement this method are there any guidelines to structuring it?

     

    ForEachObjectInList()

    Unfortunately there is less information on this method, the name suggest that it deals with objects in a list. Should I assume that the use of ForEachObject() would generate the list and then

     

    GetObjectVariable(..)

    I am not sure what the return type is. If its just a list of strings then that’s more than enough. Also within its parameters can you specify what type of object your looking for? Such as passing 2 to see if its a lineNode?

     

    GetObjectPropertyChar(…)

    Continuing on from the aforementioned, am I correct in assuming that this is more specific? Such as returning line thickness or length. Is there a list of inPropID’s

     

    traverseWhat;

    What is the difference between: allDrawing and allSymbolDef and which, if either, would give me access to the properties?

     

     

    This might be a bit early, but find holes in my logic earlier in the process is preferable to later. Assuming what I’ve searched building a method for retrieving LightFixutureSymbol data might look like

     

    private ArrayList<AnotherClass> instrumentData

     

     

    struct InstrumentData

    {

    string symbol_Name; //or const char*

    short channel_Num;

    }

     

    void MyCallBack( Handle h, CallBackPtr cbp, void* placeholder){ // Correct me if I’m wrong but the void* seems like a placeholder for a chunk of data that’s doesn’t have a specified type, hence why I changed it from env to placeholder

    InstrumentData* instData = (InstrumentData) placeholder;

    …. //Not sure what comes after

    }

     

    ArrayList<AnotherClass> traverseObjectsForLights()

    {

    InstrumentData data;

    gSDK->ForEachObject( allDrawing , MyCallBack, & data);  // What is the gSDK and why does the traversal need to be passed. Or does it call functionality from an interface.

    // is the data now in my data object? Assuming it it

     

    gSDK->ForEachObjectInList(81 [kLightNode], MyCallBack, callBackLamda) = 0; // Not to familiar with lambdas, but should I attempt to make one in the above struct class or is there another approach

    // Presumably it returns something along the lines of

     

    fixtureData = ForEachObjectInList().toArray()

     

    for(int i = 0; i =< fixtureData.size; i++)

    {

    instrumentData.add(fixutreData.get(i));

    // std::cout << instrumentData.get(i) << std::end; //Checking

    }

    return instrumentData;

    }

     

     

    I hope this isn’t too much, and if I haven’t mentioned already I am a bit of a novice when it comes to programming.

     

    Thanks

  19. Hmm,

     

    I doubt this will be my last question, but I seem to be having trouble getting a simple std::coat << "Hello, World" << std::end; out of the program (with an int main() function around it. Everything builds successfully, but nothing is outputted to the terminal. I usually use the command line interface to test and check functionality before I scale it to a proper GUI. If you have any tips regarding this I would appreciate it.

     

    Thanks

  20. Thanks for the help! I have another question but this time regarding the UUID and how to exchange data between Vectorworks and the SDK. Specifically regarding symbol data such as speakers and lights. Is there a specific method or function in the SDK that facilitates this transaction? 

     

    Thanks!
     

×
×
  • Create New...