Jump to content

DomC

Member
  • Posts

    646
  • Joined

  • Last visited

Everything posted by DomC

  1. I'm as happy as a little child right now! I just made a short movie to show what I can use this for. It allows practically a real-time exchange of wall textures, which can be accessed from a shared location or via web API. The customer can see their printable areas directly with a pre-prepared image file, and I can visualize his demands in real-time. REAL-TIME-VISUALISATION :-))) import image texture.mp4
  2. After again i have to use an import for textures. I searched the script reference and found this one: def vs.SetTextureSize(texture, newSize):    return None I would say it does exactly what we searched for. size in inch. So if we want the texture should have 1000mm in real world we use newSize = 1000 / 25.4
  3. I analyzed that several times with many Networks from users. The more nodes the slower. Do not know, if it depends of "unpurged and many lines" or on the fact, that every node has a geometry representation, Circles and polylines for graphical representation and generating the script. My workflow for PIOs for professional usage is, to have just a few nodes. And one node contains the PIOs main-code. This can be 1000 or 3000 lines. if i export this as a python file it has 1326 lines. The PIO needs 2 seconds to execute. If i export this 500 nodes, it has 29000 lines. Those are just pass nodes. Execution Time of this PIO is 0.07 seconds. So executing 10 times (290'000 lines of code) is not even a second execution of the first example with 1300 lines, needs about 2seconds depending on the size and number of linkes objects etc. Just to show, there is not direct relation between number of lines and speed. I also think about optimizing. But if we say, one should optimize the network, so we have 10times less lines. It would be the development investment on the wrong side maybe. It would sound maybe for the world to say we reduces size of script 10 or 20 times. But is is the wrong priority to focus improvements on the number of created code-lines by marionette. It maybe could result in longer waiting time for your example, because the intelligents to create the code maybe needs then more time. Just want we think clever about where someone would invest developing time. We have maybe the same wishes and should not judge about the right solution. At the End, the wish speed by copy or import objects on the file. And we want security that a deleted node or wrecked graphical network does not change the script. I think the direction of improvement should be, to be able to dump/cache the finished script in a text-based form (one node, one resource, one stile etc.) So your 1500 nodes don't need to be part of your pio anymore. Nodes are good to easy build the script or easy edit update it. Thats why we love graphical scripting. But to use the PIOs in our models in a fast and 100% reliable way, nodes are not needed. Also i am pretty sure, those are producing your speed issue not the number of coded lines.
  4. It is a copy of the node content in that path and the node run without it and user get not messages about that link. At the time you edit the node code also nothing happens if the resource not exists, if the resource exists it will update if the resource is newer than the code inside the node. Only if you exit the node it will report, that the resource is not existing and it tries to create the path. And from this Moment you can edit the Text resource to edit the code. I think this is done, to be able to update the nodes and keep them synced. But a note will not update automatically. Because changing a node without control could break existing scripts. So it is a good think to keep nodes synced if needed or triggered manually. But if you developing a big code content of a node and need to run tests ever 30 seconds the workflow with a direct "import module" is better till the script reached a releasable state. The Import would throw an error a machine which is not linked to that path. So this is just a developing method. Then you go to the #COMMAND;REFFILE; method. Also there is the Method #COMMAND;READONLYREFFILE; with protect nodes from editing. And just read the file.This is how the standard-nodes are created. It is thinkable to download and install the module through the modul installer of Marionette or the Marionette own installer inside the node from Vectorworks Reprository or from a python wheel url. like we import pillow, numpy etc.
  5. If you have luck a tool like ChatGPT can simplify your code or can help optimizing it. But we can not read take the output of those AI tools directly. Still someone have to verify the output or have to know what to do if there is still "a bug" 🐞 Lets make a spontan test. Marionette is drawing a rectangle. A very easy one. I export as a script: 160 Lines (cant post the code directly here) ChatGPT. I ask for making it more compact: Sounds good. Result 104 lines. But i do not except this is faster. Or even the first version is really measurable slow just because of the code BTW, that faild and the "optimized" script do not run, while the original script runs:
  6. You can refer to a "text" resource, which is you node definition code like this at the Beginning of the node: #COMMAND;REFFILE;[UsrLib]/Defaults\Marionette\DomC\SystemWand_v13.py; @Marionette.NodeDefinition class Params(metaclass=Marionette.OrderedClass): The system detects if you edit last in Vectorworks via Node definition or via editor in the external file and will update. But it is not a direct link to an external module. But will work if it is disconnected to the external tool. The negative think about this, we (or i do not know) how to update the node without doubleclick and exit the node. So my beste Workflow to edit external code of a Marionette Node is as following: example: @Marionette.NodeDefinition class Params(metaclass=Marionette.OrderedClass): # APPEARANCE # Name this = Marionette.Node('SystemWand_v13') this.SetDescription("") # Input Ports objs = Marionette.PortIn(None) n_offset = Marionette.PortIn(0) n_height = Marionette.PortIn(3000) n_off_end = Marionette.PortIn(68) n_max_offset = Marionette.PortIn(750) profile_dim = Marionette.PortIn(30) s_group = Marionette.PortIn('') n_profile_max_horiz = Marionette.PortIn(2000) n_profile_max_vert = Marionette.PortIn(3000) n_strut_max = Marionette.PortIn(3000) b_Gehrung = Marionette.PortIn(True, 'Ecke Gehren') # 0 = Einlauf 90, 1 = Fallstrang 2x45 wire_in = Marionette.PortIn(False) # OIP Controls # Output Ports h_poly = Marionette.PortOut() p_vertices = Marionette.PortOut() # BEHAVIOR this.SetLinksObjects() # this.SetListAbsorb() def RunNode(self): import rs.systemwandv13 from imp import reload reload (rs.systemwandv13) rs.systemwandv13.run_node(self, Marionette) So i start normal and then i import my exernal code in the RunNode. Maybe it is also possible to import the complete node code but did not tried(needed) this yet. Important is to reload because of caching. This is a very good method for fast developing without refreshing nodes manually. And then the external module: def run_node(self, Marionette): # import modules from datetime import datetime import json import vs import math import copy from math import radians, sin, cos #from inspect import currentframe, getframeinfo #cf = currentframe() selection_group = [] error_log = [] # parent pio infos pio_handle = vs.Handle(Marionette.parametric_handle) pio_parent = vs.GetParent(pio_handle) pio_parent_type = vs.GetTypeN(pio_parent) #... here you can code everything you also can code inside the node. Hope that helps. Do not know what you want to do. I think the speed of Marionette not really depends of inefficient code. It is maybe the Number of nodes which makes it slower maybe by duplicate or copy/paste an Object. But maybe it is i am sure about this.
  7. Aha, then you could use this one. I like this idea. Also for myself i have tons of scripts and this one can help execute them fast with a menu command and one single click. Thinkable ToDoes: - What would be cool, a palette with a searchable list browser or similar. I was never able to create propper popup with search bar - maybe support for sub-folders in module directory import os import importlib dialog_dict = {} def get_py_files(directory): # Traverse the directory tree and collect all .py files without their extensions py_files = [] for root, dirs, files in os.walk(directory): for file in files: if file.endswith(".py"): # Add the file name without the .py extension to the list py_files.append(os.path.splitext(file)[0]) return py_files def run_palette(directory=''): # Set the directory to search for Python scripts vs.PythonSetSearchPath(directory) # Set the search path for Python modules dialog_dict['res_names'] = get_py_files(directory) # Get all .py files id_dict = {} def dialog_main(): def CreateDialog(): # Create the main dialog layout dialog = vs.CreateLayout('Scripte Schnellzugriff', False, 'OK', 'Abbrechen') last_item_id = 10 act_item_id = last_item_id + 1 vs.CreateStaticText(dialog, act_item_id, 'Klicke auf die gewünschte \rFunktion.\r', -1) vs.SetFirstLayoutItem(dialog, act_item_id) # Create static text items for each script name for res_name in dialog_dict['res_names']: last_item_id = act_item_id act_item_id += 1 vs.CreateStaticText(dialog, act_item_id, res_name, -1) vs.SetItemClickable(dialog, act_item_id, True) vs.SetBelowItem(dialog, last_item_id, act_item_id, 0, 0) id_dict[str(act_item_id)] = res_name # Add a spacer at the end last_item_id = act_item_id act_item_id += 1 vs.CreateStaticText(dialog, act_item_id, ' ', -1) vs.SetBelowItem(dialog, last_item_id, act_item_id, 0, 0) return dialog def DialogHandler(item, data): if 10 < item < 10000: dialog_dict['func_id'] = str(item) return 1 dialog = CreateDialog() result = vs.RunLayoutDialogN(dialog, DialogHandler, False) == 1 return result result = dialog_main() if result: func_id = dialog_dict.get('func_id', False) func_name = id_dict[func_id] if func_id: # Dynamically import and execute the selected module module = importlib.import_module(func_name) directory_with_pytho_modules '/Volumes/SD_Card/Dropbox/Entwicklung/python_scripte' # Run the palette function to start the dialog run_palette(directory = directory_with_python_modules)
  8. I always try to code and comment in in english (anyway the code is not good documented on this prototype script). However this is a good idea to access to the external resource and even not copy the script resource on the working document. The steps would be: 1. Read Workgroup folder in the Windows Registry or the Macintosh Application Support. Which can be done somewhere in this forum there is a workflow to read this path. 2. Adapt the script (The Starter Palette is just one column, if you have over hundred script it will fill up the screen, so this maybe has to by changed to dynamically create more columns if needed) 3. You could use the starter Script from my example. class vssmPaletteRunner(): dialog_dict = {} def run_palette(st_palette_name = 'ArgumentPalettenname', exclude_palettes=['ST Script Module'], res_path = ''): listID, numItems = vs.BuildResourceListN(49, res_path)#Symbols id_dict = {} dialog_dict = {} res_names = [] res_dict = {} for i in range(numItems): res_name = vs.GetNameFromResourceList(listID, i) if res_name != '': res_names.append(res_name) res_dict[res_name] = i dialog_dict['res_names'] = res_names def dialog_main(): def CreateDialog(): dialog = vs.CreateLayout( 'Scripte Schnellzugriff', False, 'OK', 'Abbrechen') last_item_id = 10 act_item_id = last_item_id + 1 vs.CreateStaticText( dialog, act_item_id, 'Klicke auf die gewünschte \rFunktion.\r', -1 ) #vs.SetStaticTextColorN( dialog, act_item_id, 2) vs.SetFirstLayoutItem( dialog, act_item_id ) for res_name in dialog_dict['res_names']: last_item_id = act_item_id act_item_id += 1 fill_number = 55 - len(res_name) fill_string = ' ' * fill_number #vs.AlrtDialog(str([last_item_id, act_item_id, res_name])) #vs.CreatePushButton( dialog, act_item_id, res_name + fill_string) #vs.CreatePushButton( dialog, act_item_id, ' ' * 50) vs.CreateStaticText(dialog, act_item_id, res_name, -1) vs.SetItemClickable(dialog, act_item_id, True) #vs.AlignItemEdge( dialog, act_item_id, 3, 1, 1 ) #vs.CreateStandardIconControl(dialog, act_item_id, 0) vs.SetBelowItem( dialog, last_item_id, act_item_id, 0, 0 ) if 'Elektro' in res_name: #res = vs.GetColorButton(dialog, act_item_id) vs.SetColorButton(dialog, act_item_id, 65000,0,0) #res = vs.GetColorButton(dialog, act_item_id) last_item_id = act_item_id id_dict[str(act_item_id)] = res_name last_item_id = act_item_id act_item_id += 1 vs.CreateStaticText(dialog, act_item_id, ' ', -1) vs.SetBelowItem( dialog, last_item_id, act_item_id, 0, 0 ) return dialog # Sample dialog handler # Uncomment this code if you want to display the dialog def DialogHandler(item, data): if item == 12255: #Enter Dialog for key in id_dict: id = int(key) vs.SetItemClickable(dialog, id, True) #vs.SetItemText(dialog, id, id_dict[key]) # works also #vs.SetControlText(dialog, id, id_dict[key]) #crash #vs.AlignItemEdge( dialog, id, 3, 1, 1 ) vs.SetStaticTextColorN( dialog, id, 2) #does nothing #vs.SetColorButton(dialog, id, 62000,0,0) #does nothing if 10 < item < 10000: dialog_dict['func_id'] = str(item) return 1 if item == 1: pass result = False dialog = CreateDialog() if vs.RunLayoutDialogN(dialog, DialogHandler, False) == 1: result = True return result result = dialog_main() if result: func_id = dialog_dict.get('func_id', False) if func_id: script_name = id_dict[func_id] script_id = res_dict[script_name] #vs.AlrtDialog(str([script_name, func_id, script_id])) try: existing_res = vs.GetObject(script_name) if existing_res != vs.Handle(0): vs.DelObject(existing_res) except: pass new_res = vs.ImportResToCurFileN(listID, script_id, None) vs.PythonExecute(str(vs.GetScriptResource(script_name)[1])) vs.DelObject(new_res) #GetScriptResource vssmPaletteRunner.run_palette(res_path = '/Users/dominiquecorpataux/Downloads/test2.vwx') I modified a little: 1. BuildResourceListN with a path to the file 2. Deleted the part with the palette-name-filter That is is defined as a class is not necessary for single use. Just is necessary if you want to call the function outside in another script to path values between different scripts. And the fullPath is the path to the workgroup folder Script Document. You can test with a single path to your script document. Two open things: 1. I think the script have to be temporary imported to run and deleted after which looks not very elegant 2. "vs.PythonExecute(str(vs.GetScriptResource(script_name)[1]))" runs a python script. I do not know how to run pascal code here.
  9. Hi Interesting Thread. Also i am also very interested to a facelift of script function palette. Some industries needs a lot of custom functions (easy ones like custom-tool in the tool menu) I have an own approach of organizing through one single palette, which have Favorite Scripts but can access to non-favorite scripts as well over the separator. Also there is a dialog, which allows to add and remove script to the favorite palette. Not finished yet (i will have to implement some presets to easy reset palettes to default) The scripts have to be numbered to keep position in they separator. Not very graceful but best i saw so far. I have a class palette_runner. Which runs a script by name. And in every seperator i call the scripts which starts with a sorting number till the next separator. And a script manager to manage the favorite sript-palette. So i have just one visible script-palette which i have to re-position. ScreenFlow.mp4 VSSM Vorgabe in Arbeit DC_bem scripts_leer.vwx
  10. Small Note to this I needed again the automated creation of textures. So far it seems, that the size of the texture is generally not consistent it the document unit is not in imperial units. Best solution i fount is to #insert at the beginning of the script unit_original_predifined = vs.GetPrefInt(170) vs.SetPrefInt(170, 1) #and reverd back to preview units at the end of the script vs.SetPrefInt(170, unit_original_predifined)
  11. Hello Possible, that the Objects got Broken (there was a Bug, Styled Marionette PIOs got Broken in Projekt Sharing under specific Circumstances lower than Version Update 5). Or maybe the Symbol Based Graphic is hidden in 2D and just visible in 3D View. There you had to change The Object inside the Symbol all on top view or all on 3D. If you mix just the symbol content of the activated view would be visible. If broken, maybe try to edit the Style if it is styled and look, what is broken inside the style. If so, try to find on an older Backup your script and copy it inside the style. Or if you did not changed the script, just the Symbol, you could re-import the style from the Download-Version and replace the "maybe broken" existing Style.
  12. I already use a new Version since 2024. Had missed uploading it. - This would work on 2024 and i think, there was a bug with landscape and portrait format in some versions (it was exactly wrong side out). 1.0.3 fixe that issue. - Also new Feature with prefix and actual Datetime Usage: Copy and always paste in place. Or set coords of PlugIn to 0,0 in Info Palette. So it will automatically find the right coords on the pages.
  13. hi @raouls For me it works, when the option is ON. For you it works when this option is off. What i observed is the following: 1. I have the main Window on the external screen, second screen is internal display of mac book 2. Vectorworks is startet on the external screen 3. If The Vectorworks border nearer than 3 cm on the screen border where the internal display is arranged i have epic lags for different actions. Also other Things seems to get slow (Finder) 4. If i drag the VW Window away from the border it is getting fast as expected 5. If i turn ON (Screens uses different spaces) it also works as expected and i can work with a miximized Vectorworks Window So i am little puzzled. I i update my OS, it looks like, that i have to switch OFF the Option again.
  14. Hi @raouls I wonder, it that option on your spaces settings (print screen german version above) was on or off?
  15. Hello I got a new MacBook Pro m3 end last year. I have sonoma 14.3. After setup my new system i had a short time of very big frustration because the performance was not as i excpected. Slow and epic lags (4 seconds or more and juddery).Also other things worked laggy like text editor or Filemaker. But there i am not so sensible. I think those was lags maybe another user could would take as "normal" and ignore it but i compared to my 2018 intel mac it was slower. On the internal Monitor everything was fast very fast and smooth. Also with a new user (which is often the workflow to test if it is something related to settings of the system) I found the option "screens uses different spaces" (which is translated from my german version. Do not know, if this is the exact name of the option in english too) which was turned off. After switching it on (which does make not difference for me to work) it is the best performance i ever dreamed of and very stable. Maybe can you look at that option @Dagny? I fellow just updated his intel Mac on 14.5 and have issues. The other fellows with a Apple silicon not issues after updating on 14.5 So personally i will stay on 14.3 till i can take the risk of something do not work anymore.
  16. Took a quick look I think, it is not the Marionette Network or the code inside the Marionette that produces the crash from my sight. It is the PIO which crashes by handling it in the script. I can see a crash by duplicate and move with alt-key and by edit the script. No crash with a Version, that not contains the PIO you insert in the script. That indicates, that the PIO you use inside script is crashing. Also not crash in 2024 (but maybe still an issue). Some Points that i saw: 1. Insert PIO then delete after The strategy is, to insert a PIO which has the same size as the segment of a polygon. If a Bool is 0 then delete the PIO. So you insert the PIO, set Bool to 0 and then after insertion delete PIO. Also i see, that the text you insert is not deleted in that case what would result in async text and PIO. Better would be not insert Bool is 0. Also then you have to filter the rest of the network also. 2. Writing to the record "Korpusmöbel - Objektinfo" Which is a read-only record in my opinion. Or minimum will be overwritten by the PIO itself. Maybe it works but still something risky. 3. Crash No idea what exactly produces a crash. Definitely no crash without PIO if i deactivate the symbol node. Also no crash, running the network not as a PIO Node just as a Network. The used cabined PIO may not be designed to exist inside Marionettes or other PIOs. That's maybe the source of the crashes. However i would 2024 give a try and skip 2023. Because there i can see no crash.
  17. The Script was made, screenplane planar objects was still a standard. it would still work with grouped screenplane objects. It seems, that the dup-container node puts screenplane planar objects on the 2D representation of the PlugIn. And grouped layerplane planar objects were putted on the 3D component of the plugIn. If we switch on top view we can see the groupes. Thanks for sharing that issue.
  18. Hello Which Version you would need? Regards Dominique
  19. It seems to be possible also by deleting with the selection state. So far it seems to be the best option. vs.DeleteObjs()
  20. vs.DoMenuTextByName('Clear',0) OK, this would delete the Original PIO. But i am not feeling good by using a DoMenuText in this situation.
  21. Hello I have a PIO with Button-Widgets. One of them should convert the PIO in another PIO and back. Is it possible to delete the PIO with the Button at all? elif theButton == cButton6: if replace_object(): vs.DSelectAll() vs.SetSelect(GlobalValues.pio_handle) vs.AlertInform('Press delete after action to delete original object', '','') #This would work so far vs.DelObject(GlobalValues.pio_handle) #This wont work (and if it would work i think it may result in a crash?)
  22. Should still work in 2024 (tested on mac 2024 Sonoma) 1. Select Excel File (I use Version 1.0.4 from xlsx) By clicking the Button of the Pick File Node. But if this was wrong it would throw an error message. Maybe to prevent path issues copy on desktop 2. Sheet Name input. This should match to the sheet name in the excel file. But if this was wrong it would also work by taking the first sheet name. 3. Check "Confuguration Dialog" Anyway, if input of the xls import was wrong it would throw also an error. If just nothing happens, the creation of space maybe fails. The reason maybe could be there is no area value or the area value was not returnet on output. column1 is imported without area not space. Also click the debug method to see, how many areas are outputed. It is normal we have more field values and values than areas. Because the field and values repeat because to match the set Record Field Node. If we have 3 columns it return double fields as area outputs. If we have 5 columns it returns 4 times more fields than area outputs etc.
  23. This are the options: 1. Saving/having an external (excel) list and make it fits to the input list of the Marionette. In Excel we can use formulas to have a list and a second sheet whitch grabs the list just for the needed columns. Then import the external list directly into the worksheet inside of Vectorworks. 2. If you are using interiorcad, you can configure a cutting list export, which fits to the needs and then follow step one 3. There is an internal list you could define with interiorcad which writes directly to a worksheet 4. Copy/paste can be tricky, because pasting in a worksheet may fail because you had to activate exactly the range of the pasted list first, which is hard. So import is the better option. 5. At least it could be an option to make (small) adaptions to the script so that it reads the needed columns automatically of any list. Or even directly for external file more even directly from part out of the drawing without doing any export/ import steps. I think the simplest way is to export to excel, then delete the unwanted columns and import into the Worksheet with the worksheet menu. That brings me to the idea to maybe make an example which directly reads one of the standard cutting list formats of interiorcad.
  24. I think the column "Drehbar" was never implemented (In fact it had no impact if i write there 0 or 1 it just took the checkbox "Rotation erlauben" which was a global option for all materials). I improved the Script with Version 1.0.4 and now it reads the column as soon as i checked the checkbox "Rotation erlauben". This setting will take care of the column "Drehbar" (Rotateable)
  25. Hi Did not looked into your code details because i keep that theme for a time from my brane. I think the general we can take an objects entity matrix and set that entity matrix to another object. With Set- and get Entity Matrix. This is not really hard. What was always the point is, that having some points in 3D which defines a plane transferring to an entity matrix wen need for the SetEntityMatrix Script command. What i have so far in that direction: 1. A way to have 3 points and gets an VW entity matrix of 3 points. Somehow my code os spreaded over a bigger code so i do now know if exactly that works in your example. code and functions i needed there code snippeds. I would say the code here took me several hours of figuring out that easy looking code. But i think at the end it maybe needs just a few lines if it was optimated. Also the vs.Vec2Ang() solves a lot. It would be hard to find out in which quadrant the plane is oriented and the direction of the points etc.. Like i told, not looked yet into your code. This snipped worked here for getting rotation matrix from 3 points. Not sure, if it works in all directions and for vertical planes in every situation. I always thought there must be a general solution for that. And there is but on the other side we must fit it to the vw SetEntity matrix also the plane matrix are different from the rotation matrix. 2. Getting a centroid and a plane. With that we can project points on that plane (not a vw plane, a plane defined by the normal matrix of the custom getPlane Node in that example). Here: At one point everything is turning into hard work. But we still have fun 🙂
×
×
  • Create New...