Skip to content

Commit

Permalink
Save landmark changes to server
Browse files Browse the repository at this point in the history
  • Loading branch information
annehaley committed Oct 2, 2023
1 parent eb21b20 commit 9fab142
Show file tree
Hide file tree
Showing 4 changed files with 138 additions and 39 deletions.
34 changes: 34 additions & 0 deletions shapeworks_cloud/core/rest.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from typing import Dict, Type

from django.contrib.auth import logout
from django.core.files.base import ContentFile
from django.db.models import Q
from django.utils import timezone
from django_filters.rest_framework import DjangoFilterBackend
Expand Down Expand Up @@ -302,6 +303,39 @@ def download(self, request, **kwargs):
project = self.get_object()
return Response(serializers.ProjectDownloadSerializer(project).data)

@action(
detail=True,
url_path='landmarks',
url_name='landmarks',
methods=['POST'],
)
def set_landmarks(self, request, **kwargs):
project = self.get_object()
form_data = request.data
landmarks_info = form_data.get('info')
landmarks_locations = form_data.get('locations')
project.landmarks_info = landmarks_info

for subject_id, data in landmarks_locations.items():
for anatomy_type, locations in data.items():
landmarks_object = models.Landmarks.objects.get(
project=project, subject__id=subject_id, anatomy_type=anatomy_type
)
landmarks_object.file.save(
landmarks_object.file.name,
ContentFile(
'\n'.join(' '.join(str(n) for n in loc) for loc in locations).encode()
),
)

log_write_access(
timezone.now(),
self.request.user.username,
'Set Project Landmarks',
project.id,
)
return Response(serializers.ProjectReadSerializer(project).data)

@action(
detail=True,
url_path='groom',
Expand Down
13 changes: 12 additions & 1 deletion web/shapeworks/src/api/rest.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { AnalysisParams, DataObject, Dataset, Project, Subject } from "@/types";
import { AnalysisParams, DataObject, Dataset, LandmarkInfo, Project, Subject } from "@/types";
import { apiClient } from "./auth";
import { loadGroomedShapeForObject, loadParticlesForObject } from "@/store";

Expand Down Expand Up @@ -154,3 +154,14 @@ export async function deleteTaskProgress(taskId: number){
export async function abortTask(taskId: number) {
return (await apiClient.post(`/task-progress/${taskId}/abort/`)).data
}

export async function saveLandmarkData(
projectId: number,
landmarkInfo: LandmarkInfo[],
landmarkLocations: Record<number, Record<number, number[][]>>
) {
return (await apiClient.post(`/projects/${projectId}/landmarks/`, {
info: landmarkInfo,
locations: landmarkLocations,
}))
}
67 changes: 59 additions & 8 deletions web/shapeworks/src/components/InfoTab.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,16 @@
<script>
import { landmarkInfo, activeLandmark, selectedDataset, selectedProject, allSubjectsForDataset } from '@/store';
import { computed, ref } from 'vue';
import {
landmarkInfo,
activeLandmark,
selectedDataset,
selectedProject,
allSubjectsForDataset,
landmarkWidgets,
layersShown,
selectedDataObjects
} from '@/store';
import { computed, onMounted, ref } from 'vue';
import { saveLandmarkData } from '@/api/rest'
export default {
setup() {
Expand All @@ -12,7 +22,6 @@ export default {
{text: '# set', value: 'num_set', width: '70px'},
];
const colorDialog = ref(false);
const changesMade = ref(false);
const colorStrings = computed(() => {
return landmarkInfo.value.map(({color}) => {
Expand All @@ -32,7 +41,6 @@ export default {
landmarkInfo.value[landmarkIndex] = Object.assign(
{}, landmarkInfo.value[landmarkIndex], {name, comment}
)
changesMade.value = true;
}
function updateLandmarkColor(landmarkIndex, color) {
Expand All @@ -44,9 +52,46 @@ export default {
)
// overwrite landmarkInfo so colorStrings will recompute
landmarkInfo.value = [...landmarkInfo.value]
changesMade.value = true;
}
function submit() {
const landmarksLocations = {}
allSubjectsForDataset.value.forEach((subject) => {
const shapesShown = selectedDataObjects.value.filter((o) => o.subject === subject.id)
shapesShown.forEach((shape, actorIndex) => {
landmarkInfo.value.forEach((lInfo) => {
const anatomyId = shape.anatomy_type
let widgetId = `${subject.name}_${actorIndex}_${lInfo.id}`
const widget = landmarkWidgets.value[widgetId]
if (widget) {
if (!landmarksLocations[subject.id]) {
landmarksLocations[subject.id] = {}
}
if (!landmarksLocations[subject.id][anatomyId]) {
landmarksLocations[subject.id][anatomyId] = []
}
const handle = widget.getWidgetState().getMoveHandle();
landmarksLocations[subject.id][anatomyId].push(handle.getOrigin())
}
})
})
})
saveLandmarkData(
selectedProject.value.id,
landmarkInfo.value,
landmarksLocations
).then((response) => {
console.log(response)
})
}
onMounted(() => {
if (!layersShown.value.includes('Landmarks')) {
layersShown.value = [...layersShown.value, 'Landmarks']
}
})
return {
selectedDataset,
selectedProject,
Expand All @@ -55,11 +100,11 @@ export default {
landmarkInfo,
activeLandmark,
colorStrings,
colorDialog,
getColorObject,
updateLandmarkInfo,
updateLandmarkColor,
colorDialog,
changesMade,
submit,
}
}
}
Expand Down Expand Up @@ -128,7 +173,13 @@ export default {
{{ item.num_set }} / {{ allSubjectsForDataset.length }}
</template>
</v-data-table>
<v-btn v-if="changesMade" style="width: 100%" color="primary">Save Changes</v-btn>
<v-btn
style="width: 100%"
color="primary"
@click="submit"
>
Save Landmarks
</v-btn>
</v-expansion-panel-content>
</v-expansion-panel>
</v-expansion-panels>
Expand Down
63 changes: 33 additions & 30 deletions web/shapeworks/src/components/ShapeViewer/methods.js
Original file line number Diff line number Diff line change
Expand Up @@ -171,49 +171,52 @@ export default {
}
})
},
addLandmarks(renderer, points) {
addLandmarks(label, renderer, points) {
this.widgetManager = vtkWidgetManager.newInstance();
this.widgetManager.setRenderer(renderer);

const manipulator = vtkPickerManipulator.newInstance();
const actors = renderer.getActors();
if (actors.length > 0) {
manipulator.getPicker().addPickList(actors[0]);
actors.forEach((actor, actorIndex) => {
const manipulator = vtkPickerManipulator.newInstance();
manipulator.getPicker().addPickList(actor);

const landmarkCoordsData = points.getPoints().getData()
landmarkInfo.value.forEach((lInfo, index) => {
let widgetId = `${label}_${actorIndex}_${lInfo.id}`
let widget = undefined;
if (landmarkWidgets.value[widgetId]) {
widget = landmarkWidgets.value[widgetId]
} else {
widget = vtkSeedWidget.newInstance();
widget.setManipulator(manipulator);
landmarkWidgets.value[widgetId] = widget;

const landmarkCoordsData = points.getPoints().getData()
landmarkInfo.value.forEach((lInfo, index) => {
let widget = undefined;
if (landmarkWidgets.value[lInfo.id]) {
widget = landmarkWidgets.value[lInfo.id]
} else {
widget = vtkSeedWidget.newInstance();
widget.setManipulator(manipulator);
landmarkWidgets.value[lInfo.id] = widget;

}
const coords = landmarkCoordsData.slice(index * 3, index * 3 + 3)
const handle = widget.getWidgetState().getMoveHandle();
handle.setOrigin(coords);
handle.setColor3(...lInfo.color);

const widgetHandle = this.widgetManager.addWidget(widget)
widgetHandle.setScaleInPixels(false);
if (activeLandmark.value && lInfo.id === activeLandmark.value.id) {
widget.getWidgetState().getMoveHandle().setScale1(2);
} else {
widget.getWidgetState().getMoveHandle().setScale1(1);
}
}
const coords = landmarkCoordsData.slice(index * 3, index * 3 + 3)
const handle = widget.getWidgetState().getMoveHandle();
handle.setOrigin(coords);
handle.setColor3(...lInfo.color);

const widgetHandle = this.widgetManager.addWidget(widget)
widgetHandle.setScaleInPixels(false);
if (activeLandmark.value && lInfo.id === activeLandmark.value.id) {
widget.getWidgetState().getMoveHandle().setScale1(2);
} else {
widget.getWidgetState().getMoveHandle().setScale1(1);
}
})
})
}
},
addPoints(renderer, points, i, landmarks = false) {
addPoints(label, renderer, points, i, landmarks = false) {
let size = this.glyphSize
let source = vtkSphereSource.newInstance({
thetaResolution: SPHERE_RESOLUTION,
phiResolution: SPHERE_RESOLUTION,
});
if (landmarks) {
this.addLandmarks(renderer, points)
this.addLandmarks(label, renderer, points)
document.addEventListener('click', this.setActiveLandmark)
return;
} else {
Expand Down Expand Up @@ -428,12 +431,12 @@ export default {
this.addShapes(renderer, label, shapes.map(({ shape }) => shape));
shapes.map(({ points }) => points).forEach((pointSet, i) => {
if (pointSet.getNumberOfPoints() > 0) {
this.addPoints(renderer, pointSet, i);
this.addPoints(label, renderer, pointSet, i);
}
})
shapes.map(({ landmarks }) => landmarks).forEach((landmarkSet, i) => {
if (landmarkSet && landmarkSet.getNumberOfPoints() > 0) {
this.addPoints(renderer, landmarkSet, i, true);
this.addPoints(label, renderer, landmarkSet, i, true);
}
})

Expand Down

0 comments on commit 9fab142

Please sign in to comment.