Code Vonc

Import SVG

v 1.0

R13, R14, R15, R16, R17, R18, R19, R20 OSX Win

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

Filtre d'importation de fichiers Scalable Vector Graphics (SVG).


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




Caractéristiques


Note : des imperfections peuvent survenir dûes à la complexité du format SVG malgré tous mes efforts. Vous trouverez ci-dessous la liste des éléments non importables. Si vous rencontrez un problème avec un fichier particulier, n'hésitez pas à me l'envoyer pour améliorer les futures versions de l'importeur.

Importe :
- Rectangles (rect)
- Cercles (circle)
- Ellipses (ellipse)
- Lignes (line)
- Polylignes (polyline)
- Polygones (polygon)
- Formes (path)
- Transformations (transform)
- Couleur de remplissage (fill)
- Contours/lignes (stroke, stroke-width)

Importe partiellement :
- Textes (text, tspan) : style de texte simple
- Instances (use) : instances non modifiées
- Styles (style) : styles simples
- Unités : px, pt, pc

N'importe pas :
- Pointillés (stroke-dasharray)
- Transparence (opacity)
- Filtres
- Dégradés
- Images (image)
- Mode de remplissage (fill-rule)


Vidéo


Gear Generator + Import SVG C4D



Viméo



Documentation






Espacement des calques :
Modifie la position Z des différents objets importés.

1 cm       |       0,1 cm



Importer les couleurs :
Ajoute ou non des matériaux aux objets importés.

Activé       |       Désactivé



Remplir les formes :
Créé ou non des polygones remplissant les tracés importés.

Activé       |       Désactivé



Coupe transversale constante :
Définit si l'épaisseur des traits reste constante en fonction de l'angle. Des artefacts peuvent apparaître si l'angle est trop important.

Activé       |       Désactivé



Exemples








Codes sourcesSources code

res/c4d_symbols.h

enum
{	
	IDS_VONC_SVG_IMPORT = 1000,
	VONC_SVG_IMPORT_DEMO = 1001
};

res/description/vonc_svg_import.h

#ifndef _vonc_svg_import_H_
#define _vonc_svg_import_H_

enum
{
	VONC_SVG_IMPORT_GROUPE				= 999,
	VONC_SVG_IMPORT_GROUPE_GENERAL		= 1000,
	VONC_SVG_IMPORT_GROUPE_COURBE		= 1001,
	VONC_SVG_IMPORT_GROUPE_FORMES		= 1002,
	VONC_SVG_IMPORT_GROUPE_MATS			= 1003,
	VONC_SVG_IMPORT_GROUPE_LICENCE		= 1004,
	VONC_SVG_IMPORT_COUPECONST			= 2003,
	VONC_SVG_IMPORT_DECZ				= 2004,
	VONC_SVG_IMPORT_FORMES				= 2005,
	VONC_SVG_IMPORT_MATS				= 2006,
	VONC_SVG_IMPORT_CLE					= 2007,
	VONC_SVG_IMPORT_INFO				= 2008
};

#endif

res/description/vonc_svg_import.res

CONTAINER vonc_svg_import
{
	NAME vonc_svg_import;
	INCLUDE Fbase;

	GROUP VONC_SVG_IMPORT_GROUPE
	{
		SEPARATOR VONC_SVG_IMPORT_GROUPE_GENERAL {}
			
			REAL VONC_SVG_IMPORT_DECZ	{ UNIT METER; STEP 0.1; }
		
		SEPARATOR VONC_SVG_IMPORT_GROUPE_COURBE {}
			
			BOOL VONC_SVG_IMPORT_COUPECONST	{ }
		
		SEPARATOR VONC_SVG_IMPORT_GROUPE_FORMES {}
			
			BOOL VONC_SVG_IMPORT_FORMES	{ }
		
		SEPARATOR VONC_SVG_IMPORT_GROUPE_MATS {}
			
			BOOL VONC_SVG_IMPORT_MATS	{ }
		
		SEPARATOR { LINE; }
		
		GROUP {
			STATICTEXT VONC_SVG_IMPORT_INFO { }
		}
	}
}

res/strings_en-US/c4d_strings.str

STRINGTABLE
{
	IDS_VONC_SVG_IMPORT		"SVG (*.svg)";
	VONC_SVG_IMPORT_DEMO	"The activation key is wrong or missing. Only the 20 first elements of the SVG file will be imported with this demo version.";
}

res/strings_en-US/description/vonc_svg_import.str

STRINGTABLE vonc_svg_import
{
	vonc_svg_import					"Import SVG";
	VONC_SVG_IMPORT_GROUPE_GENERAL	"General";
	VONC_SVG_IMPORT_GROUPE_COURBE	"Lines";
	VONC_SVG_IMPORT_GROUPE_FORMES	"Shapes";
	VONC_SVG_IMPORT_GROUPE_MATS		"Colors";
	VONC_SVG_IMPORT_GROUPE_LICENCE	"License";
	VONC_SVG_IMPORT_COUPECONST		"Constant cross section";
	VONC_SVG_IMPORT_DECZ			"Spacing layers";
	VONC_SVG_IMPORT_FORMES			"Fill shapes";
	VONC_SVG_IMPORT_MATS			"Import colors";
	VONC_SVG_IMPORT_CLE				"Activation key";
	VONC_SVG_IMPORT_INFO			"v 1.0 - C\u00E9sar Vonc - http://code.vonc.fr";
}

res/strings_fr/c4d_strings.str

STRINGTABLE
{
	IDS_VONC_SVG_IMPORT		"SVG (*.svg)";
	VONC_SVG_IMPORT_DEMO	"Clef d'activation incorrecte ou manquante. Seuls les 20 premiers \u00E9l\u00E9ments du fichier SVG seront import\u00E9s avec cette version d\u00E9mo.";
}

res/strings_fr/description/vonc_svg_import.str

STRINGTABLE vonc_svg_import
{
	vonc_svg_import					"Import SVG";
	VONC_SVG_IMPORT_GROUPE_GENERAL	"G\u00E9n\u00E9ralit\u00E9s";
	VONC_SVG_IMPORT_GROUPE_COURBE	"Lignes";
	VONC_SVG_IMPORT_GROUPE_FORMES	"Formes";
	VONC_SVG_IMPORT_GROUPE_MATS		"Couleurs";
	VONC_SVG_IMPORT_GROUPE_LICENCE	"License";
	VONC_SVG_IMPORT_COUPECONST		"Coupe transversale constante";
	VONC_SVG_IMPORT_DECZ			"Espacement des calques";
	VONC_SVG_IMPORT_FORMES			"Remplir les formes";
	VONC_SVG_IMPORT_MATS			"Importer les couleurs";
	VONC_SVG_IMPORT_CLE				"Clef d'activation";
	VONC_SVG_IMPORT_INFO			"v 1.0 - C\u00E9sar Vonc - http://code.vonc.fr";
}

res/strings_fr-FR/c4d_strings.str

STRINGTABLE
{
	IDS_VONC_SVG_IMPORT		"SVG (*.svg)";
	VONC_SVG_IMPORT_DEMO	"Clef d'activation incorrecte ou manquante. Seuls les 20 premiers \u00E9l\u00E9ments du fichier SVG seront import\u00E9s avec cette version d\u00E9mo.";
}

res/strings_fr-FR/description/vonc_svg_import.str

STRINGTABLE vonc_svg_import
{
	vonc_svg_import					"Import SVG";
	VONC_SVG_IMPORT_GROUPE_GENERAL	"G\u00E9n\u00E9ralit\u00E9s";
	VONC_SVG_IMPORT_GROUPE_COURBE	"Lignes";
	VONC_SVG_IMPORT_GROUPE_FORMES	"Formes";
	VONC_SVG_IMPORT_GROUPE_MATS		"Couleurs";
	VONC_SVG_IMPORT_GROUPE_LICENCE	"License";
	VONC_SVG_IMPORT_COUPECONST		"Coupe transversale constante";
	VONC_SVG_IMPORT_DECZ			"Espacement des calques";
	VONC_SVG_IMPORT_FORMES			"Remplir les formes";
	VONC_SVG_IMPORT_MATS			"Importer les couleurs";
	VONC_SVG_IMPORT_CLE				"Clef d'activation";
	VONC_SVG_IMPORT_INFO			"v 1.0 - C\u00E9sar Vonc - http://code.vonc.fr";
}

res/strings_us/c4d_strings.str

STRINGTABLE
{
	IDS_VONC_SVG_IMPORT		"SVG (*.svg)";
	VONC_SVG_IMPORT_DEMO	"The activation key is wrong or missing. Only the 20 first elements of the SVG file will be imported with this demo version.";
}

res/strings_us/description/vonc_svg_import.str

STRINGTABLE vonc_svg_import
{
	vonc_svg_import					"Import SVG";
	VONC_SVG_IMPORT_GROUPE_GENERAL	"General";
	VONC_SVG_IMPORT_GROUPE_COURBE	"Lines";
	VONC_SVG_IMPORT_GROUPE_FORMES	"Shapes";
	VONC_SVG_IMPORT_GROUPE_MATS		"Colors";
	VONC_SVG_IMPORT_GROUPE_LICENCE	"License";
	VONC_SVG_IMPORT_COUPECONST		"Constant cross section";
	VONC_SVG_IMPORT_DECZ			"Spacing layers";
	VONC_SVG_IMPORT_FORMES			"Fill shapes";
	VONC_SVG_IMPORT_MATS			"Import colors";
	VONC_SVG_IMPORT_CLE				"Activation key";
	VONC_SVG_IMPORT_INFO			"v 1.0 - C\u00E9sar Vonc - http://code.vonc.fr";
}

vonc_svg.pyp

import os
import c4d
import struct as st
import xml.dom.minidom
import math
import hashlib
from xml.dom.minidom import parse, Node
from c4d import plugins, Vector, utils, Matrix
from c4d.utils import Rad

MODULE_ID = 1031200
IDS_VONC_SVG_IMPORT = 1000
VONC_SVG_IMPORT_COUPECONST = 2003
VONC_SVG_IMPORT_DECZ = 2004
VONC_SVG_IMPORT_FORMES = 2005
VONC_SVG_IMPORT_MATS = 2006

COULEURS_CSS = {'aliceblue':'#f0f8ff','antiquewhite':'#faebd7','aqua':'#00ffff','aquamarine':'#7fffd4','azure':'#f0ffff','beige':'#f5f5dc','bisque':'#ffe4c4',
'black':'#000000','blanchedalmond':'#ffebcd','blue':'#0000ff','blueviolet':'#8a2be2','brown':'#a52a2a','burlywood':'#deb887','cadetblue':'#5f9ea0',
'chartreuse':'#7fff00','chocolate':'#d2691e','coral':'#ff7f50','cornflowerblue':'#6495ed','cornsilk':'#fff8dc','crimson':'#dc143c','cyan':'#00ffff',
'darkblue':'#00008b','darkcyan':'#008b8b','darkgoldenrod':'#b8860b','darkgray':'#a9a9a9','darkgreen':'#006400','darkkhaki':'#bdb76b',
'darkmagenta':'#8b008b','darkolivegreen':'#556b2f','darkorange':'#ff8c00','darkorchid':'#9932cc','darkred':'#8b0000','darksalmon':'#e9967a',
'darkseagreen':'#8fbc8f','darkslateblue':'#483d8b','darkslategray':'#2f4f4f','darkturquoise':'#00ced1','darkviolet':'#9400d3','deeppink':'#ff1493',
'deepskyblue':'#00bfff','dimgray':'#696969','dodgerblue':'#1e90ff','firebrick':'#b22222','floralwhite':'#fffaf0','forestgreen':'#228b22',
'fuchsia':'#ff00ff','gainsboro':'#dcdcdc','ghostwhite':'#f8f8ff','gold':'#ffd700','goldenrod':'#daa520','gray':'#808080','green':'#008000',
'greenyellow':'#adff2f','honeydew':'#f0fff0','hotpink':'#ff69b4','indianred ':'#cd5c5c','indigo ':'#4b0082','ivory':'#fffff0','khaki':'#f0e68c',
'lavender':'#e6e6fa','lavenderblush':'#fff0f5','lawngreen':'#7cfc00','lemonchiffon':'#fffacd','lightblue':'#add8e6','lightcoral':'#f08080',
'lightcyan':'#e0ffff','lightgoldenrodyellow':'#fafad2','lightgray':'#d3d3d3','lightgreen':'#90ee90','lightpink':'#ffb6c1','lightsalmon':'#ffa07a',
'lightseagreen':'#20b2aa','lightskyblue':'#87cefa','lightslategray':'#778899','lightsteelblue':'#b0c4de','lightyellow':'#ffffe0','lime':'#00ff00',
'limegreen':'#32cd32','linen':'#faf0e6','magenta':'#ff00ff','maroon':'#800000','mediumaquamarine':'#66cdaa','mediumblue':'#0000cd',
'mediumorchid':'#ba55d3','mediumpurple':'#9370db','mediumseagreen':'#3cb371','mediumslateblue':'#7b68ee','mediumspringgreen':'#00fa9a',
'mediumturquoise':'#48d1cc','mediumvioletred':'#c71585','midnightblue':'#191970','mintcream':'#f5fffa','mistyrose':'#ffe4e1','moccasin':'#ffe4b5',
'navajowhite':'#ffdead','navy':'#000080','oldlace':'#fdf5e6','olive':'#808000','olivedrab':'#6b8e23','orange':'#ffa500','orangered':'#ff4500',
'orchid':'#da70d6','palegoldenrod':'#eee8aa','palegreen':'#98fb98','paleturquoise':'#afeeee','palevioletred':'#db7093','papayawhip':'#ffefd5',
'peachpuff':'#ffdab9','peru':'#cd853f','pink':'#ffc0cb','plum':'#dda0dd','powderblue':'#b0e0e6','purple':'#800080','red':'#ff0000',
'rosybrown':'#bc8f8f','royalblue':'#4169e1','saddlebrown':'#8b4513','salmon':'#fa8072','sandybrown':'#f4a460','seagreen':'#2e8b57','seashell':'#fff5ee',
'sienna':'#a0522d','silver':'#c0c0c0','skyblue':'#87ceeb','slateblue':'#6a5acd','slategray':'#708090','snow':'#fffafa','springgreen':'#00ff7f',
'steelblue':'#4682b4','tan':'#d2b48c','teal':'#008080','thistle':'#d8bfd8','tomato':'#ff6347','turquoise':'#40e0d0','violet':'#ee82ee',
'wheat':'#f5deb3','white':'#ffffff','whitesmoke':'#f5f5f5','yellow':'#ffff00','yellowgreen':'#9acd32'}

class ImporteurSVG(plugins.SceneLoaderData) :
	fichier = None
	format = None
	doc = None
	obj_n = 0
	obj_i = 0
	dic_ids = {}
	dic_mat = {}
	obj_complet = []
	inst_complet = []
	styleParent = None
	styleGlobal = None
	xParent = 0
	yParent = 0
	
	opt_decz = 0.5
	opt_coupeconst = True
	opt_formes = True
	opt_mats = True
	
	
	def creer(self, noeud, stylePar=None, parent=None) :
		
		self.styleParent = stylePar
		#if noeud.nodeType != Node.ELEMENT_NODE : return (None, None), True
		
		nom = noeud.nodeName
		if nom == "rect" :
			return self.rect(noeud), False
		elif nom == "circle" :
			return self.cercle(noeud), False
		elif nom == "ellipse" :
			return self.ellipse(noeud), False
		elif nom == "line" :
			return self.ligne(noeud), False
		elif nom == "path" :
			return self.forme(noeud), False
		elif nom == "polygon" :
			return self.polygone(noeud), False
		elif nom == "polyline" :
			return self.polygone(noeud, True), False
		elif nom == "use" :
			return self.instance(noeud), False
		elif nom == "text" :
			return self.texte(noeud), True
		elif nom == "tspan" :
			return self.texte(noeud, "span", parent), True
		elif nom == "style" :
			return self.style(noeud), False
		elif nom == "metadata" :
			return ([], None, None), False
		else :
			return self._defaut(noeud), True
	
	def conv_unit(self, val, defaut=0) :
		if val == "" : return defaut
		unit = ""
		if not val[-1].isdigit() :
			if len(val) <= 2 : return defaut
			unit = val[-2:]
			val = val[:-2]
			if not val[0].isdigit() : return defaut
			val = float(val)
			
			if unit == "pt" :
				val = val / 0.75
			elif unit == "pc" :
				val = val / 9.0
			
		else :
			val = float(val)
		
		return val
	
	def rec_val(self, noeud, att, type="float", defaut=None) :
		noeudatt = noeud.attributes
		if not noeudatt : return defaut
		try : prop = noeud.attributes[att]
		except KeyError : return defaut
		else :
			val = prop.value
			if type == "float" : return self.conv_unit(val)
			elif type == "str" : return val.encode('utf-8', 'replace')
	
	def recup_style(self, noeud) :
		style = {'fill':'', 'stroke':'', 'stroke-width':'', 'font-family':'', 'font-size':'', 'font-style':'', 'font-weight':'', 'text-anchor':''}
		
		if self.styleGlobal :
			_balise = str(noeud.nodeName)
			_classes = self.rec_val(noeud, "class", "str", "")
			_classes = _classes.split(' ')
			_id = self.rec_val(noeud, "id", "str")
			if _balise and _balise in self.styleGlobal : style.update(self.styleGlobal[_balise])
			for _classe in _classes :
				if _classe and '.'+_classe in self.styleGlobal : style.update(self.styleGlobal['.'+_classe])
			if _id and '#'+_id in self.styleGlobal : style.update(self.styleGlobal['#'+_id])
		
		if self.styleParent :
			# style.update(self.styleParent)
			for cle in self.styleParent :
				if not cle in style or not style[cle] : style[cle] = self.styleParent[cle]
		
		for cle in style :
			att = self.rec_val(noeud, cle, "str")
			if att : style[cle] = att
		
		style_chn = self.rec_val(noeud, "style", "str")
		if style_chn :
			style_chn = style_chn.replace(" ", "")
			style_tab = style_chn.split(';')
			for sty in style_tab :
				if not sty : continue
				sty_t = sty.split(':')
				if len(sty_t) != 2 : continue
				cle = sty_t[0]
				att = sty_t[1]
				if cle in style :
					if att : style[cle] = att
		
		if style['stroke'] and style['stroke'] != "none" and not style['stroke-width'] : style['stroke-width'] = '1'
		
		return style
	
	def rec_nom(self, noeud) :
		nom = str(noeud.nodeName)
		id = self.rec_val(noeud, "id", "str")
		if id : nom = "#" + id
		return nom
	
	def _inclinaison(self, deg, x, y, m) :
		incli = c4d.BaseObject(c4d.Oshear)
		incli[c4d.DEFORMOBJECT_SIZE] = Vector(10.0)
		incli[c4d.DEFORMOBJECT_MODE] = c4d.DEFORMOBJECT_MODE_UNLIMITED
		incli[c4d.DEFORMOBJECT_CURVATURE] = 0.0
		ech = Vector(1.0 / (m.v1.GetLength()), 1.0 / (m.v2.GetLength()), 1.0)
		incli[c4d.ID_BASEOBJECT_REL_SCALE] = ech
		if x :
			incli[c4d.ID_BASEOBJECT_REL_POSITION,c4d.VECTOR_Y] = -5.0 * ech.y
			incli[c4d.ID_BASEOBJECT_REL_ROTATION,c4d.VECTOR_Z] = math.pi
			if deg : incli[c4d.DEFORMOBJECT_STRENGTH] = math.tan(utils.Rad(x)) * -2.0
			else : incli[c4d.DEFORMOBJECT_STRENGTH] = math.tan(x) * -2.0
		elif y :
			incli[c4d.ID_BASEOBJECT_REL_POSITION,c4d.VECTOR_X] = 5.0 * ech.x
			incli[c4d.ID_BASEOBJECT_REL_ROTATION,c4d.VECTOR_Z] = math.pi * .5
			if deg : incli[c4d.DEFORMOBJECT_STRENGTH] = math.tan(utils.Rad(y)) * 2.0
			else : incli[c4d.DEFORMOBJECT_STRENGTH] = math.tan(y) * 2.0
		incli[c4d.ID_BASEOBJECT_VISIBILITY_EDITOR] = 1
		
		incli.Message(c4d.MSG_UPDATE)
		return incli
	
	def rec_matrice(self, noeud, obj) :
		matrice = obj.GetMl()
		if not noeud : return matrice
		trans = self.rec_val(noeud, "transform", type="str")
		if not trans : return matrice
		trans = trans.replace(",", " ")
		trans_t = trans.split(')')
		trans_li = []
		for tra in trans_t :
			if len(tra) <= 1 : continue
			tra_t = tra.split('(')
			if len(tra_t) <= 1 : continue
			cle = tra_t[0].replace(' ', '')
			val_t = tra_t[1].split(' ')
			val = []
			for v in val_t :
				if v : val.append(float(v))
			trans_li.append((cle, val))
		
		if not trans_li : return matrice
		m = Matrix()
		for tra in trans_li :
			cle = tra[0]
			val = tra[1]
			if cle == "translate" :
				if len(val) == 1 : val.append(0.0)
				vec = Vector(val[0], -val[1], 0.0)
				m *= utils.MatrixMove(vec)
			elif cle == "rotate" :
				r = utils.Rad(val[0])
				m *= utils.MatrixRotZ(r)
			elif cle == "scale" :
				if len(val) == 1 : val.append(val[0])
				vec = Vector(val[0], val[1], 1.0)
				m *= utils.MatrixScale(vec)
			elif cle == "matrix" :
				m2 = Matrix()
				m2.off = Vector(val[4], -val[5], 0.0)
				m2.v1 = Vector(-val[0], val[1], 0.0)
				m2.v2 = Vector(-val[2], val[3], 0.0)
				m2 *= utils.MatrixScale(Vector(-1.0, 1.0, 1.0))
				
				# self._decomposeMatrice(val)
				
				m *= m2
			elif cle == "skewX" :
				incli = self._inclinaison(True, val[0], 0, m)
				incli.InsertUnder(obj)
			elif cle == "skewY" :
				incli = self._inclinaison(True, 0, val[0], m)
				incli.InsertUnder(obj)
			
		inclDiff = utils.VectorAngle(m.v1, m.v2) - 1.57079632
		if abs(inclDiff) > 0.0001 :
			# print inclDiff
			m.v2 *= math.cos(inclDiff)
			incli = self._inclinaison(False, inclDiff, 0, m)
			incli.InsertUnder(obj)
		
		matrice.off = m.MulV(matrice.off)
		matrice *= m
		return matrice
	
	def _defaut(self, noeud) :
		obj = c4d.BaseObject(c4d.Onull)
		obj[c4d.ID_BASELIST_NAME] = self.rec_nom(noeud)
		if noeud.nodeName == "defs" :
			obj[c4d.ID_BASEOBJECT_VISIBILITY_EDITOR] = 1
			obj[c4d.ID_BASEOBJECT_VISIBILITY_RENDER] = 1
		style = None
		if noeud.nodeType == Node.ELEMENT_NODE :
			obj.SetMl(self.rec_matrice(noeud, obj))
			style = self.recup_style(noeud)
		return [obj], None, style
	
	def _peau(self, nom, mat) :
		peau = c4d.BaseObject(c4d.Oloft)
		peau[c4d.ID_BASELIST_NAME] = nom
		peau[c4d.CAP_TYPE] = c4d.CAP_TYPE_NGON
		if not self.opt_mats : return peau
		pTex = peau.MakeTag(c4d.Ttexture)
		pTex[c4d.TEXTURETAG_MATERIAL] = mat
		return peau
	
	def _extrucon(self, nom, larg, obj, mat) :
		exc = c4d.BaseObject(c4d.Osweep)
		exc[c4d.ID_BASELIST_NAME] = nom
		exc[c4d.SWEEPOBJECT_CONSTANT] = self.opt_coupeconst
		exc[c4d.ID_BASEOBJECT_REL_POSITION,c4d.VECTOR_Z] = (larg * 0.5) - 0.1
		
		profil = c4d.BaseObject(c4d.Osplinerectangle)
		profil[c4d.PRIM_RECTANGLE_WIDTH] = larg
		profil[c4d.PRIM_RECTANGLE_HEIGHT] = larg
		
		profil.Message(c4d.MSG_UPDATE)
		obj.InsertUnder(exc)
		profil.InsertUnder(exc)
		if not self.opt_mats : return exc
		pTex = exc.MakeTag(c4d.Ttexture)
		pTex[c4d.TEXTURETAG_MATERIAL] = mat
		return exc
	
	def _ellAjPts(self, pos, ell) :
		li1 = []
		# mg = ell.GetMg()
		for i in xrange(100) :
			j = i * 0.01
			p = ell.GetSplinePoint(j)# * mg
			diff = (p - pos).GetLengthSquared()
			li1.append((diff, j))
		li1.sort()
		delta = li1[0][1]
		
		bc = c4d.BaseContainer()
		bc[c4d.MDATA_SPLINE_ADDPOINTSEGMENT] = 0
		bc[c4d.MDATA_SPLINE_ADDPOINTPOSITION] = delta
		utils.SendModelingCommand(command=c4d.MCOMMAND_SPLINE_ADDPOINT, list=[ell], bc=bc, doc=self.doc)
		
		return Vector()
	
	def _ellTangentes(self, ell, posA, grand=False) :
		bs = ell.GetPointS()
		nbpts = ell.GetPointCount()
		
		if grand : utils.SendModelingCommand(command=c4d.MCOMMAND_SPLINE_REVERSE, list=[ell], doc=self.doc)
		
		points = []
		tangentes = []
		debut = 0
		
		pts = []
		pts_i = []
		pt_dep = 0
		pt_fin = 0
		pt_fin_vec = Vector()
		for i, sel in enumerate(bs.GetAll(nbpts)) :
			if not sel : continue
			pts.append(ell.GetPoint(i))
			pts_i.append(i)
		
		pts[0] = (pts[0] - posA).GetLengthSquared()
		pts[1] = (pts[1] - posA).GetLengthSquared()
		if pts[1] < pts[0] :
			pt_dep = pts_i[1]
			pt_fin = pts_i[0]
			pt_fin_vec = ell.GetPoint(pts_i[0])
		else :
			pt_dep = pts_i[0]
			pt_fin = pts_i[1]
			pt_fin_vec = ell.GetPoint(pts_i[1])
		
		#
		bs.DeselectAll()
		bs.Select(pt_dep)
		utils.SendModelingCommand(command=c4d.MCOMMAND_SPLINE_REORDER, list=[ell], doc=self.doc)
		for i, pt in enumerate(ell.GetAllPoints()) :
			if pt == pt_fin_vec :
				pt_fin = i
				bs.Select(i)
				break
		#
		
		bsGetAll = bs.GetAll(nbpts)
		
		for i, sel in enumerate(bsGetAll) :
			if sel : debut += 1
			if debut :
				j = i
				points.append(ell.GetPoint(j))
				tans = ell.GetTangent(j)
				tangentes.append((tans['vl'], tans['vr']))
				if debut == 2 : break
		
		
		return points, tangentes
	
	def _interEllipses(self, posA, posB, l, h, rot, grand=0, autre=0):
		rot = Rad(rot)
		ellA = c4d.BaseObject(c4d.Osplinecircle)
		ellA[c4d.ID_BASEOBJECT_REL_ROTATION,c4d.VECTOR_Z] = rot
		ellA[c4d.PRIM_CIRCLE_ELLIPSE] = True
		ellA[c4d.PRIM_CIRCLE_RADIUS] = l
		ellA[c4d.PRIM_CIRCLE_RADIUSY] = h
		# ellA[c4d.PRIM_REVERSE] = inv
		ellB = ellA.GetClone()
		ellC = ellA.GetClone()
		ellA[c4d.ID_BASEOBJECT_REL_POSITION] = posA
		ellB[c4d.ID_BASEOBJECT_REL_POSITION] = posB
		masque = c4d.BaseObject(1019396) # Masque spline
		ellA.InsertUnder(masque)
		ellB.InsertUnder(masque)
		ret = utils.SendModelingCommand(command=c4d.MCOMMAND_CURRENTSTATETOOBJECT, list=[masque], doc=self.doc)
		if not ret : return None
		# self.doc.InsertObject(ret[0])
		if ret[0].GetSegmentCount() > 1 :
			interA = (posA + posB) * 0.5
			interB = interA
			teta = rot - utils.VectorAngle((posB-posA), Vector(1.0, 0.0, 0.0))
			r = ( 1 / ( (((math.cos(teta))**2)/(l**2)) + (((math.sin(teta))**2)/(h**2)) ) ) ** .5
			r *= 2.0
			distAB = (posB - posA).GetLength()
			facteur = distAB / r
			ellC[c4d.PRIM_CIRCLE_RADIUS] *= facteur
			ellC[c4d.PRIM_CIRCLE_RADIUSY] *= facteur
		else :
			interA = ret[0].GetPoint(0)
			ellA[c4d.PRIM_REVERSE] = True
			# ellB[c4d.PRIM_REVERSE] = True
			ret = utils.SendModelingCommand(command=c4d.MCOMMAND_CURRENTSTATETOOBJECT, list=[masque], doc=self.doc)
			interB = ret[0].GetPoint(0)
		
		inter = None
		if posB.x == posA.x :
			if posB.y > posA.y :
				if interA.x < interB.x : inter = interA
				else : inter = interB
			else :
				if interA.x > interB.x : inter = interA
				else : inter = interB
		elif posB.x > posA.x :
			if interA.y > interB.y : inter = interA
			else : inter = interB
		else :
			if interA.y < interB.y : inter = interA
			else : inter = interB
		
		
		if grand : autre = not autre
		if autre :
			if inter == interA : inter = interB
			else : inter = interA
			grand = not grand
		
		ellC1 = ellC.GetClone()
		ellC1[c4d.ID_BASEOBJECT_REL_POSITION] = interA
		ellC2 = ellC.GetClone()
		ellC2[c4d.ID_BASEOBJECT_REL_POSITION] = interB
		
		ellC[c4d.ID_BASEOBJECT_REL_POSITION] = inter
		
		ret2 = utils.SendModelingCommand(command=c4d.MCOMMAND_MAKEEDITABLE, list=[ellC], doc=self.doc)
		
		neutre = c4d.BaseObject(c4d.Onull)
		ret2[0].InsertUnder(neutre)
		ret3 = utils.SendModelingCommand(command = c4d.MCOMMAND_JOIN,
                                list = [neutre],
                                doc = self.doc)
		
		self._ellAjPts(posA, ret3[0])
		self._ellAjPts(posB, ret3[0])
		
		return self._ellTangentes(ret3[0], posA, grand)
	
	def style(self, noeud) :
		_txt = noeud.childNodes
		css = {}
		for _txt_enf in _txt :
			if _txt_enf.nodeType == Node.TEXT_NODE or _txt_enf.nodeType == Node.CDATA_SECTION_NODE :
				chn = _txt_enf.nodeValue
				chn = chn.encode('utf-8', 'replace')
				chn = chn.replace('\n', ' ')
				chn = chn.replace('\t', ' ')
				chn = chn.replace('!important', '')
				chn = " ".join(chn.split())
				chn_tab = chn.split('}')
				for chn in chn_tab :
					if not chn : continue
					valvar = chn.split('{')
					style = {}
					valvar[1] = valvar[1].replace(' ', '')
					vars = valvar[1].split(';')
					for var in vars :
						if not var : continue
						styvar = var.split(':')
						style[styvar[0]] = styvar[1]
						
					classes = valvar[0].split(',')
					for classe in classes :
						if not classe : continue
						classe = classe.replace(' ', '')
						if classe in css : css[classe].update(style)
						else : css[classe] = style
				
				self.styleGlobal = css
		
		return None, None, None
	
	def couleur(self, coul) :
		if not coul or coul == "none" : return Vector(0.0)
		
		if coul.startswith('rgb') :
			coul = coul[4:-1]
			coul_t = coul.split(',')
			if len(coul_t) != 3 : return Vector()
			rvb = Vector()
			rvb.x = int(coul_t[0]) / 255.0
			rvb.y = int(coul_t[1]) / 255.0
			rvb.z = int(coul_t[2]) / 255.0
			return rvb
		
		if coul[0] != '#' :
			try : coul = COULEURS_CSS[coul.lower()]
			except KeyError : return Vector(1.0)
		
		coul = coul[1:]
		coul_l = len(coul)
		if coul_l != 3 and coul_l !=6 : return Vector(1.0)
		if coul_l == 3 : coul = coul[0]+coul[0]+coul[1]+coul[1]+coul[2]+coul[2]
		rvb = Vector()
		rvb.x = int(coul[0:2], 16) / 255.0
		rvb.y = int(coul[2:4], 16) / 255.0
		rvb.z = int(coul[4:6], 16) / 255.0
		return rvb
	
	def materiau(self, coul) :
		if not self.opt_mats : return None, False
		if not coul : coul = 'none'
		try : dejamat = self.dic_mat[coul]
		except KeyError :
			mat = c4d.BaseMaterial(c4d.Mmaterial)
			mat[c4d.ID_BASELIST_NAME] = coul
			mat[c4d.MATERIAL_USE_SPECULAR] = False
			mat[c4d.MATERIAL_COLOR_COLOR] = self.couleur(coul)
			self.dic_mat[coul] = mat
			return mat, True
		else : return dejamat, False
	
	def _creation(self, noeud, obj, genre="", objs_extrucon=None) :
		nom = self.rec_nom(noeud)
		style = self.recup_style(noeud)
		remplissage = style['fill']
		
		largeur = self.conv_unit(style['stroke-width'])
		trait = style['stroke']
		if not trait or trait == "none" : largeur = None
		if genre == "ligne" and not largeur : largeur = '1'
		if genre == "ligne" and not remplissage : remplissage = "none"
		
		obj[c4d.ID_BASELIST_NAME] = nom
		
		if genre == "texte" or genre == "span" :
			if not style['font-family'] : style['font-family'] = "Times New Roman"
			taille = self.conv_unit(style['font-size'], 16)
			fd = c4d.FontData()
			bc = c4d.BaseContainer()
			bc[500] = style['font-family']
			if style['font-weight'] == 'bold' : bc[502] = 700
			else : bc[502] = 400 # 400 : normal, 700 : gras
			if style['font-style'] == 'italic' : bc[503] = 255
			else : bc[503] = 0 # 0 : normal, 255 : italique
			# bc[2] = "Normal"
			bc[508] = style['font-family']
			fd.SetFont(bc)
			obj[c4d.PRIM_TEXT_FONT] = fd
			obj[c4d.PRIM_TEXT_HEIGHT] = taille
			if style['text-anchor'] == "middle" :
				obj[c4d.PRIM_TEXT_ALIGN] = c4d.PRIM_TEXT_ALIGN_MIDDLE
			elif style['text-anchor'] == "end" :
				obj[c4d.PRIM_TEXT_ALIGN] = c4d.PRIM_TEXT_ALIGN_RIGHT
		
		neutre = c4d.BaseObject(c4d.Onull)
		neutre[c4d.ID_BASELIST_NAME] = nom
		neutre.SetMl(self.rec_matrice(noeud, neutre))
		
		if not self.opt_formes :
			obj.InsertUnder(neutre)
			return [neutre], None, style
		
		if remplissage != "none" :
			mat, matnouv = self.materiau(remplissage)
			if not matnouv : ret_mat = None
			else : ret_mat = mat
			peau = self._peau(nom, mat)
			obj.InsertUnder(peau)
			
			if largeur :
				matl, matlnouv = self.materiau(style['stroke'])
				if not matlnouv : ret_matl = None
				else : ret_matl = matl
				if objs_extrucon :
					for obj_extrucon in objs_extrucon :
						obj_extrucon.Message(c4d.MSG_UPDATE)
						extrucon = self._extrucon(nom, float(largeur), obj_extrucon.GetClone(), matl)
						extrucon.InsertUnder(neutre)
				else :
					extrucon = self._extrucon(nom, float(largeur), obj.GetClone(), matl)
					extrucon.InsertUnder(neutre)
				peau.InsertUnder(neutre)
				return [neutre], (ret_mat, ret_matl), style
			
			peau.InsertUnder(neutre)
			return [neutre], [ret_mat], style
		
		if largeur :
			matl, matlnouv = self.materiau(style['stroke'])
			if not matlnouv : ret_matl = None
			else : ret_matl = matl
			if objs_extrucon :
				for obj_extrucon in objs_extrucon :
					obj_extrucon.Message(c4d.MSG_UPDATE)
					extrucon = self._extrucon(nom, float(largeur), obj_extrucon.GetClone(), matl)
					extrucon.InsertUnder(neutre)
			else :
				extrucon = self._extrucon(nom, float(largeur), obj, matl)
				extrucon.InsertUnder(neutre)
			return [neutre], [ret_matl], style
		
		obj.InsertUnder(neutre)
		return [neutre], None, style
	
	def instance(self, noeud) :
		obj = c4d.BaseObject(c4d.Oinstance)
		src = self.rec_val(noeud, "xlink:href", "str", "#")
		obj[c4d.ID_BASELIST_NAME] = self.rec_nom(noeud) + src
		obj.SetMl(self.rec_matrice(noeud, obj))
		return [obj], None, None
	
	def texte(self, noeud, genre="texte", parent=None) :
		neutre = c4d.BaseObject(c4d.Onull)
		neutre[c4d.ID_BASELIST_NAME] = self.rec_nom(noeud)
		obj = c4d.BaseObject(c4d.Osplinetext)
		if genre == "texte" :
			self.xParent = 0
			self.yParent = 0
		self.xParent = self.rec_val(noeud, "x", "float", self.xParent)
		self.yParent = self.rec_val(noeud, "y", "float", self.yParent)
		
		obj[c4d.ID_BASEOBJECT_REL_POSITION,c4d.VECTOR_X] = self.xParent
		obj[c4d.ID_BASEOBJECT_REL_POSITION,c4d.VECTOR_Y] = -self.yParent
		obj[c4d.PRIM_TEXT_ALIGN] = c4d.PRIM_TEXT_ALIGN_LEFT
		_txt = noeud.childNodes
		chn = ""
		if _txt and _txt[0].nodeType == Node.TEXT_NODE :
			chn = _txt[0].nodeValue
			chn = chn.encode('utf-8', 'replace')
			chn = chn.replace('\n', ' ')
			chn = " ".join(chn.split())
		obj[c4d.PRIM_TEXT_TEXT] = chn
		
		neutre_tab, mats, style = self._creation(noeud, obj, genre)
		self.xParent += neutre_tab[0].GetDown().GetDown().GetRad().x * 2.0
		return neutre_tab, mats, style
	
	def cercle(self, noeud) :
		obj = c4d.BaseObject(c4d.Osplinecircle)
		obj[c4d.ID_BASEOBJECT_REL_POSITION,c4d.VECTOR_X] = self.rec_val(noeud, "cx", "float", 0)
		obj[c4d.ID_BASEOBJECT_REL_POSITION,c4d.VECTOR_Y] = -self.rec_val(noeud, "cy", "float", 0)
		obj[c4d.PRIM_CIRCLE_RADIUS] = self.rec_val(noeud, "r", "float", 0)
		
		return self._creation(noeud, obj)
	
	def ellipse(self, noeud) :
		obj = c4d.BaseObject(c4d.Osplinecircle)
		obj[c4d.ID_BASEOBJECT_REL_POSITION,c4d.VECTOR_X] = self.rec_val(noeud, "cx", "float", 0)
		obj[c4d.ID_BASEOBJECT_REL_POSITION,c4d.VECTOR_Y] = -self.rec_val(noeud, "cy", "float", 0)
		obj[c4d.PRIM_CIRCLE_ELLIPSE] = True
		obj[c4d.PRIM_CIRCLE_RADIUS] = self.rec_val(noeud, "rx", "float", 0)
		obj[c4d.PRIM_CIRCLE_RADIUSY] = self.rec_val(noeud, "ry", "float", 0)
		
		return self._creation(noeud, obj)
	
	def rect(self, noeud) :
		obj = c4d.BaseObject(c4d.Osplinerectangle)
		obj_l = self.rec_val(noeud, "width", "float", 0)
		obj_h = self.rec_val(noeud, "height", "float", 0)
		obj[c4d.PRIM_RECTANGLE_WIDTH] = obj_l
		obj[c4d.PRIM_RECTANGLE_HEIGHT] = obj_h
		obj[c4d.ID_BASEOBJECT_REL_POSITION,c4d.VECTOR_X] = self.rec_val(noeud, "x", "float", 0) + obj_l * 0.5
		obj[c4d.ID_BASEOBJECT_REL_POSITION,c4d.VECTOR_Y] = -(self.rec_val(noeud, "y", "float", 0) + obj_h * 0.5)
		rx = self.rec_val(noeud, "rx", "float", 0)
		ry = self.rec_val(noeud, "ry", "float", 0)
		r = max(rx, ry)
		if r :
			obj[c4d.PRIM_RECTANGLE_ROUNDING] = True
			obj[c4d.PRIM_RECTANGLE_RADIUS] = r
		
		return self._creation(noeud, obj)
	
	def ligne(self, noeud) :
		obj = c4d.BaseObject(c4d.Ospline)
		p1 = Vector(0, 0, 0)
		p2 = Vector(0, 0, 0)
		atts = noeud.attributes.keys()
		for att in atts :
			if att == "x1" : p1.x = self.rec_val(noeud, "x1")
			if att == "y1" : p1.y = -self.rec_val(noeud, "y1")
			if att == "x2" : p2.x = self.rec_val(noeud, "x2")
			if att == "y2" : p2.y = -self.rec_val(noeud, "y2")
		obj.ResizeObject(2)
		obj.SetPoint(0, p1)
		obj.SetPoint(1, p2)
		obj.Message(c4d.MSG_UPDATE)
		
		return self._creation(noeud, obj, "ligne")
	
	def polygone(self, noeud, polyligne=False) :
		ds = self.rec_val(noeud, "points", "str")
		ds += " "
		ds = ds.replace("-", " -")
		ds = ds.replace("e -", "e-")
		ds_tab = []
		_nb = ""
		
		for d in ds : # Reformate la chaîne de caractères en tableaux
			if d.isdigit() or d == '.' or d == '-' or d == 'e' or d == '+' :
				_nb += d
			else :
				if _nb != '' : ds_tab.append(float(_nb))
				_nb = ""
		
		obj = c4d.BaseObject(c4d.Ospline)
		obj[c4d.SPLINEOBJECT_TYPE] = c4d.SPLINEOBJECT_TYPE_BEZIER
		ds_tab_l = int(round(len(ds_tab) * 0.5))
		points = []
		for i in xrange(ds_tab_l) :
			j = i * 2
			vec = Vector(ds_tab[j], -ds_tab[j+1], 0.0)
			points.append(vec)
		
		obj.ResizeObject(len(points))
		obj.SetAllPoints(points)
		obj.Message(c4d.MSG_UPDATE)
		if not polyligne : obj[c4d.SPLINEOBJECT_CLOSED] = True
		
		return self._creation(noeud, obj)
	
	def forme(self, noeud) :
		ds = self.rec_val(noeud, "d", "str")
		ds += " "
		ds = ds.replace("-", " -")
		ds = ds.replace("e -", "e-")
		li_d = ['M', 'L', 'H', 'V', 'C', 'S', 'Q', 'T', 'A', 'Z']
		li_n = [2, 2, 1, 1, 6, 4, 4, 2, 7, 0]
		ds_tab = []
		_nb = ""
		_tnb = []
		_ansi = ""
		
		for d in ds : # Reformate la chaîne de caractères en tableaux
			if d.isdigit() or d == '.' or d == '-' or d == 'e' or d == '+' :
				_nb += d
			else :
				if _nb : _tnb.append(float(_nb))
				if len(_tnb) == _ansi :
					if ds_tab[-1] != [] :
						ds_tab.append(_tnb)
					_tnb = []
				_nb = ""
				_d = d.upper()
				if _d in li_d :
					_ansi = li_n[li_d.index(_d)]
					ds_tab.append(d)
			
		_ansd = ""
		for i, d in enumerate(ds_tab) : # Ajoute les commandes implicites
			_i = i % 2
			if _i == 0 :
				if isinstance(d, str) :
					_ansd = d
					if _ansd == 'M' : _ansd = 'L'
					if _ansd == 'm' : _ansd = 'l'
				else : ds_tab.insert(i, _ansd)
				
		ds_tab_l = int(round(len(ds_tab) * 0.5))
		points = []
		tangentes = []
		segments = []
		pointseg = []
		_seg = 0
		pos = Vector()
		_pointM = Vector()
		_pointZ = None
		
		for i in xrange(ds_tab_l) :
			j = i * 2
			d = ds_tab[j]
			_d = d.upper()
			if _d != 'Z' : val = ds_tab[j+1]
			_rel = _d != d
			if _d == 'M' :
				pos = Vector(val[0], -val[1], 0.0)
				if _rel and points :
					if _pointZ : pos += _pointZ
					else : pos += points[-1]
				_pointZ = None
				_pointM = pos
				points.append(pos)
				tangentes.append([Vector(), Vector()])
				if _seg : segments.append({'cnt' : _seg, 'closed' : False})
				_seg = 0
				pointseg.append(_seg)
				_seg += 1
			elif _d == 'L' :
				pos = Vector(val[0], -val[1], 0.0)
				if _rel : pos += points[-1]
				points.append(pos)
				pointseg.append(_seg)
				tangentes.append([Vector(), Vector()])
				_seg += 1
			elif _d == 'H' :
				pos = Vector(val[0], pos.y, 0.0)
				if _rel : pos.x += points[-1].x
				points.append(pos)
				pointseg.append(_seg)
				tangentes.append([Vector(), Vector()])
				_seg += 1
			elif _d == 'V' :
				pos = Vector(pos.x, -val[0], 0.0)
				if _rel : pos.y += points[-1].y
				points.append(pos)
				pointseg.append(_seg)
				tangentes.append([Vector(), Vector()])
				_seg += 1
			elif _d == 'C' :
				_bez = 0.75
				pos = Vector(val[4], -val[5], 0.0)
				tanA = Vector(val[0], -val[1], 0.0)
				tanB = Vector(val[2], -val[3], 0.0)
				if _rel :
					pos += points[-1]
					tanA += points[-1]
					tanB += points[-1]
				tangentes[-1][1] = (tanA - points[-1])*_bez
				tangentes.append([(tanB - pos)*_bez, Vector()])
				points.append(pos)
				pointseg.append(_seg)
				_seg += 1
			elif _d == 'S' :
				_bez = 0.75
				pos = Vector(val[2], -val[3], 0.0)
				tanB = Vector(val[0], -val[1], 0.0)
				tanA = tangentes[-1][0]
				if _rel :
					pos += points[-1]
					tanB += points[-1]
				tangentes[-1][1] = -tanA
				tangentes.append([(tanB - pos)*_bez, Vector()])
				points.append(pos)
				pointseg.append(_seg)
				_seg += 1
			elif _d == 'Q' :
				_bez = 0.5
				pos = Vector(val[2], -val[3], 0.0)
				tanA = Vector(val[0], -val[1], 0.0)
				if _rel :
					pos += points[-1]
					tanA += points[-1]
				tangentes[-1][1] = (tanA - points[-1])*_bez
				tangentes.append([(tanA - pos)*_bez, Vector()])
				points.append(pos)
				pointseg.append(_seg)
				_seg += 1
			elif _d == 'T' :
				_bez = 0.5
				pos = Vector(val[0], -val[1], 0.0)
				tanA = tangentes[-1][0]
				tanB = (-tanA / _bez) + points[-1]
				if _rel :
					pos += points[-1]
				tangentes[-1][1] = -tanA
				tangentes.append([(tanB - pos)*_bez, Vector()])
				points.append(pos)
				pointseg.append(_seg)
				_seg += 1
			elif _d == 'A' :
				
				pos = Vector(val[5], -val[6], 0.0)
				if _rel :
					pos += points[-1]
				
				__points, __tangentes = self._interEllipses(points[-1], pos, val[0], val[1], val[2], int(val[3]), int(val[4]))
				__imax = len(__points) - 1
				for __i, __tan in enumerate(__tangentes) :
					if __i == 0 :
						tangentes[-1][1] = __tan[1]
					elif __i == __imax :
						tangentes.append([__tan[0], Vector()])
						points.append(pos)
						pointseg.append(_seg)
						_seg += 1
					else :
						tangentes.append(__tan)
						points.append(__points[__i])
						pointseg.append(_seg)
						_seg += 1
			
			elif _d == 'Z' :
					
				_pointZ = _pointM
				
				if _seg : segments.append({'cnt' : _seg, 'closed' : True})
				_seg = 0
			
			if i == ds_tab_l - 1 :
				if _seg : segments.append({'cnt' : _seg, 'closed' : False})
		
		# Segments en un objet
		obj = c4d.BaseObject(c4d.Ospline)
		obj[c4d.SPLINEOBJECT_TYPE] = c4d.SPLINEOBJECT_TYPE_BEZIER
		
		if points :
			obj.ResizeObject(len(points))
			obj.SetAllPoints(points)
			for i in xrange(len(points)) :
				obj.SetTangent(i, tangentes[i][0], tangentes[i][1])
			obj.Message(c4d.MSG_UPDATE)
		
		fermela = False
		if segments :
			pSeg = obj.MakeVariableTag(c4d.Tsegment, len(segments))
			#pSeg.SetAllHighlevelData(segments)
			for i, seg in enumerate(segments) :
				obj.SetSegment(i, seg['cnt'], seg['closed'])
				if seg['closed'] : fermela = True
			obj.Message(c4d.MSG_UPDATE)
		
		if fermela : obj[c4d.SPLINEOBJECT_CLOSED] = True
		
		if segments and len(segments) > 1 :
			# Un extrucon par segment
			objets_seg = []
			nb_objets = 0
			for i in xrange(len(points)) :
				_ptseg = pointseg[i]
				if _ptseg == 0 :
					_obj = c4d.BaseObject(c4d.Ospline)
					_obj[c4d.SPLINEOBJECT_TYPE] = c4d.SPLINEOBJECT_TYPE_BEZIER
					_obj.ResizeObject(segments[nb_objets]['cnt'])
					if segments[nb_objets]['closed'] : _obj[c4d.SPLINEOBJECT_CLOSED] = True
					objets_seg.append(_obj)
					nb_objets += 1
				objets_seg[nb_objets - 1].SetPoint(_ptseg, points[i])
				objets_seg[nb_objets - 1].SetTangent(_ptseg, tangentes[i][0], tangentes[i][1])
			
			return self._creation(noeud, obj, "", objets_seg)
		
		return self._creation(noeud, obj)
	
	def aj(self, objets, parent, noeud) :
		if not objets : return
		if parent : parent = parent[0]
		noeudNom = noeud.nodeName
		objet = None
		if len(objets) > 1 :
			objet = c4d.BaseObject(c4d.Onull)
			objet.SetName(objets[0].GetName())
			for _z, obj in enumerate(objets) :
				obj[c4d.ID_BASEOBJECT_REL_POSITION,c4d.VECTOR_Z] += _z * -self.opt_decz * 0.1
				obj.InsertUnder(objet)
				
		else : objet = objets[0]
		
		if objet :
			
			self.doc.InsertObject(objet, parent)
			self.doc.AddUndo(c4d.UNDOTYPE_NEW, objet)
			# if not objet.CheckType(c4d.Onull) :
			pos = objet.GetAbsPos()
			if noeudNom != "g" and noeudNom != "clipPath" and noeudNom != "defs" :
				pos.z += self.obj_n * -self.opt_decz
			objet.SetAbsPos(pos)
			self.obj_n += 1
			
			obj_nom = objet.GetName()
			cib = None
			est_inst = objet.CheckType(c4d.Oinstance)
			if obj_nom and obj_nom[0] == "#" :
				noms = obj_nom.split('#')
				nom = '#' + noms[1]
				cib =  '#' + noms[-1]
				self.dic_ids[nom] = (self.obj_i, est_inst)
			if est_inst :
				if cib :
					try : src, src_est_inst = self.dic_ids[cib]
					except KeyError : self.inst_complet.append(self.obj_i)
					else :
						if src_est_inst :
							pos = self.inst_complet.index(src)
							self.inst_complet.insert(pos, self.obj_i)
						else :
							self.inst_complet.append(self.obj_i)
				else :
					self.inst_complet.append(self.obj_i)
			
			self.obj_complet.append(objet)
			self.obj_i += 1
	
	def ajMat(self, mats) :
		if not mats : return
		for mat in mats :
			if not mat : continue
			self.doc.InsertMaterial(mat)
			self.doc.AddUndo(c4d.UNDOTYPE_NEW, mat)
	
	def _traiteinstances(self) :
		self.inst_complet.reverse()
		for inst_i in self.inst_complet :
			inst = self.obj_complet[inst_i]
			tab = inst[c4d.ID_BASELIST_NAME].split('#')
			obj_ii, obj_ii_est_inst = self.dic_ids['#' + tab[-1]]
			obj = self.obj_complet[obj_ii]
			inst[c4d.INSTANCEOBJECT_LINK] = obj
			instMl = inst.GetMl()
			instMl2 = instMl * obj.GetMl()
			pos2 = instMl2.off
			pos2.z = instMl.off.z
			instMl2.off = pos2
			inst.SetMl(instMl2)
	
	def decomposer(self, noeud, parent, style=None) :
		# if noeud.childNodes : noeud.childNodes.reverse()
		for n in noeud.childNodes :
			self.trier(n, parent, style)
	
	def trier(self, noeud, parent=None, style=None) :
		if noeud.nodeType != Node.TEXT_NODE :
			objmatsty, enf = self.creer(noeud, style, parent)
			obj = objmatsty[0]
			mat = objmatsty[1]
			sty = objmatsty[2]
			self.aj(obj, parent, noeud)
			self.ajMat(mat)
			if enf is True : self.decomposer(noeud, obj, sty)
	
	def lire(self) :
		svg = self.fichier.getElementsByTagName("svg")
		svg = svg[0]
		
		self.trier(svg)
		
		self._traiteinstances()
		
	#--
	
	def Init(self, node) :
		donnees = node.GetDataInstance()
		donnees.SetReal(VONC_SVG_IMPORT_DECZ, self.opt_decz)
		donnees.SetBool(VONC_SVG_IMPORT_COUPECONST, self.opt_coupeconst)
		donnees.SetBool(VONC_SVG_IMPORT_FORMES, self.opt_formes)
		donnees.SetBool(VONC_SVG_IMPORT_MATS, self.opt_mats)
		
		return True
	
	def Identify(self, node, name, probe, size) :
		nom = name.lower()
		if not nom.endswith('.svg') : return False
		
		# tampon = probe[0:5]
		# entete = st.unpack('<5s', tampon)[0]
		# if entete != '<?xml' and entete != '<svg ' : return False
		
		return True
	
	def Load(self, node, name, doc, filterflags, error, bt) :
		if not name : return c4d.FILEERROR_OPEN
		chemin = name.decode('UTF-8', 'strict')
		if not chemin : return c4d.FILEERROR_OPEN
		
		donnees = node.GetDataInstance()
		self.opt_decz = donnees.GetReal(VONC_SVG_IMPORT_DECZ)
		self.opt_coupeconst = donnees.GetBool(VONC_SVG_IMPORT_COUPECONST)
		self.opt_formes = donnees.GetBool(VONC_SVG_IMPORT_FORMES)
		self.opt_mats = donnees.GetBool(VONC_SVG_IMPORT_MATS)
		
		self.fichier = None
		self.doc = None
		self.obj_n = 0
		self.obj_i = 0
		self.dic_ids = {}
		self.dic_mat = {}
		self.obj_complet = []
		self.inst_complet = []
		self.styleParent = None
		self.styleGlobal = None
		self.xParent = 0
		self.yParent = 0
		
		nomext = os.path.basename(chemin)
		nom = os.path.splitext(nomext)[0]
		
		try:
			self.fichier = xml.dom.minidom.parse(chemin)
		except IOError :
			print "Fichier introuvable"
			return c4d.FILEERROR_OPEN
		
		doc.StartUndo()
		self.doc = doc
		self.lire()
		doc.EndUndo()
		
		c4d.EventAdd()
		
		self.fichier = None
		self.doc = None
		self.obj_n = 0
		self.obj_i = 0
		self.dic_ids = {}
		self.dic_mat = {}
		self.obj_complet = []
		self.inst_complet = []
		self.styleParent = None
		self.styleGlobal = None
		self.xParent = 0
		self.yParent = 0
		
		return c4d.FILEERROR_NONE
		
if __name__=='__main__':
	plugins.RegisterSceneLoaderPlugin(id=MODULE_ID, 
									str=plugins.GeLoadString(IDS_VONC_SVG_IMPORT), 
									g=ImporteurSVG, 
									info=0, 
									description="vonc_svg_import")