/// <summary> /// Add a connection to the database. Must not already exist in DB. /// </summary> /// <param name="connection">The connection to be added.</param> public void addConnection(RenderedConnection connection) { if (connection.inDB_) { throw new Exception("Connection already in database."); } if (connection.getSourceBlock().isInFlyout) { // Don't bother maintaining a database of connections in a flyout. return; } var position = this.findPositionForConnection_(connection); this.array_.Splice(position, 0, connection); connection.inDB_ = true; }
/// <summary> /// Find the closest compatible connection to this connection. /// </summary> /// <param name="conn">The connection searching for a compatible /// mate.</param> /// <param name="maxRadius">The maximum radius to another connection.</param> /// <param name="dxy">Offset between this connection's location /// in the database and the current location (as a result of dragging).</param> /// <returns>Contains two properties:' connection' which is either another connection or null, /// and 'radius' which is the distance.</returns> public RenderedConnection.Closest searchForClosest(RenderedConnection conn, double maxRadius, goog.math.Coordinate dxy) { // Don't bother. if (this.array_.Length == 0) { return(new RenderedConnection.Closest { connection = null, radius = maxRadius }); } // Stash the values of x and y from before the drag. var baseY = conn.y_; var baseX = conn.x_; conn.x_ = baseX + dxy.x; conn.y_ = baseY + dxy.y; // findPositionForConnection finds an index for insertion, which is always // after any block with the same y index. We want to search both forward // and back, so search on both sides of the index. var closestIndex = this.findPositionForConnection_(conn); Connection bestConnection = null; var bestRadius = maxRadius; RenderedConnection temp; // Walk forward and back on the y axis looking for the closest x,y point. var pointerMin = closestIndex - 1; while (pointerMin >= 0 && this.isInYRange_(pointerMin, conn.y_, maxRadius)) { temp = this.array_[pointerMin]; if (conn.isConnectionAllowed(temp, bestRadius)) { bestConnection = temp; bestRadius = temp.distanceFrom(conn); } pointerMin--; } var pointerMax = closestIndex; while (pointerMax < this.array_.Length && this.isInYRange_(pointerMax, conn.y_, maxRadius)) { temp = this.array_[pointerMax]; if (conn.isConnectionAllowed(temp, bestRadius)) { bestConnection = temp; bestRadius = temp.distanceFrom(conn); } pointerMax++; } // Reset the values of x and y. conn.x_ = baseX; conn.y_ = baseY; // If there were no valid connections, bestConnection will be null. return(new RenderedConnection.Closest { connection = bestConnection, radius = bestRadius }); }
/// <summary> /// Find all nearby connections to the given connection. /// Type checking does not apply, since this function is used for bumping. /// </summary> /// <param name="connection">The connection whose neighbours /// should be returned.</param> /// <param name="maxRadius">The maximum radius to another connection.</param> /// <returns>List of connections.</returns> public Connection[] getNeighbours(RenderedConnection connection, double maxRadius) { var db = this.array_; var currentX = connection.x_; var currentY = connection.y_; // Binary search to find the closest y location. var pointerMin = 0; var pointerMax = db.Length - 2; var pointerMid = pointerMax; while (pointerMin < pointerMid) { if (db[pointerMid].y_ < currentY) { pointerMin = pointerMid; } else { pointerMax = pointerMid; } pointerMid = (int)System.Math.Floor((pointerMin + pointerMax) / 2.0); } var neighbours = new JsArray <Connection>(); /** * Computes if the current connection is within the allowed radius of another * connection. * This function is a closure and has access to outside variables. * @param {number} yIndex The other connection's index in the database. * @return {boolean} True if the current connection's vertical distance from * the other connection is less than the allowed radius. */ var checkConnection_ = new Func <int, bool>((yIndex) => { var dx = currentX - db[yIndex].x_; var dy = currentY - db[yIndex].y_; var r = System.Math.Sqrt(dx * dx + dy * dy); if (r <= maxRadius) { neighbours.Push(db[yIndex]); } return(dy < maxRadius); }); // Walk forward and back on the y axis looking for the closest x,y point. pointerMin = pointerMid; pointerMax = pointerMid; if (db.Length != 0) { while (pointerMin >= 0 && checkConnection_(pointerMin)) { pointerMin--; } do { pointerMax++; } while (pointerMax < db.Length && checkConnection_(pointerMax)); } return(neighbours); }