There are two ways to position model elements that represent physical parts or assemblies: by constraints, or by coordinate frames . Constraints are only available on hosts such as Inventor, that support constraint-based location. Frame-based positioning is available on all hosts. This section outlines the concepts behind frame-based positioning, and some of the tools available in the Intent language that make it easier to place components.
The basic notion of frame-based positioning is the coordinate "frame" , which is a first-class datatype in Intent. A Frame is effectively a matrix transform representing the position and orientation of a 3D coordinate system relative to the "world" of X, Y, and Z coordinates. The "WorldFrame" is the identity transform. A Point with coordinates X Y and Z in the worldFrame actually is the point with those coordinates. Internally, all points (and Vectors ) are stored in World coordinates. These coordinates are sometimes visible in certain outputs, such as the representation of point values in the immediate window, or the properties panel.
Fundamental to Intent's handling of positioning and orientation is the FrameMixin Design , which provides all of the Parameters and other rules about frames . Any component whose Design mixes in FrameMixin supports Frame-based positioning. The key attribute of FrameMixin is localFrame, which is of the Frame type, and holds the transform of the local component's coordinate system relative to the world. There are several alternate ways to position a component, and all ultimately result in setting localFrame.
Most Intent Designs already mix in FrameMixin. Only those things which do not represent physical bodies (such as reports, BOMs, etc) will not include it. It is mixed into BasePart, which is a fundamental Design included with Intent.
When points or vectors are created using the Point() or Vector() functions, these functions automatically create points or vectors relative to the localFrame. A simple example will demonstrate this.
Design myRoot : BasePart Rule p1 As Point = Point(1,2,3) Child c1 As :myChild Origin = p1 End Child End Design Design myChild : BasePart Rule p2 As Point = Point(10,0,0) End Design
Now check the values of the points :
Intent >Root.p1 --> Point_(1.0, 2.0, 3.0, WorldFrame()) Intent >Root.c1.p2 --> Point_(11.0, 2.0, 3.0, WorldFrame())
Note that the output of these references are calls to the Point_() function. This function is identical to the Point() function, except that the Frame in which the coordinates are to be interpreted is explicitly required. There is a similar function for Vectors , Vector_().
The myRoot call to the Point() function uses the localFrame of the root, which is always the worldFrame. Thus, the point p1 world coordinates are exactly as entered; the localFrame is the identity transform. The c1 child is positioned at this point . That means it's localFrame is going to be translated such that its origin is at p<1,2,3>.
The child call to the Point() function uses the localFrame of c1, and thus is going to transform the coordinates provided to it. So the point <10,0,0> relative to c1 is the point p<11,2,3> in the world.
The user never has to actually know the coordinates being used by Intent. The Design myRoot will work identically even if it is not the root. And the c1 child will be in exactly the same place, relative to its parent, no matter where its parent is. All the resulting coordinates will change, but the rules do not. Furthermore, any reference to c1.p2 will be correct, and the caller need not care about the position of c1.
Further, Intent manages all Frames in a model. Just as in the example, the rule-writer only needs to write rules in "local" coordinates - the assembly modeling behavior of Intent always ensures evaluations are done correctly. When a higher-level assembly is re-positioned, all subassemblies automatically update.
One common technique for positioning parts with frame based positioning is to use the Geometric Algebra capability built into the Intent language. Because the system knows the data types, algebra with these types is carried out correctly. For example, the system knows that a Point + Vector operation produces a Point . A Vector times a scalar (numeric) quantity will produce a Vector in the same direction, but with a different length. A Point times a scalar will produce an error. A Point added to a Point is also an error.
With these capabilities, the rule writer is free to ignore the underlying coordinates and the Frames that contain them. Intent manages the details. This is called "coordinate-free" geometry.
The Inventor example below creates three spheres and stacks them to form a simple snowman.
Design Snowman : Office IvAssemblyDocument Parameter Rule baseSize As Number = 50 Child base As :IvSphere radius = baseSize ' you can specify an offset of a point by ' adding a scaled vector to a point origin = Me.origin + unitY * child.radius ' align the X axis of this sphere with the assembly X axis xDirection = unitX ' align the Y axis with the negative Z axis of the assembly yDirection = -unitZ color = "White" ignorePosition? = False grounded? = True ' position the part and ground it End Child Child body As :IvSphere radius = baseSize * 0.75 origin = base.origin + base.unitZ * (child.radius + base.radius) xDirection = base.unitX yDirection = base.unitY color = "White" ignorePosition? = False grounded? = True End Child Child head As :IvSphere radius = baseSize * 0.50 origin = body.origin + body.unitZ * (child.radius + body.radius) xDirection = body.unitX yDirection = body.unitY color = "White" ignorePosition? = False grounded? = True End Child End Design
The ignorePosition? Parameter is required only in Inventor, because the default behavior in Inventor is to use constraint-based positioning. The grounded? Parameter is also Inventor-only.
The origin, xDirection, yDirection, unitX, unitY, and unitZ rules are all provided by FrameMixin.
origin = Me.origin + unitY * child.radius
Starting from the assembly's origin ( Me .origin), add the product of a y-axis vector ( unitY is a one unit vector aligned with the y-axis) and the radius of the base.
origin = base.origin + base.unitZ * (child.radius + base.radius)
Positioning the head on the body is similar to positioning the body on the base.
So far, only the origin parameter of FrameMixin has been discussed. Using origin by itself results in translations only. When other parameters are supplied, fully general orientation can be defined. The simplest way to perform general orientation is with the xDirection and yDirection parameters. As its name implies, xDirection is a Vector parameter and specifies the direction of the x-axis of the localFrame. Somewhat at odds with its name, yDirection doesn't actually specify the y-axis. Since the axes must be orthogonal, and there is no restriction on independent parameters, the system uses the yDirection value merely to determine the plane and general direction of the y-axis. Thus, xDirection has priority.
With these three parameters, it is possible to completely specify any position and orientation for a component. The snowman example above demonstrates this as well, setting the xDirection and yDirection. While it's difficult to see changes in orientation of a sphere, it's important to know the orientation when placing something else relative to it.