RepliCAD
114 строк · 3.0 Кб
1import type { gp_Ax2 } from "replicad-opencascadejs";
2import { asDir, asPnt, makeAx2, Point, Vector } from "../geom";
3import type { BoundingBox } from "../geom";
4import { WrappingObj } from "../register";
5export type CubeFace = "front" | "back" | "top" | "bottom" | "left" | "right";
6export type ProjectionPlane =
7| "XY"
8| "XZ"
9| "YZ"
10| "YX"
11| "ZX"
12| "ZY"
13| "front"
14| "back"
15| "top"
16| "bottom"
17| "left"
18| "right";
19
20const PROJECTION_PLANES: Record<ProjectionPlane, { dir: Point; xAxis: Point }> =
21{
22XY: { dir: [0, 0, 1], xAxis: [1, 0, 0] },
23XZ: { dir: [0, -1, 0], xAxis: [1, 0, 0] },
24YZ: { dir: [1, 0, 0], xAxis: [0, 1, 0] },
25YX: { dir: [0, 0, -1], xAxis: [0, 1, 0] },
26ZX: { dir: [0, 1, 0], xAxis: [0, 0, 1] },
27ZY: { dir: [-1, 0, 0], xAxis: [0, 0, 1] },
28
29front: { dir: [0, -1, 0], xAxis: [1, 0, 0] },
30back: { dir: [0, 1, 0], xAxis: [-1, 0, 0] },
31right: { dir: [-1, 0, 0], xAxis: [0, -1, 0] },
32left: { dir: [1, 0, 0], xAxis: [0, 1, 0] },
33bottom: { dir: [0, 0, 1], xAxis: [1, 0, 0] },
34top: { dir: [0, 0, -1], xAxis: [1, 0, 0] },
35};
36
37export function isProjectionPlane(plane: unknown): plane is ProjectionPlane {
38return typeof plane === "string" && plane in PROJECTION_PLANES;
39}
40
41export function lookFromPlane(projectionPlane: ProjectionPlane) {
42const { dir, xAxis } = PROJECTION_PLANES[projectionPlane];
43return new ProjectionCamera([0, 0, 0], dir, xAxis);
44}
45
46function defaultXDir(direction: Point) {
47const dir = new Vector(direction);
48let yAxis: Point = new Vector([0, 0, 1]);
49let xAxis: Point = yAxis.cross(dir);
50if (xAxis.Length === 0) {
51yAxis = new Vector([0, 1, 0]);
52xAxis = yAxis.cross(dir);
53}
54return xAxis.normalize();
55}
56
57export class ProjectionCamera extends WrappingObj<gp_Ax2> {
58constructor(
59position: Point = [0, 0, 0],
60direction: Point = [0, 0, 1],
61xAxis?: Point
62) {
63const xDir = xAxis ? new Vector(xAxis) : defaultXDir(direction);
64const ax2 = makeAx2(position, direction, xDir);
65super(ax2);
66}
67
68get position() {
69return new Vector(this.wrapped.Location());
70}
71
72get direction() {
73return new Vector(this.wrapped.Direction());
74}
75
76get xAxis() {
77return new Vector(this.wrapped.XDirection());
78}
79
80get yAxis() {
81return new Vector(this.wrapped.YDirection());
82}
83
84autoAxes() {
85const xAxis = defaultXDir(this.direction);
86this.wrapped.SetXDirection(asDir(xAxis));
87}
88
89setPosition(position: Point) {
90this.wrapped.SetLocation(asPnt(position));
91return this;
92}
93
94setXAxis(xAxis: Point) {
95this.wrapped.SetYDirection(asDir(xAxis));
96return this;
97}
98
99setYAxis(yAxis: Point) {
100this.wrapped.SetYDirection(asDir(yAxis));
101return this;
102}
103
104lookAt(shape: { boundingBox: BoundingBox } | Point) {
105const lootAtPoint = new Vector(
106"boundingBox" in shape ? shape.boundingBox.center : shape
107);
108const direction = this.position.sub(lootAtPoint).normalized();
109
110this.wrapped.SetDirection(direction.toDir());
111this.autoAxes();
112return this;
113}
114}
115