Jump to content


  • Posts

  • Joined

  • Last visited

Posts posted by JHangstoerfer

  1. The only part that we look for during the export are the plug-in objects. The plug-in object references a symbol with the preview-geometry (as we call it) but that geometry isn't used for anything except for displaying it in the CAD and that's why "Copy from Symbol" does not work. There is no link to the plug-in object. I believe you can even modify the symbol containing our preview-geometry however you like. To restore it back to default you can delete the Symbol with the geometry and reset the asset's plug-in object using it to re-generate it or place the same asset again in the project.

    For getting "Copy from Symbol" to work you need a symbol containing the plug-in object. So create a new symbol, place the asset in there and then "Copy from Symbol" from that one.

    • Like 3
  2. On 3/17/2023 at 7:49 AM, Ned Flanders said:

    Hi-didly-ho Vectorworkers!

    Anyone out their experiencing crashing in VW2023 SP4 when rendering and exporting a night scene in Enscape?


    Enscape has been near perfect for my VW visualization workflow. Currently, I have a VW model with one Heliodon. I'm synchronized with the latest version of Enscape. I have the most recent Nvidia GPU drivers installed. I can render and export day scenes at any time of the day when the "sun" is above the horizon. As soon as I try to export a scene when the "sun" is below the horizon, without additional lights, Enscape crashes and subsequently VW crashes. 


    Any feedback?


    Could you share a small sample project? I'll take a look and see if I can reproduce it.

  3. 5 minutes ago, JBenghiat said:


    It looks like the saved view is actually a script with a view object attached. Untested, but in theory:

    - Use ISDK::CreateScriptResource to create a new script in the "Saved Views" palette. The name of the script is the name of the view.

    - Use VWViewObj to create the view

    - Set the parent of the view object to the aux list of the script object


    I thought of manually creating the script object but there are way too many edge cases that I would want to deal with. Like "Saved Views" palette name being a localized text, or when someone renamed "Saved Views", or it already exists as a different object, doesn't exist yet at all and more. There's probably even more that happens in the background that I don't know of so I'd rather use the script function to do all of this for me.

    Be careful with VWViewObj, because it deletes the view that it creates/duplicates in its dtor. That's why I mentioned that it's really only used for temporary views.

    	fhViewObj = gSDK->ViewCreateCurrent();
    VWViewObj::VWViewObj(const VWViewObj& src)
    	fhViewObj = gSDK->ViewDuplicate( src.fhViewObj );
    VWViewObj::VWViewObj(MCObjectHandle hView)
    	if (!VWViewObj::IsViewObject(hView))
    		THROW_VWFC_EXCEPTION(VWBadObjectTypeException, 0, "bad handle type when creating");
    	fhViewObj = gSDK->DuplicateObject( hView );
    	fhObject = fhViewObj;
    	VWFC_ASSERT(fhObject != nil);
    	gSDK->ViewDelete( fhViewObj );
    	fhViewObj = NULL;
    	fhObject= NULL;



  4. 16 hours ago, JBenghiat said:

    Take a look at VWFC::VWObjects::VWViewObj.

    VWViewObj only is for temporary saved views like when you want to change camera, layers and then restore to how it was previously afterwards. For creating a saved view that shows up in the navigation palette there is ISDK::CreateSavedViewWithUI or the python/vss SaveSheet. To modify a saved view you also need to use the ISDK calls directly as VWViewObj operates on a duplicate.


    16 hours ago, JBenghiat said:

    As for ExecuteScript, concatenating the string is not too hard — just use +. You can also use single quotes as your string qualified to avoid having to escape them.


    I believe CallUserProcedure only works for procedures you have registered and can therefore get the callback pointer.

    I know it's not hard but I would have rather used a type safe way instead of converting everything to string myself.
    Alright, if CallUserProcedure doesn't do what I expected then I guess I will be using the ExecuteScript method.

  5. I have a (hopefully) simple question about the usage of VectorWorks::Scripting::IPythonScriptEngine and or IVectorScriptEngine. I want to call a procedure that is not available in the SDK but is available in both python and vss.

    I want to call SaveSheet, which saves the current view, layer settings and more in a saved view (saved views used to be called sheets). The closest equivalent in the SDK that I could find was ISDK::CreateSavedViewWithUI, which does the same but instead opens up the dialogue that you would see when you manually create a saved view via the UI. Basically, I want to create a saved view without the UI.


    An obvious starting point to achieve what I want seems to be VectorWorks::Scripting::IPythonScriptEngine and VectorWorks::Scripting::IVectorScriptEngine and I also got it to work quite fast:

    VCOMPtr<VectorWorks::Scripting::IPythonScriptEngine> pythonScriptEngine{ VectorWorks::Scripting::IID_PythonScriptEngine };
    VCOMError err = pythonScriptEngine->ExecuteScript("vs.SaveSheet(\"Test\", True, True, True)");

    This might be easy to use but I don't like the fact that I have to concatenate a string if I want to change any of the parameters. For this case, both of the ScriptEngines seem to offer a function called CallUserProcedure. I think it does what I want but in a more type safe manner


    Now finally for my questions. Can CallUserProcedure be used to call SaveSheet? Is this even the correct function that I'm trying to use or does this something completely different?

    I'm also struggling to find out what the first parameter "procedureRef" has to be to achieve this call.

    This is what I think it would look like with CallUserProcedure but it's missing the procedureRef

    VCOMPtr<VectorWorks::Scripting::IPythonScriptEngine> pythonScriptEngine{ VectorWorks::Scripting::IID_PythonScriptEngine };
    PluginLibraryArgTable argTable {
      .args = {
          .argType = kStringArgType,
          .strValue = "Test"
          .argType = kBooleanArgType,
          .boolValue = true
          .argType = kBooleanArgType,
          .boolValue = true
          .argType = kBooleanArgType,
          .boolValue = true
    void* procedureRef = nullptr; // ???
    VCOMError err = pythonScriptEngine->CallUserProcedure(procedureRef, &argTable, 4);


  6. On 6/1/2022 at 4:43 PM, Nicolas Goutte said:

    VW 2022 seems to have changed its behavior and sends the kNotifyDocPostSaved notification, when a backup is made.


    So my question is: how do I know that the current kNotifyDocPostSaved is due to backup and not due to a regular saving.


    (I have to do things when the file is saved normally, but not when it is saved as a backup.)


    kNotifyDocPreSaved seems to have the information you want


    // Manual
    kNotifyDocPreSaved C:\Users\Work\AppData\Local\Temp\Untitled 1-VWTMP.swap
    kNotifyDocPostSaved C:\tmp\Untitled 1.vwx
    // Backup
    kNotifyDocPreSaved C:\tmp\VW Backup\Untitled 1-Backup-20220603201902.vwx
    kNotifyDocPostSaved C:\tmp\Untitled 1.vwx


    Note that I used gSDK->GetOpenFilesList to read the filepath of the doc during the event, I don't know whether gSDK->GetActiveDocument provides the same information

    • Like 2
  7. 23 hours ago, Dave Donley said:


    @JHangstoerfer ViewStore saves the current layer's view state to the view handle you pass to it.  So if you have the handle you want, then set view projection with gSDK->SetProjection


     and other view settings using other gSDK routines, then call ViewStore that should commit your new changes to the view handle.


    There is also a utility class VWViewObj that calls these gSDK routines to do the same things.


    gSDK->ViewStore is the call that we needed. The problem was that we used the VWViewObj utility class. In its constructor, it creates a duplicate of the original saved view so VWViewObj::StoreView doesn't actually commit those changes to the correct object.


    Here is a working sample, although this might required a RestoreView beforehand, otherwise ViewStore commits changes other than the ViewMatrix. At least I think that's how it works.

    auto viewParentHandle = VWFC::VWObject::GetNamedObject("Saved View Name");
    auto viewHandle = gSDK->FindAuxObject(viewParentHandle, saveViewNode);
    auto activeLayer = gSDK->GetActiveLayer();
    gSDK->SetViewMatrix(activeLayer, viewMatrix);


    • Like 1
  8. On 5/9/2022 at 5:50 PM, Maarten DE said:

    Since you know where the matrix is located in the aux list, you should be able to adjust it using the aux functions: https://developer.vectorworks.net/index.php/Category:VCOM:VectorWorks:ISDK(Auxiliary_and_Data_Objects)


    I thought I had some code where I adjusted something in an aux list, but I can't find it anymore...



    I don't see a way to read or write the fields from my screenshot directly. It might be possible they are additionally saved in tagged user data but I don't have the dataTags and dataIndex to read those values without brute forcing to find them.

  9. We want to update the matrix of a saved view of perspective type. In the UI this is handled via "Redefine..." in the Navigation palette and also allows you to change some restore options but those are not relevant for us.


    I don't see any methods in the SDK that would allows us to do this. There is gSDK->EditSavedViewWithUI but that opens the Edit dialog, which does not update the matrix, only the other options and the name. A way to trigger to open up the Redefine UI would also be fine for us.


    "Redefine..." seems update the matrix on the saveViewNode. Would it be possible to directly modify these fields with our new matrix?



  10. 3 hours ago, Cachino King said:

    Thank you very much! Now I understand the structure. 

    How do I use VectorWorks::Imaging::ICompressedImage if I want to export image maps?

    I need Filepath, Brightness, Width, Height, uv and Rotation data, and I found some of them in struct CompressedImageDesc. 

    So what do I do if I want to get data in this struct?


    I've only used GetImageStream from ICompressedImage.

    You don't get a file path to the image because the file content of the images is embedded in the Vectorworks project.

    You either use the file content bytes directly or you have to write them to the filesystem if you really want a Filepath. I think the compress image api can also write the files using the Save() call.


    	VectorWorks::Imaging::ICompressedImagePtr imageApi(VectorWorks::Imaging::IID_CompressedImage);
    	auto err = imageApi->CreateFromObject(imageHandle); // check err
    	// Contains jpg or png data
    	VectorWorks::Imaging::ImageStream imageStream{};
    	err = imageApi->GetImageStream(imageStream); // check err
    	// Use imageStream.bufferPtr as std::byte[] with size imageStream.bufferSizeInBytes
    	// Never used this but it looks like meta information about the image
    	VectorWorks::Imaging::CompressedImageDesc desc{};
    	err = imageApi->GetCompressedImageDesc(desc); // check err


    I don't know where you would fine extra info like brightness, uv and rotation but it sounds like this would be either in the material or in the geometry. ICompressedImage is just for the raw image file content.

  11. Field id is not the prototype value, but you don't really have to know the field id anyway.

    You need an additional step to read the transparency value, in case you have a plain transparency shader.

    Shaders are divided into families and families are divided into prototypes.


    See the difference in the texture edit dialog:



    You can use VWFC::VWTextureShaderBase::GetShaderRecordFamilyAndPrototype or each of the prototype helpers like VWTextureShaderTransparencyPlain::IsShaderRecordObject to determine what prototype it is.


    After figuring out what prototype it is you can use the helpers to read the values:

    		auto recordHandle = gSDK->GetShaderRecord(hMaterial, kShaderFamily_Transparency);
    		// option 1
    		if (VWFC::VWTextureShaderTransparencyPlain::IsShaderRecordObject(recordHandle))
    			VWFC::VWTextureShaderTransparencyPlain shader{ recordHandle };
    			auto opacity = shader.GetOpacity();
    		// option 2
    		auto family = kShaderFamily_Undefined;
    		auto prototype = 0;
    		if (!VWFC::VWTextureShaderBase::GetShaderRecordFamilyAndPrototype(recordHandle, family, prototype))
    			// "None" Transparency Shader 
    		if (prototype == kShaderPrototypeTransparency_Image)
    			VWFC::VWTextureShaderTransparencyImage shader{ recordHandle };
    			// read image file content with VectorWorks::Imaging::ICompressedImage
    			auto imageHandle = shader.GetImage();
    			auto refraction = shader.GetRefraction();
    			auto bluriness = shader.GetTransparencyBlurriness();
    			// ...


    GetOpacity uses the field Id to get the value from the record. In this case it's 4, which is a constant that is only specific to plain transparency.

    You can see those field values when you look at the record handles in the debug menu, or if you look at the .cpp files of the prototype helpers.

    But as I said before, if you use the helper you don't have to know the field id is.



  12. 5 hours ago, Cachino King said:

    Yeah, that's quite difficult for me. The functions that implement FBX export do not exist. 

    I looked up the file "MockSDK.h" and found a funtion "GetMesh". After some test, this function can let me get the vertexs of the mesh, and I found normal data, uv data all in the class "IMeshData". 

    I just need to get these data and some material data and send these to another software. This part is relatively simple. 

    Maybe there are very few kinds of polygons can convert to mesh. But I think it's enough to finish this task. 

    GetMesh only works for kMeshNode objects. It doesn't work for solids.


    4 hours ago, Cachino King said:

    VGS is too difficult to me. I just need some mesh data and material data and send to my program. Although vectorwork use solid-base to save model data, I still want to convert solid to mesh. And I found the function can implement this. 

    I read some guidance documents of my task that live sync they said is actually dynamic updating. If the scene changes in VW, the model information needs to be retransmitted. This method doesn't sound nearly as efficient as VGS, but it's easier to implement. 

    Where are you having troubles with VGS? I think it's the easiest of any of these methods. You get meshes for all objects including solids via VGS and their materials in easy to use formats. I can answer any questions you got about VGS.

    • Like 1
  13. @Cachino KingVectorworks Graphics Sync is what you want for a true live sync, assuming that you use VW2020 or higher.
    Look at Interfaces\VectorWorks\IVGS.h, you will need an extra header file for ::VGS::Operation because it's not included in the normal SDK. You'd have to contact VW and ask for access to the API.
    VGS is relatively straightforward, you get tessellated geometry, camera position, rudimentary materials (full materials with some more work), object instances and proper update events for all of it.

    Alternatively there is the Tesselator that you can use to get geometry from objects and their children.

    If you throw a layer handle into this tesselator it will export everything on that layer. The STessTraingle contains information about what is being tessellated and the object, material, triangles for it. Extra information like a transformation you can get from the object.

    This is more of a one-time export and you would need to detect any changes in the document yourself and then tessellate those parts again, which I'm not sure how to do.

    GS_TessellateIteratorProcPtr tesselationCallback = [](ETessProcReason reason, STessTraingle triangle, CallBackPtr cbp, void* pEnv)
      YourExportContext* context = static_cast<YourExportContext*>(pEnv);
      switch (reason)
          // collect data into context
    YourExportContext context{};
    TTesselator tesselator = gSDK->CreateTessellator(true);
    VectorWorks::STesselateOptions tesselationOptions{};
    MCObjectHandle handleToRecursivelyTesselate;
    gSDK->TesselateObjectN(tesselator, tesselationOptions, handleToRecursivelyTesselate, tesselationCallback, &context);


    • Like 2
  • Create New...