Skip to content

Commit 1831154

Browse files
authored
Merge pull request #337 from Geode-solutions/feat/create_voi
Feat/create voi
2 parents 9b770f8 + 940f1cc commit 1831154

File tree

11 files changed

+695
-123
lines changed

11 files changed

+695
-123
lines changed

app/components/CreateAOI.vue

Lines changed: 82 additions & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,12 @@
33
<v-card-title
44
class="pb-2 text-h6 text-primary font-weight-bold d-flex align-center"
55
>
6-
<img
6+
<v-img
77
src="/aoi.svg"
88
alt="AOI icon"
99
class="mr-3"
1010
width="48"
1111
height="48"
12-
color="grey-darken-2"
1312
/>
1413
Create Area of Interest (Bounding Box)
1514
</v-card-title>
@@ -155,6 +154,7 @@
155154
UIStore.setShowCreateTools(true)
156155
UIStore.setShowCreatePoint(false)
157156
UIStore.setShowCreateAOI(false)
157+
UIStore.setShowCreateVOI(false)
158158
}
159159
160160
const UIStore = useUIStore()
@@ -167,7 +167,6 @@
167167
const max_x = ref("")
168168
const max_y = ref("")
169169
const z = ref("")
170-
171170
const loading = ref(false)
172171
173172
const isFormFilled = computed(() => {
@@ -183,14 +182,7 @@
183182
UIStore.setShowCreateAOI(false)
184183
}
185184
186-
const safeParseFloat = (value) => {
187-
const sanitizedValue = String(value).trim().replace(",", ".")
188-
const result = parseFloat(sanitizedValue)
189-
return isNaN(result) && sanitizedValue === "" ? NaN : result
190-
}
191-
192185
function visibleBoundingBox() {
193-
console.log("visibleBoundingBox", hybridViewerStore.genericRenderWindow)
194186
if (!hybridViewerStore.genericRenderWindow.value)
195187
return [-1, 1, -1, 1, -1, 1]
196188
const renderer = hybridViewerStore.genericRenderWindow.value.getRenderer()
@@ -215,15 +207,14 @@
215207
const newMinY = boundsMinY - paddingY
216208
const newMaxY = boundsMaxY + paddingY
217209
218-
min_x.value = newMinX
219-
max_x.value = newMaxX
220-
min_y.value = newMinY
221-
max_y.value = newMaxY
222-
z.value = (bounds[4] + bounds[5]) / 2
210+
min_x.value = newMinX.toFixed(2)
211+
max_x.value = newMaxX.toFixed(2)
212+
min_y.value = newMinY.toFixed(2)
213+
max_y.value = newMaxY.toFixed(2)
214+
z.value = ((bounds[4] + bounds[5]) / 2).toFixed(2)
223215
}
224216
225217
onMounted(() => {
226-
console.log("CreateAOI mounted")
227218
initializeAOICoordinates()
228219
})
229220
@@ -232,10 +223,70 @@
232223
(newVal) => {
233224
if (newVal) {
234225
initializeAOICoordinates()
226+
name.value = ""
235227
}
236228
},
237229
)
238230
231+
const sanitizeNumberString = (str) => {
232+
if (str == null) return ""
233+
let value = String(str)
234+
.replace(/,/g, ".")
235+
.replace(/[^0-9eE+\-.]/g, "")
236+
if (/[eE]/.test(value)) {
237+
const parts = value.split(/[eE]/)
238+
if (parts.length > 2) {
239+
value =
240+
parts.slice(0, 2).join("e") +
241+
parts
242+
.slice(2)
243+
.join("")
244+
.replace(/[^0-9+\-.]/g, "")
245+
}
246+
}
247+
return value
248+
}
249+
250+
const handlePasteAOI = (event) => {
251+
const pastedText =
252+
(event && event.clipboardData && event.clipboardData.getData("text")) ||
253+
""
254+
255+
if (!pastedText) return
256+
257+
const coordinates = pastedText.match(/[-+]?\d*\.?\d+(?:[eE][-+]?\d+)?/g)
258+
if (!coordinates || coordinates.length === 0) return
259+
260+
const sanitized = coordinates.map((c) => sanitizeNumberString(c))
261+
262+
if (sanitized.length >= 4) {
263+
min_x.value = sanitized[0]
264+
min_y.value = sanitized[1]
265+
max_x.value = sanitized[2]
266+
max_y.value = sanitized[3]
267+
event.preventDefault()
268+
} else if (sanitized.length >= 2) {
269+
min_x.value = sanitized[0]
270+
min_y.value = sanitized[1]
271+
event.preventDefault()
272+
}
273+
}
274+
275+
const sanitizeInputAOI = (value, field) => {
276+
const sanitizedValue = sanitizeNumberString(value)
277+
if (field === "min_x") min_x.value = sanitizedValue
278+
else if (field === "min_y") min_y.value = sanitizedValue
279+
else if (field === "max_x") max_x.value = sanitizedValue
280+
else if (field === "max_y") max_y.value = sanitizedValue
281+
else if (field === "z") z.value = sanitizedValue
282+
}
283+
284+
const safeParseFloat = (value) => {
285+
const sanitizedValue = String(value).trim().replace(",", ".")
286+
const result = parseFloat(sanitizedValue)
287+
return isNaN(result) && sanitizedValue === "" ? NaN : result
288+
}
289+
239290
async function registerObject(data) {
240291
await viewer_call(
241292
{
@@ -252,6 +303,7 @@
252303
native_filename: data.native_file_name,
253304
viewable_filename: data.viewable_file_name,
254305
displayed_name: data.name,
306+
is_aoi: true,
255307
vtk_js: {
256308
binary_light_viewable: data.binary_light_viewable,
257309
},
@@ -262,7 +314,7 @@
262314
)
263315
}
264316
265-
async function createAOI() {
317+
const createAOI = async () => {
266318
const min_x_val = safeParseFloat(min_x.value)
267319
const min_y_val = safeParseFloat(min_y.value)
268320
const max_x_val = safeParseFloat(max_x.value)
@@ -276,19 +328,12 @@
276328
isNaN(max_y_val) ||
277329
isNaN(z_val)
278330
279-
if (hasNaN) {
280-
console.error(
281-
"AOI creation failed: One or more coordinate values resulted in NaN after parsing. Check the input format.",
282-
)
283-
loading.value = false
284-
return
285-
}
286-
287-
if (min_x_val >= max_x_val || min_y_val >= max_y_val) {
288-
console.error(
289-
"AOI creation failed: Min coordinates must be less than Max coordinates",
290-
)
291-
loading.value = false
331+
if (
332+
hasNaN ||
333+
min_x_val >= max_x_val ||
334+
min_y_val >= max_y_val ||
335+
!name.value
336+
) {
292337
return
293338
}
294339
@@ -307,101 +352,27 @@
307352
308353
const aoiSchema = back_schemas.opengeodeweb_back.create.create_aoi
309354
310-
if (!aoiSchema || typeof aoiSchema !== "object") {
311-
console.error(
312-
"FATAL ERROR: The AOI schema is missing or invalid at back_schemas.opengeodeweb_back.create.create_aoi",
313-
)
314-
loading.value = false
315-
return
316-
}
317355
loading.value = true
318356
try {
319-
await api_fetch(
357+
const response = await api_fetch(
320358
{
321359
schema: aoiSchema,
322360
params: aoiData,
323361
},
324362
{
325363
response_function: async (response) => {
326-
await registerObject(response._data)
364+
const dataToRegister = {
365+
...response._data,
366+
points: aoiPoints,
367+
z: z_val,
368+
}
369+
await registerObject(dataToRegister)
327370
},
328371
},
329372
)
330373
} catch (error) {
331-
console.error("API call failed during createAOI:", error)
332374
} finally {
333375
loading.value = false
334376
}
335377
}
336-
337-
const sanitizeNumberString = (str) => {
338-
if (str == null) return ""
339-
let value = String(str)
340-
.replace(/,/g, ".")
341-
.replace(/[^0-9eE+\-.]/g, "")
342-
if (/[eE]/.test(value)) {
343-
const parts = value.split(/[eE]/)
344-
if (parts.length > 2) {
345-
value =
346-
parts.slice(0, 2).join("e") +
347-
parts
348-
.slice(2)
349-
.join("")
350-
.replace(/[^0-9+\-.]/g, "")
351-
}
352-
}
353-
return value
354-
}
355-
356-
const handlePasteAOI = (event, type, field) => {
357-
const pastedText =
358-
(event && event.clipboardData && event.clipboardData.getData("text")) ||
359-
""
360-
361-
if (!pastedText) return
362-
363-
const coordinates = pastedText.match(/[-+]?\d*\.?\d+(?:[eE][-+]?\d+)?/g)
364-
if (!coordinates || coordinates.length === 0) return
365-
366-
const sanitized = coordinates.map((c) => sanitizeNumberString(c))
367-
368-
const xKey = `${type}_x`
369-
const yKey = `${type}_y`
370-
371-
if (sanitized.length >= 2) {
372-
if (field === "x" || type === "min") {
373-
min_x.value = sanitized[0]
374-
} else {
375-
max_x.value = sanitized[0]
376-
}
377-
if (field === "y" || type === "min") {
378-
min_y.value = sanitized[1]
379-
} else {
380-
max_y.value = sanitized[1]
381-
}
382-
event.preventDefault()
383-
} else if (sanitized.length === 1) {
384-
if (field === "x") {
385-
if (type === "min") {
386-
min_x.value = sanitized[0]
387-
} else {
388-
max_x.value = sanitized[0]
389-
}
390-
} else {
391-
if (type === "min") {
392-
min_y.value = sanitized[0]
393-
} else {
394-
max_y.value = sanitized[0]
395-
}
396-
}
397-
event.preventDefault()
398-
}
399-
}
400-
401-
const sanitizeInputAOI = (value, field) => {
402-
if (field === "min_x") min_x.value = sanitizeNumberString(value)
403-
else if (field === "min_y") min_y.value = sanitizeNumberString(value)
404-
else if (field === "max_x") max_x.value = sanitizeNumberString(value)
405-
else if (field === "max_y") max_y.value = sanitizeNumberString(value)
406-
}
407378
</script>

app/components/CreateTools.vue

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,28 @@
11
<template>
2-
<v-card :width="500" flat class="pa-4">
2+
<v-card :width="500" flat>
33
<v-card-title
4-
class="pb-2 text-h4 text-primary font-weight-bold d-flex align-center"
4+
class="text-h4 text-primary pa-4 font-weight-bold d-flex align-center"
55
>
66
<v-icon icon="mdi-creation" class="mr-3"></v-icon>
77
Create New Object
88
</v-card-title>
99

10-
<v-card-subtitle class="ma-0 text-medium-emphasis">
10+
<v-card-subtitle class="ma-0 text-medium">
1111
Choose a drawing tool to get started.
1212
</v-card-subtitle>
1313

1414
<v-card-text class="pt-6">
1515
<v-row>
16-
<v-col v-for="tool in tools" :key="tool.id" cols="6" class="d-flex">
16+
<v-col
17+
v-for="tool in tools"
18+
:key="tool.id"
19+
cols="6"
20+
class="d-flex pa-2"
21+
>
1722
<v-hover v-slot="{ isHovering, props }">
1823
<v-card
1924
v-bind="props"
20-
class="text-center pa-4 cursor-pointer transition-swing flex-grow-1 d-flex flex-column"
25+
class="text-center cursor-pointer transition-swing flex-grow-1 d-flex flex-column"
2126
:class="{
2227
'bg-blue-lighten-5': isHovering,
2328
'scale-103': isHovering,
@@ -90,6 +95,14 @@
9095
iconType: "svg",
9196
iconSource: "aoi.svg",
9297
},
98+
{
99+
id: "VOI",
100+
title: "Volume of Interest",
101+
description:
102+
"Create a 3D bounding box from an existing AOI with Z bounds.",
103+
iconType: "svg",
104+
iconSource: "voi.svg",
105+
},
93106
]
94107
95108
const emit = defineEmits(["select-tool"])

0 commit comments

Comments
 (0)