diff --git a/add_mesh_BoltFactory/__init__.py b/add_mesh_BoltFactory/__init__.py index 1a765908825e32aadd650ffe8d63483449bfe758..d763d13f2a00f745692cbfa29c94f5e263e8ea07 100644 --- a/add_mesh_BoltFactory/__init__.py +++ b/add_mesh_BoltFactory/__init__.py @@ -45,7 +45,7 @@ import bpy def register(): - Boltfactory.register() + Boltfactory.register() diff --git a/archipack/archipack_gl.py b/archipack/archipack_gl.py index f3ef034af9190d04d4b92ebcd88648f2f85a3867..f0bf84828bb74f85ba20a7c7515eb8283e8ad631 100644 --- a/archipack/archipack_gl.py +++ b/archipack/archipack_gl.py @@ -85,7 +85,7 @@ in vec2 pos; void main() { - gl_Position = ModelViewProjectionMatrix * vec4(pos, 0.0, 1.0); + gl_Position = ModelViewProjectionMatrix * vec4(pos, 0.0, 1.0); } ''' @@ -97,7 +97,7 @@ out vec4 fragColor; void main() { - fragColor = color; + fragColor = color; } ''' diff --git a/archipack/archipack_keymaps.py b/archipack/archipack_keymaps.py index f5b95957dd601d75fcaa8316a5e131f8e353c5c7..05458b9c6463a6143e30c833bca0342cd394cdf4 100644 --- a/archipack/archipack_keymaps.py +++ b/archipack/archipack_keymaps.py @@ -119,4 +119,4 @@ class Keymaps: k.alt, k.ctrl, k.shift, k.type, k.value, sub, k.name) file = open(filename, "w") file.write(str) - file.close() \ No newline at end of file + file.close() diff --git a/blenderkit/bg_blender.py b/blenderkit/bg_blender.py index e8ccb04dbd5344eb34e710e2fcbb83fe43cb138a..8a37f6ce910414168f32198ce79ce2b551bb59d1 100644 --- a/blenderkit/bg_blender.py +++ b/blenderkit/bg_blender.py @@ -239,4 +239,3 @@ def unregister(): bpy.utils.unregister_class(KillBgProcess) if bpy.app.timers.is_registered(bg_update): bpy.app.timers.unregister(bg_update) - diff --git a/blenderkit/colors.py b/blenderkit/colors.py index d01bdb0ac3eefc25a4a709c0e3db378c14562023..c61d9fa0001e090065f617bee125c266ac9c5882 100644 --- a/blenderkit/colors.py +++ b/blenderkit/colors.py @@ -20,4 +20,4 @@ TEXT = (.9, .9, .9, .6) GREEN = (.9, 1, .9, .6) -RED = (1, .5, .5, .8) \ No newline at end of file +RED = (1, .5, .5, .8) diff --git a/blenderkit/oauth.py b/blenderkit/oauth.py index 95c6bae625bb778fae3c86024ca89a7f713296dd..06e5729883884bf281ac0ada9fca23e3bf756b2f 100644 --- a/blenderkit/oauth.py +++ b/blenderkit/oauth.py @@ -104,4 +104,4 @@ class SimpleOAuthAuthenticator(object): return self._get_tokens(authorization_code=authorization_code) def get_refreshed_token(self, refresh_token): - return self._get_tokens(refresh_token=refresh_token, grant_type="refresh_token") \ No newline at end of file + return self._get_tokens(refresh_token=refresh_token, grant_type="refresh_token") diff --git a/blenderkit/tasks_queue.py b/blenderkit/tasks_queue.py index 95ffb1a688c8a1621557114045a7c23a44bc735c..4f500bbfba5646e9448fab2b2b596e81f9a30a46 100644 --- a/blenderkit/tasks_queue.py +++ b/blenderkit/tasks_queue.py @@ -103,5 +103,3 @@ def register(): def unregister(): bpy.app.handlers.load_post.remove(scene_load) - - diff --git a/blenderkit/utils.py b/blenderkit/utils.py index fe80e1a00442a58fafadd42785889352a9da2347..b9bd17f1a5a3344fa439e3b4ef4766f7720494aa 100644 --- a/blenderkit/utils.py +++ b/blenderkit/utils.py @@ -558,4 +558,4 @@ def guard_from_crash(): return False; if bpy.context.preferences.addons['blenderkit'].preferences is None: return False; - return True \ No newline at end of file + return True diff --git a/btrace/bTrace_props.py b/btrace/bTrace_props.py index 4476e0f612669ecf74f6bfda0cebb7714c5e69e0..b7e824c815e6538a1d211f58fbfa1b618121d44e 100644 --- a/btrace/bTrace_props.py +++ b/btrace/bTrace_props.py @@ -565,5 +565,3 @@ class TracerProperties(PropertyGroup): description="", default='tool_help' ) - - diff --git a/io_export_dxf/model/dxfLibrary.py b/io_export_dxf/model/dxfLibrary.py index 2dffaabe3667570b18213f47d42b73192140b7e4..50aa4d567eca7978e2e9537c5300848a810fe1fc 100644 --- a/io_export_dxf/model/dxfLibrary.py +++ b/io_export_dxf/model/dxfLibrary.py @@ -89,94 +89,94 @@ ______________________________________________________________ #import BPyMessages try: - import copy - #from struct import pack + import copy + #from struct import pack except: - copy = None + copy = None ####1) Private (only for developers) _HEADER_POINTS=['insbase','extmin','extmax'] #---helper functions----------------------------------- def _point(x,index=0): - """Convert tuple to a dxf point""" - return '\n'.join([' %s\n%s'%((i+1)*10+index,float(x[i])) for i in range(len(x))]) + """Convert tuple to a dxf point""" + return '\n'.join([' %s\n%s'%((i+1)*10+index,float(x[i])) for i in range(len(x))]) def _points(plist): - """Convert a list of tuples to dxf points""" - out = '\n'.join([_point(plist[i],i)for i in range(len(plist))]) - return out + """Convert a list of tuples to dxf points""" + out = '\n'.join([_point(plist[i],i)for i in range(len(plist))]) + return out #---base classes---------------------------------------- class _Call: - """Makes a callable class.""" - def copy(self): - """Returns a copy.""" - return copy.deepcopy(self) + """Makes a callable class.""" + def copy(self): + """Returns a copy.""" + return copy.deepcopy(self) - def __call__(self,**attrs): - """Returns a copy with modified attributes.""" - copied=self.copy() - for attr in attrs:setattr(copied,attr,attrs[attr]) - return copied + def __call__(self,**attrs): + """Returns a copy with modified attributes.""" + copied=self.copy() + for attr in attrs:setattr(copied,attr,attrs[attr]) + return copied #------------------------------------------------------- class _Entity(_Call): - """Base class for _common group codes for entities.""" - def __init__(self,paperspace=None,color=None,layer='0', - lineType=None,lineTypeScale=None,lineWeight=None, - extrusion=None,elevation=None,thickness=None, - parent=None): - """None values will be omitted.""" - self.paperspace = paperspace - self.color = color - self.layer = layer - self.lineType = lineType - self.lineTypeScale = lineTypeScale - self.lineWeight = lineWeight - self.extrusion = extrusion - self.elevation = elevation - self.thickness = thickness - #self.visible = visible - self.parent = parent - - def _common(self): - """Return common group codes as a string.""" - if self.parent:parent=self.parent - else:parent=self - result ='' - if parent.paperspace==1: result+=' 67\n1\n' - if parent.layer!=None: result+=' 8\n%s\n'%parent.layer - if parent.color!=None: result+=' 62\n%s\n'%parent.color - if parent.lineType!=None: result+=' 6\n%s\n'%parent.lineType - # TODO: if parent.lineWeight!=None: result+='370\n%s\n'%parent.lineWeight - # TODO: if parent.visible!=None: result+='60\n%s\n'%parent.visible - if parent.lineTypeScale!=None: result+=' 48\n%s\n'%parent.lineTypeScale - if parent.elevation!=None: result+=' 38\n%s\n'%parent.elevation - if parent.thickness!=None: result+=' 39\n%s\n'%parent.thickness - if parent.extrusion!=None: result+='%s\n'%_point(parent.extrusion,200) - return result + """Base class for _common group codes for entities.""" + def __init__(self,paperspace=None,color=None,layer='0', + lineType=None,lineTypeScale=None,lineWeight=None, + extrusion=None,elevation=None,thickness=None, + parent=None): + """None values will be omitted.""" + self.paperspace = paperspace + self.color = color + self.layer = layer + self.lineType = lineType + self.lineTypeScale = lineTypeScale + self.lineWeight = lineWeight + self.extrusion = extrusion + self.elevation = elevation + self.thickness = thickness + #self.visible = visible + self.parent = parent + + def _common(self): + """Return common group codes as a string.""" + if self.parent:parent=self.parent + else:parent=self + result ='' + if parent.paperspace==1: result+=' 67\n1\n' + if parent.layer!=None: result+=' 8\n%s\n'%parent.layer + if parent.color!=None: result+=' 62\n%s\n'%parent.color + if parent.lineType!=None: result+=' 6\n%s\n'%parent.lineType + # TODO: if parent.lineWeight!=None: result+='370\n%s\n'%parent.lineWeight + # TODO: if parent.visible!=None: result+='60\n%s\n'%parent.visible + if parent.lineTypeScale!=None: result+=' 48\n%s\n'%parent.lineTypeScale + if parent.elevation!=None: result+=' 38\n%s\n'%parent.elevation + if parent.thickness!=None: result+=' 39\n%s\n'%parent.thickness + if parent.extrusion!=None: result+='%s\n'%_point(parent.extrusion,200) + return result #-------------------------- class _Entities: - """Base class to deal with composed objects.""" - def __dxf__(self): - return [] + """Base class to deal with composed objects.""" + def __dxf__(self): + return [] - def __str__(self): - return ''.join([str(x) for x in self.__dxf__()]) + def __str__(self): + return ''.join([str(x) for x in self.__dxf__()]) #-------------------------- class _Collection(_Call): - """Base class to expose entities methods to main object.""" - def __init__(self,entities=[]): - self.entities=copy.copy(entities) - #link entities methods to drawing - for attr in dir(self.entities): - if attr[0]!='_': - attrObject=getattr(self.entities,attr) - if callable(attrObject): - setattr(self,attr,attrObject) + """Base class to expose entities methods to main object.""" + def __init__(self,entities=[]): + self.entities=copy.copy(entities) + #link entities methods to drawing + for attr in dir(self.entities): + if attr[0]!='_': + attrObject=getattr(self.entities,attr) + if callable(attrObject): + setattr(self,attr,attrObject) ####2) Constants #---color values @@ -199,7 +199,7 @@ TOP_CENTER = 2 TOP_RIGHT = 3 MIDDLE_LEFT = 4 MIDDLE_CENTER = 5 -MIDDLE_RIGHT = 6 +MIDDLE_RIGHT = 6 BOTTOM_LEFT = 7 BOTTOM_CENTER = 8 BOTTOM_RIGHT = 9 @@ -212,14 +212,14 @@ AT_LEAST = 1 #taller characters will override EXACT = 2 #taller characters will not override #---polyline flag 70 -CLOSED =1 # This is a closed polyline (or a polygon mesh closed in the M direction) -CURVE_FIT =2 # Curve-fit vertices have been added -SPLINE_FIT =4 # Spline-fit vertices have been added -POLYLINE_3D =8 # This is a 3D polyline -POLYGON_MESH =16 # This is a 3D polygon mesh -CLOSED_N =32 # The polygon mesh is closed in the N direction -POLYFACE_MESH =64 # The polyline is a polyface mesh -CONTINOUS_LINETYPE_PATTERN =128 # The linetype pattern is generated continuously around the vertices of this polyline +CLOSED =1 # This is a closed polyline (or a polygon mesh closed in the M direction) +CURVE_FIT =2 # Curve-fit vertices have been added +SPLINE_FIT =4 # Spline-fit vertices have been added +POLYLINE_3D =8 # This is a 3D polyline +POLYGON_MESH =16 # This is a 3D polygon mesh +CLOSED_N =32 # The polygon mesh is closed in the N direction +POLYFACE_MESH =64 # The polyline is a polyface mesh +CONTINOUS_LINETYPE_PATTERN =128 # The linetype pattern is generated continuously around the vertices of this polyline #---polyline flag 75, = curve type QUADRIC_NURBS = 5 @@ -237,7 +237,7 @@ MIDDLE = 4 #if vertical alignment = 0 FIT = 5 #if vertical alignment = 0 #vertical BASELINE = 0 -BOTTOM = 1 +BOTTOM = 1 MIDDLE = 2 TOP = 3 @@ -245,682 +245,682 @@ TOP = 3 #---entitities ----------------------------------------------- #-------------------------- class Arc(_Entity): - """Arc, angles in degrees.""" - def __init__(self,center=(0,0,0),radius=1, - startAngle=0.0,endAngle=90,**common): - """Angles in degrees.""" - _Entity.__init__(self,**common) - self.center=center - self.radius=radius - self.startAngle=startAngle - self.endAngle=endAngle - def __str__(self): - return ' 0\nARC\n%s%s\n 40\n%s\n 50\n%s\n 51\n%s\n'%\ - (self._common(),_point(self.center), - self.radius,self.startAngle,self.endAngle) + """Arc, angles in degrees.""" + def __init__(self,center=(0,0,0),radius=1, + startAngle=0.0,endAngle=90,**common): + """Angles in degrees.""" + _Entity.__init__(self,**common) + self.center=center + self.radius=radius + self.startAngle=startAngle + self.endAngle=endAngle + def __str__(self): + return ' 0\nARC\n%s%s\n 40\n%s\n 50\n%s\n 51\n%s\n'%\ + (self._common(),_point(self.center), + self.radius,self.startAngle,self.endAngle) #----------------------------------------------- class Circle(_Entity): - """Circle""" - def __init__(self,center=(0,0,0),radius=1,**common): - _Entity.__init__(self,**common) - self.center=center - self.radius=radius - def __str__(self): - return ' 0\nCIRCLE\n%s%s\n 40\n%s\n'%\ - (self._common(),_point(self.center),self.radius) + """Circle""" + def __init__(self,center=(0,0,0),radius=1,**common): + _Entity.__init__(self,**common) + self.center=center + self.radius=radius + def __str__(self): + return ' 0\nCIRCLE\n%s%s\n 40\n%s\n'%\ + (self._common(),_point(self.center),self.radius) #----------------------------------------------- class Face(_Entity): - """3dface""" - def __init__(self,points,**common): - _Entity.__init__(self,**common) - while len(points)<4: #fix for r12 format - points.append(points[-1]) - self.points=points + """3dface""" + def __init__(self,points,**common): + _Entity.__init__(self,**common) + while len(points)<4: #fix for r12 format + points.append(points[-1]) + self.points=points - def __str__(self): - out = ' 0\n3DFACE\n%s%s\n' %(self._common(),_points(self.points)) - return out + def __str__(self): + out = ' 0\n3DFACE\n%s%s\n' %(self._common(),_points(self.points)) + return out #----------------------------------------------- class Insert(_Entity): - """Block instance.""" - def __init__(self,name,point=(0,0,0), - xscale=None,yscale=None,zscale=None, - cols=None,colspacing=None,rows=None,rowspacing=None, - rotation=None, - **common): - _Entity.__init__(self,**common) - self.name=name - self.point=point - self.xscale=xscale - self.yscale=yscale - self.zscale=zscale - self.cols=cols - self.colspacing=colspacing - self.rows=rows - self.rowspacing=rowspacing - self.rotation=rotation - - def __str__(self): - result=' 0\nINSERT\n 2\n%s\n%s%s\n'%\ - (self.name,self._common(),_point(self.point)) - if self.xscale!=None:result+=' 41\n%s\n'%self.xscale - if self.yscale!=None:result+=' 42\n%s\n'%self.yscale - if self.zscale!=None:result+=' 43\n%s\n'%self.zscale - if self.rotation:result+=' 50\n%s\n'%self.rotation - if self.cols!=None:result+=' 70\n%s\n'%self.cols - if self.colspacing!=None:result+=' 44\n%s\n'%self.colspacing - if self.rows!=None:result+=' 71\n%s\n'%self.rows - if self.rowspacing!=None:result+=' 45\n%s\n'%self.rowspacing - return result + """Block instance.""" + def __init__(self,name,point=(0,0,0), + xscale=None,yscale=None,zscale=None, + cols=None,colspacing=None,rows=None,rowspacing=None, + rotation=None, + **common): + _Entity.__init__(self,**common) + self.name=name + self.point=point + self.xscale=xscale + self.yscale=yscale + self.zscale=zscale + self.cols=cols + self.colspacing=colspacing + self.rows=rows + self.rowspacing=rowspacing + self.rotation=rotation + + def __str__(self): + result=' 0\nINSERT\n 2\n%s\n%s%s\n'%\ + (self.name,self._common(),_point(self.point)) + if self.xscale!=None:result+=' 41\n%s\n'%self.xscale + if self.yscale!=None:result+=' 42\n%s\n'%self.yscale + if self.zscale!=None:result+=' 43\n%s\n'%self.zscale + if self.rotation:result+=' 50\n%s\n'%self.rotation + if self.cols!=None:result+=' 70\n%s\n'%self.cols + if self.colspacing!=None:result+=' 44\n%s\n'%self.colspacing + if self.rows!=None:result+=' 71\n%s\n'%self.rows + if self.rowspacing!=None:result+=' 45\n%s\n'%self.rowspacing + return result #----------------------------------------------- class Line(_Entity): - """Line""" - def __init__(self,points,**common): - _Entity.__init__(self,**common) - self.points=points - def __str__(self): - return ' 0\nLINE\n%s%s\n' %( - self._common(), _points(self.points)) + """Line""" + def __init__(self,points,**common): + _Entity.__init__(self,**common) + self.points=points + def __str__(self): + return ' 0\nLINE\n%s%s\n' %( + self._common(), _points(self.points)) #----------------------------------------------- class PolyLine(_Entity): - def __init__(self,points,org_point=[0,0,0],flag70=0,flag75=0,width=None,**common): - #width = number, or width = list [width_start=None, width_end=None] - #for 2d-polyline: points = [ [[x, y, z], vflag=None, [width_start=None, width_end=None], bulge=0 or None] ...] - #for 3d-polyline: points = [ [[x, y, z], vflag=None], ...] - #for polyface: points = [points_list, faces_list] - _Entity.__init__(self,**common) - self.points=points - self.org_point=org_point - self.pflag70 = flag70 - self.pflag75 = flag75 - self.polyface = False - self.polyline2d = False - self.faces = [] # dummy value - self.width= None # dummy value - if self.pflag70 & POLYFACE_MESH: - self.polyface=True - self.points=points[0] - self.faces=points[1] - self.p_count=len(self.points) - self.f_count=len(self.faces) - elif not (self.pflag70 & POLYLINE_3D): - self.polyline2d = True - if width: - if type(width)!='list': width=[width,width] - self.width=width - - def __str__(self): - result= ' 0\nPOLYLINE\n%s 70\n%s\n' %(self._common(),self.pflag70) - result+=' 66\n1\n' - result+='%s\n' %_point(self.org_point) - if self.polyface: - result+=' 71\n%s\n' %self.p_count - result+=' 72\n%s\n' %self.f_count - elif self.polyline2d: - if self.width!=None: result+=' 40\n%s\n 41\n%s\n' %(self.width[0],self.width[1]) - if self.pflag75: - result+=' 75\n%s\n' %self.pflag75 - for point in self.points: - result+=' 0\nVERTEX\n' - result+=' 8\n%s\n' %self.layer - if self.polyface: - result+='%s\n' %_point(point) - result+=' 70\n192\n' - elif self.polyline2d: - result+='%s\n' %_point(point[0]) - flag = point[1] - if len(point)>2: - [width1, width2] = point[2] - if width1!=None: result+=' 40\n%s\n' %width1 - if width2!=None: result+=' 41\n%s\n' %width2 - if len(point)==4: - bulge = point[3] - if bulge: result+=' 42\n%s\n' %bulge - if flag: - result+=' 70\n%s\n' %flag - else: - result+='%s\n' %_point(point[0]) - flag = point[1] - if flag: - result+=' 70\n%s\n' %flag - - for face in self.faces: - result+=' 0\nVERTEX\n' - result+=' 8\n%s\n' %self.layer - result+='%s\n' %_point(self.org_point) - result+=' 70\n128\n' - result+=' 71\n%s\n' %face[0] - result+=' 72\n%s\n' %face[1] - result+=' 73\n%s\n' %face[2] - if len(face)==4: result+=' 74\n%s\n' %face[3] - result+=' 0\nSEQEND\n' - result+=' 8\n%s\n' %self.layer - return result + def __init__(self,points,org_point=[0,0,0],flag70=0,flag75=0,width=None,**common): + #width = number, or width = list [width_start=None, width_end=None] + #for 2d-polyline: points = [ [[x, y, z], vflag=None, [width_start=None, width_end=None], bulge=0 or None] ...] + #for 3d-polyline: points = [ [[x, y, z], vflag=None], ...] + #for polyface: points = [points_list, faces_list] + _Entity.__init__(self,**common) + self.points=points + self.org_point=org_point + self.pflag70 = flag70 + self.pflag75 = flag75 + self.polyface = False + self.polyline2d = False + self.faces = [] # dummy value + self.width= None # dummy value + if self.pflag70 & POLYFACE_MESH: + self.polyface=True + self.points=points[0] + self.faces=points[1] + self.p_count=len(self.points) + self.f_count=len(self.faces) + elif not (self.pflag70 & POLYLINE_3D): + self.polyline2d = True + if width: + if type(width)!='list': width=[width,width] + self.width=width + + def __str__(self): + result= ' 0\nPOLYLINE\n%s 70\n%s\n' %(self._common(),self.pflag70) + result+=' 66\n1\n' + result+='%s\n' %_point(self.org_point) + if self.polyface: + result+=' 71\n%s\n' %self.p_count + result+=' 72\n%s\n' %self.f_count + elif self.polyline2d: + if self.width!=None: result+=' 40\n%s\n 41\n%s\n' %(self.width[0],self.width[1]) + if self.pflag75: + result+=' 75\n%s\n' %self.pflag75 + for point in self.points: + result+=' 0\nVERTEX\n' + result+=' 8\n%s\n' %self.layer + if self.polyface: + result+='%s\n' %_point(point) + result+=' 70\n192\n' + elif self.polyline2d: + result+='%s\n' %_point(point[0]) + flag = point[1] + if len(point)>2: + [width1, width2] = point[2] + if width1!=None: result+=' 40\n%s\n' %width1 + if width2!=None: result+=' 41\n%s\n' %width2 + if len(point)==4: + bulge = point[3] + if bulge: result+=' 42\n%s\n' %bulge + if flag: + result+=' 70\n%s\n' %flag + else: + result+='%s\n' %_point(point[0]) + flag = point[1] + if flag: + result+=' 70\n%s\n' %flag + + for face in self.faces: + result+=' 0\nVERTEX\n' + result+=' 8\n%s\n' %self.layer + result+='%s\n' %_point(self.org_point) + result+=' 70\n128\n' + result+=' 71\n%s\n' %face[0] + result+=' 72\n%s\n' %face[1] + result+=' 73\n%s\n' %face[2] + if len(face)==4: result+=' 74\n%s\n' %face[3] + result+=' 0\nSEQEND\n' + result+=' 8\n%s\n' %self.layer + return result #----------------------------------------------- class Point(_Entity): - """Point.""" - def __init__(self,points=None,**common): - _Entity.__init__(self,**common) - self.points=points - def __str__(self): # TODO: - return ' 0\nPOINT\n%s%s\n' %(self._common(), - _points(self.points) - ) + """Point.""" + def __init__(self,points=None,**common): + _Entity.__init__(self,**common) + self.points=points + def __str__(self): # TODO: + return ' 0\nPOINT\n%s%s\n' %(self._common(), + _points(self.points) + ) #----------------------------------------------- class Solid(_Entity): - """Colored solid fill.""" - def __init__(self,points=None,**common): - _Entity.__init__(self,**common) - self.points=points - def __str__(self): - return ' 0\nSOLID\n%s%s\n' %(self._common(), - _points(self.points[:2]+[self.points[3],self.points[2]]) - ) + """Colored solid fill.""" + def __init__(self,points=None,**common): + _Entity.__init__(self,**common) + self.points=points + def __str__(self): + return ' 0\nSOLID\n%s%s\n' %(self._common(), + _points(self.points[:2]+[self.points[3],self.points[2]]) + ) #----------------------------------------------- class Text(_Entity): - """Single text line.""" - def __init__(self,text='',point=(0,0,0),alignment=None, - flag=None,height=1,justifyhor=None,justifyver=None, - rotation=None,obliqueAngle=None,style=None,xscale=None,**common): - _Entity.__init__(self,**common) - self.text=text - self.point=point - self.alignment=alignment - self.flag=flag - self.height=height - self.justifyhor=justifyhor - self.justifyver=justifyver - self.rotation=rotation - self.obliqueAngle=obliqueAngle - self.style=style - self.xscale=xscale - def __str__(self): - result= ' 0\nTEXT\n%s%s\n 40\n%s\n 1\n%s\n'%\ - (self._common(),_point(self.point),self.height,self.text) - if self.rotation: result+=' 50\n%s\n'%self.rotation - if self.xscale: result+=' 41\n%s\n'%self.xscale - if self.obliqueAngle: result+=' 51\n%s\n'%self.obliqueAngle - if self.style: result+=' 7\n%s\n'%self.style - if self.flag: result+=' 71\n%s\n'%self.flag - if self.justifyhor: result+=' 72\n%s\n'%self.justifyhor - if self.alignment: result+='%s\n'%_point(self.alignment,1) - if self.justifyver: result+=' 73\n%s\n'%self.justifyver - return result + """Single text line.""" + def __init__(self,text='',point=(0,0,0),alignment=None, + flag=None,height=1,justifyhor=None,justifyver=None, + rotation=None,obliqueAngle=None,style=None,xscale=None,**common): + _Entity.__init__(self,**common) + self.text=text + self.point=point + self.alignment=alignment + self.flag=flag + self.height=height + self.justifyhor=justifyhor + self.justifyver=justifyver + self.rotation=rotation + self.obliqueAngle=obliqueAngle + self.style=style + self.xscale=xscale + def __str__(self): + result= ' 0\nTEXT\n%s%s\n 40\n%s\n 1\n%s\n'%\ + (self._common(),_point(self.point),self.height,self.text) + if self.rotation: result+=' 50\n%s\n'%self.rotation + if self.xscale: result+=' 41\n%s\n'%self.xscale + if self.obliqueAngle: result+=' 51\n%s\n'%self.obliqueAngle + if self.style: result+=' 7\n%s\n'%self.style + if self.flag: result+=' 71\n%s\n'%self.flag + if self.justifyhor: result+=' 72\n%s\n'%self.justifyhor + if self.alignment: result+='%s\n'%_point(self.alignment,1) + if self.justifyver: result+=' 73\n%s\n'%self.justifyver + return result #----------------------------------------------- class Mtext(Text): - """Surrogate for mtext, generates some Text instances.""" - def __init__(self,text='',point=(0,0,0),width=250,spacingFactor=1.5,down=0,spacingWidth=None,**options): - Text.__init__(self,text=text,point=point,**options) - if down:spacingFactor*=-1 - self.spacingFactor=spacingFactor - self.spacingWidth=spacingWidth - self.width=width - self.down=down - def __str__(self): - texts=self.text.replace('\r\n','\n').split('\n') - if not self.down:texts.reverse() - result='' - x=y=0 - if self.spacingWidth:spacingWidth=self.spacingWidth - else:spacingWidth=self.height*self.spacingFactor - for text in texts: - while text: - result+='%s' %Text(text[:self.width], - point=(self.point[0]+x*spacingWidth, - self.point[1]+y*spacingWidth, - self.point[2]), - alignment=self.alignment,flag=self.flag,height=self.height, - justifyhor=self.justifyhor,justifyver=self.justifyver, - rotation=self.rotation,obliqueAngle=self.obliqueAngle, - style=self.style,xscale=self.xscale,parent=self - ) - text=text[self.width:] - if self.rotation:x+=1 - else:y+=1 - return result[1:] + """Surrogate for mtext, generates some Text instances.""" + def __init__(self,text='',point=(0,0,0),width=250,spacingFactor=1.5,down=0,spacingWidth=None,**options): + Text.__init__(self,text=text,point=point,**options) + if down:spacingFactor*=-1 + self.spacingFactor=spacingFactor + self.spacingWidth=spacingWidth + self.width=width + self.down=down + def __str__(self): + texts=self.text.replace('\r\n','\n').split('\n') + if not self.down:texts.reverse() + result='' + x=y=0 + if self.spacingWidth:spacingWidth=self.spacingWidth + else:spacingWidth=self.height*self.spacingFactor + for text in texts: + while text: + result+='%s' %Text(text[:self.width], + point=(self.point[0]+x*spacingWidth, + self.point[1]+y*spacingWidth, + self.point[2]), + alignment=self.alignment,flag=self.flag,height=self.height, + justifyhor=self.justifyhor,justifyver=self.justifyver, + rotation=self.rotation,obliqueAngle=self.obliqueAngle, + style=self.style,xscale=self.xscale,parent=self + ) + text=text[self.width:] + if self.rotation:x+=1 + else:y+=1 + return result[1:] #----------------------------------------------- ##class _Mtext(_Entity): - """Mtext not functioning for minimal dxf.""" - """ - def __init__(self,text='',point=(0,0,0),attachment=1, - charWidth=None,charHeight=1,direction=1,height=100,rotation=0, - spacingStyle=None,spacingFactor=None,style=None,width=100, - xdirection=None,**common): - _Entity.__init__(self,**common) - self.text=text - self.point=point - self.attachment=attachment - self.charWidth=charWidth - self.charHeight=charHeight - self.direction=direction - self.height=height - self.rotation=rotation - self.spacingStyle=spacingStyle - self.spacingFactor=spacingFactor - self.style=style - self.width=width - self.xdirection=xdirection - def __str__(self): - input=self.text - text='' - while len(input)>250: - text+='3\n%s\n'%input[:250] - input=input[250:] - text+='1\n%s\n'%input - result= '0\nMTEXT\n%s\n%s\n40\n%s\n41\n%s\n71\n%s\n72\n%s%s\n43\n%s\n50\n%s\n'%\ - (self._common(),_point(self.point),self.charHeight,self.width, - self.attachment,self.direction,text, - self.height, - self.rotation) - if self.style:result+='7\n%s\n'%self.style - if self.xdirection:result+='%s\n'%_point(self.xdirection,1) - if self.charWidth:result+='42\n%s\n'%self.charWidth - if self.spacingStyle:result+='73\n%s\n'%self.spacingStyle - if self.spacingFactor:result+='44\n%s\n'%self.spacingFactor - return result - """ + """Mtext not functioning for minimal dxf.""" + """ + def __init__(self,text='',point=(0,0,0),attachment=1, + charWidth=None,charHeight=1,direction=1,height=100,rotation=0, + spacingStyle=None,spacingFactor=None,style=None,width=100, + xdirection=None,**common): + _Entity.__init__(self,**common) + self.text=text + self.point=point + self.attachment=attachment + self.charWidth=charWidth + self.charHeight=charHeight + self.direction=direction + self.height=height + self.rotation=rotation + self.spacingStyle=spacingStyle + self.spacingFactor=spacingFactor + self.style=style + self.width=width + self.xdirection=xdirection + def __str__(self): + input=self.text + text='' + while len(input)>250: + text+='3\n%s\n'%input[:250] + input=input[250:] + text+='1\n%s\n'%input + result= '0\nMTEXT\n%s\n%s\n40\n%s\n41\n%s\n71\n%s\n72\n%s%s\n43\n%s\n50\n%s\n'%\ + (self._common(),_point(self.point),self.charHeight,self.width, + self.attachment,self.direction,text, + self.height, + self.rotation) + if self.style:result+='7\n%s\n'%self.style + if self.xdirection:result+='%s\n'%_point(self.xdirection,1) + if self.charWidth:result+='42\n%s\n'%self.charWidth + if self.spacingStyle:result+='73\n%s\n'%self.spacingStyle + if self.spacingFactor:result+='44\n%s\n'%self.spacingFactor + return result + """ #---tables --------------------------------------------------- #----------------------------------------------- class Block(_Collection): - """Use list methods to add entities, eg append.""" - def __init__(self,name,layer='0',flag=0,base=(0,0,0),entities=[]): - self.entities=copy.copy(entities) - _Collection.__init__(self,entities) - self.layer=layer - self.name=name - self.flag=0 - self.base=base - def __str__(self): # TODO: - e=''.join([str(x)for x in self.entities]) - return ' 0\nBLOCK\n 8\n%s\n 2\n%s\n 70\n%s\n%s\n 3\n%s\n%s 0\nENDBLK\n'%\ - (self.layer,self.name.upper(),self.flag,_point(self.base),self.name.upper(),e) + """Use list methods to add entities, eg append.""" + def __init__(self,name,layer='0',flag=0,base=(0,0,0),entities=[]): + self.entities=copy.copy(entities) + _Collection.__init__(self,entities) + self.layer=layer + self.name=name + self.flag=0 + self.base=base + def __str__(self): # TODO: + e=''.join([str(x)for x in self.entities]) + return ' 0\nBLOCK\n 8\n%s\n 2\n%s\n 70\n%s\n%s\n 3\n%s\n%s 0\nENDBLK\n'%\ + (self.layer,self.name.upper(),self.flag,_point(self.base),self.name.upper(),e) #----------------------------------------------- class Layer(_Call): - """Layer""" - def __init__(self,name='pydxf',color=7,lineType='continuous',flag=64): - self.name=name - self.color=color - self.lineType=lineType - self.flag=flag - def __str__(self): - return ' 0\nLAYER\n 2\n%s\n 70\n%s\n 62\n%s\n 6\n%s\n'%\ - (self.name.upper(),self.flag,self.color,self.lineType) + """Layer""" + def __init__(self,name='pydxf',color=7,lineType='continuous',flag=64): + self.name=name + self.color=color + self.lineType=lineType + self.flag=flag + def __str__(self): + return ' 0\nLAYER\n 2\n%s\n 70\n%s\n 62\n%s\n 6\n%s\n'%\ + (self.name.upper(),self.flag,self.color,self.lineType) #----------------------------------------------- class LineType(_Call): - """Custom linetype""" - def __init__(self,name='CONTINUOUS',description='Solid line',elements=[0.0],flag=0): - self.name=name - self.description=description - self.elements=copy.copy(elements) - self.flag=flag - def __str__(self): - result = ' 0\nLTYPE\n 2\n%s\n 70\n%s\n 3\n%s\n 72\n65\n'%\ - (self.name.upper(),self.flag,self.description) - if self.elements: - elements = ' 73\n%s\n' %(len(self.elements)-1) - elements += ' 40\n%s\n' %(self.elements[0]) - for e in self.elements[1:]: - elements += ' 49\n%s\n' %e - result += elements - return result + """Custom linetype""" + def __init__(self,name='CONTINUOUS',description='Solid line',elements=[0.0],flag=0): + self.name=name + self.description=description + self.elements=copy.copy(elements) + self.flag=flag + def __str__(self): + result = ' 0\nLTYPE\n 2\n%s\n 70\n%s\n 3\n%s\n 72\n65\n'%\ + (self.name.upper(),self.flag,self.description) + if self.elements: + elements = ' 73\n%s\n' %(len(self.elements)-1) + elements += ' 40\n%s\n' %(self.elements[0]) + for e in self.elements[1:]: + elements += ' 49\n%s\n' %e + result += elements + return result #----------------------------------------------- class Style(_Call): - """Text style""" - def __init__(self,name='standard',flag=0,height=0,widthFactor=1.0,obliqueAngle=0.0, - mirror=0,lastHeight=1,font='arial.ttf',bigFont=''): - self.name=name - self.flag=flag - self.height=height - self.widthFactor=widthFactor - self.obliqueAngle=obliqueAngle - self.mirror=mirror - self.lastHeight=lastHeight - self.font=font - self.bigFont=bigFont - def __str__(self): - return ' 0\nSTYLE\n 2\n%s\n 70\n%s\n 40\n%s\n 41\n%s\n 50\n%s\n 71\n%s\n 42\n%s\n 3\n%s\n 4\n%s\n'%\ - (self.name.upper(),self.flag,self.flag,self.widthFactor, - self.obliqueAngle,self.mirror,self.lastHeight, - self.font.upper(),self.bigFont.upper()) + """Text style""" + def __init__(self,name='standard',flag=0,height=0,widthFactor=1.0,obliqueAngle=0.0, + mirror=0,lastHeight=1,font='arial.ttf',bigFont=''): + self.name=name + self.flag=flag + self.height=height + self.widthFactor=widthFactor + self.obliqueAngle=obliqueAngle + self.mirror=mirror + self.lastHeight=lastHeight + self.font=font + self.bigFont=bigFont + def __str__(self): + return ' 0\nSTYLE\n 2\n%s\n 70\n%s\n 40\n%s\n 41\n%s\n 50\n%s\n 71\n%s\n 42\n%s\n 3\n%s\n 4\n%s\n'%\ + (self.name.upper(),self.flag,self.flag,self.widthFactor, + self.obliqueAngle,self.mirror,self.lastHeight, + self.font.upper(),self.bigFont.upper()) #----------------------------------------------- class VPort(_Call): - def __init__(self,name,flag=0, - leftBottom=(0.0,0.0), - rightTop=(1.0,1.0), - center=(0.5,0.5), - snap_base=(0.0,0.0), - snap_spacing=(0.1,0.1), - grid_spacing=(0.1,0.1), - direction=(0.0,0.0,1.0), - target=(0.0,0.0,0.0), - height=1.0, - ratio=1.0, - lens=50.0, - frontClipping=0.0, - backClipping=0.0, - snap_rotation=0.0, - twist=0.0, - mode=0, - circle_zoom=100, - fast_zoom=1, - ucsicon=1, - snap_on=0, - grid_on=0, - snap_style=0, - snap_isopair=0 - ): - self.name=name - self.flag=flag - self.leftBottom=leftBottom - self.rightTop=rightTop - self.center=center - self.snap_base=snap_base - self.snap_spacing=snap_spacing - self.grid_spacing=grid_spacing - self.direction=direction - self.target=target - self.height=float(height) - self.ratio=float(ratio) - self.lens=float(lens) - self.frontClipping=float(frontClipping) - self.backClipping=float(backClipping) - self.snap_rotation=float(snap_rotation) - self.twist=float(twist) - self.mode=mode - self.circle_zoom=circle_zoom - self.fast_zoom=fast_zoom - self.ucsicon=ucsicon - self.snap_on=snap_on - self.grid_on=grid_on - self.snap_style=snap_style - self.snap_isopair=snap_isopair - def __str__(self): - output = [' 0', 'VPORT', - ' 2', self.name, - ' 70', self.flag, - _point(self.leftBottom), - _point(self.rightTop,1), - _point(self.center,2), # View center point (in DCS) - _point(self.snap_base,3), - _point(self.snap_spacing,4), - _point(self.grid_spacing,5), - _point(self.direction,6), #view direction from target (in WCS) - _point(self.target,7), - ' 40', self.height, - ' 41', self.ratio, - ' 42', self.lens, - ' 43', self.frontClipping, - ' 44', self.backClipping, - ' 50', self.snap_rotation, - ' 51', self.twist, - ' 71', self.mode, - ' 72', self.circle_zoom, - ' 73', self.fast_zoom, - ' 74', self.ucsicon, - ' 75', self.snap_on, - ' 76', self.grid_on, - ' 77', self.snap_style, - ' 78', self.snap_isopair - ] - - output_str = '' - for s in output: - output_str += '%s\n' %s - return output_str + def __init__(self,name,flag=0, + leftBottom=(0.0,0.0), + rightTop=(1.0,1.0), + center=(0.5,0.5), + snap_base=(0.0,0.0), + snap_spacing=(0.1,0.1), + grid_spacing=(0.1,0.1), + direction=(0.0,0.0,1.0), + target=(0.0,0.0,0.0), + height=1.0, + ratio=1.0, + lens=50.0, + frontClipping=0.0, + backClipping=0.0, + snap_rotation=0.0, + twist=0.0, + mode=0, + circle_zoom=100, + fast_zoom=1, + ucsicon=1, + snap_on=0, + grid_on=0, + snap_style=0, + snap_isopair=0 + ): + self.name=name + self.flag=flag + self.leftBottom=leftBottom + self.rightTop=rightTop + self.center=center + self.snap_base=snap_base + self.snap_spacing=snap_spacing + self.grid_spacing=grid_spacing + self.direction=direction + self.target=target + self.height=float(height) + self.ratio=float(ratio) + self.lens=float(lens) + self.frontClipping=float(frontClipping) + self.backClipping=float(backClipping) + self.snap_rotation=float(snap_rotation) + self.twist=float(twist) + self.mode=mode + self.circle_zoom=circle_zoom + self.fast_zoom=fast_zoom + self.ucsicon=ucsicon + self.snap_on=snap_on + self.grid_on=grid_on + self.snap_style=snap_style + self.snap_isopair=snap_isopair + def __str__(self): + output = [' 0', 'VPORT', + ' 2', self.name, + ' 70', self.flag, + _point(self.leftBottom), + _point(self.rightTop,1), + _point(self.center,2), # View center point (in DCS) + _point(self.snap_base,3), + _point(self.snap_spacing,4), + _point(self.grid_spacing,5), + _point(self.direction,6), #view direction from target (in WCS) + _point(self.target,7), + ' 40', self.height, + ' 41', self.ratio, + ' 42', self.lens, + ' 43', self.frontClipping, + ' 44', self.backClipping, + ' 50', self.snap_rotation, + ' 51', self.twist, + ' 71', self.mode, + ' 72', self.circle_zoom, + ' 73', self.fast_zoom, + ' 74', self.ucsicon, + ' 75', self.snap_on, + ' 76', self.grid_on, + ' 77', self.snap_style, + ' 78', self.snap_isopair + ] + + output_str = '' + for s in output: + output_str += '%s\n' %s + return output_str #----------------------------------------------- class View(_Call): - def __init__(self,name,flag=0, - width=1.0, - height=1.0, - center=(0.5,0.5), - direction=(0.0,0.0,1.0), - target=(0.0,0.0,0.0), - lens=50.0, - frontClipping=0.0, - backClipping=0.0, - twist=0.0,mode=0 - ): - self.name=name - self.flag=flag - self.width=float(width) - self.height=float(height) - self.center=center - self.direction=direction - self.target=target - self.lens=float(lens) - self.frontClipping=float(frontClipping) - self.backClipping=float(backClipping) - self.twist=float(twist) - self.mode=mode - def __str__(self): - output = [' 0', 'VIEW', - ' 2', self.name, - ' 70', self.flag, - ' 40', self.height, - _point(self.center), - ' 41', self.width, - _point(self.direction,1), - _point(self.target,2), - ' 42', self.lens, - ' 43', self.frontClipping, - ' 44', self.backClipping, - ' 50', self.twist, - ' 71', self.mode - ] - output_str = '' - for s in output: - output_str += '%s\n' %s - return output_str + def __init__(self,name,flag=0, + width=1.0, + height=1.0, + center=(0.5,0.5), + direction=(0.0,0.0,1.0), + target=(0.0,0.0,0.0), + lens=50.0, + frontClipping=0.0, + backClipping=0.0, + twist=0.0,mode=0 + ): + self.name=name + self.flag=flag + self.width=float(width) + self.height=float(height) + self.center=center + self.direction=direction + self.target=target + self.lens=float(lens) + self.frontClipping=float(frontClipping) + self.backClipping=float(backClipping) + self.twist=float(twist) + self.mode=mode + def __str__(self): + output = [' 0', 'VIEW', + ' 2', self.name, + ' 70', self.flag, + ' 40', self.height, + _point(self.center), + ' 41', self.width, + _point(self.direction,1), + _point(self.target,2), + ' 42', self.lens, + ' 43', self.frontClipping, + ' 44', self.backClipping, + ' 50', self.twist, + ' 71', self.mode + ] + output_str = '' + for s in output: + output_str += '%s\n' %s + return output_str #----------------------------------------------- def ViewByWindow(name,leftBottom=(0,0),rightTop=(1,1),**options): - width=abs(rightTop[0]-leftBottom[0]) - height=abs(rightTop[1]-leftBottom[1]) - center=((rightTop[0]+leftBottom[0])*0.5,(rightTop[1]+leftBottom[1])*0.5) - return View(name=name,width=width,height=height,center=center,**options) + width=abs(rightTop[0]-leftBottom[0]) + height=abs(rightTop[1]-leftBottom[1]) + center=((rightTop[0]+leftBottom[0])*0.5,(rightTop[1]+leftBottom[1])*0.5) + return View(name=name,width=width,height=height,center=center,**options) #---drawing #----------------------------------------------- class Drawing(_Collection): - """Dxf drawing. Use append or any other list methods to add objects.""" - def __init__(self,insbase=(0.0,0.0,0.0),extmin=(0.0,0.0,0.0),extmax=(0.0,0.0,0.0), - layers=[Layer()],linetypes=[LineType()],styles=[Style()],blocks=[], - views=[],vports=[],entities=None,fileName='test.dxf'): - # TODO: replace list with None,arial - if not entities: - entities=[] - _Collection.__init__(self,entities) - self.insbase=insbase - self.extmin=extmin - self.extmax=extmax - self.layers=copy.copy(layers) - self.linetypes=copy.copy(linetypes) - self.styles=copy.copy(styles) - self.views=copy.copy(views) - self.vports=copy.copy(vports) - self.blocks=copy.copy(blocks) - self.fileName=fileName - #print 'deb: blocks=',blocks #---------- - #private - #self.acadver='9\n$ACADVER\n1\nAC1006\n' - self.acadver=' 9\n$ACADVER\n 1\nAC1009\n' - """DXF AutoCAD-Release format codes: - AC1021 2008, 2007 - AC1018 2006, 2005, 2004 - AC1015 2002, 2000i, 2000 - AC1014 R14,14.01 - AC1012 R13 - AC1009 R12,11 - AC1006 R10 - AC1004 R9 - AC1002 R2.6 - AC1.50 R2.05 - """ - - def _name(self,x): - """Helper function for self._point""" - return ' 9\n$%s\n' %x.upper() - - def _point(self,name,x): - """Point setting from drawing like extmin,extmax,...""" - return '%s%s' %(self._name(name),_point(x)) - - def _section(self,name,x): - """Sections like tables,blocks,entities,...""" - if x: xstr=''.join(x) - else: xstr='' - return ' 0\nSECTION\n 2\n%s\n%s 0\nENDSEC\n'%(name.upper(),xstr) - - def _table(self,name,x): - """Tables like ltype,layer,style,...""" - if x: xstr=''.join(x) - else: xstr='' - return ' 0\nTABLE\n 2\n%s\n 70\n%s\n%s 0\nENDTAB\n'%(name.upper(),len(x),xstr) - - def __str__(self): - """Returns drawing as dxf string.""" - header=[self.acadver]+[self._point(attr,getattr(self,attr))+'\n' for attr in _HEADER_POINTS] - header=self._section('header',header) - - tables=[self._table('vport',[str(x) for x in self.vports]), - self._table('ltype',[str(x) for x in self.linetypes]), - self._table('layer',[str(x) for x in self.layers]), - self._table('style',[str(x) for x in self.styles]), - self._table('view',[str(x) for x in self.views]), - ] - tables=self._section('tables',tables) - blocks=self._section('blocks',[str(x) for x in self.blocks]) - entities=self._section('entities',[str(x) for x in self.entities]) - all=''.join([header,tables,blocks,entities,' 0\nEOF\n']) - return all - - def _write_section(self,file,name,data): - file.write(' 0\nSECTION\n 2\n%s\n'%name.upper()) - for x in data: - file.write(str(x)) - file.write(' 0\nENDSEC\n') - - def saveas(self,fileName,buffer=0): - """Writes DXF file. Needs target file name. If optional parameter buffer>0, then switch to old behavior: store entire output string in RAM. - """ - self.fileName=fileName - if buffer: self.save() - else: self.export() - - def save(self): - outfile=open(self.fileName,'w') - outfile.write(str(self)) - outfile.close() - - def export(self): - outfile=open(self.fileName,'w') - header=[self.acadver]+[self._point(attr,getattr(self,attr))+'\n' for attr in _HEADER_POINTS] - self._write_section(outfile,'header',header) - tables=[self._table('vport',[str(x) for x in self.vports]), - self._table('ltype',[str(x) for x in self.linetypes]), - self._table('layer',[str(x) for x in self.layers]), - self._table('style',[str(x) for x in self.styles]), - self._table('view',[str(x) for x in self.views]), - ] - self._write_section(outfile,'tables',tables) - self._write_section(outfile,'blocks',self.blocks) - self._write_section(outfile,'entities',self.entities) - outfile.write(' 0\nEOF\n') - outfile.close() + """Dxf drawing. Use append or any other list methods to add objects.""" + def __init__(self,insbase=(0.0,0.0,0.0),extmin=(0.0,0.0,0.0),extmax=(0.0,0.0,0.0), + layers=[Layer()],linetypes=[LineType()],styles=[Style()],blocks=[], + views=[],vports=[],entities=None,fileName='test.dxf'): + # TODO: replace list with None,arial + if not entities: + entities=[] + _Collection.__init__(self,entities) + self.insbase=insbase + self.extmin=extmin + self.extmax=extmax + self.layers=copy.copy(layers) + self.linetypes=copy.copy(linetypes) + self.styles=copy.copy(styles) + self.views=copy.copy(views) + self.vports=copy.copy(vports) + self.blocks=copy.copy(blocks) + self.fileName=fileName + #print 'deb: blocks=',blocks #---------- + #private + #self.acadver='9\n$ACADVER\n1\nAC1006\n' + self.acadver=' 9\n$ACADVER\n 1\nAC1009\n' + """DXF AutoCAD-Release format codes: + AC1021 2008, 2007 + AC1018 2006, 2005, 2004 + AC1015 2002, 2000i, 2000 + AC1014 R14,14.01 + AC1012 R13 + AC1009 R12,11 + AC1006 R10 + AC1004 R9 + AC1002 R2.6 + AC1.50 R2.05 + """ + + def _name(self,x): + """Helper function for self._point""" + return ' 9\n$%s\n' %x.upper() + + def _point(self,name,x): + """Point setting from drawing like extmin,extmax,...""" + return '%s%s' %(self._name(name),_point(x)) + + def _section(self,name,x): + """Sections like tables,blocks,entities,...""" + if x: xstr=''.join(x) + else: xstr='' + return ' 0\nSECTION\n 2\n%s\n%s 0\nENDSEC\n'%(name.upper(),xstr) + + def _table(self,name,x): + """Tables like ltype,layer,style,...""" + if x: xstr=''.join(x) + else: xstr='' + return ' 0\nTABLE\n 2\n%s\n 70\n%s\n%s 0\nENDTAB\n'%(name.upper(),len(x),xstr) + + def __str__(self): + """Returns drawing as dxf string.""" + header=[self.acadver]+[self._point(attr,getattr(self,attr))+'\n' for attr in _HEADER_POINTS] + header=self._section('header',header) + + tables=[self._table('vport',[str(x) for x in self.vports]), + self._table('ltype',[str(x) for x in self.linetypes]), + self._table('layer',[str(x) for x in self.layers]), + self._table('style',[str(x) for x in self.styles]), + self._table('view',[str(x) for x in self.views]), + ] + tables=self._section('tables',tables) + blocks=self._section('blocks',[str(x) for x in self.blocks]) + entities=self._section('entities',[str(x) for x in self.entities]) + all=''.join([header,tables,blocks,entities,' 0\nEOF\n']) + return all + + def _write_section(self,file,name,data): + file.write(' 0\nSECTION\n 2\n%s\n'%name.upper()) + for x in data: + file.write(str(x)) + file.write(' 0\nENDSEC\n') + + def saveas(self,fileName,buffer=0): + """Writes DXF file. Needs target file name. If optional parameter buffer>0, then switch to old behavior: store entire output string in RAM. + """ + self.fileName=fileName + if buffer: self.save() + else: self.export() + + def save(self): + outfile=open(self.fileName,'w') + outfile.write(str(self)) + outfile.close() + + def export(self): + outfile=open(self.fileName,'w') + header=[self.acadver]+[self._point(attr,getattr(self,attr))+'\n' for attr in _HEADER_POINTS] + self._write_section(outfile,'header',header) + tables=[self._table('vport',[str(x) for x in self.vports]), + self._table('ltype',[str(x) for x in self.linetypes]), + self._table('layer',[str(x) for x in self.layers]), + self._table('style',[str(x) for x in self.styles]), + self._table('view',[str(x) for x in self.views]), + ] + self._write_section(outfile,'tables',tables) + self._write_section(outfile,'blocks',self.blocks) + self._write_section(outfile,'entities',self.entities) + outfile.write(' 0\nEOF\n') + outfile.close() #---extras #----------------------------------------------- class Rectangle(_Entity): - """Rectangle, creates lines.""" - def __init__(self,point=(0,0,0),width=1,height=1,solid=None,line=1,**common): - _Entity.__init__(self,**common) - self.point=point - self.width=width - self.height=height - self.solid=solid - self.line=line - def __str__(self): - result='' - points=[self.point,(self.point[0]+self.width,self.point[1],self.point[2]), - (self.point[0]+self.width,self.point[1]+self.height,self.point[2]), - (self.point[0],self.point[1]+self.height,self.point[2]),self.point] - if self.solid: - result+= Solid(points=points[:-1],parent=self.solid) - if self.line: - for i in range(4): - result+= Line(points=[points[i],points[i+1]],parent=self) - return result[1:] + """Rectangle, creates lines.""" + def __init__(self,point=(0,0,0),width=1,height=1,solid=None,line=1,**common): + _Entity.__init__(self,**common) + self.point=point + self.width=width + self.height=height + self.solid=solid + self.line=line + def __str__(self): + result='' + points=[self.point,(self.point[0]+self.width,self.point[1],self.point[2]), + (self.point[0]+self.width,self.point[1]+self.height,self.point[2]), + (self.point[0],self.point[1]+self.height,self.point[2]),self.point] + if self.solid: + result+= Solid(points=points[:-1],parent=self.solid) + if self.line: + for i in range(4): + result+= Line(points=[points[i],points[i+1]],parent=self) + return result[1:] #----------------------------------------------- class LineList(_Entity): - """Like polyline, but built of individual lines.""" - def __init__(self,points=[],org_point=[0,0,0],closed=0,**common): - _Entity.__init__(self,**common) - self.closed=closed - self.points=copy.copy(points) - def __str__(self): - if self.closed: - points=self.points+[self.points[0]] - else: points=self.points - result='' - for i in range(len(points)-1): - result+= Line(points=[points[i][0],points[i+1][0]],parent=self) - return result[1:] + """Like polyline, but built of individual lines.""" + def __init__(self,points=[],org_point=[0,0,0],closed=0,**common): + _Entity.__init__(self,**common) + self.closed=closed + self.points=copy.copy(points) + def __str__(self): + if self.closed: + points=self.points+[self.points[0]] + else: points=self.points + result='' + for i in range(len(points)-1): + result+= Line(points=[points[i][0],points[i+1][0]],parent=self) + return result[1:] #----------------------------------------------------- def test(): - #Blocks - b=Block('test') - b.append(Solid(points=[(0,0,0),(1,0,0),(1,1,0),(0,1,0)],color=1)) - b.append(Arc(center=(1,0,0),color=2)) - - #Drawing - d=Drawing() - #tables - d.blocks.append(b) #table blocks - d.styles.append(Style()) #table styles - d.views.append(View('Normal')) #table view - d.views.append(ViewByWindow('Window',leftBottom=(1,0),rightTop=(2,1))) #idem - - #entities - d.append(Circle(center=(1,1,0),color=3)) - d.append(Face(points=[(0,0,0),(1,0,0),(1,1,0),(0,1,0)],color=4)) - d.append(Insert('test',point=(3,3,3),cols=5,colspacing=2)) - d.append(Line(points=[(0,0,0),(1,1,1)])) - d.append(Mtext('Click on Ads\nmultiple lines with mtext',point=(1,1,1),color=5,rotation=90)) - d.append(Text('Please donate!',point=(3,0,1))) - #d.append(Rectangle(point=(2,2,2),width=4,height=3,color=6,solid=Solid(color=2))) - d.append(Solid(points=[(4,4,0),(5,4,0),(7,8,0),(9,9,0)],color=3)) - #d.append(PolyLine(points=[(1,1,1),(2,1,1),(2,2,1),(1,2,1)],flag=1,color=1)) - - #d.saveas('c:\\test.dxf') - d.saveas('test.dxf') + #Blocks + b=Block('test') + b.append(Solid(points=[(0,0,0),(1,0,0),(1,1,0),(0,1,0)],color=1)) + b.append(Arc(center=(1,0,0),color=2)) + + #Drawing + d=Drawing() + #tables + d.blocks.append(b) #table blocks + d.styles.append(Style()) #table styles + d.views.append(View('Normal')) #table view + d.views.append(ViewByWindow('Window',leftBottom=(1,0),rightTop=(2,1))) #idem + + #entities + d.append(Circle(center=(1,1,0),color=3)) + d.append(Face(points=[(0,0,0),(1,0,0),(1,1,0),(0,1,0)],color=4)) + d.append(Insert('test',point=(3,3,3),cols=5,colspacing=2)) + d.append(Line(points=[(0,0,0),(1,1,1)])) + d.append(Mtext('Click on Ads\nmultiple lines with mtext',point=(1,1,1),color=5,rotation=90)) + d.append(Text('Please donate!',point=(3,0,1))) + #d.append(Rectangle(point=(2,2,2),width=4,height=3,color=6,solid=Solid(color=2))) + d.append(Solid(points=[(4,4,0),(5,4,0),(7,8,0),(9,9,0)],color=3)) + #d.append(PolyLine(points=[(1,1,1),(2,1,1),(2,2,1),(1,2,1)],flag=1,color=1)) + + #d.saveas('c:\\test.dxf') + d.saveas('test.dxf') #----------------------------------------------------- if __name__=='__main__': - if not copy: - Draw.PupMenu('Error%t|This script requires a full python install') - else: test() + if not copy: + Draw.PupMenu('Error%t|This script requires a full python install') + else: test() diff --git a/io_export_dxf/model/model.py b/io_export_dxf/model/model.py index 54e12f3a63d6c386b2c1b8ab4fb36d3087ea034c..698f5102514df7e58971545461c947d4770c5dc1 100644 --- a/io_export_dxf/model/model.py +++ b/io_export_dxf/model/model.py @@ -1,36 +1,36 @@ class DxfDrawing(object): - """ - Represents intermediate model of DXF drawing. It is useful in iterating - through exported object and for easy change the DXF handling library. - """ - def __init__(self): - self._entities = {} - self._layers = {} - self._views = [] - self._vports = [] - self._blocks = [] - - def isEmpty(self): - return len(self._entities) == 0 - - def addEntity(self, type, **kwargs): - if type not in self._entities: - self._entities[type] = [] - self._entities[type].append(kwargs) - - def addLayer(self, name, color): - self._layers[name] = color - - def containsLayer(self, name): - return name in self._layers - - def addBlock(self, block): - self._blocks.append(block) - - def containsBlock(self, blockname): - return blockname in self._blocks - - def convert(self, **kwargs): - """ Converts this drawing into DXF representation object """ - raise NotImplementedError() + """ + Represents intermediate model of DXF drawing. It is useful in iterating + through exported object and for easy change the DXF handling library. + """ + def __init__(self): + self._entities = {} + self._layers = {} + self._views = [] + self._vports = [] + self._blocks = [] + + def isEmpty(self): + return len(self._entities) == 0 + + def addEntity(self, type, **kwargs): + if type not in self._entities: + self._entities[type] = [] + self._entities[type].append(kwargs) + + def addLayer(self, name, color): + self._layers[name] = color + + def containsLayer(self, name): + return name in self._layers + + def addBlock(self, block): + self._blocks.append(block) + + def containsBlock(self, blockname): + return blockname in self._blocks + + def convert(self, **kwargs): + """ Converts this drawing into DXF representation object """ + raise NotImplementedError() diff --git a/io_export_dxf/test2.txt b/io_export_dxf/test2.txt index fd95ef1c0bfdefabde3d01df3919dd2927aa88c9..8ccff989c8623b967c159616b2e701bf2093286b 100644 --- a/io_export_dxf/test2.txt +++ b/io_export_dxf/test2.txt @@ -1 +1 @@ -migius commit test 2b \ No newline at end of file +migius commit test 2b diff --git a/io_mesh_atomic/utility_gui.py b/io_mesh_atomic/utility_gui.py index 97395036f99c6c894efcfab86a2210ea63b57e1c..295d1490fde3661f059e9106991894dd9bb64a5a 100644 --- a/io_mesh_atomic/utility_gui.py +++ b/io_mesh_atomic/utility_gui.py @@ -418,4 +418,3 @@ class SticksAllSmallerButton(Operator): None, 1.0/scn.sticks_all) return {'FINISHED'} - diff --git a/io_mesh_uv_layout/export_uv_eps.py b/io_mesh_uv_layout/export_uv_eps.py index 3280cefa31ca6497620d179ddd4e24534238329e..45f64bb7b7da08211c8e44e790e1afdfffb5fccc 100644 --- a/io_mesh_uv_layout/export_uv_eps.py +++ b/io_mesh_uv_layout/export_uv_eps.py @@ -89,4 +89,4 @@ def draw_polygon_path(uvs, width, height): def footer(): yield "showpage\n" - yield "%%EOF\n" \ No newline at end of file + yield "%%EOF\n" diff --git a/io_mesh_uv_layout/export_uv_svg.py b/io_mesh_uv_layout/export_uv_svg.py index d00f940266364a673d6ff89341834bc9486cbb3c..8aba21427dc25b85e6d6ddc06b84e612e8a1181e 100644 --- a/io_mesh_uv_layout/export_uv_svg.py +++ b/io_mesh_uv_layout/export_uv_svg.py @@ -61,4 +61,4 @@ def get_color_string(color): def footer(): yield '\n' - yield '</svg>\n' \ No newline at end of file + yield '</svg>\n' diff --git a/io_scene_gltf2/blender/exp/gltf2_blender_gather_drivers.py b/io_scene_gltf2/blender/exp/gltf2_blender_gather_drivers.py index 2a88597119c850e14ce1137ee3b487f494b707ac..b176ca45c391161f1f6b9fd57e6b9b02b504c3a8 100644 --- a/io_scene_gltf2/blender/exp/gltf2_blender_gather_drivers.py +++ b/io_scene_gltf2/blender/exp/gltf2_blender_gather_drivers.py @@ -29,7 +29,7 @@ def get_sk_drivers(blender_armature): continue # child.data can be an armature - which has no shapekeys if not hasattr(child.data, 'shape_keys'): - continue + continue if not child.data.shape_keys: continue if not child.data.shape_keys.animation_data: diff --git a/io_scene_gltf2/blender/imp/gltf2_blender_scene.py b/io_scene_gltf2/blender/imp/gltf2_blender_scene.py index ca2f8052732e7bac1b8787dfbc6bd3bd21867873..3c2a8619d25fc83cc090c38e533ae8680b29863d 100755 --- a/io_scene_gltf2/blender/imp/gltf2_blender_scene.py +++ b/io_scene_gltf2/blender/imp/gltf2_blender_scene.py @@ -91,4 +91,3 @@ class BlenderScene(): vnode = gltf.vnodes[vnode.children[0]] bpy.context.view_layer.objects.active = vnode.blender_object - diff --git a/magic_uv/lib/bglx.py b/magic_uv/lib/bglx.py index 24200caf12cdf29cb12be537e7bd4c8ec21e198f..6bc885c6406e2c1cfd1721195fc0c4bfaabebaf2 100644 --- a/magic_uv/lib/bglx.py +++ b/magic_uv/lib/bglx.py @@ -272,4 +272,3 @@ def glTexParameteri(target, pname, param): def glTexEnvi(target, pname, param): pass - diff --git a/materials_library_vx/categories.txt b/materials_library_vx/categories.txt index e5970daf1231c33587bc5162e68907fe58ea3622..fce9151ef471a0e61e755369b07469da8a69d23b 100644 --- a/materials_library_vx/categories.txt +++ b/materials_library_vx/categories.txt @@ -68,4 +68,4 @@ "Metallic Paint Clean" ] ] -] \ No newline at end of file +] diff --git a/mesh_inset/__init__.py b/mesh_inset/__init__.py index 9f7cf1b877c04a87da176d04052d789d04acc0f5..4dbd84721da65ba7701a535bf0c8e5c898196236 100644 --- a/mesh_inset/__init__.py +++ b/mesh_inset/__init__.py @@ -200,7 +200,7 @@ class MESH_OT_InsetStraightSkeleton(bpy.types.Operator): obj = bpy.context.active_object mesh = obj.data do_inset(mesh, self.inset_amount, self.inset_height, self.region, - self.quadrangulate) + self.quadrangulate) bpy.ops.object.editmode_toggle() bpy.ops.object.editmode_toggle() @@ -246,7 +246,7 @@ def calc_select_center(context): center = center / n world_center = ob.matrix_world @ center world_center_2d = view3d_utils.location_3d_to_region_2d( \ - context.region, context.region_data, world_center) + context.region, context.region_data, world_center) return (world_center_2d, world_center) def do_inset(mesh, amount, height, region, quadrangulate): diff --git a/mesh_snap_utilities_line/snap_context_l/utils_projection.py b/mesh_snap_utilities_line/snap_context_l/utils_projection.py index a9b0f0216acbc00d84b04ef7d6a6e82e7e711c6e..b941f7db366fdb56632af8de34247705bd196c36 100644 --- a/mesh_snap_utilities_line/snap_context_l/utils_projection.py +++ b/mesh_snap_utilities_line/snap_context_l/utils_projection.py @@ -214,4 +214,3 @@ def intersect_ray_segment_fac(v0, v1, ray_direction, ray_origin): c = n - t cray = c.cross(ray_direction) return cray.dot(n) / nlen - diff --git a/mesh_tools/mesh_offset_edges.py b/mesh_tools/mesh_offset_edges.py index 302483046a7e0e25b3605752823b2435f94cb227..1471d256568277317405cbd99d4841fbf52c4c59 100644 --- a/mesh_tools/mesh_offset_edges.py +++ b/mesh_tools/mesh_offset_edges.py @@ -8,7 +8,7 @@ # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License @@ -20,7 +20,7 @@ bl_info = { "name": "Offset Edges", "author": "Hidesato Ikeya, Veezen fix 2.8 (temporary)", - #i tried edit newest version, but got some errors, works only on 0,2,6 + #i tried edit newest version, but got some errors, works only on 0,2,6 "version": (0, 2, 6), "blender": (2, 80, 0), "location": "VIEW3D > Edge menu(CTRL-E) > Offset Edges", diff --git a/node_arrange.py b/node_arrange.py index e7b03c57961765a4de429d5a9e9ffbb72d937093..6d3ed807bce6d95862aa1b27c1c6e0ad62176180 100644 --- a/node_arrange.py +++ b/node_arrange.py @@ -17,17 +17,17 @@ # ##### END GPL LICENSE BLOCK ##### bl_info = { - "name": "Node Arrange", - "author": "JuhaW", - "version": (0, 2, 2), - "blender": (2, 80, 4), - "location": "Node Editor > Properties > Trees", - "description": "Node Tree Arrangement Tools", - "warning": "", + "name": "Node Arrange", + "author": "JuhaW", + "version": (0, 2, 2), + "blender": (2, 80, 4), + "location": "Node Editor > Properties > Trees", + "description": "Node Tree Arrangement Tools", + "warning": "", "doc_url": "https://docs.blender.org/manual/en/dev/addons/" "node/node_arrange.html", - "tracker_url": "https://github.com/JuhaW/NodeArrange/issues", - "category": "Node" + "tracker_url": "https://github.com/JuhaW/NodeArrange/issues", + "category": "Node" } @@ -129,406 +129,406 @@ class NA_OT_AlignNodes(Operator): return {'FINISHED'} class values(): - average_y = 0 - x_last = 0 - margin_x = 100 - mat_name = "" - margin_y = 20 + average_y = 0 + x_last = 0 + margin_x = 100 + mat_name = "" + margin_y = 20 class NA_PT_NodePanel(Panel): - bl_label = "Node Arrange" - bl_space_type = "NODE_EDITOR" - bl_region_type = "UI" - bl_category = "Arrange" - - def draw(self, context): - if context.active_node is not None: - layout = self.layout - row = layout.row() - col = layout.column - row.operator('node.button') - - row = layout.row() - row.prop(bpy.context.scene, 'nodemargin_x', text="Margin x") - row = layout.row() - row.prop(bpy.context.scene, 'nodemargin_y', text="Margin y") - row = layout.row() - row.prop(context.scene, 'node_center', text="Center nodes") - - row = layout.row() - row.operator('node.na_align_nodes', text="Align to Selected") - - row = layout.row() - node = context.space_data.node_tree.nodes.active - if node and node.select: - row.prop(node, 'location', text = "Node X", index = 0) - row.prop(node, 'location', text = "Node Y", index = 1) - row = layout.row() - row.prop(node, 'width', text = "Node width") - - row = layout.row() - row.operator('node.button_odd') + bl_label = "Node Arrange" + bl_space_type = "NODE_EDITOR" + bl_region_type = "UI" + bl_category = "Arrange" + + def draw(self, context): + if context.active_node is not None: + layout = self.layout + row = layout.row() + col = layout.column + row.operator('node.button') + + row = layout.row() + row.prop(bpy.context.scene, 'nodemargin_x', text="Margin x") + row = layout.row() + row.prop(bpy.context.scene, 'nodemargin_y', text="Margin y") + row = layout.row() + row.prop(context.scene, 'node_center', text="Center nodes") + + row = layout.row() + row.operator('node.na_align_nodes', text="Align to Selected") + + row = layout.row() + node = context.space_data.node_tree.nodes.active + if node and node.select: + row.prop(node, 'location', text = "Node X", index = 0) + row.prop(node, 'location', text = "Node Y", index = 1) + row = layout.row() + row.prop(node, 'width', text = "Node width") + + row = layout.row() + row.operator('node.button_odd') class NA_OT_NodeButton(Operator): - '''Arrange Connected Nodes/Arrange All Nodes''' - bl_idname = 'node.button' - bl_label = 'Arrange All Nodes' + '''Arrange Connected Nodes/Arrange All Nodes''' + bl_idname = 'node.button' + bl_label = 'Arrange All Nodes' - def execute(self, context): - nodemargin(self, context) - bpy.context.space_data.node_tree.nodes.update() - bpy.ops.node.view_all() + def execute(self, context): + nodemargin(self, context) + bpy.context.space_data.node_tree.nodes.update() + bpy.ops.node.view_all() - return {'FINISHED'} + return {'FINISHED'} - # not sure this is doing what you expect. - # blender.org/api/blender_python_api_current/bpy.types.Operator.html#invoke - def invoke(self, context, value): - values.mat_name = bpy.context.space_data.node_tree - nodemargin(self, context) - return {'FINISHED'} + # not sure this is doing what you expect. + # blender.org/api/blender_python_api_current/bpy.types.Operator.html#invoke + def invoke(self, context, value): + values.mat_name = bpy.context.space_data.node_tree + nodemargin(self, context) + return {'FINISHED'} class NA_OT_NodeButtonOdd(Operator): - 'Show the nodes for this material' - bl_idname = 'node.button_odd' - bl_label = 'Select Unlinked' + 'Show the nodes for this material' + bl_idname = 'node.button_odd' + bl_label = 'Select Unlinked' - def execute(self, context): - values.mat_name = bpy.context.space_data.node_tree - #mat = bpy.context.object.active_material - nodes_iterate(context.space_data.node_tree, False) - return {'FINISHED'} + def execute(self, context): + values.mat_name = bpy.context.space_data.node_tree + #mat = bpy.context.object.active_material + nodes_iterate(context.space_data.node_tree, False) + return {'FINISHED'} class NA_OT_NodeButtonCenter(Operator): - 'Show the nodes for this material' - bl_idname = 'node.button_center' - bl_label = 'Center nodes (0,0)' + 'Show the nodes for this material' + bl_idname = 'node.button_center' + bl_label = 'Center nodes (0,0)' - def execute(self, context): - values.mat_name = "" # reset - mat = bpy.context.object.active_material - nodes_center(mat) - return {'FINISHED'} + def execute(self, context): + values.mat_name = "" # reset + mat = bpy.context.object.active_material + nodes_center(mat) + return {'FINISHED'} def nodemargin(self, context): - values.margin_x = context.scene.nodemargin_x - values.margin_y = context.scene.nodemargin_y + values.margin_x = context.scene.nodemargin_x + values.margin_y = context.scene.nodemargin_y - ntree = context.space_data.node_tree + ntree = context.space_data.node_tree - #first arrange nodegroups - n_groups = [] - for i in ntree.nodes: - if i.type == 'GROUP': - n_groups.append(i) + #first arrange nodegroups + n_groups = [] + for i in ntree.nodes: + if i.type == 'GROUP': + n_groups.append(i) - while n_groups: - j = n_groups.pop(0) - nodes_iterate(j.node_tree) - for i in j.node_tree.nodes: - if i.type == 'GROUP': - n_groups.append(i) + while n_groups: + j = n_groups.pop(0) + nodes_iterate(j.node_tree) + for i in j.node_tree.nodes: + if i.type == 'GROUP': + n_groups.append(i) - nodes_iterate(ntree) + nodes_iterate(ntree) - # arrange nodes + this center nodes together - if context.scene.node_center: - nodes_center(ntree) + # arrange nodes + this center nodes together + if context.scene.node_center: + nodes_center(ntree) class NA_OT_ArrangeNodesOp(bpy.types.Operator): - bl_idname = 'node.arrange_nodetree' - bl_label = 'Nodes Private Op' - - mat_name : bpy.props.StringProperty() - margin_x : bpy.props.IntProperty(default=120) - margin_y : bpy.props.IntProperty(default=120) - - def nodemargin2(self, context): - mat = None - mat_found = bpy.data.materials.get(self.mat_name) - if self.mat_name and mat_found: - mat = mat_found - #print(mat) - - if not mat: - return - else: - values.mat_name = self.mat_name - scn = context.scene - scn.nodemargin_x = self.margin_x - scn.nodemargin_y = self.margin_y - nodes_iterate(mat) - if scn.node_center: - nodes_center(mat) - - def execute(self, context): - self.nodemargin2(context) - return {'FINISHED'} - - -def outputnode_search(ntree): # return node/None - - outputnodes = [] - for node in ntree.nodes: - if not node.outputs: - for input in node.inputs: - if input.is_linked: - outputnodes.append(node) - break - - if not outputnodes: - print("No output node found") - return None - return outputnodes - - -############################################################### -def nodes_iterate(ntree, arrange=True): - - nodeoutput = outputnode_search(ntree) - if nodeoutput is None: - #print ("nodeoutput is None") - return None - a = [] - a.append([]) - for i in nodeoutput: - a[0].append(i) - - - level = 0 - - while a[level]: - a.append([]) - - for node in a[level]: - inputlist = [i for i in node.inputs if i.is_linked] - - if inputlist: - - for input in inputlist: - for nlinks in input.links: - node1 = nlinks.from_node - a[level + 1].append(node1) - - else: - pass + bl_idname = 'node.arrange_nodetree' + bl_label = 'Nodes Private Op' + + mat_name : bpy.props.StringProperty() + margin_x : bpy.props.IntProperty(default=120) + margin_y : bpy.props.IntProperty(default=120) + + def nodemargin2(self, context): + mat = None + mat_found = bpy.data.materials.get(self.mat_name) + if self.mat_name and mat_found: + mat = mat_found + #print(mat) + + if not mat: + return + else: + values.mat_name = self.mat_name + scn = context.scene + scn.nodemargin_x = self.margin_x + scn.nodemargin_y = self.margin_y + nodes_iterate(mat) + if scn.node_center: + nodes_center(mat) - level += 1 + def execute(self, context): + self.nodemargin2(context) + return {'FINISHED'} - del a[level] - level -= 1 - #remove duplicate nodes at the same level, first wins - for x, nodes in enumerate(a): - a[x] = list(OrderedDict(zip(a[x], repeat(None)))) +def outputnode_search(ntree): # return node/None - #remove duplicate nodes in all levels, last wins - top = level - for row1 in range(top, 1, -1): - for col1 in a[row1]: - for row2 in range(row1-1, 0, -1): - for col2 in a[row2]: - if col1 == col2: - a[row2].remove(col2) - break + outputnodes = [] + for node in ntree.nodes: + if not node.outputs: + for input in node.inputs: + if input.is_linked: + outputnodes.append(node) + break - """ - for x, i in enumerate(a): - print (x) - for j in i: - print (j) - #print() - """ - """ - #add node frames to nodelist - frames = [] - print ("Frames:") - print ("level:", level) - print ("a:",a) - for row in range(level, 0, -1): + if not outputnodes: + print("No output node found") + return None + return outputnodes - for i, node in enumerate(a[row]): - if node.parent: - print ("Frame found:", node.parent, node) - #if frame already added to the list ? - frame = node.parent - #remove node - del a[row][i] - if frame not in frames: - frames.append(frame) - #add frame to the same place than node was - a[row].insert(i, frame) - pprint.pprint(a) - """ - #return None - ######################################## +############################################################### +def nodes_iterate(ntree, arrange=True): + nodeoutput = outputnode_search(ntree) + if nodeoutput is None: + #print ("nodeoutput is None") + return None + a = [] + a.append([]) + for i in nodeoutput: + a[0].append(i) - if not arrange: - nodelist = [j for i in a for j in i] - nodes_odd(ntree, nodelist=nodelist) - return None + level = 0 - ######################################## + while a[level]: + a.append([]) - levelmax = level + 1 - level = 0 - values.x_last = 0 + for node in a[level]: + inputlist = [i for i in node.inputs if i.is_linked] - while level < levelmax: + if inputlist: - values.average_y = 0 - nodes = [x for x in a[level]] - #print ("level, nodes:", level, nodes) - nodes_arrange(nodes, level) + for input in inputlist: + for nlinks in input.links: + node1 = nlinks.from_node + a[level + 1].append(node1) - level = level + 1 - - return None + else: + pass + + level += 1 + + del a[level] + level -= 1 + + #remove duplicate nodes at the same level, first wins + for x, nodes in enumerate(a): + a[x] = list(OrderedDict(zip(a[x], repeat(None)))) + + #remove duplicate nodes in all levels, last wins + top = level + for row1 in range(top, 1, -1): + for col1 in a[row1]: + for row2 in range(row1-1, 0, -1): + for col2 in a[row2]: + if col1 == col2: + a[row2].remove(col2) + break + + """ + for x, i in enumerate(a): + print (x) + for j in i: + print (j) + #print() + """ + """ + #add node frames to nodelist + frames = [] + print ("Frames:") + print ("level:", level) + print ("a:",a) + for row in range(level, 0, -1): + + for i, node in enumerate(a[row]): + if node.parent: + print ("Frame found:", node.parent, node) + #if frame already added to the list ? + frame = node.parent + #remove node + del a[row][i] + if frame not in frames: + frames.append(frame) + #add frame to the same place than node was + a[row].insert(i, frame) + + pprint.pprint(a) + """ + #return None + ######################################## + + + + if not arrange: + nodelist = [j for i in a for j in i] + nodes_odd(ntree, nodelist=nodelist) + return None + + ######################################## + + levelmax = level + 1 + level = 0 + values.x_last = 0 + + while level < levelmax: + + values.average_y = 0 + nodes = [x for x in a[level]] + #print ("level, nodes:", level, nodes) + nodes_arrange(nodes, level) + + level = level + 1 + + return None ############################################################### def nodes_odd(ntree, nodelist): - nodes = ntree.nodes - for i in nodes: - i.select = False + nodes = ntree.nodes + for i in nodes: + i.select = False - a = [x for x in nodes if x not in nodelist] - # print ("odd nodes:",a) - for i in a: - i.select = True + a = [x for x in nodes if x not in nodelist] + # print ("odd nodes:",a) + for i in a: + i.select = True def nodes_arrange(nodelist, level): - parents = [] - for node in nodelist: - parents.append(node.parent) - node.parent = None - bpy.context.space_data.node_tree.nodes.update() + parents = [] + for node in nodelist: + parents.append(node.parent) + node.parent = None + bpy.context.space_data.node_tree.nodes.update() - #print ("nodes arrange def") - # node x positions + #print ("nodes arrange def") + # node x positions - widthmax = max([x.dimensions.x for x in nodelist]) - xpos = values.x_last - (widthmax + values.margin_x) if level != 0 else 0 - #print ("nodelist, xpos", nodelist,xpos) - values.x_last = xpos + widthmax = max([x.dimensions.x for x in nodelist]) + xpos = values.x_last - (widthmax + values.margin_x) if level != 0 else 0 + #print ("nodelist, xpos", nodelist,xpos) + values.x_last = xpos - # node y positions - x = 0 - y = 0 + # node y positions + x = 0 + y = 0 - for node in nodelist: + for node in nodelist: - if node.hide: - hidey = (node.dimensions.y / 2) - 8 - y = y - hidey - else: - hidey = 0 + if node.hide: + hidey = (node.dimensions.y / 2) - 8 + y = y - hidey + else: + hidey = 0 - node.location.y = y - y = y - values.margin_y - node.dimensions.y + hidey + node.location.y = y + y = y - values.margin_y - node.dimensions.y + hidey - node.location.x = xpos #if node.type != "FRAME" else xpos + 1200 + node.location.x = xpos #if node.type != "FRAME" else xpos + 1200 - y = y + values.margin_y + y = y + values.margin_y - center = (0 + y) / 2 - values.average_y = center - values.average_y + center = (0 + y) / 2 + values.average_y = center - values.average_y - #for node in nodelist: + #for node in nodelist: - #node.location.y -= values.average_y + #node.location.y -= values.average_y - for i, node in enumerate(nodelist): - node.parent = parents[i] + for i, node in enumerate(nodelist): + node.parent = parents[i] def nodetree_get(mat): - return mat.node_tree.nodes + return mat.node_tree.nodes def nodes_center(ntree): - bboxminx = [] - bboxmaxx = [] - bboxmaxy = [] - bboxminy = [] - - for node in ntree.nodes: - if not node.parent: - bboxminx.append(node.location.x) - bboxmaxx.append(node.location.x + node.dimensions.x) - bboxmaxy.append(node.location.y) - bboxminy.append(node.location.y - node.dimensions.y) - - # print ("bboxminy:",bboxminy) - bboxminx = min(bboxminx) - bboxmaxx = max(bboxmaxx) - bboxminy = min(bboxminy) - bboxmaxy = max(bboxmaxy) - center_x = (bboxminx + bboxmaxx) / 2 - center_y = (bboxminy + bboxmaxy) / 2 - ''' - print ("minx:",bboxminx) - print ("maxx:",bboxmaxx) - print ("miny:",bboxminy) - print ("maxy:",bboxmaxy) - - print ("bboxes:", bboxminx, bboxmaxx, bboxmaxy, bboxminy) - print ("center x:",center_x) - print ("center y:",center_y) - ''' - - x = 0 - y = 0 - - for node in ntree.nodes: - - if not node.parent: - node.location.x -= center_x - node.location.y += -center_y + bboxminx = [] + bboxmaxx = [] + bboxmaxy = [] + bboxminy = [] + + for node in ntree.nodes: + if not node.parent: + bboxminx.append(node.location.x) + bboxmaxx.append(node.location.x + node.dimensions.x) + bboxmaxy.append(node.location.y) + bboxminy.append(node.location.y - node.dimensions.y) + + # print ("bboxminy:",bboxminy) + bboxminx = min(bboxminx) + bboxmaxx = max(bboxmaxx) + bboxminy = min(bboxminy) + bboxmaxy = max(bboxmaxy) + center_x = (bboxminx + bboxmaxx) / 2 + center_y = (bboxminy + bboxmaxy) / 2 + ''' + print ("minx:",bboxminx) + print ("maxx:",bboxmaxx) + print ("miny:",bboxminy) + print ("maxy:",bboxmaxy) + + print ("bboxes:", bboxminx, bboxmaxx, bboxmaxy, bboxminy) + print ("center x:",center_x) + print ("center y:",center_y) + ''' + + x = 0 + y = 0 + + for node in ntree.nodes: + + if not node.parent: + node.location.x -= center_x + node.location.y += -center_y classes = [ - NA_PT_NodePanel, - NA_OT_NodeButton, - NA_OT_NodeButtonOdd, - NA_OT_NodeButtonCenter, - NA_OT_ArrangeNodesOp, + NA_PT_NodePanel, + NA_OT_NodeButton, + NA_OT_NodeButtonOdd, + NA_OT_NodeButtonCenter, + NA_OT_ArrangeNodesOp, NA_OT_AlignNodes ] def register(): - for c in classes: - bpy.utils.register_class(c) + for c in classes: + bpy.utils.register_class(c) - bpy.types.Scene.nodemargin_x = bpy.props.IntProperty(default=100, update=nodemargin) - bpy.types.Scene.nodemargin_y = bpy.props.IntProperty(default=20, update=nodemargin) - bpy.types.Scene.node_center = bpy.props.BoolProperty(default=True, update=nodemargin) + bpy.types.Scene.nodemargin_x = bpy.props.IntProperty(default=100, update=nodemargin) + bpy.types.Scene.nodemargin_y = bpy.props.IntProperty(default=20, update=nodemargin) + bpy.types.Scene.node_center = bpy.props.BoolProperty(default=True, update=nodemargin) def unregister(): - for c in classes: - bpy.utils.unregister_class(c) + for c in classes: + bpy.utils.unregister_class(c) - del bpy.types.Scene.nodemargin_x - del bpy.types.Scene.nodemargin_y - del bpy.types.Scene.node_center + del bpy.types.Scene.nodemargin_x + del bpy.types.Scene.nodemargin_y + del bpy.types.Scene.node_center if __name__ == "__main__": - register() + register() diff --git a/object_carver/__init__.py b/object_carver/__init__.py index 4c68ce0b25250ee285aa6a858ac7dcb2b35d9826..883d5b7667a5d88dcdba26247a2960a90db2676f 100644 --- a/object_carver/__init__.py +++ b/object_carver/__init__.py @@ -17,18 +17,18 @@ # ##### END GPL LICENSE BLOCK ##### bl_info = { - "name": "Carver", - "author": "Pixivore, Cedric LEPILLER, Ted Milker, Clarkx", - "description": "Multiple tools to carve or to create objects", - "version": (1, 2, 0), - "blender": (2, 80, 0), - "location": "3D View > Ctrl/Shift/x", - "warning": "", + "name": "Carver", + "author": "Pixivore, Cedric LEPILLER, Ted Milker, Clarkx", + "description": "Multiple tools to carve or to create objects", + "version": (1, 2, 0), + "blender": (2, 80, 0), + "location": "3D View > Ctrl/Shift/x", + "warning": "", "doc_url": "https://docs.blender.org/manual/en/dev/addons/" "object/carver.html", - "support": 'COMMUNITY', - "category": "Object" - } + "support": 'COMMUNITY', + "category": "Object" + } import bpy import imp @@ -61,249 +61,249 @@ imp.reload(carver_operator) # "or to create objects" # ) # -# #Icons : \blender-2.80\2.80\datafiles\icons -# #Todo: Create a new icon for Carver +# #Icons : \blender-2.80\2.80\datafiles\icons +# #Todo: Create a new icon for Carver # bl_icon = "ops.mesh.knife_tool" # bl_widget = None # bl_keymap = ( # ("carver.operator", {"type": 'LEFTMOUSE', "value": 'PRESS'}, None), -# ) +# ) # # def draw_settings(context, layout, tool): # layout.prop(tool.operator_properties, "carver") class CarverPreferences(AddonPreferences): - bl_idname = __name__ + bl_idname = __name__ - Enable_Tab_01: BoolProperty( - name="Info", - description="Some general information and settings about the add-on", - default=False - ) - Enable_Tab_02: BoolProperty( - name="Hotkeys", - description="List of the shortcuts used during carving", - default=False - ) - Key_Create: StringProperty( - name="Object creation", - description="Object creation", - maxlen=1, - default="C" - ) - Key_Update: StringProperty( - name="Auto Bevel Update", - description="Auto Bevel Update", - maxlen=1, - default="A", - ) - Key_Bool: StringProperty( - name="Boolean type", - description="Boolean operation type", - maxlen=1, - default="T", - ) - Key_Brush: StringProperty( - name="Brush Mode", - description="Brush Mode", - maxlen=1, - default="B", - ) - Key_Help: StringProperty( - name="Help display", - description="Help display", - maxlen=1, - default="H", - ) - Key_Instant: StringProperty( - name="Instantiate", - description="Instantiate object", - maxlen=1, - default="I", - ) - Key_Close: StringProperty( - name="Close polygonal shape", - description="Close polygonal shape", - maxlen=1, - default="X", - ) - Key_Apply: StringProperty( - name="Apply operation", - description="Apply operation", - maxlen=1, - default="Q", - ) - Key_Scale: StringProperty( - name="Scale object", - description="Scale object", - maxlen=1, - default="S", - ) - Key_Gapy: StringProperty( - name="Gap rows", - description="Scale gap between columns", - maxlen=1, - default="J", - ) - Key_Gapx: StringProperty( - name="Gap columns", - description="Scale gap between columns", - maxlen=1, - default="U", - ) - Key_Depth: StringProperty( - name="Depth", - description="Cursor depth or solidify pattern", - maxlen=1, - default="D", - ) - Key_BrushDepth: StringProperty( - name="Brush Depth", - description="Brush depth", - maxlen=1, - default="C", - ) - Key_Subadd: StringProperty( - name="Add subdivision", - description="Add subdivision", - maxlen=1, - default="X", - ) - Key_Subrem: StringProperty( - name="Remove subdivision", - description="Remove subdivision", - maxlen=1, - default="W", - ) - Key_Randrot: StringProperty( - name="Random rotation", - description="Random rotation", - maxlen=1, - default="R", - ) - ProfilePrefix: StringProperty( - name="Profile prefix", - description="Prefix to look for profiles with", - default="Carver_Profile-", - ) - LineWidth: IntProperty( - name="Line Width", - description="Thickness of the drawing lines", - default=1, - ) - Key_Snap: StringProperty( - name="Grid Snap", - description="Grid Snap", - maxlen=1, - default="G", - ) + Enable_Tab_01: BoolProperty( + name="Info", + description="Some general information and settings about the add-on", + default=False + ) + Enable_Tab_02: BoolProperty( + name="Hotkeys", + description="List of the shortcuts used during carving", + default=False + ) + Key_Create: StringProperty( + name="Object creation", + description="Object creation", + maxlen=1, + default="C" + ) + Key_Update: StringProperty( + name="Auto Bevel Update", + description="Auto Bevel Update", + maxlen=1, + default="A", + ) + Key_Bool: StringProperty( + name="Boolean type", + description="Boolean operation type", + maxlen=1, + default="T", + ) + Key_Brush: StringProperty( + name="Brush Mode", + description="Brush Mode", + maxlen=1, + default="B", + ) + Key_Help: StringProperty( + name="Help display", + description="Help display", + maxlen=1, + default="H", + ) + Key_Instant: StringProperty( + name="Instantiate", + description="Instantiate object", + maxlen=1, + default="I", + ) + Key_Close: StringProperty( + name="Close polygonal shape", + description="Close polygonal shape", + maxlen=1, + default="X", + ) + Key_Apply: StringProperty( + name="Apply operation", + description="Apply operation", + maxlen=1, + default="Q", + ) + Key_Scale: StringProperty( + name="Scale object", + description="Scale object", + maxlen=1, + default="S", + ) + Key_Gapy: StringProperty( + name="Gap rows", + description="Scale gap between columns", + maxlen=1, + default="J", + ) + Key_Gapx: StringProperty( + name="Gap columns", + description="Scale gap between columns", + maxlen=1, + default="U", + ) + Key_Depth: StringProperty( + name="Depth", + description="Cursor depth or solidify pattern", + maxlen=1, + default="D", + ) + Key_BrushDepth: StringProperty( + name="Brush Depth", + description="Brush depth", + maxlen=1, + default="C", + ) + Key_Subadd: StringProperty( + name="Add subdivision", + description="Add subdivision", + maxlen=1, + default="X", + ) + Key_Subrem: StringProperty( + name="Remove subdivision", + description="Remove subdivision", + maxlen=1, + default="W", + ) + Key_Randrot: StringProperty( + name="Random rotation", + description="Random rotation", + maxlen=1, + default="R", + ) + ProfilePrefix: StringProperty( + name="Profile prefix", + description="Prefix to look for profiles with", + default="Carver_Profile-", + ) + LineWidth: IntProperty( + name="Line Width", + description="Thickness of the drawing lines", + default=1, + ) + Key_Snap: StringProperty( + name="Grid Snap", + description="Grid Snap", + maxlen=1, + default="G", + ) - def draw(self, context): - scene = context.scene - layout = self.layout + def draw(self, context): + scene = context.scene + layout = self.layout - icon_1 = "TRIA_RIGHT" if not self.Enable_Tab_01 else "TRIA_DOWN" - box = layout.box() + icon_1 = "TRIA_RIGHT" if not self.Enable_Tab_01 else "TRIA_DOWN" + box = layout.box() - box.prop(self, "Enable_Tab_01", text="Info and Settings", emboss=False, icon=icon_1) - if self.Enable_Tab_01: - box.label(text="Carver Operator:", icon="LAYER_ACTIVE") - box.label(text="Select a Mesh Object and press [CTRL]+[SHIFT]+[X] to carve", - icon="LAYER_USED") - box.label(text="To finish carving press [ESC] or [RIGHT CLICK]", - icon="LAYER_USED") - box.prop(self, "ProfilePrefix", text="Profile prefix") - row = box.row(align=True) - row.label(text="Line width:") - row.prop(self, "LineWidth", text="") + box.prop(self, "Enable_Tab_01", text="Info and Settings", emboss=False, icon=icon_1) + if self.Enable_Tab_01: + box.label(text="Carver Operator:", icon="LAYER_ACTIVE") + box.label(text="Select a Mesh Object and press [CTRL]+[SHIFT]+[X] to carve", + icon="LAYER_USED") + box.label(text="To finish carving press [ESC] or [RIGHT CLICK]", + icon="LAYER_USED") + box.prop(self, "ProfilePrefix", text="Profile prefix") + row = box.row(align=True) + row.label(text="Line width:") + row.prop(self, "LineWidth", text="") - icon_2 = "TRIA_RIGHT" if not self.Enable_Tab_02 else "TRIA_DOWN" - box = layout.box() - box.prop(self, "Enable_Tab_02", text="Keys", emboss=False, icon=icon_2) - if self.Enable_Tab_02: - split = box.split(align=True) - box = split.box() - col = box.column(align=True) - col.label(text="Object Creation:") - col.prop(self, "Key_Create", text="") - col.label(text="Auto bevel update:") - col.prop(self, "Key_Update", text="") - col.label(text="Boolean operation type:") - col.prop(self, "Key_Bool", text="") - col.label(text="Brush Depth:") - col.prop(self, "Key_BrushDepth", text="") + icon_2 = "TRIA_RIGHT" if not self.Enable_Tab_02 else "TRIA_DOWN" + box = layout.box() + box.prop(self, "Enable_Tab_02", text="Keys", emboss=False, icon=icon_2) + if self.Enable_Tab_02: + split = box.split(align=True) + box = split.box() + col = box.column(align=True) + col.label(text="Object Creation:") + col.prop(self, "Key_Create", text="") + col.label(text="Auto bevel update:") + col.prop(self, "Key_Update", text="") + col.label(text="Boolean operation type:") + col.prop(self, "Key_Bool", text="") + col.label(text="Brush Depth:") + col.prop(self, "Key_BrushDepth", text="") - box = split.box() - col = box.column(align=True) - col.label(text="Brush Mode:") - col.prop(self, "Key_Brush", text="") - col.label(text="Help display:") - col.prop(self, "Key_Help", text="") - col.label(text="Instantiate object:") - col.prop(self, "Key_Instant", text="") - col.label(text="Random rotation:") - col.prop(self, "Key_Randrot", text="") + box = split.box() + col = box.column(align=True) + col.label(text="Brush Mode:") + col.prop(self, "Key_Brush", text="") + col.label(text="Help display:") + col.prop(self, "Key_Help", text="") + col.label(text="Instantiate object:") + col.prop(self, "Key_Instant", text="") + col.label(text="Random rotation:") + col.prop(self, "Key_Randrot", text="") - box = split.box() - col = box.column(align=True) - col.label(text="Close polygonal shape:") - col.prop(self, "Key_Close", text="") - col.label(text="Apply operation:") - col.prop(self, "Key_Apply", text="") - col.label(text="Scale object:") - col.prop(self, "Key_Scale", text="") - col.label(text="Subdiv add:") - col.prop(self, "Key_Subadd", text="") + box = split.box() + col = box.column(align=True) + col.label(text="Close polygonal shape:") + col.prop(self, "Key_Close", text="") + col.label(text="Apply operation:") + col.prop(self, "Key_Apply", text="") + col.label(text="Scale object:") + col.prop(self, "Key_Scale", text="") + col.label(text="Subdiv add:") + col.prop(self, "Key_Subadd", text="") - box = split.box() - col = box.column(align=True) - col.label(text="Gap rows:") - col.prop(self, "Key_Gapy", text="") - col.label(text="Gap columns:") - col.prop(self, "Key_Gapx", text="") - col.label(text="Depth / Solidify:") - col.prop(self, "Key_Depth", text="") - col.label(text="Subdiv Remove:") - col.prop(self, "Key_Subrem", text="") + box = split.box() + col = box.column(align=True) + col.label(text="Gap rows:") + col.prop(self, "Key_Gapy", text="") + col.label(text="Gap columns:") + col.prop(self, "Key_Gapx", text="") + col.label(text="Depth / Solidify:") + col.prop(self, "Key_Depth", text="") + col.label(text="Subdiv Remove:") + col.prop(self, "Key_Subrem", text="") - box = split.box() - col = box.column(align=True) - col.label(text="Grid Snap:") - col.prop(self, "Key_Snap", text="") + box = split.box() + col = box.column(align=True) + col.label(text="Grid Snap:") + col.prop(self, "Key_Snap", text="") addon_keymaps = [] def register(): - print("Registered Carver") + print("Registered Carver") - bpy.utils.register_class(CarverPreferences) - # Todo : Add an icon in the toolbat - # bpy.utils.register_tool(CarverTool, separator=True, group=True) - carver_operator.register() + bpy.utils.register_class(CarverPreferences) + # Todo : Add an icon in the toolbat + # bpy.utils.register_tool(CarverTool, separator=True, group=True) + carver_operator.register() - # add keymap entry - kcfg = bpy.context.window_manager.keyconfigs.addon - if kcfg: - km = kcfg.keymaps.new(name='3D View', space_type='VIEW_3D') - kmi = km.keymap_items.new("carver.operator", 'X', 'PRESS', shift=True, ctrl=True) - addon_keymaps.append((km, kmi)) + # add keymap entry + kcfg = bpy.context.window_manager.keyconfigs.addon + if kcfg: + km = kcfg.keymaps.new(name='3D View', space_type='VIEW_3D') + kmi = km.keymap_items.new("carver.operator", 'X', 'PRESS', shift=True, ctrl=True) + addon_keymaps.append((km, kmi)) def unregister(): - # Todo : Add an icon in the toolbat - # bpy.utils.unregister_tool(CarverTool) - carver_operator.unregister() - bpy.utils.unregister_class(CarverPreferences) + # Todo : Add an icon in the toolbat + # bpy.utils.unregister_tool(CarverTool) + carver_operator.unregister() + bpy.utils.unregister_class(CarverPreferences) - print("Unregistered Carver") + print("Unregistered Carver") - # remove keymap entry - for km, kmi in addon_keymaps: - km.keymap_items.remove(kmi) - addon_keymaps.clear() + # remove keymap entry + for km, kmi in addon_keymaps: + km.keymap_items.remove(kmi) + addon_keymaps.clear() if __name__ == "__main__": - register() + register() diff --git a/object_carver/carver_draw.py b/object_carver/carver_draw.py index 922807ee5e09b6e9573d5f1a76c6bbea5f32f4b5..f2a3aadc7831d532afd35d37011666ede5b2a7f9 100644 --- a/object_carver/carver_draw.py +++ b/object_carver/carver_draw.py @@ -6,494 +6,494 @@ import numpy as np import gpu from gpu_extras.batch import batch_for_shader from math import( - cos, - sin, - ceil, - floor, - ) + cos, + sin, + ceil, + floor, + ) from bpy_extras.view3d_utils import ( - region_2d_to_location_3d, - location_3d_to_region_2d, + region_2d_to_location_3d, + location_3d_to_region_2d, ) from .carver_utils import ( - draw_circle, - draw_shader, - objDiagonal, - mini_grid, - ) + draw_circle, + draw_shader, + objDiagonal, + mini_grid, + ) from mathutils import ( - Color, - Euler, - Vector, - Quaternion, + Color, + Euler, + Vector, + Quaternion, ) def get_text_info(self, context, help_txt): - """ Return the dimensions of each part of the text """ + """ Return the dimensions of each part of the text """ - #Extract the longest first option in sublist - max_option = max(list(blf.dimensions(0, row[0])[0] for row in help_txt)) + #Extract the longest first option in sublist + max_option = max(list(blf.dimensions(0, row[0])[0] for row in help_txt)) - #Extract the longest key in sublist - max_key = max(list(blf.dimensions(0, row[1])[0] for row in help_txt)) + #Extract the longest key in sublist + max_key = max(list(blf.dimensions(0, row[1])[0] for row in help_txt)) - #Space between option and key with a comma separator (" : ") - comma = blf.dimensions(0, "_:_")[0] + #Space between option and key with a comma separator (" : ") + comma = blf.dimensions(0, "_:_")[0] - #Get a default height for all the letters - line_height = (blf.dimensions(0, "gM")[1] * 1.45) + #Get a default height for all the letters + line_height = (blf.dimensions(0, "gM")[1] * 1.45) - #Get the total height of the text - bloc_height = 0 - for row in help_txt: - bloc_height += line_height + #Get the total height of the text + bloc_height = 0 + for row in help_txt: + bloc_height += line_height - return(help_txt, bloc_height, max_option, max_key, comma) + return(help_txt, bloc_height, max_option, max_key, comma) def draw_string(self, color1, color2, left, bottom, text, max_option, divide = 1): - """ Draw the text like 'option : key' or just 'option' """ - - font_id = 0 - ui_scale = bpy.context.preferences.system.ui_scale - - blf.enable(font_id,blf.SHADOW) - blf.shadow(font_id, 0, 0.0, 0.0, 0.0, 1.0) - blf.shadow_offset(font_id,2,-2) - line_height = (blf.dimensions(font_id, "gM")[1] * 1.45) - y_offset = 5 - - # Test if the text is a list formatted like : ('option', 'key') - if isinstance(text,list): - spacer_text = " : " - spacer_width = blf.dimensions(font_id, spacer_text)[0] - for string in text: - blf.position(font_id, (left), (bottom + y_offset), 0) - blf.color(font_id, *color1) - blf.draw(font_id, string[0]) - blf.position(font_id, (left + max_option), (bottom + y_offset), 0) - blf.draw(font_id, spacer_text) - blf.color(font_id, *color2) - blf.position(font_id, (left + max_option + spacer_width), (bottom + y_offset), 0) - blf.draw(font_id, string[1]) - y_offset += line_height - else: - # The text is formatted like : ('option') - blf.position(font_id, left, (bottom + y_offset), 0) - blf.color(font_id, *color1) - blf.draw(font_id, text) - y_offset += line_height - - blf.disable(font_id,blf.SHADOW) + """ Draw the text like 'option : key' or just 'option' """ + + font_id = 0 + ui_scale = bpy.context.preferences.system.ui_scale + + blf.enable(font_id,blf.SHADOW) + blf.shadow(font_id, 0, 0.0, 0.0, 0.0, 1.0) + blf.shadow_offset(font_id,2,-2) + line_height = (blf.dimensions(font_id, "gM")[1] * 1.45) + y_offset = 5 + + # Test if the text is a list formatted like : ('option', 'key') + if isinstance(text,list): + spacer_text = " : " + spacer_width = blf.dimensions(font_id, spacer_text)[0] + for string in text: + blf.position(font_id, (left), (bottom + y_offset), 0) + blf.color(font_id, *color1) + blf.draw(font_id, string[0]) + blf.position(font_id, (left + max_option), (bottom + y_offset), 0) + blf.draw(font_id, spacer_text) + blf.color(font_id, *color2) + blf.position(font_id, (left + max_option + spacer_width), (bottom + y_offset), 0) + blf.draw(font_id, string[1]) + y_offset += line_height + else: + # The text is formatted like : ('option') + blf.position(font_id, left, (bottom + y_offset), 0) + blf.color(font_id, *color1) + blf.draw(font_id, text) + y_offset += line_height + + blf.disable(font_id,blf.SHADOW) # Opengl draw on screen def draw_callback_px(self, context): - font_id = 0 - region = context.region - UIColor = (0.992, 0.5518, 0.0, 1.0) - - # Cut Type - RECTANGLE = 0 - LINE = 1 - CIRCLE = 2 - self.carver_prefs = context.preferences.addons[__package__].preferences - - # Color - color1 = (1.0, 1.0, 1.0, 1.0) - color2 = UIColor - - #The mouse is outside the active region - if not self.in_view_3d: - color1 = color2 = (1.0, 0.2, 0.1, 1.0) - - # Primitives type - PrimitiveType = "Rectangle" - if self.CutType == CIRCLE: - PrimitiveType = "Circle" - if self.CutType == LINE: - PrimitiveType = "Line" - - # Width screen - overlap = context.preferences.system.use_region_overlap - - t_panel_width = 0 - if overlap: - for region in context.area.regions: - if region.type == 'TOOLS': - t_panel_width = region.width - - # Initial position - region_width = int(region.width / 2.0) - y_txt = 10 - - - # Draw the center command from bottom to top - - # Get the size of the text - text_size = 18 if region.width >= 850 else 12 - ui_scale = bpy.context.preferences.system.ui_scale - blf.size(0, round(text_size * ui_scale), 72) - - # Help Display - if (self.ObjectMode is False) and (self.ProfileMode is False): - - # Depth Cursor - TypeStr = "Cursor Depth [" + self.carver_prefs.Key_Depth + "]" - BoolStr = "(ON)" if self.snapCursor else "(OFF)" - help_txt = [[TypeStr, BoolStr]] - - # Close poygonal shape - if self.CreateMode and self.CutType == LINE: - TypeStr = "Close [" + self.carver_prefs.Key_Close + "]" - BoolStr = "(ON)" if self.Closed else "(OFF)" - help_txt += [[TypeStr, BoolStr]] - - if self.CreateMode is False: - # Apply Booleans - TypeStr = "Apply Operations [" + self.carver_prefs.Key_Apply + "]" - BoolStr = "(OFF)" if self.dont_apply_boolean else "(ON)" - help_txt += [[TypeStr, BoolStr]] - - #Auto update for bevel - TypeStr = "Bevel Update [" + self.carver_prefs.Key_Update + "]" - BoolStr = "(ON)" if self.Auto_BevelUpdate else "(OFF)" - help_txt += [[TypeStr, BoolStr]] - - # Circle subdivisions - if self.CutType == CIRCLE: - TypeStr = "Subdivisions [" + self.carver_prefs.Key_Subrem + "][" + self.carver_prefs.Key_Subadd + "]" - BoolStr = str((int(360 / self.stepAngle[self.step]))) - help_txt += [[TypeStr, BoolStr]] - - if self.CreateMode: - help_txt += [["Type [Space]", PrimitiveType]] - else: - help_txt += [["Cut Type [Space]", PrimitiveType]] - - else: - # Instantiate - TypeStr = "Instantiate [" + self.carver_prefs.Key_Instant + "]" - BoolStr = "(ON)" if self.Instantiate else "(OFF)" - help_txt = [[TypeStr, BoolStr]] - - # Random rotation - if self.alt: - TypeStr = "Random Rotation [" + self.carver_prefs.Key_Randrot + "]" - BoolStr = "(ON)" if self.RandomRotation else "(OFF)" - help_txt += [[TypeStr, BoolStr]] - - # Thickness - if self.BrushSolidify: - TypeStr = "Thickness [" + self.carver_prefs.Key_Depth + "]" - if self.ProfileMode: - BoolStr = str(round(self.ProfileBrush.modifiers["CT_SOLIDIFY"].thickness, 2)) - if self.ObjectMode: - BoolStr = str(round(self.ObjectBrush.modifiers["CT_SOLIDIFY"].thickness, 2)) - help_txt += [[TypeStr, BoolStr]] - - # Brush depth - if (self.ObjectMode): - TypeStr = "Carve Depth [" + self.carver_prefs.Key_Depth + "]" - BoolStr = str(round(self.ObjectBrush.data.vertices[0].co.z, 2)) - help_txt += [[TypeStr, BoolStr]] - - TypeStr = "Brush Depth [" + self.carver_prefs.Key_BrushDepth + "]" - BoolStr = str(round(self.BrushDepthOffset, 2)) - help_txt += [[TypeStr, BoolStr]] - - help_txt, bloc_height, max_option, max_key, comma = get_text_info(self, context, help_txt) - xCmd = region_width - (max_option + max_key + comma) / 2 - draw_string(self, color1, color2, xCmd, y_txt, help_txt, max_option, divide = 2) - - - # Separator (Line) - LineWidth = (max_option + max_key + comma) / 2 - if region.width >= 850: - LineWidth = 140 - - LineWidth = (max_option + max_key + comma) - coords = [(int(region_width - LineWidth/2), y_txt + bloc_height + 8), \ - (int(region_width + LineWidth/2), y_txt + bloc_height + 8)] - draw_shader(self, UIColor, 1, 'LINES', coords, self.carver_prefs.LineWidth) - - # Command Display - if self.CreateMode and ((self.ObjectMode is False) and (self.ProfileMode is False)): - BooleanMode = "Create" - else: - if self.ObjectMode or self.ProfileMode: - BooleanType = "Difference) [T]" if self.BoolOps == self.difference else "Union) [T]" - BooleanMode = \ - "Object Brush (" + BooleanType if self.ObjectMode else "Profil Brush (" + BooleanType - else: - BooleanMode = \ - "Difference" if (self.shift is False) and (self.ForceRebool is False) else "Rebool" - - # Display boolean mode - text_size = 40 if region.width >= 850 else 20 - blf.size(0, round(text_size * ui_scale), 72) - - draw_string(self, color2, color2, region_width - (blf.dimensions(0, BooleanMode)[0]) / 2, \ - y_txt + bloc_height + 16, BooleanMode, 0, divide = 2) - - if region.width >= 850: - - if self.AskHelp is False: - # "H for Help" text - blf.size(0, round(13 * ui_scale), 72) - help_txt = "[" + self.carver_prefs.Key_Help + "] for help" - txt_width = blf.dimensions(0, help_txt)[0] - txt_height = (blf.dimensions(0, "gM")[1] * 1.45) - - # Draw a rectangle and put the text "H for Help" - xrect = 40 - yrect = 40 - rect_vertices = [(xrect - 5, yrect - 5), (xrect + txt_width + 5, yrect - 5), \ - (xrect + txt_width + 5, yrect + txt_height + 5), (xrect - 5, yrect + txt_height + 5)] - draw_shader(self, (0.0, 0.0, 0.0), 0.3, 'TRI_FAN', rect_vertices, self.carver_prefs.LineWidth) - draw_string(self, color1, color2, xrect, yrect, help_txt, 0) - - else: - #Draw the help text - xHelp = 30 + t_panel_width - yHelp = 10 - - if self.ObjectMode or self.ProfileMode: - if self.ProfileMode: - help_txt = [["Object Mode", self.carver_prefs.Key_Brush]] - else: - help_txt = [["Cut Mode", self.carver_prefs.Key_Brush]] - - else: - help_txt =[ - ["Profil Brush", self.carver_prefs.Key_Brush],\ - ["Move Cursor", "Ctrl + LMB"] - ] - - if (self.ObjectMode is False) and (self.ProfileMode is False): - if self.CreateMode is False: - help_txt +=[ - ["Create geometry", self.carver_prefs.Key_Create],\ - ] - else: - help_txt +=[ - ["Cut", self.carver_prefs.Key_Create],\ - ] - if self.CutMode == RECTANGLE: - help_txt +=[ - ["Dimension", "MouseMove"],\ - ["Move all", "Alt"],\ - ["Validate", "LMB"],\ - ["Rebool", "Shift"] - ] - - elif self.CutMode == CIRCLE: - help_txt +=[ - ["Rotation and Radius", "MouseMove"],\ - ["Move all", "Alt"],\ - ["Subdivision", self.carver_prefs.Key_Subrem + " " + self.carver_prefs.Key_Subadd],\ - ["Incremental rotation", "Ctrl"],\ - ["Rebool", "Shift"] - ] - - elif self.CutMode == LINE: - help_txt +=[ - ["Dimension", "MouseMove"],\ - ["Move all", "Alt"],\ - ["Validate", "Space"],\ - ["Rebool", "Shift"],\ - ["Snap", "Ctrl"],\ - ["Scale Snap", "WheelMouse"],\ - ] - else: - # ObjectMode - help_txt +=[ - ["Difference", "Space"],\ - ["Rebool", "Shift + Space"],\ - ["Duplicate", "Alt + Space"],\ - ["Scale", self.carver_prefs.Key_Scale],\ - ["Rotation", "LMB + Move"],\ - ["Step Angle", "CTRL + LMB + Move"],\ - ] - - if self.ProfileMode: - help_txt +=[["Previous or Next Profile", self.carver_prefs.Key_Subadd + " " + self.carver_prefs.Key_Subrem]] - - help_txt +=[ - ["Create / Delete rows", chr(8597)],\ - ["Create / Delete cols", chr(8596)],\ - ["Gap for rows or columns", self.carver_prefs.Key_Gapy + " " + self.carver_prefs.Key_Gapx] - ] - - blf.size(0, round(15 * ui_scale), 72) - help_txt, bloc_height, max_option, max_key, comma = get_text_info(self, context, help_txt) - draw_string(self, color1, color2, xHelp, yHelp, help_txt, max_option) - - if self.ProfileMode: - xrect = region.width - t_panel_width - 80 - yrect = 80 - coords = [(xrect, yrect), (xrect+60, yrect), (xrect+60, yrect-60), (xrect, yrect-60)] - - # Draw rectangle background in the lower right - draw_shader(self, (0.0, 0.0, 0.0), 0.3, 'TRI_FAN', coords, size=self.carver_prefs.LineWidth) - - # Use numpy to get the vertices and indices of the profile object to draw - WidthProfil = 50 - location = Vector((region.width - t_panel_width - WidthProfil, 50, 0)) - ProfilScale = 20.0 - coords = [] - mesh = bpy.data.meshes[self.Profils[self.nProfil][0]] - mesh.calc_loop_triangles() - vertices = np.empty((len(mesh.vertices), 3), 'f') - indices = np.empty((len(mesh.loop_triangles), 3), 'i') - mesh.vertices.foreach_get("co", np.reshape(vertices, len(mesh.vertices) * 3)) - mesh.loop_triangles.foreach_get("vertices", np.reshape(indices, len(mesh.loop_triangles) * 3)) - - for idx, vals in enumerate(vertices): - coords.append([ - vals[0] * ProfilScale + location.x, - vals[1] * ProfilScale + location.y, - vals[2] * ProfilScale + location.z - ]) - - #Draw the silhouette of the mesh - draw_shader(self, UIColor, 0.5, 'TRIS', coords, size=self.carver_prefs.LineWidth, indices=indices) - - - if self.CutMode: - - if len(self.mouse_path) > 1: - x0 = self.mouse_path[0][0] - y0 = self.mouse_path[0][1] - x1 = self.mouse_path[1][0] - y1 = self.mouse_path[1][1] - - # Cut rectangle - if self.CutType == RECTANGLE: - coords = [ - (x0 + self.xpos, y0 + self.ypos), (x1 + self.xpos, y0 + self.ypos), \ - (x1 + self.xpos, y1 + self.ypos), (x0 + self.xpos, y1 + self.ypos) - ] - indices = ((0, 1, 2), (2, 0, 3)) - - self.rectangle_coord = coords - - draw_shader(self, UIColor, 1, 'LINE_LOOP', coords, size=self.carver_prefs.LineWidth) - - #Draw points - draw_shader(self, UIColor, 1, 'POINTS', coords, size=3) - - if self.shift or self.CreateMode: - draw_shader(self, UIColor, 0.5, 'TRIS', coords, size=self.carver_prefs.LineWidth, indices=indices) - - # Draw grid (based on the overlay options) to show the incremental snapping - if self.ctrl: - mini_grid(self, context, UIColor) - - # Cut Line - elif self.CutType == LINE: - coords = [] - indices = [] - top_grid = False - - for idx, vals in enumerate(self.mouse_path): - coords.append([vals[0] + self.xpos, vals[1] + self.ypos]) - indices.append([idx]) - - # Draw lines - if self.Closed: - draw_shader(self, UIColor, 1.0, 'LINE_LOOP', coords, size=self.carver_prefs.LineWidth) - else: - draw_shader(self, UIColor, 1.0, 'LINE_STRIP', coords, size=self.carver_prefs.LineWidth) - - # Draw points - draw_shader(self, UIColor, 1.0, 'POINTS', coords, size=3) - - # Draw polygon - if (self.shift) or (self.CreateMode and self.Closed): - draw_shader(self, UIColor, 0.5, 'TRI_FAN', coords, size=self.carver_prefs.LineWidth) - - # Draw grid (based on the overlay options) to show the incremental snapping - if self.ctrl: - mini_grid(self, context, UIColor) - - # Circle Cut - elif self.CutType == CIRCLE: - # Create a circle using a tri fan - tris_coords, indices = draw_circle(self, x0, y0) - - # Remove the vertex in the center to get the outer line of the circle - line_coords = tris_coords[1:] - draw_shader(self, UIColor, 1.0, 'LINE_LOOP', line_coords, size=self.carver_prefs.LineWidth) - - if self.shift or self.CreateMode: - draw_shader(self, UIColor, 0.5, 'TRIS', tris_coords, size=self.carver_prefs.LineWidth, indices=indices) - - if (self.ObjectMode or self.ProfileMode) and len(self.CurrentSelection) > 0: - if self.ShowCursor: - region = context.region - rv3d = context.space_data.region_3d - - if self.ObjectMode: - ob = self.ObjectBrush - if self.ProfileMode: - ob = self.ProfileBrush - mat = ob.matrix_world - - # 50% alpha, 2 pixel width line - bgl.glEnable(bgl.GL_BLEND) - - bbox = [mat @ Vector(b) for b in ob.bound_box] - objBBDiagonal = objDiagonal(self.CurrentSelection[0]) - - if self.shift: - gl_size = 4 - UIColor = (0.5, 1.0, 0.0, 1.0) - else: - gl_size = 2 - UIColor = (1.0, 0.8, 0.0, 1.0) - - line_coords = [] - idx = 0 - CRadius = ((bbox[7] - bbox[0]).length) / 2 - for i in range(int(len(self.CLR_C) / 3)): - vector3d = (self.CLR_C[idx * 3] * CRadius + self.CurLoc.x, \ - self.CLR_C[idx * 3 + 1] * CRadius + self.CurLoc.y, \ - self.CLR_C[idx * 3 + 2] * CRadius + self.CurLoc.z) - vector2d = bpy_extras.view3d_utils.location_3d_to_region_2d(region, rv3d, vector3d) - if vector2d is not None: - line_coords.append((vector2d[0], vector2d[1])) - idx += 1 - if len(line_coords) > 0 : - draw_shader(self, UIColor, 1.0, 'LINE_LOOP', line_coords, size=gl_size) - - # Object display - if self.quat_rot is not None: - ob.location = self.CurLoc - v = Vector() - v.x = v.y = 0.0 - v.z = self.BrushDepthOffset - ob.location += self.quat_rot @ v - - e = Euler() - e.x = 0.0 - e.y = 0.0 - e.z = self.aRotZ / 25.0 - - qe = e.to_quaternion() - qRot = self.quat_rot @ qe - ob.rotation_mode = 'QUATERNION' - ob.rotation_quaternion = qRot - ob.rotation_mode = 'XYZ' - - if self.ProfileMode: - if self.ProfileBrush is not None: - self.ProfileBrush.location = self.CurLoc - self.ProfileBrush.rotation_mode = 'QUATERNION' - self.ProfileBrush.rotation_quaternion = qRot - self.ProfileBrush.rotation_mode = 'XYZ' - - # Opengl defaults - bgl.glLineWidth(1) - bgl.glDisable(bgl.GL_BLEND) + font_id = 0 + region = context.region + UIColor = (0.992, 0.5518, 0.0, 1.0) + + # Cut Type + RECTANGLE = 0 + LINE = 1 + CIRCLE = 2 + self.carver_prefs = context.preferences.addons[__package__].preferences + + # Color + color1 = (1.0, 1.0, 1.0, 1.0) + color2 = UIColor + + #The mouse is outside the active region + if not self.in_view_3d: + color1 = color2 = (1.0, 0.2, 0.1, 1.0) + + # Primitives type + PrimitiveType = "Rectangle" + if self.CutType == CIRCLE: + PrimitiveType = "Circle" + if self.CutType == LINE: + PrimitiveType = "Line" + + # Width screen + overlap = context.preferences.system.use_region_overlap + + t_panel_width = 0 + if overlap: + for region in context.area.regions: + if region.type == 'TOOLS': + t_panel_width = region.width + + # Initial position + region_width = int(region.width / 2.0) + y_txt = 10 + + + # Draw the center command from bottom to top + + # Get the size of the text + text_size = 18 if region.width >= 850 else 12 + ui_scale = bpy.context.preferences.system.ui_scale + blf.size(0, round(text_size * ui_scale), 72) + + # Help Display + if (self.ObjectMode is False) and (self.ProfileMode is False): + + # Depth Cursor + TypeStr = "Cursor Depth [" + self.carver_prefs.Key_Depth + "]" + BoolStr = "(ON)" if self.snapCursor else "(OFF)" + help_txt = [[TypeStr, BoolStr]] + + # Close poygonal shape + if self.CreateMode and self.CutType == LINE: + TypeStr = "Close [" + self.carver_prefs.Key_Close + "]" + BoolStr = "(ON)" if self.Closed else "(OFF)" + help_txt += [[TypeStr, BoolStr]] + + if self.CreateMode is False: + # Apply Booleans + TypeStr = "Apply Operations [" + self.carver_prefs.Key_Apply + "]" + BoolStr = "(OFF)" if self.dont_apply_boolean else "(ON)" + help_txt += [[TypeStr, BoolStr]] + + #Auto update for bevel + TypeStr = "Bevel Update [" + self.carver_prefs.Key_Update + "]" + BoolStr = "(ON)" if self.Auto_BevelUpdate else "(OFF)" + help_txt += [[TypeStr, BoolStr]] + + # Circle subdivisions + if self.CutType == CIRCLE: + TypeStr = "Subdivisions [" + self.carver_prefs.Key_Subrem + "][" + self.carver_prefs.Key_Subadd + "]" + BoolStr = str((int(360 / self.stepAngle[self.step]))) + help_txt += [[TypeStr, BoolStr]] + + if self.CreateMode: + help_txt += [["Type [Space]", PrimitiveType]] + else: + help_txt += [["Cut Type [Space]", PrimitiveType]] + + else: + # Instantiate + TypeStr = "Instantiate [" + self.carver_prefs.Key_Instant + "]" + BoolStr = "(ON)" if self.Instantiate else "(OFF)" + help_txt = [[TypeStr, BoolStr]] + + # Random rotation + if self.alt: + TypeStr = "Random Rotation [" + self.carver_prefs.Key_Randrot + "]" + BoolStr = "(ON)" if self.RandomRotation else "(OFF)" + help_txt += [[TypeStr, BoolStr]] + + # Thickness + if self.BrushSolidify: + TypeStr = "Thickness [" + self.carver_prefs.Key_Depth + "]" + if self.ProfileMode: + BoolStr = str(round(self.ProfileBrush.modifiers["CT_SOLIDIFY"].thickness, 2)) + if self.ObjectMode: + BoolStr = str(round(self.ObjectBrush.modifiers["CT_SOLIDIFY"].thickness, 2)) + help_txt += [[TypeStr, BoolStr]] + + # Brush depth + if (self.ObjectMode): + TypeStr = "Carve Depth [" + self.carver_prefs.Key_Depth + "]" + BoolStr = str(round(self.ObjectBrush.data.vertices[0].co.z, 2)) + help_txt += [[TypeStr, BoolStr]] + + TypeStr = "Brush Depth [" + self.carver_prefs.Key_BrushDepth + "]" + BoolStr = str(round(self.BrushDepthOffset, 2)) + help_txt += [[TypeStr, BoolStr]] + + help_txt, bloc_height, max_option, max_key, comma = get_text_info(self, context, help_txt) + xCmd = region_width - (max_option + max_key + comma) / 2 + draw_string(self, color1, color2, xCmd, y_txt, help_txt, max_option, divide = 2) + + + # Separator (Line) + LineWidth = (max_option + max_key + comma) / 2 + if region.width >= 850: + LineWidth = 140 + + LineWidth = (max_option + max_key + comma) + coords = [(int(region_width - LineWidth/2), y_txt + bloc_height + 8), \ + (int(region_width + LineWidth/2), y_txt + bloc_height + 8)] + draw_shader(self, UIColor, 1, 'LINES', coords, self.carver_prefs.LineWidth) + + # Command Display + if self.CreateMode and ((self.ObjectMode is False) and (self.ProfileMode is False)): + BooleanMode = "Create" + else: + if self.ObjectMode or self.ProfileMode: + BooleanType = "Difference) [T]" if self.BoolOps == self.difference else "Union) [T]" + BooleanMode = \ + "Object Brush (" + BooleanType if self.ObjectMode else "Profil Brush (" + BooleanType + else: + BooleanMode = \ + "Difference" if (self.shift is False) and (self.ForceRebool is False) else "Rebool" + + # Display boolean mode + text_size = 40 if region.width >= 850 else 20 + blf.size(0, round(text_size * ui_scale), 72) + + draw_string(self, color2, color2, region_width - (blf.dimensions(0, BooleanMode)[0]) / 2, \ + y_txt + bloc_height + 16, BooleanMode, 0, divide = 2) + + if region.width >= 850: + + if self.AskHelp is False: + # "H for Help" text + blf.size(0, round(13 * ui_scale), 72) + help_txt = "[" + self.carver_prefs.Key_Help + "] for help" + txt_width = blf.dimensions(0, help_txt)[0] + txt_height = (blf.dimensions(0, "gM")[1] * 1.45) + + # Draw a rectangle and put the text "H for Help" + xrect = 40 + yrect = 40 + rect_vertices = [(xrect - 5, yrect - 5), (xrect + txt_width + 5, yrect - 5), \ + (xrect + txt_width + 5, yrect + txt_height + 5), (xrect - 5, yrect + txt_height + 5)] + draw_shader(self, (0.0, 0.0, 0.0), 0.3, 'TRI_FAN', rect_vertices, self.carver_prefs.LineWidth) + draw_string(self, color1, color2, xrect, yrect, help_txt, 0) + + else: + #Draw the help text + xHelp = 30 + t_panel_width + yHelp = 10 + + if self.ObjectMode or self.ProfileMode: + if self.ProfileMode: + help_txt = [["Object Mode", self.carver_prefs.Key_Brush]] + else: + help_txt = [["Cut Mode", self.carver_prefs.Key_Brush]] + + else: + help_txt =[ + ["Profil Brush", self.carver_prefs.Key_Brush],\ + ["Move Cursor", "Ctrl + LMB"] + ] + + if (self.ObjectMode is False) and (self.ProfileMode is False): + if self.CreateMode is False: + help_txt +=[ + ["Create geometry", self.carver_prefs.Key_Create],\ + ] + else: + help_txt +=[ + ["Cut", self.carver_prefs.Key_Create],\ + ] + if self.CutMode == RECTANGLE: + help_txt +=[ + ["Dimension", "MouseMove"],\ + ["Move all", "Alt"],\ + ["Validate", "LMB"],\ + ["Rebool", "Shift"] + ] + + elif self.CutMode == CIRCLE: + help_txt +=[ + ["Rotation and Radius", "MouseMove"],\ + ["Move all", "Alt"],\ + ["Subdivision", self.carver_prefs.Key_Subrem + " " + self.carver_prefs.Key_Subadd],\ + ["Incremental rotation", "Ctrl"],\ + ["Rebool", "Shift"] + ] + + elif self.CutMode == LINE: + help_txt +=[ + ["Dimension", "MouseMove"],\ + ["Move all", "Alt"],\ + ["Validate", "Space"],\ + ["Rebool", "Shift"],\ + ["Snap", "Ctrl"],\ + ["Scale Snap", "WheelMouse"],\ + ] + else: + # ObjectMode + help_txt +=[ + ["Difference", "Space"],\ + ["Rebool", "Shift + Space"],\ + ["Duplicate", "Alt + Space"],\ + ["Scale", self.carver_prefs.Key_Scale],\ + ["Rotation", "LMB + Move"],\ + ["Step Angle", "CTRL + LMB + Move"],\ + ] + + if self.ProfileMode: + help_txt +=[["Previous or Next Profile", self.carver_prefs.Key_Subadd + " " + self.carver_prefs.Key_Subrem]] + + help_txt +=[ + ["Create / Delete rows", chr(8597)],\ + ["Create / Delete cols", chr(8596)],\ + ["Gap for rows or columns", self.carver_prefs.Key_Gapy + " " + self.carver_prefs.Key_Gapx] + ] + + blf.size(0, round(15 * ui_scale), 72) + help_txt, bloc_height, max_option, max_key, comma = get_text_info(self, context, help_txt) + draw_string(self, color1, color2, xHelp, yHelp, help_txt, max_option) + + if self.ProfileMode: + xrect = region.width - t_panel_width - 80 + yrect = 80 + coords = [(xrect, yrect), (xrect+60, yrect), (xrect+60, yrect-60), (xrect, yrect-60)] + + # Draw rectangle background in the lower right + draw_shader(self, (0.0, 0.0, 0.0), 0.3, 'TRI_FAN', coords, size=self.carver_prefs.LineWidth) + + # Use numpy to get the vertices and indices of the profile object to draw + WidthProfil = 50 + location = Vector((region.width - t_panel_width - WidthProfil, 50, 0)) + ProfilScale = 20.0 + coords = [] + mesh = bpy.data.meshes[self.Profils[self.nProfil][0]] + mesh.calc_loop_triangles() + vertices = np.empty((len(mesh.vertices), 3), 'f') + indices = np.empty((len(mesh.loop_triangles), 3), 'i') + mesh.vertices.foreach_get("co", np.reshape(vertices, len(mesh.vertices) * 3)) + mesh.loop_triangles.foreach_get("vertices", np.reshape(indices, len(mesh.loop_triangles) * 3)) + + for idx, vals in enumerate(vertices): + coords.append([ + vals[0] * ProfilScale + location.x, + vals[1] * ProfilScale + location.y, + vals[2] * ProfilScale + location.z + ]) + + #Draw the silhouette of the mesh + draw_shader(self, UIColor, 0.5, 'TRIS', coords, size=self.carver_prefs.LineWidth, indices=indices) + + + if self.CutMode: + + if len(self.mouse_path) > 1: + x0 = self.mouse_path[0][0] + y0 = self.mouse_path[0][1] + x1 = self.mouse_path[1][0] + y1 = self.mouse_path[1][1] + + # Cut rectangle + if self.CutType == RECTANGLE: + coords = [ + (x0 + self.xpos, y0 + self.ypos), (x1 + self.xpos, y0 + self.ypos), \ + (x1 + self.xpos, y1 + self.ypos), (x0 + self.xpos, y1 + self.ypos) + ] + indices = ((0, 1, 2), (2, 0, 3)) + + self.rectangle_coord = coords + + draw_shader(self, UIColor, 1, 'LINE_LOOP', coords, size=self.carver_prefs.LineWidth) + + #Draw points + draw_shader(self, UIColor, 1, 'POINTS', coords, size=3) + + if self.shift or self.CreateMode: + draw_shader(self, UIColor, 0.5, 'TRIS', coords, size=self.carver_prefs.LineWidth, indices=indices) + + # Draw grid (based on the overlay options) to show the incremental snapping + if self.ctrl: + mini_grid(self, context, UIColor) + + # Cut Line + elif self.CutType == LINE: + coords = [] + indices = [] + top_grid = False + + for idx, vals in enumerate(self.mouse_path): + coords.append([vals[0] + self.xpos, vals[1] + self.ypos]) + indices.append([idx]) + + # Draw lines + if self.Closed: + draw_shader(self, UIColor, 1.0, 'LINE_LOOP', coords, size=self.carver_prefs.LineWidth) + else: + draw_shader(self, UIColor, 1.0, 'LINE_STRIP', coords, size=self.carver_prefs.LineWidth) + + # Draw points + draw_shader(self, UIColor, 1.0, 'POINTS', coords, size=3) + + # Draw polygon + if (self.shift) or (self.CreateMode and self.Closed): + draw_shader(self, UIColor, 0.5, 'TRI_FAN', coords, size=self.carver_prefs.LineWidth) + + # Draw grid (based on the overlay options) to show the incremental snapping + if self.ctrl: + mini_grid(self, context, UIColor) + + # Circle Cut + elif self.CutType == CIRCLE: + # Create a circle using a tri fan + tris_coords, indices = draw_circle(self, x0, y0) + + # Remove the vertex in the center to get the outer line of the circle + line_coords = tris_coords[1:] + draw_shader(self, UIColor, 1.0, 'LINE_LOOP', line_coords, size=self.carver_prefs.LineWidth) + + if self.shift or self.CreateMode: + draw_shader(self, UIColor, 0.5, 'TRIS', tris_coords, size=self.carver_prefs.LineWidth, indices=indices) + + if (self.ObjectMode or self.ProfileMode) and len(self.CurrentSelection) > 0: + if self.ShowCursor: + region = context.region + rv3d = context.space_data.region_3d + + if self.ObjectMode: + ob = self.ObjectBrush + if self.ProfileMode: + ob = self.ProfileBrush + mat = ob.matrix_world + + # 50% alpha, 2 pixel width line + bgl.glEnable(bgl.GL_BLEND) + + bbox = [mat @ Vector(b) for b in ob.bound_box] + objBBDiagonal = objDiagonal(self.CurrentSelection[0]) + + if self.shift: + gl_size = 4 + UIColor = (0.5, 1.0, 0.0, 1.0) + else: + gl_size = 2 + UIColor = (1.0, 0.8, 0.0, 1.0) + + line_coords = [] + idx = 0 + CRadius = ((bbox[7] - bbox[0]).length) / 2 + for i in range(int(len(self.CLR_C) / 3)): + vector3d = (self.CLR_C[idx * 3] * CRadius + self.CurLoc.x, \ + self.CLR_C[idx * 3 + 1] * CRadius + self.CurLoc.y, \ + self.CLR_C[idx * 3 + 2] * CRadius + self.CurLoc.z) + vector2d = bpy_extras.view3d_utils.location_3d_to_region_2d(region, rv3d, vector3d) + if vector2d is not None: + line_coords.append((vector2d[0], vector2d[1])) + idx += 1 + if len(line_coords) > 0 : + draw_shader(self, UIColor, 1.0, 'LINE_LOOP', line_coords, size=gl_size) + + # Object display + if self.quat_rot is not None: + ob.location = self.CurLoc + v = Vector() + v.x = v.y = 0.0 + v.z = self.BrushDepthOffset + ob.location += self.quat_rot @ v + + e = Euler() + e.x = 0.0 + e.y = 0.0 + e.z = self.aRotZ / 25.0 + + qe = e.to_quaternion() + qRot = self.quat_rot @ qe + ob.rotation_mode = 'QUATERNION' + ob.rotation_quaternion = qRot + ob.rotation_mode = 'XYZ' + + if self.ProfileMode: + if self.ProfileBrush is not None: + self.ProfileBrush.location = self.CurLoc + self.ProfileBrush.rotation_mode = 'QUATERNION' + self.ProfileBrush.rotation_quaternion = qRot + self.ProfileBrush.rotation_mode = 'XYZ' + + # Opengl defaults + bgl.glLineWidth(1) + bgl.glDisable(bgl.GL_BLEND) diff --git a/object_carver/carver_operator.py b/object_carver/carver_operator.py index c75a5ab7640efcc61650c1147d8416177dd71023..95fa4af00a6647360b2fb68866edb8c3789a051f 100644 --- a/object_carver/carver_operator.py +++ b/object_carver/carver_operator.py @@ -2,340 +2,340 @@ import bpy import bpy_extras import sys from bpy.props import ( - BoolProperty, - IntProperty, - PointerProperty, - StringProperty, - EnumProperty, - ) + BoolProperty, + IntProperty, + PointerProperty, + StringProperty, + EnumProperty, + ) from mathutils import ( - Vector, - ) + Vector, + ) from bpy_extras.view3d_utils import ( - region_2d_to_vector_3d, - region_2d_to_origin_3d, - region_2d_to_location_3d, - location_3d_to_region_2d, + region_2d_to_vector_3d, + region_2d_to_origin_3d, + region_2d_to_location_3d, + location_3d_to_region_2d, ) from .carver_profils import ( - Profils - ) + Profils + ) from .carver_utils import ( - duplicateObject, - UndoListUpdate, - createMeshFromData, - SelectObject, - Selection_Save_Restore, - Selection_Save, - Selection_Restore, - update_grid, - objDiagonal, - Undo, - UndoAdd, - Pick, - rot_axis_quat, - MoveCursor, - Picking, - CreateCutSquare, - CreateCutCircle, - CreateCutLine, - boolean_operation, - update_bevel, - CreateBevel, - Rebool, - Snap_Cursor, - ) + duplicateObject, + UndoListUpdate, + createMeshFromData, + SelectObject, + Selection_Save_Restore, + Selection_Save, + Selection_Restore, + update_grid, + objDiagonal, + Undo, + UndoAdd, + Pick, + rot_axis_quat, + MoveCursor, + Picking, + CreateCutSquare, + CreateCutCircle, + CreateCutLine, + boolean_operation, + update_bevel, + CreateBevel, + Rebool, + Snap_Cursor, + ) from .carver_draw import draw_callback_px # Modal Operator class CARVER_OT_operator(bpy.types.Operator): - bl_idname = "carver.operator" - bl_label = "Carver" - bl_description = "Cut or create Meshes in Object mode" - bl_options = {'REGISTER', 'UNDO'} + bl_idname = "carver.operator" + bl_label = "Carver" + bl_description = "Cut or create Meshes in Object mode" + bl_options = {'REGISTER', 'UNDO'} - def __init__(self): - context = bpy.context - # Carve mode: Cut, Object, Profile - self.CutMode = False - self.CreateMode = False - self.ObjectMode = False - self.ProfileMode = False + def __init__(self): + context = bpy.context + # Carve mode: Cut, Object, Profile + self.CutMode = False + self.CreateMode = False + self.ObjectMode = False + self.ProfileMode = False - # Create mode - self.ExclusiveCreateMode = False - if len(context.selected_objects) == 0: - self.ExclusiveCreateMode = True - self.CreateMode = True + # Create mode + self.ExclusiveCreateMode = False + if len(context.selected_objects) == 0: + self.ExclusiveCreateMode = True + self.CreateMode = True - # Cut type (Rectangle, Circle, Line) - self.rectangle = 0 - self.line = 1 - self.circle = 2 + # Cut type (Rectangle, Circle, Line) + self.rectangle = 0 + self.line = 1 + self.circle = 2 - # Cut Rectangle coordinates - self.rectangle_coord = [] + # Cut Rectangle coordinates + self.rectangle_coord = [] - # Selected type of cut - self.CutType = 0 + # Selected type of cut + self.CutType = 0 - # Boolean operation - self.difference = 0 - self.union = 1 - - self.BoolOps = self.difference - - self.CurrentSelection = context.selected_objects.copy() - self.CurrentActive = context.active_object - self.all_sel_obj_list = context.selected_objects.copy() - self.save_active_obj = None - - args = (self, context) - self._handle = bpy.types.SpaceView3D.draw_handler_add(draw_callback_px, args, 'WINDOW', 'POST_PIXEL') - - self.mouse_path = [(0, 0), (0, 0)] - - # Keyboard event - self.shift = False - self.ctrl = False - self.alt = False - - self.dont_apply_boolean = context.scene.mesh_carver.DontApply - self.Auto_BevelUpdate = True - - # Circle variables - self.stepAngle = [2, 4, 5, 6, 9, 10, 15, 20, 30, 40, 45, 60, 72, 90] - self.step = 4 - - # Primitives Position - self.xpos = 0 - self.ypos = 0 - self.InitPosition = False - - # Close polygonal shape - self.Closed = False - - # Depth Cursor - self.snapCursor = context.scene.mesh_carver.DepthCursor - - # Help - self.AskHelp = False - - # Working object - self.OpsObj = context.active_object - - # Rebool forced (cut line) - self.ForceRebool = False - - self.ViewVector = Vector() - self.CurrentObj = None - - # Brush - self.BrushSolidify = False - self.WidthSolidify = False - self.CarveDepth = False - self.BrushDepth = False - self.BrushDepthOffset = 0.0 - self.snap = False - - self.ObjectScale = False - - #Init create circle primitive - self.CLR_C = [] - - # Cursor location - self.CurLoc = Vector((0.0, 0.0, 0.0)) - self.SavCurLoc = Vector((0.0, 0.0, 0.0)) - - # Mouse region - self.mouse_region = -1, -1 - self.SavMousePos = None - self.xSavMouse = 0 - - # Scale, rotate object - self.ascale = 0 - self.aRotZ = 0 - self.nRotZ = 0 - self.quat_rot_axis = None - self.quat_rot = None - - self.RandomRotation = context.scene.mesh_carver.ORandom - - self.ShowCursor = True - - self.Instantiate = context.scene.mesh_carver.OInstanciate - - self.ProfileBrush = None - self.ObjectBrush = None - - self.InitBrush = { - 'location' : None, - 'scale' : None, - 'rotation_quaternion' : None, - 'rotation_euler' : None, - 'display_type' : 'WIRE', - 'show_in_front' : False - } - - # Array variables - self.nbcol = 1 - self.nbrow = 1 - self.gapx = 0 - self.gapy = 0 - self.scale_x = 1 - self.scale_y = 1 - self.GridScaleX = False - self.GridScaleY = False - - @classmethod - def poll(cls, context): - ob = None - if len(context.selected_objects) > 0: - ob = context.selected_objects[0] - # Test if selected object or none (for create mode) - return ( - (ob and ob.type == 'MESH' and context.mode == 'OBJECT') or - (context.mode == 'OBJECT' and ob is None) or - (context.mode == 'EDIT_MESH')) - - def modal(self, context, event): - PI = 3.14156 - region_types = {'WINDOW', 'UI'} - win = context.window - - # Find the limit of the view3d region - self.check_region(context,event) - - for area in win.screen.areas: - if area.type == 'VIEW_3D': - for region in area.regions: - if not region_types or region.type in region_types: - region.tag_redraw() - - # Change the snap increment value using the wheel mouse - if self.CutMode: - if self.alt is False: - if self.ctrl and (self.CutType in (self.line, self.rectangle)): - # Get the VIEW3D area - for i, a in enumerate(context.screen.areas): - if a.type == 'VIEW_3D': - space = context.screen.areas[i].spaces.active - grid_scale = space.overlay.grid_scale - grid_subdivisions = space.overlay.grid_subdivisions - - if event.type == 'WHEELUPMOUSE': - space.overlay.grid_subdivisions += 1 - elif event.type == 'WHEELDOWNMOUSE': - space.overlay.grid_subdivisions -= 1 - - if event.type in { - 'MIDDLEMOUSE', 'WHEELUPMOUSE', 'WHEELDOWNMOUSE', - 'NUMPAD_1', 'NUMPAD_2', 'NUMPAD_3', 'NUMPAD_4', 'NUMPAD_6', - 'NUMPAD_7', 'NUMPAD_8', 'NUMPAD_9', 'NUMPAD_5'}: - return {'PASS_THROUGH'} - - try: - # [Shift] - self.shift = True if event.shift else False - - # [Ctrl] - self.ctrl = True if event.ctrl else False - - # [Alt] - self.alt = False - - # [Alt] press : Init position variable before moving the cut brush with LMB - if event.alt: - if self.InitPosition is False: - self.xpos = 0 - self.ypos = 0 - self.last_mouse_region_x = event.mouse_region_x - self.last_mouse_region_y = event.mouse_region_y - self.InitPosition = True - self.alt = True - - # [Alt] release : update the coordinates - if self.InitPosition and self.alt is False: - for i in range(0, len(self.mouse_path)): - l = list(self.mouse_path[i]) - l[0] += self.xpos - l[1] += self.ypos - self.mouse_path[i] = tuple(l) - - self.xpos = self.ypos = 0 - self.InitPosition = False - - if event.type == 'SPACE' and event.value == 'PRESS': - # If object or profile mode is TRUE : Confirm the cut - if self.ObjectMode or self.ProfileMode: - # If array, remove double with intersect meshes - if ((self.nbcol + self.nbrow) > 3): - # Go in edit mode mode - bpy.ops.object.mode_set(mode='EDIT') - # Remove duplicate vertices - bpy.ops.mesh.remove_doubles() - # Return in object mode - bpy.ops.object.mode_set(mode='OBJECT') - - if self.alt: - # Save selected objects - self.all_sel_obj_list = context.selected_objects.copy() - if len(context.selected_objects) > 0: - bpy.ops.object.select_all(action='TOGGLE') - - if self.ObjectMode: - SelectObject(self, self.ObjectBrush) - else: - SelectObject(self, self.ProfileBrush) - duplicateObject(self) - else: - # Brush Cut - self.Cut() - # Save selected objects - if self.ObjectMode: - if len(self.ObjectBrush.children) > 0: - self.all_sel_obj_list = context.selected_objects.copy() - if len(context.selected_objects) > 0: - bpy.ops.object.select_all(action='TOGGLE') - - if self.ObjectMode: - SelectObject(self, self.ObjectBrush) - else: - SelectObject(self, self.ProfileBrush) - duplicateObject(self) - - UndoListUpdate(self) - - # Save cursor position - self.SavMousePos = self.CurLoc - else: - if self.CutMode is False: - # Cut Mode - self.CutType += 1 - if self.CutType > 2: - self.CutType = 0 - else: - if self.CutType == self.line: - # Cuts creation - CreateCutLine(self, context) - if self.CreateMode: - # Object creation - self.CreateGeometry() - bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW') - # Cursor Snap - context.scene.mesh_carver.DepthCursor = self.snapCursor - # Object Instantiate - context.scene.mesh_carver.OInstanciate = self.Instantiate - # Random rotation - context.scene.mesh_carver.ORandom = self.RandomRotation - - return {'FINISHED'} - else: - self.Cut() - UndoListUpdate(self) + # Boolean operation + self.difference = 0 + self.union = 1 + + self.BoolOps = self.difference + + self.CurrentSelection = context.selected_objects.copy() + self.CurrentActive = context.active_object + self.all_sel_obj_list = context.selected_objects.copy() + self.save_active_obj = None + + args = (self, context) + self._handle = bpy.types.SpaceView3D.draw_handler_add(draw_callback_px, args, 'WINDOW', 'POST_PIXEL') + + self.mouse_path = [(0, 0), (0, 0)] + + # Keyboard event + self.shift = False + self.ctrl = False + self.alt = False + + self.dont_apply_boolean = context.scene.mesh_carver.DontApply + self.Auto_BevelUpdate = True + + # Circle variables + self.stepAngle = [2, 4, 5, 6, 9, 10, 15, 20, 30, 40, 45, 60, 72, 90] + self.step = 4 + + # Primitives Position + self.xpos = 0 + self.ypos = 0 + self.InitPosition = False + + # Close polygonal shape + self.Closed = False + + # Depth Cursor + self.snapCursor = context.scene.mesh_carver.DepthCursor + + # Help + self.AskHelp = False + + # Working object + self.OpsObj = context.active_object + + # Rebool forced (cut line) + self.ForceRebool = False + + self.ViewVector = Vector() + self.CurrentObj = None + + # Brush + self.BrushSolidify = False + self.WidthSolidify = False + self.CarveDepth = False + self.BrushDepth = False + self.BrushDepthOffset = 0.0 + self.snap = False + + self.ObjectScale = False + + #Init create circle primitive + self.CLR_C = [] + + # Cursor location + self.CurLoc = Vector((0.0, 0.0, 0.0)) + self.SavCurLoc = Vector((0.0, 0.0, 0.0)) + + # Mouse region + self.mouse_region = -1, -1 + self.SavMousePos = None + self.xSavMouse = 0 + + # Scale, rotate object + self.ascale = 0 + self.aRotZ = 0 + self.nRotZ = 0 + self.quat_rot_axis = None + self.quat_rot = None + + self.RandomRotation = context.scene.mesh_carver.ORandom + + self.ShowCursor = True + + self.Instantiate = context.scene.mesh_carver.OInstanciate + + self.ProfileBrush = None + self.ObjectBrush = None + + self.InitBrush = { + 'location' : None, + 'scale' : None, + 'rotation_quaternion' : None, + 'rotation_euler' : None, + 'display_type' : 'WIRE', + 'show_in_front' : False + } + + # Array variables + self.nbcol = 1 + self.nbrow = 1 + self.gapx = 0 + self.gapy = 0 + self.scale_x = 1 + self.scale_y = 1 + self.GridScaleX = False + self.GridScaleY = False + + @classmethod + def poll(cls, context): + ob = None + if len(context.selected_objects) > 0: + ob = context.selected_objects[0] + # Test if selected object or none (for create mode) + return ( + (ob and ob.type == 'MESH' and context.mode == 'OBJECT') or + (context.mode == 'OBJECT' and ob is None) or + (context.mode == 'EDIT_MESH')) + + def modal(self, context, event): + PI = 3.14156 + region_types = {'WINDOW', 'UI'} + win = context.window + + # Find the limit of the view3d region + self.check_region(context,event) + + for area in win.screen.areas: + if area.type == 'VIEW_3D': + for region in area.regions: + if not region_types or region.type in region_types: + region.tag_redraw() + + # Change the snap increment value using the wheel mouse + if self.CutMode: + if self.alt is False: + if self.ctrl and (self.CutType in (self.line, self.rectangle)): + # Get the VIEW3D area + for i, a in enumerate(context.screen.areas): + if a.type == 'VIEW_3D': + space = context.screen.areas[i].spaces.active + grid_scale = space.overlay.grid_scale + grid_subdivisions = space.overlay.grid_subdivisions + + if event.type == 'WHEELUPMOUSE': + space.overlay.grid_subdivisions += 1 + elif event.type == 'WHEELDOWNMOUSE': + space.overlay.grid_subdivisions -= 1 + + if event.type in { + 'MIDDLEMOUSE', 'WHEELUPMOUSE', 'WHEELDOWNMOUSE', + 'NUMPAD_1', 'NUMPAD_2', 'NUMPAD_3', 'NUMPAD_4', 'NUMPAD_6', + 'NUMPAD_7', 'NUMPAD_8', 'NUMPAD_9', 'NUMPAD_5'}: + return {'PASS_THROUGH'} + + try: + # [Shift] + self.shift = True if event.shift else False + + # [Ctrl] + self.ctrl = True if event.ctrl else False + + # [Alt] + self.alt = False + + # [Alt] press : Init position variable before moving the cut brush with LMB + if event.alt: + if self.InitPosition is False: + self.xpos = 0 + self.ypos = 0 + self.last_mouse_region_x = event.mouse_region_x + self.last_mouse_region_y = event.mouse_region_y + self.InitPosition = True + self.alt = True + + # [Alt] release : update the coordinates + if self.InitPosition and self.alt is False: + for i in range(0, len(self.mouse_path)): + l = list(self.mouse_path[i]) + l[0] += self.xpos + l[1] += self.ypos + self.mouse_path[i] = tuple(l) + + self.xpos = self.ypos = 0 + self.InitPosition = False + + if event.type == 'SPACE' and event.value == 'PRESS': + # If object or profile mode is TRUE : Confirm the cut + if self.ObjectMode or self.ProfileMode: + # If array, remove double with intersect meshes + if ((self.nbcol + self.nbrow) > 3): + # Go in edit mode mode + bpy.ops.object.mode_set(mode='EDIT') + # Remove duplicate vertices + bpy.ops.mesh.remove_doubles() + # Return in object mode + bpy.ops.object.mode_set(mode='OBJECT') + + if self.alt: + # Save selected objects + self.all_sel_obj_list = context.selected_objects.copy() + if len(context.selected_objects) > 0: + bpy.ops.object.select_all(action='TOGGLE') + + if self.ObjectMode: + SelectObject(self, self.ObjectBrush) + else: + SelectObject(self, self.ProfileBrush) + duplicateObject(self) + else: + # Brush Cut + self.Cut() + # Save selected objects + if self.ObjectMode: + if len(self.ObjectBrush.children) > 0: + self.all_sel_obj_list = context.selected_objects.copy() + if len(context.selected_objects) > 0: + bpy.ops.object.select_all(action='TOGGLE') + + if self.ObjectMode: + SelectObject(self, self.ObjectBrush) + else: + SelectObject(self, self.ProfileBrush) + duplicateObject(self) + + UndoListUpdate(self) + + # Save cursor position + self.SavMousePos = self.CurLoc + else: + if self.CutMode is False: + # Cut Mode + self.CutType += 1 + if self.CutType > 2: + self.CutType = 0 + else: + if self.CutType == self.line: + # Cuts creation + CreateCutLine(self, context) + if self.CreateMode: + # Object creation + self.CreateGeometry() + bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW') + # Cursor Snap + context.scene.mesh_carver.DepthCursor = self.snapCursor + # Object Instantiate + context.scene.mesh_carver.OInstanciate = self.Instantiate + # Random rotation + context.scene.mesh_carver.ORandom = self.RandomRotation + + return {'FINISHED'} + else: + self.Cut() + UndoListUpdate(self) #----------------------------------------------------- @@ -343,1005 +343,1005 @@ class CARVER_OT_operator(bpy.types.Operator): #----------------------------------------------------- - # Object creation - if event.type == self.carver_prefs.Key_Create and event.value == 'PRESS': - if self.ExclusiveCreateMode is False: - self.CreateMode = not self.CreateMode - - # Auto Bevel Update - if event.type == self.carver_prefs.Key_Update and event.value == 'PRESS': - self.Auto_BevelUpdate = not self.Auto_BevelUpdate - - # Boolean operation type - if event.type == self.carver_prefs.Key_Bool and event.value == 'PRESS': - if (self.ProfileMode is True) or (self.ObjectMode is True): - if self.BoolOps == self.difference: - self.BoolOps = self.union - else: - self.BoolOps = self.difference - - # Brush Mode - if event.type == self.carver_prefs.Key_Brush and event.value == 'PRESS': - self.dont_apply_boolean = False - if (self.ProfileMode is False) and (self.ObjectMode is False): - self.ProfileMode = True - else: - self.ProfileMode = False - if self.ObjectBrush is not None: - if self.ObjectMode is False: - self.ObjectMode = True - self.BrushSolidify = False - self.CList = self.OB_List - - Selection_Save_Restore(self) - context.scene.mesh_carver.nProfile = self.nProfil - else: - self.ObjectMode = False - else: - self.BrushSolidify = False - Selection_Save_Restore(self) - - if self.ProfileMode: - createMeshFromData(self) - self.ProfileBrush = bpy.data.objects["CT_Profil"] - Selection_Save(self) - self.BrushSolidify = True - - bpy.ops.object.select_all(action='TOGGLE') - self.ProfileBrush.select_set(True) - context.view_layer.objects.active = self.ProfileBrush - # Set xRay - self.ProfileBrush.show_in_front = True - - bpy.ops.object.modifier_add(type='SOLIDIFY') - context.object.modifiers["Solidify"].name = "CT_SOLIDIFY" - context.object.modifiers["CT_SOLIDIFY"].thickness = 0.1 - - Selection_Restore(self) - - self.CList = self.CurrentSelection - else: - if self.ObjectBrush is not None: - if self.ObjectMode is False: - if self.ObjectBrush is not None: - self.ObjectBrush.location = self.InitBrush['location'] - self.ObjectBrush.scale = self.InitBrush['scale'] - self.ObjectBrush.rotation_quaternion = self.InitBrush['rotation_quaternion'] - self.ObjectBrush.rotation_euler = self.InitBrush['rotation_euler'] - self.ObjectBrush.display_type = self.InitBrush['display_type'] - self.ObjectBrush.show_in_front = self.InitBrush['show_in_front'] - - #Store active and selected objects - Selection_Save(self) - - #Remove Carver modifier - self.BrushSolidify = False - bpy.ops.object.select_all(action='TOGGLE') - self.ObjectBrush.select_set(True) - context.view_layer.objects.active = self.ObjectBrush - bpy.ops.object.modifier_remove(modifier="CT_SOLIDIFY") - - #Restore selected and active object - Selection_Restore(self) - else: - if self.SolidifyPossible: - #Store active and selected objects - Selection_Save(self) - self.BrushSolidify = True - bpy.ops.object.select_all(action='TOGGLE') - self.ObjectBrush.select_set(True) - context.view_layer.objects.active = self.ObjectBrush - # Set xRay - self.ObjectBrush.show_in_front = True - bpy.ops.object.modifier_add(type='SOLIDIFY') - context.object.modifiers["Solidify"].name = "CT_SOLIDIFY" - context.object.modifiers["CT_SOLIDIFY"].thickness = 0.1 - - #Restore selected and active object - Selection_Restore(self) - - # Help display - if event.type == self.carver_prefs.Key_Help and event.value == 'PRESS': - self.AskHelp = not self.AskHelp - - # Instantiate object - if event.type == self.carver_prefs.Key_Instant and event.value == 'PRESS': - self.Instantiate = not self.Instantiate - - # Close polygonal shape - if event.type == self.carver_prefs.Key_Close and event.value == 'PRESS': - if self.CreateMode: - self.Closed = not self.Closed - - if event.type == self.carver_prefs.Key_Apply and event.value == 'PRESS': - self.dont_apply_boolean = not self.dont_apply_boolean - - # Scale object - if event.type == self.carver_prefs.Key_Scale and event.value == 'PRESS': - if self.ObjectScale is False: - self.mouse_region = event.mouse_region_x, event.mouse_region_y - self.ObjectScale = True - - # Grid : Snap on grid - if event.type == self.carver_prefs.Key_Snap and event.value == 'PRESS': - self.snap = not self.snap - - # Array : Add column - if event.type == 'UP_ARROW' and event.value == 'PRESS': - self.nbrow += 1 - update_grid(self, context) - - # Array : Delete column - elif event.type == 'DOWN_ARROW' and event.value == 'PRESS': - self.nbrow -= 1 - update_grid(self, context) - - # Array : Add row - elif event.type == 'RIGHT_ARROW' and event.value == 'PRESS': - self.nbcol += 1 - update_grid(self, context) - - # Array : Delete row - elif event.type == 'LEFT_ARROW' and event.value == 'PRESS': - self.nbcol -= 1 - update_grid(self, context) - - # Array : Scale gap between columns - if event.type == self.carver_prefs.Key_Gapy and event.value == 'PRESS': - if self.GridScaleX is False: - self.mouse_region = event.mouse_region_x, event.mouse_region_y - self.GridScaleX = True - - # Array : Scale gap between rows - if event.type == self.carver_prefs.Key_Gapx and event.value == 'PRESS': - if self.GridScaleY is False: - self.mouse_region = event.mouse_region_x, event.mouse_region_y - self.GridScaleY = True - - # Cursor depth or solidify pattern - if event.type == self.carver_prefs.Key_Depth and event.value == 'PRESS': - if (self.ObjectMode is False) and (self.ProfileMode is False): - self.snapCursor = not self.snapCursor - else: - # Solidify - - if (self.ObjectMode or self.ProfileMode) and (self.SolidifyPossible): - solidify = True - - if self.ObjectMode: - z = self.ObjectBrush.data.vertices[0].co.z - ErrorMarge = 0.01 - for v in self.ObjectBrush.data.vertices: - if abs(v.co.z - z) > ErrorMarge: - solidify = False - self.CarveDepth = True - self.mouse_region = event.mouse_region_x, event.mouse_region_y - break - - if solidify: - if self.ObjectMode: - for mb in self.ObjectBrush.modifiers: - if mb.type == 'SOLIDIFY': - AlreadySoldify = True - else: - for mb in self.ProfileBrush.modifiers: - if mb.type == 'SOLIDIFY': - AlreadySoldify = True - - if AlreadySoldify is False: - Selection_Save(self) - self.BrushSolidify = True - - bpy.ops.object.select_all(action='TOGGLE') - if self.ObjectMode: - self.ObjectBrush.select_set(True) - context.view_layer.objects.active = self.ObjectBrush - # Active le xray - self.ObjectBrush.show_in_front = True - else: - self.ProfileBrush.select_set(True) - context.view_layer.objects.active = self.ProfileBrush - # Active le xray - self.ProfileBrush.show_in_front = True - - bpy.ops.object.modifier_add(type='SOLIDIFY') - context.object.modifiers["Solidify"].name = "CT_SOLIDIFY" - - context.object.modifiers["CT_SOLIDIFY"].thickness = 0.1 - - Selection_Restore(self) - - self.WidthSolidify = not self.WidthSolidify - self.mouse_region = event.mouse_region_x, event.mouse_region_y - - if event.type == self.carver_prefs.Key_BrushDepth and event.value == 'PRESS': - if self.ObjectMode: - self.CarveDepth = False - - self.BrushDepth = True - self.mouse_region = event.mouse_region_x, event.mouse_region_y - - # Random rotation - if event.type == 'R' and event.value == 'PRESS': - self.RandomRotation = not self.RandomRotation - - # Undo - if event.type == 'Z' and event.value == 'PRESS': - if self.ctrl: - if (self.CutType == self.line) and (self.CutMode): - if len(self.mouse_path) > 1: - self.mouse_path[len(self.mouse_path) - 1:] = [] - else: - Undo(self) - - # Mouse move - if event.type == 'MOUSEMOVE' : - if self.ObjectMode or self.ProfileMode: - fac = 50.0 - if self.shift: - fac = 500.0 - if self.WidthSolidify: - if self.ObjectMode: - bpy.data.objects[self.ObjectBrush.name].modifiers[ - "CT_SOLIDIFY"].thickness += (event.mouse_region_x - self.mouse_region[0]) / fac - elif self.ProfileMode: - bpy.data.objects[self.ProfileBrush.name].modifiers[ - "CT_SOLIDIFY"].thickness += (event.mouse_region_x - self.mouse_region[0]) / fac - self.mouse_region = event.mouse_region_x, event.mouse_region_y - elif self.CarveDepth: - for v in self.ObjectBrush.data.vertices: - v.co.z += (event.mouse_region_x - self.mouse_region[0]) / fac - self.mouse_region = event.mouse_region_x, event.mouse_region_y - elif self.BrushDepth: - self.BrushDepthOffset += (event.mouse_region_x - self.mouse_region[0]) / fac - self.mouse_region = event.mouse_region_x, event.mouse_region_y - else: - if (self.GridScaleX): - self.gapx += (event.mouse_region_x - self.mouse_region[0]) / 50 - self.mouse_region = event.mouse_region_x, event.mouse_region_y - update_grid(self, context) - return {'RUNNING_MODAL'} - - elif (self.GridScaleY): - self.gapy += (event.mouse_region_x - self.mouse_region[0]) / 50 - self.mouse_region = event.mouse_region_x, event.mouse_region_y - update_grid(self, context) - return {'RUNNING_MODAL'} - - elif self.ObjectScale: - self.ascale = -(event.mouse_region_x - self.mouse_region[0]) - self.mouse_region = event.mouse_region_x, event.mouse_region_y - - if self.ObjectMode: - self.ObjectBrush.scale.x -= float(self.ascale) / 150.0 - if self.ObjectBrush.scale.x <= 0.0: - self.ObjectBrush.scale.x = 0.0 - self.ObjectBrush.scale.y -= float(self.ascale) / 150.0 - if self.ObjectBrush.scale.y <= 0.0: - self.ObjectBrush.scale.y = 0.0 - self.ObjectBrush.scale.z -= float(self.ascale) / 150.0 - if self.ObjectBrush.scale.z <= 0.0: - self.ObjectBrush.scale.z = 0.0 - - elif self.ProfileMode: - if self.ProfileBrush is not None: - self.ProfileBrush.scale.x -= float(self.ascale) / 150.0 - self.ProfileBrush.scale.y -= float(self.ascale) / 150.0 - self.ProfileBrush.scale.z -= float(self.ascale) / 150.0 - else: - if self.LMB: - if self.ctrl: - self.aRotZ = - \ - ((int((event.mouse_region_x - self.xSavMouse) / 10.0) * PI / 4.0) * 25.0) - else: - self.aRotZ -= event.mouse_region_x - self.mouse_region[0] - self.ascale = 0.0 - - self.mouse_region = event.mouse_region_x, event.mouse_region_y - else: - target_hit, target_normal, target_eul_rotation = Pick(context, event, self) - if target_hit is not None: - self.ShowCursor = True - up_vector = Vector((0.0, 0.0, 1.0)) - quat_rot_axis = rot_axis_quat(up_vector, target_normal) - self.quat_rot = target_eul_rotation @ quat_rot_axis - MoveCursor(quat_rot_axis, target_hit, self) - self.SavCurLoc = target_hit - if self.ctrl: - if self.SavMousePos is not None: - xEcart = abs(self.SavMousePos.x - self.SavCurLoc.x) - yEcart = abs(self.SavMousePos.y - self.SavCurLoc.y) - zEcart = abs(self.SavMousePos.z - self.SavCurLoc.z) - if (xEcart > yEcart) and (xEcart > zEcart): - self.CurLoc = Vector( - (target_hit.x, self.SavMousePos.y, self.SavMousePos.z)) - if (yEcart > xEcart) and (yEcart > zEcart): - self.CurLoc = Vector( - (self.SavMousePos.x, target_hit.y, self.SavMousePos.z)) - if (zEcart > xEcart) and (zEcart > yEcart): - self.CurLoc = Vector( - (self.SavMousePos.x, self.SavMousePos.y, target_hit.z)) - else: - self.CurLoc = target_hit - else: - self.CurLoc = target_hit - else: - if self.CutMode: - if self.alt is False: - if self.ctrl : - # Find the closest position on the overlay grid and snap the mouse on it - # Draw a mini grid around the cursor - mouse_pos = [[event.mouse_region_x, event.mouse_region_y]] - Snap_Cursor(self, context, event, mouse_pos) - - else: - if len(self.mouse_path) > 0: - self.mouse_path[len(self.mouse_path) - - 1] = (event.mouse_region_x, event.mouse_region_y) - else: - # [ALT] press, update position - self.xpos += (event.mouse_region_x - self.last_mouse_region_x) - self.ypos += (event.mouse_region_y - self.last_mouse_region_y) - - self.last_mouse_region_x = event.mouse_region_x - self.last_mouse_region_y = event.mouse_region_y - - elif event.type == 'LEFTMOUSE' and event.value == 'PRESS': - if self.ObjectMode or self.ProfileMode: - if self.LMB is False: - target_hit, target_normal, target_eul_rotation = Pick(context, event, self) - if target_hit is not None: - up_vector = Vector((0.0, 0.0, 1.0)) - self.quat_rot_axis = rot_axis_quat(up_vector, target_normal) - self.quat_rot = target_eul_rotation @ self.quat_rot_axis - self.mouse_region = event.mouse_region_x, event.mouse_region_y - self.xSavMouse = event.mouse_region_x - - if self.ctrl: - self.nRotZ = int((self.aRotZ / 25.0) / (PI / 4.0)) - self.aRotZ = self.nRotZ * (PI / 4.0) * 25.0 - - self.LMB = True - - # LEFTMOUSE - elif event.type == 'LEFTMOUSE' and event.value == 'RELEASE' and self.in_view_3d: - if self.ObjectMode or self.ProfileMode: - # Rotation and scale - self.LMB = False - if self.ObjectScale is True: - self.ObjectScale = False - - if self.GridScaleX is True: - self.GridScaleX = False - - if self.GridScaleY is True: - self.GridScaleY = False - - if self.WidthSolidify: - self.WidthSolidify = False - - if self.CarveDepth is True: - self.CarveDepth = False - - if self.BrushDepth is True: - self.BrushDepth = False - - else: - if self.CutMode is False: - if self.ctrl: - Picking(context, event) - - else: - - if self.CutType == self.line: - if self.CutMode is False: - self.mouse_path.clear() - self.mouse_path.append((event.mouse_region_x, event.mouse_region_y)) - self.mouse_path.append((event.mouse_region_x, event.mouse_region_y)) - else: - self.mouse_path[0] = (event.mouse_region_x, event.mouse_region_y) - self.mouse_path[1] = (event.mouse_region_x, event.mouse_region_y) - self.CutMode = True - else: - if self.CutType != self.line: - # Cut creation - if self.CutType == self.rectangle: - CreateCutSquare(self, context) - if self.CutType == self.circle: - CreateCutCircle(self, context) - if self.CutType == self.line: - CreateCutLine(self, context) - - if self.CreateMode: - # Object creation - self.CreateGeometry() - bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW') - # Depth Cursor - context.scene.mesh_carver.DepthCursor = self.snapCursor - # Instantiate object - context.scene.mesh_carver.OInstanciate = self.Instantiate - # Random rotation - context.scene.mesh_carver.ORandom = self.RandomRotation - # Apply operation - context.scene.mesh_carver.DontApply = self.dont_apply_boolean - - # if Object mode, set initiale state - if self.ObjectBrush is not None: - self.ObjectBrush.location = self.InitBrush['location'] - self.ObjectBrush.scale = self.InitBrush['scale'] - self.ObjectBrush.rotation_quaternion = self.InitBrush['rotation_quaternion'] - self.ObjectBrush.rotation_euler = self.InitBrush['rotation_euler'] - self.ObjectBrush.display_type = self.InitBrush['display_type'] - self.ObjectBrush.show_in_front = self.InitBrush['show_in_front'] - - # remove solidify - Selection_Save(self) - self.BrushSolidify = False - - bpy.ops.object.select_all(action='TOGGLE') - self.ObjectBrush.select_set(True) - context.view_layer.objects.active = self.ObjectBrush - - bpy.ops.object.modifier_remove(modifier="CT_SOLIDIFY") - - Selection_Restore(self) - - context.scene.mesh_carver.nProfile = self.nProfil - - return {'FINISHED'} - else: - self.Cut() - UndoListUpdate(self) - else: - # Line - self.mouse_path.append((event.mouse_region_x, event.mouse_region_y)) - - # Change brush profil or circle subdivisions - elif (event.type == 'COMMA' and event.value == 'PRESS') or \ - (event.type == self.carver_prefs.Key_Subrem and event.value == 'PRESS'): - # Brush profil - if self.ProfileMode: - self.nProfil += 1 - if self.nProfil >= self.MaxProfil: - self.nProfil = 0 - createMeshFromData(self) - # Circle subdivisions - if self.CutType == self.circle: - self.step += 1 - if self.step >= len(self.stepAngle): - self.step = len(self.stepAngle) - 1 - # Change brush profil or circle subdivisions - elif (event.type == 'PERIOD' and event.value == 'PRESS') or \ - (event.type == self.carver_prefs.Key_Subadd and event.value == 'PRESS'): - # Brush profil - if self.ProfileMode: - self.nProfil -= 1 - if self.nProfil < 0: - self.nProfil = self.MaxProfil - 1 - createMeshFromData(self) - # Circle subdivisions - if self.CutType == self.circle: - if self.step > 0: - self.step -= 1 - # Quit - elif event.type in {'RIGHTMOUSE', 'ESC'}: - # Depth Cursor - context.scene.mesh_carver.DepthCursor = self.snapCursor - # Instantiate object - context.scene.mesh_carver.OInstanciate = self.Instantiate - # Random Rotation - context.scene.mesh_carver.ORandom = self.RandomRotation - # Apply boolean operation - context.scene.mesh_carver.DontApply = self.dont_apply_boolean - - # Reset Object - if self.ObjectBrush is not None: - self.ObjectBrush.location = self.InitBrush['location'] - self.ObjectBrush.scale = self.InitBrush['scale'] - self.ObjectBrush.rotation_quaternion = self.InitBrush['rotation_quaternion'] - self.ObjectBrush.rotation_euler = self.InitBrush['rotation_euler'] - self.ObjectBrush.display_type = self.InitBrush['display_type'] - self.ObjectBrush.show_in_front = self.InitBrush['show_in_front'] - - # Remove solidify modifier - Selection_Save(self) - self.BrushSolidify = False - - bpy.ops.object.select_all(action='TOGGLE') - self.ObjectBrush.select_set(True) - context.view_layer.objects.active = self.ObjectBrush - - bpy.ops.object.modifier_remove(modifier="CT_SOLIDIFY") - bpy.ops.object.select_all(action='TOGGLE') - - Selection_Restore(self) - - Selection_Save_Restore(self) - context.view_layer.objects.active = self.CurrentActive - context.scene.mesh_carver.nProfile = self.nProfil - - bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW') - - # Remove Copy Object Brush - if bpy.data.objects.get("CarverBrushCopy") is not None: - brush = bpy.data.objects["CarverBrushCopy"] - self.ObjectBrush.data = bpy.data.meshes[brush.data.name] - bpy.ops.object.select_all(action='DESELECT') - bpy.data.objects["CarverBrushCopy"].select_set(True) - bpy.ops.object.delete() - - return {'FINISHED'} - - return {'RUNNING_MODAL'} - - except: - print("\n[Carver MT ERROR]\n") - import traceback - traceback.print_exc() - - context.window.cursor_modal_set("DEFAULT") - context.area.header_text_set(None) - bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW') - - self.report({'WARNING'}, - "Operation finished. Failure during Carving (Check the console for more info)") - - return {'FINISHED'} - - def cancel(self, context): - # Note: used to prevent memory leaks on quitting Blender while the modal operator - # is still running, gets called on return {"CANCELLED"} - bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW') - - def invoke(self, context, event): - if context.area.type != 'VIEW_3D': - self.report({'WARNING'}, - "View3D not found or not currently active. Operation Cancelled") - self.cancel(context) - return {'CANCELLED'} - - # test if some other object types are selected that are not meshes - for obj in context.selected_objects: - if obj.type != "MESH": - self.report({'WARNING'}, - "Some selected objects are not of the Mesh type. Operation Cancelled") - self.cancel(context) - return {'CANCELLED'} - - if context.mode == 'EDIT_MESH': - bpy.ops.object.mode_set(mode='OBJECT') - - #Load the Carver preferences - self.carver_prefs = bpy.context.preferences.addons[__package__].preferences - - # Get default patterns - self.Profils = [] - for p in Profils: - self.Profils.append((p[0], p[1], p[2], p[3])) - - for o in context.scene.objects: - if not o.name.startswith(self.carver_prefs.ProfilePrefix): - continue - # In-scene profiles may have changed, remove them to refresh - for m in bpy.data.meshes: - if m.name.startswith(self.carver_prefs.ProfilePrefix): - bpy.data.meshes.remove(m) - - vertices = [] - for v in o.data.vertices: - vertices.append((v.co.x, v.co.y, v.co.z)) - - faces = [] - for f in o.data.polygons: - face = [] - for v in f.vertices: - face.append(v) - - faces.append(face) - - self.Profils.append( - (o.name, - Vector((o.location.x, o.location.y, o.location.z)), - vertices, faces) - ) - - self.nProfil = context.scene.mesh_carver.nProfile - self.MaxProfil = len(self.Profils) - - - # reset selected profile if last profile exceeds length of array - if self.nProfil >= self.MaxProfil: - self.nProfil = context.scene.mesh_carver.nProfile = 0 - - if len(context.selected_objects) > 1: - self.ObjectBrush = context.active_object - - # Copy the brush object - ob = bpy.data.objects.new("CarverBrushCopy", context.object.data.copy()) - ob.location = self.ObjectBrush.location - context.collection.objects.link(ob) - context.view_layer.update() - - # Save default variables - self.InitBrush['location'] = self.ObjectBrush.location.copy() - self.InitBrush['scale'] = self.ObjectBrush.scale.copy() - self.InitBrush['rotation_quaternion'] = self.ObjectBrush.rotation_quaternion.copy() - self.InitBrush['rotation_euler'] = self.ObjectBrush.rotation_euler.copy() - self.InitBrush['display_type'] = self.ObjectBrush.display_type - self.InitBrush['show_in_front'] = self.ObjectBrush.show_in_front - - # Test if flat object - z = self.ObjectBrush.data.vertices[0].co.z - ErrorMarge = 0.01 - self.SolidifyPossible = True - for v in self.ObjectBrush.data.vertices: - if abs(v.co.z - z) > ErrorMarge: - self.SolidifyPossible = False - break - - self.CList = [] - self.OPList = [] - self.RList = [] - self.OB_List = [] - - for obj in context.selected_objects: - if obj != self.ObjectBrush: - self.OB_List.append(obj) - - # Left button - self.LMB = False - - # Undo Variables - self.undo_index = 0 - self.undo_limit = context.preferences.edit.undo_steps - self.undo_list = [] - - # Boolean operations type - self.BooleanType = 0 - - self.UList = [] - self.UList_Index = -1 - self.UndoOps = [] - - context.window_manager.modal_handler_add(self) - return {'RUNNING_MODAL'} - - #Get the region area where the operator is used - def check_region(self,context,event): - if context.area != None: - if context.area.type == "VIEW_3D" : - for region in context.area.regions: - if region.type == "TOOLS": - t_panel = region - elif region.type == "UI": - ui_panel = region - - view_3d_region_x = Vector((context.area.x + t_panel.width, context.area.x + context.area.width - ui_panel.width)) - view_3d_region_y = Vector((context.region.y, context.region.y+context.region.height)) - - if (event.mouse_x > view_3d_region_x[0] and event.mouse_x < view_3d_region_x[1] \ - and event.mouse_y > view_3d_region_y[0] and event.mouse_y < view_3d_region_y[1]): - self.in_view_3d = True - else: - self.in_view_3d = False - else: - self.in_view_3d = False - - def CreateGeometry(self): - context = bpy.context - in_local_view = False - - for area in context.screen.areas: - if area.type == 'VIEW_3D': - if area.spaces[0].local_view is not None: - in_local_view = True - - if in_local_view: - bpy.ops.view3d.localview() - - if self.ExclusiveCreateMode: - # Default width - objBBDiagonal = 0.5 - else: - ActiveObj = self.CurrentSelection[0] - if ActiveObj is not None: - # Object dimensions - objBBDiagonal = objDiagonal(ActiveObj) / 4 - subdivisions = 2 - - if len(context.selected_objects) > 0: - bpy.ops.object.select_all(action='TOGGLE') - - context.view_layer.objects.active = self.CurrentObj - - bpy.data.objects[self.CurrentObj.name].select_set(True) - bpy.ops.object.origin_set(type='ORIGIN_GEOMETRY') - - bpy.ops.object.mode_set(mode='EDIT') - bpy.ops.mesh.select_all(action='SELECT') - bpy.ops.mesh.select_mode(type="EDGE") - if self.snapCursor is False: - bpy.ops.transform.translate(value=self.ViewVector * objBBDiagonal * subdivisions) - bpy.ops.mesh.extrude_region_move( - TRANSFORM_OT_translate={"value": -self.ViewVector * objBBDiagonal * subdivisions * 2}) - - bpy.ops.mesh.select_all(action='SELECT') - bpy.ops.mesh.normals_make_consistent() - bpy.ops.object.mode_set(mode='OBJECT') - - saved_location_0 = context.scene.cursor.location.copy() - bpy.ops.view3d.snap_cursor_to_active() - saved_location = context.scene.cursor.location.copy() - bpy.ops.object.transform_apply(location=True, rotation=True, scale=True) - context.scene.cursor.location = saved_location - bpy.ops.object.origin_set(type='ORIGIN_CURSOR') - context.scene.cursor.location = saved_location_0 - - bpy.data.objects[self.CurrentObj.name].select_set(True) - bpy.ops.object.origin_set(type='ORIGIN_GEOMETRY') - - for o in self.all_sel_obj_list: - bpy.data.objects[o.name].select_set(True) - - if in_local_view: - bpy.ops.view3d.localview() - - self.CutMode = False - self.mouse_path.clear() - self.mouse_path = [(0, 0), (0, 0)] - - def Cut(self): - context = bpy.context - - # Local view ? - in_local_view = False - for area in context.screen.areas: - if area.type == 'VIEW_3D': - if area.spaces[0].local_view is not None: - in_local_view = True - - if in_local_view: - bpy.ops.view3d.localview() - - # Save cursor position - CursorLocation = context.scene.cursor.location.copy() - - #List of selected objects - selected_obj_list = [] - - #Cut Mode with line - if (self.ObjectMode is False) and (self.ProfileMode is False): - - #Compute the bounding Box - objBBDiagonal = objDiagonal(self.CurrentSelection[0]) - if self.dont_apply_boolean: - subdivisions = 1 - else: - subdivisions = 32 - - # Get selected objects - selected_obj_list = context.selected_objects.copy() - - bpy.ops.object.select_all(action='TOGGLE') - - context.view_layer.objects.active = self.CurrentObj - - bpy.data.objects[self.CurrentObj.name].select_set(True) - bpy.ops.object.origin_set(type='ORIGIN_GEOMETRY') - - bpy.ops.object.mode_set(mode='EDIT') - bpy.ops.mesh.select_all(action='SELECT') - bpy.ops.mesh.select_mode(type="EDGE") - #Translate the created mesh away from the view - if (self.snapCursor is False) or (self.ForceRebool): - bpy.ops.transform.translate(value=self.ViewVector * objBBDiagonal * subdivisions) - #Extrude the mesh region and move the result - bpy.ops.mesh.extrude_region_move( - TRANSFORM_OT_translate={"value": -self.ViewVector * objBBDiagonal * subdivisions * 2}) - bpy.ops.mesh.select_all(action='SELECT') - bpy.ops.mesh.normals_make_consistent() - bpy.ops.object.mode_set(mode='OBJECT') - else: - # Create list - if self.ObjectMode: - for o in self.CurrentSelection: - if o != self.ObjectBrush: - selected_obj_list.append(o) - self.CurrentObj = self.ObjectBrush - else: - selected_obj_list = self.CurrentSelection - self.CurrentObj = self.ProfileBrush - - for obj in self.CurrentSelection: - UndoAdd(self, "MESH", obj) - - # List objects create with rebool - lastSelected = [] - - for ActiveObj in selected_obj_list: - context.scene.cursor.location = CursorLocation - - if len(context.selected_objects) > 0: - bpy.ops.object.select_all(action='TOGGLE') - - # Select cut object - bpy.data.objects[self.CurrentObj.name].select_set(True) - context.view_layer.objects.active = self.CurrentObj - - bpy.ops.object.mode_set(mode='EDIT') - bpy.ops.mesh.select_all(action='SELECT') - bpy.ops.object.mode_set(mode='OBJECT') - - # Select object to cut - bpy.data.objects[ActiveObj.name].select_set(True) - context.view_layer.objects.active = ActiveObj - - bpy.ops.object.mode_set(mode='EDIT') - bpy.ops.mesh.select_all(action='DESELECT') - bpy.ops.object.mode_set(mode='OBJECT') - - # Boolean operation - if (self.shift is False) and (self.ForceRebool is False): - if self.ObjectMode or self.ProfileMode: - if self.BoolOps == self.union: - boolean_operation(bool_type="UNION") - else: - boolean_operation(bool_type="DIFFERENCE") - else: - boolean_operation(bool_type="DIFFERENCE") - - # Apply booleans - if self.dont_apply_boolean is False: - BMname = "CT_" + self.CurrentObj.name - for mb in ActiveObj.modifiers: - if (mb.type == 'BOOLEAN') and (mb.name == BMname): - try: - bpy.ops.object.modifier_apply(apply_as='DATA', modifier=BMname) - except: - bpy.ops.object.modifier_remove(modifier=BMname) - exc_type, exc_value, exc_traceback = sys.exc_info() - self.report({'ERROR'}, str(exc_value)) - - bpy.ops.object.select_all(action='TOGGLE') - else: - if self.ObjectMode or self.ProfileMode: - for mb in self.CurrentObj.modifiers: - if (mb.type == 'SOLIDIFY') and (mb.name == "CT_SOLIDIFY"): - try: - bpy.ops.object.modifier_apply(apply_as='DATA', modifier="CT_SOLIDIFY") - except: - exc_type, exc_value, exc_traceback = sys.exc_info() - self.report({'ERROR'}, str(exc_value)) - - # Rebool - Rebool(context, self) - - # Test if not empty object - if context.selected_objects[0]: - rebool_RT = context.selected_objects[0] - if len(rebool_RT.data.vertices) > 0: - # Create Bevel for new objects - CreateBevel(context, context.selected_objects[0]) - - UndoAdd(self, "REBOOL", context.selected_objects[0]) - - context.scene.cursor.location = ActiveObj.location - bpy.ops.object.origin_set(type='ORIGIN_CURSOR') - else: - bpy.ops.object.delete(use_global=False) - - context.scene.cursor.location = CursorLocation - - if self.ObjectMode: - context.view_layer.objects.active = self.ObjectBrush - if self.ProfileMode: - context.view_layer.objects.active = self.ProfileBrush - - if self.dont_apply_boolean is False: - # Apply booleans - BMname = "CT_" + self.CurrentObj.name - for mb in ActiveObj.modifiers: - if (mb.type == 'BOOLEAN') and (mb.name == BMname): - try: - bpy.ops.object.modifier_apply(apply_as='DATA', modifier=BMname) - except: - bpy.ops.object.modifier_remove(modifier=BMname) - exc_type, exc_value, exc_traceback = sys.exc_info() - self.report({'ERROR'}, str(exc_value)) - # Get new objects created with rebool operations - if len(context.selected_objects) > 0: - if self.shift is True: - # Get the last object selected - lastSelected.append(context.selected_objects[0]) - - context.scene.cursor.location = CursorLocation - - if self.dont_apply_boolean is False: - # Remove cut object - if (self.ObjectMode is False) and (self.ProfileMode is False): - if len(context.selected_objects) > 0: - bpy.ops.object.select_all(action='TOGGLE') - bpy.data.objects[self.CurrentObj.name].select_set(True) - bpy.ops.object.delete(use_global=False) - else: - if self.ObjectMode: - self.ObjectBrush.display_type = self.InitBrush['display_type'] - - if len(context.selected_objects) > 0: - bpy.ops.object.select_all(action='TOGGLE') - - # Select cut objects - for obj in lastSelected: - bpy.data.objects[obj.name].select_set(True) - - for ActiveObj in selected_obj_list: - bpy.data.objects[ActiveObj.name].select_set(True) - context.view_layer.objects.active = ActiveObj - # Update bevel - list_act_obj = context.selected_objects.copy() - if self.Auto_BevelUpdate: - update_bevel(context) - - # Re-select initial objects - bpy.ops.object.select_all(action='TOGGLE') - if self.ObjectMode: - # Re-select brush - self.ObjectBrush.select_set(True) - for ActiveObj in selected_obj_list: - bpy.data.objects[ActiveObj.name].select_set(True) - context.view_layer.objects.active = ActiveObj - - # If object has children, set "Wire" draw type - if self.ObjectBrush is not None: - if len(self.ObjectBrush.children) > 0: - self.ObjectBrush.display_type = "WIRE" - if self.ProfileMode: - self.ProfileBrush.display_type = "WIRE" - - if in_local_view: - bpy.ops.view3d.localview() - - # Reset variables - self.CutMode = False - self.mouse_path.clear() - self.mouse_path = [(0, 0), (0, 0)] - - self.ForceRebool = False - - # bpy.ops.mesh.customdata_custom_splitnormals_clear() + # Object creation + if event.type == self.carver_prefs.Key_Create and event.value == 'PRESS': + if self.ExclusiveCreateMode is False: + self.CreateMode = not self.CreateMode + + # Auto Bevel Update + if event.type == self.carver_prefs.Key_Update and event.value == 'PRESS': + self.Auto_BevelUpdate = not self.Auto_BevelUpdate + + # Boolean operation type + if event.type == self.carver_prefs.Key_Bool and event.value == 'PRESS': + if (self.ProfileMode is True) or (self.ObjectMode is True): + if self.BoolOps == self.difference: + self.BoolOps = self.union + else: + self.BoolOps = self.difference + + # Brush Mode + if event.type == self.carver_prefs.Key_Brush and event.value == 'PRESS': + self.dont_apply_boolean = False + if (self.ProfileMode is False) and (self.ObjectMode is False): + self.ProfileMode = True + else: + self.ProfileMode = False + if self.ObjectBrush is not None: + if self.ObjectMode is False: + self.ObjectMode = True + self.BrushSolidify = False + self.CList = self.OB_List + + Selection_Save_Restore(self) + context.scene.mesh_carver.nProfile = self.nProfil + else: + self.ObjectMode = False + else: + self.BrushSolidify = False + Selection_Save_Restore(self) + + if self.ProfileMode: + createMeshFromData(self) + self.ProfileBrush = bpy.data.objects["CT_Profil"] + Selection_Save(self) + self.BrushSolidify = True + + bpy.ops.object.select_all(action='TOGGLE') + self.ProfileBrush.select_set(True) + context.view_layer.objects.active = self.ProfileBrush + # Set xRay + self.ProfileBrush.show_in_front = True + + bpy.ops.object.modifier_add(type='SOLIDIFY') + context.object.modifiers["Solidify"].name = "CT_SOLIDIFY" + context.object.modifiers["CT_SOLIDIFY"].thickness = 0.1 + + Selection_Restore(self) + + self.CList = self.CurrentSelection + else: + if self.ObjectBrush is not None: + if self.ObjectMode is False: + if self.ObjectBrush is not None: + self.ObjectBrush.location = self.InitBrush['location'] + self.ObjectBrush.scale = self.InitBrush['scale'] + self.ObjectBrush.rotation_quaternion = self.InitBrush['rotation_quaternion'] + self.ObjectBrush.rotation_euler = self.InitBrush['rotation_euler'] + self.ObjectBrush.display_type = self.InitBrush['display_type'] + self.ObjectBrush.show_in_front = self.InitBrush['show_in_front'] + + #Store active and selected objects + Selection_Save(self) + + #Remove Carver modifier + self.BrushSolidify = False + bpy.ops.object.select_all(action='TOGGLE') + self.ObjectBrush.select_set(True) + context.view_layer.objects.active = self.ObjectBrush + bpy.ops.object.modifier_remove(modifier="CT_SOLIDIFY") + + #Restore selected and active object + Selection_Restore(self) + else: + if self.SolidifyPossible: + #Store active and selected objects + Selection_Save(self) + self.BrushSolidify = True + bpy.ops.object.select_all(action='TOGGLE') + self.ObjectBrush.select_set(True) + context.view_layer.objects.active = self.ObjectBrush + # Set xRay + self.ObjectBrush.show_in_front = True + bpy.ops.object.modifier_add(type='SOLIDIFY') + context.object.modifiers["Solidify"].name = "CT_SOLIDIFY" + context.object.modifiers["CT_SOLIDIFY"].thickness = 0.1 + + #Restore selected and active object + Selection_Restore(self) + + # Help display + if event.type == self.carver_prefs.Key_Help and event.value == 'PRESS': + self.AskHelp = not self.AskHelp + + # Instantiate object + if event.type == self.carver_prefs.Key_Instant and event.value == 'PRESS': + self.Instantiate = not self.Instantiate + + # Close polygonal shape + if event.type == self.carver_prefs.Key_Close and event.value == 'PRESS': + if self.CreateMode: + self.Closed = not self.Closed + + if event.type == self.carver_prefs.Key_Apply and event.value == 'PRESS': + self.dont_apply_boolean = not self.dont_apply_boolean + + # Scale object + if event.type == self.carver_prefs.Key_Scale and event.value == 'PRESS': + if self.ObjectScale is False: + self.mouse_region = event.mouse_region_x, event.mouse_region_y + self.ObjectScale = True + + # Grid : Snap on grid + if event.type == self.carver_prefs.Key_Snap and event.value == 'PRESS': + self.snap = not self.snap + + # Array : Add column + if event.type == 'UP_ARROW' and event.value == 'PRESS': + self.nbrow += 1 + update_grid(self, context) + + # Array : Delete column + elif event.type == 'DOWN_ARROW' and event.value == 'PRESS': + self.nbrow -= 1 + update_grid(self, context) + + # Array : Add row + elif event.type == 'RIGHT_ARROW' and event.value == 'PRESS': + self.nbcol += 1 + update_grid(self, context) + + # Array : Delete row + elif event.type == 'LEFT_ARROW' and event.value == 'PRESS': + self.nbcol -= 1 + update_grid(self, context) + + # Array : Scale gap between columns + if event.type == self.carver_prefs.Key_Gapy and event.value == 'PRESS': + if self.GridScaleX is False: + self.mouse_region = event.mouse_region_x, event.mouse_region_y + self.GridScaleX = True + + # Array : Scale gap between rows + if event.type == self.carver_prefs.Key_Gapx and event.value == 'PRESS': + if self.GridScaleY is False: + self.mouse_region = event.mouse_region_x, event.mouse_region_y + self.GridScaleY = True + + # Cursor depth or solidify pattern + if event.type == self.carver_prefs.Key_Depth and event.value == 'PRESS': + if (self.ObjectMode is False) and (self.ProfileMode is False): + self.snapCursor = not self.snapCursor + else: + # Solidify + + if (self.ObjectMode or self.ProfileMode) and (self.SolidifyPossible): + solidify = True + + if self.ObjectMode: + z = self.ObjectBrush.data.vertices[0].co.z + ErrorMarge = 0.01 + for v in self.ObjectBrush.data.vertices: + if abs(v.co.z - z) > ErrorMarge: + solidify = False + self.CarveDepth = True + self.mouse_region = event.mouse_region_x, event.mouse_region_y + break + + if solidify: + if self.ObjectMode: + for mb in self.ObjectBrush.modifiers: + if mb.type == 'SOLIDIFY': + AlreadySoldify = True + else: + for mb in self.ProfileBrush.modifiers: + if mb.type == 'SOLIDIFY': + AlreadySoldify = True + + if AlreadySoldify is False: + Selection_Save(self) + self.BrushSolidify = True + + bpy.ops.object.select_all(action='TOGGLE') + if self.ObjectMode: + self.ObjectBrush.select_set(True) + context.view_layer.objects.active = self.ObjectBrush + # Active le xray + self.ObjectBrush.show_in_front = True + else: + self.ProfileBrush.select_set(True) + context.view_layer.objects.active = self.ProfileBrush + # Active le xray + self.ProfileBrush.show_in_front = True + + bpy.ops.object.modifier_add(type='SOLIDIFY') + context.object.modifiers["Solidify"].name = "CT_SOLIDIFY" + + context.object.modifiers["CT_SOLIDIFY"].thickness = 0.1 + + Selection_Restore(self) + + self.WidthSolidify = not self.WidthSolidify + self.mouse_region = event.mouse_region_x, event.mouse_region_y + + if event.type == self.carver_prefs.Key_BrushDepth and event.value == 'PRESS': + if self.ObjectMode: + self.CarveDepth = False + + self.BrushDepth = True + self.mouse_region = event.mouse_region_x, event.mouse_region_y + + # Random rotation + if event.type == 'R' and event.value == 'PRESS': + self.RandomRotation = not self.RandomRotation + + # Undo + if event.type == 'Z' and event.value == 'PRESS': + if self.ctrl: + if (self.CutType == self.line) and (self.CutMode): + if len(self.mouse_path) > 1: + self.mouse_path[len(self.mouse_path) - 1:] = [] + else: + Undo(self) + + # Mouse move + if event.type == 'MOUSEMOVE' : + if self.ObjectMode or self.ProfileMode: + fac = 50.0 + if self.shift: + fac = 500.0 + if self.WidthSolidify: + if self.ObjectMode: + bpy.data.objects[self.ObjectBrush.name].modifiers[ + "CT_SOLIDIFY"].thickness += (event.mouse_region_x - self.mouse_region[0]) / fac + elif self.ProfileMode: + bpy.data.objects[self.ProfileBrush.name].modifiers[ + "CT_SOLIDIFY"].thickness += (event.mouse_region_x - self.mouse_region[0]) / fac + self.mouse_region = event.mouse_region_x, event.mouse_region_y + elif self.CarveDepth: + for v in self.ObjectBrush.data.vertices: + v.co.z += (event.mouse_region_x - self.mouse_region[0]) / fac + self.mouse_region = event.mouse_region_x, event.mouse_region_y + elif self.BrushDepth: + self.BrushDepthOffset += (event.mouse_region_x - self.mouse_region[0]) / fac + self.mouse_region = event.mouse_region_x, event.mouse_region_y + else: + if (self.GridScaleX): + self.gapx += (event.mouse_region_x - self.mouse_region[0]) / 50 + self.mouse_region = event.mouse_region_x, event.mouse_region_y + update_grid(self, context) + return {'RUNNING_MODAL'} + + elif (self.GridScaleY): + self.gapy += (event.mouse_region_x - self.mouse_region[0]) / 50 + self.mouse_region = event.mouse_region_x, event.mouse_region_y + update_grid(self, context) + return {'RUNNING_MODAL'} + + elif self.ObjectScale: + self.ascale = -(event.mouse_region_x - self.mouse_region[0]) + self.mouse_region = event.mouse_region_x, event.mouse_region_y + + if self.ObjectMode: + self.ObjectBrush.scale.x -= float(self.ascale) / 150.0 + if self.ObjectBrush.scale.x <= 0.0: + self.ObjectBrush.scale.x = 0.0 + self.ObjectBrush.scale.y -= float(self.ascale) / 150.0 + if self.ObjectBrush.scale.y <= 0.0: + self.ObjectBrush.scale.y = 0.0 + self.ObjectBrush.scale.z -= float(self.ascale) / 150.0 + if self.ObjectBrush.scale.z <= 0.0: + self.ObjectBrush.scale.z = 0.0 + + elif self.ProfileMode: + if self.ProfileBrush is not None: + self.ProfileBrush.scale.x -= float(self.ascale) / 150.0 + self.ProfileBrush.scale.y -= float(self.ascale) / 150.0 + self.ProfileBrush.scale.z -= float(self.ascale) / 150.0 + else: + if self.LMB: + if self.ctrl: + self.aRotZ = - \ + ((int((event.mouse_region_x - self.xSavMouse) / 10.0) * PI / 4.0) * 25.0) + else: + self.aRotZ -= event.mouse_region_x - self.mouse_region[0] + self.ascale = 0.0 + + self.mouse_region = event.mouse_region_x, event.mouse_region_y + else: + target_hit, target_normal, target_eul_rotation = Pick(context, event, self) + if target_hit is not None: + self.ShowCursor = True + up_vector = Vector((0.0, 0.0, 1.0)) + quat_rot_axis = rot_axis_quat(up_vector, target_normal) + self.quat_rot = target_eul_rotation @ quat_rot_axis + MoveCursor(quat_rot_axis, target_hit, self) + self.SavCurLoc = target_hit + if self.ctrl: + if self.SavMousePos is not None: + xEcart = abs(self.SavMousePos.x - self.SavCurLoc.x) + yEcart = abs(self.SavMousePos.y - self.SavCurLoc.y) + zEcart = abs(self.SavMousePos.z - self.SavCurLoc.z) + if (xEcart > yEcart) and (xEcart > zEcart): + self.CurLoc = Vector( + (target_hit.x, self.SavMousePos.y, self.SavMousePos.z)) + if (yEcart > xEcart) and (yEcart > zEcart): + self.CurLoc = Vector( + (self.SavMousePos.x, target_hit.y, self.SavMousePos.z)) + if (zEcart > xEcart) and (zEcart > yEcart): + self.CurLoc = Vector( + (self.SavMousePos.x, self.SavMousePos.y, target_hit.z)) + else: + self.CurLoc = target_hit + else: + self.CurLoc = target_hit + else: + if self.CutMode: + if self.alt is False: + if self.ctrl : + # Find the closest position on the overlay grid and snap the mouse on it + # Draw a mini grid around the cursor + mouse_pos = [[event.mouse_region_x, event.mouse_region_y]] + Snap_Cursor(self, context, event, mouse_pos) + + else: + if len(self.mouse_path) > 0: + self.mouse_path[len(self.mouse_path) - + 1] = (event.mouse_region_x, event.mouse_region_y) + else: + # [ALT] press, update position + self.xpos += (event.mouse_region_x - self.last_mouse_region_x) + self.ypos += (event.mouse_region_y - self.last_mouse_region_y) + + self.last_mouse_region_x = event.mouse_region_x + self.last_mouse_region_y = event.mouse_region_y + + elif event.type == 'LEFTMOUSE' and event.value == 'PRESS': + if self.ObjectMode or self.ProfileMode: + if self.LMB is False: + target_hit, target_normal, target_eul_rotation = Pick(context, event, self) + if target_hit is not None: + up_vector = Vector((0.0, 0.0, 1.0)) + self.quat_rot_axis = rot_axis_quat(up_vector, target_normal) + self.quat_rot = target_eul_rotation @ self.quat_rot_axis + self.mouse_region = event.mouse_region_x, event.mouse_region_y + self.xSavMouse = event.mouse_region_x + + if self.ctrl: + self.nRotZ = int((self.aRotZ / 25.0) / (PI / 4.0)) + self.aRotZ = self.nRotZ * (PI / 4.0) * 25.0 + + self.LMB = True + + # LEFTMOUSE + elif event.type == 'LEFTMOUSE' and event.value == 'RELEASE' and self.in_view_3d: + if self.ObjectMode or self.ProfileMode: + # Rotation and scale + self.LMB = False + if self.ObjectScale is True: + self.ObjectScale = False + + if self.GridScaleX is True: + self.GridScaleX = False + + if self.GridScaleY is True: + self.GridScaleY = False + + if self.WidthSolidify: + self.WidthSolidify = False + + if self.CarveDepth is True: + self.CarveDepth = False + + if self.BrushDepth is True: + self.BrushDepth = False + + else: + if self.CutMode is False: + if self.ctrl: + Picking(context, event) + + else: + + if self.CutType == self.line: + if self.CutMode is False: + self.mouse_path.clear() + self.mouse_path.append((event.mouse_region_x, event.mouse_region_y)) + self.mouse_path.append((event.mouse_region_x, event.mouse_region_y)) + else: + self.mouse_path[0] = (event.mouse_region_x, event.mouse_region_y) + self.mouse_path[1] = (event.mouse_region_x, event.mouse_region_y) + self.CutMode = True + else: + if self.CutType != self.line: + # Cut creation + if self.CutType == self.rectangle: + CreateCutSquare(self, context) + if self.CutType == self.circle: + CreateCutCircle(self, context) + if self.CutType == self.line: + CreateCutLine(self, context) + + if self.CreateMode: + # Object creation + self.CreateGeometry() + bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW') + # Depth Cursor + context.scene.mesh_carver.DepthCursor = self.snapCursor + # Instantiate object + context.scene.mesh_carver.OInstanciate = self.Instantiate + # Random rotation + context.scene.mesh_carver.ORandom = self.RandomRotation + # Apply operation + context.scene.mesh_carver.DontApply = self.dont_apply_boolean + + # if Object mode, set initiale state + if self.ObjectBrush is not None: + self.ObjectBrush.location = self.InitBrush['location'] + self.ObjectBrush.scale = self.InitBrush['scale'] + self.ObjectBrush.rotation_quaternion = self.InitBrush['rotation_quaternion'] + self.ObjectBrush.rotation_euler = self.InitBrush['rotation_euler'] + self.ObjectBrush.display_type = self.InitBrush['display_type'] + self.ObjectBrush.show_in_front = self.InitBrush['show_in_front'] + + # remove solidify + Selection_Save(self) + self.BrushSolidify = False + + bpy.ops.object.select_all(action='TOGGLE') + self.ObjectBrush.select_set(True) + context.view_layer.objects.active = self.ObjectBrush + + bpy.ops.object.modifier_remove(modifier="CT_SOLIDIFY") + + Selection_Restore(self) + + context.scene.mesh_carver.nProfile = self.nProfil + + return {'FINISHED'} + else: + self.Cut() + UndoListUpdate(self) + else: + # Line + self.mouse_path.append((event.mouse_region_x, event.mouse_region_y)) + + # Change brush profil or circle subdivisions + elif (event.type == 'COMMA' and event.value == 'PRESS') or \ + (event.type == self.carver_prefs.Key_Subrem and event.value == 'PRESS'): + # Brush profil + if self.ProfileMode: + self.nProfil += 1 + if self.nProfil >= self.MaxProfil: + self.nProfil = 0 + createMeshFromData(self) + # Circle subdivisions + if self.CutType == self.circle: + self.step += 1 + if self.step >= len(self.stepAngle): + self.step = len(self.stepAngle) - 1 + # Change brush profil or circle subdivisions + elif (event.type == 'PERIOD' and event.value == 'PRESS') or \ + (event.type == self.carver_prefs.Key_Subadd and event.value == 'PRESS'): + # Brush profil + if self.ProfileMode: + self.nProfil -= 1 + if self.nProfil < 0: + self.nProfil = self.MaxProfil - 1 + createMeshFromData(self) + # Circle subdivisions + if self.CutType == self.circle: + if self.step > 0: + self.step -= 1 + # Quit + elif event.type in {'RIGHTMOUSE', 'ESC'}: + # Depth Cursor + context.scene.mesh_carver.DepthCursor = self.snapCursor + # Instantiate object + context.scene.mesh_carver.OInstanciate = self.Instantiate + # Random Rotation + context.scene.mesh_carver.ORandom = self.RandomRotation + # Apply boolean operation + context.scene.mesh_carver.DontApply = self.dont_apply_boolean + + # Reset Object + if self.ObjectBrush is not None: + self.ObjectBrush.location = self.InitBrush['location'] + self.ObjectBrush.scale = self.InitBrush['scale'] + self.ObjectBrush.rotation_quaternion = self.InitBrush['rotation_quaternion'] + self.ObjectBrush.rotation_euler = self.InitBrush['rotation_euler'] + self.ObjectBrush.display_type = self.InitBrush['display_type'] + self.ObjectBrush.show_in_front = self.InitBrush['show_in_front'] + + # Remove solidify modifier + Selection_Save(self) + self.BrushSolidify = False + + bpy.ops.object.select_all(action='TOGGLE') + self.ObjectBrush.select_set(True) + context.view_layer.objects.active = self.ObjectBrush + + bpy.ops.object.modifier_remove(modifier="CT_SOLIDIFY") + bpy.ops.object.select_all(action='TOGGLE') + + Selection_Restore(self) + + Selection_Save_Restore(self) + context.view_layer.objects.active = self.CurrentActive + context.scene.mesh_carver.nProfile = self.nProfil + + bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW') + + # Remove Copy Object Brush + if bpy.data.objects.get("CarverBrushCopy") is not None: + brush = bpy.data.objects["CarverBrushCopy"] + self.ObjectBrush.data = bpy.data.meshes[brush.data.name] + bpy.ops.object.select_all(action='DESELECT') + bpy.data.objects["CarverBrushCopy"].select_set(True) + bpy.ops.object.delete() + + return {'FINISHED'} + + return {'RUNNING_MODAL'} + + except: + print("\n[Carver MT ERROR]\n") + import traceback + traceback.print_exc() + + context.window.cursor_modal_set("DEFAULT") + context.area.header_text_set(None) + bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW') + + self.report({'WARNING'}, + "Operation finished. Failure during Carving (Check the console for more info)") + + return {'FINISHED'} + + def cancel(self, context): + # Note: used to prevent memory leaks on quitting Blender while the modal operator + # is still running, gets called on return {"CANCELLED"} + bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW') + + def invoke(self, context, event): + if context.area.type != 'VIEW_3D': + self.report({'WARNING'}, + "View3D not found or not currently active. Operation Cancelled") + self.cancel(context) + return {'CANCELLED'} + + # test if some other object types are selected that are not meshes + for obj in context.selected_objects: + if obj.type != "MESH": + self.report({'WARNING'}, + "Some selected objects are not of the Mesh type. Operation Cancelled") + self.cancel(context) + return {'CANCELLED'} + + if context.mode == 'EDIT_MESH': + bpy.ops.object.mode_set(mode='OBJECT') + + #Load the Carver preferences + self.carver_prefs = bpy.context.preferences.addons[__package__].preferences + + # Get default patterns + self.Profils = [] + for p in Profils: + self.Profils.append((p[0], p[1], p[2], p[3])) + + for o in context.scene.objects: + if not o.name.startswith(self.carver_prefs.ProfilePrefix): + continue + # In-scene profiles may have changed, remove them to refresh + for m in bpy.data.meshes: + if m.name.startswith(self.carver_prefs.ProfilePrefix): + bpy.data.meshes.remove(m) + + vertices = [] + for v in o.data.vertices: + vertices.append((v.co.x, v.co.y, v.co.z)) + + faces = [] + for f in o.data.polygons: + face = [] + for v in f.vertices: + face.append(v) + + faces.append(face) + + self.Profils.append( + (o.name, + Vector((o.location.x, o.location.y, o.location.z)), + vertices, faces) + ) + + self.nProfil = context.scene.mesh_carver.nProfile + self.MaxProfil = len(self.Profils) + + + # reset selected profile if last profile exceeds length of array + if self.nProfil >= self.MaxProfil: + self.nProfil = context.scene.mesh_carver.nProfile = 0 + + if len(context.selected_objects) > 1: + self.ObjectBrush = context.active_object + + # Copy the brush object + ob = bpy.data.objects.new("CarverBrushCopy", context.object.data.copy()) + ob.location = self.ObjectBrush.location + context.collection.objects.link(ob) + context.view_layer.update() + + # Save default variables + self.InitBrush['location'] = self.ObjectBrush.location.copy() + self.InitBrush['scale'] = self.ObjectBrush.scale.copy() + self.InitBrush['rotation_quaternion'] = self.ObjectBrush.rotation_quaternion.copy() + self.InitBrush['rotation_euler'] = self.ObjectBrush.rotation_euler.copy() + self.InitBrush['display_type'] = self.ObjectBrush.display_type + self.InitBrush['show_in_front'] = self.ObjectBrush.show_in_front + + # Test if flat object + z = self.ObjectBrush.data.vertices[0].co.z + ErrorMarge = 0.01 + self.SolidifyPossible = True + for v in self.ObjectBrush.data.vertices: + if abs(v.co.z - z) > ErrorMarge: + self.SolidifyPossible = False + break + + self.CList = [] + self.OPList = [] + self.RList = [] + self.OB_List = [] + + for obj in context.selected_objects: + if obj != self.ObjectBrush: + self.OB_List.append(obj) + + # Left button + self.LMB = False + + # Undo Variables + self.undo_index = 0 + self.undo_limit = context.preferences.edit.undo_steps + self.undo_list = [] + + # Boolean operations type + self.BooleanType = 0 + + self.UList = [] + self.UList_Index = -1 + self.UndoOps = [] + + context.window_manager.modal_handler_add(self) + return {'RUNNING_MODAL'} + + #Get the region area where the operator is used + def check_region(self,context,event): + if context.area != None: + if context.area.type == "VIEW_3D" : + for region in context.area.regions: + if region.type == "TOOLS": + t_panel = region + elif region.type == "UI": + ui_panel = region + + view_3d_region_x = Vector((context.area.x + t_panel.width, context.area.x + context.area.width - ui_panel.width)) + view_3d_region_y = Vector((context.region.y, context.region.y+context.region.height)) + + if (event.mouse_x > view_3d_region_x[0] and event.mouse_x < view_3d_region_x[1] \ + and event.mouse_y > view_3d_region_y[0] and event.mouse_y < view_3d_region_y[1]): + self.in_view_3d = True + else: + self.in_view_3d = False + else: + self.in_view_3d = False + + def CreateGeometry(self): + context = bpy.context + in_local_view = False + + for area in context.screen.areas: + if area.type == 'VIEW_3D': + if area.spaces[0].local_view is not None: + in_local_view = True + + if in_local_view: + bpy.ops.view3d.localview() + + if self.ExclusiveCreateMode: + # Default width + objBBDiagonal = 0.5 + else: + ActiveObj = self.CurrentSelection[0] + if ActiveObj is not None: + # Object dimensions + objBBDiagonal = objDiagonal(ActiveObj) / 4 + subdivisions = 2 + + if len(context.selected_objects) > 0: + bpy.ops.object.select_all(action='TOGGLE') + + context.view_layer.objects.active = self.CurrentObj + + bpy.data.objects[self.CurrentObj.name].select_set(True) + bpy.ops.object.origin_set(type='ORIGIN_GEOMETRY') + + bpy.ops.object.mode_set(mode='EDIT') + bpy.ops.mesh.select_all(action='SELECT') + bpy.ops.mesh.select_mode(type="EDGE") + if self.snapCursor is False: + bpy.ops.transform.translate(value=self.ViewVector * objBBDiagonal * subdivisions) + bpy.ops.mesh.extrude_region_move( + TRANSFORM_OT_translate={"value": -self.ViewVector * objBBDiagonal * subdivisions * 2}) + + bpy.ops.mesh.select_all(action='SELECT') + bpy.ops.mesh.normals_make_consistent() + bpy.ops.object.mode_set(mode='OBJECT') + + saved_location_0 = context.scene.cursor.location.copy() + bpy.ops.view3d.snap_cursor_to_active() + saved_location = context.scene.cursor.location.copy() + bpy.ops.object.transform_apply(location=True, rotation=True, scale=True) + context.scene.cursor.location = saved_location + bpy.ops.object.origin_set(type='ORIGIN_CURSOR') + context.scene.cursor.location = saved_location_0 + + bpy.data.objects[self.CurrentObj.name].select_set(True) + bpy.ops.object.origin_set(type='ORIGIN_GEOMETRY') + + for o in self.all_sel_obj_list: + bpy.data.objects[o.name].select_set(True) + + if in_local_view: + bpy.ops.view3d.localview() + + self.CutMode = False + self.mouse_path.clear() + self.mouse_path = [(0, 0), (0, 0)] + + def Cut(self): + context = bpy.context + + # Local view ? + in_local_view = False + for area in context.screen.areas: + if area.type == 'VIEW_3D': + if area.spaces[0].local_view is not None: + in_local_view = True + + if in_local_view: + bpy.ops.view3d.localview() + + # Save cursor position + CursorLocation = context.scene.cursor.location.copy() + + #List of selected objects + selected_obj_list = [] + + #Cut Mode with line + if (self.ObjectMode is False) and (self.ProfileMode is False): + + #Compute the bounding Box + objBBDiagonal = objDiagonal(self.CurrentSelection[0]) + if self.dont_apply_boolean: + subdivisions = 1 + else: + subdivisions = 32 + + # Get selected objects + selected_obj_list = context.selected_objects.copy() + + bpy.ops.object.select_all(action='TOGGLE') + + context.view_layer.objects.active = self.CurrentObj + + bpy.data.objects[self.CurrentObj.name].select_set(True) + bpy.ops.object.origin_set(type='ORIGIN_GEOMETRY') + + bpy.ops.object.mode_set(mode='EDIT') + bpy.ops.mesh.select_all(action='SELECT') + bpy.ops.mesh.select_mode(type="EDGE") + #Translate the created mesh away from the view + if (self.snapCursor is False) or (self.ForceRebool): + bpy.ops.transform.translate(value=self.ViewVector * objBBDiagonal * subdivisions) + #Extrude the mesh region and move the result + bpy.ops.mesh.extrude_region_move( + TRANSFORM_OT_translate={"value": -self.ViewVector * objBBDiagonal * subdivisions * 2}) + bpy.ops.mesh.select_all(action='SELECT') + bpy.ops.mesh.normals_make_consistent() + bpy.ops.object.mode_set(mode='OBJECT') + else: + # Create list + if self.ObjectMode: + for o in self.CurrentSelection: + if o != self.ObjectBrush: + selected_obj_list.append(o) + self.CurrentObj = self.ObjectBrush + else: + selected_obj_list = self.CurrentSelection + self.CurrentObj = self.ProfileBrush + + for obj in self.CurrentSelection: + UndoAdd(self, "MESH", obj) + + # List objects create with rebool + lastSelected = [] + + for ActiveObj in selected_obj_list: + context.scene.cursor.location = CursorLocation + + if len(context.selected_objects) > 0: + bpy.ops.object.select_all(action='TOGGLE') + + # Select cut object + bpy.data.objects[self.CurrentObj.name].select_set(True) + context.view_layer.objects.active = self.CurrentObj + + bpy.ops.object.mode_set(mode='EDIT') + bpy.ops.mesh.select_all(action='SELECT') + bpy.ops.object.mode_set(mode='OBJECT') + + # Select object to cut + bpy.data.objects[ActiveObj.name].select_set(True) + context.view_layer.objects.active = ActiveObj + + bpy.ops.object.mode_set(mode='EDIT') + bpy.ops.mesh.select_all(action='DESELECT') + bpy.ops.object.mode_set(mode='OBJECT') + + # Boolean operation + if (self.shift is False) and (self.ForceRebool is False): + if self.ObjectMode or self.ProfileMode: + if self.BoolOps == self.union: + boolean_operation(bool_type="UNION") + else: + boolean_operation(bool_type="DIFFERENCE") + else: + boolean_operation(bool_type="DIFFERENCE") + + # Apply booleans + if self.dont_apply_boolean is False: + BMname = "CT_" + self.CurrentObj.name + for mb in ActiveObj.modifiers: + if (mb.type == 'BOOLEAN') and (mb.name == BMname): + try: + bpy.ops.object.modifier_apply(apply_as='DATA', modifier=BMname) + except: + bpy.ops.object.modifier_remove(modifier=BMname) + exc_type, exc_value, exc_traceback = sys.exc_info() + self.report({'ERROR'}, str(exc_value)) + + bpy.ops.object.select_all(action='TOGGLE') + else: + if self.ObjectMode or self.ProfileMode: + for mb in self.CurrentObj.modifiers: + if (mb.type == 'SOLIDIFY') and (mb.name == "CT_SOLIDIFY"): + try: + bpy.ops.object.modifier_apply(apply_as='DATA', modifier="CT_SOLIDIFY") + except: + exc_type, exc_value, exc_traceback = sys.exc_info() + self.report({'ERROR'}, str(exc_value)) + + # Rebool + Rebool(context, self) + + # Test if not empty object + if context.selected_objects[0]: + rebool_RT = context.selected_objects[0] + if len(rebool_RT.data.vertices) > 0: + # Create Bevel for new objects + CreateBevel(context, context.selected_objects[0]) + + UndoAdd(self, "REBOOL", context.selected_objects[0]) + + context.scene.cursor.location = ActiveObj.location + bpy.ops.object.origin_set(type='ORIGIN_CURSOR') + else: + bpy.ops.object.delete(use_global=False) + + context.scene.cursor.location = CursorLocation + + if self.ObjectMode: + context.view_layer.objects.active = self.ObjectBrush + if self.ProfileMode: + context.view_layer.objects.active = self.ProfileBrush + + if self.dont_apply_boolean is False: + # Apply booleans + BMname = "CT_" + self.CurrentObj.name + for mb in ActiveObj.modifiers: + if (mb.type == 'BOOLEAN') and (mb.name == BMname): + try: + bpy.ops.object.modifier_apply(apply_as='DATA', modifier=BMname) + except: + bpy.ops.object.modifier_remove(modifier=BMname) + exc_type, exc_value, exc_traceback = sys.exc_info() + self.report({'ERROR'}, str(exc_value)) + # Get new objects created with rebool operations + if len(context.selected_objects) > 0: + if self.shift is True: + # Get the last object selected + lastSelected.append(context.selected_objects[0]) + + context.scene.cursor.location = CursorLocation + + if self.dont_apply_boolean is False: + # Remove cut object + if (self.ObjectMode is False) and (self.ProfileMode is False): + if len(context.selected_objects) > 0: + bpy.ops.object.select_all(action='TOGGLE') + bpy.data.objects[self.CurrentObj.name].select_set(True) + bpy.ops.object.delete(use_global=False) + else: + if self.ObjectMode: + self.ObjectBrush.display_type = self.InitBrush['display_type'] + + if len(context.selected_objects) > 0: + bpy.ops.object.select_all(action='TOGGLE') + + # Select cut objects + for obj in lastSelected: + bpy.data.objects[obj.name].select_set(True) + + for ActiveObj in selected_obj_list: + bpy.data.objects[ActiveObj.name].select_set(True) + context.view_layer.objects.active = ActiveObj + # Update bevel + list_act_obj = context.selected_objects.copy() + if self.Auto_BevelUpdate: + update_bevel(context) + + # Re-select initial objects + bpy.ops.object.select_all(action='TOGGLE') + if self.ObjectMode: + # Re-select brush + self.ObjectBrush.select_set(True) + for ActiveObj in selected_obj_list: + bpy.data.objects[ActiveObj.name].select_set(True) + context.view_layer.objects.active = ActiveObj + + # If object has children, set "Wire" draw type + if self.ObjectBrush is not None: + if len(self.ObjectBrush.children) > 0: + self.ObjectBrush.display_type = "WIRE" + if self.ProfileMode: + self.ProfileBrush.display_type = "WIRE" + + if in_local_view: + bpy.ops.view3d.localview() + + # Reset variables + self.CutMode = False + self.mouse_path.clear() + self.mouse_path = [(0, 0), (0, 0)] + + self.ForceRebool = False + + # bpy.ops.mesh.customdata_custom_splitnormals_clear() class CarverProperties(bpy.types.PropertyGroup): - DepthCursor: BoolProperty( - name="DepthCursor", - default=False - ) - OInstanciate: BoolProperty( - name="Obj_Instantiate", - default=False - ) - ORandom: BoolProperty( - name="Random_Rotation", - default=False - ) - DontApply: BoolProperty( - name="Dont_Apply", - default=False - ) - nProfile: IntProperty( - name="Num_Profile", - default=0 - ) + DepthCursor: BoolProperty( + name="DepthCursor", + default=False + ) + OInstanciate: BoolProperty( + name="Obj_Instantiate", + default=False + ) + ORandom: BoolProperty( + name="Random_Rotation", + default=False + ) + DontApply: BoolProperty( + name="Dont_Apply", + default=False + ) + nProfile: IntProperty( + name="Num_Profile", + default=0 + ) def register(): - from bpy.utils import register_class - bpy.utils.register_class(CARVER_OT_operator) - bpy.utils.register_class(CarverProperties) - bpy.types.Scene.mesh_carver = bpy.props.PointerProperty(type=CarverProperties) + from bpy.utils import register_class + bpy.utils.register_class(CARVER_OT_operator) + bpy.utils.register_class(CarverProperties) + bpy.types.Scene.mesh_carver = bpy.props.PointerProperty(type=CarverProperties) def unregister(): - from bpy.utils import unregister_class - bpy.utils.unregister_class(CarverProperties) - bpy.utils.unregister_class(CARVER_OT_operator) - del bpy.types.Scene.mesh_carver + from bpy.utils import unregister_class + bpy.utils.unregister_class(CarverProperties) + bpy.utils.unregister_class(CARVER_OT_operator) + del bpy.types.Scene.mesh_carver diff --git a/object_carver/carver_preferences.py b/object_carver/carver_preferences.py index b713119339c41f5b14185ddb0299e5f07d1e2948..1e6bc7ab403808aee4fd4c2f4241c34487b96937 100644 --- a/object_carver/carver_preferences.py +++ b/object_carver/carver_preferences.py @@ -1,194 +1,194 @@ import bpy from bpy.props import ( - BoolProperty, - IntProperty, - PointerProperty, - StringProperty, + BoolProperty, + IntProperty, + PointerProperty, + StringProperty, ) class CarverPrefs(bpy.types.AddonPreferences): - bl_idname = __name__ + bl_idname = __name__ - Enable_Tab_01: BoolProperty( - name="Info", - description="Some general information and settings about the add-on", - default=False - ) - Enable_Tab_02: BoolProperty( - name="Hotkeys", - description="List of the shortcuts used during carving", - default=False - ) - bpy.types.Scene.Key_Create: StringProperty( - name="Object creation", - description="Object creation", - maxlen=1, - default="C" - ) - bpy.types.Scene.Key_Update: StringProperty( - name="Auto Bevel Update", - description="Auto Bevel Update", - maxlen=1, - default="A", - ) - bpy.types.Scene.Key_Bool: StringProperty( - name="Boolean type", - description="Boolean operation type", - maxlen=1, - default="T", - ) - bpy.types.Scene.Key_Brush: StringProperty( - name="Brush Mode", - description="Brush Mode", - maxlen=1, - default="B", - ) - bpy.types.Scene.Key_Help: StringProperty( - name="Help display", - description="Help display", - maxlen=1, - default="H", - ) - bpy.types.Scene.Key_Instant: StringProperty( - name="Instantiate", - description="Instantiate object", - maxlen=1, - default="I", - ) - bpy.types.Scene.Key_Close: StringProperty( - name="Close polygonal shape", - description="Close polygonal shape", - maxlen=1, - default="X", - ) - bpy.types.Scene.Key_Apply: StringProperty( - name="Apply operation", - description="Apply operation", - maxlen=1, - default="Q", - ) - bpy.types.Scene.Key_Scale: StringProperty( - name="Scale object", - description="Scale object", - maxlen=1, - default="S", - ) - bpy.types.Scene.Key_Gapy: StringProperty( - name="Gap rows", - description="Scale gap between columns", - maxlen=1, - default="J", - ) - bpy.types.Scene.Key_Gapx: StringProperty( - name="Gap columns", - description="Scale gap between columns", - maxlen=1, - default="U", - ) - bpy.types.Scene.Key_Depth: StringProperty( - name="Depth", - description="Cursor depth or solidify pattern", - maxlen=1, - default="D", - ) - bpy.types.Scene.Key_BrushDepth: StringProperty( - name="Brush Depth", - description="Brush depth", - maxlen=1, - default="C", - ) - bpy.types.Scene.Key_Subadd: StringProperty( - name="Add subdivision", - description="Add subdivision", - maxlen=1, - default="X", - ) - bpy.types.Scene.Key_Subrem: StringProperty( - name="Remove subdivision", - description="Remove subdivision", - maxlen=1, - default="W", - ) - bpy.types.Scene.Key_Randrot: StringProperty( - name="Random rotation", - description="Random rotation", - maxlen=1, - default="R", - ) - bpy.types.Scene.ProfilePrefix: StringProperty( - name="Profile prefix", - description="Prefix to look for profiles with", - default="Carver_Profile-" - ) + Enable_Tab_01: BoolProperty( + name="Info", + description="Some general information and settings about the add-on", + default=False + ) + Enable_Tab_02: BoolProperty( + name="Hotkeys", + description="List of the shortcuts used during carving", + default=False + ) + bpy.types.Scene.Key_Create: StringProperty( + name="Object creation", + description="Object creation", + maxlen=1, + default="C" + ) + bpy.types.Scene.Key_Update: StringProperty( + name="Auto Bevel Update", + description="Auto Bevel Update", + maxlen=1, + default="A", + ) + bpy.types.Scene.Key_Bool: StringProperty( + name="Boolean type", + description="Boolean operation type", + maxlen=1, + default="T", + ) + bpy.types.Scene.Key_Brush: StringProperty( + name="Brush Mode", + description="Brush Mode", + maxlen=1, + default="B", + ) + bpy.types.Scene.Key_Help: StringProperty( + name="Help display", + description="Help display", + maxlen=1, + default="H", + ) + bpy.types.Scene.Key_Instant: StringProperty( + name="Instantiate", + description="Instantiate object", + maxlen=1, + default="I", + ) + bpy.types.Scene.Key_Close: StringProperty( + name="Close polygonal shape", + description="Close polygonal shape", + maxlen=1, + default="X", + ) + bpy.types.Scene.Key_Apply: StringProperty( + name="Apply operation", + description="Apply operation", + maxlen=1, + default="Q", + ) + bpy.types.Scene.Key_Scale: StringProperty( + name="Scale object", + description="Scale object", + maxlen=1, + default="S", + ) + bpy.types.Scene.Key_Gapy: StringProperty( + name="Gap rows", + description="Scale gap between columns", + maxlen=1, + default="J", + ) + bpy.types.Scene.Key_Gapx: StringProperty( + name="Gap columns", + description="Scale gap between columns", + maxlen=1, + default="U", + ) + bpy.types.Scene.Key_Depth: StringProperty( + name="Depth", + description="Cursor depth or solidify pattern", + maxlen=1, + default="D", + ) + bpy.types.Scene.Key_BrushDepth: StringProperty( + name="Brush Depth", + description="Brush depth", + maxlen=1, + default="C", + ) + bpy.types.Scene.Key_Subadd: StringProperty( + name="Add subdivision", + description="Add subdivision", + maxlen=1, + default="X", + ) + bpy.types.Scene.Key_Subrem: StringProperty( + name="Remove subdivision", + description="Remove subdivision", + maxlen=1, + default="W", + ) + bpy.types.Scene.Key_Randrot: StringProperty( + name="Random rotation", + description="Random rotation", + maxlen=1, + default="R", + ) + bpy.types.Scene.ProfilePrefix: StringProperty( + name="Profile prefix", + description="Prefix to look for profiles with", + default="Carver_Profile-" + ) - def draw(self, context): - scene = context.scene - layout = self.layout - print("DRAW !") + def draw(self, context): + scene = context.scene + layout = self.layout + print("DRAW !") - icon_1 = "TRIA_RIGHT" if not self.Enable_Tab_01 else "TRIA_DOWN" - box = layout.box() + icon_1 = "TRIA_RIGHT" if not self.Enable_Tab_01 else "TRIA_DOWN" + box = layout.box() - box.prop(self, "Enable_Tab_01", text="Info and Settings", emboss=False, icon=icon_1) - if self.Enable_Tab_01: - box.label(text="Carver Operator:", icon="LAYER_ACTIVE") - box.label(text="Select a Mesh Object and press [CTRL]+[SHIFT]+[X] to carve", - icon="LAYER_USED") - box.label(text="To finish carving press [ESC] or [RIGHT CLICK]", - icon="LAYER_USED") - box.prop(scene, "ProfilePrefix", text="Profile prefix") + box.prop(self, "Enable_Tab_01", text="Info and Settings", emboss=False, icon=icon_1) + if self.Enable_Tab_01: + box.label(text="Carver Operator:", icon="LAYER_ACTIVE") + box.label(text="Select a Mesh Object and press [CTRL]+[SHIFT]+[X] to carve", + icon="LAYER_USED") + box.label(text="To finish carving press [ESC] or [RIGHT CLICK]", + icon="LAYER_USED") + box.prop(scene, "ProfilePrefix", text="Profile prefix") - icon_2 = "TRIA_RIGHT" if not self.Enable_Tab_02 else "TRIA_DOWN" - box = layout.box() - box.prop(self, "Enable_Tab_02", text="Keys", emboss=False, icon=icon_2) - if self.Enable_Tab_02: - split = box.split(align=True) - box = split.box() - col = box.column(align=True) - col.label(text="Object Creation:") - col.prop(scene, "Key_Create", text="") - col.label(text="Auto bevel update:") - col.prop(scene, "Key_Update", text="") - col.label(text="Boolean operation type:") - col.prop(scene, "Key_Bool", text="") - col.label(text="Brush Depth:") - col.prop(scene, "Key_BrushDepth", text="") + icon_2 = "TRIA_RIGHT" if not self.Enable_Tab_02 else "TRIA_DOWN" + box = layout.box() + box.prop(self, "Enable_Tab_02", text="Keys", emboss=False, icon=icon_2) + if self.Enable_Tab_02: + split = box.split(align=True) + box = split.box() + col = box.column(align=True) + col.label(text="Object Creation:") + col.prop(scene, "Key_Create", text="") + col.label(text="Auto bevel update:") + col.prop(scene, "Key_Update", text="") + col.label(text="Boolean operation type:") + col.prop(scene, "Key_Bool", text="") + col.label(text="Brush Depth:") + col.prop(scene, "Key_BrushDepth", text="") - box = split.box() - col = box.column(align=True) - col.label(text="Brush Mode:") - col.prop(scene, "Key_Brush", text="") - col.label(text="Help display:") - col.prop(scene, "Key_Help", text="") - col.label(text="Instantiate object:") - col.prop(scene, "Key_Instant", text="") - col.label(text="Random rotation:") - col.prop(scene, "Key_Randrot", text="") + box = split.box() + col = box.column(align=True) + col.label(text="Brush Mode:") + col.prop(scene, "Key_Brush", text="") + col.label(text="Help display:") + col.prop(scene, "Key_Help", text="") + col.label(text="Instantiate object:") + col.prop(scene, "Key_Instant", text="") + col.label(text="Random rotation:") + col.prop(scene, "Key_Randrot", text="") - box = split.box() - col = box.column(align=True) - col.label(text="Close polygonal shape:") - col.prop(scene, "Key_Close", text="") - col.label(text="Apply operation:") - col.prop(scene, "Key_Apply", text="") - col.label(text="Scale object:") - col.prop(scene, "Key_Scale", text="") - col.label(text="Subdiv add:") - col.prop(scene, "Key_Subadd", text="") + box = split.box() + col = box.column(align=True) + col.label(text="Close polygonal shape:") + col.prop(scene, "Key_Close", text="") + col.label(text="Apply operation:") + col.prop(scene, "Key_Apply", text="") + col.label(text="Scale object:") + col.prop(scene, "Key_Scale", text="") + col.label(text="Subdiv add:") + col.prop(scene, "Key_Subadd", text="") - box = split.box() - col = box.column(align=True) - col.label(text="Gap rows:") - col.prop(scene, "Key_Gapy", text="") - col.label(text="Gap columns:") - col.prop(scene, "Key_Gapx", text="") - col.label(text="Depth / Solidify:") - col.prop(scene, "Key_Depth", text="") - col.label(text="Subdiv Remove:") - col.prop(scene, "Key_Subrem", text="") + box = split.box() + col = box.column(align=True) + col.label(text="Gap rows:") + col.prop(scene, "Key_Gapy", text="") + col.label(text="Gap columns:") + col.prop(scene, "Key_Gapx", text="") + col.label(text="Depth / Solidify:") + col.prop(scene, "Key_Depth", text="") + col.label(text="Subdiv Remove:") + col.prop(scene, "Key_Subrem", text="") def register(): - bpy.utils.register_class(CarverPrefs) + bpy.utils.register_class(CarverPrefs) def unregister(): - bpy.utils.unregister_class(CarverPrefs) + bpy.utils.unregister_class(CarverPrefs) diff --git a/object_carver/carver_profils.py b/object_carver/carver_profils.py index d19478c9c5f2334f3be023bcbacd6ac545d97534..9c99bf9750078b16c23aad3ca0013c60c073602f 100644 --- a/object_carver/carver_profils.py +++ b/object_carver/carver_profils.py @@ -1,409 +1,409 @@ from mathutils import ( - Vector, + Vector, ) Profils = [ - ("TEST", - Vector((0,0,1)), - [(-1, 1, 0.032334), (1, 1, 0.032334),(-1, -1, 0.032334), (1, -1, 0.01032334)], - [(0, 1, 2), (2,1,3)]), - ("CTP_4882", - Vector((2.61824, -5.56469, 0)), - [(-1.156501, 0.799282, 0.032334), - (-0.967583, 0.838861, 0.032334), - (-1.10386, 0.846403, 0.032334), - (-1.034712, 0.86089, 0.032334), - (-1.88472, -0.564419, 0.032334), - (-1.924299, -0.375502, 0.032334), - (-1.93184, -0.511778, 0.032334), - (-1.946327, -0.44263, 0.032334), - (-0.219065, -0.869195, 0.032334), - (-0.149916, -0.854708, 0.032334), - (-0.286193, -0.847167, 0.032334), - (-0.097275, -0.807588, 0.032334), - (0.692551, 0.434324, 0.032334), - (0.678064, 0.503472, 0.032334), - (0.670523, 0.367196, 0.032334), - (0.630943, 0.556113, 0.032334), - (-0.780424, -0.44263, 0.032334), - (-0.765937, -0.511778, 0.032334), - (-0.758396, -0.375502, 0.032334), - (-0.718817, -0.564419, 0.032334), - (-0.53496, 0.556113, 0.032334), - (-0.49538, 0.367196, 0.032334), - (-0.487839, 0.503472, 0.032334), - (-0.473352, 0.434324, 0.032334), - (-1.263178, -0.807588, 0.032334), - (-1.452096, -0.847167, 0.032334), - (-1.315819, -0.854708, 0.032334), - (-1.384968, -0.869195, 0.032334), - (0.131191, 0.86089, 0.032334), - (0.062043, 0.846403, 0.032334), - (0.19832, 0.838861, 0.032334), - (0.009402, 0.799282, 0.032334), - (0.946838, -0.869195, 0.032334), - (1.015987, -0.854708, 0.032334), - (0.87971, -0.847167, 0.032334), - (1.068628, -0.807588, 0.032334), - (1.858454, 0.434324, 0.032334), - (1.843967, 0.503472, 0.032334), - (1.836426, 0.367196, 0.032334), - (1.796846, 0.556113, 0.032334), - (0.385479, -0.44263, 0.032334), - (0.399966, -0.511778, 0.032334), - (0.407507, -0.375502, 0.032334), - (0.447086, -0.564419, 0.032334), - (1.297095, 0.86089, 0.032334), - (1.227946, 0.846403, 0.032334), - (1.364223, 0.838861, 0.032334), - (1.175305, 0.799282, 0.032334), - ], - [[16, 17, 19], [5, 4, 24], [14, 12, 15], [14, 15, 31], [10, 8, 11], [15, 30, 31], [19, 10, 11], - [11, 14, 31], [31, 18, 11], [8, 9, 11], [18, 16, 19], [12, 13, 15], [18, 19, 11], [28, 29, 31], - [30, 28, 31], [24, 21, 0], [23, 22, 20], [20, 1, 0], [3, 2, 0], [0, 5, 24], [7, 6, 4], [4, 25, 24], - [27, 26, 24], [21, 23, 20], [1, 3, 0], [5, 7, 4], [25, 27, 24], [21, 20, 0], [40, 41, 43], [38, 36, 39], - [38, 39, 47], [34, 32, 35], [39, 46, 47], [43, 34, 35], [35, 38, 47], [47, 42, 35], [32, 33, 35], - [42, 40, 43], [36, 37, 39], [42, 43, 35], [44, 45, 47], [46, 44, 47]]), - ("CTP_8354", - Vector((-0.06267, -2.43829, -0.0)), - [(-0.534254, -1.0, 0.032334), - (-1.0, -0.534254, 0.032334), - (-0.654798, -0.98413, 0.032334), - (-0.767127, -0.937602, 0.032334), - (-0.863586, -0.863586, 0.032334), - (-0.937602, -0.767127, 0.032334), - (-0.98413, -0.654798, 0.032334), - (1.0, -0.534254, 0.032334), - (0.534254, -1.0, 0.032334), - (0.98413, -0.654798, 0.032334), - (0.937602, -0.767127, 0.032334), - (0.863586, -0.863586, 0.032334), - (0.767127, -0.937602, 0.032334), - (0.654798, -0.98413, 0.032334), - (-1.0, 0.534254, 0.032334), - (-0.534254, 1.0, 0.032334), - (-0.98413, 0.654798, 0.032334), - (-0.937602, 0.767127, 0.032334), - (-0.863586, 0.863586, 0.032334), - (-0.767127, 0.937602, 0.032334), - (-0.654798, 0.98413, 0.032334), - (0.534254, 1.0, 0.032334), - (1.0, 0.534254, 0.032334), - (0.654798, 0.98413, 0.032334), - (0.767127, 0.937602, 0.032334), - (0.863586, 0.863586, 0.032334), - (0.937602, 0.767127, 0.032334), - (0.98413, 0.654798, 0.032334), - (-0.763998, 0.518786, 0.032334), - (-0.763998, -0.518786, 0.032334), - (-0.754202, -0.593189, 0.032334), - (-0.731454, -0.648108, 0.032334), - (-0.695267, -0.695267, 0.032334), - (-0.648108, -0.731454, 0.032334), - (-0.593189, -0.754202, 0.032334), - (-0.518786, -0.763998, 0.032334), - (0.518786, -0.763998, 0.032334), - (0.593189, -0.754202, 0.032334), - (0.648108, -0.731454, 0.032334), - (0.695267, -0.695267, 0.032334), - (0.731454, -0.648108, 0.032334), - (0.754202, -0.593189, 0.032334), - (0.763998, -0.518786, 0.032334), - (0.763998, 0.518786, 0.032334), - (0.754202, 0.593189, 0.032334), - (0.731454, 0.648108, 0.032334), - (0.695267, 0.695267, 0.032334), - (0.648108, 0.731454, 0.032334), - (0.593189, 0.754202, 0.032334), - (0.518786, 0.763998, 0.032334), - (-0.518786, 0.763998, 0.032334), - (-0.593189, 0.754202, 0.032334), - (-0.648108, 0.731454, 0.032334), - (-0.695267, 0.695267, 0.032334), - (-0.731454, 0.648108, 0.032334), - (-0.754202, 0.593189, 0.032334), - (0.518786, 0.518786, 0.032334), - (-0.518786, 0.518786, 0.032334), - (0.518786, -0.518786, 0.032334), - (-0.518786, -0.518786, 0.032334), - (-0.593189, 0.518786, 0.032334), - (-0.593189, -0.518786, 0.032334), - (0.518786, -0.593189, 0.032334), - (-0.518786, -0.593189, 0.032334), - (-0.593189, -0.593189, 0.032334), - (0.593189, 0.518786, 0.032334), - (0.593189, -0.518786, 0.032334), - (0.593189, -0.593189, 0.032334), - (-0.593189, 0.593189, 0.032334), - (-0.518786, 0.593189, 0.032334), - (0.518786, 0.593189, 0.032334), - (0.593189, 0.593189, 0.032334), - (-0.648108, 0.593189, 0.032334), - (-0.648108, 0.518786, 0.032334), - (-0.648108, -0.518786, 0.032334), - (-0.648108, -0.593189, 0.032334), - (-0.695267, 0.593189, 0.032334), - (-0.695267, 0.518786, 0.032334), - (-0.695267, -0.518786, 0.032334), - (-0.695267, -0.593189, 0.032334), - (0.648108, 0.593189, 0.032334), - (0.648108, 0.518786, 0.032334), - (0.648108, -0.518786, 0.032334), - (0.648108, -0.593189, 0.032334), - (0.695267, 0.593189, 0.032334), - (0.695267, 0.518786, 0.032334), - (0.695267, -0.518786, 0.032334), - (0.695267, -0.593189, 0.032334), - ], - [[87, 39, 40, 41], [29, 28, 14, 1], [30, 29, 1, 6], [31, 30, 6, 5], [32, 31, 5, 4], [33, 32, 4, 3], - [34, 33, 3, 2], [35, 34, 2, 0], [36, 35, 0, 8], [37, 36, 8, 13], [38, 37, 13, 12], [39, 38, 12, 11], - [40, 39, 11, 10], [41, 40, 10, 9], [42, 41, 9, 7], [43, 42, 7, 22], [44, 43, 22, 27], [45, 44, 27, 26], - [46, 45, 26, 25], [47, 46, 25, 24], [48, 47, 24, 23], [49, 48, 23, 21], [50, 49, 21, 15], [51, 50, 15, 20], - [52, 51, 20, 19], [53, 52, 19, 18], [54, 53, 18, 17], [55, 54, 17, 16], [28, 55, 16, 14], [68, 69, 50, 51], - [63, 35, 36, 62], [69, 57, 56, 70], [84, 85, 43, 44], [64, 34, 35, 63], [57, 59, 58, 56], [85, 86, 42, 43], - [60, 61, 59, 57], [73, 74, 61, 60], [72, 68, 51, 52], [75, 33, 34, 64], [61, 64, 63, 59], [59, 63, 62, 58], - [86, 87, 41, 42], [74, 75, 64, 61], [58, 62, 67, 66], [56, 58, 66, 65], [70, 56, 65, 71], [62, 36, 37, 67], - [49, 70, 71, 48], [50, 69, 70, 49], [60, 57, 69, 68], [73, 60, 68, 72], [46, 84, 44, 45], [78, 79, 75, 74], - [77, 78, 74, 73], [77, 73, 72, 76], [76, 72, 52, 53], [79, 32, 33, 75], [29, 30, 79, 78], [28, 29, 78, 77], - [28, 77, 76, 55], [55, 76, 53, 54], [30, 31, 32, 79], [66, 67, 83, 82], [65, 66, 82, 81], [71, 65, 81, 80], - [48, 71, 80, 47], [67, 37, 38, 83], [82, 83, 87, 86], [81, 82, 86, 85], [80, 81, 85, 84], [47, 80, 84, 46], - [83, 38, 39, 87]]), - ("CTP_5585", - Vector((5.0114, -2.4281, 0.0)), - [(-0.490711, -1.0, 0.032334), - (-1.0, -0.490711, 0.032334), - (1.0, -0.490711, 0.032334), - (0.490711, -1.0, 0.032334), - (-1.0, 0.490711, 0.032334), - (-0.490711, 1.0, 0.032334), - (0.490711, 1.0, 0.032334), - (1.0, 0.490711, 0.032334), - (-0.51852, 0.291276, 0.032334), - (-0.51852, -0.291276, 0.032334), - (-0.291276, -0.51852, 0.032334), - (0.291276, -0.51852, 0.032334), - (0.51852, -0.291276, 0.032334), - (0.51852, 0.291276, 0.032334), - (0.291276, 0.51852, 0.032334), - (-0.291276, 0.51852, 0.032334), - ], - [[11, 12, 13, 14], [9, 8, 4, 1], [10, 9, 1, 0], [11, 10, 0, 3], [12, 11, 3, 2], [13, 12, 2, 7], - [14, 13, 7, 6], [15, 14, 6, 5], [8, 15, 5, 4], [9, 10, 15, 8], [10, 11, 14, 15]]), - ("CTP_6960", - Vector((-0.11417, 2.48371, -0.0)), - [(0.0, 1.0, 0.016827), - (-0.382683, 0.92388, 0.016827), - (-0.707107, 0.707107, 0.016827), - (-0.92388, 0.382683, 0.016827), - (-1.0, -0.0, 0.016827), - (-0.92388, -0.382684, 0.016827), - (-0.707107, -0.707107, 0.016827), - (-0.382683, -0.92388, 0.016827), - (-0.0, -1.0, 0.016827), - (0.382683, -0.92388, 0.016827), - (0.707107, -0.707107, 0.016827), - (0.92388, -0.382684, 0.016827), - (1.0, 0.0, 0.016827), - (0.923879, 0.382684, 0.016827), - (0.707107, 0.707107, 0.016827), - (0.382683, 0.92388, 0.016827), - (-0.0, 0.546859, 0.016827), - (-0.209274, 0.505231, 0.016827), - (-0.386687, 0.386687, 0.016827), - (-0.505231, 0.209274, 0.016827), - (-0.546859, -0.0, 0.016827), - (-0.505231, -0.209274, 0.016827), - (-0.386687, -0.386687, 0.016827), - (-0.209274, -0.505231, 0.016827), - (-0.0, -0.546859, 0.016827), - (0.209274, -0.505231, 0.016827), - (0.386687, -0.386688, 0.016827), - (0.505231, -0.209274, 0.016827), - (0.546858, 0.0, 0.016827), - (0.505231, 0.209274, 0.016827), - (0.386687, 0.386688, 0.016827), - (0.209273, 0.505232, 0.016827), - ], - [[3, 19, 18, 2], [11, 27, 26, 10], [4, 20, 19, 3], [12, 28, 27, 11], [5, 21, 20, 4], [13, 29, 28, 12], - [6, 22, 21, 5], [14, 30, 29, 13], [7, 23, 22, 6], [15, 31, 30, 14], [8, 24, 23, 7], [1, 17, 16, 0], - [0, 16, 31, 15], [9, 25, 24, 8], [2, 18, 17, 1], [10, 26, 25, 9]]), - ("CTP_5359", - Vector((5.50446, 2.41669, -0.0)), - [(0.0, 0.714247, 0.023261), - (-0.382683, 0.659879, 0.023261), - (-0.707107, 0.505049, 0.023261), - (-0.92388, 0.273331, 0.023261), - (-1.0, -0.0, 0.023261), - (-0.92388, -0.273331, 0.023261), - (-0.707107, -0.505049, 0.023261), - (-0.382683, -0.659879, 0.023261), - (-0.0, -0.714247, 0.023261), - (0.382683, -0.659879, 0.023261), - (0.707107, -0.505049, 0.023261), - (0.92388, -0.273331, 0.023261), - (1.0, 0.0, 0.023261), - (0.923879, 0.273331, 0.023261), - (0.707107, 0.505049, 0.023261), - (0.382683, 0.659879, 0.023261), - (-0.0, 0.303676, 0.023261), - (-0.162705, 0.28056, 0.023261), - (-0.30064, 0.214731, 0.023261), - (-0.392805, 0.116212, 0.023261), - (-0.425169, -0.0, 0.023261), - (-0.392805, -0.116212, 0.023261), - (-0.30064, -0.214731, 0.023261), - (-0.162705, -0.28056, 0.023261), - (-0.0, -0.303676, 0.023261), - (0.162705, -0.28056, 0.023261), - (0.30064, -0.214731, 0.023261), - (0.392805, -0.116212, 0.023261), - (0.425169, 0.0, 0.023261), - (0.392805, 0.116212, 0.023261), - (0.30064, 0.214731, 0.023261), - (0.162705, 0.28056, 0.023261), - ], - [[3, 19, 18, 2], [11, 27, 26, 10], [4, 20, 19, 3], [12, 28, 27, 11], [5, 21, 20, 4], [13, 29, 28, 12], - [6, 22, 21, 5], [14, 30, 29, 13], [7, 23, 22, 6], [15, 31, 30, 14], [8, 24, 23, 7], [1, 17, 16, 0], - [0, 16, 31, 15], [9, 25, 24, 8], [2, 18, 17, 1], [10, 26, 25, 9]]), - ("CTP_5424", - Vector((2.61824, 2.34147, 0.0)), - [(1.0, -1.0, 0.032334), - (-1.0, 1.0, 0.032334), - (1.0, 1.0, 0.032334), - (0.783867, -0.259989, 0.032334), - (-0.393641, 0.857073, 0.032334), - (0.73142, -0.116299, 0.032334), - (0.657754, 0.02916, 0.032334), - (0.564682, 0.172804, 0.032334), - (0.454497, 0.311098, 0.032334), - (0.329912, 0.440635, 0.032334), - (0.193995, 0.558227, 0.032334), - (0.050092, 0.660978, 0.032334), - (-0.098254, 0.746358, 0.032334), - (-0.247389, 0.812263, 0.032334), - ], - [[3, 0, 2], [10, 9, 2], [2, 1, 4], [2, 4, 13], [5, 3, 2], [6, 5, 2], [2, 13, 12], [2, 12, 11], [7, 6, 2], - [8, 7, 2], [2, 11, 10], [9, 8, 2]]), - ("CTP_3774", - Vector((2.61824, -2.52425, 0.0)), - [(1.0, 0.0, 0.020045), - (-1.0, 0.0, 0.020045), - (0.31903, -0.664947, 0.020045), - (-0.31903, -0.664947, 0.020045), - (-0.31903, 1.0, 0.020045), - (0.31903, 1.0, 0.020045), - (0.31903, 0.0, 0.020045), - (-0.31903, 0.0, 0.020045), - (-1.0, 0.614333, 0.020045), - (-0.614333, 1.0, 0.020045), - (-0.970643, 0.761921, 0.020045), - (-0.887041, 0.887041, 0.020045), - (-0.761921, 0.970643, 0.020045), - (0.614333, 1.0, 0.020045), - (1.0, 0.614333, 0.020045), - (0.761921, 0.970643, 0.020045), - (0.887041, 0.887041, 0.020045), - (0.970643, 0.761921, 0.020045), - (-0.31903, 0.614333, 0.020045), - (0.31903, 0.614333, 0.020045), - (0.31903, 0.761921, 0.020045), - (-0.31903, 0.761921, 0.020045), - (0.31903, 0.887041, 0.020045), - (-0.31903, 0.887041, 0.020045), - (0.614333, 0.614333, 0.020045), - (0.614333, 0.0, 0.020045), - (0.614333, 0.761921, 0.020045), - (0.614333, 0.887041, 0.020045), - (-0.614333, 0.761921, 0.020045), - (-0.614333, 0.0, 0.020045), - (-0.614333, 0.887041, 0.020045), - (-0.614333, 0.614333, 0.020045), - ], - [[6, 25, 24, 19], [6, 19, 18, 7], [2, 6, 7, 3], [1, 29, 31, 8], [8, 31, 28, 10], [19, 24, 26, 20], - [18, 19, 20, 21], [21, 20, 22, 23], [10, 28, 30, 11], [20, 26, 27, 22], [22, 27, 13, 5], [23, 22, 5, 4], - [11, 30, 9, 12], [17, 16, 27, 26], [14, 17, 26, 24], [24, 25, 0, 14], [15, 13, 27, 16], [9, 30, 23, 4], - [31, 29, 7, 18], [28, 31, 18, 21], [30, 28, 21, 23]]), - ("CTP_4473", - Vector((7.31539, 0.0, 0.0)), - [(0.24549, -1.0, 0.022454), - (-0.24549, -1.0, 0.022454), - (-0.24549, 1.0, 0.022454), - (0.24549, 1.0, 0.022454), - (1.0, 0.267452, 0.022454), - (1.0, -0.267452, 0.022454), - (-1.0, -0.267452, 0.022454), - (-1.0, 0.267452, 0.022454), - (0.24549, 0.267452, 0.022454), - (0.24549, -0.267452, 0.022454), - (-0.24549, 0.267452, 0.022454), - (-0.24549, -0.267452, 0.022454), - ], - [[8, 3, 2, 10], [0, 9, 11, 1], [4, 8, 9, 5], [8, 10, 11, 9], [10, 7, 6, 11]]), - ("CTP_4003", - Vector((4.91276, 0.0, 0.0)), - [(-1.0, -1.0, 0.026945), - (1.0, -1.0, 0.026945), - (-1.0, 1.0, 0.026945), - (-0.026763, -1.0, 0.026945), - (-0.026763, 1.0, 0.026945), - (1.0, -0.026763, 0.026945), - (0.238983, 0.965014, 0.026945), - (0.486619, 0.86244, 0.026945), - (0.699268, 0.699268, 0.026945), - (0.86244, 0.486619, 0.026945), - (0.965014, 0.238983, 0.026945), - (0.238983, -1.0, 0.026945), - (0.486619, -1.0, 0.026945), - (0.699268, -1.0, 0.026945), - (0.86244, -1.0, 0.026945), - (-0.026763, 0.479676, 0.026945), - (0.486619, 0.479676, 0.026945), - (0.699268, 0.479676, 0.026945), - (0.238983, 0.479676, 0.026945), - (0.865316, 0.479676, 0.026945), - (-1.0, 0.479676, 0.026945), - (0.86244, 0.479676, 0.026945), - (-0.026763, 0.238983, 0.026945), - (0.486619, 0.238983, 0.026945), - (0.699268, 0.238983, 0.026945), - (0.238983, 0.238983, 0.026945), - (-1.0, 0.238983, 0.026945), - (0.86244, 0.238983, 0.026945), - (-0.026763, -0.026763, 0.026945), - (0.486619, -0.026763, 0.026945), - (0.699268, -0.026763, 0.026945), - (0.238983, -0.026763, 0.026945), - (-1.0, -0.026763, 0.026945), - (0.86244, -0.026763, 0.026945), - ], - [[0, 3, 28, 32], [4, 15, 18, 6], [6, 18, 16, 7], [7, 16, 17, 8], [8, 17, 21, 9], [9, 21, 19], [18, 15, 22, 25], - [19, 21, 27, 10], [16, 18, 25, 23], [17, 16, 23, 24], [20, 15, 4, 2], [21, 17, 24, 27], [27, 24, 30, 33], - [23, 25, 31, 29], [24, 23, 29, 30], [25, 22, 28, 31], [26, 22, 15, 20], [10, 27, 33, 5], [31, 28, 3, 11], - [33, 30, 13, 14], [29, 31, 11, 12], [5, 33, 14, 1], [30, 29, 12, 13], [32, 28, 22, 26]]), - ("CTP_3430", - Vector((2.61824, 0.0, 0.0)), - [(-1.0, -1.0, 0.032334), - (1.0, -1.0, 0.032334), - (-1.0, 1.0, 0.032334), - (1.0, 1.0, 0.032334), - ], - [[0, 1, 3, 2]]), - ("CTP_7175", - Vector((0.0, 0.0, 0.0)), - [(-1.0, -1.0, 0.032334), - (1.0, -1.0, 0.032334), - (-1.0, 1.0, 0.032334), - (1.0, 1.0, 0.032334), - (0.0, 0.0, 0.032334), - (0.0, 0.0, 0.032334), - (0.0, 0.0, 0.032334), - (0.0, 0.0, 0.032334), - (0.0, 0.0, 0.032334), - (-0.636126, 0.636126, 0.032334), - (-0.636126, -0.636126, 0.032334), - (0.636126, -0.636126, 0.032334), - (0.636126, 0.636126, 0.032334), - ], - [[10, 9, 2, 0], [11, 10, 0, 1], [12, 11, 1, 3], [9, 12, 3, 2]]), + ("TEST", + Vector((0,0,1)), + [(-1, 1, 0.032334), (1, 1, 0.032334),(-1, -1, 0.032334), (1, -1, 0.01032334)], + [(0, 1, 2), (2,1,3)]), + ("CTP_4882", + Vector((2.61824, -5.56469, 0)), + [(-1.156501, 0.799282, 0.032334), + (-0.967583, 0.838861, 0.032334), + (-1.10386, 0.846403, 0.032334), + (-1.034712, 0.86089, 0.032334), + (-1.88472, -0.564419, 0.032334), + (-1.924299, -0.375502, 0.032334), + (-1.93184, -0.511778, 0.032334), + (-1.946327, -0.44263, 0.032334), + (-0.219065, -0.869195, 0.032334), + (-0.149916, -0.854708, 0.032334), + (-0.286193, -0.847167, 0.032334), + (-0.097275, -0.807588, 0.032334), + (0.692551, 0.434324, 0.032334), + (0.678064, 0.503472, 0.032334), + (0.670523, 0.367196, 0.032334), + (0.630943, 0.556113, 0.032334), + (-0.780424, -0.44263, 0.032334), + (-0.765937, -0.511778, 0.032334), + (-0.758396, -0.375502, 0.032334), + (-0.718817, -0.564419, 0.032334), + (-0.53496, 0.556113, 0.032334), + (-0.49538, 0.367196, 0.032334), + (-0.487839, 0.503472, 0.032334), + (-0.473352, 0.434324, 0.032334), + (-1.263178, -0.807588, 0.032334), + (-1.452096, -0.847167, 0.032334), + (-1.315819, -0.854708, 0.032334), + (-1.384968, -0.869195, 0.032334), + (0.131191, 0.86089, 0.032334), + (0.062043, 0.846403, 0.032334), + (0.19832, 0.838861, 0.032334), + (0.009402, 0.799282, 0.032334), + (0.946838, -0.869195, 0.032334), + (1.015987, -0.854708, 0.032334), + (0.87971, -0.847167, 0.032334), + (1.068628, -0.807588, 0.032334), + (1.858454, 0.434324, 0.032334), + (1.843967, 0.503472, 0.032334), + (1.836426, 0.367196, 0.032334), + (1.796846, 0.556113, 0.032334), + (0.385479, -0.44263, 0.032334), + (0.399966, -0.511778, 0.032334), + (0.407507, -0.375502, 0.032334), + (0.447086, -0.564419, 0.032334), + (1.297095, 0.86089, 0.032334), + (1.227946, 0.846403, 0.032334), + (1.364223, 0.838861, 0.032334), + (1.175305, 0.799282, 0.032334), + ], + [[16, 17, 19], [5, 4, 24], [14, 12, 15], [14, 15, 31], [10, 8, 11], [15, 30, 31], [19, 10, 11], + [11, 14, 31], [31, 18, 11], [8, 9, 11], [18, 16, 19], [12, 13, 15], [18, 19, 11], [28, 29, 31], + [30, 28, 31], [24, 21, 0], [23, 22, 20], [20, 1, 0], [3, 2, 0], [0, 5, 24], [7, 6, 4], [4, 25, 24], + [27, 26, 24], [21, 23, 20], [1, 3, 0], [5, 7, 4], [25, 27, 24], [21, 20, 0], [40, 41, 43], [38, 36, 39], + [38, 39, 47], [34, 32, 35], [39, 46, 47], [43, 34, 35], [35, 38, 47], [47, 42, 35], [32, 33, 35], + [42, 40, 43], [36, 37, 39], [42, 43, 35], [44, 45, 47], [46, 44, 47]]), + ("CTP_8354", + Vector((-0.06267, -2.43829, -0.0)), + [(-0.534254, -1.0, 0.032334), + (-1.0, -0.534254, 0.032334), + (-0.654798, -0.98413, 0.032334), + (-0.767127, -0.937602, 0.032334), + (-0.863586, -0.863586, 0.032334), + (-0.937602, -0.767127, 0.032334), + (-0.98413, -0.654798, 0.032334), + (1.0, -0.534254, 0.032334), + (0.534254, -1.0, 0.032334), + (0.98413, -0.654798, 0.032334), + (0.937602, -0.767127, 0.032334), + (0.863586, -0.863586, 0.032334), + (0.767127, -0.937602, 0.032334), + (0.654798, -0.98413, 0.032334), + (-1.0, 0.534254, 0.032334), + (-0.534254, 1.0, 0.032334), + (-0.98413, 0.654798, 0.032334), + (-0.937602, 0.767127, 0.032334), + (-0.863586, 0.863586, 0.032334), + (-0.767127, 0.937602, 0.032334), + (-0.654798, 0.98413, 0.032334), + (0.534254, 1.0, 0.032334), + (1.0, 0.534254, 0.032334), + (0.654798, 0.98413, 0.032334), + (0.767127, 0.937602, 0.032334), + (0.863586, 0.863586, 0.032334), + (0.937602, 0.767127, 0.032334), + (0.98413, 0.654798, 0.032334), + (-0.763998, 0.518786, 0.032334), + (-0.763998, -0.518786, 0.032334), + (-0.754202, -0.593189, 0.032334), + (-0.731454, -0.648108, 0.032334), + (-0.695267, -0.695267, 0.032334), + (-0.648108, -0.731454, 0.032334), + (-0.593189, -0.754202, 0.032334), + (-0.518786, -0.763998, 0.032334), + (0.518786, -0.763998, 0.032334), + (0.593189, -0.754202, 0.032334), + (0.648108, -0.731454, 0.032334), + (0.695267, -0.695267, 0.032334), + (0.731454, -0.648108, 0.032334), + (0.754202, -0.593189, 0.032334), + (0.763998, -0.518786, 0.032334), + (0.763998, 0.518786, 0.032334), + (0.754202, 0.593189, 0.032334), + (0.731454, 0.648108, 0.032334), + (0.695267, 0.695267, 0.032334), + (0.648108, 0.731454, 0.032334), + (0.593189, 0.754202, 0.032334), + (0.518786, 0.763998, 0.032334), + (-0.518786, 0.763998, 0.032334), + (-0.593189, 0.754202, 0.032334), + (-0.648108, 0.731454, 0.032334), + (-0.695267, 0.695267, 0.032334), + (-0.731454, 0.648108, 0.032334), + (-0.754202, 0.593189, 0.032334), + (0.518786, 0.518786, 0.032334), + (-0.518786, 0.518786, 0.032334), + (0.518786, -0.518786, 0.032334), + (-0.518786, -0.518786, 0.032334), + (-0.593189, 0.518786, 0.032334), + (-0.593189, -0.518786, 0.032334), + (0.518786, -0.593189, 0.032334), + (-0.518786, -0.593189, 0.032334), + (-0.593189, -0.593189, 0.032334), + (0.593189, 0.518786, 0.032334), + (0.593189, -0.518786, 0.032334), + (0.593189, -0.593189, 0.032334), + (-0.593189, 0.593189, 0.032334), + (-0.518786, 0.593189, 0.032334), + (0.518786, 0.593189, 0.032334), + (0.593189, 0.593189, 0.032334), + (-0.648108, 0.593189, 0.032334), + (-0.648108, 0.518786, 0.032334), + (-0.648108, -0.518786, 0.032334), + (-0.648108, -0.593189, 0.032334), + (-0.695267, 0.593189, 0.032334), + (-0.695267, 0.518786, 0.032334), + (-0.695267, -0.518786, 0.032334), + (-0.695267, -0.593189, 0.032334), + (0.648108, 0.593189, 0.032334), + (0.648108, 0.518786, 0.032334), + (0.648108, -0.518786, 0.032334), + (0.648108, -0.593189, 0.032334), + (0.695267, 0.593189, 0.032334), + (0.695267, 0.518786, 0.032334), + (0.695267, -0.518786, 0.032334), + (0.695267, -0.593189, 0.032334), + ], + [[87, 39, 40, 41], [29, 28, 14, 1], [30, 29, 1, 6], [31, 30, 6, 5], [32, 31, 5, 4], [33, 32, 4, 3], + [34, 33, 3, 2], [35, 34, 2, 0], [36, 35, 0, 8], [37, 36, 8, 13], [38, 37, 13, 12], [39, 38, 12, 11], + [40, 39, 11, 10], [41, 40, 10, 9], [42, 41, 9, 7], [43, 42, 7, 22], [44, 43, 22, 27], [45, 44, 27, 26], + [46, 45, 26, 25], [47, 46, 25, 24], [48, 47, 24, 23], [49, 48, 23, 21], [50, 49, 21, 15], [51, 50, 15, 20], + [52, 51, 20, 19], [53, 52, 19, 18], [54, 53, 18, 17], [55, 54, 17, 16], [28, 55, 16, 14], [68, 69, 50, 51], + [63, 35, 36, 62], [69, 57, 56, 70], [84, 85, 43, 44], [64, 34, 35, 63], [57, 59, 58, 56], [85, 86, 42, 43], + [60, 61, 59, 57], [73, 74, 61, 60], [72, 68, 51, 52], [75, 33, 34, 64], [61, 64, 63, 59], [59, 63, 62, 58], + [86, 87, 41, 42], [74, 75, 64, 61], [58, 62, 67, 66], [56, 58, 66, 65], [70, 56, 65, 71], [62, 36, 37, 67], + [49, 70, 71, 48], [50, 69, 70, 49], [60, 57, 69, 68], [73, 60, 68, 72], [46, 84, 44, 45], [78, 79, 75, 74], + [77, 78, 74, 73], [77, 73, 72, 76], [76, 72, 52, 53], [79, 32, 33, 75], [29, 30, 79, 78], [28, 29, 78, 77], + [28, 77, 76, 55], [55, 76, 53, 54], [30, 31, 32, 79], [66, 67, 83, 82], [65, 66, 82, 81], [71, 65, 81, 80], + [48, 71, 80, 47], [67, 37, 38, 83], [82, 83, 87, 86], [81, 82, 86, 85], [80, 81, 85, 84], [47, 80, 84, 46], + [83, 38, 39, 87]]), + ("CTP_5585", + Vector((5.0114, -2.4281, 0.0)), + [(-0.490711, -1.0, 0.032334), + (-1.0, -0.490711, 0.032334), + (1.0, -0.490711, 0.032334), + (0.490711, -1.0, 0.032334), + (-1.0, 0.490711, 0.032334), + (-0.490711, 1.0, 0.032334), + (0.490711, 1.0, 0.032334), + (1.0, 0.490711, 0.032334), + (-0.51852, 0.291276, 0.032334), + (-0.51852, -0.291276, 0.032334), + (-0.291276, -0.51852, 0.032334), + (0.291276, -0.51852, 0.032334), + (0.51852, -0.291276, 0.032334), + (0.51852, 0.291276, 0.032334), + (0.291276, 0.51852, 0.032334), + (-0.291276, 0.51852, 0.032334), + ], + [[11, 12, 13, 14], [9, 8, 4, 1], [10, 9, 1, 0], [11, 10, 0, 3], [12, 11, 3, 2], [13, 12, 2, 7], + [14, 13, 7, 6], [15, 14, 6, 5], [8, 15, 5, 4], [9, 10, 15, 8], [10, 11, 14, 15]]), + ("CTP_6960", + Vector((-0.11417, 2.48371, -0.0)), + [(0.0, 1.0, 0.016827), + (-0.382683, 0.92388, 0.016827), + (-0.707107, 0.707107, 0.016827), + (-0.92388, 0.382683, 0.016827), + (-1.0, -0.0, 0.016827), + (-0.92388, -0.382684, 0.016827), + (-0.707107, -0.707107, 0.016827), + (-0.382683, -0.92388, 0.016827), + (-0.0, -1.0, 0.016827), + (0.382683, -0.92388, 0.016827), + (0.707107, -0.707107, 0.016827), + (0.92388, -0.382684, 0.016827), + (1.0, 0.0, 0.016827), + (0.923879, 0.382684, 0.016827), + (0.707107, 0.707107, 0.016827), + (0.382683, 0.92388, 0.016827), + (-0.0, 0.546859, 0.016827), + (-0.209274, 0.505231, 0.016827), + (-0.386687, 0.386687, 0.016827), + (-0.505231, 0.209274, 0.016827), + (-0.546859, -0.0, 0.016827), + (-0.505231, -0.209274, 0.016827), + (-0.386687, -0.386687, 0.016827), + (-0.209274, -0.505231, 0.016827), + (-0.0, -0.546859, 0.016827), + (0.209274, -0.505231, 0.016827), + (0.386687, -0.386688, 0.016827), + (0.505231, -0.209274, 0.016827), + (0.546858, 0.0, 0.016827), + (0.505231, 0.209274, 0.016827), + (0.386687, 0.386688, 0.016827), + (0.209273, 0.505232, 0.016827), + ], + [[3, 19, 18, 2], [11, 27, 26, 10], [4, 20, 19, 3], [12, 28, 27, 11], [5, 21, 20, 4], [13, 29, 28, 12], + [6, 22, 21, 5], [14, 30, 29, 13], [7, 23, 22, 6], [15, 31, 30, 14], [8, 24, 23, 7], [1, 17, 16, 0], + [0, 16, 31, 15], [9, 25, 24, 8], [2, 18, 17, 1], [10, 26, 25, 9]]), + ("CTP_5359", + Vector((5.50446, 2.41669, -0.0)), + [(0.0, 0.714247, 0.023261), + (-0.382683, 0.659879, 0.023261), + (-0.707107, 0.505049, 0.023261), + (-0.92388, 0.273331, 0.023261), + (-1.0, -0.0, 0.023261), + (-0.92388, -0.273331, 0.023261), + (-0.707107, -0.505049, 0.023261), + (-0.382683, -0.659879, 0.023261), + (-0.0, -0.714247, 0.023261), + (0.382683, -0.659879, 0.023261), + (0.707107, -0.505049, 0.023261), + (0.92388, -0.273331, 0.023261), + (1.0, 0.0, 0.023261), + (0.923879, 0.273331, 0.023261), + (0.707107, 0.505049, 0.023261), + (0.382683, 0.659879, 0.023261), + (-0.0, 0.303676, 0.023261), + (-0.162705, 0.28056, 0.023261), + (-0.30064, 0.214731, 0.023261), + (-0.392805, 0.116212, 0.023261), + (-0.425169, -0.0, 0.023261), + (-0.392805, -0.116212, 0.023261), + (-0.30064, -0.214731, 0.023261), + (-0.162705, -0.28056, 0.023261), + (-0.0, -0.303676, 0.023261), + (0.162705, -0.28056, 0.023261), + (0.30064, -0.214731, 0.023261), + (0.392805, -0.116212, 0.023261), + (0.425169, 0.0, 0.023261), + (0.392805, 0.116212, 0.023261), + (0.30064, 0.214731, 0.023261), + (0.162705, 0.28056, 0.023261), + ], + [[3, 19, 18, 2], [11, 27, 26, 10], [4, 20, 19, 3], [12, 28, 27, 11], [5, 21, 20, 4], [13, 29, 28, 12], + [6, 22, 21, 5], [14, 30, 29, 13], [7, 23, 22, 6], [15, 31, 30, 14], [8, 24, 23, 7], [1, 17, 16, 0], + [0, 16, 31, 15], [9, 25, 24, 8], [2, 18, 17, 1], [10, 26, 25, 9]]), + ("CTP_5424", + Vector((2.61824, 2.34147, 0.0)), + [(1.0, -1.0, 0.032334), + (-1.0, 1.0, 0.032334), + (1.0, 1.0, 0.032334), + (0.783867, -0.259989, 0.032334), + (-0.393641, 0.857073, 0.032334), + (0.73142, -0.116299, 0.032334), + (0.657754, 0.02916, 0.032334), + (0.564682, 0.172804, 0.032334), + (0.454497, 0.311098, 0.032334), + (0.329912, 0.440635, 0.032334), + (0.193995, 0.558227, 0.032334), + (0.050092, 0.660978, 0.032334), + (-0.098254, 0.746358, 0.032334), + (-0.247389, 0.812263, 0.032334), + ], + [[3, 0, 2], [10, 9, 2], [2, 1, 4], [2, 4, 13], [5, 3, 2], [6, 5, 2], [2, 13, 12], [2, 12, 11], [7, 6, 2], + [8, 7, 2], [2, 11, 10], [9, 8, 2]]), + ("CTP_3774", + Vector((2.61824, -2.52425, 0.0)), + [(1.0, 0.0, 0.020045), + (-1.0, 0.0, 0.020045), + (0.31903, -0.664947, 0.020045), + (-0.31903, -0.664947, 0.020045), + (-0.31903, 1.0, 0.020045), + (0.31903, 1.0, 0.020045), + (0.31903, 0.0, 0.020045), + (-0.31903, 0.0, 0.020045), + (-1.0, 0.614333, 0.020045), + (-0.614333, 1.0, 0.020045), + (-0.970643, 0.761921, 0.020045), + (-0.887041, 0.887041, 0.020045), + (-0.761921, 0.970643, 0.020045), + (0.614333, 1.0, 0.020045), + (1.0, 0.614333, 0.020045), + (0.761921, 0.970643, 0.020045), + (0.887041, 0.887041, 0.020045), + (0.970643, 0.761921, 0.020045), + (-0.31903, 0.614333, 0.020045), + (0.31903, 0.614333, 0.020045), + (0.31903, 0.761921, 0.020045), + (-0.31903, 0.761921, 0.020045), + (0.31903, 0.887041, 0.020045), + (-0.31903, 0.887041, 0.020045), + (0.614333, 0.614333, 0.020045), + (0.614333, 0.0, 0.020045), + (0.614333, 0.761921, 0.020045), + (0.614333, 0.887041, 0.020045), + (-0.614333, 0.761921, 0.020045), + (-0.614333, 0.0, 0.020045), + (-0.614333, 0.887041, 0.020045), + (-0.614333, 0.614333, 0.020045), + ], + [[6, 25, 24, 19], [6, 19, 18, 7], [2, 6, 7, 3], [1, 29, 31, 8], [8, 31, 28, 10], [19, 24, 26, 20], + [18, 19, 20, 21], [21, 20, 22, 23], [10, 28, 30, 11], [20, 26, 27, 22], [22, 27, 13, 5], [23, 22, 5, 4], + [11, 30, 9, 12], [17, 16, 27, 26], [14, 17, 26, 24], [24, 25, 0, 14], [15, 13, 27, 16], [9, 30, 23, 4], + [31, 29, 7, 18], [28, 31, 18, 21], [30, 28, 21, 23]]), + ("CTP_4473", + Vector((7.31539, 0.0, 0.0)), + [(0.24549, -1.0, 0.022454), + (-0.24549, -1.0, 0.022454), + (-0.24549, 1.0, 0.022454), + (0.24549, 1.0, 0.022454), + (1.0, 0.267452, 0.022454), + (1.0, -0.267452, 0.022454), + (-1.0, -0.267452, 0.022454), + (-1.0, 0.267452, 0.022454), + (0.24549, 0.267452, 0.022454), + (0.24549, -0.267452, 0.022454), + (-0.24549, 0.267452, 0.022454), + (-0.24549, -0.267452, 0.022454), + ], + [[8, 3, 2, 10], [0, 9, 11, 1], [4, 8, 9, 5], [8, 10, 11, 9], [10, 7, 6, 11]]), + ("CTP_4003", + Vector((4.91276, 0.0, 0.0)), + [(-1.0, -1.0, 0.026945), + (1.0, -1.0, 0.026945), + (-1.0, 1.0, 0.026945), + (-0.026763, -1.0, 0.026945), + (-0.026763, 1.0, 0.026945), + (1.0, -0.026763, 0.026945), + (0.238983, 0.965014, 0.026945), + (0.486619, 0.86244, 0.026945), + (0.699268, 0.699268, 0.026945), + (0.86244, 0.486619, 0.026945), + (0.965014, 0.238983, 0.026945), + (0.238983, -1.0, 0.026945), + (0.486619, -1.0, 0.026945), + (0.699268, -1.0, 0.026945), + (0.86244, -1.0, 0.026945), + (-0.026763, 0.479676, 0.026945), + (0.486619, 0.479676, 0.026945), + (0.699268, 0.479676, 0.026945), + (0.238983, 0.479676, 0.026945), + (0.865316, 0.479676, 0.026945), + (-1.0, 0.479676, 0.026945), + (0.86244, 0.479676, 0.026945), + (-0.026763, 0.238983, 0.026945), + (0.486619, 0.238983, 0.026945), + (0.699268, 0.238983, 0.026945), + (0.238983, 0.238983, 0.026945), + (-1.0, 0.238983, 0.026945), + (0.86244, 0.238983, 0.026945), + (-0.026763, -0.026763, 0.026945), + (0.486619, -0.026763, 0.026945), + (0.699268, -0.026763, 0.026945), + (0.238983, -0.026763, 0.026945), + (-1.0, -0.026763, 0.026945), + (0.86244, -0.026763, 0.026945), + ], + [[0, 3, 28, 32], [4, 15, 18, 6], [6, 18, 16, 7], [7, 16, 17, 8], [8, 17, 21, 9], [9, 21, 19], [18, 15, 22, 25], + [19, 21, 27, 10], [16, 18, 25, 23], [17, 16, 23, 24], [20, 15, 4, 2], [21, 17, 24, 27], [27, 24, 30, 33], + [23, 25, 31, 29], [24, 23, 29, 30], [25, 22, 28, 31], [26, 22, 15, 20], [10, 27, 33, 5], [31, 28, 3, 11], + [33, 30, 13, 14], [29, 31, 11, 12], [5, 33, 14, 1], [30, 29, 12, 13], [32, 28, 22, 26]]), + ("CTP_3430", + Vector((2.61824, 0.0, 0.0)), + [(-1.0, -1.0, 0.032334), + (1.0, -1.0, 0.032334), + (-1.0, 1.0, 0.032334), + (1.0, 1.0, 0.032334), + ], + [[0, 1, 3, 2]]), + ("CTP_7175", + Vector((0.0, 0.0, 0.0)), + [(-1.0, -1.0, 0.032334), + (1.0, -1.0, 0.032334), + (-1.0, 1.0, 0.032334), + (1.0, 1.0, 0.032334), + (0.0, 0.0, 0.032334), + (0.0, 0.0, 0.032334), + (0.0, 0.0, 0.032334), + (0.0, 0.0, 0.032334), + (0.0, 0.0, 0.032334), + (-0.636126, 0.636126, 0.032334), + (-0.636126, -0.636126, 0.032334), + (0.636126, -0.636126, 0.032334), + (0.636126, 0.636126, 0.032334), + ], + [[10, 9, 2, 0], [11, 10, 0, 1], [12, 11, 1, 3], [9, 12, 3, 2]]), ] diff --git a/object_carver/carver_utils.py b/object_carver/carver_utils.py index ce66052fe8e365f1cbd4fde34f110554963be1e6..495aa1ce7928ebf3b81e6dbc5f3bf4d19364431d 100644 --- a/object_carver/carver_utils.py +++ b/object_carver/carver_utils.py @@ -8,934 +8,934 @@ import sys import random import bmesh from mathutils import ( - Euler, - Matrix, - Vector, - Quaternion, + Euler, + Matrix, + Vector, + Quaternion, ) from mathutils.geometry import ( - intersect_line_plane, + intersect_line_plane, ) from math import ( - sin, - cos, - pi, - ) + sin, + cos, + pi, + ) import bpy_extras from bpy_extras import view3d_utils from bpy_extras.view3d_utils import ( - region_2d_to_vector_3d, - region_2d_to_location_3d, - location_3d_to_region_2d, + region_2d_to_vector_3d, + region_2d_to_location_3d, + location_3d_to_region_2d, ) # Cut Square def CreateCutSquare(self, context): - """ Create a rectangle mesh """ - far_limit = 10000.0 - faces=[] - - # Get the mouse coordinates - coord = self.mouse_path[0][0], self.mouse_path[0][1] - - # New mesh - me = bpy.data.meshes.new('CMT_Square') - bm = bmesh.new() - bm.from_mesh(me) - - # New object and link it to the scene - ob = bpy.data.objects.new('CMT_Square', me) - self.CurrentObj = ob - context.collection.objects.link(ob) - - # Scene information - region = context.region - rv3d = context.region_data - depth_location = region_2d_to_vector_3d(region, rv3d, coord) - self.ViewVector = depth_location - - # Get a point on a infinite plane and its direction - plane_normal = depth_location - plane_direction = plane_normal.normalized() - - if self.snapCursor: - plane_point = context.scene.cursor.location - else: - plane_point = self.OpsObj.location if self.OpsObj is not None else Vector((0.0, 0.0, 0.0)) - - # Find the intersection of a line going thru each vertex and the infinite plane - for v_co in self.rectangle_coord: - vec = region_2d_to_vector_3d(region, rv3d, v_co) - p0 = region_2d_to_location_3d(region, rv3d,v_co, vec) - p1 = region_2d_to_location_3d(region, rv3d,v_co, vec) + plane_direction * far_limit - faces.append(bm.verts.new(intersect_line_plane(p0, p1, plane_point, plane_direction))) - - # Update vertices index - bm.verts.index_update() - # New faces - t_face = bm.faces.new(faces) - # Set mesh - bm.to_mesh(me) + """ Create a rectangle mesh """ + far_limit = 10000.0 + faces=[] + + # Get the mouse coordinates + coord = self.mouse_path[0][0], self.mouse_path[0][1] + + # New mesh + me = bpy.data.meshes.new('CMT_Square') + bm = bmesh.new() + bm.from_mesh(me) + + # New object and link it to the scene + ob = bpy.data.objects.new('CMT_Square', me) + self.CurrentObj = ob + context.collection.objects.link(ob) + + # Scene information + region = context.region + rv3d = context.region_data + depth_location = region_2d_to_vector_3d(region, rv3d, coord) + self.ViewVector = depth_location + + # Get a point on a infinite plane and its direction + plane_normal = depth_location + plane_direction = plane_normal.normalized() + + if self.snapCursor: + plane_point = context.scene.cursor.location + else: + plane_point = self.OpsObj.location if self.OpsObj is not None else Vector((0.0, 0.0, 0.0)) + + # Find the intersection of a line going thru each vertex and the infinite plane + for v_co in self.rectangle_coord: + vec = region_2d_to_vector_3d(region, rv3d, v_co) + p0 = region_2d_to_location_3d(region, rv3d,v_co, vec) + p1 = region_2d_to_location_3d(region, rv3d,v_co, vec) + plane_direction * far_limit + faces.append(bm.verts.new(intersect_line_plane(p0, p1, plane_point, plane_direction))) + + # Update vertices index + bm.verts.index_update() + # New faces + t_face = bm.faces.new(faces) + # Set mesh + bm.to_mesh(me) # Cut Line def CreateCutLine(self, context): - """ Create a polygon mesh """ - far_limit = 10000.0 - vertices = [] - faces = [] - loc = [] - - # Get the mouse coordinates - coord = self.mouse_path[0][0], self.mouse_path[0][1] - - # New mesh - me = bpy.data.meshes.new('CMT_Line') - bm = bmesh.new() - bm.from_mesh(me) - - # New object and link it to the scene - ob = bpy.data.objects.new('CMT_Line', me) - self.CurrentObj = ob - context.collection.objects.link(ob) - - # Scene information - region = context.region - rv3d = context.region_data - depth_location = region_2d_to_vector_3d(region, rv3d, coord) - self.ViewVector = depth_location - - # Get a point on a infinite plane and its direction - plane_normal = depth_location - plane_direction = plane_normal.normalized() - - if self.snapCursor: - plane_point = context.scene.cursor.location - else: - plane_point = self.OpsObj.location if self.OpsObj is not None else Vector((0.0, 0.0, 0.0)) - - # Use dict to remove doubles - # Find the intersection of a line going thru each vertex and the infinite plane - for idx, v_co in enumerate(list(dict.fromkeys(self.mouse_path))): - vec = region_2d_to_vector_3d(region, rv3d, v_co) - p0 = region_2d_to_location_3d(region, rv3d,v_co, vec) - p1 = region_2d_to_location_3d(region, rv3d,v_co, vec) + plane_direction * far_limit - loc.append(intersect_line_plane(p0, p1, plane_point, plane_direction)) - vertices.append(bm.verts.new(loc[idx])) - - if idx > 0: - bm.edges.new([vertices[idx-1],vertices[idx]]) - - faces.append(vertices[idx]) - - # Update vertices index - bm.verts.index_update() - - # Nothing is selected, create close geometry - if self.CreateMode: - if self.Closed and len(vertices) > 1: - bm.edges.new([vertices[-1], vertices[0]]) - bm.faces.new(faces) - else: - # Create faces if more than 2 vertices - if len(vertices) > 1 : - bm.edges.new([vertices[-1], vertices[0]]) - bm.faces.new(faces) - - bm.to_mesh(me) + """ Create a polygon mesh """ + far_limit = 10000.0 + vertices = [] + faces = [] + loc = [] + + # Get the mouse coordinates + coord = self.mouse_path[0][0], self.mouse_path[0][1] + + # New mesh + me = bpy.data.meshes.new('CMT_Line') + bm = bmesh.new() + bm.from_mesh(me) + + # New object and link it to the scene + ob = bpy.data.objects.new('CMT_Line', me) + self.CurrentObj = ob + context.collection.objects.link(ob) + + # Scene information + region = context.region + rv3d = context.region_data + depth_location = region_2d_to_vector_3d(region, rv3d, coord) + self.ViewVector = depth_location + + # Get a point on a infinite plane and its direction + plane_normal = depth_location + plane_direction = plane_normal.normalized() + + if self.snapCursor: + plane_point = context.scene.cursor.location + else: + plane_point = self.OpsObj.location if self.OpsObj is not None else Vector((0.0, 0.0, 0.0)) + + # Use dict to remove doubles + # Find the intersection of a line going thru each vertex and the infinite plane + for idx, v_co in enumerate(list(dict.fromkeys(self.mouse_path))): + vec = region_2d_to_vector_3d(region, rv3d, v_co) + p0 = region_2d_to_location_3d(region, rv3d,v_co, vec) + p1 = region_2d_to_location_3d(region, rv3d,v_co, vec) + plane_direction * far_limit + loc.append(intersect_line_plane(p0, p1, plane_point, plane_direction)) + vertices.append(bm.verts.new(loc[idx])) + + if idx > 0: + bm.edges.new([vertices[idx-1],vertices[idx]]) + + faces.append(vertices[idx]) + + # Update vertices index + bm.verts.index_update() + + # Nothing is selected, create close geometry + if self.CreateMode: + if self.Closed and len(vertices) > 1: + bm.edges.new([vertices[-1], vertices[0]]) + bm.faces.new(faces) + else: + # Create faces if more than 2 vertices + if len(vertices) > 1 : + bm.edges.new([vertices[-1], vertices[0]]) + bm.faces.new(faces) + + bm.to_mesh(me) # Cut Circle def CreateCutCircle(self, context): - """ Create a circle mesh """ - far_limit = 10000.0 - FacesList = [] - - # Get the mouse coordinates - mouse_pos_x = self.mouse_path[0][0] - mouse_pos_y = self.mouse_path[0][1] - coord = self.mouse_path[0][0], self.mouse_path[0][1] - - # Scene information - region = context.region - rv3d = context.region_data - depth_location = region_2d_to_vector_3d(region, rv3d, coord) - self.ViewVector = depth_location - - # Get a point on a infinite plane and its direction - plane_point = context.scene.cursor.location if self.snapCursor else Vector((0.0, 0.0, 0.0)) - plane_normal = depth_location - plane_direction = plane_normal.normalized() - - # New mesh - me = bpy.data.meshes.new('CMT_Circle') - bm = bmesh.new() - bm.from_mesh(me) - - # New object and link it to the scene - ob = bpy.data.objects.new('CMT_Circle', me) - self.CurrentObj = ob - context.collection.objects.link(ob) - - # Create a circle using a tri fan - tris_fan, indices = draw_circle(self, mouse_pos_x, mouse_pos_y) - - # Remove the vertex in the center to get the outer line of the circle - verts = tris_fan[1:] - - # Find the intersection of a line going thru each vertex and the infinite plane - for vert in verts: - vec = region_2d_to_vector_3d(region, rv3d, vert) - p0 = region_2d_to_location_3d(region, rv3d, vert, vec) - p1 = p0 + plane_direction * far_limit - loc0 = intersect_line_plane(p0, p1, plane_point, plane_direction) - t_v0 = bm.verts.new(loc0) - FacesList.append(t_v0) - - bm.verts.index_update() - bm.faces.new(FacesList) - bm.to_mesh(me) + """ Create a circle mesh """ + far_limit = 10000.0 + FacesList = [] + + # Get the mouse coordinates + mouse_pos_x = self.mouse_path[0][0] + mouse_pos_y = self.mouse_path[0][1] + coord = self.mouse_path[0][0], self.mouse_path[0][1] + + # Scene information + region = context.region + rv3d = context.region_data + depth_location = region_2d_to_vector_3d(region, rv3d, coord) + self.ViewVector = depth_location + + # Get a point on a infinite plane and its direction + plane_point = context.scene.cursor.location if self.snapCursor else Vector((0.0, 0.0, 0.0)) + plane_normal = depth_location + plane_direction = plane_normal.normalized() + + # New mesh + me = bpy.data.meshes.new('CMT_Circle') + bm = bmesh.new() + bm.from_mesh(me) + + # New object and link it to the scene + ob = bpy.data.objects.new('CMT_Circle', me) + self.CurrentObj = ob + context.collection.objects.link(ob) + + # Create a circle using a tri fan + tris_fan, indices = draw_circle(self, mouse_pos_x, mouse_pos_y) + + # Remove the vertex in the center to get the outer line of the circle + verts = tris_fan[1:] + + # Find the intersection of a line going thru each vertex and the infinite plane + for vert in verts: + vec = region_2d_to_vector_3d(region, rv3d, vert) + p0 = region_2d_to_location_3d(region, rv3d, vert, vec) + p1 = p0 + plane_direction * far_limit + loc0 = intersect_line_plane(p0, p1, plane_point, plane_direction) + t_v0 = bm.verts.new(loc0) + FacesList.append(t_v0) + + bm.verts.index_update() + bm.faces.new(FacesList) + bm.to_mesh(me) def create_2d_circle(self, step, radius, rotation = 0): - """ Create the vertices of a 2d circle at (0,0) """ - verts = [] - for angle in range(0, 360, step): - verts.append(math.cos(math.radians(angle + rotation)) * radius) - verts.append(math.sin(math.radians(angle + rotation)) * radius) - verts.append(0.0) - verts.append(math.cos(math.radians(0.0 + rotation)) * radius) - verts.append(math.sin(math.radians(0.0 + rotation)) * radius) - verts.append(0.0) - return(verts) + """ Create the vertices of a 2d circle at (0,0) """ + verts = [] + for angle in range(0, 360, step): + verts.append(math.cos(math.radians(angle + rotation)) * radius) + verts.append(math.sin(math.radians(angle + rotation)) * radius) + verts.append(0.0) + verts.append(math.cos(math.radians(0.0 + rotation)) * radius) + verts.append(math.sin(math.radians(0.0 + rotation)) * radius) + verts.append(0.0) + return(verts) def draw_circle(self, mouse_pos_x, mouse_pos_y): - """ Return the coordinates + indices of a circle using a triangle fan """ - tris_verts = [] - indices = [] - segments = int(360 / self.stepAngle[self.step]) - radius = self.mouse_path[1][0] - self.mouse_path[0][0] - rotation = (self.mouse_path[1][1] - self.mouse_path[0][1]) / 2 + """ Return the coordinates + indices of a circle using a triangle fan """ + tris_verts = [] + indices = [] + segments = int(360 / self.stepAngle[self.step]) + radius = self.mouse_path[1][0] - self.mouse_path[0][0] + rotation = (self.mouse_path[1][1] - self.mouse_path[0][1]) / 2 - # Get the vertices of a 2d circle - verts = create_2d_circle(self, self.stepAngle[self.step], radius, rotation) + # Get the vertices of a 2d circle + verts = create_2d_circle(self, self.stepAngle[self.step], radius, rotation) - # Create the first vertex at mouse position for the center of the circle - tris_verts.append(Vector((mouse_pos_x + self.xpos , mouse_pos_y + self.ypos))) + # Create the first vertex at mouse position for the center of the circle + tris_verts.append(Vector((mouse_pos_x + self.xpos , mouse_pos_y + self.ypos))) - # For each vertex of the circle, add the mouse position and the translation - for idx in range(int(len(verts) / 3) - 1): - tris_verts.append(Vector((verts[idx * 3] + mouse_pos_x + self.xpos, \ - verts[idx * 3 + 1] + mouse_pos_y + self.ypos))) - i1 = idx+1 - i2 = idx+2 if idx+2 <= segments else 1 - indices.append((0,i1,i2)) + # For each vertex of the circle, add the mouse position and the translation + for idx in range(int(len(verts) / 3) - 1): + tris_verts.append(Vector((verts[idx * 3] + mouse_pos_x + self.xpos, \ + verts[idx * 3 + 1] + mouse_pos_y + self.ypos))) + i1 = idx+1 + i2 = idx+2 if idx+2 <= segments else 1 + indices.append((0,i1,i2)) - return(tris_verts, indices) + return(tris_verts, indices) # Object dimensions (SCULPT Tools tips) def objDiagonal(obj): - return ((obj.dimensions[0]**2) + (obj.dimensions[1]**2) + (obj.dimensions[2]**2))**0.5 + return ((obj.dimensions[0]**2) + (obj.dimensions[1]**2) + (obj.dimensions[2]**2))**0.5 # Bevel Update def update_bevel(context): - selection = context.selected_objects.copy() - active = context.active_object + selection = context.selected_objects.copy() + active = context.active_object - if len(selection) > 0: - for obj in selection: - bpy.ops.object.select_all(action='DESELECT') - obj.select_set(True) - context.view_layer.objects.active = obj + if len(selection) > 0: + for obj in selection: + bpy.ops.object.select_all(action='DESELECT') + obj.select_set(True) + context.view_layer.objects.active = obj - # Test object name - # Subdive mode : Only bevel weight - if obj.data.name.startswith("S_") or obj.data.name.startswith("S "): - bpy.ops.object.mode_set(mode='EDIT') - bpy.ops.mesh.region_to_loop() - bpy.ops.transform.edge_bevelweight(value=1) - bpy.ops.object.mode_set(mode='OBJECT') + # Test object name + # Subdive mode : Only bevel weight + if obj.data.name.startswith("S_") or obj.data.name.startswith("S "): + bpy.ops.object.mode_set(mode='EDIT') + bpy.ops.mesh.region_to_loop() + bpy.ops.transform.edge_bevelweight(value=1) + bpy.ops.object.mode_set(mode='OBJECT') - else: - # No subdiv mode : bevel weight + Crease + Sharp - CreateBevel(context, obj) + else: + # No subdiv mode : bevel weight + Crease + Sharp + CreateBevel(context, obj) - bpy.ops.object.select_all(action='DESELECT') + bpy.ops.object.select_all(action='DESELECT') - for obj in selection: - obj.select_set(True) - context.view_layer.objects.active = active + for obj in selection: + obj.select_set(True) + context.view_layer.objects.active = active # Create bevel def CreateBevel(context, CurrentObject): - # Save active object - SavActive = context.active_object + # Save active object + SavActive = context.active_object - # Test if initial object has bevel - bevel_modifier = False - for modifier in SavActive.modifiers: - if modifier.name == 'Bevel': - bevel_modifier = True + # Test if initial object has bevel + bevel_modifier = False + for modifier in SavActive.modifiers: + if modifier.name == 'Bevel': + bevel_modifier = True - if bevel_modifier: - # Active "CurrentObject" - context.view_layer.objects.active = CurrentObject + if bevel_modifier: + # Active "CurrentObject" + context.view_layer.objects.active = CurrentObject - bpy.ops.object.mode_set(mode='EDIT') + bpy.ops.object.mode_set(mode='EDIT') - # Edge mode - bpy.ops.mesh.select_mode(use_extend=False, use_expand=False, type='EDGE') - # Clear all - bpy.ops.mesh.select_all(action='SELECT') - bpy.ops.mesh.mark_sharp(clear=True) - bpy.ops.transform.edge_crease(value=-1) - bpy.ops.transform.edge_bevelweight(value=-1) + # Edge mode + bpy.ops.mesh.select_mode(use_extend=False, use_expand=False, type='EDGE') + # Clear all + bpy.ops.mesh.select_all(action='SELECT') + bpy.ops.mesh.mark_sharp(clear=True) + bpy.ops.transform.edge_crease(value=-1) + bpy.ops.transform.edge_bevelweight(value=-1) - bpy.ops.mesh.select_all(action='DESELECT') + bpy.ops.mesh.select_all(action='DESELECT') - # Select (in radians) all 30° sharp edges - bpy.ops.mesh.edges_select_sharp(sharpness=0.523599) - # Apply bevel weight + Crease + Sharp to the selected edges - bpy.ops.mesh.mark_sharp() - bpy.ops.transform.edge_crease(value=1) - bpy.ops.transform.edge_bevelweight(value=1) + # Select (in radians) all 30° sharp edges + bpy.ops.mesh.edges_select_sharp(sharpness=0.523599) + # Apply bevel weight + Crease + Sharp to the selected edges + bpy.ops.mesh.mark_sharp() + bpy.ops.transform.edge_crease(value=1) + bpy.ops.transform.edge_bevelweight(value=1) - bpy.ops.mesh.select_all(action='DESELECT') + bpy.ops.mesh.select_all(action='DESELECT') - bpy.ops.object.mode_set(mode='OBJECT') + bpy.ops.object.mode_set(mode='OBJECT') - CurrentObject.data.use_customdata_edge_bevel = True + CurrentObject.data.use_customdata_edge_bevel = True - for i in range(len(CurrentObject.data.edges)): - if CurrentObject.data.edges[i].select is True: - CurrentObject.data.edges[i].bevel_weight = 1.0 - CurrentObject.data.edges[i].use_edge_sharp = True + for i in range(len(CurrentObject.data.edges)): + if CurrentObject.data.edges[i].select is True: + CurrentObject.data.edges[i].bevel_weight = 1.0 + CurrentObject.data.edges[i].use_edge_sharp = True - bevel_modifier = False - for m in CurrentObject.modifiers: - if m.name == 'Bevel': - bevel_modifier = True + bevel_modifier = False + for m in CurrentObject.modifiers: + if m.name == 'Bevel': + bevel_modifier = True - if bevel_modifier is False: - bpy.ops.object.modifier_add(type='BEVEL') - mod = context.object.modifiers[-1] - mod.limit_method = 'WEIGHT' - mod.width = 0.01 - mod.profile = 0.699099 - mod.use_clight_overlap = False - mod.segments = 3 - mod.loop_slide = False + if bevel_modifier is False: + bpy.ops.object.modifier_add(type='BEVEL') + mod = context.object.modifiers[-1] + mod.limit_method = 'WEIGHT' + mod.width = 0.01 + mod.profile = 0.699099 + mod.use_clight_overlap = False + mod.segments = 3 + mod.loop_slide = False - bpy.ops.object.shade_smooth() + bpy.ops.object.shade_smooth() - context.object.data.use_auto_smooth = True - context.object.data.auto_smooth_angle = 1.0471975 + context.object.data.use_auto_smooth = True + context.object.data.auto_smooth_angle = 1.0471975 - # Restore the active object - context.view_layer.objects.active = SavActive + # Restore the active object + context.view_layer.objects.active = SavActive def MoveCursor(qRot, location, self): - """ In brush mode : Draw a circle around the brush """ - if qRot is not None: - verts = create_2d_circle(self, 10, 1) - self.CLR_C.clear() - vc = Vector() - for idx in range(int(len(verts) / 3)): - vc.x = verts[idx * 3] - vc.y = verts[idx * 3 + 1] - vc.z = verts[idx * 3 + 2] - vc = qRot @ vc - self.CLR_C.append(vc.x) - self.CLR_C.append(vc.y) - self.CLR_C.append(vc.z) + """ In brush mode : Draw a circle around the brush """ + if qRot is not None: + verts = create_2d_circle(self, 10, 1) + self.CLR_C.clear() + vc = Vector() + for idx in range(int(len(verts) / 3)): + vc.x = verts[idx * 3] + vc.y = verts[idx * 3 + 1] + vc.z = verts[idx * 3 + 2] + vc = qRot @ vc + self.CLR_C.append(vc.x) + self.CLR_C.append(vc.y) + self.CLR_C.append(vc.z) def rot_axis_quat(vector1, vector2): - """ Find the rotation (quaternion) from vector 1 to vector 2""" - vector1 = vector1.normalized() - vector2 = vector2.normalized() - cosTheta = vector1.dot(vector2) - rotationAxis = Vector((0.0, 0.0, 0.0)) - if (cosTheta < -1 + 0.001): - v = Vector((0.0, 1.0, 0.0)) - #Get the vector at the right angles to both - rotationAxis = vector1.cross(v) - rotationAxis = rotationAxis.normalized() - q = Quaternion() - q.w = 0.0 - q.x = rotationAxis.x - q.y = rotationAxis.y - q.z = rotationAxis.z - else: - rotationAxis = vector1.cross(vector2) - s = math.sqrt((1.0 + cosTheta) * 2.0) - invs = 1 / s - q = Quaternion() - q.w = s * 0.5 - q.x = rotationAxis.x * invs - q.y = rotationAxis.y * invs - q.z = rotationAxis.z * invs - return q + """ Find the rotation (quaternion) from vector 1 to vector 2""" + vector1 = vector1.normalized() + vector2 = vector2.normalized() + cosTheta = vector1.dot(vector2) + rotationAxis = Vector((0.0, 0.0, 0.0)) + if (cosTheta < -1 + 0.001): + v = Vector((0.0, 1.0, 0.0)) + #Get the vector at the right angles to both + rotationAxis = vector1.cross(v) + rotationAxis = rotationAxis.normalized() + q = Quaternion() + q.w = 0.0 + q.x = rotationAxis.x + q.y = rotationAxis.y + q.z = rotationAxis.z + else: + rotationAxis = vector1.cross(vector2) + s = math.sqrt((1.0 + cosTheta) * 2.0) + invs = 1 / s + q = Quaternion() + q.w = s * 0.5 + q.x = rotationAxis.x * invs + q.y = rotationAxis.y * invs + q.z = rotationAxis.z * invs + return q # Picking (template) def Picking(context, event): - """ Put the 3d cursor on the closest object""" - - # get the context arguments - scene = context.scene - region = context.region - rv3d = context.region_data - coord = event.mouse_region_x, event.mouse_region_y - - # get the ray from the viewport and mouse - view_vector = view3d_utils.region_2d_to_vector_3d(region, rv3d, coord) - ray_origin = view3d_utils.region_2d_to_origin_3d(region, rv3d, coord) - ray_target = ray_origin + view_vector - - def visible_objects_and_duplis(): - depsgraph = context.evaluated_depsgraph_get() - for dup in depsgraph.object_instances: - if dup.is_instance: # Real dupli instance - obj = dup.instance_object.original - yield (obj, dup.matrix.copy()) - else: # Usual object - obj = dup.object.original - yield (obj, obj.matrix_world.copy()) - - def obj_ray_cast(obj, matrix): - # get the ray relative to the object - matrix_inv = matrix.inverted() - ray_origin_obj = matrix_inv @ ray_origin - ray_target_obj = matrix_inv @ ray_target - ray_direction_obj = ray_target_obj - ray_origin_obj - # cast the ray - success, location, normal, face_index = obj.ray_cast(ray_origin_obj, ray_direction_obj) - if success: - return location, normal, face_index - return None, None, None - - # cast rays and find the closest object - best_length_squared = -1.0 - best_obj = None - - # cast rays and find the closest object - for obj, matrix in visible_objects_and_duplis(): - if obj.type == 'MESH': - hit, normal, face_index = obj_ray_cast(obj, matrix) - if hit is not None: - hit_world = matrix @ hit - length_squared = (hit_world - ray_origin).length_squared - if best_obj is None or length_squared < best_length_squared: - scene.cursor.location = hit_world - best_length_squared = length_squared - best_obj = obj - else: - if best_obj is None: - depth_location = region_2d_to_vector_3d(region, rv3d, coord) - loc = region_2d_to_location_3d(region, rv3d, coord, depth_location) - scene.cursor.location = loc + """ Put the 3d cursor on the closest object""" + + # get the context arguments + scene = context.scene + region = context.region + rv3d = context.region_data + coord = event.mouse_region_x, event.mouse_region_y + + # get the ray from the viewport and mouse + view_vector = view3d_utils.region_2d_to_vector_3d(region, rv3d, coord) + ray_origin = view3d_utils.region_2d_to_origin_3d(region, rv3d, coord) + ray_target = ray_origin + view_vector + + def visible_objects_and_duplis(): + depsgraph = context.evaluated_depsgraph_get() + for dup in depsgraph.object_instances: + if dup.is_instance: # Real dupli instance + obj = dup.instance_object.original + yield (obj, dup.matrix.copy()) + else: # Usual object + obj = dup.object.original + yield (obj, obj.matrix_world.copy()) + + def obj_ray_cast(obj, matrix): + # get the ray relative to the object + matrix_inv = matrix.inverted() + ray_origin_obj = matrix_inv @ ray_origin + ray_target_obj = matrix_inv @ ray_target + ray_direction_obj = ray_target_obj - ray_origin_obj + # cast the ray + success, location, normal, face_index = obj.ray_cast(ray_origin_obj, ray_direction_obj) + if success: + return location, normal, face_index + return None, None, None + + # cast rays and find the closest object + best_length_squared = -1.0 + best_obj = None + + # cast rays and find the closest object + for obj, matrix in visible_objects_and_duplis(): + if obj.type == 'MESH': + hit, normal, face_index = obj_ray_cast(obj, matrix) + if hit is not None: + hit_world = matrix @ hit + length_squared = (hit_world - ray_origin).length_squared + if best_obj is None or length_squared < best_length_squared: + scene.cursor.location = hit_world + best_length_squared = length_squared + best_obj = obj + else: + if best_obj is None: + depth_location = region_2d_to_vector_3d(region, rv3d, coord) + loc = region_2d_to_location_3d(region, rv3d, coord, depth_location) + scene.cursor.location = loc def Pick(context, event, self, ray_max=10000.0): - region = context.region - rv3d = context.region_data - coord = event.mouse_region_x, event.mouse_region_y - view_vector = view3d_utils.region_2d_to_vector_3d(region, rv3d, coord) - ray_origin = view3d_utils.region_2d_to_origin_3d(region, rv3d, coord) - ray_target = ray_origin + (view_vector * ray_max) - - def obj_ray_cast(obj, matrix): - matrix_inv = matrix.inverted() - ray_origin_obj = matrix_inv @ ray_origin - ray_target_obj = matrix_inv @ ray_target - success, hit, normal, face_index = obj.ray_cast(ray_origin_obj, ray_target_obj) - if success: - return hit, normal, face_index - return None, None, None - - best_length_squared = ray_max * ray_max - best_obj = None - for obj in self.CList: - matrix = obj.matrix_world - hit, normal, face_index = obj_ray_cast(obj, matrix) - rotation = obj.rotation_euler.to_quaternion() - if hit is not None: - hit_world = matrix @ hit - length_squared = (hit_world - ray_origin).length_squared - if length_squared < best_length_squared: - best_length_squared = length_squared - best_obj = obj - hits = hit_world - ns = normal - fs = face_index - - if best_obj is not None: - return hits, ns, rotation - - return None, None, None + region = context.region + rv3d = context.region_data + coord = event.mouse_region_x, event.mouse_region_y + view_vector = view3d_utils.region_2d_to_vector_3d(region, rv3d, coord) + ray_origin = view3d_utils.region_2d_to_origin_3d(region, rv3d, coord) + ray_target = ray_origin + (view_vector * ray_max) + + def obj_ray_cast(obj, matrix): + matrix_inv = matrix.inverted() + ray_origin_obj = matrix_inv @ ray_origin + ray_target_obj = matrix_inv @ ray_target + success, hit, normal, face_index = obj.ray_cast(ray_origin_obj, ray_target_obj) + if success: + return hit, normal, face_index + return None, None, None + + best_length_squared = ray_max * ray_max + best_obj = None + for obj in self.CList: + matrix = obj.matrix_world + hit, normal, face_index = obj_ray_cast(obj, matrix) + rotation = obj.rotation_euler.to_quaternion() + if hit is not None: + hit_world = matrix @ hit + length_squared = (hit_world - ray_origin).length_squared + if length_squared < best_length_squared: + best_length_squared = length_squared + best_obj = obj + hits = hit_world + ns = normal + fs = face_index + + if best_obj is not None: + return hits, ns, rotation + + return None, None, None def SelectObject(self, copyobj): - copyobj.select_set(True) + copyobj.select_set(True) - for child in copyobj.children: - SelectObject(self, child) + for child in copyobj.children: + SelectObject(self, child) - if copyobj.parent is None: - bpy.context.view_layer.objects.active = copyobj + if copyobj.parent is None: + bpy.context.view_layer.objects.active = copyobj # Undo def printUndo(self): - for l in self.UList: - print(l) + for l in self.UList: + print(l) def UndoAdd(self, type, obj): - """ Create a backup mesh before apply the action to the object """ - if obj is None: - return + """ Create a backup mesh before apply the action to the object """ + if obj is None: + return - if type != "DUPLICATE": - bm = bmesh.new() - bm.from_mesh(obj.data) - self.UndoOps.append((obj, type, bm)) - else: - self.UndoOps.append((obj, type, None)) + if type != "DUPLICATE": + bm = bmesh.new() + bm.from_mesh(obj.data) + self.UndoOps.append((obj, type, bm)) + else: + self.UndoOps.append((obj, type, None)) def UndoListUpdate(self): - self.UList.append((self.UndoOps.copy())) - self.UList_Index += 1 - self.UndoOps.clear() + self.UList.append((self.UndoOps.copy())) + self.UList_Index += 1 + self.UndoOps.clear() def Undo(self): - if self.UList_Index < 0: - return - # get previous mesh - for o in self.UList[self.UList_Index]: - if o[1] == "MESH": - bm = o[2] - bm.to_mesh(o[0].data) + if self.UList_Index < 0: + return + # get previous mesh + for o in self.UList[self.UList_Index]: + if o[1] == "MESH": + bm = o[2] + bm.to_mesh(o[0].data) - SelectObjList = bpy.context.selected_objects.copy() - Active_Obj = bpy.context.active_object - bpy.ops.object.select_all(action='TOGGLE') + SelectObjList = bpy.context.selected_objects.copy() + Active_Obj = bpy.context.active_object + bpy.ops.object.select_all(action='TOGGLE') - for o in self.UList[self.UList_Index]: - if o[1] == "REBOOL": - o[0].select_set(True) - o[0].hide_viewport = False + for o in self.UList[self.UList_Index]: + if o[1] == "REBOOL": + o[0].select_set(True) + o[0].hide_viewport = False - if o[1] == "DUPLICATE": - o[0].select_set(True) - o[0].hide_viewport = False + if o[1] == "DUPLICATE": + o[0].select_set(True) + o[0].hide_viewport = False - bpy.ops.object.delete(use_global=False) + bpy.ops.object.delete(use_global=False) - for so in SelectObjList: - bpy.data.objects[so.name].select_set(True) - bpy.context.view_layer.objects.active = Active_Obj + for so in SelectObjList: + bpy.data.objects[so.name].select_set(True) + bpy.context.view_layer.objects.active = Active_Obj - self.UList_Index -= 1 - self.UList[self.UList_Index + 1:] = [] + self.UList_Index -= 1 + self.UList[self.UList_Index + 1:] = [] def duplicateObject(self): - if self.Instantiate: - bpy.ops.object.duplicate_move_linked( - OBJECT_OT_duplicate={ - "linked": True, - "mode": 'TRANSLATION', - }, - TRANSFORM_OT_translate={ - "value": (0, 0, 0), - }, - ) - else: - bpy.ops.object.duplicate_move( - OBJECT_OT_duplicate={ - "linked": False, - "mode": 'TRANSLATION', - }, - TRANSFORM_OT_translate={ - "value": (0, 0, 0), - }, - ) - - ob_new = bpy.context.active_object - - ob_new.location = self.CurLoc - v = Vector() - v.x = v.y = 0.0 - v.z = self.BrushDepthOffset - ob_new.location += self.qRot * v - - if self.ObjectMode: - ob_new.scale = self.ObjectBrush.scale - if self.ProfileMode: - ob_new.scale = self.ProfileBrush.scale - - e = Euler() - e.x = e.y = 0.0 - e.z = self.aRotZ / 25.0 - - # If duplicate with a grid, no random rotation (each mesh in the grid is already rotated randomly) - if (self.alt is True) and ((self.nbcol + self.nbrow) < 3): - if self.RandomRotation: - e.z += random.random() - - qe = e.to_quaternion() - qRot = self.qRot * qe - ob_new.rotation_mode = 'QUATERNION' - ob_new.rotation_quaternion = qRot - ob_new.rotation_mode = 'XYZ' - - if (ob_new.display_type == "WIRE") and (self.BrushSolidify is False): - ob_new.hide_viewport = True - - if self.BrushSolidify: - ob_new.display_type = "SOLID" - ob_new.show_in_front = False - - for o in bpy.context.selected_objects: - UndoAdd(self, "DUPLICATE", o) - - if len(bpy.context.selected_objects) > 0: - bpy.ops.object.select_all(action='TOGGLE') - for o in self.all_sel_obj_list: - o.select_set(True) - - bpy.context.view_layer.objects.active = self.OpsObj + if self.Instantiate: + bpy.ops.object.duplicate_move_linked( + OBJECT_OT_duplicate={ + "linked": True, + "mode": 'TRANSLATION', + }, + TRANSFORM_OT_translate={ + "value": (0, 0, 0), + }, + ) + else: + bpy.ops.object.duplicate_move( + OBJECT_OT_duplicate={ + "linked": False, + "mode": 'TRANSLATION', + }, + TRANSFORM_OT_translate={ + "value": (0, 0, 0), + }, + ) + + ob_new = bpy.context.active_object + + ob_new.location = self.CurLoc + v = Vector() + v.x = v.y = 0.0 + v.z = self.BrushDepthOffset + ob_new.location += self.qRot * v + + if self.ObjectMode: + ob_new.scale = self.ObjectBrush.scale + if self.ProfileMode: + ob_new.scale = self.ProfileBrush.scale + + e = Euler() + e.x = e.y = 0.0 + e.z = self.aRotZ / 25.0 + + # If duplicate with a grid, no random rotation (each mesh in the grid is already rotated randomly) + if (self.alt is True) and ((self.nbcol + self.nbrow) < 3): + if self.RandomRotation: + e.z += random.random() + + qe = e.to_quaternion() + qRot = self.qRot * qe + ob_new.rotation_mode = 'QUATERNION' + ob_new.rotation_quaternion = qRot + ob_new.rotation_mode = 'XYZ' + + if (ob_new.display_type == "WIRE") and (self.BrushSolidify is False): + ob_new.hide_viewport = True + + if self.BrushSolidify: + ob_new.display_type = "SOLID" + ob_new.show_in_front = False + + for o in bpy.context.selected_objects: + UndoAdd(self, "DUPLICATE", o) + + if len(bpy.context.selected_objects) > 0: + bpy.ops.object.select_all(action='TOGGLE') + for o in self.all_sel_obj_list: + o.select_set(True) + + bpy.context.view_layer.objects.active = self.OpsObj def update_grid(self, context): - """ - Thanks to batFINGER for his help : - source : http://blender.stackexchange.com/questions/55864/multiple-meshes-not-welded-with-pydata - """ - verts = [] - edges = [] - faces = [] - numface = 0 - - if self.nbcol < 1: - self.nbcol = 1 - if self.nbrow < 1: - self.nbrow = 1 - if self.gapx < 0: - self.gapx = 0 - if self.gapy < 0: - self.gapy = 0 - - # Get the data from the profils or the object - if self.ProfileMode: - brush = bpy.data.objects.new( - self.Profils[self.nProfil][0], - bpy.data.meshes[self.Profils[self.nProfil][0]] - ) - obj = bpy.data.objects["CT_Profil"] - obfaces = brush.data.polygons - obverts = brush.data.vertices - lenverts = len(obverts) - else: - brush = bpy.data.objects["CarverBrushCopy"] - obj = context.selected_objects[0] - obverts = brush.data.vertices - obfaces = brush.data.polygons - lenverts = len(brush.data.vertices) - - # Gap between each row / column - gapx = self.gapx - gapy = self.gapy - - # Width of each row / column - widthx = brush.dimensions.x * self.scale_x - widthy = brush.dimensions.y * self.scale_y - - # Compute the corners so the new object will be always at the center - left = -((self.nbcol - 1) * (widthx + gapx)) / 2 - start = -((self.nbrow - 1) * (widthy + gapy)) / 2 - - for i in range(self.nbrow * self.nbcol): - row = i % self.nbrow - col = i // self.nbrow - startx = left + ((widthx + gapx) * col) - starty = start + ((widthy + gapy) * row) - - # Add random rotation - if (self.RandomRotation) and not (self.GridScaleX or self.GridScaleY): - rotmat = Matrix.Rotation(math.radians(360 * random.random()), 4, 'Z') - for v in obverts: - v.co = v.co @ rotmat - - verts.extend([((v.co.x - startx, v.co.y - starty, v.co.z)) for v in obverts]) - faces.extend([[v + numface * lenverts for v in p.vertices] for p in obfaces]) - numface += 1 - - # Update the mesh - # Create mesh data - mymesh = bpy.data.meshes.new("CT_Profil") - # Generate mesh data - mymesh.from_pydata(verts, edges, faces) - # Calculate the edges - mymesh.update(calc_edges=True) - # Update data - obj.data = mymesh - # Make the object active to remove doubles - context.view_layer.objects.active = obj + """ + Thanks to batFINGER for his help : + source : http://blender.stackexchange.com/questions/55864/multiple-meshes-not-welded-with-pydata + """ + verts = [] + edges = [] + faces = [] + numface = 0 + + if self.nbcol < 1: + self.nbcol = 1 + if self.nbrow < 1: + self.nbrow = 1 + if self.gapx < 0: + self.gapx = 0 + if self.gapy < 0: + self.gapy = 0 + + # Get the data from the profils or the object + if self.ProfileMode: + brush = bpy.data.objects.new( + self.Profils[self.nProfil][0], + bpy.data.meshes[self.Profils[self.nProfil][0]] + ) + obj = bpy.data.objects["CT_Profil"] + obfaces = brush.data.polygons + obverts = brush.data.vertices + lenverts = len(obverts) + else: + brush = bpy.data.objects["CarverBrushCopy"] + obj = context.selected_objects[0] + obverts = brush.data.vertices + obfaces = brush.data.polygons + lenverts = len(brush.data.vertices) + + # Gap between each row / column + gapx = self.gapx + gapy = self.gapy + + # Width of each row / column + widthx = brush.dimensions.x * self.scale_x + widthy = brush.dimensions.y * self.scale_y + + # Compute the corners so the new object will be always at the center + left = -((self.nbcol - 1) * (widthx + gapx)) / 2 + start = -((self.nbrow - 1) * (widthy + gapy)) / 2 + + for i in range(self.nbrow * self.nbcol): + row = i % self.nbrow + col = i // self.nbrow + startx = left + ((widthx + gapx) * col) + starty = start + ((widthy + gapy) * row) + + # Add random rotation + if (self.RandomRotation) and not (self.GridScaleX or self.GridScaleY): + rotmat = Matrix.Rotation(math.radians(360 * random.random()), 4, 'Z') + for v in obverts: + v.co = v.co @ rotmat + + verts.extend([((v.co.x - startx, v.co.y - starty, v.co.z)) for v in obverts]) + faces.extend([[v + numface * lenverts for v in p.vertices] for p in obfaces]) + numface += 1 + + # Update the mesh + # Create mesh data + mymesh = bpy.data.meshes.new("CT_Profil") + # Generate mesh data + mymesh.from_pydata(verts, edges, faces) + # Calculate the edges + mymesh.update(calc_edges=True) + # Update data + obj.data = mymesh + # Make the object active to remove doubles + context.view_layer.objects.active = obj def boolean_operation(bool_type="DIFFERENCE"): - ActiveObj = bpy.context.active_object - sel_index = 0 if bpy.context.selected_objects[0] != bpy.context.active_object else 1 + ActiveObj = bpy.context.active_object + sel_index = 0 if bpy.context.selected_objects[0] != bpy.context.active_object else 1 - # bpy.ops.object.modifier_apply(apply_as='DATA', modifier="CT_SOLIDIFY") - bool_name = "CT_" + bpy.context.selected_objects[sel_index].name - BoolMod = ActiveObj.modifiers.new(bool_name, "BOOLEAN") - BoolMod.object = bpy.context.selected_objects[sel_index] - BoolMod.operation = bool_type - bpy.context.selected_objects[sel_index].display_type = 'WIRE' - while ActiveObj.modifiers.find(bool_name) > 0: - bpy.ops.object.modifier_move_up(modifier=bool_name) + # bpy.ops.object.modifier_apply(apply_as='DATA', modifier="CT_SOLIDIFY") + bool_name = "CT_" + bpy.context.selected_objects[sel_index].name + BoolMod = ActiveObj.modifiers.new(bool_name, "BOOLEAN") + BoolMod.object = bpy.context.selected_objects[sel_index] + BoolMod.operation = bool_type + bpy.context.selected_objects[sel_index].display_type = 'WIRE' + while ActiveObj.modifiers.find(bool_name) > 0: + bpy.ops.object.modifier_move_up(modifier=bool_name) def Rebool(context, self): - target_obj = context.active_object + target_obj = context.active_object - Brush = context.selected_objects[1] - Brush.display_type = "WIRE" + Brush = context.selected_objects[1] + Brush.display_type = "WIRE" - #Deselect all - bpy.ops.object.select_all(action='TOGGLE') + #Deselect all + bpy.ops.object.select_all(action='TOGGLE') - target_obj.display_type = "SOLID" - target_obj.select_set(True) - bpy.ops.object.duplicate() + target_obj.display_type = "SOLID" + target_obj.select_set(True) + bpy.ops.object.duplicate() - rebool_obj = context.active_object + rebool_obj = context.active_object - m = rebool_obj.modifiers.new("CT_INTERSECT", "BOOLEAN") - m.operation = "INTERSECT" - m.object = Brush + m = rebool_obj.modifiers.new("CT_INTERSECT", "BOOLEAN") + m.operation = "INTERSECT" + m.object = Brush - m = target_obj.modifiers.new("CT_DIFFERENCE", "BOOLEAN") - m.operation = "DIFFERENCE" - m.object = Brush + m = target_obj.modifiers.new("CT_DIFFERENCE", "BOOLEAN") + m.operation = "DIFFERENCE" + m.object = Brush - for mb in target_obj.modifiers: - if mb.type == 'BEVEL': - mb.show_viewport = False + for mb in target_obj.modifiers: + if mb.type == 'BEVEL': + mb.show_viewport = False - if self.ObjectBrush or self.ProfileBrush: - rebool_obj.show_in_front = False - try: - bpy.ops.object.modifier_apply(apply_as='DATA', modifier="CT_SOLIDIFY") - except: - exc_type, exc_value, exc_traceback = sys.exc_info() - self.report({'ERROR'}, str(exc_value)) + if self.ObjectBrush or self.ProfileBrush: + rebool_obj.show_in_front = False + try: + bpy.ops.object.modifier_apply(apply_as='DATA', modifier="CT_SOLIDIFY") + except: + exc_type, exc_value, exc_traceback = sys.exc_info() + self.report({'ERROR'}, str(exc_value)) - if self.dont_apply_boolean is False: - try: - bpy.ops.object.modifier_apply(apply_as='DATA', modifier="CT_INTERSECT") - except: - exc_type, exc_value, exc_traceback = sys.exc_info() - self.report({'ERROR'}, str(exc_value)) + if self.dont_apply_boolean is False: + try: + bpy.ops.object.modifier_apply(apply_as='DATA', modifier="CT_INTERSECT") + except: + exc_type, exc_value, exc_traceback = sys.exc_info() + self.report({'ERROR'}, str(exc_value)) - bpy.ops.object.select_all(action='TOGGLE') + bpy.ops.object.select_all(action='TOGGLE') - for mb in target_obj.modifiers: - if mb.type == 'BEVEL': - mb.show_viewport = True + for mb in target_obj.modifiers: + if mb.type == 'BEVEL': + mb.show_viewport = True - context.view_layer.objects.active = target_obj - target_obj.select_set(True) - if self.dont_apply_boolean is False: - try: - bpy.ops.object.modifier_apply(apply_as='DATA', modifier="CT_DIFFERENCE") - except: - exc_type, exc_value, exc_traceback = sys.exc_info() - self.report({'ERROR'}, str(exc_value)) + context.view_layer.objects.active = target_obj + target_obj.select_set(True) + if self.dont_apply_boolean is False: + try: + bpy.ops.object.modifier_apply(apply_as='DATA', modifier="CT_DIFFERENCE") + except: + exc_type, exc_value, exc_traceback = sys.exc_info() + self.report({'ERROR'}, str(exc_value)) - bpy.ops.object.select_all(action='TOGGLE') + bpy.ops.object.select_all(action='TOGGLE') - rebool_obj.select_set(True) + rebool_obj.select_set(True) def createMeshFromData(self): - if self.Profils[self.nProfil][0] not in bpy.data.meshes: - # Create mesh and object - me = bpy.data.meshes.new(self.Profils[self.nProfil][0]) - # Create mesh from given verts, faces. - me.from_pydata(self.Profils[self.nProfil][2], [], self.Profils[self.nProfil][3]) - me.validate(verbose=True, clean_customdata=True) - # Update mesh with new data - me.update() - - if "CT_Profil" not in bpy.data.objects: - ob = bpy.data.objects.new("CT_Profil", bpy.data.meshes[self.Profils[self.nProfil][0]]) - ob.location = Vector((0.0, 0.0, 0.0)) - - # Link object to scene and make active - bpy.context.collection.objects.link(ob) - bpy.context.view_layer.update() - bpy.context.view_layer.objects.active = ob - ob.select_set(True) - ob.location = Vector((10000.0, 0.0, 0.0)) - ob.display_type = "WIRE" - - self.SolidifyPossible = True - else: - bpy.data.objects["CT_Profil"].data = bpy.data.meshes[self.Profils[self.nProfil][0]] + if self.Profils[self.nProfil][0] not in bpy.data.meshes: + # Create mesh and object + me = bpy.data.meshes.new(self.Profils[self.nProfil][0]) + # Create mesh from given verts, faces. + me.from_pydata(self.Profils[self.nProfil][2], [], self.Profils[self.nProfil][3]) + me.validate(verbose=True, clean_customdata=True) + # Update mesh with new data + me.update() + + if "CT_Profil" not in bpy.data.objects: + ob = bpy.data.objects.new("CT_Profil", bpy.data.meshes[self.Profils[self.nProfil][0]]) + ob.location = Vector((0.0, 0.0, 0.0)) + + # Link object to scene and make active + bpy.context.collection.objects.link(ob) + bpy.context.view_layer.update() + bpy.context.view_layer.objects.active = ob + ob.select_set(True) + ob.location = Vector((10000.0, 0.0, 0.0)) + ob.display_type = "WIRE" + + self.SolidifyPossible = True + else: + bpy.data.objects["CT_Profil"].data = bpy.data.meshes[self.Profils[self.nProfil][0]] def Selection_Save_Restore(self): - if "CT_Profil" in bpy.data.objects: - Selection_Save(self) - bpy.ops.object.select_all(action='DESELECT') - bpy.data.objects["CT_Profil"].select_set(True) - bpy.context.view_layer.objects.active = bpy.data.objects["CT_Profil"] - if bpy.data.objects["CT_Profil"] in self.all_sel_obj_list: - self.all_sel_obj_list.remove(bpy.data.objects["CT_Profil"]) - bpy.ops.object.delete(use_global=False) - Selection_Restore(self) + if "CT_Profil" in bpy.data.objects: + Selection_Save(self) + bpy.ops.object.select_all(action='DESELECT') + bpy.data.objects["CT_Profil"].select_set(True) + bpy.context.view_layer.objects.active = bpy.data.objects["CT_Profil"] + if bpy.data.objects["CT_Profil"] in self.all_sel_obj_list: + self.all_sel_obj_list.remove(bpy.data.objects["CT_Profil"]) + bpy.ops.object.delete(use_global=False) + Selection_Restore(self) def Selection_Save(self): - obj_name = getattr(bpy.context.active_object, "name", None) - self.all_sel_obj_list = bpy.context.selected_objects.copy() - self.save_active_obj = obj_name + obj_name = getattr(bpy.context.active_object, "name", None) + self.all_sel_obj_list = bpy.context.selected_objects.copy() + self.save_active_obj = obj_name def Selection_Restore(self): - for o in self.all_sel_obj_list: - o.select_set(True) - if self.save_active_obj: - bpy.context.view_layer.objects.active = bpy.data.objects.get(self.save_active_obj, None) + for o in self.all_sel_obj_list: + o.select_set(True) + if self.save_active_obj: + bpy.context.view_layer.objects.active = bpy.data.objects.get(self.save_active_obj, None) def Snap_Cursor(self, context, event, mouse_pos): - """ Find the closest position on the overlay grid and snap the mouse on it """ - # Get the context arguments - region = context.region - rv3d = context.region_data - - # Get the VIEW3D area - for i, a in enumerate(context.screen.areas): - if a.type == 'VIEW_3D': - space = context.screen.areas[i].spaces.active - - # Get the grid overlay for the VIEW_3D - grid_scale = space.overlay.grid_scale - grid_subdivisions = space.overlay.grid_subdivisions - - # Use the grid scale and subdivision to get the increment - increment = (grid_scale / grid_subdivisions) - half_increment = increment / 2 - - # Convert the 2d location of the mouse in 3d - for index, loc in enumerate(reversed(mouse_pos)): - mouse_loc_3d = region_2d_to_location_3d(region, rv3d, loc, (0, 0, 0)) - - # Get the remainder from the mouse location and the ratio - # Test if the remainder > to the half of the increment - for i in range(3): - modulo = mouse_loc_3d[i] % increment - if modulo < half_increment: - modulo = - modulo - else: - modulo = increment - modulo - - # Add the remainder to get the closest location on the grid - mouse_loc_3d[i] = mouse_loc_3d[i] + modulo - - # Get the snapped 2d location - snap_loc_2d = location_3d_to_region_2d(region, rv3d, mouse_loc_3d) - - # Replace the last mouse location by the snapped location - if len(self.mouse_path) > 0: - self.mouse_path[len(self.mouse_path) - (index + 1) ] = tuple(snap_loc_2d) + """ Find the closest position on the overlay grid and snap the mouse on it """ + # Get the context arguments + region = context.region + rv3d = context.region_data + + # Get the VIEW3D area + for i, a in enumerate(context.screen.areas): + if a.type == 'VIEW_3D': + space = context.screen.areas[i].spaces.active + + # Get the grid overlay for the VIEW_3D + grid_scale = space.overlay.grid_scale + grid_subdivisions = space.overlay.grid_subdivisions + + # Use the grid scale and subdivision to get the increment + increment = (grid_scale / grid_subdivisions) + half_increment = increment / 2 + + # Convert the 2d location of the mouse in 3d + for index, loc in enumerate(reversed(mouse_pos)): + mouse_loc_3d = region_2d_to_location_3d(region, rv3d, loc, (0, 0, 0)) + + # Get the remainder from the mouse location and the ratio + # Test if the remainder > to the half of the increment + for i in range(3): + modulo = mouse_loc_3d[i] % increment + if modulo < half_increment: + modulo = - modulo + else: + modulo = increment - modulo + + # Add the remainder to get the closest location on the grid + mouse_loc_3d[i] = mouse_loc_3d[i] + modulo + + # Get the snapped 2d location + snap_loc_2d = location_3d_to_region_2d(region, rv3d, mouse_loc_3d) + + # Replace the last mouse location by the snapped location + if len(self.mouse_path) > 0: + self.mouse_path[len(self.mouse_path) - (index + 1) ] = tuple(snap_loc_2d) def mini_grid(self, context, color): - """ Draw a snap mini grid around the cursor based on the overlay grid""" - # Get the context arguments - region = context.region - rv3d = context.region_data - - # Get the VIEW3D area - for i, a in enumerate(context.screen.areas): - if a.type == 'VIEW_3D': - space = context.screen.areas[i].spaces.active - screen_height = context.screen.areas[i].height - screen_width = context.screen.areas[i].width - - #Draw the snap grid, only in ortho view - if not space.region_3d.is_perspective : - grid_scale = space.overlay.grid_scale - grid_subdivisions = space.overlay.grid_subdivisions - increment = (grid_scale / grid_subdivisions) - - # Get the 3d location of the mouse forced to a snap value in the operator - mouse_coord = self.mouse_path[len(self.mouse_path) - 1] - - snap_loc = region_2d_to_location_3d(region, rv3d, mouse_coord, (0, 0, 0)) - - # Add the increment to get the closest location on the grid - snap_loc[0] += increment - snap_loc[1] += increment - - # Get the 2d location of the snap location - snap_loc = location_3d_to_region_2d(region, rv3d, snap_loc) - origin = location_3d_to_region_2d(region, rv3d, (0,0,0)) - - # Get the increment value - snap_value = snap_loc[0] - mouse_coord[0] - - grid_coords = [] - - # Draw lines on X and Z axis from the cursor through the screen - grid_coords = [ - (0, mouse_coord[1]), (screen_width, mouse_coord[1]), - (mouse_coord[0], 0), (mouse_coord[0], screen_height) - ] - - # Draw a mlini grid around the cursor to show the snap options - grid_coords += [ - (mouse_coord[0] + snap_value, mouse_coord[1] + 25 + snap_value), - (mouse_coord[0] + snap_value, mouse_coord[1] - 25 - snap_value), - (mouse_coord[0] + 25 + snap_value, mouse_coord[1] + snap_value), - (mouse_coord[0] - 25 - snap_value, mouse_coord[1] + snap_value), - (mouse_coord[0] - snap_value, mouse_coord[1] + 25 + snap_value), - (mouse_coord[0] - snap_value, mouse_coord[1] - 25 - snap_value), - (mouse_coord[0] + 25 + snap_value, mouse_coord[1] - snap_value), - (mouse_coord[0] - 25 - snap_value, mouse_coord[1] - snap_value), - ] - draw_shader(self, color, 0.3, 'LINES', grid_coords, size=2) + """ Draw a snap mini grid around the cursor based on the overlay grid""" + # Get the context arguments + region = context.region + rv3d = context.region_data + + # Get the VIEW3D area + for i, a in enumerate(context.screen.areas): + if a.type == 'VIEW_3D': + space = context.screen.areas[i].spaces.active + screen_height = context.screen.areas[i].height + screen_width = context.screen.areas[i].width + + #Draw the snap grid, only in ortho view + if not space.region_3d.is_perspective : + grid_scale = space.overlay.grid_scale + grid_subdivisions = space.overlay.grid_subdivisions + increment = (grid_scale / grid_subdivisions) + + # Get the 3d location of the mouse forced to a snap value in the operator + mouse_coord = self.mouse_path[len(self.mouse_path) - 1] + + snap_loc = region_2d_to_location_3d(region, rv3d, mouse_coord, (0, 0, 0)) + + # Add the increment to get the closest location on the grid + snap_loc[0] += increment + snap_loc[1] += increment + + # Get the 2d location of the snap location + snap_loc = location_3d_to_region_2d(region, rv3d, snap_loc) + origin = location_3d_to_region_2d(region, rv3d, (0,0,0)) + + # Get the increment value + snap_value = snap_loc[0] - mouse_coord[0] + + grid_coords = [] + + # Draw lines on X and Z axis from the cursor through the screen + grid_coords = [ + (0, mouse_coord[1]), (screen_width, mouse_coord[1]), + (mouse_coord[0], 0), (mouse_coord[0], screen_height) + ] + + # Draw a mlini grid around the cursor to show the snap options + grid_coords += [ + (mouse_coord[0] + snap_value, mouse_coord[1] + 25 + snap_value), + (mouse_coord[0] + snap_value, mouse_coord[1] - 25 - snap_value), + (mouse_coord[0] + 25 + snap_value, mouse_coord[1] + snap_value), + (mouse_coord[0] - 25 - snap_value, mouse_coord[1] + snap_value), + (mouse_coord[0] - snap_value, mouse_coord[1] + 25 + snap_value), + (mouse_coord[0] - snap_value, mouse_coord[1] - 25 - snap_value), + (mouse_coord[0] + 25 + snap_value, mouse_coord[1] - snap_value), + (mouse_coord[0] - 25 - snap_value, mouse_coord[1] - snap_value), + ] + draw_shader(self, color, 0.3, 'LINES', grid_coords, size=2) def draw_shader(self, color, alpha, type, coords, size=1, indices=None): - """ Create a batch for a draw type """ - bgl.glEnable(bgl.GL_BLEND) - bgl.glEnable(bgl.GL_LINE_SMOOTH) - if type =='POINTS': - bgl.glPointSize(size) - else: - bgl.glLineWidth(size) - try: - if len(coords[0])>2: - shader = gpu.shader.from_builtin('3D_UNIFORM_COLOR') - else: - shader = gpu.shader.from_builtin('2D_UNIFORM_COLOR') - batch = batch_for_shader(shader, type, {"pos": coords}, indices=indices) - shader.bind() - shader.uniform_float("color", (color[0], color[1], color[2], alpha)) - batch.draw(shader) - bgl.glLineWidth(1) - bgl.glPointSize(1) - bgl.glDisable(bgl.GL_LINE_SMOOTH) - bgl.glDisable(bgl.GL_BLEND) - except: - exc_type, exc_value, exc_traceback = sys.exc_info() - self.report({'ERROR'}, str(exc_value)) + """ Create a batch for a draw type """ + bgl.glEnable(bgl.GL_BLEND) + bgl.glEnable(bgl.GL_LINE_SMOOTH) + if type =='POINTS': + bgl.glPointSize(size) + else: + bgl.glLineWidth(size) + try: + if len(coords[0])>2: + shader = gpu.shader.from_builtin('3D_UNIFORM_COLOR') + else: + shader = gpu.shader.from_builtin('2D_UNIFORM_COLOR') + batch = batch_for_shader(shader, type, {"pos": coords}, indices=indices) + shader.bind() + shader.uniform_float("color", (color[0], color[1], color[2], alpha)) + batch.draw(shader) + bgl.glLineWidth(1) + bgl.glPointSize(1) + bgl.glDisable(bgl.GL_LINE_SMOOTH) + bgl.glDisable(bgl.GL_BLEND) + except: + exc_type, exc_value, exc_traceback = sys.exc_info() + self.report({'ERROR'}, str(exc_value)) diff --git a/object_collection_manager/internals.py b/object_collection_manager/internals.py index e2e6a64b2f8750914761915a22591a538179680d..64c4815008f2159d3e0ca621f002252858f941b2 100644 --- a/object_collection_manager/internals.py +++ b/object_collection_manager/internals.py @@ -214,4 +214,3 @@ def send_report(message): bpy.ops.view3d.cm_send_report(ctx, 'INVOKE_DEFAULT', message=message) bpy.app.timers.register(report) - diff --git a/oscurart_tools/files/reload_images.py b/oscurart_tools/files/reload_images.py index 68b5c61be97893ed85c3c531b573a1b1ede28443..8461e26df35b7569ff4431aa5197197fe980a2d4 100644 --- a/oscurart_tools/files/reload_images.py +++ b/oscurart_tools/files/reload_images.py @@ -33,5 +33,3 @@ class reloadImages (Operator): for imgs in bpy.data.images: imgs.reload() return {'FINISHED'} - - diff --git a/oscurart_tools/files/save_incremental.py b/oscurart_tools/files/save_incremental.py index b10db327d93bbf2a1ef34cfddb91fcd2ce12949d..d7eb4652fbccb5db392e121a625f92b16a47ae75 100644 --- a/oscurart_tools/files/save_incremental.py +++ b/oscurart_tools/files/save_incremental.py @@ -66,5 +66,3 @@ class saveIncrementalBackup (bpy.types.Operator): def execute(self, context): saveBkp(self, context) return {'FINISHED'} - - diff --git a/oscurart_tools/mesh/apply_linked_meshes.py b/oscurart_tools/mesh/apply_linked_meshes.py index 0bd7bf47df605eaaba3d65fcec2620047fa941e6..63e7f907950d698c2e9e4e80ae2cb73598cb81b8 100644 --- a/oscurart_tools/mesh/apply_linked_meshes.py +++ b/oscurart_tools/mesh/apply_linked_meshes.py @@ -53,8 +53,3 @@ class ApplyLRT(bpy.types.Operator): def execute(self, context): applyLRTEx(self, context) return {'FINISHED'} - - - - - diff --git a/oscurart_tools/mesh/flipped_uvs.py b/oscurart_tools/mesh/flipped_uvs.py index 14d1be4ce21fa03bcae8d410e255fac4864f8e39..13d837f1f6ced0b042f0cc384422e6355d4619eb 100644 --- a/oscurart_tools/mesh/flipped_uvs.py +++ b/oscurart_tools/mesh/flipped_uvs.py @@ -57,4 +57,4 @@ class selectFlippedUvs(bpy.types.Operator): def execute(self, context): defSelectFlippedUvs(self, context) - return {'FINISHED'} \ No newline at end of file + return {'FINISHED'} diff --git a/oscurart_tools/mesh/overlap_island.py b/oscurart_tools/mesh/overlap_island.py index 68b3d3393b2604af9d8d85277964fb890b065a94..c6b70cd231eda24eb6074a71486719a6c418defd 100644 --- a/oscurart_tools/mesh/overlap_island.py +++ b/oscurart_tools/mesh/overlap_island.py @@ -95,6 +95,3 @@ class OscOverlapUv(Operator): def execute(self, context): DefOscOverlapUv(self,self.offset,self.rotate) return {'FINISHED'} - - - diff --git a/oscurart_tools/mesh/overlap_uvs.py b/oscurart_tools/mesh/overlap_uvs.py index 2960bb3d66c07df6ea58ee9316f988fb0688d4b5..d0d13752063b4b3e89c37c8f74edbbe3022568b0 100644 --- a/oscurart_tools/mesh/overlap_uvs.py +++ b/oscurart_tools/mesh/overlap_uvs.py @@ -128,4 +128,3 @@ class PasteUvIsland(Operator): def execute(self, context): defPasteUvsIsland(self, self.uvOffset, self.rotateUv, context) return {'FINISHED'} - diff --git a/oscurart_tools/mesh/remove_modifiers.py b/oscurart_tools/mesh/remove_modifiers.py index 186588ce4dc6051056f54b1c604ee188401c245a..db01520063ba3d2ac56a683bd4a911f4ec509e0d 100644 --- a/oscurart_tools/mesh/remove_modifiers.py +++ b/oscurart_tools/mesh/remove_modifiers.py @@ -42,6 +42,3 @@ class RemoveModifiers(bpy.types.Operator): def execute(self, context): funcRemoveModifiers(self,context) return {'FINISHED'} - - - diff --git a/oscurart_tools/mesh/select_doubles.py b/oscurart_tools/mesh/select_doubles.py index b2a7d4345a73a7e4b1bc9ae368dfd92c7d433ee2..6551824a2e41e6c628273ef7466de4d78c6ba2cf 100644 --- a/oscurart_tools/mesh/select_doubles.py +++ b/oscurart_tools/mesh/select_doubles.py @@ -72,6 +72,3 @@ class SelectDoubles(Operator): def execute(self, context): SelDoubles(self, context,self.distance) return {'FINISHED'} - - - diff --git a/oscurart_tools/mesh/vertex_color_id.py b/oscurart_tools/mesh/vertex_color_id.py index 2eb9790dd635d41e0610b2551134884ecd126d07..6c68938a4510c5e6afcb58903cd0cdccf02183a5 100644 --- a/oscurart_tools/mesh/vertex_color_id.py +++ b/oscurart_tools/mesh/vertex_color_id.py @@ -65,6 +65,3 @@ class createVCMask(bpy.types.Operator): def execute(self, context): vertexColorMask(self, context) return {'FINISHED'} - - - diff --git a/oscurart_tools/object/distribute.py b/oscurart_tools/object/distribute.py index 991d664b4a7ff9ae7464e55cf36f369519e4ab24..a0fb6263b3592bd12094dd666b24eac45b672730 100644 --- a/oscurart_tools/object/distribute.py +++ b/oscurart_tools/object/distribute.py @@ -67,4 +67,3 @@ class DistributeOsc(Operator): self.Booly = True self.Boolz = True return context.window_manager.invoke_props_dialog(self) - diff --git a/oscurart_tools/object/search_and_select.py b/oscurart_tools/object/search_and_select.py index 707c7188c23d913f651aa9051ae94693580e5c5b..63787af43ccc0aea55b2d299610f4773a1860ff2 100644 --- a/oscurart_tools/object/search_and_select.py +++ b/oscurart_tools/object/search_and_select.py @@ -57,6 +57,3 @@ class SearchAndSelectOt(bpy.types.Operator): self.count = True self.end = True return context.window_manager.invoke_props_dialog(self) - - - diff --git a/oscurart_tools/render/batch_maker.py b/oscurart_tools/render/batch_maker.py index fed15dccb79599fd4e459a8d0fabf466b1affbc6..ca386546f11396401dbf70c66ff8b4adc6612ec9 100644 --- a/oscurart_tools/render/batch_maker.py +++ b/oscurart_tools/render/batch_maker.py @@ -48,4 +48,3 @@ class oscBatchMaker (bpy.types.Operator): def execute(self, context): batchMaker(self.bin) return {'FINISHED'} - diff --git a/oscurart_tools/render/material_overrides.py b/oscurart_tools/render/material_overrides.py index 5720d293300bde044680a09d58c8a8c55916ee74..faa9be6379b011dd6597d711e571f1c7c738ffee 100644 --- a/oscurart_tools/render/material_overrides.py +++ b/oscurart_tools/render/material_overrides.py @@ -175,4 +175,3 @@ class OscOverridesKill(bpy.types.Operator): ovlist = context.scene.ovlist ovlist.remove(self.index) return {'FINISHED'} - diff --git a/power_sequencer/scripts/BPSRender/bpsrender/__init__.py b/power_sequencer/scripts/BPSRender/bpsrender/__init__.py index 35a40273111a11f540497e54ba95d7f06193a22d..f14cfb6aacdac444a4541e30dbad103f17d168d4 100644 --- a/power_sequencer/scripts/BPSRender/bpsrender/__init__.py +++ b/power_sequencer/scripts/BPSRender/bpsrender/__init__.py @@ -14,4 +14,3 @@ # You should have received a copy of the GNU General Public License along with Power Sequencer. If # not, see <https://www.gnu.org/licenses/>. # - diff --git a/presets/pov/light/17_(1700K)_135W_Low_Pressure_Sodium.py b/presets/pov/light/17_(1700K)_135W_Low_Pressure_Sodium.py index a6486c019a1a6b5f874e24b05a2493e4af87bbd2..fc40d7723ceb117ffaca216f03e1961f3b160c66 100644 --- a/presets/pov/light/17_(1700K)_135W_Low_Pressure_Sodium.py +++ b/presets/pov/light/17_(1700K)_135W_Low_Pressure_Sodium.py @@ -8,4 +8,4 @@ lampdata = bpy.context.object.data lampdata.color = (1.0, 0.5764706134796143, 0.16078431904315948) lampdata.energy = 8.43048#22600lm/21.446(=lux)*0.004(distance) *2 for distance is the point of half strength lampdata.distance = 1.0 -lampdata.falloff_type = 'INVERSE_SQUARE' \ No newline at end of file +lampdata.falloff_type = 'INVERSE_SQUARE' diff --git a/presets/pov/world/4_Cartoony_Sky.py b/presets/pov/world/4_Cartoony_Sky.py index 90b87bf509e7b1f46ffb5c84dcdd2747688fe4a8..c2410a35f97b987a107a167937ee4e97272e8c2a 100644 --- a/presets/pov/world/4_Cartoony_Sky.py +++ b/presets/pov/world/4_Cartoony_Sky.py @@ -16,4 +16,4 @@ scene.pov.media_scattering_type = '4' scene.pov.media_samples = 35 scene.pov.media_diffusion_color = (0.20000000298023224, 0.4000000059604645, 1.0) scene.pov.media_absorption_color = (0.0, 0.0, 0.0) -scene.pov.media_eccentricity = 0.0 \ No newline at end of file +scene.pov.media_eccentricity = 0.0 diff --git a/presets/pov/world/5_Under_Water.py b/presets/pov/world/5_Under_Water.py index 36af41961b668db3923f78cd846d94c0393b0889..5dfd9c594ffb4c46546c9fa5c7af9303cfb286d8 100644 --- a/presets/pov/world/5_Under_Water.py +++ b/presets/pov/world/5_Under_Water.py @@ -16,4 +16,4 @@ scene.pov.media_scattering_type = '5' scene.pov.media_samples = 35 scene.pov.media_diffusion_color = (0.000034, 0.000034, 0.000017) scene.pov.media_absorption_color = (0.00000455, 0.00000165, 0.00000031) -scene.pov.media_eccentricity = 0.7 \ No newline at end of file +scene.pov.media_eccentricity = 0.7 diff --git a/rigify/base_generate.py b/rigify/base_generate.py index ea1415c9ba15719de2d6a6aa3e5338aa110b9fb0..7141d77e751422ac93009f163ca55f635fd1025a 100644 --- a/rigify/base_generate.py +++ b/rigify/base_generate.py @@ -465,4 +465,3 @@ class BaseGenerator: for bone in self.obj.data.bones: if bone.parent is None: self.__build_rig_tree_rec(bone, None, handled) - diff --git a/rigify/rot_mode.py b/rigify/rot_mode.py index 9398a737cd9db489228cef4b41567d71b2de48dc..6ea9f241f10bfd00d44b67abb88f61395a11b427 100644 --- a/rigify/rot_mode.py +++ b/rigify/rot_mode.py @@ -11,7 +11,7 @@ This script/addon: TO-DO: - To convert object's rotation mode (already done in Mutant Bob script, - but not done in this one. + but not done in this one. - To understand "EnumProperty" and write it well. - Code clean - ... diff --git a/rigify/utils/metaclass.py b/rigify/utils/metaclass.py index 77ce4b6bb5d83dfc564bcbacd4d0850b768de825..9e169e056bb3a4024421f1e797f162d130ae6ecb 100644 --- a/rigify/utils/metaclass.py +++ b/rigify/utils/metaclass.py @@ -168,4 +168,3 @@ class SingletonPluginMetaclass(StagedMetaclass): owner.plugin_list.append(new_obj) owner.plugin_list.sort(key=lambda obj: obj.priority, reverse=True) return new_obj - diff --git a/space_view3d_math_vis/draw.py b/space_view3d_math_vis/draw.py index 8adeeb0bec1bf9b4124b2621f780ef53974b7868..60467faadbd06bf702ec1a451f6d0332f279023d 100644 --- a/space_view3d_math_vis/draw.py +++ b/space_view3d_math_vis/draw.py @@ -244,4 +244,4 @@ def draw_bounding_boxes(matrices, scale, color): single_color_shader.bind() single_color_shader.uniform_float("color", color) - batch.draw(single_color_shader) \ No newline at end of file + batch.draw(single_color_shader) diff --git a/space_view3d_pie_menus/pie_origin.py b/space_view3d_pie_menus/pie_origin.py index f1edf2791ecfdcaf63486ffe4975cbdddd49642c..bc74fd1b1969e3f24af898e69e3290d7c25491dc 100644 --- a/space_view3d_pie_menus/pie_origin.py +++ b/space_view3d_pie_menus/pie_origin.py @@ -277,7 +277,7 @@ class PIE_MT_OriginPivot(Menu): # 2 - BOTTOM pie.operator("object.pivotobottom_edit", text="Origin to Bottom", icon='TRIA_DOWN') - # 8 - TOP + # 8 - TOP pie.operator("object.setorigintoselected_edit", text="Origin To Selected", icon='SNAP_INCREMENT') # 7 - TOP - LEFT diff --git a/space_view3d_spacebar_menu/__init__.py b/space_view3d_spacebar_menu/__init__.py index c46aea7fa7aaf960a8c7cde96095af73e20f239b..51a7d4dd897b26ba7434f015557bf1f6f64e169b 100644 --- a/space_view3d_spacebar_menu/__init__.py +++ b/space_view3d_spacebar_menu/__init__.py @@ -827,20 +827,20 @@ class VIEW3D_MT_Space_Dynamic_Menu(Menu): # Text Edit Mode def menu_func(self, context): - layout = self.layout - - layout.menu("VIEW3D_MT_View_Menu", icon='ZOOM_ALL') - layout.menu("VIEW3D_MT_select_edit_text", icon='VIEW3D') - layout.separator() - layout.operator_context = 'INVOKE_REGION_WIN' - layout.operator("wm.search_menu", text="Search", icon='VIEWZOOM') - layout.menu("VIEW3D_MT_Animation_Player", - text="Animation", icon='PLAY') - layout.menu("SCREEN_MT_user_menu", text="Quick Favorites", icon='HEART') - layout.operator("object.editmode_toggle", text="Enter Object Mode", - icon='OBJECT_DATA') - layout.separator() - layout.menu("VIEW3D_MT_UndoS", icon='ARROW_LEFTRIGHT') + layout = self.layout + + layout.menu("VIEW3D_MT_View_Menu", icon='ZOOM_ALL') + layout.menu("VIEW3D_MT_select_edit_text", icon='VIEW3D') + layout.separator() + layout.operator_context = 'INVOKE_REGION_WIN' + layout.operator("wm.search_menu", text="Search", icon='VIEWZOOM') + layout.menu("VIEW3D_MT_Animation_Player", + text="Animation", icon='PLAY') + layout.menu("SCREEN_MT_user_menu", text="Quick Favorites", icon='HEART') + layout.operator("object.editmode_toggle", text="Enter Object Mode", + icon='OBJECT_DATA') + layout.separator() + layout.menu("VIEW3D_MT_UndoS", icon='ARROW_LEFTRIGHT') # Preferences utility functions diff --git a/space_view3d_spacebar_menu/edit_mesh.py b/space_view3d_spacebar_menu/edit_mesh.py index eff16c0d32130fe480f9a445d4fbb5fef390640e..c7098c699e99668504e9d31eaad67b98e3e5ffc2 100644 --- a/space_view3d_spacebar_menu/edit_mesh.py +++ b/space_view3d_spacebar_menu/edit_mesh.py @@ -20,13 +20,13 @@ import bpy from bpy.types import ( - Operator, - Menu, - ) + Operator, + Menu, + ) from bpy.props import ( - BoolProperty, - StringProperty, - ) + BoolProperty, + StringProperty, + ) from .object_menus import * from .snap_origin_cursor import * @@ -36,210 +36,210 @@ from .snap_origin_cursor import * # ********** Edit Multiselect ********** class VIEW3D_MT_Edit_Multi(Menu): - bl_label = "Mode Select" + bl_label = "Mode Select" - def draw(self, context): - layout = self.layout + def draw(self, context): + layout = self.layout - layout.operator("selectedit.vertex", text="Vertex", icon='VERTEXSEL') - layout.operator("selectedit.edge", text="Edge", icon='EDGESEL') - layout.operator("selectedit.face", text="Face", icon='FACESEL') - layout.operator("selectedit.vertsfaces", text="Vertex/Faces", icon='VERTEXSEL') - layout.operator("selectedit.vertsedges", text="Vertex/Edges", icon='EDGESEL') - layout.operator("selectedit.edgesfaces", text="Edges/Faces", icon='FACESEL') - layout.operator("selectedit.vertsedgesfaces", text="Vertex/Edges/Faces", icon='OBJECT_DATAMODE') + layout.operator("selectedit.vertex", text="Vertex", icon='VERTEXSEL') + layout.operator("selectedit.edge", text="Edge", icon='EDGESEL') + layout.operator("selectedit.face", text="Face", icon='FACESEL') + layout.operator("selectedit.vertsfaces", text="Vertex/Faces", icon='VERTEXSEL') + layout.operator("selectedit.vertsedges", text="Vertex/Edges", icon='EDGESEL') + layout.operator("selectedit.edgesfaces", text="Edges/Faces", icon='FACESEL') + layout.operator("selectedit.vertsedgesfaces", text="Vertex/Edges/Faces", icon='OBJECT_DATAMODE') # ********** Edit Mesh Edge ********** class VIEW3D_MT_EditM_Edge(Menu): - bl_label = "Edges" + bl_label = "Edges" - def draw(self, context): - layout = self.layout - layout.operator_context = 'INVOKE_REGION_WIN' + def draw(self, context): + layout = self.layout + layout.operator_context = 'INVOKE_REGION_WIN' - layout.operator("mesh.mark_seam") - layout.operator("mesh.mark_seam", text="Clear Seam").clear = True - layout.separator() + layout.operator("mesh.mark_seam") + layout.operator("mesh.mark_seam", text="Clear Seam").clear = True + layout.separator() - layout.operator("mesh.mark_sharp") - layout.operator("mesh.mark_sharp", text="Clear Sharp").clear = True - layout.operator("mesh.extrude_move_along_normals", text="Extrude") - layout.separator() + layout.operator("mesh.mark_sharp") + layout.operator("mesh.mark_sharp", text="Clear Sharp").clear = True + layout.operator("mesh.extrude_move_along_normals", text="Extrude") + layout.separator() - layout.operator("mesh.edge_rotate", - text="Rotate Edge CW").direction = 'CW' - layout.operator("mesh.edge_rotate", - text="Rotate Edge CCW").direction = 'CCW' - layout.separator() + layout.operator("mesh.edge_rotate", + text="Rotate Edge CW").direction = 'CW' + layout.operator("mesh.edge_rotate", + text="Rotate Edge CCW").direction = 'CCW' + layout.separator() - layout.operator("TFM_OT_edge_slide", text="Edge Slide") - layout.operator("mesh.loop_multi_select", text="Edge Loop") - layout.operator("mesh.loop_multi_select", text="Edge Ring").ring = True - layout.operator("mesh.loop_to_region") - layout.operator("mesh.region_to_loop") + layout.operator("TFM_OT_edge_slide", text="Edge Slide") + layout.operator("mesh.loop_multi_select", text="Edge Loop") + layout.operator("mesh.loop_multi_select", text="Edge Ring").ring = True + layout.operator("mesh.loop_to_region") + layout.operator("mesh.region_to_loop") # multiple edit select modes. class VIEW3D_OT_selecteditVertex(Operator): - bl_idname = "selectedit.vertex" - bl_label = "Vertex Mode" - bl_description = "Vert Select" - bl_options = {'REGISTER', 'UNDO'} + bl_idname = "selectedit.vertex" + bl_label = "Vertex Mode" + bl_description = "Vert Select" + bl_options = {'REGISTER', 'UNDO'} - def execute(self, context): - if context.object.mode != "EDIT": - bpy.ops.object.mode_set(mode="EDIT") - bpy.ops.mesh.select_mode(use_extend=False, use_expand=False, type='VERT') - if bpy.ops.mesh.select_mode != "EDGE, FACE": - bpy.ops.mesh.select_mode(use_extend=False, use_expand=False, type='VERT') - return {'FINISHED'} + def execute(self, context): + if context.object.mode != "EDIT": + bpy.ops.object.mode_set(mode="EDIT") + bpy.ops.mesh.select_mode(use_extend=False, use_expand=False, type='VERT') + if bpy.ops.mesh.select_mode != "EDGE, FACE": + bpy.ops.mesh.select_mode(use_extend=False, use_expand=False, type='VERT') + return {'FINISHED'} class VIEW3D_OT_selecteditEdge(Operator): - bl_idname = "selectedit.edge" - bl_label = "Edge Mode" - bl_description = "Edge Select" - bl_options = {'REGISTER', 'UNDO'} + bl_idname = "selectedit.edge" + bl_label = "Edge Mode" + bl_description = "Edge Select" + bl_options = {'REGISTER', 'UNDO'} - def execute(self, context): - if context.object.mode != "EDIT": - bpy.ops.object.mode_set(mode="EDIT") - bpy.ops.mesh.select_mode(use_extend=False, use_expand=False, type='EDGE') - if bpy.ops.mesh.select_mode != "VERT, FACE": - bpy.ops.mesh.select_mode(use_extend=False, use_expand=False, type='EDGE') - return {'FINISHED'} + def execute(self, context): + if context.object.mode != "EDIT": + bpy.ops.object.mode_set(mode="EDIT") + bpy.ops.mesh.select_mode(use_extend=False, use_expand=False, type='EDGE') + if bpy.ops.mesh.select_mode != "VERT, FACE": + bpy.ops.mesh.select_mode(use_extend=False, use_expand=False, type='EDGE') + return {'FINISHED'} class VIEW3D_OT_selecteditFace(Operator): - bl_idname = "selectedit.face" - bl_label = "Multiedit Face" - bl_description = "Face Mode" - bl_options = {'REGISTER', 'UNDO'} + bl_idname = "selectedit.face" + bl_label = "Multiedit Face" + bl_description = "Face Mode" + bl_options = {'REGISTER', 'UNDO'} - def execute(self, context): - if context.object.mode != "EDIT": - bpy.ops.object.mode_set(mode="EDIT") - bpy.ops.mesh.select_mode(use_extend=False, use_expand=False, type='FACE') - if bpy.ops.mesh.select_mode != "VERT, EDGE": - bpy.ops.mesh.select_mode(use_extend=False, use_expand=False, type='FACE') - return {'FINISHED'} + def execute(self, context): + if context.object.mode != "EDIT": + bpy.ops.object.mode_set(mode="EDIT") + bpy.ops.mesh.select_mode(use_extend=False, use_expand=False, type='FACE') + if bpy.ops.mesh.select_mode != "VERT, EDGE": + bpy.ops.mesh.select_mode(use_extend=False, use_expand=False, type='FACE') + return {'FINISHED'} # Components Multi Selection Mode class VIEW3D_OT_selecteditVertsEdges(Operator): - bl_idname = "selectedit.vertsedges" - bl_label = "Verts Edges Mode" - bl_description = "Vert/Edge Select" - bl_options = {'REGISTER', 'UNDO'} - - def execute(self, context): - if context.object.mode != "EDIT": - bpy.ops.object.mode_set(mode="EDIT") - bpy.ops.mesh.select_mode(use_extend=False, use_expand=False, type='VERT') - if bpy.ops.mesh.select_mode != "VERT, EDGE, FACE": - bpy.ops.object.mode_set(mode="EDIT") - bpy.ops.mesh.select_mode(use_extend=False, use_expand=False, type='VERT') - bpy.ops.mesh.select_mode(use_extend=True, use_expand=False, type='EDGE') - return {'FINISHED'} + bl_idname = "selectedit.vertsedges" + bl_label = "Verts Edges Mode" + bl_description = "Vert/Edge Select" + bl_options = {'REGISTER', 'UNDO'} + + def execute(self, context): + if context.object.mode != "EDIT": + bpy.ops.object.mode_set(mode="EDIT") + bpy.ops.mesh.select_mode(use_extend=False, use_expand=False, type='VERT') + if bpy.ops.mesh.select_mode != "VERT, EDGE, FACE": + bpy.ops.object.mode_set(mode="EDIT") + bpy.ops.mesh.select_mode(use_extend=False, use_expand=False, type='VERT') + bpy.ops.mesh.select_mode(use_extend=True, use_expand=False, type='EDGE') + return {'FINISHED'} class VIEW3D_OT_selecteditEdgesFaces(Operator): - bl_idname = "selectedit.edgesfaces" - bl_label = "Edges Faces Mode" - bl_description = "Edge/Face Select" - bl_options = {'REGISTER', 'UNDO'} - - def execute(self, context): - if context.object.mode != "EDIT": - bpy.ops.object.mode_set(mode="EDIT") - bpy.ops.mesh.select_mode(use_extend=False, use_expand=False, type='EDGE') - if bpy.ops.mesh.select_mode != "VERT, EDGE, FACE": - bpy.ops.object.mode_set(mode="EDIT") - bpy.ops.mesh.select_mode(use_extend=False, use_expand=False, type='EDGE') - bpy.ops.mesh.select_mode(use_extend=True, use_expand=False, type='FACE') - return {'FINISHED'} + bl_idname = "selectedit.edgesfaces" + bl_label = "Edges Faces Mode" + bl_description = "Edge/Face Select" + bl_options = {'REGISTER', 'UNDO'} + + def execute(self, context): + if context.object.mode != "EDIT": + bpy.ops.object.mode_set(mode="EDIT") + bpy.ops.mesh.select_mode(use_extend=False, use_expand=False, type='EDGE') + if bpy.ops.mesh.select_mode != "VERT, EDGE, FACE": + bpy.ops.object.mode_set(mode="EDIT") + bpy.ops.mesh.select_mode(use_extend=False, use_expand=False, type='EDGE') + bpy.ops.mesh.select_mode(use_extend=True, use_expand=False, type='FACE') + return {'FINISHED'} class VIEW3D_OT_selecteditVertsFaces(Operator): - bl_idname = "selectedit.vertsfaces" - bl_label = "Verts Faces Mode" - bl_description = "Vert/Face Select" - bl_options = {'REGISTER', 'UNDO'} - - def execute(self, context): - if context.object.mode != "EDIT": - bpy.ops.object.mode_set(mode="EDIT") - bpy.ops.mesh.select_mode(use_extend=False, use_expand=False, type='VERT') - if bpy.ops.mesh.select_mode != "VERT, EDGE, FACE": - bpy.ops.object.mode_set(mode="EDIT") - bpy.ops.mesh.select_mode(use_extend=False, use_expand=False, type='VERT') - bpy.ops.mesh.select_mode(use_extend=True, use_expand=False, type='FACE') - return {'FINISHED'} + bl_idname = "selectedit.vertsfaces" + bl_label = "Verts Faces Mode" + bl_description = "Vert/Face Select" + bl_options = {'REGISTER', 'UNDO'} + + def execute(self, context): + if context.object.mode != "EDIT": + bpy.ops.object.mode_set(mode="EDIT") + bpy.ops.mesh.select_mode(use_extend=False, use_expand=False, type='VERT') + if bpy.ops.mesh.select_mode != "VERT, EDGE, FACE": + bpy.ops.object.mode_set(mode="EDIT") + bpy.ops.mesh.select_mode(use_extend=False, use_expand=False, type='VERT') + bpy.ops.mesh.select_mode(use_extend=True, use_expand=False, type='FACE') + return {'FINISHED'} class VIEW3D_OT_selecteditVertsEdgesFaces(Operator): - bl_idname = "selectedit.vertsedgesfaces" - bl_label = "Verts Edges Faces Mode" - bl_description = "Vert/Edge/Face Select" - bl_options = {'REGISTER', 'UNDO'} - - def execute(self, context): - if context.object.mode != "EDIT": - bpy.ops.object.mode_set(mode="EDIT") - bpy.ops.mesh.select_mode(use_extend=False, use_expand=False, type='VERT') - if bpy.ops.mesh.select_mode != "VERT, EDGE, FACE": - bpy.ops.object.mode_set(mode="EDIT") - bpy.ops.mesh.select_mode(use_extend=False, use_expand=False, type='VERT') - bpy.ops.mesh.select_mode(use_extend=True, use_expand=False, type='EDGE') - bpy.ops.mesh.select_mode(use_extend=True, use_expand=False, type='FACE') - return {'FINISHED'} + bl_idname = "selectedit.vertsedgesfaces" + bl_label = "Verts Edges Faces Mode" + bl_description = "Vert/Edge/Face Select" + bl_options = {'REGISTER', 'UNDO'} + + def execute(self, context): + if context.object.mode != "EDIT": + bpy.ops.object.mode_set(mode="EDIT") + bpy.ops.mesh.select_mode(use_extend=False, use_expand=False, type='VERT') + if bpy.ops.mesh.select_mode != "VERT, EDGE, FACE": + bpy.ops.object.mode_set(mode="EDIT") + bpy.ops.mesh.select_mode(use_extend=False, use_expand=False, type='VERT') + bpy.ops.mesh.select_mode(use_extend=True, use_expand=False, type='EDGE') + bpy.ops.mesh.select_mode(use_extend=True, use_expand=False, type='FACE') + return {'FINISHED'} # ********** Normals / Auto Smooth Menu ********** # Thanks to marvin.k.breuer for the Autosmooth part of the menu def menu_func(self, context): - layout = self.layout - obj = context.object - obj_data = context.active_object.data - layout.separator() - layout.prop(obj_data, "use_auto_smooth", text="Normals: Auto Smooth") + layout = self.layout + obj = context.object + obj_data = context.active_object.data + layout.separator() + layout.prop(obj_data, "use_auto_smooth", text="Normals: Auto Smooth") - # Auto Smooth Angle - two tab spaces to align it with the rest of the menu - layout.prop(obj_data, "auto_smooth_angle", - text=" Auto Smooth Angle") + # Auto Smooth Angle - two tab spaces to align it with the rest of the menu + layout.prop(obj_data, "auto_smooth_angle", + text=" Auto Smooth Angle") # List The Classes # classes = ( - VIEW3D_MT_Edit_Multi, - VIEW3D_MT_EditM_Edge, - VIEW3D_OT_selecteditVertex, - VIEW3D_OT_selecteditEdge, - VIEW3D_OT_selecteditFace, - VIEW3D_OT_selecteditVertsEdges, - VIEW3D_OT_selecteditEdgesFaces, - VIEW3D_OT_selecteditVertsFaces, - VIEW3D_OT_selecteditVertsEdgesFaces, + VIEW3D_MT_Edit_Multi, + VIEW3D_MT_EditM_Edge, + VIEW3D_OT_selecteditVertex, + VIEW3D_OT_selecteditEdge, + VIEW3D_OT_selecteditFace, + VIEW3D_OT_selecteditVertsEdges, + VIEW3D_OT_selecteditEdgesFaces, + VIEW3D_OT_selecteditVertsFaces, + VIEW3D_OT_selecteditVertsEdgesFaces, ) # Register Classes & Hotkeys # def register(): - for cls in classes: - bpy.utils.register_class(cls) + for cls in classes: + bpy.utils.register_class(cls) - bpy.types.VIEW3D_MT_edit_mesh_normals.append(menu_func) + bpy.types.VIEW3D_MT_edit_mesh_normals.append(menu_func) # Unregister Classes & Hotkeys # def unregister(): - for cls in reversed(classes): - bpy.utils.unregister_class(cls) + for cls in reversed(classes): + bpy.utils.unregister_class(cls) - bpy.types.VIEW3D_MT_edit_mesh_normals.remove(menu_func) + bpy.types.VIEW3D_MT_edit_mesh_normals.remove(menu_func) if __name__ == "__main__": - register() + register() diff --git a/space_view3d_spacebar_menu/snap_origin_cursor.py b/space_view3d_spacebar_menu/snap_origin_cursor.py index f10f2dfc020cb31e4124a0cb69b7165d6b7e6786..b150a4926bf3bf54b2782b316c770857081f8e89 100644 --- a/space_view3d_spacebar_menu/snap_origin_cursor.py +++ b/space_view3d_spacebar_menu/snap_origin_cursor.py @@ -20,283 +20,283 @@ import bpy from bpy.types import ( - Operator, - Menu, - ) + Operator, + Menu, +) from bpy.props import ( - BoolProperty, - StringProperty, - ) + BoolProperty, + StringProperty, +) from .object_menus import * # ********** Object Snap Cursor ********** class VIEW3D_MT_Snap_Context(Menu): - bl_label = "Snapping" + bl_label = "Snapping" - def draw(self, context): - layout = self.layout - toolsettings = context.tool_settings - layout.prop(toolsettings, "use_snap") - layout.prop(toolsettings, "snap_elements", expand=True) + def draw(self, context): + layout = self.layout + toolsettings = context.tool_settings + layout.prop(toolsettings, "use_snap") + layout.prop(toolsettings, "snap_elements", expand=True) class VIEW3D_MT_Snap_Origin(Menu): - bl_label = "Snap Origin" - - def draw(self, context): - layout = self.layout - layout.operator_context = 'EXEC_AREA' - layout.operator("object.origin_set", - text="Geometry to Origin").type = 'GEOMETRY_ORIGIN' - layout.separator() - layout.operator("object.origin_set", - text="Origin to Geometry").type = 'ORIGIN_GEOMETRY' - layout.operator("object.origin_set", - text="Origin to 3D Cursor").type = 'ORIGIN_CURSOR' - layout.operator("object.origin_set", - text="Origin to Center of Mass").type = 'ORIGIN_CENTER_OF_MASS' + bl_label = "Snap Origin" + + def draw(self, context): + layout = self.layout + layout.operator_context = 'EXEC_AREA' + layout.operator("object.origin_set", + text="Geometry to Origin").type = 'GEOMETRY_ORIGIN' + layout.separator() + layout.operator("object.origin_set", + text="Origin to Geometry").type = 'ORIGIN_GEOMETRY' + layout.operator("object.origin_set", + text="Origin to 3D Cursor").type = 'ORIGIN_CURSOR' + layout.operator("object.origin_set", + text="Origin to Center of Mass").type = 'ORIGIN_CENTER_OF_MASS' class VIEW3D_MT_CursorMenu(Menu): - bl_label = "Snap To" - - def draw(self, context): - layout = self.layout - layout.operator_context = 'INVOKE_REGION_WIN' - layout.menu("VIEW3D_MT_Snap_Origin") - layout.menu("VIEW3D_MT_Snap_Context") - layout.separator() - layout.operator("view3d.snap_cursor_to_selected", - text="Cursor to Selected") - layout.operator("view3d.snap_cursor_to_center", - text="Cursor to World Origin") - layout.operator("view3d.snap_cursor_to_grid", - text="Cursor to Grid") - layout.operator("view3d.snap_cursor_to_active", - text="Cursor to Active") - layout.separator() - layout.operator("view3d.snap_selected_to_cursor", - text="Selection to Cursor").use_offset = False - layout.operator("view3d.snap_selected_to_cursor", - text="Selection to Cursor (Keep Offset)").use_offset = True - layout.operator("view3d.snap_selected_to_grid", - text="Selection to Grid") - layout.operator("view3d.snap_cursor_selected_to_center", - text="Selection and Cursor to World Origin") + bl_label = "Snap To" + + def draw(self, context): + layout = self.layout + layout.operator_context = 'INVOKE_REGION_WIN' + layout.menu("VIEW3D_MT_Snap_Origin") + layout.menu("VIEW3D_MT_Snap_Context") + layout.separator() + layout.operator("view3d.snap_cursor_to_selected", + text="Cursor to Selected") + layout.operator("view3d.snap_cursor_to_center", + text="Cursor to World Origin") + layout.operator("view3d.snap_cursor_to_grid", + text="Cursor to Grid") + layout.operator("view3d.snap_cursor_to_active", + text="Cursor to Active") + layout.separator() + layout.operator("view3d.snap_selected_to_cursor", + text="Selection to Cursor").use_offset = False + layout.operator("view3d.snap_selected_to_cursor", + text="Selection to Cursor (Keep Offset)").use_offset = True + layout.operator("view3d.snap_selected_to_grid", + text="Selection to Grid") + layout.operator("view3d.snap_cursor_selected_to_center", + text="Selection and Cursor to World Origin") class VIEW3D_MT_CursorMenuLite(Menu): - bl_label = "Snap to" - - def draw(self, context): - layout = self.layout - layout.operator_context = 'INVOKE_REGION_WIN' - layout.menu("VIEW3D_MT_Snap_Origin") - layout.separator() - layout.operator("view3d.snap_cursor_to_selected", - text="Cursor to Selected") - layout.operator("view3d.snap_cursor_to_center", - text="Cursor to World Origin") - layout.operator("view3d.snap_cursor_to_grid", - text="Cursor to Grid") - layout.operator("view3d.snap_cursor_to_active", - text="Cursor to Active") - layout.separator() - layout.operator("view3d.snap_selected_to_cursor", - text="Selection to Cursor").use_offset = False - layout.operator("view3d.snap_selected_to_cursor", - text="Selection to Cursor (Keep Offset)").use_offset = True - layout.operator("view3d.snap_selected_to_grid", - text="Selection to Grid") - layout.operator("view3d.snap_cursor_selected_to_center", - text="Selection and Cursor to World Origin") + bl_label = "Snap to" + + def draw(self, context): + layout = self.layout + layout.operator_context = 'INVOKE_REGION_WIN' + layout.menu("VIEW3D_MT_Snap_Origin") + layout.separator() + layout.operator("view3d.snap_cursor_to_selected", + text="Cursor to Selected") + layout.operator("view3d.snap_cursor_to_center", + text="Cursor to World Origin") + layout.operator("view3d.snap_cursor_to_grid", + text="Cursor to Grid") + layout.operator("view3d.snap_cursor_to_active", + text="Cursor to Active") + layout.separator() + layout.operator("view3d.snap_selected_to_cursor", + text="Selection to Cursor").use_offset = False + layout.operator("view3d.snap_selected_to_cursor", + text="Selection to Cursor (Keep Offset)").use_offset = True + layout.operator("view3d.snap_selected_to_grid", + text="Selection to Grid") + layout.operator("view3d.snap_cursor_selected_to_center", + text="Selection and Cursor to World Origin") # Code thanks to Isaac Weaver (wisaac) D1963 class VIEW3D_OT_SnapCursSelToCenter(Operator): - bl_idname = "view3d.snap_cursor_selected_to_center" - bl_label = "Snap Cursor & Selection to World Origin" - bl_description = ("Snap 3D cursor and selected objects to the center \n" - "Works only in Object Mode") + bl_idname = "view3d.snap_cursor_selected_to_center" + bl_label = "Snap Cursor & Selection to World Origin" + bl_description = ("Snap 3D cursor and selected objects to the center \n" + "Works only in Object Mode") - @classmethod - def poll(cls, context): - return (context.area.type == "VIEW_3D" and context.mode == "OBJECT") + @classmethod + def poll(cls, context): + return (context.area.type == "VIEW_3D" and context.mode == "OBJECT") - def execute(self, context): - context.scene.cursor.location = (0, 0, 0) - for obj in context.selected_objects: - obj.location = (0, 0, 0) - return {'FINISHED'} + def execute(self, context): + context.scene.cursor.location = (0, 0, 0) + for obj in context.selected_objects: + obj.location = (0, 0, 0) + return {'FINISHED'} # Cursor Edge Intersection Defs # def abs(val): - if val > 0: - return val - return -val + if val > 0: + return val + return -val def edgeIntersect(context, operator): - from mathutils.geometry import intersect_line_line + from mathutils.geometry import intersect_line_line - obj = context.active_object + obj = context.active_object - if (obj.type != "MESH"): - operator.report({'ERROR'}, "Object must be a mesh") - return None + if (obj.type != "MESH"): + operator.report({'ERROR'}, "Object must be a mesh") + return None - edges = [] - mesh = obj.data - verts = mesh.vertices + edges = [] + mesh = obj.data + verts = mesh.vertices - is_editmode = (obj.mode == 'EDIT') - if is_editmode: - bpy.ops.object.mode_set(mode='OBJECT') + is_editmode = (obj.mode == 'EDIT') + if is_editmode: + bpy.ops.object.mode_set(mode='OBJECT') - for e in mesh.edges: - if e.select: - edges.append(e) + for e in mesh.edges: + if e.select: + edges.append(e) - if len(edges) > 2: - break + if len(edges) > 2: + break - if is_editmode: - bpy.ops.object.mode_set(mode='EDIT') + if is_editmode: + bpy.ops.object.mode_set(mode='EDIT') - if len(edges) != 2: - operator.report({'ERROR'}, - "Operator requires exactly 2 edges to be selected") - return + if len(edges) != 2: + operator.report({'ERROR'}, + "Operator requires exactly 2 edges to be selected") + return - line = intersect_line_line(verts[edges[0].vertices[0]].co, - verts[edges[0].vertices[1]].co, - verts[edges[1].vertices[0]].co, - verts[edges[1].vertices[1]].co) + line = intersect_line_line(verts[edges[0].vertices[0]].co, + verts[edges[0].vertices[1]].co, + verts[edges[1].vertices[0]].co, + verts[edges[1].vertices[1]].co) - if line is None: - operator.report({'ERROR'}, "Selected edges do not intersect") - return + if line is None: + operator.report({'ERROR'}, "Selected edges do not intersect") + return - point = line[0].lerp(line[1], 0.5) - context.scene.cursor.location = obj.matrix_world @ point + point = line[0].lerp(line[1], 0.5) + context.scene.cursor.location = obj.matrix_world @ point # Cursor Edge Intersection Operator # class VIEW3D_OT_CursorToEdgeIntersection(Operator): - bl_idname = "view3d.snap_cursor_to_edge_intersection" - bl_label = "Cursor to Edge Intersection" - bl_description = "Finds the mid-point of the shortest distance between two edges" + bl_idname = "view3d.snap_cursor_to_edge_intersection" + bl_label = "Cursor to Edge Intersection" + bl_description = "Finds the mid-point of the shortest distance between two edges" - @classmethod - def poll(cls, context): - obj = context.active_object - return (obj is not None and obj.type == 'MESH') + @classmethod + def poll(cls, context): + obj = context.active_object + return (obj is not None and obj.type == 'MESH') - def execute(self, context): - # Prevent unsupported Execution in Local View modes - space = bpy.context.space_data - if space.local_view: - self.report({'INFO'}, 'Global Perspective modes only unable to continue.') - return {'FINISHED'} - edgeIntersect(context, self) - return {'FINISHED'} + def execute(self, context): + # Prevent unsupported Execution in Local View modes + space = bpy.context.space_data + if space.local_view: + self.report({'INFO'}, 'Global Perspective modes only unable to continue.') + return {'FINISHED'} + edgeIntersect(context, self) + return {'FINISHED'} # Origin To Selected Edit Mode # def vfeOrigin(context): - try: - cursorPositionX = context.scene.cursor.location[0] - cursorPositionY = context.scene.cursor.location[1] - cursorPositionZ = context.scene.cursor.location[2] - bpy.ops.view3d.snap_cursor_to_selected() - bpy.ops.object.mode_set() - bpy.ops.object.origin_set(type='ORIGIN_CURSOR', center='MEDIAN') - bpy.ops.object.mode_set(mode='EDIT') - context.scene.cursor.location[0] = cursorPositionX - context.scene.cursor.location[1] = cursorPositionY - context.scene.cursor.location[2] = cursorPositionZ - return True - except: - return False + try: + cursorPositionX = context.scene.cursor.location[0] + cursorPositionY = context.scene.cursor.location[1] + cursorPositionZ = context.scene.cursor.location[2] + bpy.ops.view3d.snap_cursor_to_selected() + bpy.ops.object.mode_set() + bpy.ops.object.origin_set(type='ORIGIN_CURSOR', center='MEDIAN') + bpy.ops.object.mode_set(mode='EDIT') + context.scene.cursor.location[0] = cursorPositionX + context.scene.cursor.location[1] = cursorPositionY + context.scene.cursor.location[2] = cursorPositionZ + return True + except: + return False class VIEW3D_OT_SetOriginToSelected(Operator): - bl_idname = "object.setorigintoselected" - bl_label = "Set Origin to Selected" - bl_description = "Set Origin to Selected" + bl_idname = "object.setorigintoselected" + bl_label = "Set Origin to Selected" + bl_description = "Set Origin to Selected" - @classmethod - def poll(cls, context): - return (context.area.type == "VIEW_3D" and context.active_object is not None) + @classmethod + def poll(cls, context): + return (context.area.type == "VIEW_3D" and context.active_object is not None) - def execute(self, context): - check = vfeOrigin(context) - if not check: - self.report({"ERROR"}, "Set Origin to Selected could not be performed") - return {'CANCELLED'} + def execute(self, context): + check = vfeOrigin(context) + if not check: + self.report({"ERROR"}, "Set Origin to Selected could not be performed") + return {'CANCELLED'} - return {'FINISHED'} + return {'FINISHED'} # ********** Edit Mesh Cursor ********** class VIEW3D_MT_EditCursorMenu(Menu): - bl_label = "Snap To" - - def draw(self, context): - layout = self.layout - layout.operator_context = 'INVOKE_REGION_WIN' - layout.operator("object.setorigintoselected", - text="Origin to Selected V/F/E") - layout.separator() - layout.menu("VIEW3D_MT_Snap_Origin") - layout.menu("VIEW3D_MT_Snap_Context") - layout.separator() - layout.operator("view3d.snap_cursor_to_selected", - text="Cursor to Selected") - layout.operator("view3d.snap_cursor_to_center", - text="Cursor to World Origin") - layout.operator("view3d.snap_cursor_to_grid", - text="Cursor to Grid") - layout.operator("view3d.snap_cursor_to_active", - text="Cursor to Active") - layout.operator("view3d.snap_cursor_to_edge_intersection", - text="Cursor to Edge Intersection") - layout.separator() - layout.operator("view3d.snap_selected_to_cursor", - text="Selection to Cursor").use_offset = False - layout.operator("view3d.snap_selected_to_cursor", - text="Selection to Cursor (Keep Offset)").use_offset = True - layout.operator("view3d.snap_selected_to_grid", - text="Selection to Grid") + bl_label = "Snap To" + + def draw(self, context): + layout = self.layout + layout.operator_context = 'INVOKE_REGION_WIN' + layout.operator("object.setorigintoselected", + text="Origin to Selected V/F/E") + layout.separator() + layout.menu("VIEW3D_MT_Snap_Origin") + layout.menu("VIEW3D_MT_Snap_Context") + layout.separator() + layout.operator("view3d.snap_cursor_to_selected", + text="Cursor to Selected") + layout.operator("view3d.snap_cursor_to_center", + text="Cursor to World Origin") + layout.operator("view3d.snap_cursor_to_grid", + text="Cursor to Grid") + layout.operator("view3d.snap_cursor_to_active", + text="Cursor to Active") + layout.operator("view3d.snap_cursor_to_edge_intersection", + text="Cursor to Edge Intersection") + layout.separator() + layout.operator("view3d.snap_selected_to_cursor", + text="Selection to Cursor").use_offset = False + layout.operator("view3d.snap_selected_to_cursor", + text="Selection to Cursor (Keep Offset)").use_offset = True + layout.operator("view3d.snap_selected_to_grid", + text="Selection to Grid") # List The Classes # classes = ( - VIEW3D_MT_CursorMenu, - VIEW3D_MT_CursorMenuLite, - VIEW3D_MT_Snap_Context, - VIEW3D_MT_Snap_Origin, - VIEW3D_OT_SnapCursSelToCenter, - VIEW3D_OT_CursorToEdgeIntersection, - VIEW3D_OT_SetOriginToSelected, - VIEW3D_MT_EditCursorMenu, + VIEW3D_MT_CursorMenu, + VIEW3D_MT_CursorMenuLite, + VIEW3D_MT_Snap_Context, + VIEW3D_MT_Snap_Origin, + VIEW3D_OT_SnapCursSelToCenter, + VIEW3D_OT_CursorToEdgeIntersection, + VIEW3D_OT_SetOriginToSelected, + VIEW3D_MT_EditCursorMenu, ) # Register Classes & Hotkeys # def register(): - for cls in classes: - bpy.utils.register_class(cls) + for cls in classes: + bpy.utils.register_class(cls) # Unregister Classes & Hotkeys # def unregister(): - for cls in reversed(classes): - bpy.utils.unregister_class(cls) + for cls in reversed(classes): + bpy.utils.unregister_class(cls) if __name__ == "__main__": - register() + register() diff --git a/space_view3d_stored_views/io.py b/space_view3d_stored_views/io.py index 4f9aaa837ca83e1d9a1290b4759eea9e469bf910..83a5499d7aa6959d5bb0c004649284a072bae7d6 100644 --- a/space_view3d_stored_views/io.py +++ b/space_view3d_stored_views/io.py @@ -340,4 +340,4 @@ def register(): def unregister(): for cls in classes: - bpy.utils.unregister_class(cls) \ No newline at end of file + bpy.utils.unregister_class(cls) diff --git a/space_view3d_stored_views/operators.py b/space_view3d_stored_views/operators.py index 4cf8a2cf4662d50b09c91963ae8b368e38df46ac..284e785c702ee7446ff1b89692c87cc26ca88405 100644 --- a/space_view3d_stored_views/operators.py +++ b/space_view3d_stored_views/operators.py @@ -179,4 +179,4 @@ def register(): def unregister(): for cls in classes: - bpy.utils.unregister_class(cls) \ No newline at end of file + bpy.utils.unregister_class(cls) diff --git a/space_view3d_stored_views/properties.py b/space_view3d_stored_views/properties.py index 0bf9509727cfed26275b11a0197c05624193fda2..51666ce27d173e65e9f2e0384aa86104ac042175 100644 --- a/space_view3d_stored_views/properties.py +++ b/space_view3d_stored_views/properties.py @@ -134,4 +134,4 @@ def register(): def unregister(): for cls in classes: - bpy.utils.unregister_class(cls) \ No newline at end of file + bpy.utils.unregister_class(cls) diff --git a/sun_position/geo.py b/sun_position/geo.py index 6d49f2ad206a4e38c2c1c8a2c75b7a1014e5da6a..59c27e3926e125487004e36aa6f8e0102a40c162 100644 --- a/sun_position/geo.py +++ b/sun_position/geo.py @@ -36,7 +36,7 @@ class Parser: def add(self, name, pattern, virtual=False): """ Adds a new named pattern (regular expression) that can reference previously added patterns by %(pattern_name)s. - Virtual patterns can be used to make expressions more compact but don't show up in the parse tree. """ + Virtual patterns can be used to make expressions more compact but don't show up in the parse tree. """ self.raw_patterns[name] = "(?:" + pattern + ")" self.virtual[name] = virtual @@ -169,7 +169,7 @@ def get_coordinate(b): def parse_position(s): """ Takes a (utf8-encoded) string describing a position and returns a tuple of floats for latitude and longitude in degrees. - Tries to be as tolerant as possible with input. Returns None if parsing doesn't succeed. """ + Tries to be as tolerant as possible with input. Returns None if parsing doesn't succeed. """ parse_tree = position_parser.parse("position", s) if parse_tree == None: return None