Using the API

Need help, or want to share a macro? Post here!
vocx
Posts: 2693
Joined: Thu Oct 18, 2018 9:18 pm

Re: Using the API

Postby vocx » Thu Dec 05, 2019 2:23 am

clel wrote:
Wed Dec 04, 2019 10:46 am
...
Is efficiency really such a big concern?
Well, one could strip the diagrams at first. But also uploading 5 GB like once a week should be ok imho. There might also be the ability to only upload the diff maybe with GitHub pages. That will probably drastically reduce the traffic.
By efficiency, I mean everything that is required. It is simple to upload something automatically to a remote SSH server or whatever, but as you correctly pointed out, it would be better to do it with diffs or something like that.

Also, space is limited, if we upload a version of the documentation every week, after 52 weeks we have 260 GB used in storage. It doesn't seem to be a lot, but we also have to consider traffic. How do we handle traffic? How do we handle if there is a problem with the compilation?
Assuming you do automated builds with Travis or Jenkins, that would probably rather easy? Although I have to admit that I am not very familiar with automated building.
Well, that's exactly what we should investigate.
I got the impression that Doxygen does not contain all Python classes. Also the documentation (comments) seem to be completely missing currently. Part.Shape() for example is not listed in Doxygen. As a first step I'd be happy to see those classes and comments integrated in Doxygen. Because currently I get the impression that while Doxygen might contain the C++ code, it mostly lacks the Python API available.
That's because, as I said previously, many Python classes are in fact generated from C++ sources. So the documentation of Part.Shape is actually in Part::TopoShape. This is the internal C++ class that is accessed on the Python side as Part.Shape. It's a bit confusing.

Which documentation (comments) are missing currently? Most documentation is in header files (.h), which is extracted by Doxygen and converted into documentation. On the Python side, if the .py files don't have the right docstrings """inside triple quotes""" these strings will not be picked up by Doxygen. Some Python files have incorrect docstrings or have no docstrings at all. These are problems which need to be solved by the developers, but which interested users can help with.
To support the documentation effort, and code development, your donation is appreciated: paypal.
User avatar
clel
Posts: 33
Joined: Mon Jun 13, 2016 10:30 am

Re: Using the API

Postby clel » Thu Dec 05, 2019 11:26 am

vocx wrote:
Thu Dec 05, 2019 2:23 am
clel wrote:
Wed Dec 04, 2019 10:46 am
...
Is efficiency really such a big concern?
Well, one could strip the diagrams at first. But also uploading 5 GB like once a week should be ok imho. There might also be the ability to only upload the diff maybe with GitHub pages. That will probably drastically reduce the traffic.
By efficiency, I mean everything that is required. It is simple to upload something automatically to a remote SSH server or whatever, but as you correctly pointed out, it would be better to do it with diffs or something like that.
Better, yes. But maybe not needed in the first place.
Also, space is limited, if we upload a version of the documentation every week, after 52 weeks we have 260 GB used in storage. It doesn't seem to be a lot, but we also have to consider traffic. How do we handle traffic? How do we handle if there is a problem with the compilation?
Valid point, thus it is probably wise to delete older versions and only keep the most current one plus versions for older FreeCAD releases.
Assuming you do automated builds with Travis or Jenkins, that would probably rather easy? Although I have to admit that I am not very familiar with automated building.
Well, that's exactly what we should investigate.
I got the impression that Doxygen does not contain all Python classes. Also the documentation (comments) seem to be completely missing currently. Part.Shape() for example is not listed in Doxygen. As a first step I'd be happy to see those classes and comments integrated in Doxygen. Because currently I get the impression that while Doxygen might contain the C++ code, it mostly lacks the Python API available.
That's because, as I said previously, many Python classes are in fact generated from C++ sources. So the documentation of Part.Shape is actually in Part::TopoShape. This is the internal C++ class that is accessed on the Python side as Part.Shape. It's a bit confusing.
Then I misunderstood it when I read that. It is rather frustrating not to have any documentation available online for those generated Python classes. I think it is important to have it, since it is needed for Python scripting. There is no way that I know to easily find out the corresponding C++ classes.
Which documentation (comments) are missing currently? Most documentation is in header files (.h), which is extracted by Doxygen and converted into documentation. On the Python side, if the .py files don't have the right docstrings """inside triple quotes""" these strings will not be picked up by Doxygen. Some Python files have incorrect docstrings or have no docstrings at all. These are problems which need to be solved by the developers, but which interested users can help with.
If we take Part::TopoShape as an example (https://www.freecadweb.org/api/d8/ded/c ... 2a73c67f6f): The read method that is linked is not documented at all to my impression. Also it is missing the tesselate() function which is accesible through Python with Part.Shape().tesselate(). This makes me wonder, where the tesselate() function comes from.
vocx
Posts: 2693
Joined: Thu Oct 18, 2018 9:18 pm

Re: Using the API

Postby vocx » Thu Dec 05, 2019 8:00 pm

clel wrote:
Thu Dec 05, 2019 11:26 am
...
Then I misunderstood it when I read that. It is rather frustrating not to have any documentation available online for those generated Python classes. I think it is important to have it, since it is needed for Python scripting. There is no way that I know to easily find out the corresponding C++ classes.
Correct. It is certainly not intuitive at the beginning. If you are just a user, you most probably won't need to know internal details like these because you only use the graphical interface. Once you want to write macros and workbenches, then you become a power user, and start to understand more how FreeCAD is built. In general, most power users and developers start by copying the code they see in other workbenches and macros, and build from there.
If we take Part::TopoShape as an example (https://www.freecadweb.org/api/d8/ded/c ... 2a73c67f6f): The read method that is linked is not documented at all to my impression.
The read function indeed doesn't have much documentation; it seems it doesn't need much because it takes a single argument which is just a string (filename path).

In the source code, you can see that the documentation block is only at the beginning. There are no details for each function.

https://github.com/FreeCAD/FreeCAD/blob ... #L173-L191

Code: Select all

    /** @name Input/Output */
    //@{
    void read(const char *FileName);
    void write(const char *FileName) const;
    void dump(std::ostream& out) const;
    void importIges(const char *FileName);
    void importStep(const char *FileName);
    void importBrep(const char *FileName);
    void importBrep(std::istream&, int indicator=1);
    void importBinary(std::istream&);
    void exportIges(const char *FileName) const;
    void exportStep(const char *FileName) const;
    void exportBrep(const char *FileName) const;
    void exportBrep(std::ostream&) const;
    void exportBinary(std::ostream&);
    void exportStl (const char *FileName, double deflection) const;
    void exportFaceSet(double, double, const std::vector<App::Color>&, std::ostream&) const;
    void exportLineSet(std::ostream&) const;
    //@}
If you'd like to improve this, you'd need to write the appropriate documentation blocks like this.

Code: Select all

    /** Read an input file; the file can be a step file, or a ...*/
    void read(const char *FileName);
    /** Write the shape into the file, resulting in a new step file...*/
    void write(const char *FileName) const;
    ...
And so on. You'd need to add the documentation to the header files, and make sure that what you write is correct according to the implementation in the corresponding .cpp file.
Also it is missing the tesselate() function which is accesible through Python with Part.Shape().tesselate(). This makes me wonder, where the tesselate() function comes from.
The tessellate method is one of those defined in the Python wrapper, so in TopoShapePy.xml, and implemented in TopoShapePyImp.cpp.

https://github.com/FreeCAD/FreeCAD/blob ... #L568-L572

Code: Select all

    <Methode Name="tessellate" Const="true">
      <Documentation>
        <UserDocu>Tessellate the shape and return a list of vertices and face indices</UserDocu>
      </Documentation>
    </Methode>
https://github.com/FreeCAD/FreeCAD/blob ... 1907-L1942

Code: Select all

PyObject* TopoShapePy::tessellate(PyObject *args)
{
    try {
        float tolerance;
        PyObject* ok = Py_False;
        if (!PyArg_ParseTuple(args, "f|O!",&tolerance,&PyBool_Type,&ok))
            return 0;
        std::vector<Base::Vector3d> Points;
        std::vector<Data::ComplexGeoData::Facet> Facets;
        if (PyObject_IsTrue(ok))
            BRepTools::Clean(getTopoShapePtr()->getShape());
        getTopoShapePtr()->getFaces(Points, Facets,tolerance);
        Py::Tuple tuple(2);
        Py::List vertex;
        for (std::vector<Base::Vector3d>::const_iterator it = Points.begin();
            it != Points.end(); ++it)
            vertex.append(Py::asObject(new Base::VectorPy(*it)));
        tuple.setItem(0, vertex);
        Py::List facet;
        for (std::vector<Data::ComplexGeoData::Facet>::const_iterator
            it = Facets.begin(); it != Facets.end(); ++it) {
            Py::Tuple f(3);
            f.setItem(0,Py::Long((long)it->I1));
            f.setItem(1,Py::Long((long)it->I2));
            f.setItem(2,Py::Long((long)it->I3));
            facet.append(f);
        }
        tuple.setItem(1, facet);
        return Py::new_reference_to(tuple);
    }
    catch (Standard_Failure& e) {
        PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
        return NULL;
    }
}
To support the documentation effort, and code development, your donation is appreciated: paypal.
User avatar
clel
Posts: 33
Joined: Mon Jun 13, 2016 10:30 am

Re: Using the API

Postby clel » Fri Dec 06, 2019 10:47 am

vocx wrote:
Thu Dec 05, 2019 8:00 pm
clel wrote:
Thu Dec 05, 2019 11:26 am
...
Then I misunderstood it when I read that. It is rather frustrating not to have any documentation available online for those generated Python classes. I think it is important to have it, since it is needed for Python scripting. There is no way that I know to easily find out the corresponding C++ classes.
Correct. It is certainly not intuitive at the beginning. If you are just a user, you most probably won't need to know internal details like these because you only use the graphical interface. Once you want to write macros and workbenches, then you become a power user, and start to understand more how FreeCAD is built. In general, most power users and developers start by copying the code they see in other workbenches and macros, and build from there.
The problem of simply copying stuff is that there is often no documentation what a certain function actually does and what the arguments are for. Also there is a high chance that the copied function is not the best way to do a task. I have at least one example of code here in the forum that is not ideal, where at least nowadays better, easier and more robust functions exist to achieve a task. Thus I find it crucial to have the code documented in order to be able to check the quality of pasted code.
If we take Part::TopoShape as an example (https://www.freecadweb.org/api/d8/ded/c ... 2a73c67f6f): The read method that is linked is not documented at all to my impression.
The read function indeed doesn't have much documentation; it seems it doesn't need much because it takes a single argument which is just a string (filename path).
Well, I think it is not even documented that the argument is the path? Also it is not documented what the function actually does (does it open the file at the given path? does it set the document to active? etc.)
In the source code, you can see that the documentation block is only at the beginning. There are no details for each function.

https://github.com/FreeCAD/FreeCAD/blob ... #L173-L191

Code: Select all

    /** @name Input/Output */
    //@{
    void read(const char *FileName);
    void write(const char *FileName) const;
    void dump(std::ostream& out) const;
    void importIges(const char *FileName);
    void importStep(const char *FileName);
    void importBrep(const char *FileName);
    void importBrep(std::istream&, int indicator=1);
    void importBinary(std::istream&);
    void exportIges(const char *FileName) const;
    void exportStep(const char *FileName) const;
    void exportBrep(const char *FileName) const;
    void exportBrep(std::ostream&) const;
    void exportBinary(std::ostream&);
    void exportStl (const char *FileName, double deflection) const;
    void exportFaceSet(double, double, const std::vector<App::Color>&, std::ostream&) const;
    void exportLineSet(std::ostream&) const;
    //@}
If you'd like to improve this, you'd need to write the appropriate documentation blocks like this.

Code: Select all

    /** Read an input file; the file can be a step file, or a ...*/
    void read(const char *FileName);
    /** Write the shape into the file, resulting in a new step file...*/
    void write(const char *FileName) const;
    ...
And so on. You'd need to add the documentation to the header files, and make sure that what you write is correct according to the implementation in the corresponding .cpp file.
Also it is missing the tesselate() function which is accesible through Python with Part.Shape().tesselate(). This makes me wonder, where the tesselate() function comes from.
The tessellate method is one of those defined in the Python wrapper, so in TopoShapePy.xml, and implemented in TopoShapePyImp.cpp.
Ah, found the problem. Above, you said the wrapper used Part::TopoShape, but you apparently meant Part::TopoShapePy. This one has the tesselate function.

https://github.com/FreeCAD/FreeCAD/blob ... #L568-L572

Code: Select all

    <Methode Name="tessellate" Const="true">
      <Documentation>
        <UserDocu>Tessellate the shape and return a list of vertices and face indices</UserDocu>
      </Documentation>
    </Methode>
https://github.com/FreeCAD/FreeCAD/blob ... 1907-L1942

Code: Select all

PyObject* TopoShapePy::tessellate(PyObject *args)
{
    try {
        float tolerance;
        PyObject* ok = Py_False;
        if (!PyArg_ParseTuple(args, "f|O!",&tolerance,&PyBool_Type,&ok))
            return 0;
        std::vector<Base::Vector3d> Points;
        std::vector<Data::ComplexGeoData::Facet> Facets;
        if (PyObject_IsTrue(ok))
            BRepTools::Clean(getTopoShapePtr()->getShape());
        getTopoShapePtr()->getFaces(Points, Facets,tolerance);
        Py::Tuple tuple(2);
        Py::List vertex;
        for (std::vector<Base::Vector3d>::const_iterator it = Points.begin();
            it != Points.end(); ++it)
            vertex.append(Py::asObject(new Base::VectorPy(*it)));
        tuple.setItem(0, vertex);
        Py::List facet;
        for (std::vector<Data::ComplexGeoData::Facet>::const_iterator
            it = Facets.begin(); it != Facets.end(); ++it) {
            Py::Tuple f(3);
            f.setItem(0,Py::Long((long)it->I1));
            f.setItem(1,Py::Long((long)it->I2));
            f.setItem(2,Py::Long((long)it->I3));
            facet.append(f);
        }
        tuple.setItem(1, facet);
        return Py::new_reference_to(tuple);
    }
    catch (Standard_Failure& e) {
        PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
        return NULL;
    }
}
The Python documentation generated from the FreeCAD App is much better, for example the class Shape:

Code: Select all

class Shape(Data.ComplexGeoData)
    	TopoShape is the OpenCasCade topological shape wrapper.
Sub-elements such as vertices, edges or faces are accessible as:
* Vertex#, where # is in range(1, number of vertices)
* Edge#, where # is in range(1, number of edges)
* Face#, where # is in range(1, number of faces)
 
  	

Method resolution order:
    Shape
    Data.ComplexGeoData
    Base.Persistence
    Base.BaseClass
    builtins.PyObjectBase
    builtins.object

Methods defined here:

__delattr__(self, name, /)
    Implement delattr(self, name).

__getattribute__(self, name, /)
    Return getattr(self, name).

__getstate__(...)
    Serialize the content of this shape to a string in BREP format.

__init__(self, /, *args, **kwargs)
    Initialize self.  See help(type(self)) for accurate signature.

__new__(*args, **kwargs) from builtins.type
    Create and return a new object.  See help(type) for accurate signature.

__repr__(self, /)
    Return repr(self).

__setattr__(self, name, value, /)
    Implement setattr(self, name, value).

__setstate__(...)
    Deserialize the content of this shape from a string in BREP format.

ancestorsOfType(...)
    ancestorsOfType(shape, shape type) -> list
    For a sub-shape of this shape get its ancestors of a type.

check(...)
    Checks the shape and report errors in the shape structure.
    This is a more detailed check as done in isValid().
    myShape.check(runBopCheck = False)
    if runBopCheck is True, a BOPCheck analysis is also performed.

childShapes(...)
    childShapes([cumOri=True, cumLoc=True]) -> list
    Return a list of sub-shapes that are direct children of this shape.
     * If cumOri is true, the function composes all
       sub-shapes with the orientation of this shape.
     * If cumLoc is true, the function multiplies all
       sub-shapes by the location of this shape, i.e. it applies to
       each sub-shape the transformation that is associated with this shape.

cleaned(...)
    This creates a cleaned copy of the shape with the triangulation removed.
    This can be useful to reduce file size when exporting as a BREP file.
    Warning: Use the cleaned shape with care because certain algorithms may work incorrectly
    if the shape has no internal triangulation any more.

common(...)
    Intersection of this and a given (list of) topo shape.
    common(tool) -> Shape
      or
    common((tool1,tool2,...),[tolerance=0.0]) -> Shape
     
    Intersection of this and a given list of topo shapes.
     
    Supports:
    - Fuzzy Boolean operations (global tolerance for a Boolean operation)
    - Support of multiple arguments for a single Boolean operation (s1 AND (s2 OR s3))
    - Parallelization of Boolean Operations algorithm
     
    OCC 6.9.0 or later is required.

complement(...)
    Computes the complement of the orientation of this shape,
    i.e. reverses the interior/exterior status of boundaries of this shape.

copy(...)
    Create a copy of this shape
    copy(copyGeom=True, copyMesh=False) -> Shape
    If copyMesh is True, triangulation contained in original shape will be
    copied along with geometry.
    If copyGeom is False, only topological objects will be copied, while
    geometry and triangulation will be shared with original shape.

cut(...)
    Difference of this and a given (list of) topo shape
    cut(tool) -> Shape
      or
    cut((tool1,tool2,...),[tolerance=0.0]) -> Shape
     
    Substraction of this and a given list of topo shapes.
     
    Supports:
    - Fuzzy Boolean operations (global tolerance for a Boolean operation)
    - Support of multiple arguments for a single Boolean operation
    - Parallelization of Boolean Operations algorithm
     
    OCC 6.9.0 or later is required.

defeaturing(...)
    Remove a feature defined by supplied faces and return a new shape.
    The parameter is a list of faces.

distToShape(...)
    Find the minimum distance to another shape.
    distToShape(Shape s):  Returns a list of minimum distance and solution point pairs.
     
    Returned is a tuple of three: (dist, vectors, infos).
     
    dist is the minimum distance, in mm (float value).
     
    vectors is a list of pairs of App.Vector. Each pair corresponds to solution.
    Example: [(Vector (2.0, -1.0, 2.0), Vector (2.0, 0.0, 2.0)), (Vector (2.0,
    -1.0, 2.0), Vector (2.0, -1.0, 3.0))] First vector is a point on self, second
    vector is a point on s.
     
    infos contains additional info on the solutions. It is a list of tuples:
    (topo1, index1, params1, topo2, index2, params2)
     
        topo1, topo2 are strings identifying type of BREP element: 'Vertex',
        'Edge', or 'Face'.
     
        index1, index2 are indexes of the elements (zero-based).
     
        params1, params2 are parameters of internal space of the elements. For
        vertices, params is None. For edges, params is one float, u. For faces,
        params is a tuple (u,v).

dumpToString(...)
    Dump information about the shape to a string.

exportBinary(...)
    Export the content of this shape in binary format to a file.

exportBrep(...)
    Export the content of this shape to an BREP file. BREP is a CasCade native format.

exportBrepToString(...)
    Export the content of this shape to a string in BREP format. BREP is a CasCade native format.

exportIges(...)
    Export the content of this shape to an IGES file.

exportStep(...)
    Export the content of this shape to an STEP file.

exportStl(...)
    Export the content of this shape to an STL mesh file.

extrude(...)
    Extrude the shape along a direction.

fix(...)
    Tries to fix a broken shape. True is returned if the operation succeeded, False otherwise.
    fix(working precision, minimum precision, maximum precision)

fixTolerance(...)
    fixTolerance(value, ShapeType=Shape)
     
    Sets (enforces) tolerances in a shape to the given value
    ShapeType = Vertex : only vertices are set
    ShapeType = Edge   : only edges are set
    ShapeType = Face   : only faces are set
    ShapeType = Wire   : to have edges and their vertices set
    ShapeType = other value : all (vertices,edges,faces) are set

fuse(...)
    Union of this and a given (list of) topo shape.
    fuse(tool) -> Shape
      or
    fuse((tool1,tool2,...),[tolerance=0.0]) -> Shape
     
    Union of this and a given list of topo shapes.
     
    Supports (OCCT 6.9.0 and above):
    - Fuzzy Boolean operations (global tolerance for a Boolean operation)
    - Support of multiple arguments for a single Boolean operation
    - Parallelization of Boolean Operations algorithm
     
    Beginning from OCCT 6.8.1 a tolerance value can be specified.

generalFuse(...)
    generalFuse(list_of_other_shapes, fuzzy_value = 0.0): Run general fuse algorithm (GFA) between this and given shapes.
     
    list_of_other_shapes: shapes to run the algorithm against (the list is
    effectively prepended by 'self').
     
    fuzzy_value: extra tolerance to apply when searching for interferences, in
    addition to tolerances of the input shapes.
     
    Returns a tuple of 2: (result, map).
     
    result is a compound containing all the pieces generated by the algorithm
    (e.g., for two spheres, the pieces are three touching solids). Pieces that
    touch share elements.
     
    map is a list of lists of shapes, providing the info on which children of
    result came from which argument. The length of list is equal to length of
    list_of_other_shapes + 1. First element is a list of pieces that came from
    shape of this, and the rest are those that come from corresponding shapes in
    list_of_other_shapes.
    hint: use isSame method to test shape equality
     
    Parallelization of Boolean Operations algorithm
     
    OCC 6.9.0 or later is required.

getElement(...)
    Returns a SubElement

getTolerance(...)
    getTolerance(mode, ShapeType=Shape) -> float
     
    Determines a tolerance from the ones stored in a shape
    mode = 0 : returns the average value between sub-shapes,
    mode > 0 : returns the maximal found,
    mode < 0 : returns the minimal found.
    ShapeType defines what kinds of sub-shapes to consider:
    Shape (default) : all : Vertex, Edge, Face,
    Vertex : only vertices,
    Edge   : only edges,
    Face   : only faces,
    Shell  : combined Shell + Face, for each face (and containing
             shell), also checks edge and Vertex

globalTolerance(...)
    globalTolerance(mode) -> float
     
    Returns the computed tolerance according to the mode
    mode = 0 : average
    mode > 0 : maximal
    mode < 0 : minimal

hashCode(...)
    This value is computed from the value of the underlying shape reference and the location.
    Orientation is not taken into account.

importBinary(...)
    Import the content to this shape of a string in BREP format.

importBrep(...)
    Load the shape from a file in BREP format.

importBrepFromString(...)
    Load the shape from a string that keeps the content in BREP format.
    importBrepFromString(str,False) to not display a progress bar.

inTolerance(...)
    inTolerance(value, ShapeType=Shape) -> float
     
    Determines which shapes have a tolerance within a given interval
    ShapeType is interpreted as in the method getTolerance

isClosed(...)
    Checks if the shape is closed
    If the shape is a shell it returns True if it has no free boundaries (edges).
    If the shape is a wire it returns True if it has no free ends (vertices).
    (Internal and External sub-shepes are ignored in these checks)
    If the shape is an edge it returns True if its vertices are the same.

isEqual(...)
    Checks if both shapes are equal.
    This means geometry, placement and orientation are equal.

isInside(...)
    Checks whether a point is inside or outside the shape.
    isInside(App.Vector, float, Boolean) => Boolean
    The App.Vector is the point you want to check if it's inside or not
    float gives the tolerance
    Boolean indicates if the point lying directly on a face is considered to be inside or not

isNull(...)
    Checks if the shape is null.

isPartner(...)
    Checks if both shapes share the same geometry.
    Placement and orientation may differ.

isSame(...)
    Checks if both shapes share the same geometry
    and placement. Orientation may differ.

isValid(...)
    Checks if the shape is valid, i.e. neither null, nor empty nor corrupted.

limitTolerance(...)
    limitTolerance(tmin, tmax=0, ShapeType=Shape)
     
    Limits tolerances in a shape as follows :
    tmin = tmax -> as fixTolerance (forces)
    tmin = 0   -> maximum tolerance will be tmax
    tmax = 0 or not given (more generally, tmax < tmin) ->
    tmax ignored, minimum will be tmin
    else, maximum will be max and minimum will be min
    ShapeType = Vertex : only vertices are set
    ShapeType = Edge   : only edges are set
    ShapeType = Face   : only faces are set
    ShapeType = Wire   : to have edges and their vertices set
    ShapeType = other value : all (vertices,edges,faces) are set
    Returns True if at least one tolerance of the sub-shape has
    been modified

makeChamfer(...)
    Make chamfer.

makeFillet(...)
    Make fillet.

makeOffset2D(...)
    makeOffset2D(offset, join = 0, fill = False, openResult = false, intersection =
    false): makes an offset shape (2d offsetting). The function supports keyword
    arguments. Input shape (self) can be edge, wire, face, or a compound of those.
     
    * offset: distance to expand the shape by. Negative value will shrink the
    shape.
     
    * join: method of offsetting non-tangent joints. 0 = arcs, 1 = tangent, 2 =
    intersection
     
    * fill: if true, the output is a face filling the space covered by offset. If
    false, the output is a wire.
     
    * openResult: affects the way open wires are processed. If False, an open wire
    is made. If True, a closed wire is made from a double-sided offset, with rounds
    around open vertices.
     
    * intersection: affects the way compounds are processed. If False, all children
    are offset independently. If True, and children are edges/wires, the children
    are offset in a collective manner. If compounding is nested, collectiveness
    does not spread across compounds (only direct children of a compound are taken
    collectively).
     
    Returns: result of offsetting (wire or face or compound of those). Compounding
    structure follows that of source shape.

makeOffsetShape(...)
    makeOffsetShape(offset, tolerance, inter = False, self_inter = False,
    offsetMode = 0, join = 0, fill = False): makes an offset shape (3d offsetting).
    The function supports keyword arguments.
     
    * offset: distance to expand the shape by. Negative value will shrink the
    shape.
     
    * tolerance: precision of approximation.
     
    * inter: (parameter to OCC routine; not implemented)
     
    * self_inter: (parameter to OCC routine; not implemented)
     
    * offsetMode: 0 = skin; 1 = pipe; 2 = recto-verso
     
    * join: method of offsetting non-tangent joints. 0 = arcs, 1 = tangent, 2 =
    intersection
     
    * fill: if true, offsetting a shell is to yield a solid
     
    Returns: result of offsetting.

makeParallelProjection(...)
    Parallel projection of an edge or wire on this shape
    makeParallelProjection(shape, dir)

makePerspectiveProjection(...)
    Perspective projection of an edge or wire on this shape
    makePerspectiveProjection(shape, pnt)

makeShapeFromMesh(...)
    Make a compound shape out of mesh data.
    Note: This should be used for rather small meshes only.

makeThickness(...)
    makeThickness(List of shapes, Offset (Float), Tolerance (Float)) -> Shape
    A hollowed solid is built from an initial solid and a set of faces on this solid,
    which are to be removed. The remaining faces of the solid become the walls of
    the hollowed solid, their thickness defined at the time of construction.

mirror(...)
    Mirror this shape on a given plane.
    The plane is given with its base point and its normal direction.

multiFuse(...)
    multiFuse((tool1,tool2,...),[tolerance=0.0]) -> Shape
     
    Union of this and a given list of topo shapes.
     
    Supports (OCCT 6.9.0 and above):
    - Fuzzy Boolean operations (global tolerance for a Boolean operation)
    - Support of multiple arguments for a single Boolean operation
    - Parallelization of Boolean Operations algorithm
     
    Beginning from OCCT 6.8.1 a tolerance value can be specified.
    Deprecated: use fuse() instead.

nullify(...)
    Destroys the reference to the underlying shape stored in this shape.
    As a result, this shape becomes null.

oldFuse(...)
    Union of this and a given topo shape (old algorithm).

optimalBoundingBox(...)
    optimalBoundingBox(useTriangulation = True, useShapeTolerance = False) -> bound box

overTolerance(...)
    overTolerance(value, ShapeType=Shape) -> float
     
    Determines which shapes have a tolerance over the given value
    ShapeType is interpreted as in the method getTolerance

project(...)
    Project a list of shapes on this shape

proximity(...)
    proximity(Shape s): Returns two lists of Face indexes for the Faces involved in the intersection.

read(...)
    Read in an IGES, STEP or BREP file.

reflectLines(...)
    Build reflect lines on a shape according to the axes of view.
    Reflect lines are represented by edges in 3d.
    reflectLines(ViewDir, ViewPos, UpDir) -> Shape

removeInternalWires(...)
    Removes internal wires (also holes) from the shape.

removeShape(...)
    Remove a sub-shape and return a new shape.
    The parameter is a list of shapes.

removeSplitter(...)
    Removes redundant edges from the B-REP model

replaceShape(...)
    Replace a sub-shape with a new shape and return a new shape.
    The parameter is in the form list of tuples with the two shapes.

reverse(...)
    Reverses the orientation of this shape.

revolve(...)
    Revolve the shape around an Axis to a given degree.
    Part.revolve(Vector(0,0,0),Vector(0,0,1),360) - revolves the shape around the Z Axis 360 degree.
     
    Hints: Sometimes you want to create a rotation body out of a closed edge or wire.
    Example:
    from FreeCAD import Base
    import Part
    V=Base.Vector
     
    e=Part.Ellipse()
    s=e.toShape()
    r=s.revolve(V(0,0,0),V(0,1,0), 360)
    Part.show(r)
     
    However, you may possibly realize some rendering artifacts or that the mesh
    creation seems to hang. This is because this way the surface is created twice.
    Since the curve is a full ellipse it is sufficient to do a rotation of 180 degree
    only, i.e. r=s.revolve(V(0,0,0),V(0,1,0), 180)
     
    Now when rendering this object you may still see some artifacts at the poles. Now the
    problem seems to be that the meshing algorithm doesn't like to rotate around a point
    where there is no vertex.
     
    The idea to fix this issue is that you create only half of the ellipse so that its shape
    representation has vertexes at its start and end point.
     
    from FreeCAD import Base
    import Part
    V=Base.Vector
     
    e=Part.Ellipse()
    s=e.toShape(e.LastParameter/4,3*e.LastParameter/4)
    r=s.revolve(V(0,0,0),V(0,1,0), 360)
    Part.show(r)

rotate(...)
    Apply the rotation (degree) to the current location of this shape
    Shp.rotate(Vector(0,0,0),Vector(0,0,1),180) - rotate the shape around the Z Axis 180 degrees.

scale(...)
    Apply scaling with point and factor to this shape.

section(...)
    Section of this with a given (list of) topo shape.
    section(tool,[approximation=False]) -> Shape
      or
    section((tool1,tool2,...),[tolerance=0.0, approximation=False]) -> Shape
     
    If approximation is True, section edges are approximated to a C1-continuous BSpline curve.
     
    Section of this and a given list of topo shapes.
     
    Supports:
    - Fuzzy Boolean operations (global tolerance for a Boolean operation)
    - Support of multiple arguments for a single Boolean operation (s1 AND (s2 OR s3))
    - Parallelization of Boolean Operations algorithm
     
    OCC 6.9.0 or later is required.

sewShape(...)
    Sew the shape if there is a gap.

slice(...)
    Make single slice of this shape.

slices(...)
    Make slices of this shape.

tessellate(...)
    Tessellate the shape and return a list of vertices and face indices

toNurbs(...)
    Conversion of the complete geometry of a shape into NURBS geometry.
    For example, all curves supporting edges of the basis shape are converted
    into B-spline curves, and all surfaces supporting its faces are converted
    into B-spline surfaces.

transformGeometry(...)
    Apply geometric transformation on this or a copy the shape.
    This method returns a new shape.
    The transformation to be applied is defined as a 4x4 matrix.
    The underlying geometry of the following shapes may change:
    - a curve which supports an edge of the shape, or
    - a surface which supports a face of the shape;
     
    For example, a circle may be transformed into an ellipse when
    applying an affinity transformation. It may also happen that
    the circle then is represented as a B-spline curve.
     
    The transformation is applied to:
    - all the curves which support edges of the shape, and
    - all the surfaces which support faces of the shape.
     
    Note: If you want to transform a shape without changing the
    underlying geometry then use the methods translate or rotate.
     
    transformGeometry(Matrix) -> Shape

transformShape(...)
    Apply transformation on a shape without changing
    the underlying geometry.
    transformShape(Matrix,[boolean copy=False]) -> None

translate(...)
    Apply the translation to the current location of this shape.

writeInventor(...)
    Write the mesh in OpenInventor format to a string.

Data descriptors defined here:

Area
    Total area of the faces of the shape.

CompSolids
    List of subsequent shapes in this shape.

Compounds
    List of compounds in this shape.

Edges
    List of Edges in this shape.

Faces
    List of faces in this shape.

Length
    Total length of the edges of the shape.

Orientation
    Returns the orientation of the shape.

ShapeType
    Returns the type of the shape.

Shells
    List of subsequent shapes in this shape.

Solids
    List of subsequent shapes in this shape.

Vertexes
    List of vertexes in this shape.

Volume
    Total volume of the solids of the shape.

Wires
    List of wires in this shape.

Methods inherited from Data.ComplexGeoData:

getFacesFromSubelement(...)
    Return vertexes and faces from a sub-element

Data descriptors inherited from Data.ComplexGeoData:

BoundBox
    Get the BoundBox of the object

Matrix
    Get the current transformation of the object as matrix

Placement
    Get the current transformation of the object as placement

Methods inherited from Base.Persistence:

dumpContent(...)
    Dumps the content of the object, both the XML representation as well as the additional datafiles  
    required, into a byte representation. It will be returned as byte array.
    dumpContent() -- returns a byte array with full content
    dumpContent(Compression=1-9) -- Sets the data compression from 0 (no) to 9 (max)

restoreContent(...)
    Restore the content of the object from a byte representation as stored by "dumpContent".
    It could be restored from any python object implementing the buffer protocol.
    restoreContent(buffer) -- restores from the given byte array

Data descriptors inherited from Base.Persistence:

Content
    Content of the object in XML representation

MemSize
    Memory size of the object in byte

Methods inherited from Base.BaseClass:

getAllDerivedFrom(...)
    Returns all descendants

isDerivedFrom(...)
    Returns true if given type is a father

Data descriptors inherited from Base.BaseClass:

Module
    Module in which this class is defined

TypeId
    Is the type of the FreeCAD object with module domain
So most of the documentation seems to be already there, but that is not displayed in the FreeCAD API from Doxygen. Since relying on Python for scripting, I think it is more important to have the Python classes documented somewhere. The C++ classes are also good to have, but currently it seems, the complete Python documentation is lacking from Doxygen, correct?
vocx
Posts: 2693
Joined: Thu Oct 18, 2018 9:18 pm

Re: Using the API

Postby vocx » Fri Dec 06, 2019 5:32 pm

clel wrote:
Fri Dec 06, 2019 10:47 am
...
... the complete Python documentation is lacking from Doxygen, correct?
Workbenches that are made in Python, that is, that have actual Python files are documented, but the level documentation depends on the docstrings. For example, Draft has many docstrings so it does have reasonably good documentation. Same FEM, Path, Arch, and others.
To support the documentation effort, and code development, your donation is appreciated: paypal.
User avatar
clel
Posts: 33
Joined: Mon Jun 13, 2016 10:30 am

Re: Using the API

Postby clel » Wed Dec 18, 2019 3:25 pm

The problem is probably that this is not what I meant with Python documentation. But good to know that it is not lacking entirely. However it seems that all inherited classes from C classes are not there unfortunately, while I showed you that the documentation itself is present at a different place. So ideally there would be a way to integrate that documentation into Doxygen or another system that aims to have a complete documentation available online.