imported wrl: howto get a bounding box?
Forum rules
and Helpful information
and Helpful information
IMPORTANT: Please click here and read this first, before asking for help
Also, be nice to others! Read the FreeCAD code of conduct!
Also, be nice to others! Read the FreeCAD code of conduct!
imported wrl: howto get a bounding box?
Hi,
is it possible to create and display a bounding box of a wrl model file imported in FreeCAD?
My target would be to create an 'envelope' for a wrl object, to be able to move & align the wrl object to other 3D shapes using its BBox as a reference.
Thanks in advance for any help.
Maurice
is it possible to create and display a bounding box of a wrl model file imported in FreeCAD?
My target would be to create an 'envelope' for a wrl object, to be able to move & align the wrl object to other 3D shapes using its BBox as a reference.
Thanks in advance for any help.
Maurice
Re: imported wrl: howto get a bounding box?
Hi again,
is there anyone that could give me a tip?
I found these threads that may also be relevant:
https://forum.freecadweb.org/viewtopic. ... rl#p208857
is there anyone that could give me a tip?
I found these threads that may also be relevant:
https://forum.freecadweb.org/viewtopic. ... rl#p208857
https://forum.freecadweb.org/viewtopic. ... 626#p78106microelly2 wrote: ↑Thu Jan 11, 2018 9:00 pm After the good results in testing the light and shadow nodes (https://forum.freecadweb.org/viewtopic. ... 20#p208588)
I'm optimistic to implement a VRML/Open Inventor GUI for non programmers.
wmayer wrote: ↑Sat Feb 07, 2015 3:50 pm In the first place VRML is a modelling language representing a 3d scenegraph. It can contain any kind of primitive geometries like spheres, cylinders, planes or it can contain text or it can contain meshes. So, your VRML file *can* contain a mesh but it doesn't need to.
-
- Veteran
- Posts: 5513
- Joined: Thu Apr 05, 2018 1:53 am
Re: imported wrl: howto get a bounding box?
Only thing I can think of that *might* work is to parse the ASCII representation of the IV object to acquire a list of points you could then sort through to find the MinX, MaxX, etc., and from those perhaps create a bounding box. Here is some messy bit of not optimized hackery I was playing around with to do this. At the end of it the points[] list will be a list of vectors.
Next step is to go through the points[] list and save the largest and smallest x,y,z values (so you'd have 6 in all, smallest and largest of each).
In this case "spheres" is the label of an import wrl file, which was just 2 spheres side by side. If the placement has been changed, I don't know if the points[] list would contain values relative to that placement or not. You would probably need to offset your bounding box with the object's placement.
Code: Select all
import FreeCAD
from FreeCAD import Base
df = App.ActiveDocument.getObject("spheres")
vo = df.ViewObject
iv = vo.IV
idx = iv.find("point [")
idx2 = iv.find("]",idx)
pts = iv[idx+len("point ["):idx2].replace('\n','').replace(' ','')
splt = pts.split(',')
pointStrings = []
points=[]
for s in splt:
pointStrings.append(s.split(' '))
for ps in pointStrings:
if len(ps)==4:
if len(ps[3])>0:
ps = ps[1:4]
else:
ps = ps[0:3]
try:
points.append(Base.Vector(float(ps[0]),float(ps[1]),float(ps[2])))
except:
FreeCAD.Console.PrintMessage('exception: '+str(ps)+'\n')
In this case "spheres" is the label of an import wrl file, which was just 2 spheres side by side. If the placement has been changed, I don't know if the points[] list would contain values relative to that placement or not. You would probably need to offset your bounding box with the object's placement.
Re: imported wrl: howto get a bounding box?
hi
here by wmayer for my macro Macro_BoundingBox_Tracing
other see search def getTextSize(self,vobj):
i tray adapt for my macro , but ...
PS: i upgrade my macro for ver 0.17
mario
here by wmayer for my macro Macro_BoundingBox_Tracing
Code: Select all
# -*- coding: utf-8 -*-
##http://forum.freecadweb.org/viewtopic.php?f=13&t=22331
selEx = FreeCADGui.Selection.getSelectionEx()
objs = [selobj.Object for selobj in selEx]
if len(objs) >= 1:
if hasattr(objs[0], "Shape"):
s = objs[0].Shape
elif hasattr(objs[0], "Mesh"):
s = objs[0].Mesh
elif hasattr(objs[0], "Points"):
s = objs[0].Points
else:
print "oups"
try:
print s
except Exception:
print "oups oups"
Code: Select all
#https://code.alephobjects.com/file/data/die5vpa3cwqodz6poakk/PHID-FILE-v2tfm6wj7rylxg7mi2hs/file
def getTextSize(self,vobj):
from pivy import coin
if vobj.DisplayMode == "3D text":
text = self.text3d
else:
text = self.text2d
v = FreeCADGui.ActiveDocument.ActiveView.getViewer().getSoRenderManager().getViewportRegion()
b = coin.SoGetBoundingBoxAction(v)
return b.getBoundingBox().getSize().getValue()
PS: i upgrade my macro for ver 0.17
mario
Maybe you need a special feature, go into Macros_recipes and Code_snippets, Topological_data_scripting.
My macros on Gist.github here complete macros Wiki and forum.
My macros on Gist.github here complete macros Wiki and forum.
Re: imported wrl: howto get a bounding box?
thanks a lot... this approach is fine!TheMarkster wrote: ↑Sun Oct 07, 2018 7:44 pm Only thing I can think of that *might* work is to parse the ASCII representation of the IV object to acquire a list of points you could then sort through to find the MinX, MaxX, etc., and from those perhaps create a bounding box. Here is some messy bit of not optimized hackery I was playing around with to do this. At the end of it the points[] list will be a list of vectors.
Next step is to go through the points[] list and save the largest and smallest x,y,z values (so you'd have 6 in all, smallest and largest of each).Code: Select all
...
In this case "spheres" is the label of an import wrl file, which was just 2 spheres side by side. If the placement has been changed, I don't know if the points[] list would contain values relative to that placement or not. You would probably need to offset your bounding box with the object's placement.
here my WIP macro:
Code: Select all
import FreeCAD
from FreeCAD import Base
sel = FreeCADGui.Selection.getSelection()
if len (sel) > 0:
df = App.ActiveDocument.getObject(sel[0].Name)
vo = df.ViewObject
iv = vo.IV
idx = iv.find("point [")
idx2 = iv.find("]",idx)
pts = iv[idx+len("point ["):idx2].replace('\n','').replace(' ','')
splt = pts.split(',')
pointStrings = []
points=[]
for s in splt:
pointStrings.append(s.split(' '))
for ps in pointStrings:
if len(ps)==4:
if len(ps[3])>0:
ps = ps[1:4]
else:
ps = ps[0:3]
try:
points.append(Base.Vector(float(ps[0]),float(ps[1]),float(ps[2])))
except:
FreeCAD.Console.PrintMessage('exception: '+str(ps)+'\n')
#print (points)
xmin=0;ymin=0;zmin=0;
xmax=0;ymax=0;zmax=0;
for p in points:
# print (p,p.x)
if p.x > xmax:
xmax=p.x
if p.x < xmin:
xmin=p.x
if p.y > ymax:
ymax=p.y
if p.y < ymin:
ymin=p.y
if p.z > zmax:
zmax=p.z
if p.z < zmin:
zmin=p.z
print ('xmin=',xmin,' xmax=',xmax)
print ('ymin=',ymin,' ymax=',ymax)
print ('zmin=',zmin,' zmax=',zmax)
else:
print('select a WRL model')
Hi Mario, thanks for the tips...
but this approach doesn't seem to work with pure wrl files (no mesh inside)mario52 wrote: ↑Mon Oct 08, 2018 4:40 pm hi
here by wmayer for my macro Macro_BoundingBox_Tracing
other see search def getTextSize(self,vobj):Code: Select all
....
i tray adapt for my macro , but ...Code: Select all
...
PS: i upgrade my macro for ver 0.17
mario
here my non functional testing code:
Code: Select all
import FreeCAD
from FreeCAD import Base
def getWrlSize(vobj):
from pivy import coin
print (vobj.DisplayMode)
#if vobj.DisplayMode == "3D text":
# text = self.text3d
#else:
# text = self.text2d
v = FreeCADGui.ActiveDocument.ActiveView.getViewer().getSoRenderManager().getViewportRegion()
b = coin.SoGetBoundingBoxAction(v)
return b.getBoundingBox().getSize().getValue()
sel = FreeCADGui.Selection.getSelection()
df = App.ActiveDocument.getObject(sel[0].Name)
vo = df.ViewObject
print (getWrlSize(vo))
I'm attaching a very simple wrl testing file coming from kicad (there is a 2.54 scale factor inside)
-
- Veteran
- Posts: 5513
- Joined: Thu Apr 05, 2018 1:53 am
Re: imported wrl: howto get a bounding box?
Excellent. I added these 3 lines to your code:
print ('xmin=',xmin,' xmax=',xmax)
print ('ymin=',ymin,' ymax=',ymax)
print ('zmin=',zmin,' zmax=',zmax)
to make a sort of half boundbox out of draft wires just for testing purposes.
This is a big file (the dragon) about 175 MB, and it takes a noticeable time to run (but not too bad, less than a minute). Should consider a progress indicator of some kind, and also optimizing. I think the finding of min/max points maybe could be done where the points[] list is being built instead of building it, might be faster.
print ('xmin=',xmin,' xmax=',xmax)
print ('ymin=',ymin,' ymax=',ymax)
print ('zmin=',zmin,' zmax=',zmax)
Code: Select all
Draft.makeLine(Base.Vector(xmin,ymin,zmin),Base.Vector(xmin,ymin,zmax))
Draft.makeLine(Base.Vector(xmin,ymin,zmin),Base.Vector(xmax,ymin,zmin))
Draft.makeLine(Base.Vector(xmin,ymin,zmin),Base.Vector(xmin,ymax,zmin))
This is a big file (the dragon) about 175 MB, and it takes a noticeable time to run (but not too bad, less than a minute). Should consider a progress indicator of some kind, and also optimizing. I think the finding of min/max points maybe could be done where the points[] list is being built instead of building it, might be faster.
Re: imported wrl: howto get a bounding box?
I added a bounding box from @mario BBox MacroTheMarkster wrote: ↑Tue Oct 09, 2018 8:26 pm Excellent. I added these 3 lines to your code:
print ('xmin=',xmin,' xmax=',xmax)
print ('ymin=',ymin,' ymax=',ymax)
print ('zmin=',zmin,' zmax=',zmax)to make a sort of half boundbox out of draft wires just for testing purposes.Code: Select all
Draft.makeLine(Base.Vector(xmin,ymin,zmin),Base.Vector(xmin,ymin,zmax)) Draft.makeLine(Base.Vector(xmin,ymin,zmin),Base.Vector(xmax,ymin,zmin)) Draft.makeLine(Base.Vector(xmin,ymin,zmin),Base.Vector(xmin,ymax,zmin))
...
Code: Select all
# -*- coding: utf-8 -*-
import FreeCAD, Draft
from FreeCAD import Base
sel = FreeCADGui.Selection.getSelection()
if len (sel) == 1:
limit=1e10
xmin=limit;ymin=limit;zmin=limit
xmax=-limit;ymax=-limit;zmax=-limit
df = App.ActiveDocument.getObject(sel[0].Name)
vo = df.ViewObject
print (vo.DisplayMode)
if vo.DisplayMode == 'VRML':
iv = vo.IV
idx = iv.find("point [")
idx2 = iv.find("]",idx)
pts = iv[idx+len("point ["):idx2].replace('\n','').replace(' ','')
splt = pts.split(',')
pointStrings = []
points=[]
for s in splt:
pointStrings.append(s.split(' '))
for ps in pointStrings:
if len(ps)==4:
if len(ps[3])>0:
ps = ps[1:4]
else:
ps = ps[0:3]
try:
px = float(ps[0]); py = float(ps[1]); pz = float(ps[2]);
points.append(Base.Vector(px,py,pz))
xmax = max(px,xmax);xmin = min(px,xmin)
ymax = max(py,ymax);ymin = min(py,ymin)
zmax = max(pz,zmax);zmin = min(pz,zmin)
except:
FreeCAD.Console.PrintMessage('exception: '+str(ps)+'\n')
#print (points)
print ('xmin=',xmin,' xmax=',xmax)
print ('ymin=',ymin,' ymax=',ymax)
print ('zmin=',zmin,' zmax=',zmax)
#Draft.makeLine(Base.Vector(xmin,ymin,zmin),Base.Vector(xmin,ymin,zmax))
#Draft.makeLine(Base.Vector(xmin,ymin,zmin),Base.Vector(xmax,ymin,zmin))
#Draft.makeLine(Base.Vector(xmin,ymin,zmin),Base.Vector(xmin,ymax,zmin))
BBox = App.ActiveDocument.addObject("Part::Box",sel[0].Name + "_BBox")
BBox.Label = sel[0].Label+'_BBox'
BBox.Length.Value = abs(xmax-xmin)
BBox.Width.Value = abs(ymax-ymin)
BBox.Height.Value = abs(zmax-zmin)
BBox.Placement=App.Placement(App.Vector(xmin,ymin,zmin), App.Rotation(App.Vector(0,0,1),0), App.Vector(0,0,0))
FreeCADGui.ActiveDocument.getObject(BBox.Name).LineColor = (1., 0., 0.)
FreeCADGui.ActiveDocument.getObject(BBox.Name).PointColor = (1., 0., 0.)
FreeCADGui.ActiveDocument.getObject(BBox.Name).ShapeColor = (1., 0., 0.)
FreeCADGui.ActiveDocument.getObject(BBox.Name).Transparency = 80
App.Console.PrintMessage(BBox.Label + " Volume : " + str(BBox.Shape.Volume)+"\n")
else:
print('select a WRL model')
else:
print('select a WRL model')
I wouldn't know how to add the progress indicator ... but it would be niceTheMarkster wrote: ↑Tue Oct 09, 2018 8:26 pm This is a big file (the dragon) about 175 MB, and it takes a noticeable time to run (but not too bad, less than a minute). Should consider a progress indicator of some kind, and also optimizing.
BTW the macro should also handle
- scale
- translation
- rotation
if present in the VRML (but this would be more difficult to achieve (because I don't think they are available at python level).
Thanks all for the very nice suggestions.
Maurice
-
- Veteran
- Posts: 5513
- Joined: Thu Apr 05, 2018 1:53 am
Re: imported wrl: howto get a bounding box?
The progress indicator could be as simple as some text in the report view.
If you want to see what the IV ASCII text representation looks like:
There is a transform section, which could be parsed:
Code: Select all
import FreeCAD
from PySide import QtGui
from time import sleep
for ii in range (0,10):
print("step "+str(ii)+" of 10 \n")
QtGui.QApplication.processEvents()
sleep(.001) #1 millisecond
#do lengthy processing here
Code: Select all
print(iv)
Code: Select all
Transform {
translation 0 0 0
rotation 0 0 1 0
scaleFactor 1 1 1
center 0 0 0
}
Re: imported wrl: howto get a bounding box?
Thanks,TheMarkster wrote: ↑Tue Oct 09, 2018 11:14 pm If you want to see what the IV ASCII text representation looks like:
There is a transform section, which could be parsed:Code: Select all
print(iv)
Code: Select all
Transform { translation 0 0 0 rotation 0 0 1 0 scaleFactor 1 1 1 center 0 0 0 }
some little improvements:
(Rotation doesn't seem to work correctly ATM )
Attached a test file (Dinosaur.wrl is fine, Dragon.wrl is not)
Code: Select all
# -*- coding: utf-8 -*-
import FreeCAD, Draft
from FreeCAD import Base
import math
sel = FreeCADGui.Selection.getSelection()
if len (sel) == 1:
limit=1e10
xmin=limit;ymin=limit;zmin=limit
xmax=-limit;ymax=-limit;zmax=-limit
df = App.ActiveDocument.getObject(sel[0].Name)
vo = df.ViewObject
print (vo.DisplayMode)
if vo.DisplayMode == 'VRML':
iv = vo.IV
if 1:
with open(r'c:\Temp\mywrldump.txt', 'w') as the_file:
the_file.write(iv)
#print(iv)
idx = iv.find("point [")
idx2 = iv.find("]",idx)
pts = iv[idx+len("point ["):idx2].replace('\n','').replace(' ','')
idx = iv.find('VRMLTransform')
idx2 = iv.find("}",idx)
VTransf = iv[idx:idx2]
#print(VTransf)
scale_f = (1.,1.,1.)
idx = VTransf.find('scale ')
#print ('idx scale ',idx)
if idx != -1:
idx2 = VTransf.find("\n",idx)
scale = VTransf[idx:idx2]
#print (scale)
scale_list = scale[6:].split(' ')
scale_f = (float(scale_list[0]),float(scale_list[1]),float(scale_list[2]))
print ('scale ', scale_f)
translation_f = (0.,0.,0.)
idx = VTransf.find("translation ")
#print ('idx translation ',idx)
if idx != -1:
idx2 = VTransf.find("\n",idx)
translation = VTransf[idx:idx2]
#print (translation)
translation_list = translation[12:].split(' ')
translation_f = (float(translation_list[0]),float(translation_list[1]),float(translation_list[2]))
print('translation ',translation_f)
rotation_f=(0.,0.,0.,0.)
idx = VTransf.find("rotation ")
#print ('idx rotation ',idx)
if idx != -1:
idx2 = VTransf.find("\n",idx)
rotation = VTransf[idx:idx2]
#print (rotation)
rotation_list = rotation[9:].replace(' ',' ').split(' ')
#print (rotation_list)
rotation_f = (float(rotation_list[0]),float(rotation_list[1]),float(rotation_list[2]),float(rotation_list[3]))
print('rotation ',rotation_f)
splt = pts.split(',')
pointStrings = []
points=[]
for s in splt:
pointStrings.append(s.split(' '))
for ps in pointStrings:
if len(ps)==4:
if len(ps[3])>0:
ps = ps[1:4]
else:
ps = ps[0:3]
try:
px = float(ps[0]); py = float(ps[1]); pz = float(ps[2]);
points.append(Base.Vector(px,py,pz))
xmax = max(px,xmax);xmin = min(px,xmin)
ymax = max(py,ymax);ymin = min(py,ymin)
zmax = max(pz,zmax);zmin = min(pz,zmin)
except:
FreeCAD.Console.PrintMessage('exception: '+str(ps)+'\n')
#print (points)
print ('xmin=',xmin,' xmax=',xmax)
print ('ymin=',ymin,' ymax=',ymax)
print ('zmin=',zmin,' zmax=',zmax)
#Draft.makeLine(Base.Vector(xmin,ymin,zmin),Base.Vector(xmin,ymin,zmax))
#Draft.makeLine(Base.Vector(xmin,ymin,zmin),Base.Vector(xmax,ymin,zmin))
#Draft.makeLine(Base.Vector(xmin,ymin,zmin),Base.Vector(xmin,ymax,zmin))
BBox = App.ActiveDocument.addObject("Part::Box",sel[0].Name + "_BBox")
BBox.Label = sel[0].Label+'_BBox'
BBox.Length.Value = abs(xmax-xmin)*scale_f[0];
BBox.Width.Value = abs(ymax-ymin)*scale_f[1];
BBox.Height.Value = abs(zmax-zmin)*scale_f[2];
BBox.Placement=App.Placement(App.Vector(xmin*scale_f[0]+translation_f[0],ymin*scale_f[1]+translation_f[1],zmin*scale_f[2]+translation_f[2]), \
App.Rotation(App.Vector(rotation_f[0],rotation_f[1],rotation_f[2]),(rotation_f[3])), App.Vector(0,0,0))
#BBox.Placement=App.Placement(App.Vector(xmin,ymin,zmin), App.Rotation(App.Vector(0,0,1),0), App.Vector(0,0,0))
FreeCADGui.ActiveDocument.getObject(BBox.Name).LineColor = (1., 0., 0.)
FreeCADGui.ActiveDocument.getObject(BBox.Name).PointColor = (1., 0., 0.)
FreeCADGui.ActiveDocument.getObject(BBox.Name).ShapeColor = (1., 0., 0.)
FreeCADGui.ActiveDocument.getObject(BBox.Name).Transparency = 80
App.Console.PrintMessage(BBox.Label + " Volume : " + str(BBox.Shape.Volume)+"\n")
else:
print('select a WRL model')
else:
print('select a WRL model')
Re: imported wrl: howto get a bounding box?
Hi Maurice,
Path creates a bounding box of a selected object.
Path creates a bounding box of a selected object.
Gruß Herbert