OpenNURBS 3DM file support?
Forum rules
Be nice to others! Read the FreeCAD code of conduct!
Be nice to others! Read the FreeCAD code of conduct!
OpenNURBS 3DM file support?
I think that a good adition to FreeCAD will be the ability to read and write the OpenNURBS file format .3DM
3DM is the de-facto file-format for Rhino and Moi3D.
The SDK is free to use and implement in any application. OpenNURBS Toolkit: http://wiki.mcneel.com/developer/opennurbs/home
The openNURBS Initiative provides CAD, CAM, CAE, and computer graphics software developers the tools to accurately transfer 3-D geometry between applications.
3DM is the de-facto file-format for Rhino and Moi3D.
The SDK is free to use and implement in any application. OpenNURBS Toolkit: http://wiki.mcneel.com/developer/opennurbs/home
The openNURBS Initiative provides CAD, CAM, CAE, and computer graphics software developers the tools to accurately transfer 3-D geometry between applications.
Re: OpenNURBS 3DM file support?
It's actually a very old feature request! issue #337
Just waiting for a good soul decided to work on this
Just waiting for a good soul decided to work on this
Re: OpenNURBS 3DM file support?
As of 2020 this feature it is steel needed!
McNeel just release better libraries for Python, Javascript and .NET:
rhino3dm is a set of libraries based on the OpenNURBS geometry library with a "RhinoCommon" style. This provides the ability to access and manipulate geometry through .NET, Python or JavaScript applications independent of Rhino.
Libraries based on OpenNURBS with a RhinoCommon style
P.S: As I do use Rhino a lot, I will be very pleased to see a native implementation of the .3dm file format into FreeCAD. Also .3dm-s are supported by the Moi3D software.
McNeel just release better libraries for Python, Javascript and .NET:
rhino3dm is a set of libraries based on the OpenNURBS geometry library with a "RhinoCommon" style. This provides the ability to access and manipulate geometry through .NET, Python or JavaScript applications independent of Rhino.
Libraries based on OpenNURBS with a RhinoCommon style
P.S: As I do use Rhino a lot, I will be very pleased to see a native implementation of the .3dm file format into FreeCAD. Also .3dm-s are supported by the Moi3D software.
Re: OpenNURBS 3DM file support?
I am following the progress of rhino3dm.
But I think it is not complete yet.
I gave a try last week; I was able to import surfaces.
But I haven't found a way to get the trimming edges yet.
But I think it is not complete yet.
I gave a try last week; I was able to import surfaces.
But I haven't found a way to get the trimming edges yet.
Re: OpenNURBS 3DM file support?
Good to see some progress. Do you have a script to share? I am eager to test this. Thank you.
Re: OpenNURBS 3DM file support?
Here it is.
You must install rhino3dm python binding first.
On linux, I simply had to do :
You must install rhino3dm python binding first.
On linux, I simply had to do :
Code: Select all
pip install --user rhino3dm
Code: Select all
import os
import FreeCAD as App
import FreeCADGui as Gui
try:
import rhino3dm as r3
except ModuleNotFoundError:
App.Console.PrintError("You must install rhino3dm first !")
att = ["ApplicationName",
"ApplicationUrl",
"ApplicationDetails",
"CreatedBy",
"LastEditedBy",
"Revision"]
class File3dm:
def __init__(self, path):
self.f3dm = r3.File3dm.Read(path)
def parse_objects(self, doc=None):
if not doc:
doc = App.newDocument("3dm import")
part = doc.addObject('App::Part','Part')
for i in range(len(self.f3dm.Objects)):
obj_fullname = "{}".format(self.f3dm.Objects[i].Geometry)
first_split = obj_fullname.split(".")
second_split = first_split[-1].split(" ")
print("-----------------\n{}".format(second_split[0]))
obj = self.import_geometry(doc, self.f3dm.Objects[i].Geometry)
if obj:
part.addObject(obj)
def import_geometry(self, doc, geo):
if isinstance(geo, r3.Brep): #str(geo.ObjectType) == "ObjectType.Brep":
#print("Brep object")
print("is solid : {}".format(geo.IsSolid))
print("is manifold : {}".format(geo.IsManifold))
print("is surface : {}".format(geo.IsSurface))
print("has {} faces".format(len(geo.Faces)))
print("has {} surfaces".format(len(geo.Surfaces)))
print("has {} edges".format(len(geo.Edges)))
shapes = []
for i in range(len(geo.Faces)):
#print(geo.Faces[i])
s = self.create_surface(geo.Faces[i])
shapes.append(s.toShape())
#print("Face {} has {} edges".format(i,len(geo.Faces[i].Edges)))
com = Part.Compound(shapes)
obj = doc.addObject("Part::Feature","Faces")
obj.Shape = com
# shapes = []
# for i in range(len(geo.Edges)):
# #print(geo.Faces[i])
# c = self.create_curve(geo.Edges[i])
# shapes.append(c.toShape())
# com = Part.Compound(shapes)
# obj = doc.addObject("Part::Feature","Edges")
# obj.Shape = com
return obj
if isinstance(geo, r3.Curve):
print("Curve object")
def create_curve(self, edge):
nc = edge.ToNurbsCurve()
#print("{} x {}".format(nu.Degree(0), nu.Degree(1)))
pts = []
weights = []
for u in range(len(nc.Points)):
p = nc.Points[u]
#print(App.Vector(p.X,p.Y,p.Z))
pts.append(App.Vector(p.X,p.Y,p.Z))
weights.append(p.W)
ku, mu = self.getFCKnots(nc.Knots)
periodic = False #mu[0] <= nu.Degree(0)
bs = Part.BSplineCurve()
bs.buildFromPolesMultsKnots(pts, mu, ku, periodic, nc.Degree, weights)
if mu[0] < (nc.Degree+1):
bs.setPeriodic()
return bs
def create_surface(self, surf):
nu = surf.ToNurbsSurface()
#print("{} x {}".format(nu.Degree(0), nu.Degree(1)))
pts = []
weights = []
for u in range(nu.Points.CountU):
row = []
wrow = []
for v in range(nu.Points.CountV):
p = nu.Points[u,v]
#print(App.Vector(p.X,p.Y,p.Z))
row.append(App.Vector(p.X,p.Y,p.Z))
wrow.append(p.W)
pts.append(row)
weights.append(wrow)
ku, mu = self.getFCKnots(nu.KnotsU)
kv, mv = self.getFCKnots(nu.KnotsV)
uperiodic = False #mu[0] <= nu.Degree(0)
vperiodic = False #mv[0] <= nu.Degree(1)
# print(list(nu.KnotsU))
# print(ku, mu)
# print(kv, mv)
# vflatknots = list(nu.KnotsV)
# print("{}\n{}".format(uflatknots, vflatknots))
bs = Part.BSplineSurface()
bs.buildFromPolesMultsKnots(pts, mu, mv, ku, kv, uperiodic, vperiodic, nu.Degree(0), nu.Degree(1), weights)
if mu[0] < (nu.Degree(0)+1):
bs.setUPeriodic()
if mv[0] < (nu.Degree(1)+1):
bs.setVPeriodic()
return bs
def getFCKnots(self,fknots):
k = list(fknots)
mults = []
knots = list(set(k))
knots.sort()
for kn in knots:
mults.append(k.count(kn))
mults[0] += 1
mults[-1] += 1
return knots, mults
doc = App.ActiveDocument
if doc is None:
doc = App.newDocument("3dm_file")
from PySide import QtGui
dialogCaption = "Select a 3dm file"
dialogDir = ""
dialogFilter = "Rhino 3dm (*.3dm);;All files (*.*)"
fname = QtGui.QFileDialog.getOpenFileName(None, dialogCaption, dialogDir, dialogFilter)
fname = fname[0]
fi = File3dm(fname)
fi.parse_objects(doc)
Gui.SendMsgToActiveView("ViewFit")
-
- Veteran
- Posts: 2756
- Joined: Mon Feb 27, 2012 5:31 pm
Re: OpenNURBS 3DM file support?
@Chris_G - Are you going to add a Workbench that has an importer?
Re: OpenNURBS 3DM file support?
I don't know.
I just did a quick test out of curiosity.
But writing a whole importer may be more work than I can handle.
I just did a quick test out of curiosity.
But writing a whole importer may be more work than I can handle.
Re: OpenNURBS 3DM file support?
I notated issue #337.
Alone you go faster. Together we go farther
Please mark thread [Solved]
Want to contribute back to FC? Checkout:
'good first issues' | Open TODOs and FIXMEs | How to Help FreeCAD | How to report Bugs
Please mark thread [Solved]
Want to contribute back to FC? Checkout:
'good first issues' | Open TODOs and FIXMEs | How to Help FreeCAD | How to report Bugs
-
- Veteran
- Posts: 2756
- Joined: Mon Feb 27, 2012 5:31 pm
Re: OpenNURBS 3DM file support?
Okay if I fork your CurvesWB repro and have a go at adding an importer for 3DM based on your test code?
i.e. Would you be okay with handling any Pull requests that I then make?