Code Vonc

Sélections Supplétives

v 1.8

R13+ OSX Win

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

v 1.8 : (29 septembre 2013)
- Ajout de la sélection par miroir.

v 1.7 :
- Ajout de la sélection aléatoire.
- Les boîtes de dialogues sont désormais asynchrones.
- Plus d'options pour la sélection par orientation.
- Traduction anglaise par Lubo Bezek.
- Traduction tchèque par Pavel Zoch.
- Correction de divers bogues.

v 1.5 :
- La sélection alternative affecte désormais les points.
- Ajout de la sélection des éléments adjacents.
- Ajout de la sélection de position.
- Ajout de la description des outils.


Lot de sélections en tout genre.

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




Sélectionner les polygones de même orientation

Sélectionne les polygones ayant la même orientation que le polygone sélectionné.


Sélectionner les éléments alternativement

Sélectionne les polygones ou les points à intervalle régulier à partir de la sélection active.
Sélectionner un polygone sur 2, 1 sur 3, 2 sur 4...


Sélectionner les polygones de même taille

Sélectionne tous les polygones ayant plus ou moins le même périmètre que le polygone sélectionné.


Sélectionner les triangles

Sélectionne tous les triangles de l'objet actif.


Sélectionner les quadrangles

Sélectionne tous les quadrangles de l'objet actif.


Sélectionner les n-gones

Sélectionne tous les n-gones de l'objet actif.


Sélectionner jusqu'à l'indice

Sélectionne tous les polygones ou tous les points d'indice inférieur au polygone/point sélectionné d'un objet ou d'une cerce (spline).


Sélectionner les contours

Sélectionne tous les contours de l'objet actif.


Sélectionner les éléments adjacents

Sélectionne les polygones ou les points adjacents à la sélection active.


Sélectionner jusqu'à la position

Sélectionne les points ou les polygones ayant une position supérieure ou inférieure à un point donné.


Sélection aléatoire

Sélectionne les points ou les polygones de façon aléatoire. Un facteur chance permet de sélectionner plus ou moins d'éléments. Il est également possible de sélectionner un nombre précis d'éléments.

Sélection par miroir

Sélectionne les points, arêtes ou polygones opposés par rapport à l'axe de l'objet.



Codes sourcesSources code

res/c4d_symbols.h

enum
{
	SS_SS_VAL			= 101,
	SS_SS_FER			= 102,
	
	SS_SELDIR_NOM		= 1001,
    SS_SELDIR_TOL		= 1002,
	SS_SELDIR_LIM		= 1003,
	SS_SELDIR_AID		= 1004,
	SS_SELDIR_NOR		= 1005,
	
	SS_SELNSN_NOM		= 1101,
	SS_SELNSN_SEL		= 1102,
	SS_SELNSN_SUR		= 1103,
	SS_SELNSN_DEC		= 1104,
	SS_SELNSN_AID		= 1105,
	
	SS_SELTAIL_NOM		= 1201,
	SS_SELTAIL_TOL		= 1202,
	SS_SELTAIL_INF		= 1203,
	SS_SELTAIL_SUP		= 1204,
	SS_SELTAIL_AID		= 1205,
	
	SS_SELTRI_NOM		= 1301,
	SS_SELTRI_AID		= 1302,
	
	SS_SELQUAD_NOM		= 1401,
	SS_SELQUAD_AID		= 1402,
	
	SS_SELNGON_NOM		= 1501,
	SS_SELNGON_AID		= 1502,
	
	SS_SELCON_NOM		= 1601,
	SS_SELCON_AID		= 1602,
	
	SS_SELIND_NOM		= 1701,
	SS_SELIND_AID		= 1702,
	
	SS_SELADJ_NOM		= 1801,
	SS_SELADJ_AID		= 1802,
	
	SS_SELPOS_NOM		= 1901,
	SS_SELPOS_TOL		= 1902,
	SS_SELPOS_AID		= 1903,
	
	SS_SELPIF_NOM		= 2001,
	SS_SELPIF_AID		= 2002,
	SS_SELPIF_SRC		= 2003,
	SS_SELPIF_QTE		= 2004,
	SS_SELPIF_CHC		= 2005,
	
	SS_SELMIR_NOM		= 2101,
	SS_SELMIR_AID		= 2102,
	SS_SELMIR_TOL		= 2103,
	SS_SELMIR_AJS		= 2104,
	
	_DUMMY_ELEMENT_
}

res/strings_cz/c4d_strings.str

STRINGTABLE 
{
  SS_SS_VAL       "Pou\u017E\u00EDt";
  SS_SS_FER       "Zav\u0159\u00EDt";
  SS_SELDIR_NOM   "V\u00FDb\u011Br podle sm\u011Bru norm\u00E1ly polygonu";
  SS_SELDIR_TOL   "Tolerance :";
  SS_SELDIR_LIM   "Pouze spojen\u00E9 s v\u00FDb\u011Brem";
  SS_SELDIR_NOR   "Definice norm\u00E1ly";
  SS_SELDIR_AID   "Vybran\u00E9 budou polygony se stejn\u00FDm sm\u011Brem norm\u00E1l.";
  SS_SELNSN_NOM   "St\u0159\u00EDdav\u00FD v\u00FDb\u011Br bod\u016F/polygon\u016F";
  SS_SELNSN_SEL   "V\u00FDb\u011Br :";
  SS_SELNSN_SUR   "+ Mezera :";
  SS_SELNSN_DEC   "Posun :";
  SS_SELNSN_AID   "Vybere body nebo polygony v nastaven\u00FDch vzd\u00E1lenostech od aktu\u00E1ln\u00EDho v\u00FDb\u011Bru.";
  SS_SELTAIL_NOM  "V\u00FDb\u011Br podle velikosti polygonu";
  SS_SELTAIL_TOL  "Tolerance :";
  SS_SELTAIL_INF  "V\u010Detn\u011B men\u0161\u00EDch rozm\u011Br\u016F";
  SS_SELTAIL_SUP  "V\u010Detn\u011B v\u011Bt\u0161\u00EDch rozm\u011Br\u016F";
  SS_SELTAIL_AID  "Vybere v\u0161echny polygony v\u00EDcem\u00E9n\u011B shodn\u00E9 velikosti podle nastaven\u00E9 tolerance vybran\u00E9ho polygonu.";
  SS_SELTRI_NOM   "V\u00FDb\u011Br troj\u00FAheln\u00EDkov\u00FDch polygon\u016F";
  SS_SELTRI_AID   "Vybere v\u0161echny troj\u00FAheln\u00EDkov\u00E9 polygony aktivn\u00EDho objektu.";
  SS_SELQUAD_NOM  "V\u00FDb\u011Br \u010Dty\u0159\u00FAheln\u00EDkov\u00FDch polygon\u016F";
  SS_SELQUAD_AID  "Vybere v\u0161echny \u010Dty\u0159\u00FAheln\u00EDkov\u00E9 polygony aktivn\u00EDho objektu.";
  SS_SELNGON_NOM  "V\u00FDb\u011Br n-\u00FAheln\u00EDkov\u00FDch polygon\u016F";
  SS_SELNGON_AID  "Vybere v\u0161echny n-\u00FAheln\u00EDkov\u00E9 polygony aktivn\u00EDho objektu.";
  SS_SELCON_NOM   "V\u00FDb\u011Br obrysu";
  SS_SELCON_AID   "Vybere obrys aktivn\u00EDho objektu";
  SS_SELIND_NOM   "V\u00FDb\u011Br od za\u010D\u00E1tku po vybran\u00E9";
  SS_SELIND_AID   "Vybere v\u0161echny body/polygony od po\u010D\u00E1tku (index 0) a\u017E po vybran\u00FD bod/polygon objektu/k\u0159ivky";
  SS_SELADJ_NOM   "Zv\u011Bt\u0161it v\u00FDb\u011Br";
  SS_SELADJ_AID   "Zv\u011Bt\u0161\u00ED v\u00FDb\u011Br polygon\u016F \u010Di bod\u016F k aktivn\u00EDmu v\u00FDb\u011Bru.";
  SS_SELPOS_NOM   "V\u00FDb\u011Br z\u00E1visl\u00FD na pozici";
  SS_SELPOS_TOL   "Tolerance :";
  SS_SELPOS_AID   "Vybere body a nebo polygony s ni\u017E\u0161\u00ED a nebo vy\u0161\u0161\u00ED poz\u00EDc\u00ED, ne\u017E m\u00E1 vybran\u00FD element.";
  SS_SELPIF_NOM   "N\u00E1hodn\u00FD v\u00FDb\u011Br";
  SS_SELPIF_AID   "N\u00E1hodn\u011B vybere polygony nebo body aktivn\u00EDho objektu.";
  SS_SELPIF_SRC   "Po\u010D\u00E1tek n\u00E1h. :";
  SS_SELPIF_QTE   "Po\u010Det :";
  SS_SELPIF_CHC   "\u0160ance :";
  SS_SELMIR_NOM   "Zrcadlov\u00FD v\u00FDb\u011Br";
  SS_SELMIR_AID   "Vybere body,hrany nebo polygony na prot\u011Bj\u0161\u00ED ose.";
  SS_SELMIR_TOL   "Tolerance :";
  SS_SELMIR_AJS   "P\u0159idat k v\u00FDb\u011Bru";
}

res/strings_fr/c4d_strings.str

STRINGTABLE
{
	SS_SS_VAL			"Appliquer";
	SS_SS_FER			"Fermer";
	
	SS_SELDIR_NOM		"S\u00E9lectionner les polys de m\u00EAme orientation";
	SS_SELDIR_TOL		"Tol\u00E9rance :";
	SS_SELDIR_LIM		"Limiter aux \u00E9l\u00E9ments connect\u00E9s";
	SS_SELDIR_NOR		"D\u00E9finir la normale";
	SS_SELDIR_AID		"S\u00E9lectionne les polygones ayant la m\u00EAme normale que le polygone s\u00E9lectionn\u00E9.";
	
	SS_SELNSN_NOM		"S\u00E9lectionner les \u00E9l\u00E9ments alternativement";
	SS_SELNSN_SEL		"S\u00E9lectionner :";
	SS_SELNSN_SUR		"Sur :";
	SS_SELNSN_DEC		"D\u00E9calage :";
	SS_SELNSN_AID		"S\u00E9lectionne les polygones ou les points \u00E0 intervalle r\u00E9gulier \u00E0 partir de la s\u00E9lection active.";
	
	SS_SELTAIL_NOM		"S\u00E9lectionner les polys de m\u00EAme taille";
	SS_SELTAIL_TOL		"Tol\u00E9rance :";
	SS_SELTAIL_INF		"Inclure les tailles inf\u00E9rieures";
	SS_SELTAIL_SUP		"Inclure les tailles sup\u00E9rieures";
	SS_SELTAIL_AID		"S\u00E9lectionne tous les polygones ayant plus ou moins le m\u00EAme p\u00E9rim\u00E8tre que le polygone s\u00E9lectionn\u00E9.";
	
	SS_SELTRI_NOM		"S\u00E9lectionner les triangles";
	SS_SELTRI_AID		"S\u00E9lectionne tous les triangles de l'objet actif.";
	
	SS_SELQUAD_NOM		"S\u00E9lectionner les quadrangles";
	SS_SELQUAD_AID		"S\u00E9lectionne tous les quadrangles de l'objet actif.";
	
	SS_SELNGON_NOM		"S\u00E9lectionner les n-gones";
	SS_SELNGON_AID		"S\u00E9lectionne tous les n-gones de l'objet actif.";
	
	SS_SELCON_NOM		"S\u00E9lectionner les contours";
	SS_SELCON_AID		"S\u00E9lectionne tous les contours de l'objet actif.";
	
	SS_SELIND_NOM		"S\u00E9lectionner jusqu'\u00E0 l'indice";
	SS_SELIND_AID		"S\u00E9lectionne tous les polygones ou tous les points d'indice inf\u00E9rieur au polygone/point s\u00E9lectionn\u00E9 d'un objet ou d'une cerce (spline).";
	
	SS_SELADJ_NOM		"S\u00E9lectionner les \u00E9l\u00E9ments adjacents";
	SS_SELADJ_AID		"S\u00E9lectionne les polygones ou les points adjacents \u00E0 la s\u00E9lection active.";
	
	SS_SELPOS_NOM		"S\u00E9lectionner jusqu'\u00E0 la position";
	SS_SELPOS_TOL		"Tol\u00E9rance :";
	SS_SELPOS_AID		"S\u00E9lectionne les points ou les polygones ayant une position sup\u00E9rieure ou inf\u00E9rieure \u00E0 un point donn\u00E9.";
	
	SS_SELPIF_NOM		"S\u00E9lectionner les \u00E9l\u00E9ments al\u00E9atoirement";
	SS_SELPIF_AID		"S\u00E9lectionne des polygones ou des points de fa\u00E7on al\u00E9atoire.";
	SS_SELPIF_SRC		"Source :";
	SS_SELPIF_QTE		"Quantit\u00E9 :";
	SS_SELPIF_CHC		"Chances :";
	
	SS_SELMIR_NOM		"S\u00E9lectionner les \u00E9l\u00E9ments par miroir";
	SS_SELMIR_AID		"S\u00E9lectionne les points, ar\u00EAtes ou polygones oppos\u00E9s par rapport l'axe.";
	SS_SELMIR_TOL		"Tol\u00E9rance :";
	SS_SELMIR_AJS		"Ajouter \u00E0 la s\u00E9lection";
}

res/strings_us/c4d_strings.str

STRINGTABLE 
{
  SS_SS_VAL       "Apply";
  SS_SS_FER       "Close";
  SS_SELDIR_NOM   "Select by polygon normal direction";
  SS_SELDIR_TOL   "Tolerance :";
  SS_SELDIR_LIM   "Limited to connected elements";
  SS_SELDIR_NOR   "Define normal";
  SS_SELDIR_AID   "Polygons with same normal direction will be selected.";
  SS_SELNSN_NOM   "Select points/polygons alternately";
  SS_SELNSN_SEL   "Selected :";
  SS_SELNSN_SUR   "+Gap :";
  SS_SELNSN_DEC   "Offset :";
  SS_SELNSN_AID   "Selects polygons or points at regular intervals from the current selection.";
  SS_SELTAIL_NOM  "Select by polygon size";
  SS_SELTAIL_TOL  "Tolerance :";
  SS_SELTAIL_INF  "Include smaller sizes";
  SS_SELTAIL_SUP  "Include larger sizes";
  SS_SELTAIL_AID  "Selects all polygons with more or less the same area as the selected polygon.";
  SS_SELTRI_NOM   "Select triangles";
  SS_SELTRI_AID   "Selects all triangles of the active object.";
  SS_SELQUAD_NOM  "Select quadrangles";
  SS_SELQUAD_AID  "Selects all quadrangles of the active object.";
  SS_SELNGON_NOM  "Select n-gons";
  SS_SELNGON_AID  "Selects all n-gons of the active object.";
  SS_SELCON_NOM   "Select the contour";
  SS_SELCON_AID   "Selects contour edges of the active object.";
  SS_SELIND_NOM   "Select from first to selected";
  SS_SELIND_AID   "Selects all points/polygons from first to selected point/polygon of active  polygon object or spline.";
  SS_SELADJ_NOM   "Grow selection";
  SS_SELADJ_AID   "Selects polygons or points adjacent to the active selection.";
  SS_SELPOS_NOM   "Select based on position";
  SS_SELPOS_TOL   "Tolerance :";
  SS_SELPOS_AID   "Selects points or polygons with a higher or lower position at a given point.";
  SS_SELPIF_NOM   "Random selection";
  SS_SELPIF_AID   "Selects polygons or points randomly.";
  SS_SELPIF_SRC   "Seed :";
  SS_SELPIF_QTE   "Quantity :";
  SS_SELPIF_CHC   "Chance :";
  SS_SELMIR_NOM   "Mirror selection";
  SS_SELMIR_AID   "Selects points, edges or polygons opposit to the axis.";
  SS_SELMIR_TOL   "Tolerance :";
  SS_SELMIR_AJS	  "Add to the selection";
}

vonc_selsup.pyp

import os
import c4d
import math
import random
from c4d import plugins, bitmaps, gui, documents, Vector
from c4d.utils import GetAngle, Neighbor, VectorEqual, SendModelingCommand
from c4d.plugins import GeLoadString as txt
from math import isnan

doc = c4d.documents.GetActiveDocument()
MODULE_ID = 1028615
SEPARATEUR_ID = 1028614
ID_SELTRI = 1028616
ID_SELQUAD = 1028617
ID_SELNGON = 1028618
ID_SELDIR = 1028625
ID_SELNSN = 1028626
ID_SELCON = 1028627
ID_SELIND = 1028628
ID_SELTAIL = 1028644
ID_SELADJ = 1029578
ID_SELPOS = 1029579
ID_SELPIF = 1030552
ID_SELMIR = 1031153

SS_SS_VAL = 101
SS_SS_FER = 102
SS_SELDIR_NOM = 1001
SS_SELDIR_TOL = 1002
SS_SELDIR_LIM = 1003
SS_SELDIR_AID = 1004
SS_SELDIR_NOR = 1005
SS_SELNSN_NOM = 1101
SS_SELNSN_SEL = 1102
SS_SELNSN_SUR = 1103
SS_SELNSN_DEC = 1104
SS_SELNSN_AID = 1105
SS_SELTAIL_NOM = 1201
SS_SELTAIL_TOL = 1202
SS_SELTAIL_INF = 1203
SS_SELTAIL_SUP = 1204
SS_SELTAIL_AID = 1205
SS_SELTRI_NOM = 1301
SS_SELTRI_AID = 1302
SS_SELQUAD_NOM = 1401
SS_SELQUAD_AID = 1402
SS_SELNGON_NOM = 1501
SS_SELNGON_AID = 1502
SS_SELCON_NOM = 1601
SS_SELCON_AID = 1602
SS_SELIND_NOM = 1701
SS_SELIND_AID = 1702
SS_SELADJ_NOM = 1801
SS_SELADJ_AID = 1802
SS_SELPOS_NOM = 1901
SS_SELPOS_TOL = 1902
SS_SELPOS_AID = 1903
SS_SELPIF_NOM = 2001
SS_SELPIF_AID = 2002
SS_SELPIF_SRC = 2003
SS_SELPIF_QTE = 2004
SS_SELPIF_CHC = 2005
SS_SELMIR_NOM = 2101
SS_SELMIR_AID = 2102
SS_SELMIR_TOL = 2103
SS_SELMIR_AJS = 2104
	

class Seldir_Dialogue(gui.GeDialog) :
	tolerance = 0.17453
	limite = False
	norbool = False
	normale = Vector()
	
	def CreateLayout(self) :
		self.GroupBegin(100, c4d.BFH_SCALEFIT, 1, 1)
		self.GroupBorderSpace(5, 5, 5, 5)
		
		self.GroupBegin(101, c4d.BFH_SCALEFIT, 2, 1)
		self.AddStaticText(20, c4d.BFH_FIT, 0, 0, txt(SS_SELDIR_TOL))
		self.AddEditSlider(11, c4d.BFH_SCALEFIT)
		self.GroupEnd()
		
		self.GroupBegin(102, c4d.BFH_SCALEFIT, 1, 1)
		self.AddCheckbox(12, c4d.BFH_SCALEFIT, 0, 0, txt(SS_SELDIR_LIM))
		self.AddCheckbox(13, c4d.BFH_SCALEFIT, 0, 0, txt(SS_SELDIR_NOR))
		self.GroupEnd()
		
		self.GroupBegin(104, c4d.BFH_SCALEFIT, 3, 1)
		self.AddEditNumberArrows(130, c4d.BFH_SCALEFIT)
		self.AddEditNumberArrows(131, c4d.BFH_SCALEFIT)
		self.AddEditNumberArrows(132, c4d.BFH_SCALEFIT)
		self.GroupEnd()
		
		self.GroupBegin(103, c4d.BFH_SCALEFIT, 2, 1)
		self.AddButton(1, c4d.BFH_SCALEFIT, initw = 70, inith = 15, name = txt(SS_SS_VAL))
		self.AddButton(2, c4d.BFH_SCALEFIT, initw = 70, inith = 15, name = txt(SS_SS_FER))
		self.GroupEnd()
		
		self.GroupEnd()
		return True
	
	def InitValues(self) :
		self.SetTitle(txt(SS_SELDIR_NOM))
		self.SetDegree(11, self.tolerance, 0, 360)
		self.SetReal(130, 0.0, step=1.0)
		self.SetReal(131, 0.0, step=1.0)
		self.SetReal(132, 0.0, step=1.0)
		self.Enable(130, False)
		self.Enable(131, False)
		self.Enable(132, False)
		return True
	
	def Command(self, id, msg) :
		if id == 13 :
			nor = self.GetBool(13)
			self.Enable(130, nor)
			self.Enable(131, nor)
			self.Enable(132, nor)
			
		if id == c4d.DLG_OK :
			self.tolerance = self.GetReal(11)
			self.limite = self.GetBool(12)
			self.norbool = self.GetBool(13)
			self.normale = self.GetVector(130, 131, 132)
			
			doc = documents.GetActiveDocument()
			obj = doc.GetActiveObject()
			self.sel_dir(doc, obj)
		elif id == c4d.DLG_CANCEL :
			self.Close()
		return True
	
	
	def recup_norm(self, index, obj) :
		poly = obj.GetPolygon(index)
		pA = obj.GetPoint(poly.a)
		pB = obj.GetPoint(poly.b)
		pC = obj.GetPoint(poly.c)
		pD = obj.GetPoint(poly.d)
		normale = (pA - pC).Cross(pB - pD)
		normale.Normalize()
		return normale
	
	def verif(self, va, vb, tol) :
		angle = GetAngle(va, vb)
		if isnan(angle) :
			if VectorEqual(va, -vb) : return False
			return True
		if tol >= angle : return True
		else : return False
	
	def sel_dir(self, doc, obj) :
		if not obj : return
		if obj.GetType() != c4d.Opolygon : return
		if doc.GetMode() != c4d.Mpolygons : return
		
		bs = obj.GetPolygonS()
		nbsel = bs.GetCount()
		if nbsel == 0 and not self.norbool : return 
		
		# dial = Seldir_Dialogue()
		# dial.Open(c4d.DLG_TYPE_MODAL)
		# if dial.annuler : return
		
		nbpol = obj.GetPolygonCount()
		normale_ref = Vector(0, 0, 0)
		
		doc.StartUndo()
		doc.AddUndo(c4d.UNDOTYPE_CHANGE_SELECTION, obj)
		
		premsel = 0
		for index, selec in enumerate(bs.GetAll(nbpol)) :
			if not selec: continue
			normale = self.recup_norm(index, obj)
			normale_ref += normale
			premsel = index
		
		if self.norbool : normale_ref = self.normale
		
		normale_ref.Normalize()
		tolerance = self.tolerance
		limite = self.limite
		
		for i in xrange(nbpol) :
			normale = self.recup_norm(i, obj)
			if self.verif(normale_ref, normale, tolerance) :
				bs.Select(i)
		
		if limite and nbsel :
			commande = c4d.ID_MODELING_FILL_SELECTION_TOOL
			mode = c4d.MODELINGCOMMANDMODE_POLYGONSELECTION
			params = c4d.BaseContainer()
			# for i in xrange(2160) :
				# params[i] = 167
			params[2157] = premsel #167
			SendModelingCommand(command=commande, list=[obj], mode=mode, bc=params, doc=doc, flags=c4d.MODELINGCOMMANDFLAGS_0)
		
		doc.EndUndo()
		c4d.EventAdd()
		c4d.CallCommand(12187) # Polygones
	
	
class Seldir(plugins.CommandData) :
	dialog = None
	
	def Execute(self, doc) :
		if self.dialog is None:
			self.dialog = Seldir_Dialogue()
		return self.dialog.Open(dlgtype=c4d.DLG_TYPE_ASYNC, pluginid=ID_SELDIR, defaulth=100, defaultw=70)

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

class Selnsn_Dialogue(gui.GeDialog) :
	a = 1
	b = 2
	dec = 0
	
	def CreateLayout(self) :
		self.GroupBegin(10, c4d.BFH_SCALEFIT, 2, 3)
		self.GroupBorderSpace(5, 5, 5, 5)
		self.AddStaticText(20, c4d.BFH_SCALEFIT, 0, 0, txt(SS_SELNSN_SEL))
		self.AddEditNumberArrows(30, c4d.BFH_SCALEFIT)
		self.AddStaticText(21, c4d.BFH_SCALEFIT, 0, 0, txt(SS_SELNSN_SUR))
		self.AddEditNumberArrows(31, c4d.BFH_SCALEFIT)
		self.AddStaticText(22, c4d.BFH_SCALEFIT, 0, 0, txt(SS_SELNSN_DEC))
		self.AddEditNumberArrows(32, c4d.BFH_SCALEFIT)
		self.AddButton(1, c4d.BFH_SCALEFIT, initw = 70, inith = 15, name = txt(SS_SS_VAL))
		self.AddButton(2, c4d.BFH_SCALEFIT, initw = 70, inith = 15, name = txt(SS_SS_FER))
		self.GroupEnd()
		return True
	
	def InitValues(self) :
		self.SetTitle(txt(SS_SELNSN_NOM))
		self.SetLong(30, 1, 1)
		self.SetLong(31, 2, 1)
		return True
	
	def Command(self, id, msg) :
		if id == 1 :
			self.a = self.GetLong(30)
			self.b = self.GetLong(31)
			self.dec = self.GetLong(32)
			doc = documents.GetActiveDocument()
			obj = doc.GetActiveObject()
			self.sel_nsn(doc, obj)
		if id == 2 :
			self.Close()
		return True
	
	def verif(self, p, li, bs) :
		if not bs.IsSelected(p) : return False
		if li.IsSelected(p) : return False
		return True
	
	def point_voisin(self, pp, li, bs, n, obj) :
		if pp is None : return None
		
		polys = n.GetPointPolys(pp)
		points = []
		for poly in polys :
			poly = obj.GetPolygon(poly)
			points.extend([poly.a, poly.b, poly.c, poly.d])
		points = list(set(points))
		
		points_aretes = []
		for pt in points :
			arete = n.GetEdgePolys(pp, pt)
			if arete != (-1, -1) : points_aretes.append(pt)
		
		for pt in points_aretes :
			if not bs.IsSelected(pt) : continue
			if li.IsSelected(pt) : continue
			return pt
		
		return None
	
	def mono_voisin(self, pp, li, bs, n, obj) :
		if pp is None : return None
		pol = obj.GetPolygon(pp)
		
		nab = n.GetNeighbor(pol.a, pol.b, pp)
		if self.verif(nab, li, bs) : return nab
		
		nbc = n.GetNeighbor(pol.b, pol.c, pp)
		if self.verif(nbc, li, bs) : return nbc
		
		ncd = n.GetNeighbor(pol.c, pol.d, pp)
		if self.verif(ncd, li, bs) : return ncd
		
		nda = n.GetNeighbor(pol.d, pol.a, pp)
		if self.verif(nda, li, bs) : return nda
		
		return None

	def sel_nsn(self, doc, obj) :
		if not obj : return
		polygonal = obj.CheckType(c4d.Opolygon)
		cerce = obj.CheckType(c4d.Ospline)
		modePoints = doc.GetMode() == c4d.Mpoints
		modePolys = doc.GetMode() == c4d.Mpolygons
		if not polygonal and not cerce : return
		#if polygonal and not modePolys : return
		if cerce and not modePoints : return
		if not modePoints and not modePolys : return
		
		if modePolys :
			bs = obj.GetPolygonS()
			nbp = obj.GetPolygonCount()
		else :
			bs = obj.GetPointS()
			nbp = obj.GetPointCount()
		
		bs_total = bs.GetCount()
		if bs_total and bs_total < 2 : return
		
		# dial = Selnsn_Dialogue()
		# dial.Open(c4d.DLG_TYPE_MODAL)
		# if dial.annuler : return
		
		a = self.a
		b = self.b
		if (self.b < self.a) : b = a
		dec = self.dec % b
		
		doc.StartUndo()
		doc.AddUndo(c4d.UNDOTYPE_CHANGE_SELECTION, obj)
		
		#-----------
		if cerce :
			if not bs_total : bs.SelectAll(nbp-1)
			li = bs.GetClone()
			bs.DeselectAll()
			j = dec
			bs_sel = li.GetAll(nbp)
			for i, sel in enumerate(bs_sel) :
				if not sel :
					j = dec
					continue
				if (j%b) < a : bs.Select(i)
				j += 1
			
			doc.EndUndo()
			c4d.EventAdd()
			return
		#----------
		
		n = Neighbor()
		n.Init(obj)
		if not bs_total : bs.SelectAll(nbp)
		
		def traite(li, p, ordre) :
			if p != None :
				li.Select(p)
				ordre.append(p)
		
		def tour(pp) :
			ordre1 = []
			voisin = self.mono_voisin
			if modePoints : voisin = self.point_voisin
			
			pa = voisin(pp, li, bs, n, obj)
			traite(li, pp, ordre1)
			traite(li, pa, ordre1)
			
			po = voisin(pa, li, bs, n, obj)
			while (po != None) :
				traite(li, po, ordre1)
				po = voisin(po, li, bs, n, obj)
			
			ordre2 = []
			pb = voisin(pp, li, bs, n, obj)
			if pb != None :
				traite(li, pb, ordre2)
				po = voisin(pb, li, bs, n, obj)
			else : po = None
			while (po != None) :
				traite(li, po, ordre2)
				po = voisin(po, li, bs, n, obj)
			
			ordre1.reverse()
			ordre1.extend(ordre2)
			return ordre1
		
		ordre = []
		
		li = bs.GetClone()
		li.DeselectAll()
		bs_sel = bs.GetAll(nbp)
		for i, sel in enumerate(bs_sel) :
			if not sel : continue
			if li.IsSelected(i) : continue
			ordre.extend(tour(i))
		
		j = 0
		jmax = len(ordre)
		bs.DeselectAll()
		
		while (j < jmax) :
			for k in xrange(a) :
				s = j + k + dec
				if s >= jmax : break
				bs.Select(ordre[s])
			j += b
		
		doc.EndUndo()
		c4d.EventAdd()
	
	
class Selnsn(plugins.CommandData) :
	dialog = None
	
	def Execute(self, doc) :
		if self.dialog is None:
			self.dialog = Selnsn_Dialogue()
		return self.dialog.Open(dlgtype=c4d.DLG_TYPE_ASYNC, pluginid=ID_SELNSN, defaulth=100, defaultw=100)

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

class Seltri(plugins.CommandData) :
	def sel_tri(self, doc, obj) :
		if not obj : return
		if obj.GetType() != c4d.Opolygon : return
		ng = obj.GetNgonEdgesCompact()
		bs = obj.GetPolygonS()
		n = -1
		doc.StartUndo()
		doc.AddUndo(c4d.UNDOTYPE_CHANGE_SELECTION, obj)
		for p in ng :
			n += 1
			if p != 0: continue
			pol = obj.GetPolygon(n)
			if pol.c == pol.d : bs.Select(n)
		doc.EndUndo()
		c4d.EventAdd()
		c4d.CallCommand(12187) # Polygones
	
	def Execute(self, doc) :
		obj = doc.GetActiveObject()
		self.sel_tri(doc, obj)
		return True

class Selquad(plugins.CommandData) :
	def sel_quad(self, doc, obj):
		if not obj: return
		if obj.GetType() != c4d.Opolygon: return
		ng = obj.GetNgonEdgesCompact()
		bs = obj.GetPolygonS()
		n = -1
		doc.StartUndo()
		doc.AddUndo(c4d.UNDOTYPE_CHANGE_SELECTION, obj)
		for p in ng:
			n += 1
			if p != 0: continue
			pol = obj.GetPolygon(n)
			if pol.c != pol.d : bs.Select(n)
		doc.EndUndo()
		c4d.EventAdd()
		c4d.CallCommand(12187) # Polygones
	
	def Execute(self, doc) :
		obj = doc.GetActiveObject()
		self.sel_quad(doc, obj)
		return True

class Selngon(plugins.CommandData) :
	def sel_ngon(self, doc, obj) :
		if not obj: return
		if obj.GetType() != c4d.Opolygon: return
		ng = obj.GetNgonEdgesCompact()
		bs = obj.GetPolygonS()
		n = 0
		doc.StartUndo()
		doc.AddUndo(c4d.UNDOTYPE_CHANGE_SELECTION, obj)
		for p in ng:
			if p != 0: bs.Select(n)
			n += 1
		doc.EndUndo()
		c4d.EventAdd()
		c4d.CallCommand(12187) # Polygones
	
	def Execute(self, doc) :
		obj = doc.GetActiveObject()
		self.sel_ngon(doc, obj)
		return True

class Selcon(plugins.CommandData) :
	def sel_con(self, doc, obj):
		if not obj: return
		if obj.GetType() != c4d.Opolygon: return
		nb_pol = obj.GetPolygonCount()
		bs = c4d.BaseSelect()
		n = Neighbor()
		n.Init(obj)
		
		for i in xrange(nb_pol):
			pol = obj.GetPolygon(i)
			
			pa = pol.a
			pb = pol.b
			pc = pol.c
			pd = pol.d
			
			nab = n.GetNeighbor(pa, pb, i)
			nbc = n.GetNeighbor(pb, pc, i)
			ncd = n.GetNeighbor(pc, pd, i)
			nda = n.GetNeighbor(pd, pa, i)
			
			cotes = n.GetPolyInfo(i)["edge"]
			
			if nab == -1:
				bs.Select(cotes[0])
			if nbc == -1:
				bs.Select(cotes[1])
			if ncd == -1:
				if pc != pd: bs.Select(cotes[2])
			if nda == -1:
				bs.Select(cotes[3])
		
		doc.StartUndo()
		doc.AddUndo(c4d.UNDOTYPE_CHANGE_SELECTION, obj)
		obj.SetSelectedEdges(n, bs, 0)
		doc.EndUndo()
		c4d.EventAdd()
		c4d.CallCommand(16351) # Arêtes
	
	def Execute(self, doc) :
		obj = doc.GetActiveObject()
		self.sel_con(doc, obj)
		return True

class Selind(plugins.CommandData) :
	def sel_ind(self, doc, obj):
		if not obj : return
		if obj.GetType() != c4d.Opolygon and obj.GetType() != c4d.Ospline : return
		
		if c4d.IsCommandChecked(12187) and obj.GetType() == c4d.Opolygon : # Polygones
			bs = obj.GetPolygonS()
			nbp = obj.GetPolygonCount()
		else :
			bs = obj.GetPointS()
			nbp = obj.GetPointCount()
		
		nbsel = bs.GetCount()
		if nbsel == 0 : return 
		
		doc.StartUndo()
		doc.AddUndo(c4d.UNDOTYPE_CHANGE_SELECTION, obj)
		
		for i, sel in enumerate(bs.GetAll(nbp)) :
			if not sel :
				bs.Select(i)
				continue
			break
		
		doc.EndUndo()
		c4d.EventAdd()
	
	def Execute(self, doc) :
		obj = doc.GetActiveObject()
		self.sel_ind(doc, obj)
		return True

class Seltail_Dialogue(gui.GeDialog) :
	tol = 0
	inf = False
	sup = False
	
	def CreateLayout(self) :
		self.GroupBegin(10, c4d.BFH_SCALEFIT, 1, 4)
		self.GroupBorderSpace(5, 5, 5, 5)
		self.GroupBegin(15, c4d.BFH_SCALEFIT, 2, 1)
		self.AddStaticText(16, c4d.BFH_SCALEFIT, name = txt(SS_SELTAIL_TOL))
		self.AddEditNumberArrows(11, c4d.BFH_SCALEFIT)
		self.GroupEnd()
		self.AddCheckbox(13, c4d.BFH_SCALEFIT, initw = 250, inith = 10, name = txt(SS_SELTAIL_INF))
		self.AddCheckbox(14, c4d.BFH_SCALEFIT, initw = 250, inith = 10, name = txt(SS_SELTAIL_SUP))
		self.GroupBegin(16, c4d.BFH_SCALEFIT, 2, 1)
		self.AddButton(1, c4d.BFH_SCALEFIT, initw = 70, inith = 15, name = txt(SS_SS_VAL))
		self.AddButton(2, c4d.BFH_SCALEFIT, initw = 70, inith = 15, name = txt(SS_SS_FER))
		self.GroupEnd()
		self.GroupEnd()
		return True
	
	def InitValues(self) :
		self.SetTitle(txt(SS_SELTAIL_NOM))
		self.SetPercent(11, 0.005, 0)
		return True
	
	def Command(self, id, msg) :
		if id == 1 :
			self.tol = self.GetReal(11)
			self.inf = self.GetBool(13)
			self.sup = self.GetBool(14)
			doc = documents.GetActiveDocument()
			obj = doc.GetActiveObject()
			self.sel_tail(doc, obj)
		if id == 2 :
			self.Close()
		return True
		
	def perim(self, i, obj) :
		poly = obj.GetPolygon(i)
		pA = obj.GetPoint(poly.a)
		pB = obj.GetPoint(poly.b)
		pC = obj.GetPoint(poly.c)
		pD = obj.GetPoint(poly.d)
		per = (pA - pB).GetLengthSquared() + (pB - pC).GetLengthSquared() + (pC - pD).GetLengthSquared() + (pD - pA).GetLengthSquared()
		return per

	def verif(self, ta, tb, tol, inf, sup) :
		tatol = ta*tol
		if inf :
			if tb <= (ta + tatol) :
				 return True
		
		if sup :
			if tb >= (ta - tatol) :
				 return True
		
		if tb <= (ta + tatol) :
			if tb >= (ta - tatol) :
				return True
		
		return False
	
	def sel_tail(self, doc, obj):
		if not obj : return
		if obj.GetType() != c4d.Opolygon : return
		if doc.GetMode() != c4d.Mpolygons : return
		
		bs = obj.GetPolygonS()
		nbsel = bs.GetCount()
		if nbsel == 0 : return 
		
		# dial = Seltail_Dialogue()
		# dial.Open(c4d.DLG_TYPE_MODAL)
		# if dial.annuler : return
		
		nbpol = obj.GetPolygonCount()
		taille_ref = 0
		
		doc.StartUndo()
		doc.AddUndo(c4d.UNDOTYPE_CHANGE_SELECTION, obj)
		
		for index, selec in enumerate(bs.GetAll(nbpol)) :
			if not selec: continue
			taille = self.perim(index, obj)
			taille_ref += taille
		
		for i in xrange(nbpol) :
			taille = self.perim(i, obj)
			if self.verif(taille_ref, taille, self.tol, self.inf, self.sup) :
				bs.Select(i)
		
		doc.EndUndo()
		c4d.EventAdd()
		c4d.CallCommand(12187) # Polygones
	

class Seltail(plugins.CommandData) :
	dialog = None
	
	def Execute(self, doc) :
		if self.dialog is None:
			self.dialog = Seltail_Dialogue()
		return self.dialog.Open(dlgtype=c4d.DLG_TYPE_ASYNC, pluginid=ID_SELTAIL, defaulth=100, defaultw=70)

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

class Seladj(plugins.CommandData) :
	def sel_adj(self, doc, obj):
		if not obj : return
		modePoints = doc.GetMode() == c4d.Mpoints
		modePolys = doc.GetMode() == c4d.Mpolygons
		polygonal = obj.CheckType(c4d.Opolygon)
		cerce = obj.CheckType(c4d.Ospline)
		if not polygonal and not cerce : return
		if not modePoints and not modePolys : return
		if cerce and modePolys : return
		
		if polygonal :
			nb_pol = obj.GetPolygonCount()
			bs = obj.GetPolygonS()
			n = Neighbor()
			n.Init(obj)
			
		nb_pts = obj.GetPointCount()
		bs_p = obj.GetPointS()

		doc.StartUndo()
		doc.AddUndo(c4d.UNDOTYPE_CHANGE_SELECTION, obj)
		
		if modePolys :
			for i, sel in enumerate(bs.GetAll(nb_pol)):
				if not sel: continue
				pol = obj.GetPolygon(i)
				
				cotes = []
				cotes.extend(n.GetPointPolys(pol.a))
				cotes.extend(n.GetPointPolys(pol.b))
				cotes.extend(n.GetPointPolys(pol.c))
				cotes.extend(n.GetPointPolys(pol.d))
				
				for p in cotes :
					bs.Select(p)
		
		else :
			if polygonal :
				for i, sel in enumerate(bs_p.GetAll(nb_pts)):
					if not sel : continue
					polys = n.GetPointPolys(i)
					for poly in polys :
						p = obj.GetPolygon(poly)
						bs_p.Select(p.a)
						bs_p.Select(p.b)
						bs_p.Select(p.c)
						bs_p.Select(p.d)
			else :
				for i, sel in enumerate(bs_p.GetAll(nb_pts)):
					if not sel : continue
					iP = i + 1
					iM = i - 1
					if iP < nb_pts : bs_p.Select(iP)
					if iM >= 0 : bs_p.Select(iM)

		doc.EndUndo()
		c4d.EventAdd()
	
	def Execute(self, doc) :
		obj = doc.GetActiveObject()
		self.sel_adj(doc, obj)
		return True

class Selpos_Dialogue(gui.GeDialog) :
	tol = 0.001
	pos = Vector()
	Xcon = 0
	Ycon = 0
	Zcon = 0
	
	def CreateLayout(self) :
		self.GroupBegin(10, c4d.BFH_SCALEFIT, 1, 3)
		self.GroupBorderSpace(5, 5, 5, 5)
		
		self.GroupBegin(12, c4d.BFH_SCALEFIT, 5, 3)
		self.AddStaticText(20, c4d.BFH_SCALEFIT, name = "X")
		self.AddCheckbox(21, c4d.BFH_SCALEFIT, initw = 70, inith = 10, name = "<")
		self.AddCheckbox(22, c4d.BFH_SCALEFIT, initw = 70, inith = 10, name = ">")
		self.AddCheckbox(23, c4d.BFH_SCALEFIT, initw = 70, inith = 10, name = "=")
		self.AddEditNumberArrows(24, c4d.BFH_SCALEFIT, initw = 140)
		
		self.AddStaticText(30, c4d.BFH_SCALEFIT, name = "Y")
		self.AddCheckbox(31, c4d.BFH_SCALEFIT, initw = 70, inith = 10, name = "<")
		self.AddCheckbox(32, c4d.BFH_SCALEFIT, initw = 70, inith = 10, name = ">")
		self.AddCheckbox(33, c4d.BFH_SCALEFIT, initw = 70, inith = 10, name = "=")
		self.AddEditNumberArrows(34, c4d.BFH_SCALEFIT, initw = 140)
		
		self.AddStaticText(40, c4d.BFH_SCALEFIT, name = "Z")
		self.AddCheckbox(41, c4d.BFH_SCALEFIT, initw = 70, inith = 10, name = "<")
		self.AddCheckbox(42, c4d.BFH_SCALEFIT, initw = 70, inith = 10, name = ">")
		self.AddCheckbox(43, c4d.BFH_SCALEFIT, initw = 70, inith = 10, name = "=")
		self.AddEditNumberArrows(44, c4d.BFH_SCALEFIT, initw = 140)
		self.GroupEnd()
		
		self.GroupBegin(14, c4d.BFH_SCALEFIT, 2, 1)
		self.AddStaticText(13, c4d.BFH_SCALEFIT, name = txt(SS_SELPOS_TOL))
		self.AddEditNumberArrows(11, c4d.BFH_SCALEFIT)
		
		self.AddButton(1, c4d.BFH_SCALEFIT, initw = 70, inith = 15, name = txt(SS_SS_VAL))
		self.AddButton(2, c4d.BFH_SCALEFIT, initw = 70, inith = 15, name = txt(SS_SS_FER))
		self.GroupEnd()
		
		self.GroupEnd()
		return True
	
	def InitValues(self) :
		doc = documents.GetActiveDocument()
		obj = doc.GetActiveObject()
		self.pos = self.sel_pos(doc, obj, True)
		self.SetTitle(txt(SS_SELPOS_NOM))
		self.SetMeter(11, self.tol, 0)
		if self.pos is None : return True
		self.SetMeter(24, self.pos.x)
		self.SetMeter(34, self.pos.y)
		self.SetMeter(44, self.pos.z)
		return True
	
	def conditionneur(self, n) :
		inf = self.GetBool(n+1)
		sup = self.GetBool(n+2)
		ega = self.GetBool(n+3)
		# 0 : aucun, 1 : =, 2 : <, 3 : <=, 4 : >, 5 : >=
		return (inf*2 + sup*4 + ega)
	
	def Command(self, id, msg) :
		if id == 21 and self.GetBool(21) : self.SetBool(22, False)
		if id == 22 and self.GetBool(22) : self.SetBool(21, False)
		if id == 31 and self.GetBool(31) : self.SetBool(32, False)
		if id == 32 and self.GetBool(32) : self.SetBool(31, False)
		if id == 41 and self.GetBool(41) : self.SetBool(42, False)
		if id == 42 and self.GetBool(42) : self.SetBool(41, False)
		
		if id == 1 :
			self.tol = self.GetReal(11)
			if self.pos is None : return True
			self.pos.x = self.GetReal(24)
			self.pos.y = self.GetReal(34)
			self.pos.z = self.GetReal(44)
			self.Xcon = self.conditionneur(20)
			self.Ycon = self.conditionneur(30)
			self.Zcon = self.conditionneur(40)
			doc = documents.GetActiveDocument()
			obj = doc.GetActiveObject()
			self.sel_pos(doc, obj)
		if id == 2 :
			self.Close()
		return True
	
	def CoreMessage(self, id, msg) :
		if id == c4d.EVMSG_CHANGE :
			self.InitValues()
		return True
	
	def condition(self, pt, pos, con, tol) :
		if con == 1 :
			if pt < (pos+tol) and pt > (pos-tol) : return True
		elif con == 2 :
			if pt < (pos+tol) : return True
		elif con == 3 :
			if pt <= (pos+tol) : return True
		elif con == 4 :
			if pt > (pos-tol) : return True
		elif con == 5 :
			if pt >= (pos-tol) : return True
		return False
	
	def centrepoly(self, obj, i) :
		poly = obj.GetPolygon(i)
		centre = Vector()
		centre += obj.GetPoint(poly.a)
		centre += obj.GetPoint(poly.b)
		centre += obj.GetPoint(poly.c)
		if poly.c == poly.d :
			centre /= 3.0
		else :
			centre += obj.GetPoint(poly.d)
			centre *= 0.25
		return centre
	
	def sel_pos(self, doc, obj, init=False) :
		if not obj : return
		polygonal = obj.CheckType(c4d.Opolygon)
		cerce = obj.CheckType(c4d.Ospline)
		if not polygonal and not cerce : return
		mode = doc.GetMode()
		if mode != c4d.Mpoints and mode != c4d.Mpolygons : return
		if mode == c4d.Mpolygons and cerce : return
		
		if mode == c4d.Mpoints :
			points = True
			bs = obj.GetPointS()
		else :
			points = False
			bs = obj.GetPolygonS()
		
		nbsel = bs.GetCount()
		if points : nbp = obj.GetPointCount()
		else : nbp = obj.GetPolygonCount()
		
		if not init :
			doc.StartUndo()
			doc.AddUndo(c4d.UNDOTYPE_CHANGE_SELECTION, obj)
		
		centrepoly = self.centrepoly
		nb = 0
		p = Vector()
		pos_min = Vector()
		pos_max = Vector()
		
		for i, sel in enumerate(bs.GetAll(nbp)) :
			if not sel : continue
			
			if points : p = obj.GetPoint(i)
			else : p = centrepoly(obj, i)
			
			if p.x < pos_min.x or not nb : pos_min.x = p.x
			if p.y < pos_min.y or not nb : pos_min.y = p.y
			if p.z < pos_min.z or not nb : pos_min.z = p.z
			
			if p.x > pos_max.x or not nb : pos_max.x = p.x
			if p.y > pos_max.y or not nb : pos_max.y = p.y
			if p.z > pos_max.z or not nb : pos_max.z = p.z
			
			nb += 1
			if nb == nbp : break
		
		pos = (pos_min + pos_max) * 0.5
		
		if init : return pos
		
		# dial = Selpos_Dialogue(pos)
		# dial.Open(c4d.DLG_TYPE_MODAL)
		# if dial.annuler : return
		
		pos = self.pos
		tol = self.tol
		Xcon = self.Xcon
		Ycon = self.Ycon
		Zcon = self.Zcon
		condition = self.condition
		pt = Vector()
		
		for i in xrange(nbp) :
			if points :
				pt = obj.GetPoint(i)
			else :
				pt = centrepoly(obj, i)
			cond = 0
			res = 0
			if Xcon :
				cond += condition(pt.x, pos.x, Xcon, tol)
				res += 1
			if Ycon :
				cond += condition(pt.y, pos.y, Ycon, tol)
				res += 1
			if Zcon :
				cond += condition(pt.z, pos.z, Zcon, tol)
				res += 1
			if cond == res :
				bs.Select(i)
			
		doc.EndUndo()
		c4d.EventAdd()

class Selpos(plugins.CommandData) :
	dialog = None
	
	def Execute(self, doc) :
		if self.dialog is None:
			self.dialog = Selpos_Dialogue()
		return self.dialog.Open(dlgtype=c4d.DLG_TYPE_ASYNC, pluginid=ID_SELPOS, defaulth=100, defaultw=70)

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

class Selmir_Dialogue(gui.GeDialog) :
	tol = 0.001
	Xcon = True
	Ycon = 0
	Zcon = 0
	ajsel = True
	
	def CreateLayout(self) :
		self.GroupBegin(10, c4d.BFH_SCALEFIT, 1, 3)
		self.GroupBorderSpace(5, 5, 5, 5)
		
		self.GroupBegin(12, c4d.BFH_SCALEFIT, 3, 1)
		self.AddCheckbox(21, c4d.BFH_SCALEFIT, initw = 20, inith = 0, name = "-X")
		self.AddCheckbox(22, c4d.BFH_SCALEFIT, initw = 20, inith = 0, name = "-Y")
		self.AddCheckbox(23, c4d.BFH_SCALEFIT, initw = 20, inith = 0, name = "-Z")
		self.GroupEnd()
		
		self.GroupBegin(15, c4d.BFH_SCALEFIT, 1, 1)
		self.AddCheckbox(24, c4d.BFH_SCALEFIT, initw = 0, inith = 0, name = txt(SS_SELMIR_AJS))
		self.GroupEnd()
		
		self.GroupBegin(14, c4d.BFH_SCALEFIT, 2, 1)
		self.AddStaticText(13, c4d.BFH_SCALEFIT, name = txt(SS_SELMIR_TOL))
		self.AddEditNumberArrows(11, c4d.BFH_SCALEFIT)
		
		self.AddButton(1, c4d.BFH_SCALEFIT, initw = 80, inith = 15, name = txt(SS_SS_VAL))
		self.AddButton(2, c4d.BFH_SCALEFIT, initw = 80, inith = 15, name = txt(SS_SS_FER))
		self.GroupEnd()
		
		self.GroupEnd()
		return True
	
	def InitValues(self) :
		doc = documents.GetActiveDocument()
		obj = doc.GetActiveObject()
		self.SetTitle(txt(SS_SELMIR_NOM))
		self.SetMeter(11, self.tol, 0.0001, step = 0.01)
		self.SetBool(21, self.Xcon)
		self.SetBool(22, self.Ycon)
		self.SetBool(23, self.Zcon)
		self.SetBool(24, self.ajsel)
		return True
	
	def Command(self, id, msg) :
		if id == 11 : self.tol = self.GetReal(11)
		if id == 21 : self.Xcon = self.GetBool(21)
		if id == 22 : self.Ycon = self.GetBool(22)
		if id == 23 : self.Zcon = self.GetBool(23)
		if id == 24 : self.ajsel = self.GetBool(24)
		if id == 1 :
			self.tol = self.GetReal(11)
			self.Xcon = self.GetBool(21)
			self.Ycon = self.GetBool(22)
			self.Zcon = self.GetBool(23)
			doc = documents.GetActiveDocument()
			obj = doc.GetActiveObject()
			self.sel_mir(doc, obj)
		if id == 2 :
			self.Close()
		return True
	
	def _texte(self, vec, tol) :
		vec *= tol
		vec.x = int(vec.x)
		vec.y = int(vec.y)
		vec.z = int(vec.z)
		p_txt = str(int(vec.x)) + "." + str(int(vec.y)) + "." + str(int(vec.z))
		return p_txt, vec
	
	def _centrepoly(self, obj, poly) :
		centre = Vector()
		centre += obj.GetPoint(poly.a)
		centre += obj.GetPoint(poly.b)
		centre += obj.GetPoint(poly.c)
		if poly.c == poly.d :
			centre /= 3.0
		else :
			centre += obj.GetPoint(poly.d)
			centre *= 0.25
		return centre
		
	def _centrearete(self, obj, poly, arete, polycen) :
		centre = Vector()
		aretes = [(poly.a, poly.b), (poly.b, poly.c), (poly.c, poly.d), (poly.d, poly.a)]
		for i in xrange(2) :
			centre += obj.GetPoint(aretes[arete][i])
		centre = centre * 0.5 + polycen
		return centre
	
	def sel_mir(self, doc, obj) :
		if not obj : return
		polygonal = obj.CheckType(c4d.Opolygon)
		cerce = obj.CheckType(c4d.Ospline)
		if not polygonal and not cerce : return
		mode = doc.GetMode()
		if cerce and mode != c4d.Mpoints : return
		
		if mode == c4d.Mpoints :
			bs = obj.GetPointS()
			tab = obj.GetAllPoints()
			nbp = obj.GetPointCount()
			
		elif mode == c4d.Medges :
			bs = obj.GetEdgeS()
			tab = obj.GetAllPolygons()
			nbp = obj.GetPolygonCount()
			
		elif mode == c4d.Mpolygons :
			bs = obj.GetPolygonS()
			tab = obj.GetAllPolygons()
			nbp = obj.GetPolygonCount()
			
		else :
			return
		
		if not bs or not nbp : return
		nbsel = bs.GetCount()
		if not nbsel : return
		
		dic = {}
		liste = []
		tol = self.tol
		itol = 1.0 / tol
		Xcon = self.Xcon
		Ycon = self.Ycon
		Zcon = self.Zcon
		Mpolys = c4d.Mpolygons
		Maretes = c4d.Medges
		_centrepoly = self._centrepoly
		_centrearete = self._centrearete
		_texte = self._texte
		
		for i, p in enumerate(tab) :
			if mode == Maretes :
				polycen = _centrepoly(obj, p)
				for j in xrange(4) :
					pt = _centrearete(obj, p, j, polycen)
					p_txt, vec = _texte(pt, itol)
					if (p_txt in dic) : dic[p_txt].append(i*4 + j)
					else : dic[p_txt] = [i*4 + j]
					liste.append(vec)
			else :
				if mode == Mpolys : pt = _centrepoly(obj, p)
				else : pt = p
				p_txt, vec = _texte(pt, itol)
				if (p_txt in dic) : dic[p_txt].append(i)
				else : dic[p_txt] = [i]
				liste.append(vec)
		
		doc.StartUndo()
		doc.AddUndo(c4d.UNDOTYPE_CHANGE_SELECTION, obj)
		
		if self.ajsel : bsAct = bs
		else :
			bsAct = bs.GetClone()
			bs.DeselectAll()
		
		if mode == Maretes : nbp = nbp * 4 + 4
		
		for i, sel in enumerate(bsAct.GetAll(nbp)) :
			if not sel : continue
			
			vec = liste[i]
			if Xcon : vec.x *= -1
			if Ycon : vec.y *= -1
			if Zcon : vec.z *= -1
			p_txt = str(int(vec.x)) + "." + str(int(vec.y)) + "." + str(int(vec.z))
			
			try :
				js = dic[p_txt]
			except KeyError :
				pass
			else :
				for j in js :
					bs.Select(j)
		
		if mode == Maretes :
			obj.ValidateEdgeSelection(bs)
			
		doc.EndUndo()
		c4d.EventAdd()

class Selmir(plugins.CommandData) :
	dialog = None
	
	def Execute(self, doc) :
		if self.dialog is None:
			self.dialog = Selmir_Dialogue()
		return self.dialog.Open(dlgtype=c4d.DLG_TYPE_ASYNC, pluginid=ID_SELMIR, defaulth=80, defaultw=100)

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


class Selpif_Dialogue(gui.GeDialog) :
	src = 123456
	chc = 0
	bool_src = False
	qte = 10
	bool_qte = False
	
	def CreateLayout(self) :
		self.GroupBegin(100, c4d.BFH_SCALEFIT, 1, 1)
		self.GroupBorderSpace(5, 5, 5, 5)
		
		self.GroupBegin(101, c4d.BFH_SCALEFIT, 2, 2)
		self.AddCheckbox(12, c4d.BFH_SCALEFIT, initw = 0, inith = 0, name = txt(SS_SELPIF_SRC))
		self.AddEditNumberArrows(11, c4d.BFH_SCALEFIT)
		self.AddCheckbox(16, c4d.BFH_SCALEFIT, initw = 0, inith = 0, name = txt(SS_SELPIF_QTE))
		self.AddEditNumberArrows(15, c4d.BFH_SCALEFIT)
		self.AddStaticText(13, c4d.BFH_SCALEFIT, name = txt(SS_SELPIF_CHC))
		self.AddEditNumberArrows(14, c4d.BFH_SCALEFIT)
		self.GroupEnd()
		
		self.GroupBegin(102, c4d.BFH_SCALEFIT, 2, 2)
		self.AddButton(1, c4d.BFH_SCALEFIT, initw = 70, inith = 15, name = txt(SS_SS_VAL))
		self.AddButton(2, c4d.BFH_SCALEFIT, initw = 70, inith = 15, name = txt(SS_SS_FER))
		self.GroupEnd()
		
		self.GroupEnd()
		return True
	
	def InitValues(self) :
		self.SetTitle(txt(SS_SELPIF_NOM))
		self.SetLong(11, self.src)
		self.SetBool(12, self.bool_src)
		self.SetLong(15, self.qte, 0)
		self.SetBool(16, self.bool_qte)
		self.SetLong(14, self.chc)
		self.Enable(11, self.bool_src)
		self.Enable(15, self.bool_qte)
		self.Enable(14, not self.bool_qte)
		self.Enable(11, self.bool_src)
		return True
		
	def Command(self, id, msg) :
		if id == 12 : self.Enable(11, self.GetBool(12))
		if id == 16 :
			self.Enable(15, self.GetBool(16))
			self.Enable(14, not self.GetBool(16))
		
		if id == 1 :
			self.src = self.GetLong(11)
			self.bool_src = self.GetBool(12)
			self.qte = self.GetLong(15)
			self.bool_qte = self.GetBool(16)
			self.chc = self.GetLong(14)
			doc = documents.GetActiveDocument()
			obj = doc.GetActiveObject()
			self.sel_pif(doc, obj)
		if id == 2 :
			self.Close()
		return True
	
	def sel_pif(self, doc, obj) :
		if not obj : return
		polygonal = obj.CheckType(c4d.Opolygon)
		cerce = obj.CheckType(c4d.Ospline)
		if not polygonal and not cerce : return
		mode = doc.GetMode()
		if mode != c4d.Mpoints and mode != c4d.Mpolygons : return
		if mode == c4d.Mpolygons and cerce : return
		
		if mode == c4d.Mpoints :
			points = True
			bs = obj.GetPointS()
		else :
			points = False
			bs = obj.GetPolygonS()
		
		nbsel = bs.GetCount()
		if points : nbp = obj.GetPointCount()
		else : nbp = obj.GetPolygonCount()
		
		doc.StartUndo()
		doc.AddUndo(c4d.UNDOTYPE_CHANGE_SELECTION, obj)
		src = self.src
		chc = abs(self.chc) + 1
		qte = self.qte
		if qte > nbp : qte = nbp
		bs.DeselectAll()
		
		if self.bool_src : random.seed(src)
		
		if self.bool_qte :
			liste = [0] * nbp
			for i in xrange(qte) : liste[i] = 1
			random.shuffle(liste)
			bs.SetAll(liste)
		
		else :
			if self.chc > 0 :
				for i in xrange(nbp) :
					pif = random.randint(0, chc)
					if pif : bs.Select(i)
			else :
				for i in xrange(nbp) :
					pif = random.randint(0, chc)
					if not pif : bs.Select(i)
			
		doc.EndUndo()
		c4d.EventAdd()

class Selpif(plugins.CommandData) :
	dialog = None
	
	def Execute(self, doc) :
		if self.dialog is None:
			self.dialog = Selpif_Dialogue()
		return self.dialog.Open(dlgtype=c4d.DLG_TYPE_ASYNC, pluginid=ID_SELPIF, defaulth=100, defaultw=70)

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


class SelSup(plugins.CommandData) :
	pass

def icone(nom) :
	bmp = bitmaps.BaseBitmap()
	dir, file = os.path.split(__file__)
	fn = os.path.join(dir, "res", nom)
	bmp.InitWith(fn)
	return bmp

if __name__ == "__main__":
	plugins.RegisterCommandPlugin(id=ID_SELNSN, str = "#$00" + txt(SS_SELNSN_NOM), info = 0, help = txt(SS_SELNSN_AID), dat = Selnsn(), icon = icone("selnsn.tif"))
	plugins.RegisterCommandPlugin(id=ID_SELADJ, str = "#$01" + txt(SS_SELADJ_NOM), info = 0, help = txt(SS_SELADJ_AID), dat = Seladj(), icon = icone("seladj.tif"))
	plugins.RegisterCommandPlugin(id=ID_SELPIF, str = "#$02" + txt(SS_SELPIF_NOM), info = 0, help = txt(SS_SELPIF_AID), dat = Selpif(), icon = icone("selpif.tif"))
	plugins.RegisterCommandPlugin(id=ID_SELMIR, str = "#$03" + txt(SS_SELMIR_NOM), info = 0, help = txt(SS_SELMIR_AID), dat = Selmir(), icon = icone("selmir.tif"))
	plugins.RegisterCommandPlugin(id=ID_SELDIR, str = "#$04" + txt(SS_SELDIR_NOM), info = 0, help = txt(SS_SELDIR_AID), dat = Seldir(), icon = icone("seldir.tif"))
	plugins.RegisterCommandPlugin(id=ID_SELTAIL, str = "#$05" + txt(SS_SELTAIL_NOM), info = 0, help = txt(SS_SELTAIL_AID), dat = Seltail(), icon = icone("seltail.tif"))
	plugins.RegisterCommandPlugin(id=ID_SELTRI, str = "#$06" + txt(SS_SELTRI_NOM), info = 0, help = txt(SS_SELTRI_AID), dat = Seltri(), icon = icone("seltri.tif"))
	plugins.RegisterCommandPlugin(id=ID_SELQUAD, str = "#$07" + txt(SS_SELQUAD_NOM), info = 0, help = txt(SS_SELQUAD_AID), dat = Selquad(), icon = icone("selquad.tif"))
	plugins.RegisterCommandPlugin(id=ID_SELNGON, str = "#$08" + txt(SS_SELNGON_NOM), info = 0, help = txt(SS_SELNGON_AID), dat = Selngon(), icon = icone("selngon.tif"))
	plugins.RegisterCommandPlugin(id=ID_SELCON, str = "#$09" + txt(SS_SELCON_NOM), info = 0, help = txt(SS_SELCON_AID), dat = Selcon(), icon = icone("selcon.tif"))
	plugins.RegisterCommandPlugin(id=ID_SELIND, str = "#$10" + txt(SS_SELIND_NOM), info = 0, help = txt(SS_SELIND_AID), dat = Selind(), icon = icone("selind.tif"))
	plugins.RegisterCommandPlugin(id=ID_SELPOS, str = "#$11" + txt(SS_SELPOS_NOM), info = 0, help = txt(SS_SELPOS_AID), dat = Selpos(), icon = icone("selpos.tif"))
	plugins.RegisterCommandPlugin(id=SEPARATEUR_ID, str = "#$12--", info = 0, help = "vonc_selsup", dat = SelSup(), icon = None)
	plugins.RegisterCommandPlugin(id=MODULE_ID, str = "#$13v 1.8 - http://code.vonc.fr", info = 0, help = "http://code.vonc.fr", dat = SelSup(), icon = icone("selsup.tif"))