Jump to content

twk

Member
  • Posts

    964
  • Joined

  • Last visited

Reputation

561 Spectacular

Personal Information

  • Occupation
    Architectural Designer
  • Homepage
    www.cba-design.co.nz
  • Location
    New Zealand

Recent Profile Visitors

10,010 profile views
  1. Thanks @Lada. But 2027! 🙃.. that's a long wait. I would've thought that with subscriptions and incremental updates between versions, expanding API access wouldn’t necessarily be tied only to major releases, especially for exposing existing internal data rather than introducing new functionality. But for context here's what I'm needing it for: I’ve built an internal document auditor to enforce office standards and perform QA checks across: Layers (Sheets and Design) Classes Records Worksheets Viewports Plugin Styles: Data tags Drawing Labels Reference Markers Elevation Markers Detail Call outs Section Markers The two major gaps preventing this from being complete are: Viewport Plug-in Styles At the moment there is no way to: Query which plug-in styles are assigned to a viewport Validate those styles against office standards Flag non-compliant viewports Even read-only access here would unlock a lot of automation. 2. Data Visualizations There currently appears to be no API access to: List Data Visualizations present in a document Determine which Data Visualization(s) are applied to a given viewport Inspect, at minimum: Criteria used Classes / objects affected Visual overrides being applied Ideally this would also allow assigning or swapping Data Visualizations programmatically, but even query-only access would be a significant step forward. Thanks for the reply, and here's to hoping we could get some of this before 2027. Ive already made enhancement requests for this, a couple of years ago
  2. Hi all, I’m trying to determine whether there is any Script / API access to: Reading or detecting Viewport Styles applied to a viewport Reading or detecting Data Visualizations applied to a viewport (Ideally) assigning or swapping these programmatically I’ve searched the scripting documentation and reviewed the current Viewport object selectors here: https://github.com/Vectorworks/developer-scripting/blob/main/Function Reference/Appendix/pages/Appendix G - Object Selectors.md From what I can see, the selectors cover general viewport properties (update state, render background, view type, position, etc.), but nothing appears to relate to Viewport Styles or Data Visualizations. @Vlado Thanks, Tui
  3. The experience has been great. Very intuitive and helps you understand vectorworks scripting concepts. Used it a lot for understanding how textures are called, etc.
  4. Hi @klinzey, care to elaborate what is mentioned here? What are .vs and .px files? and are you saying if we change our python module files, from .py to .px this will then work with encryption and obfuscation? or just encryption? I feel there are bits left out in this explanation.
  5. The problem is that the code uses vs.MoveTo() and vs.LineTo() to create the worktop profile, which creates an open path of line segments rather than a closed polygon. When you extrude an open path, Vectorworks creates a hollow shell instead of a solid object. vs.BeginXtrd(bottom_z, top_z) first = True for (x, y) in pts: if first: vs.MoveTo(x, y) first = False else: vs.LineTo(x, y) vs.EndXtrd() The Fix: You need to use vs.BeginPoly(), vs.AddPoint(), and vs.EndPoly() to create a proper closed polygon before extruding: vs.BeginXtrd(bottom_z, top_z) vs.BeginPoly() for (x, y) in pts: vs.AddPoint(x, y) vs.EndPoly() vs.EndXtrd() worktop = vs.LNewObj() Note: You don't need to manually close the polygon by appending pts[0] to your points list - vs.EndPoly() automatically closes the polygon for you. So you can remove the line pts.append(pts[0]) from your point-building code. Notes The BeginPoly()/AddPoint()/EndPoly() sequence creates a proper closed polygon object that can be extruded into a solid. The rest of your code correctly uses vs.Rect() for rectangular profiles, which is why those extrusions work properly.
  6. This is almost certainly an SEO content marketing strategy. According to Claude research, every major CAD company does this — Autodesk publishes "What is CAD?" articles, Onshape has "Learn CAD the Easy Way" beginner content, etc. The goal isn't to help existing users. It's to: Rank for high-volume educational search terms Build domain authority across their entire site Capture students and researchers at the awareness stage Own the educational keywords in their space It's a numbers game — publish educational content → rank on Google → maybe 0.5% of that traffic eventually converts. Meanwhile, the Newsroom Digest gets sent to actual architects who already know what detail drawings are. Not criticizing the strategy necessarily, but yeah — the disconnect between the email audience and the article audience is real. Would be better to see "Advanced Detailing Workflows in VW2026" or "Data-Driven Detail Generation" in users' inbox.
  7. Interesting Idea. You can place the temp images on a layer somewhere and reference in with the Image function.
  8. here are some screenshots: The temp object/drawing on document, the worksheet with the values, and the object info palette: The Plugin-Manager, the Plugin Definition: The Parameters: also plugin needs to be event enabled:
  9. I recently indexed the entire Vectorworks official scripting documentation from GitHub using DeepWiki - it's a service that creates an AI-powered chat interface for any GitHub repository's documentation. (<Vectorworks/developer-scripting>) Instead of hunting through dozens of markdown files trying to figure out event-enabled plugins, I just asked DeepWiki directly and it guided me through the entire process. I used it to build this complete testWorksheet.py example that does exactly what you're asking for - dynamically populating popup choices from worksheet data. # testWorksheet.py import vs # Event constants kObjOnInitXProperties = 5 kParametricRecalculate = 3 kObjOnWidgetPrep = 41 kObjOnAddState = 44 # Added constant for clarity # Property constants kObjXPropHasUIOverride = 8 kObjXHasCustomWidgetVisibilities = 12 kObjXPropAcceptStates = 18 # Added constant for clarity kParametricEnableStateEventing = 590 # Added constant for clarity # Event result constants kObjectEventHandled = -8 # Configuration constants POPUP_PARAM_NAME = "WorksheetValues" # Change to match your popup parameter name WORKSHEET_NAME_PARAM = "WorksheetName" def read_popup_values_from_worksheet(worksheet_name: str, start_row: int = 2, end_row: int = 20, column: int = 1): """ How/Why: Reads a clean list of values from a specific worksheet column so a popup can reflect external data. - Uses Vectorworks worksheet API safely, ignoring empty cells and trimming strings. - Keeps row/column 1-based to match VW conventions. """ popup_values = [] # Locate worksheet ws_h = vs.GetObject(worksheet_name) if not ws_h: vs.AlrtDialog(f'Worksheet "{worksheet_name}" not found') return popup_values # Collect values (strings prioritized; numbers converted) for row in range(start_row, end_row + 1): try: if not vs.IsValidWSCell(ws_h, row, column): continue if vs.IsWSCellString(ws_h, row, column): s = vs.GetWSCellStringN(ws_h, row, column) if s and s.strip(): popup_values.append(s.strip()) elif vs.IsWSCellNumber(ws_h, row, column): val = vs.GetWSCellValue(ws_h, row, column) popup_values.append(str(val)) except Exception as e: # Keep robust on malformed cell content vs.AlrtDialog(f"Worksheet read error at row {row}, col {column}: {e}") return popup_values def populate_popup_from_worksheet(widget_id: int, worksheet_name: str): """ How/Why: Rebuilds the popup choices to reflect current worksheet content during WidgetPrep, ensuring OIP shows up-to-date options without forcing recalculation. """ # Reset current popup items vs.vsoWidgetPopupClear(widget_id) # Validate input if not worksheet_name or not worksheet_name.strip(): return # Configure read window start_row = 2 # Skip header end_row = 20 # Adjust for your data column = 1 # 1-based # Read and add values = read_popup_values_from_worksheet(worksheet_name, start_row, end_row, column) for value_id, display_text in enumerate(values): # Note: API takes integer IDs; documentation may show string vs.vsoWidgetPopupAdd(widget_id, value_id, display_text) # Optional separator + edit affordance if values: vs.vsoWidgetPopupAdd(widget_id, len(values), "-") vs.vsoWidgetPopupAdd(widget_id, len(values) + 1, "Edit Worksheet...") def create_plugin_geometry(): """ How/Why: Keeps geometry creation isolated so ParametricRecalculate stays tidy and testable. Replace this with your actual object creation code. """ # Example placeholder geometry vs.Rect(0, 0, 100, 100) vs.Circle(50, 50, 25) vs.Line((0, 0), (100, 100)) # 3D example: # vs.Box(0, 0, 0, 100, 100, 50) def main(): """ How/Why: Central event router that follows VW's event-enabled plugin rules. - InitX: declare capabilities and insert OIP widgets - AddState: only add state (no other logic) - WidgetPrep: populate dynamic UI (popups, visibilities, etc.) - Recalculate: build/update geometry and clear plugin state """ event, message = vs.vsoGetEventInfo() # Get plugin info (may be incomplete very early during init; do not exit early) ok, plugin_name, plugin_handle, record_handle, wall_handle = vs.GetCustomObjectInfo() # Map param name to OIP widget ID (param index is 0-based; widget ID is 1-based) # Guard for name lookup to avoid exceptions during very early init popup_param_index = None if plugin_name: idx = vs.vsoParamName2Index(plugin_name, POPUP_PARAM_NAME) if idx is not None and idx >= 0: popup_param_index = idx + 1 if event == kObjOnInitXProperties: # Enable extended behaviors and insert OIP widgets vs.SetObjPropVS(kObjXPropHasUIOverride, True) vs.SetObjPropVS(kObjXHasCustomWidgetVisibilities, True) vs.SetPrefInt(kParametricEnableStateEventing, 1) vs.SetObjPropVS(kObjXPropAcceptStates, True) vs.vsoInsertAllParams() elif event == kObjOnAddState: # VW rule: only add current state here if plugin_handle: _ = vs.vsoStateAddCurrent(plugin_handle, message) elif event == kObjOnWidgetPrep: # Rebuild dynamic popup content if popup_param_index is not None and plugin_handle and plugin_name: ws_name = vs.GetRField(plugin_handle, plugin_name, WORKSHEET_NAME_PARAM) if ws_name and ws_name.strip(): populate_popup_from_worksheet(popup_param_index, ws_name) # Must mark as handled vs.vsoSetEventResult(kObjectEventHandled) elif event == kParametricRecalculate: # Main geometry update create_plugin_geometry() # Clear state after successful recalc if plugin_handle: vs.vsoStateClear(plugin_handle) # PIOs are executed by VW; keep for standalone testing if needed: # if __name__ == "__main__": # main() This is honestly a game-changer for learning Vectorworks scripting. Tools like LLMs (ChatGPT/Claude/Gemini, etc) and now DeepWiki make it so much easier than the old days of digging through scattered documentation and forum posts. You can literally have a conversation with the official docs! This link is another prompt I asked it to prepare docs on event-enabled plugins using the script as context - really helpful for understanding the full workflow. https://deepwiki.com/search/earlier-we-built-this-code-tog_a8da7663-214c-428f-8690-e5863ffcac2b?mode=fast Basically: Event-Enabled Plugin Quick Reference Your testWorksheet.py demonstrates a parametric plugin that handles four key events to customize the Object Info Palette and manage dynamic content. Core Events Event 5 (InitXProperties) - Plugin setup Enable UI customization with SetObjPropVS(kObjXPropHasUIOverride, True) Add all parameters as widgets with vsoInsertAllParams() Event 44 (AddState) - State tracking Only call vsoStateAddCurrent(plugin_handle, message) - nothing else! Event 41 (WidgetPrep) - Dynamic UI updates Populate your popup with vsoWidgetPopupClear() and vsoWidgetPopupAdd() Must end with vsoSetEventResult(-8) Event 3 (ParametricRecalculate) - Geometry creation Create your geometry here Always call vsoStateClear(plugin_handle) when finished Key Documentation Links: Object Events Overview - Complete event system guide Parametric Custom Shape Pane Popup - Dynamic popup examples Plug-in with widget basic example - Python widget tutorial Widget Tips: Use vsoParamName2Index(plugin_name, param_name) + 1 to get widget IDs Parameter index is 0-based, widget ID is 1-based (hence the +1) The pattern is simple: setup (5) → track changes (44) → update UI (41) → create geometry (3).
  10. Yes, you need to have an event-enabled plugin to do this
  11. You use the stake tool, and set the parameters accordingly. (Mode=Set eleve to site model)
  12. Find it here: https://deepwiki.com/Vectorworks/developer-scripting also added are: https://deepwiki.com/Vectorworks/developer-worksheets https://deepwiki.com/Vectorworks/developer-sdk (I added the latter 2 but haven't used them) What is DeepWiki? DeepWiki is an AI-powered tool created by Cognition AI (the team behind Devin) that transforms any GitHub repository into an interactive, Wikipedia-style knowledge base⁠⁠⁠⁠. Think of it as having a senior developer who knows the entire codebase sitting next to you, ready to answer questions instantly. Since Vectorworks moved its documentation from the mediawiki site, to github, it was the perfect timing. Any public repo can be added to the AI wiki aggregator. Why this helps: Natural language search: "How do I create custom tools?" Visual code maps and architecture diagrams Instant answers without digging through folders Zero setup - just visit the URL Important note: This is unofficial - just me adding a public repo to a free tool. Not affiliated with Vectorworks Inc. If the official team has concerns, please let me know and I'll find out how to remove it. Example: Screen Recording 2025-09-08 110231.mp4
  13. Oh yes, that code looks complicated, I simply use Criteria. the criteria string logic is like this: (PON=<YourPluginName>)&(L=<Grab Name of Active Layer>)&(SEL=TRUE) then use: vs.ForEachObject() Rather than checking selection/layer states manually, I use VectorScript Criteria eg code: criteria = f"(PON={PIO.PIName}) & (L={vs.GetLName(vs.ActLayer())}) & (SEL=TRUE)" vs.ForEachObject(SetRecordFieldValue, criteria) # SetRecordFieldValue, being some function that acts on these objects (set your params for other objects through here)
  14. I've done the 'FindSelectedObjects' routine during the reset event, as that is where the parameter change happens. You just have to cater for different scenarios: - Objects only on Active Layer - On Visible layers - Visible/Active Layers (Layer option Show/Snap/Modify) etc
×
×
  • Create New...