index.ts 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. import { lineVector, Pos, vectorAngle, verticalVector } from "@/utils/math.ts";
  2. import { BaseItem, generateSnapInfos, getBaseItem } from "../util.ts";
  3. import { getMouseColors } from "@/utils/colors.ts";
  4. import { InteractiveFix, InteractiveTo, MatResponseProps } from "../index.ts";
  5. import { inRevise, onlyId, rangMod } from "@/utils/shared.ts";
  6. import { MathUtils } from "three";
  7. import { DrawStore, useStore } from "@/core/store/index.ts";
  8. import { getInitCtx, NLineDataCtx, normalLineData } from "./use-draw.ts";
  9. import { SelectionManageBus, UseGetSelectionManage } from "@/core/hook/use-selection.ts";
  10. import { EntityShape } from "@/deconstruction.js";
  11. import mitt from "mitt";
  12. import { watch } from "vue";
  13. export { default as Component } from "./line.vue";
  14. export { default as TempComponent } from "./temp-line.vue";
  15. export { useDraw } from "./use-draw.ts";
  16. export const shapeName = "线段";
  17. export const defaultStyle = {
  18. stroke: "#000000",
  19. strokeWidth: 20,
  20. dash: [30, 0],
  21. };
  22. export const addMode = "single-dots";
  23. export const getMouseStyle = (data: LineData) => {
  24. const strokeStatus = getMouseColors(data.stroke || defaultStyle.stroke);
  25. const strokeWidth = data.strokeWidth || defaultStyle.strokeWidth;
  26. return {
  27. default: { stroke: data.stroke || defaultStyle.stroke, strokeWidth },
  28. hover: { stroke: strokeStatus.hover },
  29. select: { stroke: strokeStatus.select },
  30. focus: { stroke: strokeStatus.hover },
  31. press: { stroke: strokeStatus.press },
  32. };
  33. };
  34. export const getSnapInfos = (data: LineData) => {
  35. const vh = generateSnapInfos(getSnapPoints(data), true, false, true);
  36. data.lines.forEach((item) => {
  37. const a = data.points.find((p) => p.id === item.a)!;
  38. const b = data.points.find((p) => p.id === item.b)!;
  39. const prevVector = lineVector([a, b]);
  40. const vLine = verticalVector(prevVector);
  41. vh.push({
  42. point: a,
  43. links: [b],
  44. linkDirections: [prevVector],
  45. linkAngle: [rangMod(MathUtils.radToDeg(vectorAngle(vLine)), 180)],
  46. });
  47. });
  48. return vh;
  49. };
  50. export const getSnapPoints = (data: LineData) => {
  51. return data.points;
  52. };
  53. export type LineData = Partial<typeof defaultStyle> &
  54. BaseItem & {
  55. points: (Pos & { id: string })[];
  56. lines: {
  57. id: string;
  58. a: string;
  59. b: string;
  60. strokeWidth: number;
  61. stroke: string;
  62. dash: number[];
  63. }[];
  64. polygon: { points: string[]; id: string }[];
  65. updateTime?: number;
  66. calcTime?: number;
  67. };
  68. export const interactiveToData: InteractiveTo<"line"> = ({
  69. info,
  70. preset = {},
  71. ...args
  72. }) => {
  73. if (info.cur) {
  74. const baseItem = getBaseItem();
  75. return interactiveFixData({
  76. ...args,
  77. info,
  78. data: {
  79. ...defaultStyle,
  80. ...baseItem,
  81. ...preset,
  82. lines: [],
  83. points: [],
  84. polygon: [],
  85. },
  86. });
  87. }
  88. };
  89. export const interactiveFixData: InteractiveFix<"line"> = ({ data, info }) => {
  90. const nv = [...info.consumed, info.cur!];
  91. data.points.length = nv.length;
  92. for (let i = 0; i < nv.length; i++) {
  93. if (inRevise(data.points[i], nv[i])) {
  94. if (!data.points[i]) {
  95. data.points[i] = {
  96. id: onlyId(),
  97. ...nv[i],
  98. };
  99. } else {
  100. data.points[i] = {
  101. ...data.points[i],
  102. ...nv[i],
  103. };
  104. }
  105. }
  106. }
  107. data.lines.length = nv.length - 1;
  108. for (let i = 0; i < nv.length - 1; i++) {
  109. if (!data.lines[i]) {
  110. data.lines[i] = {
  111. id: onlyId(),
  112. ...defaultStyle,
  113. a: data.points[i].id,
  114. b: data.points[i + 1].id,
  115. };
  116. }
  117. }
  118. // data.polygon = [{points: [data.lines.map((item) => item.id)], id: onlyId()}];
  119. return data;
  120. };
  121. const matResPoints = new Set<string>()
  122. let matCtx: NLineDataCtx | null
  123. let matData: LineData
  124. export const startMatResponse = () => {
  125. matCtx = getInitCtx()
  126. }
  127. export const matResponse = ({
  128. data,
  129. mat,
  130. operId
  131. }: MatResponseProps<"line">) => {
  132. matData = data
  133. const line = data.lines.find(item => item.id === operId)
  134. if (!line) return;
  135. const ids = [line.a, line.b]
  136. for (const id of ids) {
  137. if (matResPoints.has(id)) {
  138. continue;
  139. }
  140. const ndx = data.points.findIndex(item => item.id === id)
  141. if (~ndx) {
  142. const point = data.points[ndx]
  143. data.points[ndx] = {
  144. ...point,
  145. ...mat.point(point)
  146. }
  147. matCtx!.update.points[point.id] = data.points[ndx]
  148. matResPoints.add(id)
  149. }
  150. }
  151. return data;
  152. };
  153. export const endMatResponse = () => {
  154. matResPoints.clear()
  155. // matCtx && normalLineData(matData, matCtx)
  156. // console.log(matData, matCtx)
  157. matCtx = null
  158. }
  159. export const getPredefine = (key: keyof LineData) => {
  160. if (key === "strokeWidth") {
  161. return { proportion: true };
  162. }
  163. };
  164. export const childrenDataGetter = (data: LineData, id: string) => {
  165. const line = data.lines.find(item => item.id === id)
  166. if (!line) return;
  167. const ids = [line.a, line.b]
  168. return data.points.filter(p => ids.includes(p.id))
  169. }
  170. export const delItem = (store: DrawStore, data: LineData, childId: string) => {
  171. if (!childId) {
  172. store.delItem("line", data.id);
  173. return;
  174. }
  175. let ndx;
  176. if (~(ndx = data.lines.findIndex((item) => item.id === childId))) {
  177. const delLine = data.lines[ndx];
  178. const ctx = getInitCtx();
  179. ctx.del.lines[delLine.id] = delLine;
  180. data.lines.splice(ndx, 1);
  181. normalLineData(data, ctx);
  182. store.setItem("line", { value: data, id: data.id });
  183. } else if (~(ndx = data.points.findIndex((item) => item.id === childId))) {
  184. const { ctx } = delPoint(data, childId);
  185. normalLineData(data, ctx);
  186. store.setItem("line", { value: data, id: data.id });
  187. }
  188. };
  189. export const delPoint = (data: LineData, id: string, ctx = getInitCtx()) => {
  190. const p = data.points.find((item) => item.id === id);
  191. if (!p) return { data, ctx };
  192. const checkLines = data.lines.filter(
  193. (item) => item.a === p.id || item.b === p.id
  194. );
  195. if (checkLines.length > 1) {
  196. const joinPoints = new Set<string>();
  197. checkLines.forEach((item) => {
  198. joinPoints.add(item.a);
  199. joinPoints.add(item.b);
  200. });
  201. if (joinPoints.size === 3) {
  202. const prev = checkLines.find((item) => item.b === p.id);
  203. const next = checkLines.find((item) => item.a === p.id);
  204. if (prev && next) {
  205. const l = { ...prev, id: onlyId(), b: next.b };
  206. ctx.add.lines[l.id] = l;
  207. data.lines.push(l);
  208. } else {
  209. const l = prev || next || checkLines[0];
  210. const ps = [...joinPoints].filter((item) => item !== p.id);
  211. const nl = { ...l, id: onlyId(), a: ps[0], b: ps[1] };
  212. ctx.add.lines[l.id] = nl;
  213. data.lines.push(nl);
  214. }
  215. }
  216. }
  217. checkLines.forEach((l) => {
  218. ctx.del.lines[l.id] = l;
  219. const ndx = data.lines.findIndex((ln) => ln.id === l.id);
  220. ~ndx && data.lines.splice(ndx, 1);
  221. });
  222. ctx.del.points[p.id] = p;
  223. const ndx = data.points.findIndex((pn) => pn.id === p.id);
  224. ~ndx && data.points.splice(ndx, 1);
  225. return { data, ctx };
  226. };
  227. export const useGetSelectionManage: UseGetSelectionManage = () => {
  228. const store = useStore();
  229. const canSelect = (shape: EntityShape) => {
  230. const id = shape.id();
  231. const line = store.getTypeItems('line')[0]
  232. return !!(id && line.lines.some(item => item.id === id));
  233. };
  234. const listener = (shape: EntityShape) => {
  235. const bus: SelectionManageBus = mitt();
  236. const stop = watch(
  237. () => canSelect(shape),
  238. (exixts, _) => {
  239. if (!exixts) {
  240. bus.emit("del", shape);
  241. }
  242. },
  243. { immediate: true }
  244. );
  245. return { stop, bus };
  246. };
  247. return { canSelect, listener };
  248. };