Tips on improving techdraw performance
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!
Re: Tips on improving techdraw performance
Not trying to buzz kill, Isn't the hard part of this getting dimensions, end points, arcs, ect. And could this be a DXF instead of a SVG?
Thanks.
Thanks.
Re: Tips on improving techdraw performance
One issue at a time please
Re: Tips on improving techdraw performance
Sorry, I was actually trying to make less work. I thought the DXF format was created to rid the issues of trying to convert dots into lines. The svg format is not very easy to use when it comes to creating dimensions. Please proceed..
Re: Tips on improving techdraw performance
Ok I found a way to scale!
New version of the script, it should now work with any FreeCAD model. Just open a model, set the camera to your liking, and fire the script! (it can be saved as a macro too)
It now scales things correctly (there might be imprecision due to the SVG viewport size being an int, needs further testing), and supports lines and texts and dimensions too, although the text get exploded/rendered. This will need to get bettered at some point. But it's becoming quite powerful..
New version of the script, it should now work with any FreeCAD model. Just open a model, set the camera to your liking, and fire the script! (it can be saved as a macro too)
Code: Select all
import FreeCAD,FreeCADGui
from pivy import coin
from PySide import QtCore,QtGui
import os,re,math,tempfile
import TechDraw
# a name to save a temp file
svgfile = tempfile.mkstemp(suffix=".svg")[1]
# set object lighting to single face to get black fills
# but this creates artifacts in svg output, triangulation gets visible...
#ldict = {}
#for o in FreeCAD.ActiveDocument.Objects:
# if hasattr(o,"ViewObject") and hasattr(o.ViewObject,"Lighting"):
# ldict[o.Name] = o.ViewObject.Lighting
# o.ViewObject.Lighting = "One side"
# get nodes to render
sg = FreeCADGui.ActiveDocument.ActiveView.getSceneGraph()
ac = FreeCADGui.ActiveDocument.ActiveView.getCamera()
rn = coin.SoSeparator()
for n in sg.getChildren():
if isinstance(n,coin.SoSeparator):
ncopy = n.copy()
rn.addChild(ncopy)
# reset lighting of objects
#for o in FreeCAD.ActiveDocument.Objects:
# if o.Name in ldict:
# o.ViewObject.Lighting = ldict[o.Name]
# create viewer
v = FreeCADGui.createViewer()
if hasattr(v,"setName"):
v.setName("RenderViewer")
vv = v.getViewer()
vv.setBackgroundColor(1,1,1)
v.redraw()
# set clip plane
#clip = coin.SoClipPlane()
#clip.on = True
#plane = coin.SbPlane(coin.SbVec3f(1,0,0),5000) #dir, position on dir
#clip.plane.setValue(plane)
#rn.insertChild(clip,0)
# set scenegraph
vv.setSceneGraph(rn)
# set camera
#c = '#Inventor V2.1 ascii\n\n\nOrthographicCamera {\n viewportMapping ADJUST_CAMERA\n position -36733.652 -7668.0435 256.88913\n orientation -0.57735038 0.57735038 0.57735038 4.1887903\n nearDistance 5128.5186\n farDistance 76777.062\n aspectRatio 1\n focalDistance 40917\n height 11075.028\n\n}\n'
v.setCamera(ac)
# get the viewer's mdi subwindow
mdi = None
mw = FreeCADGui.getMainWindow()
for sw in mw.findChildren(QtGui.QMdiSubWindow):
if sw.windowTitle() == "RenderViewer":
mdi = sw
break
# save view
v.saveVectorGraphic(svgfile,1) # number is pixel size
# fix linewidths - the 1px default one is a bit too big...
f = open(svgfile,"r")
svg = f.read()
f.close()
svg = svg.replace("stroke-width:1.0;","stroke-width:0.2;")
svg = svg.replace("stroke-width=\"1px","stroke-width=\"0.2px")
# get 3D view dimensions, and calculate scale factor
factor = 1
if mdi:
ww = mdi.width()
wh = mdi.height()
p1 = v.getPoint(0,0)
p2 = v.getPoint(ww,wh)
diag = (p2.sub(p1)).Length
vpdim = re.findall("width=\"(.*?)\" height=\"(.*?)\"",svg)
if vpdim:
vpw = float(vpdim[0][0])
vph = float(vpdim[0][1])
vpdiag = math.hypot(vpw,vph)
factor = diag/vpdiag
#print("mdi:",ww,wh,"vp:",vpw,vph,"factor:",factor)
# remove background rectangle
svg = re.sub("<path.*?>","",svg,count=1,flags=re.MULTILINE|re.DOTALL)
# embed everything in a scale group and scale the viewport
if factor != 1:
svg = svg.replace("<g>","<g transform=\"scale("+str(factor)+","+str(factor)+")\">\n<g>",1)
svg = svg.replace("</svg>","</g>\n</svg>")
svg = re.sub("width=\""+vpdim[0][0]+"\"","width=\""+str(vpw*factor)+"\"",svg,count=1,flags=re.MULTILINE|re.DOTALL)
svg = re.sub("height=\""+vpdim[0][1]+"\"","height=\""+str(vph*factor)+"\"",svg,count=1,flags=re.MULTILINE|re.DOTALL)
# save result
#f = open(svgfile,"w")
#f.write(svg)
#f.close()
# close viewer
if mdi:
mdi.close()
# find or create TD page
pages = FreeCAD.ActiveDocument.findObjects("TechDraw::DrawPage")
if pages:
page = pages[0]
else:
page = FreeCAD.ActiveDocument.addObject('TechDraw::DrawPage','Page')
template = FreeCAD.ActiveDocument.addObject('TechDraw::DrawSVGTemplate','Template')
template.Template = os.path.join(FreeCAD.getResourceDir(),'Mod/TechDraw/Templates/A4_LandscapeTD.svg')
page.Template = template
view = FreeCAD.ActiveDocument.addObject('TechDraw::DrawViewSymbol','RenderedView')
view.Symbol = svg
# calculate a rough scale factor...
view.Scale = 1000.0/(vpw*factor)
page.addView(view)
FreeCAD.ActiveDocument.recompute()
Re: Tips on improving techdraw performance
This is a whole new level of kickbutt-ness!
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
Re: Tips on improving techdraw performance
The way it's done by many in FreeCAD, is that you add the dimensions using Draft Dimension on the 3D model itself. Then, in TechDraw you just show those dimensions. You don't add more dimensions there.
Always add the important information to your posts if you need help. Also see Tutorials and Video tutorials.
To support the documentation effort, and code development, your donation is appreciated: liberapay.com/FreeCAD.
To support the documentation effort, and code development, your donation is appreciated: liberapay.com/FreeCAD.
Re: Tips on improving techdraw performance
Thanks vocx, I was looking at those dims and I couldn't figure out how they were placed.vocx » Fri Aug 16, 2019 2:46 am
The way it's done by many in FreeCAD, is that you add the dimensions using Draft Dimension on the 3D model itself. Then, in TechDraw you just show those dimensions. You don't add more dimensions there.
Yorik, when I ran the code as a macro I had to comment out.
Code: Select all
line 39, in <module> v.setBackgroundColor(1,1,1) <type 'exceptions.AttributeError'>: setBackgroundColor
- wandererfan
- Veteran
- Posts: 6268
- Joined: Tue Nov 06, 2012 5:42 pm
- Contact:
Re: Tips on improving techdraw performance
If I remember rightly, this code determines the real world size of the viewport in mm, then computes a scale that corrects the generated image to be the right size in TD. It is working on bit maps, but the principle should be the same for Svg.yorik wrote: ↑Thu Aug 15, 2019 3:31 pm So I think before passing the SVG to the ViewSymbol, we'll need to scale it properly, but I suppose it shouldn't be hard to either convert the C++ code you're referring to, or make a python binding for it. Only, I couldn't locate that code, could you give me some direction?
Code: Select all
Gui::View3DInventor* view3d = qobject_cast<Gui::View3DInventor*>(mdi3d);
if (view3d != nullptr) {
Base::Console().Message("G3d::grab3dView - have a view3d\n");
Gui::View3DInventorViewer* viewer = view3d->getViewer();
if (viewer == nullptr) {
Base::Console().Message("G3d::grab3dView - no V3DIV\n");
return result;
}
SbVec2s vpsize = viewer->getSoRenderManager()->getViewportRegion().getViewportSizePixels();
vpWpx= vpsize[0]; //viewport size in pixels
vpHpx = vpsize[1];
//save picture as vpWpxx x vpHpx rectangle. ie same as screen
viewer->savePicture(vpWpx, vpHpx, 8, bg, img); //what is magic number 8? a page size?
//determine scale of 3dView bitmap
SoCamera * const camera = viewer->getSoRenderManager()->getCamera();
if (!camera) {
Base::Console().Message("G3d::grab3dView - no camera\n");
return result;
}
double heightmm = 0.0;
double angle = 0.0;
double focalDistance = camera->focalDistance.getValue();
if (camera->getTypeId() == SoOrthographicCamera::getClassTypeId()) {
Base::Console().Message("G3d::grab3dView - camera is ortho\n");
SoOrthographicCamera* oCam = dynamic_cast<SoOrthographicCamera*>(camera);
heightmm = oCam->height.getValue();
angle = M_PI / 4.0; //45*
} else if (camera->getTypeId() == SoPerspectiveCamera::getClassTypeId()) {
Base::Console().Message("G3d::grab3dView - camera is persp\n");
SoPerspectiveCamera* pCam = dynamic_cast<SoPerspectiveCamera*>(camera);
angle = pCam->heightAngle.getValue();
heightmm = tan(angle / 2.0) * focalDistance * 2.0;
} else {
msg = QT_TR_NOOP("Grabber::grab3dView - camera is Unknown");
msg += "\n";
Base::Console().Warning(msg.c_str());
return result;
}
double vpmmppx = heightmm/vpHpx; //height in mm / viewport height in px = mm/px
double preScale = vpmmppx/tdmmppx; //this is pretty good as a prescaler to size for TD
feat->PreScale.setValue(preScale);
- wandererfan
- Veteran
- Posts: 6268
- Joined: Tue Nov 06, 2012 5:42 pm
- Contact:
Re: Tips on improving techdraw performance
Great thanks!! Easy to convert to python. One thing, though, this code has the same limitation as the one I'm using now: the view size is obtained in pixels, which could give quite a lot of imprecision (enough to change the value of a dimension, for ex). But I suppose we'll have to live with it for now, there might be further checks we can apply later on to refine the scale factor.wandererfan wrote: ↑Fri Aug 16, 2019 1:28 pm If I remember rightly, this code determines the real world size of the viewport in mm, then computes a scale that corrects the generated image to be the right size in TD. It is working on bit maps, but the principle should be the same for Svg.
You are running 0.18 probably... This was added later I think.
One issue with the code above, is that texts are decomposed into many triangles (on the image in my last post, turning the dimension on doubles the size of the svg file and makes TD significantly slower). However, adding texts in SVG is simple and fast. Maybe we need some extra processing there, remove texts from the coin graph and re-add them manually... Lots of room for improvement!