Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added shorthand to mark branch points from context menu #6012

Merged
merged 10 commits into from
Feb 4, 2022
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,11 @@ type CreateBranchPointAction = {
timestamp: number,
};
type DeleteBranchPointAction = { type: "DELETE_BRANCHPOINT" };
type DeleteBranchpointByIdAction = {
type: "DELETE_BRANCHPOINT_BY_ID",
nodeId: number,
treeId: number,
};
type ToggleTreeAction = { type: "TOGGLE_TREE", treeId: ?number, timestamp: number };
type SetTreeVisibilityAction = {
type: "SET_TREE_VISIBILITY",
Expand Down Expand Up @@ -146,6 +151,7 @@ export type SkeletonTracingAction =
| SetNodePositionAction
| CreateBranchPointAction
| DeleteBranchPointAction
| DeleteBranchpointByIdAction
| RequestDeleteBranchPointAction
| CreateTreeAction
| AddTreesAndGroupsAction
Expand Down Expand Up @@ -186,6 +192,7 @@ export const SkeletonTracingSaveRelevantActions = [
"SET_NODE_RADIUS",
"SET_NODE_POSITION",
"CREATE_BRANCHPOINT",
"DELETE_BRANCHPOINT_BY_ID",
"DELETE_BRANCHPOINT",
"CREATE_TREE",
"ADD_TREES_AND_GROUPS",
Expand Down Expand Up @@ -314,6 +321,15 @@ export const deleteBranchPointAction = (): DeleteBranchPointAction => ({
type: "DELETE_BRANCHPOINT",
});

export const deleteBranchpointByIdAction = (
nodeId: number,
treeId: number,
): DeleteBranchpointByIdAction => ({
type: "DELETE_BRANCHPOINT_BY_ID",
nodeId,
treeId,
});

export const requestDeleteBranchPointAction = (): RequestDeleteBranchPointAction => ({
type: "REQUEST_DELETE_BRANCHPOINT",
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -609,6 +609,27 @@ function SkeletonTracingReducer(state: OxalisState, action: Action): OxalisState
.getOrElse(state);
}

case "DELETE_BRANCHPOINT_BY_ID": {
const { nodeId, treeId } = action;
return getTree(skeletonTracing, treeId)
.map(tree =>
update(state, {
tracing: {
skeleton: {
trees: {
[treeId]: {
branchPoints: {
$set: tree.branchPoints.filter(bp => bp.nodeId !== nodeId),
},
},
},
},
},
}),
)
.getOrElse(state);
}

case "CREATE_TREE": {
const { timestamp } = action;
return createTree(state, timestamp)
Expand Down
34 changes: 34 additions & 0 deletions frontend/javascripts/oxalis/view/context_menu.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ import {
setActiveNodeAction,
createTreeAction,
setTreeVisibilityAction,
createBranchPointAction,
deleteBranchpointByIdAction,
} from "oxalis/model/actions/skeletontracing_actions";
import {
hasAgglomerateMapping,
Expand Down Expand Up @@ -88,6 +90,8 @@ type DispatchProps = {|
addNewBoundingBox: Vector3 => void,
deleteBoundingBox: number => void,
setActiveCell: (number, somePosition?: Vector3) => void,
createBranchPoint: (number, number) => void,
deleteBranchpointById: (number, number) => void,
|};

type StateProps = {|
Expand Down Expand Up @@ -242,6 +246,8 @@ function NodeContextMenuOptions({
deleteEdge,
mergeTrees,
deleteNode,
createBranchPoint,
deleteBranchpointById,
setActiveNode,
hideTree,
useLegacyBindings,
Expand All @@ -252,6 +258,7 @@ function NodeContextMenuOptions({
const { activeTreeId, trees, activeNodeId } = skeletonTracing;
const clickedTree = findTreeByNodeId(trees, clickedNodeId).get();
const areInSameTree = activeTreeId === clickedTree.treeId;
const isBranchpoint = clickedTree.branchPoints.find(bp => bp.nodeId === clickedNodeId) != null;
const isTheSameNode = activeNodeId === clickedNodeId;
let areNodesConnected = false;
if (areInSameTree && !isTheSameNode && activeNodeId != null) {
Expand Down Expand Up @@ -295,6 +302,27 @@ function NodeContextMenuOptions({
>
Delete this Node {activeNodeId === clickedNodeId ? shortcutBuilder(["Del"]) : null}
</Menu.Item>
{isBranchpoint ? (
<Menu.Item
className="node-context-menu-item"
key="branchpoint-node"
onClick={() =>
activeNodeId != null ? deleteBranchpointById(clickedNodeId, clickedTree.treeId) : null
}
>
Unmark as Branchpoint
</Menu.Item>
) : (
<Menu.Item
className="node-context-menu-item"
key="branchpoint-node"
onClick={() =>
activeNodeId != null ? createBranchPoint(clickedNodeId, clickedTree.treeId) : null
}
>
Mark as Branchpoint {activeNodeId === clickedNodeId ? shortcutBuilder(["B"]) : null}
</Menu.Item>
)}
<Menu.Item
className="node-context-menu-item"
key="measure-node-path-length"
Expand Down Expand Up @@ -774,6 +802,12 @@ const mapDispatchToProps = (dispatch: Dispatch<*>) => ({
deleteNode(nodeId: number, treeId: number) {
dispatch(deleteNodeAction(nodeId, treeId));
},
createBranchPoint(nodeId: number, treeId: number) {
dispatch(createBranchPointAction(nodeId, treeId));
},
deleteBranchpointById(nodeId: number, treeId: number) {
dispatch(deleteBranchpointByIdAction(nodeId, treeId));
},
setActiveNode(nodeId: number) {
dispatch(setActiveNodeAction(nodeId));
},
Expand Down
26 changes: 26 additions & 0 deletions frontend/javascripts/test/reducers/skeletontracing_reducer.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -632,6 +632,32 @@ test("SkeletonTracing should delete a branchpoint", t => {
t.is(newState.tracing.skeleton.activeTreeId, 1);
});

test("SkeletonTracing should delete specific selected branchpoint", t => {
const createNodeAction = SkeletonTracingActions.createNodeAction(
position,
rotation,
viewport,
resolution,
);
const createBranchPointAction = SkeletonTracingActions.createBranchPointAction();

// create one node and set it as branchpoint, create a second node and jump back to branchpoint
let newState = SkeletonTracingReducer(initialState, createNodeAction);
newState = SkeletonTracingReducer(newState, createBranchPointAction);
newState = SkeletonTracingReducer(newState, createNodeAction);
newState = SkeletonTracingReducer(newState, createBranchPointAction);

const deleteBranchpointByIdAction = SkeletonTracingActions.deleteBranchpointByIdAction(1, 1);
newState = SkeletonTracingReducer(newState, deleteBranchpointByIdAction);

t.not(newState, initialState);
t.is(newState.tracing.skeleton.trees[1].branchPoints.length, 1);
t.is(newState.tracing.skeleton.trees[1].branchPoints[0].nodeId, 2);
t.is(newState.tracing.skeleton.trees[1].nodes.size(), 2);
t.is(newState.tracing.skeleton.activeNodeId, 2);
t.is(newState.tracing.skeleton.activeTreeId, 1);
});

test("SkeletonTracing should delete several branchpoints", t => {
const createNodeAction = SkeletonTracingActions.createNodeAction(
position,
Expand Down