@faicad/fai-cq-gears 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/dist/bevel_gear.d.ts +113 -0
  2. package/dist/bevel_gear.d.ts.map +1 -0
  3. package/dist/bevel_gear.js +327 -0
  4. package/dist/bevel_gear.js.map +1 -0
  5. package/dist/crossed_helical_gear.d.ts +24 -0
  6. package/dist/crossed_helical_gear.d.ts.map +1 -0
  7. package/dist/crossed_helical_gear.js +24 -0
  8. package/dist/crossed_helical_gear.js.map +1 -0
  9. package/dist/crossed_pair.d.ts +177 -0
  10. package/dist/crossed_pair.d.ts.map +1 -0
  11. package/dist/crossed_pair.js +237 -0
  12. package/dist/crossed_pair.js.map +1 -0
  13. package/dist/features.d.ts +184 -0
  14. package/dist/features.d.ts.map +1 -0
  15. package/dist/features.js +408 -0
  16. package/dist/features.js.map +1 -0
  17. package/dist/index.d.ts +178 -0
  18. package/dist/index.d.ts.map +1 -0
  19. package/dist/index.js +223 -0
  20. package/dist/index.js.map +1 -0
  21. package/dist/math.d.ts +200 -0
  22. package/dist/math.d.ts.map +1 -0
  23. package/dist/math.js +274 -0
  24. package/dist/math.js.map +1 -0
  25. package/dist/pairs.d.ts +161 -0
  26. package/dist/pairs.d.ts.map +1 -0
  27. package/dist/pairs.js +183 -0
  28. package/dist/pairs.js.map +1 -0
  29. package/dist/planetary.d.ts +96 -0
  30. package/dist/planetary.d.ts.map +1 -0
  31. package/dist/planetary.js +139 -0
  32. package/dist/planetary.js.map +1 -0
  33. package/dist/profile.d.ts +439 -0
  34. package/dist/profile.d.ts.map +1 -0
  35. package/dist/profile.js +592 -0
  36. package/dist/profile.js.map +1 -0
  37. package/dist/rack_gear.d.ts +125 -0
  38. package/dist/rack_gear.d.ts.map +1 -0
  39. package/dist/rack_gear.js +344 -0
  40. package/dist/rack_gear.js.map +1 -0
  41. package/dist/ring_gear.d.ts +54 -0
  42. package/dist/ring_gear.d.ts.map +1 -0
  43. package/dist/ring_gear.js +133 -0
  44. package/dist/ring_gear.js.map +1 -0
  45. package/dist/spline-face.d.ts +99 -0
  46. package/dist/spline-face.d.ts.map +1 -0
  47. package/dist/spline-face.js +94 -0
  48. package/dist/spline-face.js.map +1 -0
  49. package/dist/spur_gear.d.ts +112 -0
  50. package/dist/spur_gear.d.ts.map +1 -0
  51. package/dist/spur_gear.js +206 -0
  52. package/dist/spur_gear.js.map +1 -0
  53. package/dist/worm_gear.d.ts +78 -0
  54. package/dist/worm_gear.d.ts.map +1 -0
  55. package/dist/worm_gear.js +256 -0
  56. package/dist/worm_gear.js.map +1 -0
  57. package/package.json +47 -0
package/dist/math.js ADDED
@@ -0,0 +1,274 @@
1
+ /**
2
+ * math — cq_gears `utils.py` 的 numpy 子集(零依赖,TS 手写)
3
+ *
4
+ * 约定(**与 Python 逐字对齐,不要"修正"**):
5
+ *
6
+ * - `rotationMatrix(axis, alpha)` 返回 cq 的同款 Rodrigues 矩阵 R(列向量约定 `p' = R·p`)。
7
+ * - cq 里齿轮点集用的是 `pts @ r_mat`(**行向量**左乘),等价于 `Rᵀ·p`,即**绕轴转 −alpha**。
8
+ * 这不是笔误——`spur_gear.py::_build_tooth_faces` 就是这么写的,实测
9
+ * (`spur-helix15` 参考数据)确认齿面扭转方向与 `−twist_angle` 一致。
10
+ * 所以本模块同时提供 `applyRowMatrix()`(忠实复刻)与 `rotateRows()`(语义命名)。
11
+ */
12
+ /**
13
+ * 构造一个 `Vec3`。
14
+ *
15
+ * @param x x 分量
16
+ * @param y y 分量
17
+ * @param z z 分量
18
+ * @returns 三维向量
19
+ */
20
+ export const vec3 = (x, y, z) => ({ x, y, z });
21
+ /**
22
+ * 向量加法。
23
+ *
24
+ * @param a 左操作数
25
+ * @param b 右操作数
26
+ * @returns `a + b`
27
+ */
28
+ export const add = (a, b) => ({ x: a.x + b.x, y: a.y + b.y, z: a.z + b.z });
29
+ /**
30
+ * 向量减法。
31
+ *
32
+ * @param a 左操作数
33
+ * @param b 右操作数
34
+ * @returns `a - b`
35
+ */
36
+ export const sub = (a, b) => ({ x: a.x - b.x, y: a.y - b.y, z: a.z - b.z });
37
+ /**
38
+ * 标量乘法。
39
+ *
40
+ * @param a 向量
41
+ * @param k 标量
42
+ * @returns `k·a`
43
+ */
44
+ export const scale = (a, k) => ({ x: a.x * k, y: a.y * k, z: a.z * k });
45
+ /**
46
+ * 点积。
47
+ *
48
+ * @param a 左操作数
49
+ * @param b 右操作数
50
+ * @returns `a·b`
51
+ */
52
+ export const dot = (a, b) => a.x * b.x + a.y * b.y + a.z * b.z;
53
+ /**
54
+ * 叉积。
55
+ *
56
+ * @param a 左操作数
57
+ * @param b 右操作数
58
+ * @returns `a×b`
59
+ */
60
+ export const cross = (a, b) => ({
61
+ x: a.y * b.z - a.z * b.y,
62
+ y: a.z * b.x - a.x * b.z,
63
+ z: a.x * b.y - a.y * b.x,
64
+ });
65
+ /**
66
+ * 向量模长。
67
+ *
68
+ * @param a 向量
69
+ * @returns 模长
70
+ */
71
+ export const norm = (a) => Math.sqrt(dot(a, a));
72
+ /**
73
+ * 归一化;零向量返回零向量(避免除零)。
74
+ *
75
+ * @param a 向量
76
+ * @returns 单位向量(零向量输入返回零向量)
77
+ */
78
+ export const normalize = (a) => {
79
+ const n = norm(a);
80
+ return n === 0 ? { x: 0, y: 0, z: 0 } : scale(a, 1 / n);
81
+ };
82
+ /**
83
+ * `np.linspace(a, b, n)` —— 闭区间,含两端。
84
+ *
85
+ * @param a 起始值
86
+ * @param b 结束值
87
+ * @param n 点数
88
+ * @returns n 个等距点(n <= 1 时只含 a)
89
+ */
90
+ export function linspace(a, b, n) {
91
+ if (n <= 1)
92
+ return [a];
93
+ const out = new Array(n);
94
+ const step = (b - a) / (n - 1);
95
+ for (let i = 0; i < n; i++)
96
+ out[i] = a + step * i;
97
+ return out;
98
+ }
99
+ /**
100
+ * 弧度夹到 [0, 2π)。
101
+ *
102
+ * @param t 任意弧度角
103
+ * @returns 归一化后的弧度角
104
+ */
105
+ export function normalizeAngle2pi(t) {
106
+ const twoPi = Math.PI * 2;
107
+ let r = t % twoPi;
108
+ if (r < 0)
109
+ r += twoPi;
110
+ return r;
111
+ }
112
+ /**
113
+ * `cq_gears.utils.rotation_matrix` 的逐字移植(Rodrigues,列向量约定)。
114
+ *
115
+ * @param axis 旋转轴(无需归一化,内部归一)
116
+ * @param alpha 旋转角(弧度)
117
+ * @returns 3×3 Rodrigues 旋转矩阵(行主序)
118
+ */
119
+ export function rotationMatrix(axis, alpha) {
120
+ const n = norm(axis);
121
+ const ux = axis.x / n;
122
+ const uy = axis.y / n;
123
+ const uz = axis.z / n;
124
+ const sina = Math.sin(alpha);
125
+ const cosa = Math.cos(alpha);
126
+ const k = 1 - cosa;
127
+ return [
128
+ [cosa + k * ux * ux, ux * uy * k - uz * sina, ux * uz * k + uy * sina],
129
+ [uy * ux * k + uz * sina, cosa + k * uy * uy, uy * uz * k - ux * sina],
130
+ [uz * ux * k - uy * sina, uz * uy * k + ux * sina, cosa + k * uz * uz],
131
+ ];
132
+ }
133
+ /**
134
+ * 行向量左乘:`pts @ m`(cq 的实际用法)。
135
+ *
136
+ * 结果第 j 分量 = Σᵢ pᵢ·m[i][j],等价于 `mᵀ · p`。
137
+ *
138
+ * @param points 行向量点集
139
+ * @param m 3×3 矩阵
140
+ * @returns 变换后的点集
141
+ */
142
+ export function applyRowMatrix(points, m) {
143
+ return points.map((p) => ({
144
+ x: p.x * m[0][0] + p.y * m[1][0] + p.z * m[2][0],
145
+ y: p.x * m[0][1] + p.y * m[1][1] + p.z * m[2][1],
146
+ z: p.x * m[0][2] + p.y * m[1][2] + p.z * m[2][2],
147
+ }));
148
+ }
149
+ /**
150
+ * 语义化包装:`applyRowMatrix(pts, rotationMatrix(axis, alpha))`。
151
+ *
152
+ * ⚠️ 因为 cq 用行向量左乘,实际旋转角是 **−alpha**。
153
+ *
154
+ * @param points 点集
155
+ * @param axis 旋转轴
156
+ * @param alpha 名义旋转角(弧度,实际为 −alpha)
157
+ * @returns 旋转后的点集
158
+ */
159
+ export function rotateRows(points, axis, alpha) {
160
+ return applyRowMatrix(points, rotationMatrix(axis, alpha));
161
+ }
162
+ /**
163
+ * 真正按 +alpha 旋转(标准列向量约定),用于 TS 侧需要正向旋转的场景。
164
+ *
165
+ * @param points 点集
166
+ * @param axis 旋转轴
167
+ * @param alpha 旋转角(弧度)
168
+ * @returns 旋转后的点集
169
+ */
170
+ export function rotatePoints(points, axis, alpha) {
171
+ const m = rotationMatrix(axis, -alpha);
172
+ return points.map((p) => ({
173
+ x: m[0][0] * p.x + m[0][1] * p.y + m[0][2] * p.z,
174
+ y: m[1][0] * p.x + m[1][1] * p.y + m[1][2] * p.z,
175
+ z: m[2][0] * p.x + m[2][1] * p.y + m[2][2] * p.z,
176
+ }));
177
+ }
178
+ /**
179
+ * `cq_gears.utils.sphere_to_cartesian` 的逐字移植:球坐标 → 笛卡尔。
180
+ *
181
+ * ⚠️ 注意极点角 `gamma` 是**从 +Z 轴量起**(`z = r·cos(gamma)`),
182
+ * 而不是数学习惯里从 XY 平面量起的仰角——BevelGear 的整套公式都建立在这个约定上。
183
+ *
184
+ * @param r 球半径
185
+ * @param gamma 极角(弧度,自 +Z 轴)
186
+ * @param theta 方位角(弧度)
187
+ * @returns 笛卡尔坐标
188
+ */
189
+ export function sphereToCartesian(r, gamma, theta) {
190
+ return {
191
+ x: r * Math.sin(gamma) * Math.sin(theta),
192
+ y: r * Math.sin(gamma) * Math.cos(theta),
193
+ z: r * Math.cos(gamma),
194
+ };
195
+ }
196
+ /**
197
+ * `cq_gears.utils.s_inv` 的逐字移植:球面渐开线(给定极角 → 方位角)。
198
+ *
199
+ * `phi = arccos(tan(gamma0)/tan(gamma))`;
200
+ * `return arccos(cos(gamma)/cos(gamma0))/sin(gamma0) − phi`。
201
+ *
202
+ * 定义域外(`|tan(gamma0)/tan(gamma)| > 1`)与 Python 的 numpy 一样返回 NaN——
203
+ * 由调用方决定是否报错,本函数不静默替换。
204
+ *
205
+ * @param gamma0 基锥极角(弧度)
206
+ * @param gamma 曲线上点的极角(弧度)
207
+ * @returns 该点的方位角(弧度)
208
+ */
209
+ export function sInv(gamma0, gamma) {
210
+ const phi = Math.acos(Math.tan(gamma0) / Math.tan(gamma));
211
+ return Math.acos(Math.cos(gamma) / Math.cos(gamma0)) / Math.sin(gamma0) - phi;
212
+ }
213
+ /**
214
+ * `cq_gears.utils.s_arc` 的逐字移植:球面上的一段圆弧。
215
+ *
216
+ * Python 侧是 `cos(t)·a + sin(t)·(k×a) + (k·a)(1−cos t)·k`(`a` = 球心到弧心方向
217
+ * 偏移 `r_delta` 后的单位向量,`k` = 弧心的单位向量),再整体乘球半径。
218
+ *
219
+ * @param sr 球半径
220
+ * @param cGamma 弧心的极角(弧度)
221
+ * @param cTheta 弧心的方位角(弧度)
222
+ * @param rDelta 弧心与弧上任一点的夹角(弧度)
223
+ * @param start 起始角(弧度)
224
+ * @param end 终止角(弧度)
225
+ * @param n 点数(含两端)
226
+ * @returns 弧上 n 个点
227
+ */
228
+ export function sArc(sr, cGamma, cTheta, rDelta, start, end, n = 32) {
229
+ const a = sphereToCartesian(1.0, cGamma + rDelta, cTheta);
230
+ const k = sphereToCartesian(1.0, cGamma, cTheta);
231
+ const ka = cross(k, a);
232
+ const kdota = dot(k, a);
233
+ return linspace(start, end, n).map((t) => {
234
+ const ct = Math.cos(t);
235
+ const st = Math.sin(t);
236
+ const w = 1 - ct;
237
+ return vec3(sr * (ct * a.x + st * ka.x + kdota * w * k.x), sr * (ct * a.y + st * ka.y + kdota * w * k.y), sr * (ct * a.z + st * ka.z + kdota * w * k.z));
238
+ });
239
+ }
240
+ /**
241
+ * `cq_gears.utils.angle_between` 的移植:向量 OA 与 OB 的夹角。
242
+ *
243
+ * @param o 公共起点
244
+ * @param a 向量 OA 的终点
245
+ * @param b 向量 OB 的终点
246
+ * @returns 夹角(弧度)
247
+ */
248
+ export function angleBetween(o, a, b) {
249
+ const p = sub(a, o);
250
+ const q = sub(b, o);
251
+ return Math.acos(dot(p, q) / (norm(p) * norm(q)));
252
+ }
253
+ /**
254
+ * `cq_gears.utils.circle3d_by3points` 的移植:三点定圆。
255
+ *
256
+ * @param a 第一点
257
+ * @param b 第二点
258
+ * @param c 第三点
259
+ * @returns `{ radius, center }`
260
+ */
261
+ export function circle3dBy3points(a, b, c) {
262
+ let u = sub(b, a);
263
+ let w = cross(sub(c, a), u);
264
+ u = normalize(u);
265
+ w = normalize(w);
266
+ const v = cross(w, u);
267
+ const bx = dot(sub(b, a), u);
268
+ const cx = dot(sub(c, a), u);
269
+ const cy = dot(sub(c, a), v);
270
+ const h = ((cx - bx / 2) ** 2 + cy ** 2 - (bx / 2) ** 2) / (2 * cy);
271
+ const center = add(a, add(scale(u, bx / 2), scale(v, h)));
272
+ return { radius: norm(sub(a, center)), center };
273
+ }
274
+ //# sourceMappingURL=math.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"math.js","sourceRoot":"","sources":["../src/math.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,161 @@
1
+ /**
2
+ * pairs — 齿轮对(装配体)构造
3
+ *
4
+ * 对应 cq_gears `bevel_gear.py::BevelGearPair`:把两个单体锥齿轮按轴交角装配成一个
5
+ * Compound(`asm.toCompound()`),本包返回**两件各自的 solid**,由调用方决定导出方式
6
+ * (`exportStepFromSolids` 把它们各写成一个 XCAF 条目/产品)。
7
+ *
8
+ * ## 装配定位链(2026-09-12 在 cadquery-env 实测确定,非推断)
9
+ *
10
+ * Python 侧:
11
+ *
12
+ * ```python
13
+ * loc = cq.Location()
14
+ * loc *= cq.Location(cq.Vector(0, 0, gear.cone_h), cq.Vector(0, 1, 0), degrees(axis_angle))
15
+ * loc *= cq.Location(cq.Vector(0, 0, -pinion.cone_h))
16
+ * if pinion.z % 2 == 0:
17
+ * loc *= cq.Location(cq.Vector(0, 0, 0), cq.Vector(0, 0, 1), degrees(pi / pinion.z))
18
+ * ```
19
+ *
20
+ * 两条实测结论(`out/probe-loc.py`,输出见当日日志):
21
+ *
22
+ * 1. `LocA * LocB` 的复合是**右到左**——先应用 B,再应用 A
23
+ * (实测 `(r*t)·(1,0,0) = (0,11,0)`:先平移 +10x 再绕 Z 转 90°,而非反过来)。
24
+ * 故 `loc = A*B*C` 的施加顺序是 **C → B → A**。
25
+ * 2. `Location(t, ax, angle)` 的 `t` 是**平移分量**,旋转轴恒是**过原点**的
26
+ * `gp_Ax1(Vector(0,0,0), ax)`——不是「绕 t 点旋转」。
27
+ * 实测 `Location((0,0,5), Y, 90)` 作用在 `(1,0,0)` 上得 `(0,0,4)`
28
+ * =「先绕原点 Y 转 90° 得 (0,0,-1),再平移 +5z」,且 `toTuple()` 为 `((0,0,5),(0,90,0))`。
29
+ *
30
+ * 所以 pinion 的最终位姿是,按施加顺序:
31
+ *
32
+ * | 步 | 对应 Python | 本文件实现 |
33
+ * |---|---|---|
34
+ * | C | `Location((0,0,0), Z, degrees(pi/z))`,**仅 pinion 齿数为偶** | 绕 Z 转过原点转 `π/z` |
35
+ * | B | `Location((0,0,-pinion.cone_h))` | 沿 Z 平移 `-pinionConeH` |
36
+ * | A | `Location((0,0,gear.cone_h), Y, degrees(axis_angle))` | 绕 Y 转过原点转 `axisAngle`,再沿 Z 平移 `+gearConeH` |
37
+ *
38
+ * gear 不加任何定位(Python 用 `cq.Location()` 恒等)。
39
+ *
40
+ * ## 与 Python 的两处差异(照抄,不改)
41
+ *
42
+ * - **pinion 不传 `clearance`**:Python 侧 `BevelGearPair.__init__` 给 gear 传了
43
+ * `clearance`、给 pinion 只传了 `backlash`(`clearance` 落回默认 0.0)。
44
+ * 本实现逐字保持这个不对称。
45
+ * - **pinion 的螺旋角取负**:`-helix_angle`(一对锥齿轮的旋向相反)。
46
+ */
47
+ import type { BrepHandle } from '@faicad/faijs';
48
+ import type { GearKernel } from '@faicad/cq-compat';
49
+ import { type BevelGearGeometry } from './profile.js';
50
+ import type { SplineFaceStrategy } from './spline-face.js';
51
+ /** 锥齿轮副参数(逐字沿用 Python `BevelGearPair.__init__` 的构造参数名)。 */
52
+ export interface BevelGearPairParams {
53
+ module: number;
54
+ /** 大轮齿数(cq `gear_teeth`)。 */
55
+ gear_teeth: number;
56
+ /** 小轮齿数(cq `pinion_teeth`)。 */
57
+ pinion_teeth: number;
58
+ face_width: number;
59
+ /** 轴交角(度,cq `axis_angle`,默认 90)。 */
60
+ axis_angle?: number;
61
+ pressure_angle?: number;
62
+ helix_angle?: number;
63
+ clearance?: number;
64
+ backlash?: number;
65
+ }
66
+ /** 齿轮对构造选项。 */
67
+ export interface BuildBevelGearPairOptions {
68
+ /** 齿面建面策略(两件共用)。 */
69
+ strategy?: SplineFaceStrategy;
70
+ /** 轴孔直径(两件共用,cq `bore_d`)。 */
71
+ boreD?: number;
72
+ /** 是否裁底(两件共用)。 */
73
+ trimBottom?: boolean;
74
+ /** 是否裁顶(两件共用)。 */
75
+ trimTop?: boolean;
76
+ /** 是否对 pinion 施加装配定位(cq `transform_pinion`,默认 true)。 */
77
+ transformPinion?: boolean;
78
+ /** 是否构建大轮(cq `build_gear`,默认 true)。 */
79
+ buildGear?: boolean;
80
+ /** 是否构建小轮(cq `build_pinion`,默认 true)。 */
81
+ buildPinion?: boolean;
82
+ }
83
+ /** pinion 定位链的输入量(拆出来便于单测直接验证定位本身)。 */
84
+ export interface PinionPlacement {
85
+ /** 轴交角(度)。 */
86
+ axisAngleDeg: number;
87
+ /** 大轮锥顶到底面的距离 `BevelGear.cone_h`。 */
88
+ gearConeH: number;
89
+ /** 小轮锥顶到底面的距离 `BevelGear.cone_h`。 */
90
+ pinionConeH: number;
91
+ /** 小轮齿数(决定是否施加绕 Z 的 π/z 对齿旋转)。 */
92
+ pinionTeeth: number;
93
+ }
94
+ /** 一对锥齿轮的构建结果。 */
95
+ export interface BevelGearPairBuild {
96
+ /** 大轮 solid(未加定位)。 */
97
+ gear?: BrepHandle;
98
+ /** 小轮 solid(**已加**定位,除非 `transformPinion: false`)。 */
99
+ pinion?: BrepHandle;
100
+ /** 大轮几何量(含 `coneH`)。 */
101
+ gearGeometry: BevelGearGeometry;
102
+ /** 小轮几何量(含 `coneH`)。 */
103
+ pinionGeometry: BevelGearGeometry;
104
+ /** 实际使用的轴交角(度)。 */
105
+ axisAngleDeg: number;
106
+ }
107
+ /**
108
+ * 齿轮对的导出条目(名字 + solid),供 `exportStepFromSolids` 一件一个产品。
109
+ *
110
+ * ⚠️ 不带颜色:cq 侧的装配色(`BevelGearPair.asm_gear_color = 'goldenrod'` /
111
+ * `asm_pinion_color = 'lightsteelblue'`)在 `assemble()` 里赋给 `cq.Assembly`,
112
+ * 而 `_build()` 返回的是 `asm.toCompound()`——**颜色在这一步就被丢掉了**。
113
+ * 实测参考 STEP(`out/ref-pairs/bp-basic.step`)里 `MANIFOLD_SOLID_BREP` 计数为 2、
114
+ * `COLOUR_RGB` 计数为 **0**。故 B 侧同样不着色,两侧才逐项可比。
115
+ *
116
+ * @param build `buildBevelGearPair` 的结果
117
+ * @returns 按 gear → pinion 顺序排列的条目(缺件则跳过)
118
+ */
119
+ export declare function bevelPairExportParts(build: BevelGearPairBuild): Array<{
120
+ name: string;
121
+ solid: BrepHandle;
122
+ }>;
123
+ /**
124
+ * 复刻 `BevelGearPair.__init__` 的分锥角分配。
125
+ *
126
+ * `delta_gear = atan(sin(A) / (pinion_teeth/gear_teeth + cos(A)))`、
127
+ * `delta_pinion = atan(sin(A) / (gear_teeth/pinion_teeth + cos(A)))`。
128
+ *
129
+ * @param params 齿轮副参数
130
+ * @returns 大轮 / 小轮的分度锥角(度)
131
+ */
132
+ export declare function bevelPairConeAngles(params: BevelGearPairParams): {
133
+ gearDeg: number;
134
+ pinionDeg: number;
135
+ };
136
+ /**
137
+ * 把小轮摆到与大轮啮合的位姿(复刻 Python 的三步 `loc *=`,见文件头表格)。
138
+ *
139
+ * 施加顺序 **C → B → A**,对应内核操作的调用顺序:
140
+ * 先绕 Z 转(仅齿数为偶)、再沿 Z 平移 `-pinionConeH`、
141
+ * 再绕 Y 转过原点转 `axisAngle`、最后沿 Z 平移 `+gearConeH`。
142
+ *
143
+ * @param kernel 原始 OCCT 内核
144
+ * @param pinion 小轮 solid
145
+ * @param place 定位链输入量
146
+ * @returns 定位后的小轮 solid
147
+ */
148
+ export declare function placePinion(kernel: GearKernel, pinion: BrepHandle, place: PinionPlacement): BrepHandle;
149
+ /**
150
+ * 构建一对锥齿轮(`BevelGearPair`)。
151
+ *
152
+ * 两件都走 `buildBevelGearSolid`;差异只在参数:pinion 拿 `-helix_angle`,
153
+ * 且**不传** `clearance`(逐字复刻 Python 的不对称传参)。
154
+ *
155
+ * @param kernel 原始 OCCT 内核
156
+ * @param params 齿轮副参数
157
+ * @param options 构造选项
158
+ * @returns 两件 solid(pinion 默认已定位)与两件几何量
159
+ */
160
+ export declare function buildBevelGearPair(kernel: GearKernel, params: BevelGearPairParams, options?: BuildBevelGearPairOptions): BevelGearPairBuild;
161
+ //# sourceMappingURL=pairs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pairs.d.ts","sourceRoot":"","sources":["../src/pairs.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAA;AAC/C,OAAO,KAAK,EAAE,UAAU,EAAY,MAAM,mBAAmB,CAAA;AAC7D,OAAO,EAAqB,KAAK,iBAAiB,EAAwB,MAAM,WAAW,CAAA;AAE3F,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAA;AAEvD,2DAA2D;AAC3D,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,MAAM,CAAA;IACd,6BAA6B;IAC7B,UAAU,EAAE,MAAM,CAAA;IAClB,+BAA+B;IAC/B,YAAY,EAAE,MAAM,CAAA;IACpB,UAAU,EAAE,MAAM,CAAA;IAClB,oCAAoC;IACpC,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AAED,eAAe;AACf,MAAM,WAAW,yBAAyB;IACxC,oBAAoB;IACpB,QAAQ,CAAC,EAAE,kBAAkB,CAAA;IAC7B,8BAA8B;IAC9B,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,kBAAkB;IAClB,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,kBAAkB;IAClB,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,wDAAwD;IACxD,eAAe,CAAC,EAAE,OAAO,CAAA;IACzB,uCAAuC;IACvC,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,yCAAyC;IACzC,WAAW,CAAC,EAAE,OAAO,CAAA;CACtB;AAKD,uCAAuC;AACvC,MAAM,WAAW,eAAe;IAC9B,cAAc;IACd,YAAY,EAAE,MAAM,CAAA;IACpB,qCAAqC;IACrC,SAAS,EAAE,MAAM,CAAA;IACjB,qCAAqC;IACrC,WAAW,EAAE,MAAM,CAAA;IACnB,kCAAkC;IAClC,WAAW,EAAE,MAAM,CAAA;CACpB;AAED,kBAAkB;AAClB,MAAM,WAAW,kBAAkB;IACjC,sBAAsB;IACtB,IAAI,CAAC,EAAE,UAAU,CAAA;IACjB,sDAAsD;IACtD,MAAM,CAAC,EAAE,UAAU,CAAA;IACnB,wBAAwB;IACxB,YAAY,EAAE,iBAAiB,CAAA;IAC/B,wBAAwB;IACxB,cAAc,EAAE,iBAAiB,CAAA;IACjC,mBAAmB;IACnB,YAAY,EAAE,MAAM,CAAA;CACrB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,kBAAkB,GACxB,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,UAAU,CAAA;CAAE,CAAC,CAK5C;AAGD;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,mBAAmB,GAAG;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CASvG;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,WAAW,CACzB,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,eAAe,GAC7D,UAAU,CAWZ;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,UAAU,EAClB,MAAM,EAAE,mBAAmB,EAC3B,OAAO,GAAE,yBAA8B,GACtC,kBAAkB,CAqDpB"}
package/dist/pairs.js ADDED
@@ -0,0 +1,183 @@
1
+ /**
2
+ * pairs — 齿轮对(装配体)构造
3
+ *
4
+ * 对应 cq_gears `bevel_gear.py::BevelGearPair`:把两个单体锥齿轮按轴交角装配成一个
5
+ * Compound(`asm.toCompound()`),本包返回**两件各自的 solid**,由调用方决定导出方式
6
+ * (`exportStepFromSolids` 把它们各写成一个 XCAF 条目/产品)。
7
+ *
8
+ * ## 装配定位链(2026-09-12 在 cadquery-env 实测确定,非推断)
9
+ *
10
+ * Python 侧:
11
+ *
12
+ * ```python
13
+ * loc = cq.Location()
14
+ * loc *= cq.Location(cq.Vector(0, 0, gear.cone_h), cq.Vector(0, 1, 0), degrees(axis_angle))
15
+ * loc *= cq.Location(cq.Vector(0, 0, -pinion.cone_h))
16
+ * if pinion.z % 2 == 0:
17
+ * loc *= cq.Location(cq.Vector(0, 0, 0), cq.Vector(0, 0, 1), degrees(pi / pinion.z))
18
+ * ```
19
+ *
20
+ * 两条实测结论(`out/probe-loc.py`,输出见当日日志):
21
+ *
22
+ * 1. `LocA * LocB` 的复合是**右到左**——先应用 B,再应用 A
23
+ * (实测 `(r*t)·(1,0,0) = (0,11,0)`:先平移 +10x 再绕 Z 转 90°,而非反过来)。
24
+ * 故 `loc = A*B*C` 的施加顺序是 **C → B → A**。
25
+ * 2. `Location(t, ax, angle)` 的 `t` 是**平移分量**,旋转轴恒是**过原点**的
26
+ * `gp_Ax1(Vector(0,0,0), ax)`——不是「绕 t 点旋转」。
27
+ * 实测 `Location((0,0,5), Y, 90)` 作用在 `(1,0,0)` 上得 `(0,0,4)`
28
+ * =「先绕原点 Y 转 90° 得 (0,0,-1),再平移 +5z」,且 `toTuple()` 为 `((0,0,5),(0,90,0))`。
29
+ *
30
+ * 所以 pinion 的最终位姿是,按施加顺序:
31
+ *
32
+ * | 步 | 对应 Python | 本文件实现 |
33
+ * |---|---|---|
34
+ * | C | `Location((0,0,0), Z, degrees(pi/z))`,**仅 pinion 齿数为偶** | 绕 Z 转过原点转 `π/z` |
35
+ * | B | `Location((0,0,-pinion.cone_h))` | 沿 Z 平移 `-pinionConeH` |
36
+ * | A | `Location((0,0,gear.cone_h), Y, degrees(axis_angle))` | 绕 Y 转过原点转 `axisAngle`,再沿 Z 平移 `+gearConeH` |
37
+ *
38
+ * gear 不加任何定位(Python 用 `cq.Location()` 恒等)。
39
+ *
40
+ * ## 与 Python 的两处差异(照抄,不改)
41
+ *
42
+ * - **pinion 不传 `clearance`**:Python 侧 `BevelGearPair.__init__` 给 gear 传了
43
+ * `clearance`、给 pinion 只传了 `backlash`(`clearance` 落回默认 0.0)。
44
+ * 本实现逐字保持这个不对称。
45
+ * - **pinion 的螺旋角取负**:`-helix_angle`(一对锥齿轮的旋向相反)。
46
+ */
47
+ import { bevelGearGeometry } from './profile.js';
48
+ import { buildBevelGearSolid } from './bevel_gear.js';
49
+ const Z_AXIS = { point: { x: 0, y: 0, z: 0 }, direction: { x: 0, y: 0, z: 1 } };
50
+ const Y_AXIS = { point: { x: 0, y: 0, z: 0 }, direction: { x: 0, y: 1, z: 0 } };
51
+ /**
52
+ * 齿轮对的导出条目(名字 + solid),供 `exportStepFromSolids` 一件一个产品。
53
+ *
54
+ * ⚠️ 不带颜色:cq 侧的装配色(`BevelGearPair.asm_gear_color = 'goldenrod'` /
55
+ * `asm_pinion_color = 'lightsteelblue'`)在 `assemble()` 里赋给 `cq.Assembly`,
56
+ * 而 `_build()` 返回的是 `asm.toCompound()`——**颜色在这一步就被丢掉了**。
57
+ * 实测参考 STEP(`out/ref-pairs/bp-basic.step`)里 `MANIFOLD_SOLID_BREP` 计数为 2、
58
+ * `COLOUR_RGB` 计数为 **0**。故 B 侧同样不着色,两侧才逐项可比。
59
+ *
60
+ * @param build `buildBevelGearPair` 的结果
61
+ * @returns 按 gear → pinion 顺序排列的条目(缺件则跳过)
62
+ */
63
+ export function bevelPairExportParts(build) {
64
+ const parts = [];
65
+ if (build.gear)
66
+ parts.push({ name: 'gear', solid: build.gear });
67
+ if (build.pinion)
68
+ parts.push({ name: 'pinion', solid: build.pinion });
69
+ return parts;
70
+ }
71
+ /**
72
+ * 复刻 `BevelGearPair.__init__` 的分锥角分配。
73
+ *
74
+ * `delta_gear = atan(sin(A) / (pinion_teeth/gear_teeth + cos(A)))`、
75
+ * `delta_pinion = atan(sin(A) / (gear_teeth/pinion_teeth + cos(A)))`。
76
+ *
77
+ * @param params 齿轮副参数
78
+ * @returns 大轮 / 小轮的分度锥角(度)
79
+ */
80
+ export function bevelPairConeAngles(params) {
81
+ const axis = ((params.axis_angle ?? 90.0) * Math.PI) / 180.0;
82
+ const sinA = Math.sin(axis);
83
+ const cosA = Math.cos(axis);
84
+ const ratio = params.pinion_teeth / params.gear_teeth;
85
+ return {
86
+ gearDeg: (Math.atan(sinA / (ratio + cosA)) * 180.0) / Math.PI,
87
+ pinionDeg: (Math.atan(sinA / (1.0 / ratio + cosA)) * 180.0) / Math.PI,
88
+ };
89
+ }
90
+ /**
91
+ * 把小轮摆到与大轮啮合的位姿(复刻 Python 的三步 `loc *=`,见文件头表格)。
92
+ *
93
+ * 施加顺序 **C → B → A**,对应内核操作的调用顺序:
94
+ * 先绕 Z 转(仅齿数为偶)、再沿 Z 平移 `-pinionConeH`、
95
+ * 再绕 Y 转过原点转 `axisAngle`、最后沿 Z 平移 `+gearConeH`。
96
+ *
97
+ * @param kernel 原始 OCCT 内核
98
+ * @param pinion 小轮 solid
99
+ * @param place 定位链输入量
100
+ * @returns 定位后的小轮 solid
101
+ */
102
+ export function placePinion(kernel, pinion, place) {
103
+ let s = pinion;
104
+ if (place.pinionTeeth % 2 === 0) {
105
+ // C:`degrees(pi/z)` 传进 `Location` 后被 radians() 转回,净效果 = π/z 弧度。
106
+ s = kernel.rotate(s, Z_AXIS, Math.PI / place.pinionTeeth);
107
+ }
108
+ // B
109
+ s = kernel.translate(s, 0, 0, -place.pinionConeH);
110
+ // A:绕 Y(过原点)转轴交角,再沿 Z 平移 gear.cone_h
111
+ s = kernel.rotate(s, Y_AXIS, (place.axisAngleDeg * Math.PI) / 180.0);
112
+ return kernel.translate(s, 0, 0, place.gearConeH);
113
+ }
114
+ /**
115
+ * 构建一对锥齿轮(`BevelGearPair`)。
116
+ *
117
+ * 两件都走 `buildBevelGearSolid`;差异只在参数:pinion 拿 `-helix_angle`,
118
+ * 且**不传** `clearance`(逐字复刻 Python 的不对称传参)。
119
+ *
120
+ * @param kernel 原始 OCCT 内核
121
+ * @param params 齿轮副参数
122
+ * @param options 构造选项
123
+ * @returns 两件 solid(pinion 默认已定位)与两件几何量
124
+ */
125
+ export function buildBevelGearPair(kernel, params, options = {}) {
126
+ const axisAngleDeg = params.axis_angle ?? 90.0;
127
+ const { gearDeg, pinionDeg } = bevelPairConeAngles(params);
128
+ const common = {};
129
+ if (options.strategy !== undefined)
130
+ common.strategy = options.strategy;
131
+ if (options.boreD !== undefined)
132
+ common.boreD = options.boreD;
133
+ if (options.trimBottom !== undefined)
134
+ common.trimBottom = options.trimBottom;
135
+ if (options.trimTop !== undefined)
136
+ common.trimTop = options.trimTop;
137
+ const gearParams = {
138
+ module: params.module,
139
+ teeth_number: params.gear_teeth,
140
+ cone_angle: gearDeg,
141
+ face_width: params.face_width,
142
+ };
143
+ if (params.pressure_angle !== undefined)
144
+ gearParams.pressure_angle = params.pressure_angle;
145
+ if (params.helix_angle !== undefined)
146
+ gearParams.helix_angle = params.helix_angle;
147
+ if (params.clearance !== undefined)
148
+ gearParams.clearance = params.clearance;
149
+ if (params.backlash !== undefined)
150
+ gearParams.backlash = params.backlash;
151
+ const pinionParams = {
152
+ module: params.module,
153
+ teeth_number: params.pinion_teeth,
154
+ cone_angle: pinionDeg,
155
+ face_width: params.face_width,
156
+ };
157
+ if (params.pressure_angle !== undefined)
158
+ pinionParams.pressure_angle = params.pressure_angle;
159
+ // 旋向相反;`clearance` 故意不传(Python 同样没传)。
160
+ pinionParams.helix_angle = -(params.helix_angle ?? 0.0);
161
+ if (params.backlash !== undefined)
162
+ pinionParams.backlash = params.backlash;
163
+ const gearGeometry = bevelGearGeometry(gearParams);
164
+ const pinionGeometry = bevelGearGeometry(pinionParams);
165
+ const out = { gearGeometry, pinionGeometry, axisAngleDeg };
166
+ if (options.buildGear !== false) {
167
+ out.gear = buildBevelGearSolid(kernel, gearParams, common);
168
+ }
169
+ if (options.buildPinion !== false) {
170
+ let pinion = buildBevelGearSolid(kernel, pinionParams, common);
171
+ if (options.transformPinion !== false) {
172
+ pinion = placePinion(kernel, pinion, {
173
+ axisAngleDeg,
174
+ gearConeH: gearGeometry.coneH,
175
+ pinionConeH: pinionGeometry.coneH,
176
+ pinionTeeth: params.pinion_teeth,
177
+ });
178
+ }
179
+ out.pinion = pinion;
180
+ }
181
+ return out;
182
+ }
183
+ //# sourceMappingURL=pairs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pairs.js","sourceRoot":"","sources":["../src/pairs.ts"],"names":[],"mappings":"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"}