/// <returns> /// True if this and another tile are both polygons in the same plane and they overlap. /// </returns> public bool OverlapsWith(TileInSpace another) { var p1 = this.Vertices as Polygon3D; var p2 = another.Vertices as Polygon3D; return(p1 != null && p2 != null && p1.OverlapsWith(p2)); }
/// <summary> /// Calculates pushing of another object intersecting with this one. /// </summary> /// <param name="another">The tile to be pushed.</param> /// <param name="direction">Pushing direction.</param> /// <returns>Pushing vector of another object.</returns> public Vector3D PushingIntersected(TileInSpace another, UnitVector3D direction) { // Estimate the maximum length of both intersecting objects (lower bound) // Create vector of sum of their lengths in the pushing direction var box1 = new Box3D(another.Vertices); var box2 = new Box3D(this.Vertices); var falsePushingVector = ((box1.MaxCorner - box1.MinCorner).Length + (box2.MaxCorner - box2.MinCorner).Length) * direction; // Create false object moved by negation of the created vector as if it was to be pushed to its actual position // This false object surely does not intersects with the "another" IPolytope falseVertices = CreateVertices(RotateAndMoveCollection(null, -falsePushingVector, Vertices), Name + "-false"); // The method "PushingOf" returns the actual pushing vector of the intersecting object return(falseVertices.PushingOf(another.Vertices, falsePushingVector)); }
/// <summary> /// For a cTAM 1D electric ladder, calculates charges of all tiles and re-colors tiles accordingly /// </summary> /// <param name="tile">Starting tile of the ladder</param> /// <param name="mSystem">M system which simulates a cTAM</param> private static void CalculateLadder(TileInSpace tile, MSystem mSystem) { var ladder = new List <TileInSpace>() { null }; // Element ladder[0] is unused, to agree with paper formulas // The cycle must terminate as the tiles are passed in increasing X-coordinate order while (tile != null) { ladder.Add(tile); // Next tile to the east from the current one tile = tile.EastConnector?.ConnectedTo?.OnTile; } var t = ladder.Count - 1; if (t <= 0) { return; } var coefR = new double[t + 1]; coefR[t] = 1; var coefV = new double[t + 1]; coefV[0] = 1; for (int k = t - 1; k >= 1; k--) { coefR[k] = 1 - 1 / (coefR[k + 1] + ladder[k + 1].AlphaRatio + 1); } for (int k = 1; k <= t; k++) { tile = ladder[k]; coefV[k] = coefV[k - 1] * coefR[k] / (coefR[k] + tile.AlphaRatio); tile.EastConnector.Voltage = mSystem.Nu0 * coefV[k]; // Color change: lower voltage -> darker, but no less than 1/3 of the original light var coef = 0.75 / Math.Max(1 - mSystem.Tau / mSystem.Nu0, 0.01); var darkRatio = Math.Max((coefV[k] - 1) * coef + 1, 0); var origColor = ((Tile)tile).Color; tile.SetNewColor(origColor.A, (int)(origColor.R * darkRatio), (int)(origColor.G * darkRatio), (int)(origColor.B * darkRatio)); } }
/// <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); }
/// <summary> /// ConnectorOnTileInSpace constructor /// </summary> /// <param name="tile">Tile on which is this connector placed.</param> /// <param name="connector">Base connector from which this connector derives.</param> public ConnectorOnTileInSpace(TileInSpace tile, Connector connector) : base(tile, connector) { OnTile = tile; v_Positions = connector.Positions; // assignment to Positions would cause double check of positions on tile }
/// <summary> /// Surface connector constructor /// </summary> /// <param name="tile">Tile on which is this connector placed.</param> public SurfaceConnector(TileInSpace tile) { v_OnTile = tile; }
/// <summary> /// Protein constructor. /// </summary> /// <param name="tile">Tile on which is this protein placed.</param> /// <param name="protein">Base protein from which this protein derives.</param> public ProteinOnTileInSpace(TileInSpace tile, ProteinOnTile protein) : base(protein.Name, protein.Position) { m_tile = tile; }
/// <returns> /// True if this tile intersects or overlaps another tile. Optimized. /// </returns> public bool CollidesWith(TileInSpace another) { return(Vertices.IntersectionsWith(another.Vertices).Any()); }
/// <summary> /// Calculates possible pushing of "another" object by this one, being itself /// pushed by its "PushingVector" field which MAY cause its intersection with "another". /// If this object already intersects "another", its "PushingVector" is returned. /// </summary> /// <param name="another">The tile to be eventually pushed.</param> /// <returns>Pushing vector of another object.</returns> public Vector3D PushingNonIntersected(TileInSpace another) { return(Vertices.PushingOf(another.Vertices, PushingVector)); }
/// <summary> /// Gets the set of floating objects within a reaction distance from the center of a tile. /// Only objects unused in this simulation step are considered. /// TODO low priority: return floating objects close to the whole shape of the tile except border /// </summary> public FloatingObjectsSet GetNearObjects(TileInSpace tile, NamedMultiset targetMultiset) { return(GetNearObjects(tile.Position, targetMultiset)); }