/// <summary> /// Returns true if connectors are of the same size and they are not both point connectors on 2D tiles. /// </summary> public bool IsSizeComppatibleWith(ConnectorOnTile connector) => Positions.Count == 1 && connector.Positions.Count == 1 && (OnTile.Vertices is Segment3D || connector.OnTile.Vertices is Segment3D) || Positions.Count == 2 && connector.Positions.Count == 2 && Math.Abs(Positions[0].DistanceTo(Positions[1]) - connector.Positions[0].DistanceTo(connector.Positions[1])) <= MSystem.Tolerance;
/// <summary> /// Returns a pair of facet connectors at distinct positions on "tile" which match "glue1" and "glue2" in GlueRelation. /// If no such pair exist, then both returned connectors are null. /// TODO: check whether connectors are on opposite ends of the tile /// </summary> public Tuple <ConnectorOnTile, ConnectorOnTile> MatchingConectors(Tile tile, Glue glue1, Glue glue2) { ConnectorOnTile conn2 = null; var facetConnectors = tile.Connectors.Where(conn => conn.Positions.All(point => tile.Vertices.ContainsPoint(point))); var conn1 = facetConnectors.FirstOrDefault( connector1 => GlueRelation.MatchAsymmetric(glue1, connector1.Glue) && (conn2 = facetConnectors.FirstOrDefault( connector2 => !Geometry.Overlap(connector1.Positions, connector2.Positions) && GlueRelation.MatchAsymmetric(glue2, connector2.Glue))) != null); return(Tuple.Create(conn1, conn2)); }
/// <summary> TODO low priority: move to class Connector when MSystem is available as singleton /// Checks whether two connector are mutually compatible (dimension, size, glues). /// Order of connectors matters due to possibly asymmetric glue relation! /// </summary> /// <param name="connector1"></param> /// <param name="connector2"></param> public bool AreCompatible(ConnectorOnTileInSpace connector1, ConnectorOnTile connector2) { // compatible glues and connector sizes bool result = GlueRelation.ContainsKey(Tuple.Create(connector1.Glue, connector2.Glue)) && connector1.IsSizeComppatibleWith(connector2); if (!result || Nu0 <= 0) { return(result); } //if Nu0 > 0, then this is a cTAM: check if connector voltage exceeds the threshold if (connector2.OnTile.Connectors.Count == 4) { // Assume that an inner cTAM tile can connect only to an east or south connector // It is attachable only if it connects to two connectors simultaneously and // the sum o heir voltage exceeds the threshold Tau ConnectorOnTileInSpace otherConnector = null; if (connector1 == connector1.OnTile.EastConnector) { otherConnector = connector1.OnTile.NorthConnector?.ConnectedTo?.OnTile.EastConnector?.ConnectedTo ?.OnTile.SouthConnector; } if (connector1 == connector1.OnTile.SouthConnector) { otherConnector = connector1.OnTile.WestConnector?.ConnectedTo?.OnTile.SouthConnector?.ConnectedTo ?.OnTile.EastConnector; } return(otherConnector != null && otherConnector.Voltage + connector1.Voltage >= Tau); } else { // Border cTAM return(connector1.Voltage >= Tau); } }
/// <summary> /// Calculates position and angle of a new tile connecting to this connection and connects it. /// The connector given as parameter determines also the connecting object. /// </summary> /// <param name="connector">Connector on the new tile by which it connects</param> /// <returns>New tile in space connected to this connection.</returns> public TileInSpace ConnectObject(ConnectorOnTile connector) { // Place the old and the new object into the same plane or line TileInSpace newTile = new TileInSpace(connector.OnTile, Point3D.Origin, OnTile.Quaternion); int index = connector.OnTile.Connectors.IndexOf(connector); ConnectorOnTileInSpace newConnector = newTile.Connectors[index]; UnitVector3D axis = OnTile.Vertices.Normal; // rotation axis - TRY REVERSE IN CASE OF MALFUNCTION // Edge-to-edge if (newConnector.Positions.Count == 2 && Positions.Count == 2) { // Rotate the new object so that connector directions are opposite Vector3D vector1 = Positions[1] - Positions[0]; Vector3D vector2 = newConnector.Positions[0] - newConnector.Positions[1]; Angle angle = vector2.SignedAngleTo(vector1, axis); newTile.Rotate(axis, angle); // Rotate the new tile around the connector edge so that // the angle between both tiles is the angle associated with the connector newTile.Rotate(vector1.Normalize(), Angle.FromDegrees(180) - Angle); // TRY REVERSE IN CASE OF MALFUNCTION // Move the new object so that the connectors match newTile.Move(Positions[0] - newConnector.Positions[1]); } // Point-to-point else if (newConnector.Positions.Count == 1 && Positions.Count == 1) { // Rotate the new object around an axis perpendicular to it by the angle associated with the connector var newSegment = newTile.Vertices as Segment3D; var thisSegment = OnTile.Vertices as Segment3D; var thisAxis = thisSegment?.Vector.Normalize() ?? OnTile.Vertices.Normal; if (newSegment == null) { // Tile connecting to a segment if (thisSegment != null) { axis = newTile.Vertices.Normal.CrossProduct(-Math.Sign(connector.Angle.Radians) * thisSegment.Vector).Normalize(); } // ELSE 2D tile connecting to a 2D tile by a single point - should never happen } else { if (OnTile.Vertices is Polygon3D) // Segment connecting to a tile { axis = axis.CrossProduct(-newSegment.Vector).Normalize(); } // ELSE segment connecting to a segment - axis set above as a normal to this segment } newTile.Rotate(axis, Angle); // TRY REVERSE AXIS OR ROTATION IN CASE OF MALFUNCTION // the newly connected object has one degree of freedom - rotate randomly newTile.Rotate(thisAxis, Angle.FromRadians(Randomizer.NextDoubleBetween(0, 2 * Math.PI))); // Move the new object so that the connectors match newTile.Move(Positions[0] - newConnector.Positions[0]); } else { throw new ArgumentException("Connecting incompatible connectors:" + this + "\n and" + newConnector); } ConnectTo(newConnector); return(newTile); }