feat: scene -> standard
This commit is contained in:
parent
6319afa218
commit
7da2ac2f2a
46
scene.md
Normal file
46
scene.md
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
# 标准地图数据结构
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface StandardScene {
|
||||||
|
robotGroups?: Array<RobotGroup>; // 机器人组信息
|
||||||
|
robots?: Array<RobotInfo>; // 机器人信息
|
||||||
|
points?: Array<StandardScenePoint>; // 标准点位信息
|
||||||
|
routes?: Array<StandardSceneRoute>; // 标准线路信息
|
||||||
|
areas?: Array<StandardSceneArea>; // 标准区域信息
|
||||||
|
blocks?: Array<[number, number]>; // 障碍点集合
|
||||||
|
}
|
||||||
|
interface StandardScenePoint {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
x: number;
|
||||||
|
y: number;
|
||||||
|
type: number; // 点位类型
|
||||||
|
robots?: Array<string>; // 绑定机器人id集合
|
||||||
|
actions?: Array<string>; // 绑定动作点id集合
|
||||||
|
config?: object; // 其它属性配置(可按需增加)
|
||||||
|
properties?: unknown; // 附加数据(前端不做任何处理)
|
||||||
|
}
|
||||||
|
interface StandardSceneRoute {
|
||||||
|
id: string;
|
||||||
|
connect: [string, string]; // 连接点位id
|
||||||
|
type: 'line' | 'bezier2' | 'bezier3'; // 线路类型
|
||||||
|
pass?: number; // 可通行类型
|
||||||
|
c1?: { x?: number; y?: number }; // 控制点1
|
||||||
|
c2?: { x?: number; y?: number }; // 控制点2
|
||||||
|
config?: object; // 其它属性配置(可按需增加)
|
||||||
|
properties?: unknown; // 附加数据(前端不做任何处理)
|
||||||
|
}
|
||||||
|
interface StandardSceneArea {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
x: number;
|
||||||
|
y: number;
|
||||||
|
w: number;
|
||||||
|
h: number;
|
||||||
|
type: number; // 区域类型
|
||||||
|
points?: Array<string>; // 绑定点位id集合
|
||||||
|
routes?: Array<string>; // 绑定线路id集合
|
||||||
|
config?: object; // 其它属性配置(可按需增加)
|
||||||
|
properties?: unknown; // 附加数据(前端不做任何处理)
|
||||||
|
}
|
||||||
|
```
|
@ -14,8 +14,6 @@ export enum MapPointType {
|
|||||||
停靠点,
|
停靠点,
|
||||||
动作点,
|
动作点,
|
||||||
禁行点,
|
禁行点,
|
||||||
|
|
||||||
障碍点 = 99,
|
|
||||||
}
|
}
|
||||||
export const MAP_POINT_TYPES = Object.freeze(
|
export const MAP_POINT_TYPES = Object.freeze(
|
||||||
<[string, MapPointType][]>Object.entries(MapPointType).filter(([, v]) => typeof v === 'number'),
|
<[string, MapPointType][]>Object.entries(MapPointType).filter(([, v]) => typeof v === 'number'),
|
||||||
@ -25,6 +23,7 @@ export const MAP_POINT_TYPES = Object.freeze(
|
|||||||
//#region 线路
|
//#region 线路
|
||||||
export enum MapRouteType {
|
export enum MapRouteType {
|
||||||
直线 = 'line',
|
直线 = 'line',
|
||||||
|
二阶贝塞尔曲线 = 'bezier2',
|
||||||
三阶贝塞尔曲线 = 'bezier3',
|
三阶贝塞尔曲线 = 'bezier3',
|
||||||
}
|
}
|
||||||
export const MAP_ROUTE_TYPE = invert(MapRouteType);
|
export const MAP_ROUTE_TYPE = invert(MapRouteType);
|
||||||
|
@ -13,6 +13,8 @@ export interface MapPen extends Pen {
|
|||||||
|
|
||||||
attrs?: Record<string, unknown>; // 额外属性
|
attrs?: Record<string, unknown>; // 额外属性
|
||||||
activeAttrs?: Array<string>; // 已激活的额外属性
|
activeAttrs?: Array<string>; // 已激活的额外属性
|
||||||
|
|
||||||
|
properties?: unknown; // 第三方附加参数
|
||||||
}
|
}
|
||||||
|
|
||||||
//#region 点位
|
//#region 点位
|
||||||
@ -30,8 +32,8 @@ export interface MapRouteInfo {
|
|||||||
type: MapRouteType; // 线路类型
|
type: MapRouteType; // 线路类型
|
||||||
direction?: -1 | 1; // 方向
|
direction?: -1 | 1; // 方向
|
||||||
pass?: MapRoutePassType; // 可通行类型
|
pass?: MapRoutePassType; // 可通行类型
|
||||||
c1?: Point; // 控制点A
|
c1?: Point; // 控制点1
|
||||||
c2?: Point; // 控制点B
|
c2?: Point; // 控制点2
|
||||||
}
|
}
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
|
@ -9,11 +9,58 @@ export interface SceneDetail extends SceneInfo {
|
|||||||
json?: string; // 场景JSON
|
json?: string; // 场景JSON
|
||||||
}
|
}
|
||||||
export interface GroupSceneDetail extends SceneDetail {
|
export interface GroupSceneDetail extends SceneDetail {
|
||||||
group: RobotGroup;
|
group: RobotGroup; // 机器人组信息
|
||||||
robots?: Array<RobotInfo>;
|
robots?: Array<RobotInfo>; // 机器人信息
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SceneData extends Meta2dData {
|
export interface SceneData extends Meta2dData {
|
||||||
robots?: Array<RobotInfo>;
|
robotGroups?: Array<RobotGroup>; // 机器人组信息
|
||||||
robotGroups?: Array<RobotGroup>;
|
robots?: Array<RobotInfo>; // 机器人信息
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface StandardScene {
|
||||||
|
robotGroups?: Array<RobotGroup>; // 机器人组信息
|
||||||
|
robots?: Array<RobotInfo>; // 机器人信息
|
||||||
|
points?: Array<StandardScenePoint>; // 标准点位信息
|
||||||
|
routes?: Array<StandardSceneRoute>; // 标准线路信息
|
||||||
|
areas?: Array<StandardSceneArea>; // 标准区域信息
|
||||||
|
blocks?: Array<[number, number]>; // 障碍点集合
|
||||||
|
}
|
||||||
|
export interface StandardScenePoint {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
desc?: string; // 描述
|
||||||
|
x: number;
|
||||||
|
y: number;
|
||||||
|
type: number; // 点位类型
|
||||||
|
robots?: Array<string>; // 绑定机器人id集合
|
||||||
|
actions?: Array<string>; // 绑定动作点id集合
|
||||||
|
config?: object; // 其它属性配置(可按需增加)
|
||||||
|
properties?: unknown; // 附加数据(前端不做任何处理)
|
||||||
|
}
|
||||||
|
export interface StandardSceneRoute {
|
||||||
|
id: string;
|
||||||
|
desc?: string; // 描述
|
||||||
|
from: string; // 起点点位id
|
||||||
|
to: string; // 终点点位id
|
||||||
|
type: 'line' | 'bezier2' | 'bezier3'; // 线路类型
|
||||||
|
pass?: number; // 可通行类型
|
||||||
|
c1?: { x?: number; y?: number }; // 控制点1
|
||||||
|
c2?: { x?: number; y?: number }; // 控制点2
|
||||||
|
config?: object; // 其它属性配置(可按需增加)
|
||||||
|
properties?: unknown; // 附加数据(前端不做任何处理)
|
||||||
|
}
|
||||||
|
export interface StandardSceneArea {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
desc?: string; // 描述
|
||||||
|
x: number;
|
||||||
|
y: number;
|
||||||
|
w: number;
|
||||||
|
h: number;
|
||||||
|
type: number; // 区域类型
|
||||||
|
points?: Array<string>; // 绑定点位id集合
|
||||||
|
routes?: Array<string>; // 绑定线路id集合
|
||||||
|
config?: object; // 其它属性配置(可按需增加)
|
||||||
|
properties?: unknown; // 附加数据(前端不做任何处理)
|
||||||
}
|
}
|
||||||
|
@ -92,8 +92,11 @@ const route = computed<MapRouteInfo | null>(() => {
|
|||||||
</a-col>
|
</a-col>
|
||||||
</a-row>
|
</a-row>
|
||||||
|
|
||||||
<template v-if="MapRouteType.三阶贝塞尔曲线 === route.type">
|
<a-row
|
||||||
<a-row align="middle" :gutter="8">
|
v-if="[MapRouteType.二阶贝塞尔曲线, MapRouteType.三阶贝塞尔曲线].includes(route.type)"
|
||||||
|
align="middle"
|
||||||
|
:gutter="8"
|
||||||
|
>
|
||||||
<a-col flex="auto">
|
<a-col flex="auto">
|
||||||
<a-typography-text>{{ $t('控制点1') }}:</a-typography-text>
|
<a-typography-text>{{ $t('控制点1') }}:</a-typography-text>
|
||||||
</a-col>
|
</a-col>
|
||||||
@ -125,7 +128,7 @@ const route = computed<MapRouteInfo | null>(() => {
|
|||||||
</a-col>
|
</a-col>
|
||||||
</a-row>
|
</a-row>
|
||||||
|
|
||||||
<a-row align="middle" :gutter="8">
|
<a-row v-if="MapRouteType.三阶贝塞尔曲线 === route.type" align="middle" :gutter="8">
|
||||||
<a-col flex="auto">
|
<a-col flex="auto">
|
||||||
<a-typography-text>{{ $t('控制点2') }}:</a-typography-text>
|
<a-typography-text>{{ $t('控制点2') }}:</a-typography-text>
|
||||||
</a-col>
|
</a-col>
|
||||||
@ -156,7 +159,6 @@ const route = computed<MapRouteInfo | null>(() => {
|
|||||||
</a-space>
|
</a-space>
|
||||||
</a-col>
|
</a-col>
|
||||||
</a-row>
|
</a-row>
|
||||||
</template>
|
|
||||||
</a-flex>
|
</a-flex>
|
||||||
<a-empty v-else :image="sTheme.empty" />
|
<a-empty v-else :image="sTheme.empty" />
|
||||||
</a-card>
|
</a-card>
|
||||||
|
@ -12,15 +12,23 @@ import {
|
|||||||
type Point,
|
type Point,
|
||||||
} from '@api/map';
|
} from '@api/map';
|
||||||
import type { RobotGroup, RobotInfo } from '@api/robot';
|
import type { RobotGroup, RobotInfo } from '@api/robot';
|
||||||
import type { GroupSceneDetail, SceneData } from '@api/scene';
|
import type {
|
||||||
|
GroupSceneDetail,
|
||||||
|
SceneData,
|
||||||
|
StandardScene,
|
||||||
|
StandardSceneArea,
|
||||||
|
StandardScenePoint,
|
||||||
|
StandardSceneRoute,
|
||||||
|
} from '@api/scene';
|
||||||
import sTheme from '@core/theme.service';
|
import sTheme from '@core/theme.service';
|
||||||
import { CanvasLayer, LockState, Meta2d, type Meta2dStore, type Pen, s8 } from '@meta2d/core';
|
import { CanvasLayer, LockState, Meta2d, type Meta2dStore, type Pen, s8 } from '@meta2d/core';
|
||||||
import { useObservable } from '@vueuse/rxjs';
|
import { useObservable } from '@vueuse/rxjs';
|
||||||
import { clone, get, isNil, isString, pick, remove, some } from 'lodash-es';
|
import { clone, get, isEmpty, isNil, isString, pick, remove, some } from 'lodash-es';
|
||||||
import { BehaviorSubject, debounceTime, filter, map, Subject, switchMap } from 'rxjs';
|
import { BehaviorSubject, debounceTime, filter, map, Subject, switchMap } from 'rxjs';
|
||||||
import { reactive, watch } from 'vue';
|
import { reactive, watch } from 'vue';
|
||||||
|
|
||||||
export class EditorService extends Meta2d {
|
export class EditorService extends Meta2d {
|
||||||
|
//#region 场景文件
|
||||||
public async load(map?: string, editable = false, detail?: Partial<GroupSceneDetail>): Promise<void> {
|
public async load(map?: string, editable = false, detail?: Partial<GroupSceneDetail>): Promise<void> {
|
||||||
let data = map ? JSON.parse(map) : undefined;
|
let data = map ? JSON.parse(map) : undefined;
|
||||||
if (!isNil(detail)) {
|
if (!isNil(detail)) {
|
||||||
@ -32,22 +40,101 @@ export class EditorService extends Meta2d {
|
|||||||
this.setState(editable);
|
this.setState(editable);
|
||||||
}
|
}
|
||||||
public save(): string {
|
public save(): string {
|
||||||
const data = this.data();
|
const scene: StandardScene = {
|
||||||
data.pens.forEach((pen: MapPen) => {
|
robotGroups: this.robotGroups.value,
|
||||||
remove(pen.point?.robots ?? [], (v) => !this.#robotMap.has(v));
|
robots: this.robots,
|
||||||
remove(pen.point?.actions ?? [], (v) => this.getPenById(v)?.point?.type !== MapPointType.动作点);
|
points: this.points.value.map((v) => this.#mapScenePoint(v)).filter((v) => !isNil(v)),
|
||||||
remove(pen.area?.points ?? [], (v) => {
|
routes: this.routes.value.map((v) => this.#mapSceneRoute(v)).filter((v) => !isNil(v)),
|
||||||
const { point } = this.getPenById(v) ?? {};
|
areas: this.areas.value.map((v) => this.#mapSceneArea(v)).filter((v) => !isNil(v)),
|
||||||
if (isNil(point)) return true;
|
blocks: [],
|
||||||
if (point.type === MapPointType.禁行点) return true;
|
};
|
||||||
if (pen.area?.type === MapAreaType.库区 && point.type !== MapPointType.动作点) return true;
|
return JSON.stringify(scene);
|
||||||
return false;
|
|
||||||
});
|
|
||||||
remove(pen.area?.routes ?? [], (v) => isNil(this.getPenById(v)));
|
|
||||||
});
|
|
||||||
return JSON.stringify(data);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#mapScenePoint(pen?: MapPen): StandardScenePoint | null {
|
||||||
|
if (!pen?.id || isEmpty(pen?.point)) return null;
|
||||||
|
const { id, x = 0, y = 0, label, desc, properties } = pen;
|
||||||
|
const { type, robots, actions } = pen.point;
|
||||||
|
const point: StandardScenePoint = {
|
||||||
|
id: id,
|
||||||
|
name: label || id,
|
||||||
|
desc,
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
type,
|
||||||
|
config: {},
|
||||||
|
properties,
|
||||||
|
};
|
||||||
|
if ([MapPointType.充电点, MapPointType.停靠点].includes(type)) {
|
||||||
|
point.robots = robots?.filter((v) => this.#robotMap.has(v));
|
||||||
|
}
|
||||||
|
if (MapPointType.等待点 === type) {
|
||||||
|
point.actions = actions?.filter((v) => this.getPenById(v)?.point?.type === MapPointType.动作点);
|
||||||
|
}
|
||||||
|
return point;
|
||||||
|
}
|
||||||
|
#mapSceneRoute(pen?: MapPen): StandardSceneRoute | null {
|
||||||
|
if (!pen?.id || pen.anchors?.length !== 2 || isEmpty(pen?.route)) return null;
|
||||||
|
const { id, anchors, desc, properties } = pen;
|
||||||
|
const { type, direction = 1, pass, c1, c2 } = pen.route;
|
||||||
|
const [p1, p2] = anchors.map((v) => v.connectTo!);
|
||||||
|
const route: StandardSceneRoute = {
|
||||||
|
id: id,
|
||||||
|
desc,
|
||||||
|
from: direction < 0 ? p2 : p1,
|
||||||
|
to: direction < 0 ? p1 : p2,
|
||||||
|
type,
|
||||||
|
pass,
|
||||||
|
config: {},
|
||||||
|
properties,
|
||||||
|
};
|
||||||
|
switch (type) {
|
||||||
|
case MapRouteType.二阶贝塞尔曲线:
|
||||||
|
route.c1 = c1;
|
||||||
|
break;
|
||||||
|
case MapRouteType.三阶贝塞尔曲线:
|
||||||
|
route.c1 = direction < 0 ? c2 : c1;
|
||||||
|
route.c2 = direction < 0 ? c1 : c2;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return route;
|
||||||
|
}
|
||||||
|
#mapSceneArea(pen: MapPen): StandardSceneArea | null {
|
||||||
|
if (!pen.id || isEmpty(pen.area)) return null;
|
||||||
|
const { id, x = 0, y = 0, width = 0, height = 0, label, desc, properties } = pen;
|
||||||
|
const { type, points, routes } = pen.area;
|
||||||
|
const area: StandardSceneArea = {
|
||||||
|
id,
|
||||||
|
name: label || id,
|
||||||
|
desc,
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
w: width,
|
||||||
|
h: height,
|
||||||
|
type,
|
||||||
|
config: {},
|
||||||
|
properties,
|
||||||
|
};
|
||||||
|
if (MapAreaType.库区 === type) {
|
||||||
|
area.points = points?.filter((v) => this.getPenById(v)?.point?.type === MapPointType.动作点);
|
||||||
|
}
|
||||||
|
if ([MapAreaType.互斥区, MapAreaType.非互斥区].includes(type)) {
|
||||||
|
area.points = points?.filter((v) => {
|
||||||
|
const { point } = this.getPenById(v) ?? {};
|
||||||
|
if (isNil(point)) return false;
|
||||||
|
if (point.type === MapPointType.禁行点) return false;
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (MapAreaType.互斥区 === type) {
|
||||||
|
area.routes = routes?.filter((v) => !isEmpty(this.getPenById(v)?.area));
|
||||||
|
}
|
||||||
|
return area;
|
||||||
|
}
|
||||||
|
//#endregion
|
||||||
|
|
||||||
public setState(editable?: boolean): void {
|
public setState(editable?: boolean): void {
|
||||||
this.lock(editable ? LockState.None : LockState.DisableEdit);
|
this.lock(editable ? LockState.None : LockState.DisableEdit);
|
||||||
}
|
}
|
||||||
@ -458,6 +545,7 @@ export class EditorService extends Meta2d {
|
|||||||
this.register({ line: () => new Path2D() });
|
this.register({ line: () => new Path2D() });
|
||||||
this.registerCanvasDraw({ point: drawPoint, line: drawLine, area: drawArea });
|
this.registerCanvasDraw({ point: drawPoint, line: drawLine, area: drawArea });
|
||||||
this.registerAnchors({ point: anchorPoint });
|
this.registerAnchors({ point: anchorPoint });
|
||||||
|
this.addDrawLineFn('bezier2', lineBezier2);
|
||||||
this.addDrawLineFn('bezier3', lineBezier3);
|
this.addDrawLineFn('bezier3', lineBezier3);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -545,7 +633,7 @@ function drawLine(ctx: CanvasRenderingContext2D, pen: MapPen): void {
|
|||||||
const { x: x2 = 0, y: y2 = 0 } = p2 ?? {};
|
const { x: x2 = 0, y: y2 = 0 } = p2 ?? {};
|
||||||
const { type, direction = 1, pass = 0, c1, c2 } = pen.route ?? {};
|
const { type, direction = 1, pass = 0, c1, c2 } = pen.route ?? {};
|
||||||
const { x: dx1 = x2 - x1, y: dy1 = 0 } = c1 ?? {};
|
const { x: dx1 = x2 - x1, y: dy1 = 0 } = c1 ?? {};
|
||||||
const { x: dx2 = 0, y: dy2 = y2 - y1 } = c2 ?? {};
|
const { x: dx2 = 0, y: dy2 = y1 - y2 } = c2 ?? {};
|
||||||
|
|
||||||
ctx.save();
|
ctx.save();
|
||||||
ctx.beginPath();
|
ctx.beginPath();
|
||||||
@ -555,10 +643,15 @@ function drawLine(ctx: CanvasRenderingContext2D, pen: MapPen): void {
|
|||||||
case MapRouteType.直线:
|
case MapRouteType.直线:
|
||||||
ctx.lineTo(x2, y2);
|
ctx.lineTo(x2, y2);
|
||||||
break;
|
break;
|
||||||
|
case MapRouteType.二阶贝塞尔曲线:
|
||||||
|
ctx.quadraticCurveTo(x1 + dx1, y1 + dy1, x2, y2);
|
||||||
|
p1.next = { x: x1 + (2 / 3) * dx1, y: y1 + (2 / 3) * dy1 };
|
||||||
|
p2.prev = { x: x2 / 3 + (2 / 3) * (x1 + dx1), y: y2 / 3 + (2 / 3) * (y1 + dy1) };
|
||||||
|
break;
|
||||||
case MapRouteType.三阶贝塞尔曲线:
|
case MapRouteType.三阶贝塞尔曲线:
|
||||||
ctx.bezierCurveTo(x1 + dx1, y1 + dy1, x2 - dx2, y2 - dy2, x2, y2);
|
ctx.bezierCurveTo(x1 + dx1, y1 + dy1, x2 + dx2, y2 + dy2, x2, y2);
|
||||||
p1.next = { x: x1 + dx1, y: y1 + dy1 };
|
p1.next = { x: x1 + dx1, y: y1 + dy1 };
|
||||||
p2.prev = { x: x2 - dx2, y: y2 - dy2 };
|
p2.prev = { x: x2 + dx2, y: y2 + dy2 };
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@ -573,8 +666,10 @@ function drawLine(ctx: CanvasRenderingContext2D, pen: MapPen): void {
|
|||||||
switch (type) {
|
switch (type) {
|
||||||
case MapRouteType.直线:
|
case MapRouteType.直线:
|
||||||
return Math.atan2(y2 - y1, x2 - x1);
|
return Math.atan2(y2 - y1, x2 - x1);
|
||||||
|
case MapRouteType.二阶贝塞尔曲线:
|
||||||
|
return direction < 0 ? Math.atan2(dy1, dx1) : Math.atan2(y2 - y1 - dy1, x2 - x1 - dx1);
|
||||||
case MapRouteType.三阶贝塞尔曲线:
|
case MapRouteType.三阶贝塞尔曲线:
|
||||||
return direction < 0 ? Math.atan2(dy1, dx1) : Math.atan2(dy2, dx2);
|
return direction < 0 ? Math.atan2(dy1, dx1) : Math.atan2(-dy2, -dx2);
|
||||||
default:
|
default:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -592,6 +687,16 @@ function drawLine(ctx: CanvasRenderingContext2D, pen: MapPen): void {
|
|||||||
ctx.setTransform(1, 0, 0, 1, 0, 0);
|
ctx.setTransform(1, 0, 0, 1, 0, 0);
|
||||||
ctx.restore();
|
ctx.restore();
|
||||||
}
|
}
|
||||||
|
function lineBezier2(_: Meta2dStore, pen: MapPen): void {
|
||||||
|
if (pen.calculative?.worldAnchors?.length !== 2) return;
|
||||||
|
const { c1 } = pen.route ?? {};
|
||||||
|
const [p1, p2] = pen.calculative?.worldAnchors ?? [];
|
||||||
|
const { x: x1 = 0, y: y1 = 0 } = p1 ?? {};
|
||||||
|
const { x: x2 = 0, y: y2 = 0 } = p2 ?? {};
|
||||||
|
const { x: dx = x2 - x1, y: dy = 0 } = c1 ?? {};
|
||||||
|
pen.calculative.worldAnchors[0].next = { x: x1 + (2 / 3) * dx, y: y1 + (2 / 3) * dy };
|
||||||
|
pen.calculative.worldAnchors[1].prev = { x: x2 / 3 + (2 / 3) * (x1 + dx), y: y2 / 3 + (2 / 3) * (y1 + dy) };
|
||||||
|
}
|
||||||
function lineBezier3(_: Meta2dStore, pen: MapPen): void {
|
function lineBezier3(_: Meta2dStore, pen: MapPen): void {
|
||||||
if (pen.calculative?.worldAnchors?.length !== 2) return;
|
if (pen.calculative?.worldAnchors?.length !== 2) return;
|
||||||
const { c1, c2 } = pen.route ?? {};
|
const { c1, c2 } = pen.route ?? {};
|
||||||
@ -599,9 +704,9 @@ function lineBezier3(_: Meta2dStore, pen: MapPen): void {
|
|||||||
const { x: x1 = 0, y: y1 = 0 } = p1 ?? {};
|
const { x: x1 = 0, y: y1 = 0 } = p1 ?? {};
|
||||||
const { x: x2 = 0, y: y2 = 0 } = p2 ?? {};
|
const { x: x2 = 0, y: y2 = 0 } = p2 ?? {};
|
||||||
const { x: dx1 = x2 - x1, y: dy1 = 0 } = c1 ?? {};
|
const { x: dx1 = x2 - x1, y: dy1 = 0 } = c1 ?? {};
|
||||||
const { x: dx2 = 0, y: dy2 = y2 - y1 } = c2 ?? {};
|
const { x: dx2 = 0, y: dy2 = y1 - y2 } = c2 ?? {};
|
||||||
pen.calculative.worldAnchors[0].next = { x: x1 + dx1, y: y1 + dy1 };
|
pen.calculative.worldAnchors[0].next = { x: x1 + dx1, y: y1 + dy1 };
|
||||||
pen.calculative.worldAnchors[1].prev = { x: x2 - dx2, y: y2 - dy2 };
|
pen.calculative.worldAnchors[1].prev = { x: x2 + dx2, y: y2 + dy2 };
|
||||||
}
|
}
|
||||||
|
|
||||||
function drawArea(ctx: CanvasRenderingContext2D, pen: MapPen): void {
|
function drawArea(ctx: CanvasRenderingContext2D, pen: MapPen): void {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user