Workflow - Assembly Builder
-
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 12/09/2007 at 04:17, xxxxxxxx wrote:
User Information:
Cinema 4D Version: 10.1
Platform: Windows ;
Language(s) : C.O.F.F.E.E ; C++ ;---------
Hello,
I'm searching for a solution to build up an assembly in C4D. I have an assembly inside CAD and the corresponding parts in a C4D-library. Because of the great amount of components I'd like to automate this task.
The information about assembly structure and position of the parts I already have in a textfile.
Is it possible to merge components to the active scene and if yes, can anybody give me a short source code how to do this. Coffee doesn't work because with COFFEE you can only load documents but no merging. (that's what I fournd out until now)
I need all objects that are inside the parts of the C4D-library.
A sample project or a project template for visual studio 2003/2005 prof. helps a lot, too. I'm a newbie in C4D-SDK.
Thanks in advance
guckmalda -
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 12/09/2007 at 11:29, xxxxxxxx wrote:
The project that comes with C4D (in cinema4Dsdk) is sufficient as a template for building your own C++ projects. Actually, it is the recommended way to do so.
In the C++ SDK there is a MergeDocument() method. In what format are the 'parts' that you have ready for import?
The best way to do this is to make a Command plugin (a plugin that is run from the Plugins menu). If this is a one-time thing, you could hard code the path to all of the parts but it might be better to open a file dialog to point to the folder from which to start.
The problem with a source example is that there is a lot of infrastructure needed around the plugin besides the merging part. You'll need a Main.cpp with PluginStart, PluginEnd, and PluginMessage. Here's a skeletal Main.cpp:
Bool RegisterMyCmdPlugin(); //*---------------------------------------------------------------------------* Bool PluginStart() //*---------------------------------------------------------------------------* { GePrint("Starting My Plugin"); // register plugin and return return RegisterMyCmdPlugin(); } //*---------------------------------------------------------------------------* void PluginEnd() //*---------------------------------------------------------------------------* { } //*---------------------------------------------------------------------------* Bool PluginMessage(LONG id, void* data) //*---------------------------------------------------------------------------* { if (id == C4DPL_INIT_SYS) { // initialize global resource object if (!resource.Init()) return FALSE; } else if (id == C4DPL_ENDACTIVITY) { return TRUE; } else if (id == C4DMSG_PRIORITY) return TRUE; return FALSE; }
Then you'll need to derive a class from the CommandData like this:
Header:
//////////////////////////////////////////////////////////////// // MyCmdPlugin.h //////////////////////////////////////////////////////////////// // Main Registered Class //////////////////////////////////////////////////////////////// #ifndef _MYCMDPLUGIN_H_ #define _MYCMDPLUGIN_H_ class MyDialog; // CLASS: MyCmdPlugin class MyCmdPlugin : public CommandData { INSTANCEOF(MyCmdPlugin, CommandData) private: GeDialog* myDialog; public: MyCmdPlugin(); ~MyCmdPlugin(); // CommandData Bool Execute(BaseDocument* doc); LONG GetState(BaseDocument* doc); Bool RestoreLayout(void* secret); }; #endif //_MYCMDPLUGIN_H_
Source:
//////////////////////////////////////////////////////////////// // MyCmdPlugin.cpp //////////////////////////////////////////////////////////////// // Includes #include "c4d.h" #include "c4d_symbols.h" #include "MyDialog.h" #include "MyCmdPlugin.h" // METHODS: MyCmdPlugin ================================================================================================== // Constructor //*---------------------------------------------------------------------------* MyCmdPlugin::MyCmdPlugin() //*---------------------------------------------------------------------------* { myDialog = NULL; } // Destructor //*---------------------------------------------------------------------------* MyCmdPlugin::~MyCmdPlugin() //*---------------------------------------------------------------------------* { gDelete(myDialog); } // CommandData.Execute //*---------------------------------------------------------------------------* Bool MyCmdPlugin::Execute(BaseDocument* doc) //*---------------------------------------------------------------------------* { if (!myDialog) { myDialog = gNew MyDialog; if (!myDialog) return FALSE; } if (myDialog->IsOpen()) return TRUE; return myDialog->Open(TRUE,ID_MYCMDPLUGIN,-1,-1,320,320,ID_MYDIALOG); } // CommandData.GetState //*---------------------------------------------------------------------------* LONG MyCmdPlugin::GetState(BaseDocument* doc) //*---------------------------------------------------------------------------* { return CMD_ENABLED; } // CommandData.RestoreLayout //*---------------------------------------------------------------------------* Bool MyCmdPlugin::RestoreLayout(void* secret) //*---------------------------------------------------------------------------* { if (!myDialog) { myDialog = gNew MyDialog; if (!myDialog) return FALSE; } return myDialog>RestoreLayout(ID_MYCMDPLUGIN, ID_MYDIALOG, secret); } // Global Registrant Method for My Command plugin //*---------------------------------------------------------------------------* Bool RegisterMyCmdPlugin() //*---------------------------------------------------------------------------* { return RegisterCommandPlugin(ID_MYCMDPLUGIN, GeLoadString(MY_PLUGIN_NAME), 0, "pluginicon.tif", "My Cmd Plugin", gNew MyCmdPlugin); }
If you are going to need a dialog for any user input, you'll need to derive a class from GeDialog (MyDialog mentioned here). Use the GeDialog::Command method to get a button click for "OK" or similar to start the process. If you are just going for it with no dialog, you could have the process of merging and setting up work from the MyCmdPlugin::Execute method.
As for the process itself, you'll probably need a BrowseFiles class to traverse the folder and start loading the files. First get the current document:
BaseDocument* doc = GetActiveDocument();
if (!doc) return FALSE;
AutoAlloc<BrowseFiles> browse;
if (!browse) return FALSE;
StopAllThreads(); // Required when modifying a scene
// traverse files/folders in folder using the specified loop structure for BrowseFiles
if (!MergeDocument(doc, filename, flags, NULL)) continue;etc.
-
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 13/09/2007 at 01:25, xxxxxxxx wrote:
Hello kuroyume0161,
First attempt is to merge c4d-files. Shouldn't a problem, what do you think?
BrowseFiles is okay, but I want to select the files from the filenames in the textfile. I can be sure that the files are in the folder.
I try it with the method you described. First shot with hardcoded values, and then step by step.
Do you have experience merging files? Is there anything I have to be carefull with?
guckmalda -
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 13/09/2007 at 02:52, xxxxxxxx wrote:
Quote: _Is there anything I have to be carefull with?
>
> * * *
_
There should be no problems with merging documents. Just make sure to set the right flags, for instance SCENEFILTER_OBJECTS if you want to merge only objects and their materials into the document.
cheers,
Matthias -
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 13/09/2007 at 09:45, xxxxxxxx wrote:
If you are going to pull the filenames from a text file, then you just need to parse it and add the filepath to a Filename class. It is important that the path is absolute if the path to the files isn't the same as your plugin's folder.
The best way to concatenate here is to create the Filename with the path only and then use SetFile() with the filename, for instance:
String fname; // Set to filename extracted from file while parsing ... Filename file = Filename("C:\MyFiles\C4D"); file.SetFile(fname); MergeDocument(doc, file, SCENEFILTER_OBJECTS|SCENEFILTER_PROGRESSALLOWED, NULL);
Matthias, is SCENEFILTER_MERGESCENE required at all?
-
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 17/09/2007 at 10:08, xxxxxxxx wrote:
Hello again, merging files works fine. The next step is to create a null-object in the object-browser and then assigning all objects of the merged part to this null-object.
Do I have to analyze the document, I want to merge, before or after merging again to get the objects or are there any attributes where the objects come from?
It is important that I can create the assembly structure like the CAD-structure.
Do you have any ideas doing that? -
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 17/09/2007 at 10:42, xxxxxxxx wrote:
This is going to be tough since the merge occurs directly without any notion of what is being added. At first glance, you could create an AtomArray to point to the existing scene objects (root objects should be all that is necessary). When the merge is complete, any root objects *not* in the AtomArray are obviously from the newly merged document. Create your null-object and parent those accordingly.
-
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 17/09/2007 at 12:46, xxxxxxxx wrote:
Quote: Originally posted by kuroyume0161 on 17 September 2007
>
> * * *
>
> Create your null-object and parent those accordingly.
>
>
> * * *Can you give me a hint which member or function I have to call to put the objects under the created null object and how to change the name of the null-object?
I think there is no tutorial for this taskThanks in advance
-
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 17/09/2007 at 17:32, xxxxxxxx wrote:
It's all laid out in the docs, but the way to do it is:
BaseObject* obj; BaseDocument* doc = GetActiveDocument(); // Allocate your null-object and insert into document BaseObject* nobj = BaseObject::Alloc(Onull); if (!nobj) return FALSE; // If you are tracking the scenes, it would make // sense to name the null-object to reflect this. // for example: nobj->SetName("Scene."+LongToString(docNumber)); doc->InsertObject(nobj, NULL, NULL, FALSE); // If the object is in the document, it must be removed // before changing its parents! obj->Remove(); // Insert the object under the null-object - as last item. // If the third argument is NULL, it will be added to the // top. doc->InsertObject(obj, nobj, nobj->GetDownLast(), FALSE);
What you'll have to do to find the newly added objects (and set to 'obj' in turn) is this:
// Allocated and filled in with current scene root objects before MergeDocument() is called AutoAlloc<AtomArray> array; if (!array) return FALSE; BaseObject* obj; for (obj = doc->GetFirstObject(); obj; obj = obj->GetNext()) { array->Append(obj); } ... // MergeDocument() ... // After MergeDocument() LONG k, acnt = array->GetCount(); BaseObject* aobj; BaseObject* nobj; for (obj = doc->GetFirstObject(); obj; obj = nobj) { nobj = obj->GetNext(); for (k = 0L; k != acnt; ++k) { aobj = static_cast<BaseObject*>(array->GetIndex(k)); if (aobj == obj) break; } // Reached the end of the AtomArray list without any matches if (k == acnt) { // 'obj' is new, parent to null-object } }