@rocon/balcan 0.0.3 → 1.0.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.
@@ -1,3 +1,4 @@
1
+ /** 비트맵 처리 관련 함수 */
1
2
  export declare namespace bitmap {
2
3
  /** data URL 이미지를 상하 반전한 새 data URL 반환 */
3
4
  function flipVertical(dataUrl: string): Promise<string>;
@@ -1,3 +1,4 @@
1
+ /** 비트맵 처리 관련 함수 */
1
2
  export var bitmap;
2
3
  (function (bitmap) {
3
4
  /** data URL 이미지를 상하 반전한 새 data URL 반환 */
@@ -1,40 +1,78 @@
1
- import type Konva from 'konva';
2
1
  import type { KonvaEventObject } from 'konva/lib/Node';
2
+ import Konva from 'konva';
3
3
  import { Subject } from 'rxjs';
4
- import type { Scene, Actor, Staff } from './types.balcan';
5
- export declare function useBalcan(): {
6
- createDirector: (name: string, stage: Konva.Stage) => Director | undefined;
7
- directors: Readonly<{
8
- [k: string]: Director;
9
- }>;
10
- };
4
+ import type { Actor, BalcanStage, Scene, Staff } from './types.balcan';
5
+ /**
6
+ * Director 생성
7
+ * @param divQuerySelector Konva.Stage 가 생성될 div 의 querySelector
8
+ */
9
+ export declare function createDirector(divQuerySelector: string): Director | undefined;
10
+ export declare function getDirector(divQuerySelector: string): Director | undefined;
11
+ /**
12
+ * 기존 Director 를 회수합니다
13
+ * @param divQuerySelector Director 가 생성된 div 의 querySelector
14
+ */
15
+ export declare function destroyDirector(divQuerySelector: string): void;
16
+ /**
17
+ * 디렉터는 하나의 Konva.Stage 와 그 위에 올라올 수 있는 Balcan 요소들을 Containing 합니다.
18
+ * Konva.Stage 는 보통 하나의 div 에 매칭되기 때문에 Director 역시 하나의 Div와 매칭된다고 봐도 좋습니다.
19
+ */
11
20
  export declare class Director {
12
21
  readonly name: string;
13
- readonly stage: Konva.Stage;
14
- scenes: {
22
+ readonly _stage: Konva.Stage;
23
+ private _isPointerOverStage;
24
+ readonly scenes: {
15
25
  [k: string]: Scene;
16
26
  };
17
- actors: {
27
+ readonly actors: {
18
28
  [k: string]: Actor;
19
29
  };
20
- staffs: {
30
+ readonly staffs: {
21
31
  [k: string]: Staff;
22
32
  };
23
33
  constructor(name: string, stage: Konva.Stage);
24
- private _doubleClickEvent;
34
+ /** 내부의 모든 자원을 회수합니다 */
35
+ dispose(): void;
36
+ private _clickHandler;
37
+ /**
38
+ * 이 클래스의 set scale 을 사용하여 스케일 변경시 발생하는 이벤트
39
+ */
25
40
  onScaleChanged$: Subject<{
26
41
  scale: number;
27
42
  }>;
28
- onMouseDoubleClicked$: Subject<KonvaEventObject<MouseEvent, import("konva/lib/Stage").Stage>>;
43
+ /**
44
+ * stage 에서 더블 클릭 이벤트
45
+ */
46
+ onMouseDoubleClicked$: Subject<KonvaEventObject<MouseEvent, BalcanStage>>;
47
+ /**
48
+ * stage 에서 키보드 down 이벤트
49
+ */
29
50
  onKeyDown$: Subject<KeyboardEvent>;
51
+ /** addEventListener 로 등록 시 일반 메서드는 this 가 컨테이너로 바뀌므로 화살표로 바인딩 */
52
+ private _keydownHandler;
53
+ private _mouseenterHandler;
54
+ private _mouseleaveHandler;
55
+ /**
56
+ * director 에 scene 을 추가하는 메서드
57
+ */
30
58
  addScene(scene: Scene): {
31
59
  type: any;
32
60
  uniqueId: string;
33
61
  data: any;
34
62
  director: import("./types.balcan").Director;
63
+ onDestroy: () => void;
35
64
  };
65
+ /**
66
+ * stage 에서 scene 을 제거합니다. scene 에서 정의한 onDestory 를 호출해서 클리어를 유도 합니다
67
+ */
36
68
  removeScene(uniqueId: string): void;
69
+ /**
70
+ * stage 에서 모든 scene 을 제거합니다.
71
+ */
37
72
  removeAllScenes(): void;
73
+ /**
74
+ * stage 에 actor 을 추가합니다.
75
+ */
38
76
  addActor(actor: Actor): {
39
77
  type: any;
40
78
  entityId: string;
@@ -45,13 +83,22 @@ export declare class Director {
45
83
  addPlugin?: (plugin: import("./types.balcan").Plugin) => void;
46
84
  removePlugin?: (pluginKey: string) => void;
47
85
  onDestroy?: () => void;
48
- onBeforeRender?: () => void;
49
- onRender?: () => void;
50
- onUpdate?: () => void;
51
86
  };
87
+ /**
88
+ * actor 의 id 를 변경할 수 있습니다
89
+ */
52
90
  changeActorId(oldId: string, newId: string): void;
91
+ /**
92
+ * stage 에서 actor 을 제거합니다. actor 에서 정의한 onDestory 를 호출해서 클리어를 유도 합니다
93
+ */
53
94
  removeActor(uniqueId: string): void;
95
+ /**
96
+ * stage 에서 모든 actor 을 제거합니다.
97
+ */
54
98
  removeAllActors(): void;
99
+ /**
100
+ * stage 에 staff 을 추가합니다.
101
+ */
55
102
  addStaff(staff: Staff): {
56
103
  type: any;
57
104
  entityId: string;
@@ -62,12 +109,66 @@ export declare class Director {
62
109
  addPlugin?: (plugin: import("./types.balcan").Plugin) => void;
63
110
  removePlugin?: (pluginKey: string) => void;
64
111
  onDestroy?: () => void;
65
- onBeforeRender?: () => void;
66
- onRender?: () => void;
67
112
  };
113
+ /**
114
+ * stage 에서 모든 staff 을 제거합니다.
115
+ */
68
116
  removeAllStaffs(): void;
117
+ /**
118
+ * stage 에서 staff 을 제거합니다. staff 에서 정의한 onDestory 를 호출해서 클리어를 유도 합니다
119
+ */
69
120
  removeStaff(uniqueId: string): void;
121
+ get stage(): BalcanStage;
122
+ /** 마우스 포인터가 stage(div) 위에 있는지 여부 */
123
+ get isPointerOverStage(): boolean;
124
+ /**
125
+ * stage 의 현재 scale 을 반환합니다
126
+ */
70
127
  get scale(): number;
128
+ /**
129
+ * stage 의 scale 을 변경합니다
130
+ */
71
131
  set scale(scale: number);
72
- render(): void;
132
+ /** 마우스 커서 모양을 변경한다 */
133
+ changeMouseCursor(cursorStyle: string): void;
134
+ /** 현재 마우스 위치에 있는 첫 번째 shape 를 가져온다 */
135
+ pickShape(): import("konva/lib/Shape").Shape<import("konva/lib/Shape").ShapeConfig> | null;
136
+ /** 현재 마우스 위치에 있는 모든 shape 목록을 가져온다 */
137
+ pickShapes(): import("konva/lib/Shape").Shape<import("konva/lib/Shape").ShapeConfig>[];
138
+ /** 현재 마우스포인터의 pose + position 계산 */
139
+ getPointerPosePosition(originPoint: BalcanGeo.Vector2 | BalcanGeo.Pose, pixelPerMeter: number): BalcanGeo.PosePosition;
140
+ /** 여러 포지션을 변환하는 도구모음 클로져 */
141
+ positionConverter(): {
142
+ /** viewport 의 중심점은 월드좌표의 어디에 해당하는지 계산함 */
143
+ viewportCenterToWorld(): {
144
+ x: number;
145
+ y: number;
146
+ };
147
+ /** viewport 좌표를 월드좌표로 변환함 */
148
+ viewportToWorld(vector: BalcanGeo.Vector2): {
149
+ x: number;
150
+ y: number;
151
+ };
152
+ /** 월드좌표를 viewport 좌표로 변환함 */
153
+ worldToViewport(vector: BalcanGeo.Vector2): BalcanGeo.Vector2;
154
+ };
155
+ /**
156
+ * 어떠한 위치를 지정하여 viewport 의 중앙으로 가져다 놓는다
157
+ * (= 카메라 초점을 어떠한 위치로 이동한다)
158
+ */
159
+ moveCamera(params: MoveCameraParams): void;
73
160
  }
161
+ type MoveCameraParams = {
162
+ /** 지정한 shape 로 카메라를 이동함 */
163
+ type: 'shape';
164
+ shape: Konva.Shape | Konva.Group;
165
+ } | {
166
+ /** 지정한 viewport 좌표로 카메라를 이동함 */
167
+ type: 'viewportPosition';
168
+ vector: BalcanGeo.Vector2;
169
+ } | {
170
+ /** 지정한 월드 좌표로 카메라를 이동함 */
171
+ type: 'worldPosition';
172
+ vector: BalcanGeo.Vector2;
173
+ };
174
+ export {};
@@ -1,61 +1,123 @@
1
+ import Konva from 'konva';
1
2
  import { Subject } from 'rxjs';
2
- function balcanStore() {
3
- const _directors = {};
4
- function addDirector(director) {
5
- _directors[director.name] = director;
6
- }
7
- return {
8
- directors: _directors,
9
- addDirector,
10
- };
3
+ import { math } from './math.balcan';
4
+ import { util } from './util.balcan';
5
+ const directors = {};
6
+ /**
7
+ * 새 Director 를 생성
8
+ * @param divQuerySelector Konva.Stage 가 생성될 div 의 querySelector
9
+ */
10
+ export function createDirector(divQuerySelector) {
11
+ if (divQuerySelector in directors) {
12
+ console.error('Director with the same name already exists.');
13
+ return directors[divQuerySelector];
14
+ }
15
+ const div = document.querySelector(divQuerySelector);
16
+ if (!div) {
17
+ console.error('Div element not found.');
18
+ return undefined;
19
+ }
20
+ const stage = new Konva.Stage({
21
+ container: div,
22
+ width: div.clientWidth,
23
+ height: div.clientHeight,
24
+ draggable: true,
25
+ });
26
+ const director = new Director(divQuerySelector, stage);
27
+ directors[divQuerySelector] = director;
28
+ return director;
11
29
  }
12
- const $store = balcanStore();
13
- export function useBalcan() {
14
- return {
15
- createDirector,
16
- directors: $store.directors,
17
- };
18
- function createDirector(name, stage) {
19
- if (!stage) {
20
- console.error('Konva Stage is required to create a new stage.');
21
- return undefined;
22
- }
23
- const director = new Director(name, stage);
24
- $store.addDirector(director);
25
- return director;
30
+ export function getDirector(divQuerySelector) {
31
+ if (!(divQuerySelector in directors)) {
32
+ console.error(`Director with the name ${divQuerySelector} not found.`);
33
+ return undefined;
26
34
  }
35
+ return directors[divQuerySelector];
36
+ }
37
+ /**
38
+ * 기존 Director 를 회수합니다
39
+ * @param divQuerySelector Director 가 생성된 div 의 querySelector
40
+ */
41
+ export function destroyDirector(divQuerySelector) {
42
+ const director = directors[divQuerySelector];
43
+ director?.dispose();
44
+ delete directors[divQuerySelector];
27
45
  }
46
+ /**
47
+ * 디렉터는 하나의 Konva.Stage 와 그 위에 올라올 수 있는 Balcan 요소들을 Containing 합니다.
48
+ * Konva.Stage 는 보통 하나의 div 에 매칭되기 때문에 Director 역시 하나의 Div와 매칭된다고 봐도 좋습니다.
49
+ */
28
50
  export class Director {
29
51
  name;
30
- stage;
52
+ _stage;
53
+ _isPointerOverStage = false;
31
54
  scenes;
32
55
  actors;
33
56
  staffs;
34
57
  constructor(name, stage) {
35
58
  this.name = name;
36
- this.stage = stage;
59
+ this._stage = stage;
37
60
  this.staffs = {};
38
61
  this.scenes = {};
39
62
  this.actors = {};
40
- this._doubleClickEvent();
41
- stage.container().addEventListener('keydown', (e) => {
42
- this.onKeyDown$.next(e);
43
- });
44
- stage.on('click', () => {
45
- stage.container().tabIndex = 1;
46
- stage.container().focus();
47
- });
48
- }
49
- _doubleClickEvent() {
50
- this.stage.on('dblclick', (e) => {
63
+ util.stageDoubleClickEvent(stage, (e) => {
51
64
  this.onMouseDoubleClicked$.next(e);
52
- this.stage.off('dblclick');
53
- setTimeout(() => this._doubleClickEvent(), 400);
54
65
  });
66
+ stage.container().addEventListener('keydown', this._keydownHandler);
67
+ stage.container().addEventListener('mouseenter', this._mouseenterHandler);
68
+ stage.container().addEventListener('mouseleave', this._mouseleaveHandler);
69
+ stage.on('click', this._clickHandler);
70
+ }
71
+ /** 내부의 모든 자원을 회수합니다 */
72
+ dispose() {
73
+ this.removeAllScenes();
74
+ this.removeAllActors();
75
+ this.removeAllStaffs();
76
+ this._stage
77
+ .container()
78
+ .removeEventListener('keydown', this._keydownHandler);
79
+ this._stage
80
+ .container()
81
+ .removeEventListener('mouseenter', this._mouseenterHandler);
82
+ this._stage
83
+ .container()
84
+ .removeEventListener('mouseleave', this._mouseleaveHandler);
85
+ this._stage.off('click', this._clickHandler);
86
+ this._stage.off('dblclick');
87
+ this._stage.destroyChildren();
88
+ this._stage.destroy();
89
+ delete directors[this.name];
55
90
  }
91
+ _clickHandler(e) {
92
+ e.currentTarget.container().tabIndex = 1;
93
+ e.currentTarget.container().focus();
94
+ }
95
+ /**
96
+ * 이 클래스의 set scale 을 사용하여 스케일 변경시 발생하는 이벤트
97
+ */
56
98
  onScaleChanged$ = new Subject();
99
+ /**
100
+ * stage 에서 더블 클릭 이벤트
101
+ */
57
102
  onMouseDoubleClicked$ = new Subject();
103
+ /**
104
+ * stage 에서 키보드 down 이벤트
105
+ */
58
106
  onKeyDown$ = new Subject();
107
+ /** addEventListener 로 등록 시 일반 메서드는 this 가 컨테이너로 바뀌므로 화살표로 바인딩 */
108
+ _keydownHandler = (e) => {
109
+ if (this.onKeyDown$)
110
+ this.onKeyDown$.next(e);
111
+ };
112
+ _mouseenterHandler = () => {
113
+ this._isPointerOverStage = true;
114
+ };
115
+ _mouseleaveHandler = () => {
116
+ this._isPointerOverStage = false;
117
+ };
118
+ /**
119
+ * director 에 scene 을 추가하는 메서드
120
+ */
59
121
  addScene(scene) {
60
122
  if (this.scenes[scene.uniqueId]) {
61
123
  console.error('Scene with the same uniqueId already exists.');
@@ -64,19 +126,31 @@ export class Director {
64
126
  this.scenes[scene.uniqueId] = scene;
65
127
  return scene;
66
128
  }
129
+ /**
130
+ * stage 에서 scene 을 제거합니다. scene 에서 정의한 onDestory 를 호출해서 클리어를 유도 합니다
131
+ */
67
132
  removeScene(uniqueId) {
68
- // this.scenes[uniqueId]?.onDestroy?.();
133
+ this.scenes[uniqueId]?.onDestroy();
69
134
  delete this.scenes[uniqueId];
70
135
  }
136
+ /**
137
+ * stage 에서 모든 scene 을 제거합니다.
138
+ */
71
139
  removeAllScenes() {
72
140
  Object.keys(this.scenes).forEach((k) => {
73
141
  this.removeScene(k);
74
142
  });
75
143
  }
144
+ /**
145
+ * stage 에 actor 을 추가합니다.
146
+ */
76
147
  addActor(actor) {
77
148
  this.actors[actor.uniqueId] = actor;
78
149
  return actor;
79
150
  }
151
+ /**
152
+ * actor 의 id 를 변경할 수 있습니다
153
+ */
80
154
  changeActorId(oldId, newId) {
81
155
  const actor = this.actors[oldId];
82
156
  if (!actor)
@@ -85,52 +159,159 @@ export class Director {
85
159
  this.actors[newId] = actor;
86
160
  delete this.actors[oldId];
87
161
  }
162
+ /**
163
+ * stage 에서 actor 을 제거합니다. actor 에서 정의한 onDestory 를 호출해서 클리어를 유도 합니다
164
+ */
88
165
  removeActor(uniqueId) {
89
166
  this.actors[uniqueId]?.onDestroy?.();
90
167
  delete this.actors[uniqueId];
91
168
  }
169
+ /**
170
+ * stage 에서 모든 actor 을 제거합니다.
171
+ */
92
172
  removeAllActors() {
93
173
  Object.keys(this.actors).forEach((k) => {
94
174
  this.removeActor(k);
95
175
  });
96
176
  }
177
+ /**
178
+ * stage 에 staff 을 추가합니다.
179
+ */
97
180
  addStaff(staff) {
98
181
  this.staffs[staff.uniqueId] = staff;
99
182
  return staff;
100
183
  }
184
+ /**
185
+ * stage 에서 모든 staff 을 제거합니다.
186
+ */
101
187
  removeAllStaffs() {
102
188
  Object.keys(this.staffs).forEach((k) => {
103
189
  this.removeStaff(k);
104
190
  });
105
191
  }
192
+ /**
193
+ * stage 에서 staff 을 제거합니다. staff 에서 정의한 onDestory 를 호출해서 클리어를 유도 합니다
194
+ */
106
195
  removeStaff(uniqueId) {
107
196
  this.staffs[uniqueId]?.onDestroy?.();
108
197
  delete this.staffs[uniqueId];
109
198
  }
199
+ get stage() {
200
+ return this._stage;
201
+ }
202
+ /** 마우스 포인터가 stage(div) 위에 있는지 여부 */
203
+ get isPointerOverStage() {
204
+ return this._isPointerOverStage;
205
+ }
206
+ /**
207
+ * stage 의 현재 scale 을 반환합니다
208
+ */
110
209
  get scale() {
111
- return this.stage.scale().x;
210
+ return this._stage.scale().x;
112
211
  }
212
+ /**
213
+ * stage 의 scale 을 변경합니다
214
+ */
113
215
  set scale(scale) {
114
- this.stage.scale({
216
+ this._stage.scale({
115
217
  x: scale,
116
218
  y: scale,
117
219
  });
118
220
  this.onScaleChanged$.next({ scale });
119
221
  }
120
- render() {
121
- for (const uniqueId in this.staffs) {
122
- const staff = this.staffs[uniqueId];
123
- staff.onBeforeRender?.();
124
- staff.plugins.forEach((x) => x.onBeforeRender?.());
125
- staff.onRender?.();
126
- staff.plugins.forEach((x) => x.onRender?.());
222
+ /** 마우스 커서 모양을 변경한다 */
223
+ changeMouseCursor(cursorStyle) {
224
+ this.stage.container().style.cursor = cursorStyle;
225
+ }
226
+ /** 현재 마우스 위치에 있는 첫 번째 shape 를 가져온다 */
227
+ pickShape() {
228
+ return this.stage.getIntersection(this.stage.getPointerPosition() ?? {
229
+ x: 0,
230
+ y: 0,
231
+ });
232
+ }
233
+ /** 현재 마우스 위치에 있는 모든 shape 목록을 가져온다 */
234
+ pickShapes() {
235
+ return this.stage.getAllIntersections(this.stage.getPointerPosition() ?? {
236
+ x: 0,
237
+ y: 0,
238
+ });
239
+ }
240
+ /** 현재 마우스포인터의 pose + position 계산 */
241
+ getPointerPosePosition(originPoint, pixelPerMeter) {
242
+ if (!this.isPointerOverStage) {
243
+ return {
244
+ pose: {
245
+ x: 0,
246
+ y: 0,
247
+ theta: 0,
248
+ },
249
+ position: {
250
+ stagex: 0,
251
+ stagey: 0,
252
+ degree: 0,
253
+ },
254
+ };
255
+ }
256
+ const pointer = this.stage.getRelativePointerPosition();
257
+ const position = {
258
+ stagex: pointer?.x ?? 0,
259
+ stagey: pointer?.y ?? 0,
260
+ degree: 0,
261
+ };
262
+ const pose = math.transformPosition(position, originPoint, pixelPerMeter);
263
+ return {
264
+ pose,
265
+ position,
266
+ };
267
+ }
268
+ /** 여러 포지션을 변환하는 도구모음 클로져 */
269
+ positionConverter() {
270
+ // eslint-disable-next-line @typescript-eslint/no-this-alias
271
+ const director = this;
272
+ return {
273
+ /** viewport 의 중심점은 월드좌표의 어디에 해당하는지 계산함 */
274
+ viewportCenterToWorld() {
275
+ return this.viewportToWorld({
276
+ x: director.stage.width() / 2,
277
+ y: director.stage.height() / 2,
278
+ });
279
+ },
280
+ /** viewport 좌표를 월드좌표로 변환함 */
281
+ viewportToWorld(vector) {
282
+ const offset = math.vectorSubtract(vector, director.stage.getAbsolutePosition());
283
+ return math.vectorDivide(offset, director.scale);
284
+ },
285
+ /** 월드좌표를 viewport 좌표로 변환함 */
286
+ worldToViewport(vector) {
287
+ const scaledOffset = math.vectorMultiply(vector, director.scale);
288
+ return math.vectorAdd(director.stage.getAbsolutePosition(), scaledOffset);
289
+ },
290
+ };
291
+ }
292
+ /**
293
+ * 어떠한 위치를 지정하여 viewport 의 중앙으로 가져다 놓는다
294
+ * (= 카메라 초점을 어떠한 위치로 이동한다)
295
+ */
296
+ moveCamera(params) {
297
+ if (params.type === 'viewportPosition') {
298
+ const moveVector = math.vectorSubtract({
299
+ x: this.stage.width() / 2,
300
+ y: this.stage.height() / 2,
301
+ }, params.vector);
302
+ this.stage.absolutePosition(math.vectorAdd(this.stage.getAbsolutePosition(), moveVector));
303
+ }
304
+ if (params.type === 'worldPosition') {
305
+ const centerWorldPosition = this.positionConverter().viewportCenterToWorld();
306
+ const moveVector = math.vectorSubtract(centerWorldPosition, params.vector);
307
+ const scaledMoveVector = math.vectorMultiply(moveVector, this.scale);
308
+ this.stage.absolutePosition(math.vectorAdd(this.stage.getAbsolutePosition(), scaledMoveVector));
127
309
  }
128
- for (const uniqueId in this.actors) {
129
- const actor = this.actors[uniqueId];
130
- actor.onBeforeRender?.();
131
- actor.plugins.forEach((x) => x.onBeforeRender?.());
132
- actor.onRender?.();
133
- actor.plugins.forEach((x) => x.onRender?.());
310
+ else if (params.type === 'shape') {
311
+ this.moveCamera({
312
+ type: 'viewportPosition',
313
+ vector: params.shape.getAbsolutePosition(),
314
+ });
134
315
  }
135
316
  }
136
317
  }
@@ -1,4 +1,6 @@
1
+ /** 일반 수학과 기하학 관련 계산 함수들을 모아둔 네임스페이스 */
1
2
  export declare namespace math {
3
+ /** 주어진 숫자들의 평균을 구한다 */
2
4
  function average(...values: number[]): number;
3
5
  function radian(deg: number, opt?: {
4
6
  invertY?: boolean;
@@ -28,8 +30,73 @@ export declare namespace math {
28
30
  }): number;
29
31
  /** 벡터 덧셈 */
30
32
  function vectorAdd<T extends BalcanGeo.Vector2 | BalcanGeo.Pose>(v1: T, v2: T): T;
33
+ /** 벡터 뺄셈 */
34
+ function vectorSubtract<T extends BalcanGeo.Vector2 | BalcanGeo.Pose>(v1: T, v2: T): T;
35
+ /** 벡터 곱셈 */
36
+ function vectorMultiply<T extends BalcanGeo.Vector2 | BalcanGeo.Pose>(v1: T, scalar: number): T;
37
+ /** 벡터 나눗셈 */
38
+ function vectorDivide<T extends BalcanGeo.Vector2 | BalcanGeo.Pose>(v1: T, scalar: number): T;
31
39
  /** 벡터 내적 */
32
40
  function vectorDot<T extends BalcanGeo.Vector2 | BalcanGeo.Pose>(v1: T, v2: T): number;
33
- /** position like 자료형을 vector2d 로 변환함 */
41
+ /** 좌표형 자료형 (Position, Pose) 를 vector2d 로 변환함 */
34
42
  function vector2d<T extends BalcanGeo.Vector2 | BalcanGeo.Position | BalcanGeo.Pose>(point: T): BalcanGeo.Vector2;
43
+ /** 벡터들 에 회전 행렬 적용 */
44
+ function rotateVectors(params: {
45
+ /** 회전할 점들 */
46
+ points: BalcanGeo.Vector2[];
47
+ /** 회전 각도 */
48
+ rotateAngle: number;
49
+ /** 회전 각도 단위 */
50
+ angleUnit?: 'degree' | 'radian';
51
+ /** 중심점 */
52
+ centerPosition?: BalcanGeo.Vector2;
53
+ /** Y방향 반전? true 를 할경우 회전방향이 시계방향이 되는 효과가 있음. */
54
+ invertY?: boolean;
55
+ }): {
56
+ x: number;
57
+ y: number;
58
+ }[];
59
+ /**
60
+ * 어떤 점 P와 어떤 선분 S가 있다고 할 때
61
+ * 선분 S 위에 존재할 수 있는 무수한 점들 중 - P에서 가장 가까운 점 X를 찾는다
62
+ * @param point 점 위치벡터 P
63
+ * @param segmentPosition 선분 S의 정의 (양 끝점의 좌표)
64
+ * @returns X점의 좌표 벡터
65
+ */
66
+ function nearestPointOnSegment(point: BalcanGeo.Vector2, segmentPosition: [BalcanGeo.Vector2, BalcanGeo.Vector2] | [BalcanGeo.Pose, BalcanGeo.Pose]): BalcanGeo.Vector2;
67
+ /**
68
+ * 주어진 점이 주어진 다각형 내부에 있는지 확인
69
+ * @param point 점의 좌표
70
+ * @param polygon 다각형의 정의 (점들의 좌표)
71
+ * @returns 점이 다각형 내부에 있는지 여부
72
+ */
73
+ function isPointInPolygon(point: BalcanGeo.Vector2, polygon: BalcanGeo.Vector2[]): boolean;
74
+ /**
75
+ * originPoint 와 endPoint 를 잇는 선분을 가정하고
76
+ * extendLength 만큼 양쪽으로 늘이거나 줄인 선분을 반환
77
+ * (extendLength는 음수일 수도 있음)
78
+ */
79
+ function extendSegment(params: {
80
+ originPoint: BalcanGeo.Vector2;
81
+ endPoint: BalcanGeo.Vector2;
82
+ extendLengthFromOrigin: number;
83
+ extendLengthFromEnd: number;
84
+ }): {
85
+ origin: BalcanGeo.Vector2;
86
+ end: BalcanGeo.Vector2;
87
+ };
88
+ /**
89
+ * 실좌표계 상 위치 (Pose) 를 화면좌표계로 변환
90
+ * @param pose 실좌표계 상의 위치
91
+ * @param origin 원점을 삼으려는 화면좌표계 상 좌표
92
+ * @param pixelPerMeter 1미터당 픽셀 수
93
+ */
94
+ function transformPose(pose: BalcanGeo.Pose, origin: BalcanGeo.Vector2, pixelPerMeter: number): BalcanGeo.Position;
95
+ /**
96
+ * 화면좌표계상 위치를 실좌표계로 변환
97
+ * @param position
98
+ * @param realOrigin 원점을 삼으려는 화면좌표계 상 좌표
99
+ * @param pixelPerMeter 1미터당 픽셀 수
100
+ */
101
+ function transformPosition(position: BalcanGeo.Position, realOrigin: BalcanGeo.Vector2, pixelPerMeter: number): BalcanGeo.Pose;
35
102
  }