Macro PartToVRML

From FreeCAD Documentation
Revision as of 22:10, 3 February 2016 by Easyw-fc (talk | contribs)

Description

This macro converts selected parts to VRML meshes for small size and faster loading (VRML models Kicad and Blender compatible)


Script

The icone

Macro_PartToVRML.FCMacro

# -*- coding: utf-8 -*-

# PartToVRML.FCMacro
# creates VRML model of selected object(s), with colors (for Kicad and Blender compatibility)
# useful messages on Report view
#

__title__ = "PartToVRML"
__author__ = "easyw-fc, hyOzd"
__url__     = "http://www.freecadweb.org/"
__version__ = "1.9.1"
__date__    = "03/02/2016"

__Comment__ = "This macro creates VRML model of selected object(s), with colors (for Kicad and Blender compatibility)"
__Web__ = "http://www.freecadweb.org/"
__Wiki__ = "http://www.freecadweb.org/wiki/index.php?title=Macro_PartToVRML"
__Icon__  = "/usr/lib/freecad/Mod/plugins/icons/Macro_PartToVRML.png"
__IconW__  = "C:/Users/User Name/AppData/Roaming/FreeCAD/Macro_PartToVRML.png"
__Help__ = "start the macro and follow the instructions"
__Status__ = "stable"
__Requires__ = "Freecad"

# FreeCAD VRML python exporter 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 sw 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 GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with expVrmlColor.FCMacro.  If not, see
# <http://www.gnu.org/licenses/>.

## export VRML from FreeCAD is a python macro that will export simplified VRML of 
## a (multi)selected Part or fused Part to VRML optimized to Kicad and compatible with Blender
## the size of VRML is much smaller compared to the one exported from FC Gui
## and the loading/rendering time is smaller too
## change mesh deviation to increase quality of VRML

## to do 
#  export material properties to vrml

import FreeCAD,FreeCADGui,Part,Mesh
import PySide
from PySide import QtGui, QtCore
from collections import namedtuple
import sys, os
from os.path import expanduser

#clearing previous messages
mw=Gui.getMainWindow()
c=mw.findChild(QtGui.QPlainTextEdit, "Python console")
c.clear()
r=mw.findChild(QtGui.QTextEdit, "Report view")
r.clear()

def say(msg):
    FreeCAD.Console.PrintMessage(msg)
    FreeCAD.Console.PrintMessage('\n')

# points: [Vector, Vector, ...]
# faces: [(pi, pi, pi), ], pi: point index
# color: (Red, Green, Blue), values range from 0 to 1.0
Mesh = namedtuple('Mesh', ['points', 'faces', 'color', 'transp'])

def shapeToMesh(shape, color, transp, scale=None):
    mesh_deviation=0.03 #the smaller the best quality, 1 coarse; 0.03 good compromise :)
    mesh_data = shape.tessellate(mesh_deviation)
    points = mesh_data[0]
    if scale != None:
        points = map(lambda p: p*scale, points)
    newMesh= Mesh(points = points,
                faces = mesh_data[1],
                color = color, transp=transp)
    return newMesh
        
def exportVRML(objects, filepath):
    """Export given list of Mesh objects to a VRML file.

    `Mesh` structure is defined at root."""

    with open(filepath, 'w') as f:
        # write the standard VRML header
        f.write("#VRML V2.0 utf8\n\n")
        for obj in objects:
            f.write("Shape { geometry IndexedFaceSet \n{ coordIndex [")
            # write coordinate indexes for each face
            f.write(','.join("%d,%d,%d,-1" % f for f in obj.faces))
            f.write("]\n") # closes coordIndex
            f.write("coord Coordinate { point [")
            # write coordinate points for each vertex
            #f.write(','.join('%.3f %.3f %.3f' % (p.x, p.y, p.z) for p in obj.points))
            f.write(','.join('%.3f %.3f %.3f' % (p.x, p.y, p.z) for p in obj.points))
            f.write("]\n}") # closes Coordinate
            #shape_col=(1.0, 0.0, 0.0)#, 0.0)
            f.write("}\n") # closes points
            #say(obj.color)
            shape_col=obj.color[:-1] #remove last item
            #say(shape_col)
            shape_transparency=obj.transp
            f.write("appearance Appearance{material Material{diffuseColor %f %f %f\n" % shape_col)
            f.write("transparency %f}}" % shape_transparency)
            f.write("}\n") # closes Shape
        say(filepath+' written')
###

def export(componentObjs, fullfilePathName, scale=None):
    """ Exports given ComponentModel object using FreeCAD.

    `componentObjs` : a ComponentObjs list
    `fullfilePathName` : name of the FC file, extension is important
    
    """
    
    exp_name=componentObjs[0].Label
    path, fname = os.path.split(fullfilePathName)
    fname=os.path.splitext(fname)[0]
    if scale != None:
        filename=path+os.sep+exp_name+'.wrl'
    else:
        filename=path+os.sep+exp_name+'_1_1.wrl'
    say(filename)    
    color=[]
    Diffuse_color=[]
    transparency=[]
    for obj in componentObjs:
        say(obj.Label)
        color.append(Gui.ActiveDocument.getObject(obj.Name).ShapeColor)
        transparency.append(Gui.ActiveDocument.getObject(obj.Name).Transparency/100.0)
        #say("color")
        #say(Gui.ActiveDocument.getObject(obj.Name).DiffuseColor)
        Diffuse_color.append(Gui.ActiveDocument.getObject(obj.Name).DiffuseColor)
    i=0
    meshes=[]
    #say("diffuse color")
    #say(Diffuse_color)
    indexColor=0;
    color_vector=[]
    applyDiffuse=0
    for obj in componentObjs:
        shape1=obj.Shape
        single_color=Diffuse_color[i];
        #check lenght color
        #say("len color")
        #say(len(single_color))
        #colors less then faces
        if(len(single_color)!=len(shape1.Faces)):
            applyDiffuse=0;
            #copy color to all faces
        #else copy singolar colors for faces
        else:
            applyDiffuse=1;
            for color in single_color:
                color_vector.append(color)
        #say("color_vector")
        #say(color_vector)
        for index in range(len(shape1.Faces)):
            #say("color x")
            #say(color_vector[indexColor])
            singleFace=shape1.Faces[index]
            if(applyDiffuse):
                #say(color_vector[indexColor])
                meshes.append(shapeToMesh(singleFace, color_vector[indexColor], transparency[i], scale))
            else:
                #say(single_color[0])
                meshes.append(shapeToMesh(singleFace, single_color[0], transparency[i], scale))
            indexColor=indexColor+1
            #meshes.append(shapeToMesh(face, Diffuse_color[i], transparency[i], scale))
        color_vector=[]
        indexColor=0;
        i=i+1            
    exportVRML(meshes, filename)
    return
###

def go_export():
    sel = FreeCADGui.Selection.getSelection()
    if not sel:
        FreeCAD.Console.PrintWarning("Select something first!\n\n")
        msg="export VRML from FreeCAD is a python macro that will export simplified VRML of "
        msg+="a (multi)selected Part or fused Part to VRML optimized to Kicad and compatible with Blender "
        msg+="the size of VRML is much smaller compared to the one exported from FC Gui "
        msg+="and the loading/rendering time is also smaller\n"
        msg+="change mesh deviation to increase quality of VRML"
        say(msg)
    else:
        objs = []
        for obj in sel:
                objs.append(obj)
                #say(obj.Label)
                #say(obj.Name)
        say(fullFilePathName)
        #say(objs)
        export(objs, fullFilePathName, scale=None)
        export(objs, fullFilePathName, 0.3937)
    
doc = FreeCAD.ActiveDocument
if doc!=None:
    fullFilePathName=doc.FileName
    if fullFilePathName=="":
        home = expanduser("~")
        fullFilePathName=home+os.sep+doc.Label+'.FCStd'
        say('path not found, saving to '+fullFilePathName)
        #say(fullFilePathName)
    else:
        say(fullFilePathName)
    go_export()