|
@@ -198,6 +198,39 @@ export class TrivialParser {
|
|
|
const updatedSurface = updatedGeometry.w * updatedGeometry.h;
|
|
|
const updatedAsNode = findCorrespondingAsNode(corrState.nodes.get(updatedNodeId) as INodeState);
|
|
|
|
|
|
+ const findAndSetNewParent = (geometry: Geometry2DRect, asNodeState: INodeState) => {
|
|
|
+ const surface = geometry.w * geometry.h;
|
|
|
+ // Of all other geometries that we are inside of, find the one with the smallest surface area.
|
|
|
+ // This will be our new parent.
|
|
|
+ let smallestParent: INodeState | null = null;
|
|
|
+ let smallestSurface = Infinity;
|
|
|
+ for (const [otherNodeId,otherNodeState] of sourceState.nodes.entries()) {
|
|
|
+ if (otherNodeState.creation === edgeCreation.source) {
|
|
|
+ continue; // don't compare with ourselves
|
|
|
+ }
|
|
|
+ const otherGeometry = getGeometry(otherNodeId);
|
|
|
+ if (otherGeometry !== undefined) {
|
|
|
+ const inside = isInside(geometry, otherGeometry);
|
|
|
+ if (inside) {
|
|
|
+ const surface = otherGeometry.w * otherGeometry.h;
|
|
|
+ if (surface < smallestSurface) {
|
|
|
+ smallestSurface = surface;
|
|
|
+ smallestParent = findCorrespondingAsNode(corrState.nodes.get(otherNodeId) as INodeState);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (smallestParent !== null) {
|
|
|
+ const existingLink = asNodeState.getOutgoingEdges().get("hasParent");
|
|
|
+ if (existingLink !== smallestParent) {
|
|
|
+ console.log("updated geometry is on inside...");
|
|
|
+ const asParentLink = asNodeState.getDeltasForSetEdge(this.primitiveRegistry, "hasParent", smallestParent.asTarget());
|
|
|
+ applyToState(corrState, asParentLink);
|
|
|
+ targetDeltas.push(...asParentLink);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
// 1. Check if existing parent links still hold
|
|
|
// 1.a. outgoing parent links
|
|
|
const otherAsNodeState = updatedAsNode.getOutgoingEdges().get("hasParent");
|
|
@@ -219,7 +252,10 @@ export class TrivialParser {
|
|
|
const otherCsNodeState = findCorrespondingAsNode(otherAsNodeState, true);
|
|
|
const otherNodeId = otherCsNodeState.creation.id.value;
|
|
|
const otherGeometry = getGeometry(otherNodeId);
|
|
|
- if (otherGeometry === undefined || !isInside(otherGeometry, updatedGeometry)) {
|
|
|
+ if (otherGeometry === undefined) {
|
|
|
+ throw new Error("Assertion failed: The Corresponding CS node of an AS node that is target of 'hasParent' has no geometry.");
|
|
|
+ }
|
|
|
+ if (!isInside(otherGeometry, updatedGeometry)) {
|
|
|
// parent relation no longer holds
|
|
|
const otherAsNode = findCorrespondingAsNode(corrState.nodes.get(otherNodeId) as INodeState);
|
|
|
console.log("deleting incoming link...")
|
|
@@ -227,27 +263,21 @@ export class TrivialParser {
|
|
|
const deleteLink = otherAsNode.getDeltasForSetEdge(this.primitiveRegistry, "hasParent", null); // deletes the edge
|
|
|
applyToState(corrState, deleteLink);
|
|
|
targetDeltas.push(...deleteLink);
|
|
|
+ // Find new parent of otherAsNode:
|
|
|
+ findAndSetNewParent(otherGeometry, otherAsNode);
|
|
|
+ // The above function call leads to time complexity O(n^2) for parsing.
|
|
|
+ // There should be ways to make it more efficient (e.g., keeping all rountangles sorted by their surface area, in order to find the new parent much quicker), but for our demonstrator, the bottleneck is React/d3, not the parsing/rendering process.
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 2. Compare the new geometry to every other rountangle
|
|
|
- let smallestParent: INodeState | null = null;
|
|
|
- let smallestSurface = Infinity;
|
|
|
for (const [otherNodeId,otherNodeState] of sourceState.nodes.entries()) {
|
|
|
if (otherNodeState.creation === edgeCreation.source) {
|
|
|
continue; // don't compare with ourselves
|
|
|
}
|
|
|
const otherGeometry = getGeometry(otherNodeId);
|
|
|
if (otherGeometry !== undefined) {
|
|
|
- const inside = isInside(updatedGeometry, otherGeometry);
|
|
|
- // CORRECT: For geometries that the updated geometry is inside of, we are only interested in the smallest of them:
|
|
|
- if (inside) {
|
|
|
- const surface = otherGeometry.w * otherGeometry.h;
|
|
|
- if (surface < smallestSurface) {
|
|
|
- smallestSurface = surface;
|
|
|
- smallestParent = findCorrespondingAsNode(corrState.nodes.get(otherNodeId) as INodeState);
|
|
|
- }
|
|
|
- }
|
|
|
+ findAndSetNewParent(updatedGeometry, updatedAsNode);
|
|
|
const outside = isInside(otherGeometry, updatedGeometry);
|
|
|
// CORRECT: For geometries that are inside of our updated geometry, we should only "steal" their outgoing parent link if our updated geometry is smaller than their current parent.
|
|
|
if (outside) {
|
|
@@ -274,15 +304,6 @@ export class TrivialParser {
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
- if (smallestParent !== null) {
|
|
|
- const existingLink = updatedAsNode.getOutgoingEdges().get("hasParent");
|
|
|
- if (existingLink !== smallestParent) {
|
|
|
- console.log("updated geometry is on inside...");
|
|
|
- const asParentLink = updatedAsNode.getDeltasForSetEdge(this.primitiveRegistry, "hasParent", smallestParent.asTarget());
|
|
|
- applyToState(corrState, asParentLink);
|
|
|
- targetDeltas.push(...asParentLink);
|
|
|
- }
|
|
|
- }
|
|
|
}
|
|
|
}
|
|
|
}
|