feat(B07): CAD를 AutoCAD 명령 체계로 재구성한다 (조사표 1·2·3·5절)
저장소 사고로 잃은 4개 커밋(38eb7cd4·b8a11756·281528bf·f60b488d)의 작업물을 하나로 다시 담았다. 내용은 동일하다. ■ 구조 - commands/: 명령 정의(id·AutoCAD 별칭·글리프·도구/즉시실행)를 단일 소스로 두고 리본·명령행·단축키가 모두 이 레지스트리를 읽는다. tools/tool.consts.ts 폐지. - ribbon/: 탭→패널→명령 데이터(ribbon.config.ts)와 범용 렌더러 분리. AutoCAD 배치(홈·삽입·주석·뷰·출력)와 패널 확장(▾)을 따른다. - tools/factories/sequence-tool.ts: 점·숫자·문자·객체·선택 단계를 선언하면 xstate 머신을 만들어 주는 공장. 명령당 170줄 보일러플레이트 제거. - helpers/geometry/: 3점 호·정다각형·타원·스플라인·구름형·평행이동·해치 스캔선· 점렬 샘플링 등 상태 없는 순수 함수. - Toolbar 483줄을 QuickAccessBar/Ribbon/InspectorPanel/StatusBar/CommandLine/ ViewControls/PropertiesEditor/QuickProperties로 분해. ■ 명령 (조사표 기준) - 1절 그리기 21건, 2절 수정 27건, 3절 도면층·특성·그룹·유틸리티 39건 전부 반영. - 5절 주석 34건 중 26건 반영(문자·치수 16종·지시선·표·구름형·주석 축척). - HatchEntity 추가(solid·pattern·cross·gradient) + JSON 왕복, Layer에 색·선가중치· 선종류·동결·투명도 필드 추가, 그리기 루프가 동결·숨김·투명도를 반영. ■ 화면 실측에서 고친 결함 - 명령행 포커스 상태에서 ENTER가 도구로 가지 않던 문제 - 명령행 문자 입력이 접두사가 같은 명령으로 실행되던 문제 - 명령이 끝나도 입력을 계속 먹던 문제(점 입력 명령만 반복, 나머지는 선택 도구 복귀) - 시퀀스 단계 인덱스 오사용 9건 + 단계 값 종류 검사 추가 - 해치 내부를 클릭해도 선택되지 않던 문제 미반영 8건(맞춤법 검사·꺾기 치수·치수 끊기/재연관/검사 치수·기하공차·지시선 수집· 축척 리스트 편집)은 조사표 `반영` 열과 PLAN.md에 사유를 적었다.
This commit is contained in:
@@ -22,6 +22,10 @@ export class ArcEntity implements Entity, StartAndEndpointEntity {
|
||||
public lineWidth = 1;
|
||||
public lineDash: number[] | undefined = undefined;
|
||||
public layerId: string;
|
||||
/** 0~1 객체 투명도 (Entity 인터페이스의 선택 항목) */
|
||||
public opacity?: number;
|
||||
/** GROUP으로 묶인 객체가 공유하는 식별자 */
|
||||
public groupId?: string;
|
||||
|
||||
private arc: Arc;
|
||||
|
||||
|
||||
@@ -15,6 +15,10 @@ export class ArrowHeadEntity implements Entity {
|
||||
public lineWidth = 1;
|
||||
public lineDash: number[] = [];
|
||||
public layerId: string;
|
||||
/** 0~1 객체 투명도 (Entity 인터페이스의 선택 항목) */
|
||||
public opacity?: number;
|
||||
/** GROUP으로 묶인 객체가 공유하는 식별자 */
|
||||
public groupId?: string;
|
||||
|
||||
// 3 corners of the arrow head
|
||||
constructor(
|
||||
|
||||
@@ -14,6 +14,10 @@ export class CircleEntity implements Entity {
|
||||
public lineWidth = 1;
|
||||
public lineDash: number[] | undefined = undefined;
|
||||
public layerId: string;
|
||||
/** 0~1 객체 투명도 (Entity 인터페이스의 선택 항목) */
|
||||
public opacity?: number;
|
||||
/** GROUP으로 묶인 객체가 공유하는 식별자 */
|
||||
public groupId?: string;
|
||||
|
||||
private circle: Circle;
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ import type { ImageJsonData } from './ImageEntity';
|
||||
import type { LineEntity, LineJsonData } from './LineEntity';
|
||||
import type { PointJsonData } from './PointEntity';
|
||||
import type { RectangleJsonData } from './RectangleEntity';
|
||||
import type { HatchJsonData } from './HatchEntity';
|
||||
import type { TextJsonData } from './TextEntity.ts';
|
||||
|
||||
export interface Entity {
|
||||
@@ -18,6 +19,10 @@ export interface Entity {
|
||||
lineWidth: number;
|
||||
lineDash: number[] | undefined;
|
||||
layerId: string;
|
||||
/** 0~1 객체 투명도. 없으면 도면층 값을 따른다 */
|
||||
opacity?: number;
|
||||
/** GROUP으로 묶인 객체가 공유하는 식별자 */
|
||||
groupId?: string;
|
||||
draw(drawController: DrawController, highlighted?: boolean, selected?: boolean): void;
|
||||
|
||||
/**
|
||||
@@ -57,6 +62,7 @@ export enum EntityName {
|
||||
ArrowHead = 'ArrowHead',
|
||||
Text = 'Text',
|
||||
PolyLine = 'PolyLine',
|
||||
Hatch = 'Hatch',
|
||||
}
|
||||
|
||||
export type ShapeJsonData =
|
||||
@@ -67,6 +73,7 @@ export type ShapeJsonData =
|
||||
| PointJsonData
|
||||
| ImageJsonData
|
||||
| ArrowHeadJsonData
|
||||
| HatchJsonData
|
||||
| TextJsonData;
|
||||
|
||||
export interface JsonEntity<TShapeJsonData = ShapeJsonData> {
|
||||
|
||||
@@ -0,0 +1,261 @@
|
||||
/**
|
||||
* 채움 객체 — 해치(HATCH)·그라데이션(GRADIENT)·와이프아웃(WIPEOUT)이 공유한다.
|
||||
* 경계는 닫힌 점렬 하나로 갖는다 (섬 경계는 아직 다루지 않는다).
|
||||
*/
|
||||
import { Box, Point, Polygon, Segment } from '@flatten-js/core';
|
||||
import type { Shape, SnapPoint } from '../App.types';
|
||||
import { SnapPointType } from '../App.types';
|
||||
import type { DrawController } from '../drawControllers/DrawController';
|
||||
import { hatchSpans } from '../helpers/geometry/hatch-lines';
|
||||
import { getExportColor } from '../helpers/get-export-color';
|
||||
import { mirrorPointOverAxis } from '../helpers/mirror-point-over-axis';
|
||||
import { scalePoint } from '../helpers/scale-point';
|
||||
import { getActiveLayerId, isEntityHighlighted, isEntitySelected } from '../state';
|
||||
import { type Entity, EntityName, type JsonEntity } from './Entity';
|
||||
import type { LineEntity } from './LineEntity';
|
||||
|
||||
export type HatchStyle = 'solid' | 'pattern' | 'cross' | 'gradient';
|
||||
|
||||
export interface HatchOptions {
|
||||
style: HatchStyle;
|
||||
/** 채움 색 (solid·gradient 시작색) */
|
||||
color: string;
|
||||
/** gradient 끝색 */
|
||||
color2?: string;
|
||||
/** 패턴 선 간격 (도면 단위) */
|
||||
spacing: number;
|
||||
/** 패턴 선 각도 (라디안) */
|
||||
angle: number;
|
||||
}
|
||||
|
||||
const DEFAULT_OPTIONS: HatchOptions = {
|
||||
style: 'pattern',
|
||||
color: '#ffffff',
|
||||
spacing: 1,
|
||||
angle: Math.PI / 4,
|
||||
};
|
||||
|
||||
const GRADIENT_STEPS = 48;
|
||||
|
||||
export class HatchEntity implements Entity {
|
||||
public id: string = crypto.randomUUID();
|
||||
public lineColor = '#fff';
|
||||
public lineWidth = 1;
|
||||
public lineDash: number[] | undefined = undefined;
|
||||
public layerId: string;
|
||||
/** 0~1 객체 투명도 (Entity 인터페이스의 선택 항목) */
|
||||
public opacity?: number;
|
||||
/** GROUP으로 묶인 객체가 공유하는 식별자 */
|
||||
public groupId?: string;
|
||||
|
||||
private points: Point[];
|
||||
public options: HatchOptions;
|
||||
|
||||
constructor(layerId: string, points: Point[], options?: Partial<HatchOptions>) {
|
||||
this.layerId = layerId;
|
||||
this.points = points.map((point) => point.clone());
|
||||
this.options = { ...DEFAULT_OPTIONS, ...options };
|
||||
}
|
||||
|
||||
public getPoints(): Point[] {
|
||||
return this.points;
|
||||
}
|
||||
|
||||
public draw(
|
||||
drawController: DrawController,
|
||||
parentHighlighted?: boolean,
|
||||
parentSelected?: boolean
|
||||
): void {
|
||||
if (this.points.length < 3) return;
|
||||
const highlighted = parentHighlighted ?? isEntityHighlighted(this);
|
||||
const selected = parentSelected ?? isEntitySelected(this);
|
||||
|
||||
if (this.options.style === 'solid') {
|
||||
drawController.setFillStyles(this.options.color);
|
||||
drawController.fillPolygon(...this.points);
|
||||
} else if (this.options.style === 'gradient') {
|
||||
this.drawGradient(drawController);
|
||||
} else {
|
||||
drawController.setLineStyles(highlighted, selected, this.options.color, this.lineWidth);
|
||||
const angles =
|
||||
this.options.style === 'cross'
|
||||
? [this.options.angle, this.options.angle + Math.PI / 2]
|
||||
: [this.options.angle];
|
||||
for (const angle of angles) {
|
||||
for (const [start, end] of hatchSpans(this.points, angle, this.options.spacing)) {
|
||||
drawController.drawLine(start, end);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 경계선 — 선택·강조 상태를 볼 수 있어야 하므로 항상 그린다
|
||||
drawController.setLineStyles(highlighted, selected, this.lineColor, this.lineWidth, this.lineDash);
|
||||
for (let index = 1; index < this.points.length; index++) {
|
||||
drawController.drawLine(this.points[index - 1], this.points[index]);
|
||||
}
|
||||
}
|
||||
|
||||
/** 그라데이션 — 촘촘한 스캔선의 색을 조금씩 바꿔 표현한다 */
|
||||
private drawGradient(drawController: DrawController): void {
|
||||
const box = this.getBoundingBox();
|
||||
const spacing = Math.max((box.ymax - box.ymin) / GRADIENT_STEPS, 1e-6);
|
||||
const spans = hatchSpans(this.points, 0, spacing);
|
||||
if (!spans.length) return;
|
||||
const minY = Math.min(...spans.map(([start]) => start.y));
|
||||
const maxY = Math.max(...spans.map(([start]) => start.y));
|
||||
const range = maxY - minY || 1;
|
||||
for (const [start, end] of spans) {
|
||||
const ratio = (start.y - minY) / range;
|
||||
drawController.setLineStyles(
|
||||
false,
|
||||
false,
|
||||
mixColors(this.options.color, this.options.color2 ?? this.options.color, ratio),
|
||||
2
|
||||
);
|
||||
drawController.drawLine(start, end);
|
||||
}
|
||||
}
|
||||
|
||||
public move(x: number, y: number) {
|
||||
this.points = this.points.map((point) => point.translate(x, y));
|
||||
}
|
||||
|
||||
public scale(scaleOrigin: Point, scaleFactor: number) {
|
||||
this.points = this.points.map((point) => scalePoint(point, scaleOrigin, scaleFactor));
|
||||
this.options.spacing *= scaleFactor;
|
||||
}
|
||||
|
||||
public rotate(rotateOrigin: Point, angle: number) {
|
||||
this.points = this.points.map((point) => point.rotate(angle, rotateOrigin));
|
||||
}
|
||||
|
||||
public mirror(mirrorAxis: LineEntity) {
|
||||
this.points = this.points.map((point) => mirrorPointOverAxis(point, mirrorAxis));
|
||||
}
|
||||
|
||||
public clone(): HatchEntity {
|
||||
return new HatchEntity(getActiveLayerId(), this.points, { ...this.options });
|
||||
}
|
||||
|
||||
private toPolygon(): Polygon {
|
||||
return new Polygon(this.points.map((point) => [point.x, point.y] as [number, number]));
|
||||
}
|
||||
|
||||
public getBoundingBox(): Box {
|
||||
const xs = this.points.map((point) => point.x);
|
||||
const ys = this.points.map((point) => point.y);
|
||||
return new Box(Math.min(...xs), Math.min(...ys), Math.max(...xs), Math.max(...ys));
|
||||
}
|
||||
|
||||
public intersectsWithBox(box: Box): boolean {
|
||||
return this.getBoundingBox().intersect(box);
|
||||
}
|
||||
|
||||
public isContainedInBox(box: Box): boolean {
|
||||
const own = this.getBoundingBox();
|
||||
return (
|
||||
box.xmin <= own.xmin && box.ymin <= own.ymin && box.xmax >= own.xmax && box.ymax >= own.ymax
|
||||
);
|
||||
}
|
||||
|
||||
public getFirstPoint(): Point | null {
|
||||
return this.points[0] ?? null;
|
||||
}
|
||||
|
||||
public getShape(): Shape | null {
|
||||
return this.points.length >= 3 ? this.toPolygon() : null;
|
||||
}
|
||||
|
||||
public getSnapPoints(): SnapPoint[] {
|
||||
return this.points.map((point) => ({ point, type: SnapPointType.LineEndPoint }));
|
||||
}
|
||||
|
||||
public getIntersections(entity: Entity): Point[] {
|
||||
const otherShape = entity.getShape();
|
||||
if (!otherShape || this.points.length < 3) return [];
|
||||
return this.toPolygon().intersect(otherShape);
|
||||
}
|
||||
|
||||
public distanceTo(shape: Shape): [number, Segment] | null {
|
||||
if (this.points.length < 3) return null;
|
||||
const polygon = this.toPolygon();
|
||||
// 채운 면 안쪽을 찍어도 잡히도록 내부는 거리 0으로 본다 (AutoCAD의 해치 선택)
|
||||
if (shape instanceof Point && polygon.contains(shape)) {
|
||||
return [0, new Segment(shape, shape)];
|
||||
}
|
||||
return polygon.distanceTo(shape) as [number, Segment];
|
||||
}
|
||||
|
||||
public getSvgString(): string | null {
|
||||
const path = this.points
|
||||
.map((point, index) => `${index === 0 ? 'M' : 'L'} ${point.x} ${point.y}`)
|
||||
.join(' ');
|
||||
const fill = this.options.style === 'solid' ? getExportColor(this.options.color) : 'none';
|
||||
return `<path d="${path} Z" fill="${fill}" stroke="${getExportColor(this.lineColor)}" stroke-width="${this.lineWidth}" />`;
|
||||
}
|
||||
|
||||
public getType(): EntityName {
|
||||
return EntityName.Hatch;
|
||||
}
|
||||
|
||||
public containsPointOnShape(point: Point): boolean {
|
||||
if (this.points.length < 3) return false;
|
||||
return this.toPolygon().contains(point);
|
||||
}
|
||||
|
||||
public async toJson(): Promise<JsonEntity<HatchJsonData> | null> {
|
||||
return {
|
||||
id: this.id,
|
||||
type: EntityName.Hatch,
|
||||
lineColor: this.lineColor,
|
||||
lineWidth: this.lineWidth,
|
||||
lineDash: this.lineDash,
|
||||
layerId: this.layerId,
|
||||
shapeData: {
|
||||
points: this.points.map((point) => ({ x: point.x, y: point.y })),
|
||||
options: this.options,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
public static async fromJson(jsonEntity: JsonEntity<HatchJsonData>): Promise<HatchEntity> {
|
||||
if (!jsonEntity.shapeData) {
|
||||
throw new Error('Invalid JSON entity of type Hatch: missing shapeData');
|
||||
}
|
||||
const hatch = new HatchEntity(
|
||||
jsonEntity.layerId || getActiveLayerId(),
|
||||
jsonEntity.shapeData.points.map((point) => new Point(point.x, point.y)),
|
||||
jsonEntity.shapeData.options
|
||||
);
|
||||
hatch.id = jsonEntity.id;
|
||||
hatch.lineColor = jsonEntity.lineColor;
|
||||
hatch.lineWidth = jsonEntity.lineWidth;
|
||||
hatch.lineDash = jsonEntity.lineDash;
|
||||
return hatch;
|
||||
}
|
||||
}
|
||||
|
||||
/** 두 hex 색을 ratio(0~1)로 섞는다 */
|
||||
function mixColors(from: string, to: string, ratio: number): string {
|
||||
const parse = (color: string) => {
|
||||
const hex = color.replace('#', '');
|
||||
const full = hex.length === 3 ? [...hex].map((char) => char + char).join('') : hex;
|
||||
return [
|
||||
Number.parseInt(full.slice(0, 2), 16),
|
||||
Number.parseInt(full.slice(2, 4), 16),
|
||||
Number.parseInt(full.slice(4, 6), 16),
|
||||
];
|
||||
};
|
||||
const [r1, g1, b1] = parse(from);
|
||||
const [r2, g2, b2] = parse(to);
|
||||
const channel = (a: number, b: number) =>
|
||||
Math.round(a + (b - a) * Math.min(1, Math.max(0, ratio)))
|
||||
.toString(16)
|
||||
.padStart(2, '0');
|
||||
return `#${channel(r1, r2)}${channel(g1, g2)}${channel(b1, b2)}`;
|
||||
}
|
||||
|
||||
export interface HatchJsonData {
|
||||
points: { x: number; y: number }[];
|
||||
options: HatchOptions;
|
||||
}
|
||||
@@ -18,6 +18,10 @@ export class ImageEntity implements Entity {
|
||||
public lineWidth = 1;
|
||||
public lineDash: number[] | undefined = undefined;
|
||||
public layerId: string;
|
||||
/** 0~1 객체 투명도 (Entity 인터페이스의 선택 항목) */
|
||||
public opacity?: number;
|
||||
/** GROUP으로 묶인 객체가 공유하는 식별자 */
|
||||
public groupId?: string;
|
||||
|
||||
private imageElement: HTMLImageElement;
|
||||
private polygon: Polygon;
|
||||
|
||||
@@ -22,6 +22,10 @@ export class LineEntity implements Entity, StartAndEndpointEntity {
|
||||
public lineWidth = 1;
|
||||
public lineDash: number[] | undefined = undefined;
|
||||
public layerId: string;
|
||||
/** 0~1 객체 투명도 (Entity 인터페이스의 선택 항목) */
|
||||
public opacity?: number;
|
||||
/** GROUP으로 묶인 객체가 공유하는 식별자 */
|
||||
public groupId?: string;
|
||||
|
||||
private segment: Segment;
|
||||
|
||||
|
||||
@@ -2,16 +2,14 @@ import { Box, Line, Point, Segment, Vector } from '@flatten-js/core';
|
||||
import { minBy, round } from 'es-toolkit';
|
||||
import { max, min } from 'es-toolkit/compat';
|
||||
import {
|
||||
ARROW_HEAD_LENGTH,
|
||||
ARROW_HEAD_WIDTH,
|
||||
EPSILON,
|
||||
MEASUREMENT_DECIMAL_PLACES,
|
||||
MEASUREMENT_EXTENSION_LENGTH,
|
||||
MEASUREMENT_FONT_SIZE,
|
||||
MEASUREMENT_LABEL_OFFSET,
|
||||
MEASUREMENT_ORIGIN_MARGIN,
|
||||
TO_RADIANS,
|
||||
} from '../App.consts';
|
||||
import { getDimArrowSize, getDimDecimals, getDimTextHeight } from '../commands/dim-settings';
|
||||
import type { Shape, SnapPoint } from '../App.types';
|
||||
import type { DrawController } from '../drawControllers/DrawController';
|
||||
import { pointDistance } from '../helpers/distance-between-points';
|
||||
@@ -45,6 +43,10 @@ export class MeasurementEntity implements Entity {
|
||||
public lineWidth = 1;
|
||||
public lineDash: number[] | undefined = undefined;
|
||||
public layerId: string;
|
||||
/** 0~1 객체 투명도 (Entity 인터페이스의 선택 항목) */
|
||||
public opacity?: number;
|
||||
/** GROUP으로 묶인 객체가 공유하는 식별자 */
|
||||
public groupId?: string;
|
||||
|
||||
private startPoint: Point;
|
||||
private endPoint: Point;
|
||||
@@ -57,6 +59,22 @@ export class MeasurementEntity implements Entity {
|
||||
this.offsetPoint = offsetPoint;
|
||||
}
|
||||
|
||||
public getStartPoint(): Point {
|
||||
return this.startPoint;
|
||||
}
|
||||
|
||||
public getEndPoint(): Point {
|
||||
return this.endPoint;
|
||||
}
|
||||
|
||||
public getOffsetPoint(): Point {
|
||||
return this.offsetPoint;
|
||||
}
|
||||
|
||||
public setOffsetPoint(point: Point): void {
|
||||
this.offsetPoint = point;
|
||||
}
|
||||
|
||||
public getDrawPoints() {
|
||||
// Return if measurement is zero length
|
||||
if (isPointEqual(this.startPoint, this.endPoint)) {
|
||||
@@ -136,7 +154,7 @@ export class MeasurementEntity implements Entity {
|
||||
(offsetStartPoint.x + offsetEndPoint.x) / 2,
|
||||
(offsetStartPoint.y + offsetEndPoint.y) / 2
|
||||
);
|
||||
const textHeight = MEASUREMENT_FONT_SIZE / worldFactor;
|
||||
const textHeight = getDimTextHeight() / worldFactor;
|
||||
const totalOffset = MEASUREMENT_LABEL_OFFSET / worldFactor + textHeight / 2;
|
||||
const midpointMeasurementLineOffset = midpointMeasurementLine
|
||||
.clone()
|
||||
@@ -197,7 +215,7 @@ export class MeasurementEntity implements Entity {
|
||||
const vectorFromEndToStartUnit = vectorFromEndToStart.normalize();
|
||||
const baseOfArrow = endPoint
|
||||
.clone()
|
||||
.translate(vectorFromEndToStartUnit.multiply(ARROW_HEAD_LENGTH / worldFactor));
|
||||
.translate(vectorFromEndToStartUnit.multiply(getDimArrowSize() / worldFactor));
|
||||
const perpendicularVector1 = vectorFromEndToStartUnit.rotate(90 * TO_RADIANS);
|
||||
const perpendicularVector2 = vectorFromEndToStartUnit.rotate(-90 * TO_RADIANS);
|
||||
const leftCornerOfArrow = baseOfArrow
|
||||
@@ -284,7 +302,7 @@ export class MeasurementEntity implements Entity {
|
||||
drawController.drawLine(offsetEndPointMargin, offsetEndPointExtend);
|
||||
|
||||
const distance = String(
|
||||
round(pointDistance(this.startPoint, this.endPoint), MEASUREMENT_DECIMAL_PLACES)
|
||||
round(pointDistance(this.startPoint, this.endPoint), getDimDecimals())
|
||||
);
|
||||
const originalTextDirection = normalUnit.rotate90CW();
|
||||
let finalTextDirection = originalTextDirection;
|
||||
@@ -297,7 +315,7 @@ export class MeasurementEntity implements Entity {
|
||||
drawController.drawText(distance, midpointMeasurementLineOffset, {
|
||||
textAlign: 'center',
|
||||
textDirection: finalTextDirection,
|
||||
fontSize: MEASUREMENT_FONT_SIZE / (drawController.getScreenScale() || 1),
|
||||
fontSize: getDimTextHeight() / (drawController.getScreenScale() || 1),
|
||||
textColor: this.lineColor,
|
||||
});
|
||||
}
|
||||
@@ -401,12 +419,12 @@ export class MeasurementEntity implements Entity {
|
||||
|
||||
// Calculate text properties
|
||||
const distance = String(
|
||||
round(pointDistance(this.startPoint, this.endPoint), MEASUREMENT_DECIMAL_PLACES)
|
||||
round(pointDistance(this.startPoint, this.endPoint), getDimDecimals())
|
||||
);
|
||||
const worldFactor = annotationWorldFactor();
|
||||
const textHeight = MEASUREMENT_FONT_SIZE / worldFactor;
|
||||
const textHeight = getDimTextHeight() / worldFactor;
|
||||
// Estimate width: textString.length * fontSize * aspectRatioFactor
|
||||
const textWidth = (distance.length * MEASUREMENT_FONT_SIZE * 0.6) / worldFactor;
|
||||
const textWidth = (distance.length * getDimTextHeight() * 0.6) / worldFactor;
|
||||
|
||||
const { midpointMeasurementLineOffset, normalUnit } = drawPoints;
|
||||
|
||||
|
||||
@@ -15,6 +15,10 @@ export class PointEntity implements Entity {
|
||||
public lineWidth = 1;
|
||||
public lineDash: number[] | undefined = undefined;
|
||||
public layerId: string;
|
||||
/** 0~1 객체 투명도 (Entity 인터페이스의 선택 항목) */
|
||||
public opacity?: number;
|
||||
/** GROUP으로 묶인 객체가 공유하는 식별자 */
|
||||
public groupId?: string;
|
||||
|
||||
public point: Point;
|
||||
|
||||
|
||||
@@ -16,6 +16,10 @@ export class PolyLineEntity implements Entity {
|
||||
public lineWidth = 1;
|
||||
public lineDash: number[] | undefined = undefined;
|
||||
public layerId: string;
|
||||
/** 0~1 객체 투명도 (Entity 인터페이스의 선택 항목) */
|
||||
public opacity?: number;
|
||||
/** GROUP으로 묶인 객체가 공유하는 식별자 */
|
||||
public groupId?: string;
|
||||
|
||||
private readonly entities: Entity[];
|
||||
|
||||
@@ -26,6 +30,11 @@ export class PolyLineEntity implements Entity {
|
||||
);
|
||||
}
|
||||
|
||||
/** 폴리선을 이루는 선·호 목록 (EXPLODE·샘플링에서 읽는다) */
|
||||
public getEntities(): Entity[] {
|
||||
return this.entities;
|
||||
}
|
||||
|
||||
public numberOfSegments(): number {
|
||||
return this.entities.length;
|
||||
}
|
||||
|
||||
@@ -17,6 +17,10 @@ export class RectangleEntity implements Entity {
|
||||
public lineWidth = 1;
|
||||
public lineDash: number[] | undefined = undefined;
|
||||
public layerId: string;
|
||||
/** 0~1 객체 투명도 (Entity 인터페이스의 선택 항목) */
|
||||
public opacity?: number;
|
||||
/** GROUP으로 묶인 객체가 공유하는 식별자 */
|
||||
public groupId?: string;
|
||||
|
||||
private polygon: Polygon;
|
||||
|
||||
|
||||
@@ -22,6 +22,10 @@ export class TextEntity implements Entity {
|
||||
public lineWidth = 1;
|
||||
public lineDash: number[] = [];
|
||||
public layerId: string;
|
||||
/** 0~1 객체 투명도 (Entity 인터페이스의 선택 항목) */
|
||||
public opacity?: number;
|
||||
/** GROUP으로 묶인 객체가 공유하는 식별자 */
|
||||
public groupId?: string;
|
||||
private readonly options: TextOptions;
|
||||
|
||||
constructor(
|
||||
|
||||
Reference in New Issue
Block a user