Code Vonc

Aire et volume

v 1.3

R13+ OSX Win

TéléchargerDownload
Faire un donMake a donation
Comment installer ?How to install ?
CommentairesComments

Copier le dossier « vonc_airevol » dans le dossier « plugins » du répertoire de Cinéma 4D.




v 1.3 :
- Calcul de multiples objets.
- Mise à jour auto.
- Traduction tchèque par Lubo Bezek.

v 1.2 :
- Corrections mineures.

v 1.1 :
- Possibilité de changer l'unité.
- Prise en compte de l'échelle du document.


Calcule l'aire et le volume :
- d'objets fermés,
- d'objets ouverts,
- de sélections de polygones,
- de tracés (splines).



Codes sourcesSources code

res/c4d_symbols.h

enum
{
    VONC_AIRVOL_NOM = 1000,
	VONC_AIRVOL_ETAT_0 = 1001,
	VONC_AIRVOL_ETAT_1 = 1002,
	VONC_AIRVOL_AIRE = 1003,
	VONC_AIRVOL_VOLUME = 1004,
	VONC_AIRVOL_CALCULER = 1005,
	VONC_AIRVOL_POLSEL = 1006,
	VONC_AIRVOL_LICENCE = 1007,
	VONC_AIRVOL_CLEF = 1008,
	VONC_AIRVOL_INFO = 1009,
	VONC_AIRVOL_AIDE = 1010,
	VONC_AIRVOL_OBJSEL = 1011,
	VONC_AIRVOL_SOUSOBJ = 1012,
	VONC_AIRVOL_TOTAL = 1013,
	VONC_AIRVOL_TOTALE = 1014,
	VONC_AIRVOL_MAJ = 1015,
	
    _DUMMY_ELEMENT_
};

res/strings_cz/c4d_strings.str

STRINGTABLE 
{
  VONC_AIRVOL_NOM       "Plocha a Objem";
  VONC_AIRVOL_AIRE      "Celkov\u00E1 plocha";
  VONC_AIRVOL_VOLUME    "Celkov\u00FD objem";
  VONC_AIRVOL_CALCULER  "Po\u010D\u00EDtat";
  VONC_AIRVOL_POLSEL    "Vybran\u00FDch polygon\u016F";
  VONC_AIRVOL_OBJSEL    "Objekt\u016F";
  VONC_AIRVOL_INFO      "C\u00E9sar Vonc - http://code.vonc.fr";
  VONc_AIRVOL_AIDE      "Vypo\u010D\u00EDt\u00E1v\u00E1 plochu a objem objekt\u016F, v\u00FDb\u011Bru polygon\u016F nebo k\u0159ivek.";
  VONC_AIRVOL_SOUSOBJ   "V\u010Detn\u011B pod\u0159\u00EDzen\u00FDch";
  VONC_AIRVOL_MAJ       "Automatick\u00E1 aktualizace";
}

res/strings_fr/c4d_strings.str

STRINGTABLE
{
	VONC_AIRVOL_NOM 		"Aire et Volume";
	VONC_AIRVOL_AIRE		"Aire totale";
	VONC_AIRVOL_VOLUME		"Volume total";
	VONC_AIRVOL_CALCULER	"Calculer";
	VONC_AIRVOL_POLSEL		"Polygones s\u00E9lectionn\u00E9s";
	VONC_AIRVOL_OBJSEL		"Objets";
	VONC_AIRVOL_INFO		"C\u00E9sar Vonc - http://code.vonc.fr";
	VONc_AIRVOL_AIDE		"Calcule l'aire et le volume d'objets, de s\u00E9lections de polygones ou de splines.";
	VONC_AIRVOL_SOUSOBJ		"Inclure les sous-objets";
	VONC_AIRVOL_MAJ			"Mise \u00E0 jour auto"; 
}

res/strings_us/c4d_strings.str

STRINGTABLE
{
	VONC_AIRVOL_NOM 		"Area and Volume";
	VONC_AIRVOL_AIRE		"Total area";
	VONC_AIRVOL_VOLUME		"Total volume";
	VONC_AIRVOL_CALCULER	"Calculate";
	VONC_AIRVOL_POLSEL		"Selected polygons";
	VONC_AIRVOL_OBJSEL		"Objects";
	VONC_AIRVOL_INFO		"C\u00E9sar Vonc - http://code.vonc.fr";
	VONc_AIRVOL_AIDE		"Calculate the area and volume of objects, polygons selections or splines.";
	VONC_AIRVOL_SOUSOBJ		"Add childrens";
	VONC_AIRVOL_MAJ			"Auto update";
}

vonc_airevol.pyp

import os
import c4d
from c4d import gui, plugins, utils, bitmaps, Vector
from c4d.utils import SendModelingCommand, Neighbor
from c4d.plugins import GeLoadString as txt

# César Vonc - code.vonc.fr

MODULE_ID = 1030057
VONC_AIRVOL_NOM = 1000
VONC_AIRVOL_ETAT_0 = 1001
VONC_AIRVOL_ETAT_1 = 1002
VONC_AIRVOL_AIRE = 1003
VONC_AIRVOL_VOLUME = 1004
VONC_AIRVOL_CALCULER = 1005
VONC_AIRVOL_POLSEL = 1006
VONC_AIRVOL_LICENCE = 1007
VONC_AIRVOL_CLEF = 1008
VONC_AIRVOL_INFO = 1009
VONC_AIRVOL_AIDE = 1010
VONC_AIRVOL_OBJSEL = 1011
VONC_AIRVOL_SOUSOBJ = 1012
VONC_AIRVOL_TOTAL = 1013
VONC_AIRVOL_TOTALE = 1014
VONC_AIRVOL_MAJ = 1015
VERSION = "1.3"

class Airevolume() :
	
	def __init__(self, so) :
		self.objs = None
		self.sousObj = so
		self.aire = 0
		self.volume = 0
		self.sel = 0
		self.nbObj = 0
		self.liObjs = []
		self.liVol = []
		self.liAire = []
		
		self.doc = c4d.documents.GetActiveDocument()
		self.op = self.doc.GetActiveObject()
		
		if so :
			self.objs = self.doc.GetActiveObjects(c4d.GETACTIVEOBJECTFLAGS_0)
		else :
			self.objs = self.doc.GetActiveObjects(c4d.GETACTIVEOBJECTFLAGS_CHILDREN)
	
	def fermeTrous(self, obj, mat) :
		obj.SetMg(mat)
		doc = self.doc
		doc.InsertObject(obj)
		polys = obj.GetAllPolygons()
		n = Neighbor()
		n.Init(obj)
		params = c4d.BaseContainer()
		params[c4d.MDATA_CLOSEHOLE_INDEX] = obj
		params[c4d.MDATA_CLOSEHOLE_TRI] = True
		mode = c4d.MODELINGCOMMANDMODE_EDGESELECTION
		commande = c4d.ID_MODELING_CLOSEHOLE_TOOL
		
		for i, pol in enumerate(polys):
			nab = n.GetNeighbor(pol.a, pol.b, i)
			nbc = n.GetNeighbor(pol.b, pol.c, i)
			ncd = n.GetNeighbor(pol.c, pol.d, i)
			nda = n.GetNeighbor(pol.d, pol.a, i)
			cotes = n.GetPolyInfo(i)["edge"]
			
			if nab == -1:
				params[c4d.MDATA_CLOSEHOLE_EDGE] = cotes[0]
				SendModelingCommand(command=commande, list=[obj], mode=mode, bc=params, doc=doc)
				n.Init(obj)
			if nbc == -1:
				params[c4d.MDATA_CLOSEHOLE_EDGE] = cotes[1]
				SendModelingCommand(command=commande, list=[obj], mode=mode, bc=params, doc=doc)
				n.Init(obj)
			if ((ncd == -1) and (pol.c != pol.d)):
				params[c4d.MDATA_CLOSEHOLE_EDGE] = cotes[2]
				SendModelingCommand(command=commande, list=[obj], mode=mode, bc=params, doc=doc)
				n.Init(obj)
			if nda == -1:
				params[c4d.MDATA_CLOSEHOLE_EDGE] = cotes[3]
				SendModelingCommand(command=commande, list=[obj], mode=mode, bc=params, doc=doc)
				n.Init(obj)
		
		obj.Remove()
		c4d.EventAdd()
		return obj

	def volumeTetraedre(self, p1, p2, p3) :
		return p1.Dot(p2.Cross(p3)) / 6.0

	def aireTriangle(self, A, B, C) :
		vAB = A - B
		vAC = A - C
		return vAB.Cross(vAC).GetLength() * 0.5
	
	def Calcule(self) :
		self.aire = 0
		self.volume = 0
		self.sel = 0
		tab3 = []
		for obj in self.objs :
			conv = SendModelingCommand(command=c4d.MCOMMAND_CURRENTSTATETOOBJECT, list=[obj], doc=self.doc)
			if not conv : continue
			conv = conv[0]
			conv.SetMg(obj.GetMg())
			cache = conv.GetDeformCache() or conv.GetCache() or conv
			cache = cache.GetDeformCache() or cache
			if cache : tab3.append(cache)
		
		self.objs = tab3
		
		if self.sousObj :
			tab = []
			tab2 = []
			for obj in self.objs :
				tab2.append(obj)
				sobj = obj.GetDown()
				if sobj : tab.append(sobj)
			for obj in tab :
				while obj :
					objs = [obj]
					for o in objs :
						tab2.append(o)
						objs.extend(o.GetChildren())
					obj = obj.GetNext()
			
			self.objs = tab2
		
		for obj in self.objs :
			aire, volume = self.CalculeObj(obj)
			self.aire += aire
			self.volume += volume
			if aire or volume :
				self.liObjs.append(obj.GetName())
				self.liAire.append(aire)
				self.liVol.append(volume)
		
		# self.nbObj = len(self.objs)
		self.nbObj = len(self.liObjs)
		
		
	def CalculeObj(self, obj):
		if not obj : return 0, 0
		doc = self.doc
		
		# Si cerce
		if obj.CheckType(c4d.Ospline) :
			peau = c4d.BaseObject(c4d.Oloft)
			obj.GetClone().InsertUnder(peau)
			retour = SendModelingCommand(command=c4d.MCOMMAND_CURRENTSTATETOOBJECT, list=[peau], doc=doc)
			if not retour : return 0, 0
			if retour[0].CheckType(c4d.Opolygon) : obj = retour[0]
			else : obj = retour[0].GetDown()
			if not obj : return 0, 0
		
		if not obj.CheckType(c4d.Opolygon) :
			return 0, 0
		
		# Détache la sélection
		if obj.GetBit(c4d.BIT_ACTIVE) :
			if doc.GetMode() == c4d.Mpolygons :
				bs = obj.GetPolygonS()
				self.sel += bs.GetCount()
				retour = SendModelingCommand(command=c4d.MCOMMAND_SPLIT, list=[obj], 
							mode=c4d.MODELINGCOMMANDMODE_POLYGONSELECTION, doc=doc)
				if not retour : return 0, 0
				obj = retour[0]
		
		# Optimise
		params = c4d.BaseContainer()
		params[c4d.MDATA_OPTIMIZE_TOLERANCE] = 0.001
		params[c4d.MDATA_OPTIMIZE_POINTS] = False
		params[c4d.MDATA_OPTIMIZE_POLYGONS] = True
		params[c4d.MDATA_OPTIMIZE_UNUSEDPOINTS] = True
		SendModelingCommand(command=c4d.MCOMMAND_OPTIMIZE, list=[obj], bc=params, doc=doc)
		
		# Ferme les trous
		objVol = self.fermeTrous(obj.GetClone(), obj.GetMg())
		
		# Aligne les normales
		SendModelingCommand(command=c4d.MCOMMAND_ALIGNNORMALS, list=[obj], doc=doc)
		SendModelingCommand(command=c4d.MCOMMAND_ALIGNNORMALS, list=[objVol], doc=doc)
		
		# Triangule
		SendModelingCommand(command=c4d.MCOMMAND_TRIANGULATE, list=[obj], doc=doc)
		SendModelingCommand(command=c4d.MCOMMAND_TRIANGULATE, list=[objVol], doc=doc)
		
		# --
		
		polys = obj.GetAllPolygons()
		pts = obj.GetAllPoints()
		polysVol = objVol.GetAllPolygons()
		ptsVol = objVol.GetAllPoints()
		
		ech = Vector(obj.GetMg().v1.GetLength(), obj.GetMg().v2.GetLength(), obj.GetMg().v3.GetLength())
		pts = [pt.__rxor__(ech) for pt in pts]
		ech = Vector(objVol.GetMg().v1.GetLength(), objVol.GetMg().v2.GetLength(), objVol.GetMg().v3.GetLength())
		# ech = objVol.GetAbsScale()
		ptsVol = [pt.__rxor__(ech) for pt in ptsVol]
		
		aire = 0.0
		for pol in polys :
			aire += self.aireTriangle(pts[pol.a], pts[pol.b], pts[pol.c])
		
		volume = 0.0
		for pol in polysVol :
			volume += self.volumeTetraedre(ptsVol[pol.a], ptsVol[pol.b], ptsVol[pol.c])
		
		volume = abs(volume)
		return aire, volume
	
class Dialogue(gui.GeDialog):
	
	def __init__(self) :
		self.airevol = None
		self.uniteFin = 0
		self.sousObj = True
		self.majAuto = True
		self.caches = [[],0,0,0,0]
		self.airevol = Airevolume(self.sousObj)
		self.airevol.Calcule()
		
		prefs = c4d.GetWorldContainer()
		unitePref = prefs[c4d.WPREF_UNITS_BASIC]
		self.uniteFin = unitePref
	
	def unite(self, v, valeur) :
		doc = c4d.documents.GetActiveDocument()
		
		donneesDoc = doc.GetData()[c4d.DOCUMENT_DOCUNIT]
		ech, uniteDoc = donneesDoc.GetUnitScale()
		
		uniteFin = self.uniteFin
		
		ufin = ""
		if uniteFin == c4d.UNIT_NONE : ufin = ""
		elif uniteFin == c4d.UNIT_KM : ufin = "km"
		elif uniteFin == c4d.UNIT_M : ufin = "m"
		elif uniteFin == c4d.UNIT_CM : ufin = "cm"
		elif uniteFin == c4d.UNIT_MM : ufin = "mm"
		elif uniteFin == c4d.UNIT_UM : ufin = "µm"
		elif uniteFin == c4d.UNIT_NM : ufin = "nm"
		elif uniteFin == c4d.UNIT_MILE : ufin = "mi"
		elif uniteFin == c4d.UNIT_YARD : ufin = "yd"
		elif uniteFin == c4d.UNIT_FEET : ufin = "ft"
		elif uniteFin == c4d.UNIT_INCH : ufin = "in"
		
		valeur *= ech**v
		
		fac = 1.0
		if uniteDoc == c4d.UNIT_KM : fac *= 10.0**(3*v)
		elif uniteDoc == c4d.UNIT_CM : fac *= 10.0**(-2*v)
		elif uniteDoc == c4d.UNIT_MM : fac *= 10.0**(-3*v)
		elif uniteDoc == c4d.UNIT_UM : fac *= 10.0**(-6*v)
		elif uniteDoc == c4d.UNIT_NM : fac *= 10.0**(-9*v)
		elif uniteDoc == c4d.UNIT_MILE : fac *= 1609.344**v
		elif uniteDoc == c4d.UNIT_YARD : fac *= 0.9144**v
		elif uniteDoc == c4d.UNIT_FEET : fac *= 0.3048**v
		elif uniteDoc == c4d.UNIT_INCH : fac *= 0.0254**v
		
		if ufin == "km" : fac *= 10.0**(-3*v)
		elif ufin == "cm" : fac *= 10.0**(2*v)
		elif ufin == "mm" : fac *= 10.0**(3*v)
		elif ufin == "µm" : fac *= 10.0**(6*v)
		elif ufin == "nm" : fac *= 10.0**(9*v)
		elif ufin == "mi" : fac /= 1609.344**v
		elif ufin == "yd" : fac /= 0.9144**v
		elif ufin == "ft" : fac /= 0.3048**v
		elif ufin == "in" : fac /= 0.0254**v
		
		valeur *= fac
		
		if v == 2 : v = "²"
		elif v == 3 : v = "³"
		if valeur > 10.0 : valeur = round(valeur, 4)
		retour = str(valeur) + " " + ufin + v
		return retour
	
	def rapport(self) :
		chn = ""
		chn += txt(VONC_AIRVOL_POLSEL) + " : " + str(self.airevol.sel) + "\r\n"
		chn += txt(VONC_AIRVOL_OBJSEL) + " : " + str(self.airevol.nbObj) + "\r\n"
		chn += "\r\n"
		
		liNb = len(self.airevol.liObjs)
		
		if liNb > 1 : chn += txt(VONC_AIRVOL_AIRE) + " : " + self.unite(2, self.airevol.aire) + "\r\n"
		else : chn += txt(VONC_AIRVOL_AIRE) + " : \r\n"
		for i in xrange(liNb) :
			chn += "    " + self.airevol.liObjs[i] + " : " + self.unite(2, self.airevol.liAire[i]) + "\r\n"
		chn += "\r\n"
		
		if liNb > 1 : chn += txt(VONC_AIRVOL_VOLUME) + " : " + self.unite(3, self.airevol.volume) + "\r\n"
		else : chn += txt(VONC_AIRVOL_VOLUME) + " : \r\n"
		for i in xrange(liNb) :
			if i : chn += "\r\n"
			chn += "    " + self.airevol.liObjs[i] + " : " + self.unite(3, self.airevol.liVol[i])
		
		return chn
	
	def opere(self, force=False) :
		self.sousObj = self.GetBool(23)
		self.majAuto = self.GetBool(24)
		
		doc = c4d.documents.GetActiveDocument()
		if self.sousObj :
			objs = doc.GetActiveObjects(c4d.GETACTIVEOBJECTFLAGS_0)
		else :
			objs = doc.GetActiveObjects(c4d.GETACTIVEOBJECTFLAGS_CHILDREN)
		caches = [objs, 0, 0, 0, 0]
		if objs :
			tabobjs = objs[:]
			for obj in tabobjs :
				caches[1] += obj.GetDirty(c4d.DIRTY_SELECT)
				caches[2] += obj.GetDirty(c4d.DIRTY_MATRIX)
				caches[3] += obj.GetDirty(c4d.DIRTY_DATA)
				caches[4] += obj.GetDirty(c4d.DIRTY_CHILDREN)
				tabobjs.extend(obj.GetChildren())
		if not force :
			if caches == self.caches :
				self.caches = caches
				return
		
		self.caches = caches
		self.airevol = Airevolume(self.sousObj)
		self.airevol.Calcule()
		self.uniteFin = self.GetLong(41)
		self.SetString(26, self.rapport())
	
	def CreateLayout(self) :
		self.GroupBegin(40, c4d.BFH_SCALEFIT, 2, 1)
		self.GroupBorderSpace(5, 0, 5, 0)
		self.AddButton(21, c4d.BFH_SCALE|c4d.BFH_RIGHT, initw=150, inith=20, name=txt(VONC_AIRVOL_CALCULER))
		self.AddComboBox(41, c4d.BFH_SCALE|c4d.BFH_CENTER, initw=60)
		# self.AddChild(41, c4d.UNIT_NONE, "")
		self.AddChild(41, c4d.UNIT_KM, "km")
		self.AddChild(41, c4d.UNIT_M, "m")
		self.AddChild(41, c4d.UNIT_CM, "cm")
		self.AddChild(41, c4d.UNIT_MM, "mm")
		self.AddChild(41, c4d.UNIT_UM, "µm")
		self.AddChild(41, c4d.UNIT_NM, "nm")
		self.AddChild(41, c4d.UNIT_MILE, "mi")
		self.AddChild(41, c4d.UNIT_YARD, "yd")
		self.AddChild(41, c4d.UNIT_FEET, "ft")
		self.AddChild(41, c4d.UNIT_INCH, "in")
		self.GroupEnd()
		
		self.GroupBegin(20, c4d.BFH_SCALEFIT, 1, 1)
		self.GroupBorderSpace(5, 0, 5, 0)
		self.AddCheckbox(23, c4d.BFH_SCALEFIT, 0, 0, txt(VONC_AIRVOL_SOUSOBJ))
		self.AddCheckbox(24, c4d.BFH_SCALEFIT, 0, 0, txt(VONC_AIRVOL_MAJ))
		self.GroupEnd()
		
		self.GroupBegin(25, c4d.BFH_SCALEFIT|c4d.BFV_SCALEFIT, 1, 1)
		self.GroupBorderSpace(5, 0, 5, 0)
		self.GroupBorderNoTitle(c4d.BORDER_THIN_IN)
		self.AddMultiLineEditText(26, c4d.BFH_SCALEFIT|c4d.BFV_SCALEFIT)
		self.GroupEnd()
		
		self.GroupBegin(30, c4d.BFH_SCALEFIT, 1, 1)
		self.GroupBorderSpace(5, 5, 5, 5)
		self.AddStaticText(31, c4d.BFH_SCALEFIT, name="v "+VERSION+" - "+txt(VONC_AIRVOL_INFO))
		self.GroupEnd()
		return True
	
	def InitValues(self) :
		self.SetTitle(txt(VONC_AIRVOL_NOM))
		self.SetLong(41, self.uniteFin)
		self.SetBool(23, self.sousObj)
		self.SetBool(24, self.majAuto)
		self.SetString(26, self.rapport())
		return True
	
	def Command(self, id, msg) :
		if id == 21 or id == 23 or id == 24 :
			self.opere(True)
		elif id == 41 :
			self.uniteFin = self.GetLong(41)
			self.SetString(26, self.rapport())
			
		return True
	
	def CoreMessage(self, id, msg) :
		
		if self.majAuto and id == c4d.EVMSG_CHANGE :
			self.opere()
		
		return True

class AirevolumeCommande(c4d.plugins.CommandData):
	dialog = None
	
	def Execute(self, doc):
		if self.dialog is None:
		   self.dialog = Dialogue()
		return self.dialog.Open(dlgtype=c4d.DLG_TYPE_ASYNC, pluginid=MODULE_ID, defaulth=300, defaultw=100)

	def RestoreLayout(self, sec_ref):
		if self.dialog is None:
		   self.dialog = Dialogue()
		return self.dialog.Restore(pluginid=MODULE_ID, secret=sec_ref)

if __name__ == "__main__":
	 bmp = bitmaps.BaseBitmap()
	 dir, f = os.path.split(__file__)
	 fn = os.path.join(dir, "res", "vonc_airevol.tif")
	 bmp.InitWith(fn)
	 c4d.plugins.RegisterCommandPlugin(id=MODULE_ID, str=txt(VONC_AIRVOL_NOM),
									  help=txt(VONC_AIRVOL_AIDE),info=0,
										dat=AirevolumeCommande(), icon=bmp)