Hi All,
I was hoping for some help on doing collision detection between nodes (specifically between their subparts) and links.
For clarification, my node template is a base panel with a text box above a picture part. The error image is a shape over the picture part and only shown if there is a collision.
So far this is what I have:
// check for node collisions.
function checkForNodeCollisions(diagram, nodesThatHaveMoved, deletedNodes) {
deletedNodes = (typeof deletedNodes === “undefined”) ? false : deletedNodes;
var allNodes = [];
var nodes = diagram.nodes;
while (nodes.next()) {
var node = nodes.value;
if (!(node.collisionSet)) { // not defined, so define it as a Set of Parts.
node.collisionSet = new go.Set(go.Part);
}
allNodes.push(node);
}
for (var i = 0; i < allNodes.length; i++) {
var nodeA = allNodes<em>;
var pictureA = nodeA.findObject("nodePart");
for (var j = i; j < allNodes.length; j++) {
var nodeB = allNodes[j];
var pictureB = nodeB.findObject("nodePart");
// don't check itself
if (nodeA !== nodeB) {
if (pictureA !== null && pictureB !== null) {
if (pictureA.actualBounds.intersectsRect(pictureB.actualBounds) &&
deletedNodes !== true) {
// nodes in owner groups will always intersect so check for them.
if (!isNodeInGroup(nodeA, nodeB)) {
nodeA.collisionSet.add(nodeB);
nodeB.collisionSet.add(nodeA);
}
}
else {
if (nodeA instanceof go.Group) {
var groupNodes = nodeA.memberParts;
while (groupNodes.next()) {
var n = groupNodes.value;
if (n instanceof go.Node) { // only remove nodes not, links.
nodeB.collisionSet.remove(n);
}
}
}
nodeA.collisionSet.remove(nodeB);
nodeB.collisionSet.remove(nodeA);
}
}
}
}
var links = diagram.links;
while (links.next()) {
var link = links.value;
var checkIntersection = true;
if (link.fromNode !== null && link.fromNode === nodeA ||
link.toNode !== null && link.toNode === nodeA) {
checkIntersection = false;
nodeA.collisionSet.remove(link);
}
if (checkIntersection) {
// TODO: Get link path here and test for intersection with picture.
if (pictureA !== null && pictureA.actualBounds.intersectsRect(link.actualBounds)) {
nodeA.collisionSet.add(link);
}
else {
nodeA.collisionSet.remove(link);
}
}
}
}
diagram.model.startTransaction("change collision colour");
var nodes = diagram.nodes;
while (nodes.next()) {
var node = nodes.value;
if (node.collisionSet.count > 0) {
if (node instanceof go.Group) {
var containedNodes = node.memberParts;
var groupShape = node.findObject("groupSHAPE"); // case sensitive!
if (groupShape !== null) {
groupShape.fill = "rgba(255,0,0,0.4)";
groupShape.stroke = "gray";
}
while (containedNodes.next()) {
var n = containedNodes.value;
var errorImage = n.findObject("errorImage");
if (errorImage !== null) {
errorImage.visible = true;
}
}
}
else {
var errorImage = node.findObject("errorImage");
if (errorImage !== null) {
errorImage.visible = true;
}
}
}
else {
if (node instanceof go.Group) {
var containedNodes = node.memberParts;
var groupShape = node.findObject("groupSHAPE"); // case sensitive!
if (groupShape !== null) {
groupShape.fill = "rgba(128,128,128,0.2)";
groupShape.stroke = "rgba(128,128,128,0.2)";
}
while (containedNodes.next()) {
var n = containedNodes.value;
var errorImage = n.findObject("errorImage");
if (errorImage !== null) {
errorImage.visible = false;
}
}
}
else {
var errorImage = node.findObject("errorImage");
if (errorImage !== null) {
errorImage.visible = false;
}
}
}
}
diagram.model.commitTransaction("change collision colour");
};
// check if this node is in this group.
function isNodeInGroup(node1, node2) {
if (!(node1 instanceof go.Group) && !(node2 instanceof go.Group)) {
return false;
}
else if ((node1 instanceof go.Group) && !(node2 instanceof go.Group)) {
return isNodeInthisGroup(node2, node1);
}
else if (!(node1 instanceof go.Group) && (node2 instanceof go.Group)) {
return isNodeInthisGroup(node1, node2);
}
return false;
};
/// check if this node in contained by this group.
function isNodeInthisGroup(node, group) {
if (node.containingGroup === group) {
// tODO Check for nested groups higher up?
return true;
}
return false;
};
However I currently have some problems:
- The picture.actualBounds returns the co-ordinates of the part in the node base panel, not in document co-ordinates. I need a clever way of translating the points into document co-ordinates but I can't think of one yet.
- the link.actualBounds returns the bounding box around the whole link, but I would like to actually get the intersection of the path segments with the node picture rect. This also requires transforming the line segments into document co-ordinates. And this obviously gets more tricky when the link is a Bezier curve!
- How would this work fro groups, specifically nested groups? My grouping check currently one goes one level and will probably clash with the links of nodes that the group contains.
Thanks.
Jonathan