omdl  v1.0
OpenSCAD Mechanical Design Library
align.scad
Go to the documentation of this file.
1 //! Shape alignment tools.
2 /***************************************************************************//**
3  \file
4  \author Roy Allen Sutton
5  \date 2017-2019,2026
6 
7  \copyright
8 
9  This file is part of [omdl] (https://github.com/royasutton/omdl),
10  an OpenSCAD mechanical design library.
11 
12  The \em omdl is free software; you can redistribute it and/or modify
13  it under the terms of the [GNU Lesser General Public License]
14  (http://www.gnu.org/licenses/lgpl.html) as published by the Free
15  Software Foundation; either version 2.1 of the License, or (at
16  your option) any later version.
17 
18  The \em omdl is distributed in the hope that it will be useful,
19  but WITHOUT ANY WARRANTY; without even the implied warranty of
20  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21  Lesser General Public License for more details.
22 
23  You should have received a copy of the GNU Lesser General Public
24  License along with the \em omdl; if not, write to the Free Software
25  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
26  02110-1301, USA; or see <http://www.gnu.org/licenses/>.
27 
28  \details
29 
30  \amu_define group_name (Alignment)
31  \amu_define group_brief (Shape alignment tools.)
32 
33  \amu_include (include/amu/doxyg_init_pd_gds_ipg.amu)
34 *******************************************************************************/
35 
36 // group(s) begin (test summary and includes-required)
37 /***************************************************************************//**
38  \amu_include (include/amu/doxyg_define_in_parent_open.amu)
39  \amu_include (include/amu/includes_required.amu)
40 *******************************************************************************/
41 
42 // member-wide reference definitions
43 /***************************************************************************//**
44  \amu_define group_references
45  (
46  [line conventions]: \ref data_types_lines
47  )
48 *******************************************************************************/
49 
50 // member-wide documentation and conventions
51 /***************************************************************************//**
52  \addtogroup \amu_eval(${group})
53  \details
54  \anchor \amu_eval(${group})_conventions
55  \par Conventions
56 
57  - The subject line is the line or axis to be moved and is named \p l
58  in all modules. The reference line is the target to align toward
59  and is named \p r in all modules.
60 
61  - Alignment point selectors \p lp and \p rp are integers that
62  identify the point on the respective line at which the translation
63  is anchored.
64 
65  - The override coordinates \p lpo and \p rpo are only used when \p lp
66  or \p rp is 4.
67 
68  - All angles are in degrees.
69 *******************************************************************************/
70 
71 //----------------------------------------------------------------------------//
72 // members
73 //----------------------------------------------------------------------------//
74 
75 //! Orient a line or vector to a reference line or vector.
76 /***************************************************************************//**
77  \param l <line-3d | line-2d> The line or vector to align.
78  \param r <line-3d | line-2d> The reference line or vector.
79 
80  \param ar <decimal> Axial roll about \p r (in degrees).
81 
82  \details
83 
84  Rotates children so that the direction of \p l is aligned with the
85  direction of \p r, then applies an optional axial roll \p ar about
86  \p r. The rotation pivot is always the world origin; no
87  translation is performed. Use align_ll() when translation to a
88  specific point along \p r is also required.
89 
90  When \p l and \p r are parallel or anti-parallel their cross
91  product is the zero vector, which would leave rotate() undefined.
92  In that case a perpendicular fallback axis is derived
93  automatically: \c cross(ll,x_axis3d_uv) is tried first, then \c
94  cross(ll,y_axis3d_uv) if \p l happens to be collinear with the
95  x-axis. The threshold for treating the cross product as near-zero
96  is the library constant grid_fine.
97 
98  See [line conventions] for more information.
99 
100  \amu_eval(${group_references})
101 *******************************************************************************/
102 module orient_ll
103 (
104  l = z_axis3d_ul,
105  r = z_axis3d_ul,
106  ar = 0
107 )
108 {
109  ll = point_to_3d(vol_to_origin(l));
110  lr = point_to_3d(vol_to_origin(r));
111 
112  ax = cross(ll, lr);
113 
114  // When ll and lr are parallel or anti-parallel, cross() returns the zero
115  // vector, which makes rotate() undefined. Select a fallback axis that is
116  // guaranteed to be perpendicular to ll: try x_axis3d_uv first, then y_axis3d_uv
117  // in the degenerate case where ll is itself collinear with x_axis3d_uv.
118  ax_fb1 = (norm(ax) > grid_fine) ? ax : cross(ll, x_axis3d_uv);
119  ax_safe = (norm(ax_fb1) > grid_fine) ? ax_fb1 : cross(ll, y_axis3d_uv);
120 
121  rotate(ar, lr)
122  rotate(angle_ll(ll, lr), ax_safe)
123  children();
124 }
125 
126 //! Align a line or vector to a reference line or vector.
127 /***************************************************************************//**
128  \param l <line-3d | line-2d> The line or vector to align.
129  \param r <line-3d | line-2d> The reference line or vector.
130 
131  \param lp <integer> The line alignment point (see table).
132  \param rp <integer> The reference-line alignment point (see table).
133 
134  \param ar <decimal> Axial roll about \p r (in degrees).
135 
136  \param to <vector-3d | vector-2d> Translation offset about \p r.
137  \param ro <decimal-list-1:3 | decimal> Rotation offset about \p r
138  (in degrees).
139 
140  \param lpo <point-3d | point-2d> User-supplied alignment point on
141  \p l. Used when \p lp is \b 4.
142  \param rpo <point-3d | point-2d> User-supplied alignment point on
143  \p r. Used when \p rp is \b 4.
144 
145  \details
146 
147  The specified alignment point for the line \p l will be translated
148  to the specified alignment point for the reference line \p r.
149 
150  The transform is applied in four layers, from outermost to
151  innermost. First, the world origin is translated to the selected
152  alignment point on \p r. Second, the child is oriented so that the
153  direction of \p l matches the direction of \p r, and the axial roll
154  \p ar is applied about \p r. Third, the offset translation \p to
155  and offset rotation \p ro are applied in the frame of \p r after
156  orientation, meaning \p to shifts along and perpendicular to the
157  reference direction rather than in world coordinates. Fourth, the
158  selected alignment point on \p l is translated back to the origin
159  to anchor the child at the correct position.
160 
161  | lp, rp | alignment point |
162  |:-------:|:----------------------------------|
163  | 0 | none (no translation) |
164  | 1 | initial |
165  | 2 | median |
166  | 3 | termination |
167  | 4 | user-supplied (\p lpo / \p rpo) |
168 
169  See [line conventions] for more information.
170 
171  \amu_eval(${group_references})
172 *******************************************************************************/
173 module align_ll
174 (
175  l = z_axis3d_ul,
176  r = z_axis3d_ul,
177  lp = 0,
178  rp = 0,
179  ar = 0,
180  to = origin3d,
181  ro = origin3d,
182  lpo,
183  rpo
184 )
185 {
186  li = point_to_3d(line_ip(l));
187  lt = point_to_3d(line_tp(l));
188 
189  ri = point_to_3d(line_ip(r));
190  rt = point_to_3d(line_tp(r));
191 
192  ll = [li, lt];
193  lm = mean(ll);
194 
195  lr = [ri, rt];
196  rm = mean(lr);
197 
198  // translate reference
199  translate(select_ci([origin3d, ri, rm, rt, point_to_3d(rpo)], rp))
200 
201  // orient and roll line about reference (delegates to orient_ll so that the
202  // parallel / anti-parallel fallback axis logic is not duplicated here)
203  orient_ll(ll, lr, ar)
204  {
205  // apply offsets
206  translate(to)
207  rotate(ro)
208 
209  // translate alignment point
210  translate(-select_ci([origin3d, li, lm, lt, point_to_3d(lpo)], lp))
211  children();
212  }
213 }
214 
215 //! Align an objects Cartesian axis to reference line or vector.
216 /***************************************************************************//**
217  \param a <integer> The Cartesian axis index to align
218  (\b x_axis_ci, \b y_axis_ci, or \b z_axis_ci).
219  \param r <line-3d | line-2d> The reference line or vector.
220 
221  \param rp <integer> The reference-line alignment point (see table).
222 
223  \param ar <decimal> Axial roll about \p r (in degrees).
224 
225  \param to <vector-3d | vector-2d> Translation offset about \p r.
226  \param ro <decimal-list-1:3 | decimal> Rotation offset about \p r
227  (in degrees).
228 
229  \param rpo <point-3d | point-2d> User-supplied alignment point on
230  \p r. Used when \p rp is \b 4.
231 
232  \details
233 
234  The origin will be translated to the specified alignment point for
235  the reference line \p r. Equivalent to calling align_ll() with \p
236  l fixed to the Cartesian axis selected by \p a.
237 
238  Because the subject line is always the selected Cartesian axis
239  rooted at the world origin, the alignment point on the subject line
240  is always the origin and cannot be overridden. The parameters \p
241  lp and \p lpo of align_ll() are therefore fixed to \c 0 and \c
242  origin3d respectively and are not exposed here.
243 
244  | rp | alignment point |
245  |:-------:|:----------------------------------|
246  | 0 | none (no translation) |
247  | 1 | initial |
248  | 2 | median |
249  | 3 | termination |
250  | 4 | user-supplied (\p rpo) |
251 
252  See [line conventions] for more information.
253 
254  \amu_eval(${group_references})
255 *******************************************************************************/
256 module align_al
257 (
258  a = z_axis_ci,
259  r = z_axis3d_ul,
260  rp = 0,
261  ar = 0,
262  to = origin3d,
263  ro = origin3d,
264  rpo
265 )
266 {
267  assert
268  (
269  a == x_axis_ci || a == y_axis_ci || a == z_axis_ci,
270  "align_al: 'a' must be x_axis_ci (0), y_axis_ci (1), or z_axis_ci (2)"
271  );
272 
274 
275  align_ll(ra, r, 0, rp, ar, to, ro, origin3d, rpo)
276  children();
277 }
278 
279 //! @}
280 //! @}
281 
282 //----------------------------------------------------------------------------//
283 // end of file
284 //----------------------------------------------------------------------------//
x_axis3d_uv
<vector-3d> The unit vector of the positive x-axis in 3d Euclidean space.
Definition: constants.scad:428
x_axis_ci
<integer> The coordinate axis index for the Euclidean space x-axis.
Definition: constants.scad:395
y_axis_ci
<integer> The coordinate axis index for the Euclidean space y-axis.
Definition: constants.scad:398
z_axis3d_ul
<line-3d> A positively-directed unit line centered on the z-axis in 3d Euclidean space.
Definition: constants.scad:443
z_axis_ci
<integer> The coordinate axis index for the Euclidean space z-axis.
Definition: constants.scad:401
origin3d
<point-3d> The origin point coordinate in 3-dimensional Euclidean space.
Definition: constants.scad:425
y_axis3d_uv
<vector-3d> The unit vector of the positive y-axis in 3d Euclidean space.
Definition: constants.scad:431
y_axis3d_ul
<line-3d> A positively-directed unit line centered on the y-axis in 3d Euclidean space.
Definition: constants.scad:440
x_axis3d_ul
<line-3d> A positively-directed unit line centered on the x-axis in 3d Euclidean space.
Definition: constants.scad:437
grid_fine
OpenSCAD fine grid limit.
Definition: constants.scad:310
function line_tp(l)
Return the terminal point of a line or vector.
function angle_ll(l1, l2, s=true)
Compute the angle between two lines or vectors in a 3d or 2d-space.
function vol_to_origin(l)
Convert line to vector by shifting it to the origin.
function point_to_3d(p)
Return 3d point unchanged or add a zeroed third dimension to 2d point.
function line_ip(l)
Return the initial point of a line or vector.
function mean(v)
Compute the mean/average of a list of numbers.
function select_ci(v, i, l=true)
Select specified element from list or return a default.
module align_al(a=z_axis_ci, r=z_axis3d_ul, rp=0, ar=0, to=origin3d, ro=origin3d, rpo)
Align an objects Cartesian axis to reference line or vector.
Definition: align.scad:367
module orient_ll(l=z_axis3d_ul, r=z_axis3d_ul, ar=0)
Orient a line or vector to a reference line or vector.
Definition: align.scad:209
module align_ll(l=z_axis3d_ul, r=z_axis3d_ul, lp=0, rp=0, ar=0, to=origin3d, ro=origin3d, lpo, rpo)
Align a line or vector to a reference line or vector.
Definition: align.scad:282