Created
September 4, 2020 08:31
-
-
Save brothermechanic/50ed5556d3ddcb14fc431c160b2a4ba1 to your computer and use it in GitHub Desktop.
FC_Subd_to_Nurbs.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# This program is free software; you can redistribute it and/or modify | |
# it under the terms of the GNU General Public License as published by | |
# the Free Software Foundation; either version 3 of the License, or | |
# (at your option) any later version. | |
# | |
# This program is distributed in the hope that it will be useful, but | |
# WITHOUT ANY WARRANTY; without even the implied warranty of | |
# MERCHANTIBILITY 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 | |
# along with this program. If not, see <http://www.gnu.org/licenses/>. | |
bl_info = { | |
"name" : "FC_subd_to_nurbs", | |
"author" : "Andrea Rastelli", | |
"description" : "subd to nurbs delirium converter", | |
"blender" : (2, 83, 0), | |
"version" : (0, 0, 1), | |
"location" : "Item", | |
"warning" : "IN DEVELOPMENT, weirdness", | |
"category" : "Mesh" | |
} | |
import bpy | |
from bpy.types import ( | |
PropertyGroup, | |
Panel | |
) | |
from bpy.props import ( | |
BoolProperty, | |
EnumProperty, | |
IntProperty, | |
FloatProperty, | |
StringProperty, | |
PointerProperty | |
) | |
#GLOBAL PROPS | |
class GLOBAL_UL_FreeCadBlender_props(PropertyGroup): | |
ex_dir = StringProperty(name="export folder",subtype="DIR_PATH") | |
fc_dir = StringProperty(name="FC37 bin path",subtype="DIR_PATH") | |
fname = StringProperty(name="file name",default="filename") | |
#GLOBAL PANEL | |
class VIEW3D_PT_FreeCadBlender_tool(Panel): | |
bl_space_type = 'VIEW_3D' | |
bl_region_type = 'UI' | |
bl_category = "Item" | |
bl_label = "SUBD_TO_NURBS" | |
@classmethod | |
def poll(cls, context): | |
obj = context.active_object | |
return (obj and obj.type == 'MESH' and context.mode == 'EDIT_MESH') | |
def draw(self, context): | |
layout = self.layout | |
layout.use_property_split = True | |
con = context.scene.FreeCadBlender_props | |
layout.prop(con, "ex_dir") | |
layout.prop(con, "fc_dir") | |
layout.prop(con, "fname") | |
layout.operator("mesh.fcb_subd_to_nurbs", text="to nurbs...almost") # OPERATOR | |
#OPERATOR | |
class MESH_OT_FreeCadBlender_subd_to_nurbs(bpy.types.Operator): | |
bl_idname = "mesh.fcb_subd_to_nurbs" | |
bl_label = "subd_to_nurbs" | |
bl_options = {'REGISTER', 'UNDO'} | |
@classmethod | |
def poll(cls, context): | |
obj = context.active_object | |
return (obj and obj.type == 'MESH' and context.mode == 'EDIT_MESH') | |
def execute(self, context): | |
SUBD_TO_NURBS() | |
return {'FINISHED'} | |
def invoke(self, context,event): | |
self.execute(context) | |
return {'FINISHED'} | |
classes = ( | |
GLOBAL_UL_FreeCadBlender_props, | |
MESH_OT_FreeCadBlender_subd_to_nurbs, | |
VIEW3D_PT_FreeCadBlender_tool | |
) | |
def register(): | |
from bpy.utils import register_class | |
for cls in classes: | |
register_class(cls) | |
bpy.types.Scene.FreeCadBlender_props = PointerProperty( | |
type = GLOBAL_UL_FreeCadBlender_props | |
) | |
def unregister(): | |
del(bpy.types.Scene.FreeCadBlender_props) | |
from bpy.utils import unregister_class | |
for cls in reversed(classes): | |
unregister_class(cls) | |
if __name__ == "__main__": | |
register() | |
def SUBD_TO_NURBS(): | |
import bpy,sys | |
sys.path.append(bpy.path.abspath(bpy.context.scene.FreeCadBlender_props.fc_dir)) | |
ex_dir = bpy.path.abspath(bpy.context.scene.FreeCadBlender_props.ex_dir) | |
fname = bpy.context.scene.FreeCadBlender_props.fname | |
import FreeCAD as F | |
from FreeCAD import Part | |
F.newDocument("freecad_temp") | |
F.setActiveDocument('freecad_temp') | |
import bpy,bmesh | |
bpy.ops.object.editmode_toggle() | |
bpy.ops.object.editmode_toggle() | |
obj = bpy.context.edit_object | |
me = obj.data | |
bm = bmesh.from_edit_mesh(me) | |
patches=[] | |
stored=set() | |
def get_verts(vert): | |
verts=set() | |
for e in vert.link_edges: | |
for v in e.verts: verts.add(v) | |
return verts | |
count=0 | |
for f in bm.faces: | |
bpy.ops.mesh.select_all(action='DESELECT') | |
if f not in stored: | |
print ('PATCH:',count); count+=1 | |
bsplines=[] | |
f.select=True | |
bpy.ops.mesh.select_linked(delimit={'SEAM'}) | |
Fgroup= set( [f for f in bm.faces if f.select] ) | |
Vgroup= set( [v for v in bm.verts if v.select] ) | |
corners= set() | |
borders = set() | |
centers = set() | |
for v in Vgroup: | |
linkedVerts= get_verts(v) | |
links = len ( set(Vgroup)&linkedVerts ) | |
if links == 3 : corners.add(v) | |
elif links == 4 : borders.add(v) | |
else: centers.add(v) | |
for b in borders: | |
linkedVerts= get_verts(b) | |
op = [ v for v in linkedVerts if v in corners ] | |
triad = [op[0],b,op[1]] | |
bsplines.append(triad) | |
for f in bm.faces: | |
if f.select: stored.add(f) | |
s1=bsplines.pop() | |
c1=s1[0] | |
c2,c3=None,None | |
bspline_ord=[s1] | |
print(s1) | |
for s in bsplines: | |
for v in s: | |
if v == c1: | |
bspline_ord.append(s) | |
print(s) | |
if s[0]==c1: c2=s[2] | |
elif s[2]==c1: c2=s[0] | |
break | |
for s in bsplines: | |
if s not in bspline_ord: | |
for v in s: | |
if v==c2 and s not in bspline_ord: | |
bspline_ord.append(s) | |
print(s) | |
break | |
break | |
for s in bsplines: | |
if s not in bspline_ord: | |
print(s) | |
bspline_ord.append(s) | |
patches.append(bspline_ord) | |
#patches.append(bsplines) | |
for p in patches: | |
curves=[] | |
item=0 | |
for b in p: | |
Points=[] | |
Points.append( F.Vector( b[0].co.x,b[0].co.y,b[0].co.z ) ) | |
Points.append( F.Vector( b[1].co.x,b[1].co.y,b[1].co.z ) ) | |
Points.append( F.Vector( b[2].co.x,b[2].co.y,b[2].co.z ) ) | |
curve=Part.BSplineCurve() | |
curve.increaseDegree(1) | |
curve.interpolate(Points) | |
curves.append(curve) | |
com = Part.makeCompound([x.toShape() for x in curves]) | |
com_obj = F.ActiveDocument.addObject('Part::Feature', 'boundary_edges%s'%item) | |
com_obj.Shape = com | |
F.ActiveDocument.recompute() | |
edge_names = ["Edge%d"%(n+1) for n in range(len(com.Edges))] | |
#edge_names = [n.name for n in com.Edges] | |
patch = F.ActiveDocument.addObject("Surface::Filling","Surface%s"%item) | |
patch.BoundaryEdges = (com_obj, edge_names) | |
F.ActiveDocument.recompute() | |
item+=1 | |
F.ActiveDocument.recompute() | |
SURFS= [] | |
for obj in F.ActiveDocument.Objects: | |
if 'Surface' in obj.Name: | |
SURFS.append(obj) | |
if 'boundary' in obj.Name: | |
F.ActiveDocument.removeObject(obj.Name) | |
F.activeDocument().addObject("Part::Compound","Compound") | |
F.activeDocument().Compound.Links = SURFS | |
F.ActiveDocument.recompute() | |
print (ex_dir+fname+'.step') | |
ex_dir=ex_dir+fname+'.step' | |
F.ActiveDocument.getObject("Compound").Shape.exportStep(ex_dir) | |
F.closeDocument("freecad_temp") | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment