@eturnity/eturnity_maths 8.46.2 → 9.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/geometry.js +59 -9
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eturnity/eturnity_maths",
3
- "version": "8.46.2",
3
+ "version": "9.7.0",
4
4
  "author": "Eturnity Team",
5
5
  "main": "src/index.js",
6
6
  "private": false,
package/src/geometry.js CHANGED
@@ -29,8 +29,19 @@ export function getPolylineLength(outline) {
29
29
  )
30
30
  }, 0)
31
31
  }
32
- export function getConcaveOutlines(selectedPanels, onePanelOutline) {
33
- let buckets = groupAdjacentObjects(selectedPanels)
32
+ /**
33
+ * Gets the concave outlines of the selected panels.
34
+ * @param {Array} selectedPanels - Array of selected panels
35
+ * @param {Array} onePanelOutline - Outline of one panel
36
+ * @param {Function} customAdjacentFn - Optional callback (objA, objB) => boolean for additional adjacency checks (e.g., cross-grid)
37
+ * @returns {Object} Object with outlines and buckets
38
+ */
39
+ export function getConcaveOutlines(
40
+ selectedPanels,
41
+ onePanelOutline,
42
+ customAdjacentFn = null
43
+ ) {
44
+ let buckets = groupAdjacentObjects(selectedPanels, customAdjacentFn)
34
45
  const outlines = []
35
46
  for (let bucketIndex = 0; bucketIndex < buckets.length; bucketIndex++) {
36
47
  outlines.push(
@@ -898,7 +909,13 @@ export function isClockWise(outline) {
898
909
  }
899
910
  return sum > 0
900
911
  }
901
- export function groupAdjacentObjects(objects) {
912
+ /**
913
+ * Groups objects into buckets of adjacent objects based on row_index and col_index.
914
+ * @param {Array} objects - Array of objects with row_index, col_index, and optionally moduleField.id and gridIndex
915
+ * @param {Function} customAdjacentFn - Optional callback (objA, objB) => boolean for additional adjacency checks (e.g., cross-grid)
916
+ * @returns {Array} Array of buckets, where each bucket is an array of indices into the original objects array
917
+ */
918
+ export function groupAdjacentObjects(objects, customAdjacentFn = null) {
902
919
  if (!objects || objects.length == 0) return []
903
920
  // objects with 2D indexes
904
921
  // Check if the objects form an adjacent group
@@ -906,6 +923,23 @@ export function groupAdjacentObjects(objects) {
906
923
  let indexList = Array.from({ length: numberOfObjects }, (e, i) => i)
907
924
  let buckets = []
908
925
  let inBucket = 0
926
+
927
+ // Pre-compute custom adjacency pairs if callback provided
928
+ const customAdjacentPairs = new Map()
929
+ if (customAdjacentFn) {
930
+ for (let i = 0; i < numberOfObjects; i++) {
931
+ customAdjacentPairs.set(i, [])
932
+ }
933
+ for (let i = 0; i < numberOfObjects; i++) {
934
+ for (let j = i + 1; j < numberOfObjects; j++) {
935
+ if (customAdjacentFn(objects[i], objects[j])) {
936
+ customAdjacentPairs.get(i).push(j)
937
+ customAdjacentPairs.get(j).push(i)
938
+ }
939
+ }
940
+ }
941
+ }
942
+
909
943
  while (inBucket < objects.length) {
910
944
  let detatchedIndex = indexList.find((i) => !buckets.flat().includes(i))
911
945
  if (detatchedIndex == null) break
@@ -916,24 +950,40 @@ export function groupAdjacentObjects(objects) {
916
950
  if (visited.indexOf(currentObjectIndex) == -1) {
917
951
  //if next queued index hasn't been visited, we mark it as visited and we collect all neighbourg to queue
918
952
  visited.push(currentObjectIndex)
919
- let x = objects[currentObjectIndex].row_index
920
- let y = objects[currentObjectIndex].col_index
953
+ const currentObject = objects[currentObjectIndex]
954
+ let x = currentObject.row_index
955
+ let y = currentObject.col_index
956
+ const moduleFieldId = currentObject.moduleField?.id
957
+ const gridIndex = currentObject.gridIndex
958
+ const isSameGrid = (o) =>
959
+ o.moduleField?.id == moduleFieldId && o.gridIndex == gridIndex
960
+
961
+ // Same-grid neighbors (index-based)
921
962
  const left = objects.findIndex(
922
- (o) => o.row_index == x - 1 && o.col_index == y
963
+ (o) => o.row_index == x - 1 && o.col_index == y && isSameGrid(o)
923
964
  )
924
965
  const right = objects.findIndex(
925
- (o) => o.row_index == x + 1 && o.col_index == y
966
+ (o) => o.row_index == x + 1 && o.col_index == y && isSameGrid(o)
926
967
  )
927
968
  const top = objects.findIndex(
928
- (o) => o.row_index == x && o.col_index == y - 1
969
+ (o) => o.row_index == x && o.col_index == y - 1 && isSameGrid(o)
929
970
  )
930
971
  const bottom = objects.findIndex(
931
- (o) => o.row_index == x && o.col_index == y + 1
972
+ (o) => o.row_index == x && o.col_index == y + 1 && isSameGrid(o)
932
973
  )
933
974
  if (left != -1 && visited.indexOf(left) == -1) queue.push(left)
934
975
  if (right != -1 && visited.indexOf(right) == -1) queue.push(right)
935
976
  if (top != -1 && visited.indexOf(top) == -1) queue.push(top)
936
977
  if (bottom != -1 && visited.indexOf(bottom) == -1) queue.push(bottom)
978
+
979
+ // Custom adjacency (e.g., cross-grid)
980
+ if (customAdjacentFn) {
981
+ for (const neighborIndex of customAdjacentPairs.get(
982
+ currentObjectIndex
983
+ )) {
984
+ if (visited.indexOf(neighborIndex) == -1) queue.push(neighborIndex)
985
+ }
986
+ }
937
987
  }
938
988
  }
939
989
  inBucket += visited.length