-
Notifications
You must be signed in to change notification settings - Fork 9
Programming documentation
Arrays of placements have shape, and the actual array is stored inside the shape.
The array's shape is a compound of shapes. The kind of shapes does not matter, but they must not be another compound (because Lattice automatically traverses nesting when reading out the placements).
Placements are stored to and extracted from compound children's Placement attributes. That is, to create a shape to be read out by Lattice:
- Prepare the shapes
- Set shapes' Placement properties
Part.makeCompound(shapes)
It was tested, that as of OCC 6.7.1, shells and solids don't lose placements even after saving-restoring a file. Vertexes, however, do lose placements.
This leads to constraints on the type of marker shapes that can be used. Marker can be any single thing: a line, an edge, a wire, a face, a shell, a solid, or a compsolid (and not Vertex, because those lose placements, and not compounds, because they will be scanned inside).
To obtain the array of placements given a shape, do this:
import lattice2BaseFeature
list_of_placements = lattice2BaseFeature.getPlacementsList(shape)
Lattice workbench recognizes arrays of placements by testing for property 'isLattice' of the document object. If the string value read out from that property contains "On", it is considered to be an array of placements. If the property is absent, or returned string does not contain "On", the object is recognized as a generic shape by Lattice.
This identification way provides easy compatibility between Lattice v1 and Lattice v2, and (hopefully) easy compatibility from other workbenches, without even having to import Lattice2
.
The whole Lattice2 workbench can be imported by import Lattice2
. This is not particularly useful at the moment, because Lattice2 doesn't run on GUI-less FreeCAD (although that might be changed - drop me a message if you are interested in that).
Lattice doesn't expose a rich API, because it is mostly a collection of features, most having relatively simple code. Nevertheless, there are a few modules that might come in handy, for example:
- lattice2GeomUtils.py contains a routine to construct FreeCAD.Rotation by aligning axes to directions supplied as vectors. This is used extensively inside Lattice itself.
- lattice2CompoundExplorer.py has an iterator object for recursively traversing nested compounds.
- lattice2InterpolatorUtil.py is a hack around Part.BSplineCurve, that allows to BSpline-interpolate an f(x)-style functions. It is used by Resample feature.
It is assumed that you are interested in creating a feature that can output an array of placements.
It is a good idea to derive your feature from LatticeBaseFeature (declared in lattice2BaseFeature.py). It provides quite a bit of functionality out of the box, such as the ability to select markers, exposing the placement as Placement property, etc.
It is important to not override some of the methods of LatticeBaseFeature. If you do, the basic functionality of LatticeBaseFeature will be broken, and the whole point of deriving from it will be gone. The methods to NOT override are:
- instead of
__init__
, definederivedInit
. - instead of
execute
, definederivedExecute
. derivedExecute can return the list of placements (which will automatically switch 'isLattice' to 'On' if it is in auto mode), or None (which will switch the feature to become generic shape). - if you override onChanged, make sure to call the original onChanged (otherwise, automatic coloring of arrays will stop working)
All these rules apply to document object's proxy. As for ViewProvider, LatticeBaseFeature currently provides almost no special functionality, so it can be replaced completely.
Lattice2 creates new documentObjects in a manner a little bit different from most other FreeCAD features.
The main difference is recomputing policy. After creating a document object, only the new object is recomputed, not the whole document. This is done via lattice2Executer.py, which calls Proxy's execute()
method.
Executer also provides a tool to pop up error messages and warnings to user when the feature is first recomputed. For that to work, the feature's execute()
/derivedExecute()
should use lattice2Executer.warning()
to issue warnings. No special actions are needed for errors other than raising an exception, because these are caught by lattice2Executer and displayed as a pop-up.
lattice2Executer.warning()
displays a message only if lattice2Executer.globalIsCreatingLatticeFeature global variable is set to true. If a message is displayed, the user has two buttons to click: 'continue', which simply lets the code execute further, of 'abort'. If user clicks 'abort', lattice2Common.CancelError() exception is raised, which is to terminate the command. You should catch that exception and undo the creation of the feature (the convenient way to do so is FreeCAD.ActiveDocument.abortTransaction())
There is also a convenient error message box function defined in lattice2Common.py - msgError(err)
. It does not display a message for CancelError
, which frees you from hassle of checking types of exceptions.
Introduction to Lattice workbench
Boolean operations on arrays, Compound structure
Shape-driven arrays, Draft arrays in Lattice2
"Subsequencing" (sublink iteration, TopoSeries)
- (common pieces)
-- Common properties of placement features
-- Common properties of array generators
- (features)
-- Single Placement
-- Attached Placement
-- Array an attached Placement
-- Linear Array
-- Polar Array
-- Array From Shape
-- Invert placements
-- Join Arrays
-- Array Filter
-- Project Array
-- Resample Array
-- Populate With Copies
-- Populate With Children
-- Mirror
-- PartDesign Pattern
-- Downgrade
-- SubLink
-- Subsequence
-- Make Compound
-- Compound Filter
-- Fuse Compound
-- Bounding Box
-- Shape String
-- ParaSeries
-- TopoSeries
-- Shape info feature
- (tools)
-- Explode Array
-- Explode Compound
-- Inspect tool
-- Substitute Object
-- Expose links to subelements
-- Recompute controlling tools