Skip to content

Instantly share code, notes, and snippets.

@CsatiZoltan
Created September 2, 2021 08:35
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save CsatiZoltan/f4fd10bf20923143ba0e0678ea1d3d61 to your computer and use it in GitHub Desktop.
Save CsatiZoltan/f4fd10bf20923143ba0e0678ea1d3d61 to your computer and use it in GitHub Desktop.
Python interface for projection onto a surface in FreeCAD
class Projection:
"""Projection of a curve onto a surface.
This class implements parametric projection, i.e. whenever there is a change in the curve
to be projected, in the surface on which we project, or in direction of the projection,
the projection is redone automatically.
As a typical workflow:
1. The user gives either programmatically or via the GUI the curve and the surface as FreeCAD
document objects of type `Part.Feature`, moreover the direction of the projection as a
tuple/list of three numbers.
2. The user creates a new FreeCAD document object of type `Part::FeaturePython`, which will
serve as a container to hold the projected curve.
3. The user instantiates the :class:`Projection` class by passing the container, the curve,
the surface and the direction of the projection.
The rest is managed by this class. Specifically, whenever any of the three parameters change,
the new projected curve is automatically computed and is replotted on the screen when in GUI
mode.
If you are only interested in the projection functionality, use its :meth:`project`
method directly.
For the description of the projection, see the :meth:`project` method.
Parameters
----------
doc : FreeCAD.Document with TypeId of Part::FeaturePython
The document object that will contain this :class:`Projection` object. Such an object
can be created by :code:`FreeCAD.ActiveDocument.addObject('Part::FeaturePython', '...')`.
curve : Part.Feature
Curve that we project.
surface : Part.Feature
Surface we project onto.
direction : tuple of float
Direction of the projection.
Notes
-----
Projecting a curve onto a surface is available in the `Part` workbench of FreeCAD. However,
it has two shortcomings:
1. It cannot be fine-tuned without the GUI, as it is not exposed to Python.
2. The projection is not parametric.
This class solves both of these issues:
1. We rely on PythonOCC to use the underlying projection implemented in OpenCASCADE. The
PythonOCC object is then converted to a Part object, which can be used from within FreeCAD
as usual.
2. This class is a so-called scripted object, allowing a parametric workflow.
"""
def __init__(self, doc, curve, surface, direction):
if doc.TypeId != 'Part::FeaturePython':
raise TypeError('The document object must have TypeId of "Part::FeaturePython".')
if not isinstance(curve, Part.Feature):
raise TypeError('The curve must be a Part Feature object.')
if not isinstance(surface, Part.Feature):
raise TypeError('The surface must be a Part Feature object.')
doc.addProperty('App::PropertyLink', 'Curve', 'Parameters', 'Curve to project')
doc.addProperty('App::PropertyLink', 'Surface', 'Parameters', 'Surface to project onto')
doc.addProperty('App::PropertyDirection', 'Direction', 'Parameters',
'Direction of projection')
doc.Curve = curve
doc.Surface = surface
doc.Direction = direction
doc.Proxy = self
def execute(self, doc):
"""Recomputes the projection.
Parameters
----------
doc : FreeCAD.Document with TypeId of Part::FeaturePython
The document object that contains this :class:`Projection` object.
Returns
-------
None
"""
projection_direction = (doc.Direction.x, doc.Direction.y, doc.Direction.z)
projected_curve = self.project(doc.Curve.Shape, doc.Surface.Shape, projection_direction)
doc.Shape = projected_curve
doc.recompute()
@staticmethod
def project(curve, surface, direction):
"""Cylindrical projection of a curve onto a surface.
Parameters
----------
curve : Part.Wire
Curve to be projected.
surface : Part.Face
Surface to project onto.
direction : tuple of float
Direction vector of the projection, tuple of three numbers.
Returns
-------
Part.Compound
A compound object, containing the parts of the projected curve.
Raises
------
Exception
If the projection algorithm of OpenCASCADE fails. This typically happens if the
projected curve would not lie on the surface.
Notes
-----
This function is a wrapper around the cylindrical projection functionality available in
OpenCASCADE. For details, see its documentation:
https://dev.opencascade.org/doc/refman/html/class_b_rep_proj___projection.html
"""
curve = Part.__toPythonOCC__(curve)
surface = Part.__toPythonOCC__(surface)
projection_direction = gp_Dir(*direction)
proj = BRepProj_Projection(curve, surface, projection_direction)
if not proj.IsDone():
raise Exception('Projection failed.')
return Part.__fromPythonOCC__(proj.Shape())
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment