123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254 |
- import { Line } from "konva/lib/shapes/Line";
- import { Container } from "../packages";
- import {
- createLineByDire,
- getLine2Angle,
- getLineDire,
- getLineDist,
- getLineProjection,
- getRotateDire,
- getVerticaLineDire,
- } from "./math";
- import { MathUtils } from "three";
- type AdsorbBaseProps = { tree: Container; position: number[] };
- export type AdsorbPointProps = AdsorbBaseProps & {
- refPointName?: string;
- radius?: number;
- exclusionIds?: string[];
- };
- /**
- * 参考点吸附
- */
- export const getAdsorbPointPosition = ({
- tree,
- position,
- refPointName = "adsord-point",
- exclusionIds = [],
- radius = 10,
- }: AdsorbPointProps) => {
- const refPositions = tree.stage
- .find(`.${refPointName}`)
- .filter((point) => !exclusionIds.includes(point.id()))
- .map((ref) => {
- const refPos = ref.position();
- return [refPos.x, refPos.y];
- });
- return getAdsorbPointPositionRaw({ refPositions, radius, position });
- };
- export const getAdsorbPointPositionRaw = ({
- position,
- radius = 10,
- refPositions,
- }: {
- refPositions: number[][];
- position: number[];
- radius: number;
- }) => {
- let adsorbPosition: number[] | null = null;
- let minDis = Number.MAX_VALUE;
- for (const refPosition of refPositions) {
- const dis = getLineDist(refPosition, position);
- if (dis < radius && dis < minDis) {
- minDis = dis;
- adsorbPosition = refPosition;
- }
- }
- return adsorbPosition;
- };
- type AdsorbLineProps = AdsorbBaseProps & {
- refLineName?: "adsord-line";
- exclusionIds?: string[];
- radiusInner?: number;
- angle?: number;
- };
- /**
- * 参考线吸附
- */
- export const getAdsorbLinePosition = ({
- tree,
- position,
- refLineName = "adsord-line",
- exclusionIds = [],
- angle = 2,
- radiusInner = 500,
- }: AdsorbLineProps) => {
- const refLines = tree.stage
- .find<Line>(`.${refLineName}`)
- .filter((line) => {
- if (exclusionIds.includes(line.id())) {
- return false;
- }
- const points = line.points();
- return (
- getLineDist([points[0], points[1]], position) < radiusInner ||
- getLineDist([points[2], points[3]], position) < radiusInner
- );
- })
- .map((ref) => {
- return [...ref.points(), ref.id()] as any;
- });
- return getAdsorbLinePositionRaw({ position, refLines, angle });
- };
- const adsorbLineAngles = [0, 90, 180, 270, 360];
- export const getAdsorbLinePositionRaw = ({
- position,
- refLines,
- angle = 3,
- }: {
- position: number[];
- refLineName?: "adsord-line";
- refLines: number[][];
- angle?: number;
- }) => {
- let adsorbAngle: number | null = null;
- let adsorbLine: number[] | null = null;
- let isAdsorb = false;
- for (const refLine of refLines) {
- const points = [
- [refLine[0], refLine[1]],
- [refLine[2], refLine[3]],
- ];
- const cAngles = points.map((start) => {
- let angle = MathUtils.radToDeg(
- getLine2Angle(refLine, [...start, ...position])
- );
- return (angle + 360) % 360;
- });
- let i = 0,
- j = 0;
- for (i = 0; i < cAngles.length; i++) {
- for (j = 0; j < adsorbLineAngles.length; j++) {
- const adAngle = adsorbLineAngles[j];
- if (cAngles[i] >= adAngle - angle && cAngles[i] <= adAngle + angle) {
- break;
- }
- }
- if (j !== adsorbLineAngles.length) {
- break;
- }
- }
- if (j !== adsorbLineAngles.length || i !== cAngles.length) {
- adsorbLine = refLine;
- adsorbAngle = adsorbLineAngles[j];
- const rdire = getRotateDire(
- getLineDire(adsorbLine),
- MathUtils.degToRad(adsorbAngle)
- );
- const start =
- getLineDist([adsorbLine[0], adsorbLine[1]], position) >
- getLineDist([adsorbLine[2], adsorbLine[3]], position)
- ? [adsorbLine[2], adsorbLine[3]]
- : [adsorbLine[0], adsorbLine[1]];
- adsorbLine = createLineByDire(rdire, start, 10);
- position = getLineProjection(adsorbLine, position).point;
- isAdsorb = true;
- }
- }
- if (isAdsorb) {
- return position;
- }
- };
- export const getAdsorbCrossPosition = ({
- position,
- angle,
- points,
- }: AdsorbSelfLinesProps) => {
- if (!points?.length) return;
- if (points.length === 1) {
- const point = points[0];
- const refLines = [
- [point[0] - 1, point[1], point[0] + 1, point[1]],
- [point[0], point[1] - 1, point[0], point[1] + 1],
- ];
- return getAdsorbLinePositionRaw({ position, refLines, angle });
- }
- };
- export type AdsorbSelfLinesProps = {
- points?: number[][];
- angle?: number;
- position: number[];
- };
- export const getAdsorbSelfLinesPosition = ({
- position,
- points,
- angle,
- }: AdsorbSelfLinesProps) => {
- if (!points?.length) return;
- // 当前位置始终在第一个点
- const last = points.slice(0, 2).flatMap((a) => a);
- const first = points
- .slice(points.length - 2, points.length)
- .flatMap((a) => a);
- const vlines = [
- last,
- // createLineByDire(getVerticaLineDire(last), [last[2], last[3]], 10),
- createLineByDire(getVerticaLineDire(first), [first[2], first[3]], 10),
- ];
- // 垂直最后一段
- return (
- getAdsorbLinePositionRaw({
- position,
- refLines: vlines,
- angle,
- }) || position
- );
- };
- export type AdsorbProps = Omit<
- AdsorbPointProps & AdsorbLineProps & AdsorbSelfLinesProps,
- "position"
- > & {
- pixel?: number[];
- position?: number[];
- radiusInner?: number;
- pointsArray?: number[][][];
- };
- export const getAdsorbPosition = (props: AdsorbProps) => {
- const position = props.position || props.tree.getRealFromStage(props.pixel);
- let refPosition: number[];
- if ((refPosition = getAdsorbPointPosition({ ...props, position }))) {
- return refPosition;
- } else if ((refPosition = getAdsorbCrossPosition({ ...props, position }))) {
- return refPosition;
- } else if (
- (refPosition = getAdsorbSelfLinesPosition({ ...props, position }))
- ) {
- return refPosition;
- }
- if (props.pointsArray) {
- for (let i = 0; i < props.pointsArray.length; i++) {
- if (
- (refPosition = getAdsorbSelfLinesPosition({
- ...props,
- position,
- points: props.pointsArray[i],
- }))
- ) {
- return refPosition;
- }
- }
- }
- // if ((refPosition = getAdsorbLinePosition({ ...props, position }))) {
- // return refPosition;
- // }
- return position;
- };
|