cutting tool, line delete tool

This commit is contained in:
Evert Prants 2023-01-18 21:15:51 +02:00
parent cef1b80679
commit 452bcd5c01
Signed by: evert
GPG Key ID: 1688DA83D222D0B5
6 changed files with 146 additions and 5 deletions

View File

@ -59,6 +59,8 @@ import {
HomeIcon,
ArrowsPointingOutIcon,
ArrowDownOnSquareIcon,
ScissorsIcon,
XMarkIcon,
} from '@heroicons/vue/24/outline';
import { useSessionStorage } from '@vueuse/core';
import { onMounted, ref, shallowRef } from 'vue';
@ -139,6 +141,20 @@ const toolbar: ToolbarTool[] = [
},
],
},
{
title: 'Cut',
icon: ScissorsIcon,
tool: 'cut',
subTool: 'cut',
children: [
{
title: 'Cut Segment',
icon: XMarkIcon,
tool: 'cut',
subTool: 'remove-segment',
},
],
},
];
const selectTool = (newTool?: string, newSubTool?: string) => {

View File

@ -1,6 +1,6 @@
<template>
<div
class="absolute bottom-0 z-10 w-screen max-w-xs rounded-lg bg-white lg:left-1/2 lg:ml-0 lg:-translate-x-1/2"
class="absolute bottom-0 z-10 w-screen max-w-md rounded-lg bg-white lg:left-1/2 lg:ml-0 lg:-translate-x-1/2"
>
<div
class="flex flex-1 flex-row items-center justify-center space-x-2 py-4 px-4 shadow-lg ring-1 ring-black ring-opacity-5"

View File

@ -129,6 +129,9 @@ export class HousePlannerCanvas {
}
for (const segment of segments) {
if (segment.start) {
path.moveTo(...segment.start);
}
if ((segment as BezierSegment).startControl) {
this.makeBezier(segment as BezierSegment, path);
continue;

View File

@ -10,6 +10,7 @@ import {
ToolEvent,
Vec2,
} from './interfaces';
import { CutTool } from './tools/cut';
import { LineTool } from './tools/line';
import { MoveTool } from './tools/move';
@ -22,6 +23,7 @@ export class HousePlannerCanvasTools implements ICanvasToolMouseEvents {
public tools: Record<string, ICanvasToolBase<unknown>> = {
['move']: new MoveTool(this),
['line']: new LineTool(this),
['cut']: new CutTool(this),
};
public history = new HousePlannerCanvasHistory();
public lastStrokeWidth = 16;

View File

@ -0,0 +1,121 @@
import {
BezierSegment,
LayerObject,
Line,
LineSegment,
Vec2,
} from '../interfaces';
import { CanvasToolBase } from './tool-base';
export type CutToolType = 'cut' | 'remove-segment';
export class CutTool extends CanvasToolBase<CutToolType> {
public name = 'cut';
public subTool: CutToolType | undefined = 'cut';
mouseMoved(mouse: Vec2, offset: Vec2, mouseAbsolute: Vec2) {
super.mouseMoved(mouse, offset, mouseAbsolute);
this.renderer.draw();
}
mouseDown(targetObject?: LayerObject | undefined): void {
if (
!targetObject ||
targetObject.type === 'curve' ||
targetObject.type === 'object'
)
return;
const line = targetObject as Line;
const segment = this.manager.getMousedLineSegment(line);
if (!segment) return;
const segmentIndex = line.segments.indexOf(segment);
if (this.subTool === 'remove-segment') {
const nextSegment = line.segments[segmentIndex + 1];
if (!nextSegment) return;
if (segment.start) {
nextSegment.start = segment.start;
line.segments.splice(segmentIndex, 1);
} else {
nextSegment.start = segment.end;
line.segments.splice(segmentIndex, 1);
}
} else {
const currentEnd: Vec2 = [...segment.end];
segment.end = [...this.mousePosition];
line.segments.splice(segmentIndex + 1, 0, { end: currentEnd });
}
this.renderer.draw();
}
drawBezierControls(bezier: BezierSegment, previousEnd: Vec2) {
const [cp1x, cp1y] = bezier.startControl;
const [cp2x, cp2y] = bezier.endControl;
const [endx, endy] = bezier.end;
const [prevx, prevy] = previousEnd;
this.ctx.fillStyle = '#00ddffaa';
this.ctx.strokeStyle = '#00ddffaa';
this.ctx.lineWidth = 2;
this.ctx.beginPath();
this.ctx.arc(cp1x, cp1y, this.manager.selectError / 2, 0, 2 * Math.PI);
this.ctx.fill();
this.ctx.beginPath();
this.ctx.arc(cp2x, cp2y, this.manager.selectError / 2, 0, 2 * Math.PI);
this.ctx.fill();
this.ctx.beginPath();
this.ctx.moveTo(cp1x, cp1y);
this.ctx.lineTo(prevx, prevy);
this.ctx.stroke();
this.ctx.beginPath();
this.ctx.moveTo(cp2x, cp2y);
this.ctx.lineTo(endx, endy);
this.ctx.stroke();
}
drawLineControls(line: LineSegment, previousEnd: Vec2) {
const [endx, endy] = line.end;
this.ctx.fillStyle = '#00ddffaa';
this.ctx.beginPath();
this.ctx.arc(endx, endy, this.manager.selectError / 2, 0, 2 * Math.PI);
this.ctx.fill();
if (line.start) {
const [startx, starty] = line.start;
this.ctx.beginPath();
this.ctx.arc(
startx,
starty,
this.manager.selectError / 2,
0,
2 * Math.PI
);
this.ctx.fill();
}
}
drawControls(): void {
for (const object of this.manager.selectedObjects) {
const line = object as Line;
if (line.segments && line.render) {
let lastSegment = null;
for (const segment of line.segments) {
const bezier = segment as BezierSegment;
const previousPoint = lastSegment ? lastSegment.end : segment.start!;
if (bezier.startControl && bezier.endControl) {
this.drawBezierControls(bezier, previousPoint);
}
this.drawLineControls(segment, previousPoint);
lastSegment = segment;
}
}
}
const [mx, my] = this.mousePosition;
this.ctx.fillStyle = '#00ddffaa';
this.ctx.beginPath();
this.ctx.arc(mx, my, this.manager.selectError / 2, 0, 2 * Math.PI);
this.ctx.fill();
}
}

View File

@ -6,6 +6,7 @@ import { CanvasToolBase } from './tool-base';
export type LineToolType = 'line' | 'curve' | 'room';
export class LineTool extends CanvasToolBase<LineToolType> {
public name = 'line';
public autoClose = false;
private drawingLine: Line | null = null;
public subTool: LineToolType = 'line';
@ -17,8 +18,6 @@ export class LineTool extends CanvasToolBase<LineToolType> {
this.ctx.fill();
}
mouseDown(targetObject?: LayerObject | undefined): void {}
mouseMoved(mouse: Vec2, offset: Vec2, mouseAbsolute: Vec2): void {
super.mouseMoved(mouse, offset, mouseAbsolute);
if (this.drawingLine) {
@ -116,7 +115,7 @@ export class LineTool extends CanvasToolBase<LineToolType> {
) ||
this.drawingLine.type === 'curve'
) {
if (this.drawingLine.type !== 'curve') {
if (this.drawingLine.type !== 'curve' && this.autoClose) {
this.drawingLine.segments.splice(
this.drawingLine.segments.length - 1,
1
@ -136,7 +135,7 @@ export class LineTool extends CanvasToolBase<LineToolType> {
value: [],
},
]);
this.drawingLine.closed = true;
this.drawingLine.closed = this.autoClose;
this.canvas.dispatchEvent(
new CustomEvent('hpc:newobject', {
detail: this.drawingLine,