Exporting OBJ code

i know that the exportation to .obj is done by a python script. What I want to know is what is calling this script “importOBJ.py” with this function

def export(exportList,filename):
    "called when freecad exports a file"
    outfile = pythonopen(filename,"wb")
    ver = FreeCAD.Version()
    outfile.write("# FreeCAD v" + ver[0] + "." + ver[1] + " build" + ver[2] + " Arch module\n")
    outfile.write("# http://www.freecadweb.org\n")
    offset = 1
    for obj in exportList:
        if obj.isDerivedFrom("Part::Feature"):
            if obj.ViewObject.isVisible():
                vlist,elist,flist = getIndices(obj.Shape,offset)
                offset += len(vlist)
                outfile.write("o " + obj.Name + "\n")
                for v in vlist:
                    outfile.write("v" + v + "\n")
                for e in elist:
                    outfile.write("l" + e + "\n")
                for f in flist:
                    outfile.write("f" + f + "\n")
    outfile.close()
    FreeCAD.Console.PrintMessage(translate("Arch","successfully written ")+filename+"\n")

After a file of a type is imported, what happens to the data of that file? I do know that the module of importing a file is from OpenCascade but the exportation to OBJ is not. How and where is it converted before the exportation? “exportList” seems to be storing simple shapes with lists of the vertexes and faces. How and where are these lists put together?

Everything importet into freecad is stored in its internal data structures. If you import step the individual parts are stored each in a TopoShape object. Those data objects are than added to the document structure via document objects, in the case of step objects this are Part::Feature document objects. The TopoShape is added to the Part::Feature via its “Shape” proeprty. So after importing simply look at the tree, there is your data. How to access the data within the shape see http://www.freecadweb.org/wiki/index.php?title=Topological_data_scripting

“exportList” seems to be storing simple shapes with lists of the vertexes and faces. How and where are these lists put together?

That is wrong, as you can see from this line

if obj.isDerivedFrom("Part::Feature"):

The list stores document objects. This list is created by the export GUI, every selected document object is passed to this function. what to do with it is the functions own responsibility. In the script you postet it is checked if a Part::Feature document object is to be exportet, and if so it accesses the topological data via the Shape property:

obj.Shape

From there it has access to all the data it needs.

Thanks for the help. I have now found this

void TopoShape::exportStep(const char *filename) const
{
    try {
        // write step file
        STEPControl_Writer aWriter;

        Handle_Message_ProgressIndicator pi = new ProgressIndicator(100);
        aWriter.WS()->MapWriter()->SetProgress(pi);
        pi->NewScope(100, "Writing STEP file...");
        pi->Show();

        if (aWriter.Transfer(this->_Shape, STEPControl_AsIs) != IFSelect_RetDone) 
            throw Base::Exception("Error in transferring STEP");
		
        APIHeaderSection_MakeHeader makeHeader(aWriter.Model());
        makeHeader.SetName(new TCollection_HAsciiString((const Standard_CString)(encodeFilename(filename).c_str())));
        makeHeader.SetAuthorValue (1, new TCollection_HAsciiString("FreeCAD"));
        makeHeader.SetOrganizationValue (1, new TCollection_HAsciiString("FreeCAD"));
        makeHeader.SetOriginatingSystem(new TCollection_HAsciiString("FreeCAD"));
        makeHeader.SetDescriptionValue(1, new TCollection_HAsciiString("FreeCAD Model"));

        if (aWriter.Write(encodeFilename(filename).c_str()) != IFSelect_RetDone) 
            throw Base::Exception("Writing of STEP failed");
        pi->EndScope();
    }
    catch (Standard_Failure) {
        Handle(Standard_Failure) aFail = Standard_Failure::Caught();
        throw Base::Exception(aFail->GetMessageString());
    }
}

This is where the translation is made when exporting to STEP right?

 if (aWriter.Transfer(this->_Shape, STEPControl_AsIs) != IFSelect_RetDone)

is this _Shape stored inside a TopoShape the same as obj.Shape in the python script?
How can I access the data without Python scripts? Is it possibel to make a substitute for the python script with c++?

Sorry for all the newbie questions, I am very new to combining python scripts with “regular code”

is this _Shape stored inside a TopoShape the same as obj.Shape in the python script?

No, you mixing up things. “obj.Shape” is a property of a document object of type Part::PropertyShape. This property is used to store a TopoShape. A TopoShape is the freecad object holding all the geometry data. This TopoShape is the one returned from the python expression “obj.Shape”. Internally the toposhape keeps the geometry data by storing a open cascade topological data structure, which is namen _Shape. You can access the opencascade shape stored in a TopoShape from c++, but not directly from python.

How can I access the data without Python scripts? Is it possibel to make a substitute for the python script with c++?

You simpöly use the c++ types to access the document objects, properties and shapes. You can either add a new command to a workbench (spoosibly your own) or register a new export type where you use c++ code to export. this can also be done via a custom workbench. How to create a own workbench in c++ is best found out by studiying existing ones and copy how they do it.

You simpöly use the c++ types to access the document objects, properties and shapes.

And how do I do that? for instance the python script uses this function called “tesselate” to get the vertex- and facelists for exporting.

def getIndices(shape,offset):
    "returns a list with 2 lists: vertices and face indexes, offsetted with the given amount"
    vlist = []
    elist = []
    flist = []
    curves = None
    for e in shape.Edges:
        if not isinstance(e.Curve,Part.Line):
            if not curves:
                curves = shape.tessellate(1) #Returns projection with BSplines and Ellipses broken into line segments.
                FreeCAD.Console.PrintWarning(translate("Arch","Found a shape containing curves, triangulating\n"))
    if curves:
        for v in curves[0]:
            vlist.append(" "+str(round(v.x,p))+" "+str(round(v.y,p))+" "+str(round(v.z,p)))
        for f in curves[1]:
            fi = ""
            for vi in f:
                fi += " " + str(vi + offset)
            flist.append(fi)
    	.
    	.
    	.
    	.

Which is calling this function

PyObject * TopoShapePy::staticCallback_tessellate (PyObject *self, PyObject *args)
{
    // test if twin object not allready deleted
    if (!((PyObjectBase*) self)->isValid()){
        PyErr_SetString(PyExc_ReferenceError, "This object is already deleted most likely through closing a document. This reference is no longer valid!");
        return NULL;
    }


    try { // catches all exceptions coming up from c++ and generate a python exception
        PyObject* ret = ((TopoShapePy*)self)->tessellate(args);
        return ret;
    }
    catch(const Base::Exception& e) // catch the FreeCAD exceptions
    {
     .
     .
     .
     .
     
}

Do you mean I have to use these? or how do I know how to access the properties and shapes?

for instance the python script uses this function called “tesselate” to get the vertex- and facelists for exporting.

You use this function to get a tesselation of a the geometries hold by the edge or face. While the shape is a real geometry, a tesselation is a approximation by triangles and linesegment, it is a mesh. In FreeCAD Vertex and Face as well as Edge refere to topologies. Just for clarification and because the naming here may be a bit confusing.

Do you mean I have to use these? or how do I know how to access the properties and shapes?

No, thsoe functions are the bridge between python and c++, you do not need to use them. I don’t have a compiler here right now, but in general this should look like this, for example in your custom command’s activated() method (assuming you have a part object selected in the 3d view):

//get the selected object
std::vector<Gui::SelectionObject> selection = getSelection().getSelectionEx();
Part::Feature *obj = static_cast<Part::Feature*>(selection[0].getObject());

//we know that Part::Features have a Shape proertie, so just access it
const Part::TopoShape& TopShape = obj->Shape.getShape();

//access the tessellation. the function has a different name in c++
float tolerance;
std::vector<Base::Vector3d> Points;
std::vector<Data::ComplexGeoData::Facet> Facets;
TopShape->getFaces(Points, Facets, tolerance);

//we can also get subshapes, like edges or vertices. But note that this function returns a TopoDS_Shape, which is a occ object and not the same as the TopoShape
TopoDS_Shape sub =  TopShape.getSubShape("Edge2");

To see what can be done with the individual c++ objects you can study the source code, for example https://github.com/FreeCAD/FreeCAD/blob/master/src/Mod/Part/App/TopoShape.h or the online source documentation, even if it is a bit sparse: http://opencyclingcomputer.eu/FreeCAD/SourceDocu/html/index.html

thank you so much. I had some problem with “getSelection”, even though I dont want to go through selecting in 3d view. I managed to get it through the topoShape instead. It looks so simple now.. Now I just have to figure out how to get the material to obj!

Is it possible to get the different parts from this shape? Inside “TopoShape::importStep” the toposhapes _Shape is set to the STEPControl_Readers OneShape() which creates one big part from all small parts. But I need to differentiate those

use “getSubShape” for that

how do I know the subshapes names?

/// get the Topo"sub"Shape with the given name
    TopoDS_Shape getSubShape(const char* Type) const;

They are named consistent, always FaceXY, EdgeXY, VertexXY with XY being numbers from 1 to max. Of course this still implies you know how many subshapes there are. This method is most convinient for selection stuff. If you know nothing about the shape I would go with the openCascade API to access the subparts, see http://www.opencascade.com/doc/occt-6.9.0/refman/html/class_top_exp___explorer.html

these subshapes are for all the faces right? one subshape is one face and not a Part right? is it possible to get all the faces for one part only?

Please study the opencascade documentation to understand the data structures. There you find how to explore the data structures, and also that a shape can contain multiple solids, or compounds or compsolids. If you want subparts just iterate over those entities, and then iterate over the faces and edges and so on of the individual solids.