Jump to content

twk

Member
  • Posts

    877
  • Joined

  • Last visited

Everything posted by twk

  1. Hmm have you tried using these outside of plugins? The same code flow for me crashes vw. I'll post back with code soon
  2. there is an error in the code, the line should be instead: if rst_handle not in [0, None]: <... rest of code here ...>
  3. I'll have to think about this, the vs.GetObjectVariableReal(vp_largest, 1003) function returns the scale in mm, regardless of the document units. I don't have any experience either in imperial scales as we use the metric system. Will post back when found a solution..
  4. @tbexon, you're a genius, I kept crashing previously, regardless of the developer mode on or off. The only thing that was missing from my code, was the reset object_hand call. Also, what is happening here: if theEvent == tb.Constants.kObjXPropPreference: defaultVals = {} # Creates blank Dict for default vals MakePropertiesDialog() don't think I've ever use the kObjXPropPreference constant in my plugins
  5. I noticed that in your code, the try and except block within the create_tab_definition function may not work as intended. Vectorworks won't actually throw an exception if the object name already exists, so the except block might never be executed. Instead, you could check whether vs.NameObject(f"RST_{story}") returns a valid handle (i.e., not [0, None]) to determine if the object already exists. If it does, you can simply retrieve the handle and create the duplicate object within the existing folder. Here's an updated version of the create_tab_definition function with this check: def create_tab_definition(handle_ref_tab, story): rst_handle = vs.NameObject(f"RST_{story}") if rst_handle != [0, None]: folder_handle = rst_handle[0] else: folder_handle = vs.BeginFolderN(18) vs.NameObject(f"RST_{story}", folder_handle) vs.EndFolder() ws_handle = vs.CreateDuplicateObject(handle_ref_tab, folder_handle) return ws_handle The other thing that I havent tested, or come accross is using the vs.CreateDuplicateObject to duplicate resources. Does that actually work? I will try later.
  6. What is the logic flow of your code? -> get_custom_info_ok, plugin_name_internal, plugin_handle, plugin_record_handle, plugin_wallHand = vs.GetCustomObjectInfo() -> if get_custom_info_ok: <main plugin code functions> -> theEvent, theMessage = vs.vsoGetEventInfo() set an AlrtDialog for both theEvent, and theMessage and see what you get
  7. You could play around with putting each site model on its own layer for the 3 park levels as suggested above? If i'm understanding correctly? Then using hardscapes, with targetted design layer modifiers, for both the hardscape and the site model. ie: - each level will have additional design layers specific to it, for restricting modifiers to each site model DTM Do you have sections/sketches to show your intention?
  8. Interesting, "Title Block Border" objects may have a symbol name within it that controls the graphical layout of it, however this symbol is housed in a unique object (the Title Block Border object), that is placed on each sheet layer separately. If you were to go down the naming route, you'd have to have a unique name for each title block border object on each sheet layer, which is not optimal. I've added checks in the code below, to alert you of the amount of sheets found in the document, and then another alert dialog to tell you if the criteria didn't find any title blocks or viewports on the layer, as its looping through it. Try it again and see what messages the alert dialog throws out. If not, post/DM me your VWX file, maybe your sheet/title block setup is different. import vs alert_dialog = lambda x:vs.AlrtDialog(str(x)) def list_sheet_layer_names(): layer_names = [] hLayer = vs.FLayer() while hLayer != None: layer_names.append(hLayer) hLayer = vs.NextLayer(hLayer) layer_type = lambda x: vs.GetObjectVariableInt(x, 154) layer_names = [vs.GetLName(x) for x in layer_names if layer_type(x) == 2] # filter to only include sheet layers return layer_names def get_objects_from_criteria(criteria): object_handles = [] def get_obj(h): object_handles.append(h) vs.ForEachObject(get_obj, criteria) return object_handles def get_object_area(object): top_left, bot_right = vs.GetBBox(object) length = bot_right[0] - top_left[0] height = top_left[1] - bot_right[1] return length * height sheet_layer_names = list_sheet_layer_names() alert_dialog(f"No. Sheets in Document : {len(sheet_layer_names)}") if len(sheet_layer_names) > 0: for layer in list_sheet_layer_names(): titleblock_crit_str = f"(((L='{layer}') & (PON='Title Block Border')))" viewports_crit = f"(((L='{layer}') & (T=VIEWPORT)))" titleblocks = get_objects_from_criteria(titleblock_crit_str) viewports = get_objects_from_criteria(viewports_crit) if all([len(titleblocks) > 0, len(viewports) > 0]): titleblock = titleblocks[0] # get single first found only vp_area_max = 0.0 vp_largest = None for viewport in viewports: vp_area = get_object_area(viewport) if vp_area > vp_area_max: vp_area_max = vp_area vp_largest = viewport if vp_largest: vp_scale = vs.GetObjectVariableReal(vp_largest, 1003) vs.SetRField(titleblock, 'Title Block Sheet Data', 'Scale', f'1:{vp_scale:.0f}') else: alert_dialog(f"No Title Block or Viewport found on sheet {layer}")
  9. And here is what I came up with, (FYI, I used chatGPT to explain the code with inline comments!). ** As always, save before running the script, and no responsibility taken for loss of work 😅 ** import vs # Define a function to list the names of all sheet layers in the current document def list_sheet_layer_names(): layer_names = [] hLayer = vs.FLayer() # Use a while loop and the NextLayer() function to iterate through all the sheet layers in the document while hLayer != None: layer_names.append(hLayer) hLayer = vs.NextLayer(hLayer) # Use a lambda function to filter the list of layer names to only include sheet layers layer_type = lambda x:vs.GetObjectVariableInt(x, 154) layer_names = [vs.GetLName(x) for x in layer_names if layer_type(x) == 2] return layer_names # Define a function to get the handles of all objects in the current document that meet certain criteria def get_objects_from_criteria(criteria): object_handles = [] def get_obj(h): object_handles.append(h) # Use the ForEachObject() function to iterate through all objects in the document and add their handles to the list if they meet the criteria vs.ForEachObject(get_obj, criteria) return object_handles # Define a function to calculate the area of a given object def get_object_area(object): top_left, bot_right = vs.GetBBox(object) length = bot_right[0] - top_left[0] height = top_left[1] - bot_right[1] return length * height # Iterate through all sheet layers in the current document for layer in list_sheet_layer_names(): # Define criteria strings to find title blocks and viewports on the current layer titleblock_crit_str = f"(((L='{layer}') & (PON='Title Block Border')))" viewports_crit = f"(((L='{layer}') & (T=VIEWPORT)))" # Use the get_objects_from_criteria() function to get lists of title blocks and viewports on the current layer titleblocks = get_objects_from_criteria(titleblock_crit_str) viewports = get_objects_from_criteria(viewports_crit) # If there is at least one title block and one viewport on the current layer, find the largest viewport and set the scale of the title block to match if all([len(titleblocks)>0, len(viewports)>0]): titleblock = titleblocks[0] # get single first found only vp_area_max = 0.0 vp_largest = None # Iterate through all viewports on the current layer and find the one with the largest area for viewport in viewports: vp_area = get_object_area(viewport) if vp_area > vp_area_max: vp_area_max = vp_area vp_largest = viewport # If a largest viewport is found, set the scale of the title block to match if vp_largest: vp_scale = vs.GetObjectVariableReal(vp_largest, 1003) vs.SetRField(titleblock, 'Title Block Sheet Data', 'Scale', f'1:{vp_scale:.0f}')
  10. I’d actually loop through viewports via sheets: 1. Generate a list of sheet layers. 2. For each sheet layer in the list, use a criteria that searches for viewports with T=Viewport only on this layer. 3. To find a title block within the same loop, use another criteria that searches for a plugin name of "Title Block Border" on the same layer. 4. Within the loop of step 2, locate the largest viewport. You can choose to use the viewport with the largest scale or the one with the largest bounding box. Once found, write the scale to the handle of the title block found in step 3. When I have time to code, I'll see if I can post something Also try to always use f-strings for concatenation. eg criteria = f"((R in ['{strRecordName}']))"
  11. Not until now 🤣.. This is a direct copy and paste of my prompt and the result, however, I'm pretty sure its a simpe scenario, and there will be hallucinations for more advanced requests. But certainly there are tools out there that will make all these possible some day.. Prompt: With your knowledge of Marionette coding and Vectorworks python api functions, build another Marionette node code that creates a rectangle. The two input nodes are just the width and height, and the output node is the resulting rectangle created Result: Certainly, here's a Marionette node code that takes width and height as input and creates a rectangle with those dimensions: #COMMAND;READONLYREFFILE;[VWLibDef]/Objects\Parametric\Rect-2.vwx; #Modified by [Your Name] [Current Date] @Marionette.NodeDefinition class Params(metaclass = Marionette.OrderedClass): # APPEARANCE this = Marionette.Node('Rectangle') this.SetDescription('Creates a rectangle with the specified dimensions.') # INPUTS width = Marionette.PortIn(0, 'Width') width.SetDescription('The width of the rectangle.') height = Marionette.PortIn(0, 'Height') height.SetDescription('The height of the rectangle.') # OUTPUTS rect = Marionette.PortOut('h', 'Rectangle') rect.SetDescription('The resulting rectangle.') def RunNode(): # Inputs w = Params.width.value h = Params.height.value # Script rect = vs.CreateRectangle(vs.Vector(0, 0), w, h) # Outputs Params.rect.value = rect This code defines a Marionette node that takes two inputs, width and height, and outputs a rectangle object with those dimensions. The script creates a rectangle using the vs.CreateRectangle function from the Vectorworks Python API, which takes a position vector and the width and height of the rectangle. The rect object is then outputted as the result of the node. As you can see it came up with the first two lines just because of the context of the chat session I'm sure. This is still crazy though.
  12. Been having fun lately exploring and trying to understand code in my own library, and now in Marionette's under the hood native nodes that are shipped with Vectorworks. If you're ever stuck wondering how or what the method of madness is for some of the nodes, just ask ChatGPT to explain the code to you! Example below is the prompt used to help understand the Nurbs "Divide Curve" node: Prompt: "Can you explain this code:" #COMMAND;READONLYREFFILE;[VWLibDef]/Objects\NURBS$\03. Operations\Divide Curve.py; #Modified by MFarrell May 2017 @Marionette.NodeDefinition class Params(metaclass = Marionette.OrderedClass): #APPEARANCE #Name this = Marionette.Node( 'Divide Curve' ) this.SetDescription( "Returns a list of 3D points along a NURBS curve. The points split up the curve into segments of equal length" ) #Input Ports curve = Marionette.PortIn( vs.Handle(0), 'hCurve' ) curve.SetDescription( "A NURBS curve object" ) divs = Marionette.PortIn( 3, 'iDivs' ) divs.SetDescription( "The number of segments to divide the curve" ) #OIP Controls #Output Ports pnts3D = Marionette.PortOut('listPts') pnts3D.SetDescription( "The list of result points" ) #BEHAVIOR def RunNode(self): #inputs curve = self.Params.curve.value div = self.Params.divs.value #script if(div > 0): dispose = False if vs.GetPlanarRef(curve) == 0: vs.SetPlanarRefIDToGround(curve) if vs.GetTypeN(curve) != 111: curve = vs.ConvertToNURBS(curve, True) dispose = True inc = 1 / div pos = 0 result = [] while pos < 1: ok, p, outParam, outIndex = vs.GetPointAndParameterOnNurbsCurveAtGivenLength(curve, pos) result.append((p[0],p[1],p[2])) pos = pos + inc # Floating point addition operation will never give us a perfect "1" for pos. That's why we do this at the end: ok, p, outParam, outIndex = vs.GetPointAndParameterOnNurbsCurveAtGivenLength(curve, 1) result.append((p[0],p[1],p[2])) if dispose: vs.Marionette_DisposeObj(curve) # Delete duplicates (CASE: periodic curves (circles, for ex.) whose start and end points are the same) cleanP = [] for p in result: cpy = True for np in cleanP: if vs.EqPt3D(p, np, 0.000001): cpy = False break if cpy: cleanP.append(p) #outputs self.Params.pnts3D.value = cleanP ChatGPT Explanation: This is a Python script for a Marionette node in Vectorworks, a computer-aided design software. The node is called "Divide Curve" and it takes two inputs: a NURBS curve object and an integer value for the number of segments to divide the curve. It outputs a list of 3D points that are evenly spaced along the curve. The script first checks whether the input curve is planar or not. If it is not planar, it sets the planar reference to the ground plane. Then it checks whether the input curve is already a NURBS curve or not. If it is not, it converts it to a NURBS curve. The reason for this is that the script uses a function that only works with NURBS curves. Next, the script calculates the increment value for dividing the curve into the desired number of segments. It initializes a list to hold the result points and uses a while loop to calculate points along the curve at regular intervals based on the increment value. The loop continues until it has reached the end of the curve. After the loop is finished, the script checks for duplicates in the result point list. It deletes duplicates that might have been created if the input curve was periodic (like a circle). Finally, the script outputs the list of 3D points to the "pnts3D" output port of the node.
  13. If there is an existing class name with a digit at the end of the class name, creating a class with the same name will increment that last digit in the class name
  14. Agree with all of what Pat and Sam Jones said. With regards to your specific questions: I’m wanting to start to push the boundaries of what can be done with Vectorworks, and am seeking direction for best practices, Scripting resources, and or any additional materials that you may deem helpful in this endeavor. - This forum, and the vectorworks dev wiki (link stickied in scripting forum), are your best resources. Vectorworks also ships with a PDF for the vectorscript language. Really looking to program repeat tasks and sequences that I currently use in my daily workflow. - This can be done with all three routes, ie Vectroscript, Python, C++ And I would like to be able to develop a customized “super” template that has a centralized repository for all future drawings to save time on production efforts. - Depending on your actual specifics, template scripting has been attempted in the past. Search the forums. There were some pitfalls users faced. Which language should be best utilized from a programming point of view, and is there recent documentation for the most current release? - Which language? from a programming point of view? all three of them will help you, and the recent documentation is on the Vectorworks Dev Wiki. My experience with the languages are as such: Vectorscript Pros: - Native debugger within Vectorworks. - You can script in user-interactivity easier than using Python - Native vectorworks language Cons - Explicit variables(yes this is contrary to what Sam mentioned 😁) - Intermedia learning curve if new to programming Python Pros: - Easy learning curve. Plethora of tutorials online - Access to every external library from the python development community - Faster development testing (in my tests) - Debugging can be done in an external ide with code error checking, syntax highlighting. (I use PyCharm, but there are others out there) Cons - Hard to script in user-interactivity C++ Pros: - You have more access to the Vectorworks under-the-hood functions Cons: - Steep learning curve. (I have yet to dive into this one. But when I will....) I spent about 2 years learning and developing plugins using vectorscript, when python support came out, I spent 1 year learning python, and then abandoned vectorscript, and develop solely in python ever since. But if you've read the forums you'd see alot people still using vectorscipt and others python. Well that was a round-about-post to say: "It all depends.."
  15. I should've prefaced my post, by saying I haven't actually tried any of this 😂😂. Ever since reading and liking a few posts on twitter, my feed has been flooded with videos and tweets like the ones I posted here. I should also mention, that everything is moving incredibly fast to follow whats happening. The amount of offshoot diffusion models, gpt models, locally run gpt/diffusion models, being released daily is quite mind blowing. It's like seeing a beautiful avalanche; from a distance it looks beautiful, the sheer mass of it so very difficult to comprehend, but at the back of your mind you know alot is getting destroyed in the process.
  16. If you're up for following along with some video tutorials here are some good ones, as I believe Veras uses a custom built ControlNet ontop of stable diffusion:
  17. Hi @Jeremy Best, can you confirm this in the NZ installations? VW2023 SP4
  18. Yep, will do on Monday. Thanks @Nikolay Zhelyazkov
  19. Yep, new empty file, adding title block, shows the same fields. I am using the Version for NZ.
  20. Anyone else getting new(read incorrect) revision fields in their revision edits dialog box? 'DP Name' and 'DP Reg No.' See below: This is 2022's Title Block:
  21. Greetings all, How is everyone organising their data visualizations? We desperatly need better organisation as we're using it more and more in our office templates. We need: - Groupable data vis - Saved as resources (ie accessible and shareable through the resource manager) - Saved States for Multiple Selected Viz's on one viewport - Scriptable access (vectorscript and python script functions to customise organisation of these things!) at the moment were relying on strict naming conventions to keep organised, but surely there are better solutions I'm hoping:
  22. Yep, thats the old way I would normally do things. But the Site Model has an option to select which design layers you want the site model to be affected by. Giving you the option of having multiple options of grading a site.
  23. @AlanW all the modifiers are set to proposed. I'll see if I can send a separate file for this. Hopefully the video is clear enough to see the problem. Just wanting to see if anyone has faced the same issue?
  24. Not the underlying data within the site model. those stay the same if I go into the site model data. What I'm seeing is that when I change the Site Model "Display" either in 2D or 3D, and set the "Display" to be "Existing" it is showing the Existing contours altered
×
×
  • Create New...