hi zipit, no worries,
thank you for your time!
Yes it is misterious, thats why I asked so vague. You can reproduce a heavy data import by putting my object sent to you into a cloner (5x1x5) and convert it (CSO) -
Running the below script takes about 4 seconds to run and about 1Minute plus to display with the same weird finished but not fnished behavior.
Use below script, set your C4D to only have one window otherwise I have status bar issues!
The status bar displays when its fnished with main()
the console lags behind but displays 4 secons !
Latest Version, difference to the slim version is mainly with some quality of live code.
by the way, scripts running for 1hour + are no strangers here - we often start them over night ... thats kinda normal the behavior is not
kind regards mogh
#!py3
import c4d, sys, os, math
from c4d import gui
from c4d.documents import GetActiveDocument
#Version 1.5
import cProfile, pstats
#import time
def profile(func):
# A simple profiling decorator.
profiler = cProfile.Profile()
def wrapper(*args, **kwargs):
result = None
try:
result = profiler.runcall(func, *args, **kwargs)
except Exception as error:
raise error
finally:
stats = pstats.Stats(profiler)
# To get the full profile do this.
stats.strip_dirs().sort_stats("cumtime").print_stats()
t = round(stats.total_tt, 3)
#print (f"{func.__name__} took {t} sec.\n")
return result
return wrapper
#@profile
def gime_time (milliseconds):
hours,milliseconds = divmod(milliseconds, 3600000)
minutes, milliseconds = divmod(milliseconds, 60000)
seconds = float(milliseconds) / 1000
s = "%i:%02i:%06.3f" % (hours, minutes, seconds)
return s
#@profile
def GetNextObject(op):
if not op: return
if op.GetDown(): return op.GetDown()
while op.GetUp() and not op.GetNext():
op = op.GetUp()
return op.GetNext()
#@profile
def get_all_objects (op):
allachsen_list = list()
all_objects_list = list()
while op:
if op.GetName() == 'Achsen-Objekt' or op.GetName() == 'Axis' :
allachsen_list.append(op)
all_objects_list.append(op)
op = GetNextObject(op)
#return {'all_objects_list' : all_objects}, allachsen
return all_objects_list, allachsen_list
#@profile
def statusbar (counter, secondcounter):
#print (secondcounter, int((100*secondcounter)/counter) )
if int((100*secondcounter)/counter) in [10,20,30,40,50,60,70,80,90,100]:
#print("Textupdate at: ", int((100*secondcounter)/counter))
c4d.StatusSetText ('%s - %s Objects are processed.' %(secondcounter, counter))
c4d.StatusSetBar(int(100*secondcounter/counter)) #statusbar
#c4d.gui.GeUpdateUI()
def savetorun(checkSelection = False):
try:
doc = GetActiveDocument()
except Exception as e:
print (e)
raise TypeError("No Active Document!")
exit()
return False
try:
op = doc.GetFirstObject()
except Exception as e:
print (e)
c4d.StatusSetText ('No Objects, nothing to do here.')
raise TypeError("No Objects, nothing to do here.")
exit()
return False
selected = None
if checkSelection == True:
selected = doc.GetActiveObject()
if selected == None:
c4d.StatusSetText ('No Object/s selected, nothing to do here.')
print ("No Object/s selected, nothing to do here.")
exit()
return False
return doc, op, selected
def savedoc(doc):
path = doc.GetDocumentPath()
name = doc.GetDocumentName()
name = name[ :-4 ] + "_conectedaxis.c4d"
filename = os.path.join(path, name)
saveflags = (c4d.SAVEDOCUMENTFLAGS_DONTADDTORECENTLIST | c4d.SAVEDOCUMENTFLAGS_DIALOGSALLOWED)
c4d.documents.SaveDocument(doc, filename, saveflags, format=c4d.FORMAT_C4DEXPORT)
#@profile
def JoinCommand(doc, op):
""" Apply a join command to the object passe as argument
:param op: the object to apply current state to object to.
:type: BaseObject
:return: the result of the command or raise an error if command failed
:rtype: BaseObject
"""
# null = c4d.BaseObject(c4d.Onull)
# #for o in op.GetChildren:
# op.InsertUnder(null)
#settings = c4d.BaseContainer()
#settings[c4d.MDATA_JOIN_MERGE_SELTAGS] = True
# bc = settings,
res = c4d.utils.SendModelingCommand(command = c4d.MCOMMAND_JOIN,
list = [op],
mode = c4d.MODELINGCOMMANDMODE_ALL,
doc = doc)
# Cheks if the command didn't failed
if res is False:
raise TypeError("return value of Join command is not valid")
elif res is True:
print ("Command successful. But no object.")
elif isinstance(res, list):
#if c4d.GetC4DVersion() < 21000: res[0].SetAbsPos(c4d.Vector())
op.Remove()
return res[0] # Returns the first item containing the object of the list. ??? GetClone() ???
#@profile
def set_point_object_transform(node, transform):
"""Sets the global transform of a point object while keeping its points in place.
Args:
node (c4d.PointObject): The point object to move the axis for.
transform (c4d.Matrix): The new global transform for the object.
Raises:
TypeError: When node or transform are not of specified type.
"""
if (not isinstance(node, c4d.PointObject) or
not isinstance(transform, c4d.Matrix)):
msg = f"Illegal argument types: {type(node)}{type(transform)}"
raise TypeError(msg)
#mg = node.GetMg()
# Move the points in the global frame and then into the new frame.
points = [p * ~transform for p in node.GetAllPoints()]
# Set the points and stuff ;)
node.SetAllPoints(points)
node.Message(c4d.MSG_UPDATE)
node.SetMg(transform)
#@profile
def joinmanagment(n):
# n "Axis" null will be not alive in a few steps get everything we need from it
if n.GetUp() :
parent = n.GetUp()
else:
print ("No Parent To Axis Null. Probably not save to run this sript anyway.")
c4d.StatusClear()
c4d.StatusSetText ('No Parent found! - Probalby mo CAD import Doc. Script Stopped.')
exit()
return False
newobject = JoinCommand(doc, n) # combine the poly objects
if not newobject.IsAlive():
raise TypeError("Object is not alive.")
return False
newobject.SetName(str(parent.GetName()))
newobject.InsertUnder(parent)
set_point_object_transform(newobject, n.GetMg()) # set points with global matrix from parent n "Axis"
#@profile
def main():
c4d.CallCommand(13957) # Konsole löschen
now = c4d.GeGetTimer() # start stopwatch
# Savetorun: Set True to check for slected objects and get them returned or throw an error, otherwise slected is None.
doc, op , selected = savetorun()
c4d.StatusSetSpin()
all_objects, allachsen = get_all_objects(op) # get two lists
null_counter = len(allachsen)
if null_counter == 0: # check if found something to do.
c4d.StatusClear()
c4d.StatusSetText ('No Axis Objects found, nothing to do here.')
print ("No Axis Objects found, nothing to do here.")
exit()
counter = len(all_objects)
secondcounter = 0
print (counter,' Objects' ,'\n' ,null_counter,' Nulls and their children to connect' ,'\n' ,'----------------------------------------------------' )
c4d.StatusSetText ('%s Objects are processed.' %(null_counter))
for n in allachsen:
secondcounter += 1
statusbar(null_counter, secondcounter)
joinmanagment(n)
#if joinmanagment(n) == False: break
print ('----------------------------------------------------')
print ('END OF SCRIPT %s ms ' %(gime_time(c4d.GeGetTimer() - now)) )
#savedoc(doc)
c4d.StatusClear()
c4d.StatusSetText ('Script finished - C4D needs a while to diplay the new viewport?!')
c4d.EventAdd() # update cinema 4d
return True
if __name__=='__main__':
main()