Beispiel #1
0
        /// <summary>
        /// Gets all intersection of this polygon with a polytope (segment or polygon).
        /// Ignores boundary touches within Msystem.Tolerance.
        /// If the polytope is parallel to this polygon, nothing is returned even if they overlap.
        /// </summary>
        /// <param name="polytope">Polyline to intersect with.</param>
        /// <returns>List of intersection points.</returns>
        public HashSet <Point3D> IntersectionsWith(IPolytope polytope)
        {
            var result = new HashSet <Point3D>(Geometry.PointComparer);

            if (Center.DistanceTo(polytope.Center) > Radius + polytope.Radius)
            {
                return(result);  // Optimization - quick test excluding intersection
            }
            var polygon = polytope as Polygon3D;

            if (polygon != null)
            {
                var intersections = OneWayIntersectionsWith(polygon);
                intersections.UnionWith(polygon.OneWayIntersectionsWith(this));
                if (intersections.Any())
                {
                    var center = Point3D.Centroid(intersections);
                    if (ContainsPoint(center, MSystem.Tolerance) && polygon.ContainsPoint(center, MSystem.Tolerance))
                    {
                        return(intersections);
                    }
                }
            }
            if (polytope is Segment3D)
            {
                var intersection = IntersectionWith(polytope[0], polytope[1], MSystem.Tolerance, false);
                if (!intersection.IsNaN())
                {
                    result.Add(intersection);
                }
            }
            return(result);
        }
Beispiel #2
0
        /// <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));
        }
Beispiel #3
0
        /// <summary>
        /// Throws exception if the connector does not lie entirely on its tile or does not have smaller dimension
        /// or when a connector with Angle==0 on segment is not its endpoint
        /// or when a connector with Angle==0 on polygon is not at its border (if it is edge, must be clocwise)
        /// </summary>
        protected void CheckPositions(IReadOnlyList<Point3D> positions, IPolytope polytope)
        {
            var message = $"{this} of object {OnTile.Name}: ";

            if (! (positions.Count == 1 || polytope is Polygon3D && positions.Count == 2))
                throw new InvalidOperationException(message + "connector contains too many points.");
                
            if (! positions.All(point => polytope.ContainsPoint(point)))
                throw new InvalidOperationException(message + "all points must lie on the object.");

            if (Angle.Radians == 0)
                if (polytope is Polygon3D)
                {
                    var polygon = polytope as Polygon3D;
                    switch (positions.Count)
                    {
                        case 1:
                            // If Angle == 0 => connector must be on the polygon's border
                            if (polygon.ContainsPoint(positions[0], MSystem.Tolerance))
                                throw new InvalidOperationException(message + "connector with zero angle must lie on the border.");
                            break;

                        case 2:
                            int i = -1;
                            int j = -1;
                            for (int k = 0; k < polygon.Count; k++)
                            {
                                if (polygon[k].MyEquals(positions[0]))
                                    i = k;
                                if (polygon[k].MyEquals(positions[1]))
                                    j = k;
                            }
                            if (! (i >= 0 && (i + 1) % polygon.Count == j))
                                throw new InvalidOperationException(message + "connector with zero angle must be an edge of polygon, clockwise.");
                            break;
                    }

                }
                else if (polytope is Segment3D && ! polytope.Contains(positions[0], PointComparer))
                    throw new InvalidOperationException(message + "connector with zero angle must lie at an endpoint of segment.");
        }
Beispiel #4
0
        /// <summary>
        /// Tile constructor. TODO low priority: separate constructor for vertices 1D, vertices 2D
        /// </summary>
        /// <param name="name">Name of the tile.</param>
        /// <param name="vertices">Vertices of the tile.</param>
        /// <param name="connectors">Connectors of the tile.</param>
        /// <param name="surfaceGlue">Surface glue of the tile.</param>
        /// <param name="proteins">Proteins of the tile.</param>
        /// <param name="color">Color of the tile (named if possible).</param>
        /// <param name="alpha">Alpha attribute of the color</param>
        /// <param name="alphaRatio">Tile resistor ratio, for cTAM tilings</param>
        public Tile(string name, IList <Point3D> vertices, IEnumerable <Connector> connectors, Glue surfaceGlue, IList <ProteinOnTile> proteins,
                    Color color, int alpha = 255, double alphaRatio = 1) : base(name)
        {
            Vertices    = CreateVertices(vertices, name);
            SurfaceGlue = surfaceGlue ?? new Glue("EmptyGlue");
            Color       = color;
            Alpha       = alpha;
            AlphaRatio  = alphaRatio;

            Proteins = new ReadOnlyCollection <ProteinOnTile>(proteins ?? new List <ProteinOnTile>());
            foreach (var protein in Proteins)
            {
                if (!Vertices.ContainsPoint(protein.Position))
                {
                    throw new InvalidOperationException($"{protein} must be on the object {name}.");
                }
            }

            Connectors = new ReadOnlyCollection <ConnectorOnTile>(connectors?.Select(conn => new ConnectorOnTile(this, conn)).ToList()
                                                                  ?? new List <ConnectorOnTile>());
        }
Beispiel #5
0
        /// <summary>
        /// Returns minimal distance of a vertex of "polytope" to an edge of this polygon in the direction of "movement".
        /// Boundary touches are ignored.
        /// Original position of the vertex must be outside the polygon.
        /// The result is bounded from above by the length of "movement".
        /// </summary>
        /// <param name="polytope"></param>
        /// <param name="movement"></param>
        private double UnidirectionalDistance(IPolytope polytope, Vector3D movement)
        {
            var distance = movement.Length;

            foreach (var point in polytope)
            {
                for (int i = 0; i < Edges.Count; i++)
                {
                    // if the final point  of the movement lies towards inside the polygon from the edge
                    if (v_EdgeNormals[i].DotProduct(point.ToVector3D() + movement) + v_D[i] > MSystem.Tolerance)
                    {
                        var closePoints = new Line3D(point, point + movement).ClosestPointsBetween(Edges[i], true);
                        if (closePoints.Item1.DistanceTo(closePoints.Item2) <= MSystem.Tolerance)
                        {
                            // The projection of "point" by pushingVector intersects "edge"
                            distance = Math.Min(distance, point.DistanceTo(closePoints.Item1));
                        }
                    }
                }
            }
            return(distance);
        }
Beispiel #6
0
        /// <summary>
        /// Calculates possible pushing of "another" polytope by this segment being itself
        /// pushed by "pushingVector" which MAY cause its intersection with "another".
        /// If this segment already intersects "another", "pushingVector" is returned.
        /// </summary>
        /// <param name="another">The vertices of object to be eventually pushed.</param>
        /// <param name="pushingVector">Pushing vector of this object.</param>
        /// <returns>Pushing vector of another object.</returns>
        public Vector3D PushingOf(IPolytope another, Vector3D pushingVector)
        {
            Polygon3D polygon = another as Polygon3D;

            if (polygon == null || pushingVector.Length < MSystem.Tolerance)  // length must be tested, otherwise the Polygon3D ctor may throw an exception
            {
                return(default(Vector3D));
            }

            if (this.Vector.IsParallelTo(pushingVector))
            {
                var intersection0 = polygon.IntersectionWith(this[0], this[0] + pushingVector);
                var intersection1 = polygon.IntersectionWith(this[1], this[1] + pushingVector);

                var vector0 = intersection0.IsNaN() ? pushingVector : intersection0 - this[0];
                var vector1 = intersection1.IsNaN() ? pushingVector : intersection1 - this[1];

                // Get minimal vector from this segment to the intersection point
                var minVector = vector0.Length > vector1.Length ? vector1 : vector0;
                return(pushingVector - minVector);
            }

            var projectionFace = new Polygon3D(new List <Point3D> {
                this[0], this[1], this[1] + pushingVector, this[0] + pushingVector
            },
                                               Name + "-pushing projection");
            double pLength = pushingVector.Length, distance = pLength;

            foreach (var point in polygon.IntersectionsWith(projectionFace))
            {
                distance = Math.Min(distance, point.DistanceTo(
                                        Edges[0].ClosestPointsBetween(new Line3D(point, point - pushingVector), true).Item2));
            }

            return(pushingVector.ScaleBy((pLength - distance) / pLength));
        }
Beispiel #7
0
 /// <summary>
 /// Calculates pushing of "another" polytope by this polygon, being itself
 /// pushed by "pushingVector" which MAY cause its intersection with "another".
 /// If this polygon already intersects "another", "pushingVector" is returned.
 /// </summary>
 /// <param name="another">The polytope to be eventually pushed.</param>
 /// <param name="pushingVector">Pushing vector of this polytope</param>
 /// <returns>Pushing vector of another polytope which is not longer than "pushingVector".</returns>
 public Vector3D PushingOf(IPolytope another, Vector3D pushingVector)
 {
     if (pushingVector.Length < MSystem.Tolerance)   // must be tested, otherwise the Polygon3D ctor may throw an exception
     {
         return(default);
Beispiel #8
0
        /// <summary>
        /// Gets all intersection of this segment with a list of vertices.
        /// Ignores boundary touchs within Msystem.Tolerance.
        /// </summary>
        /// <param name="another">Vertices to intersect with.</param>
        /// <returns>List of intersection points.</returns>
        public HashSet <Point3D> IntersectionsWith(IPolytope another)
        {
            var polygon = another as Polygon3D;

            return(polygon?.IntersectionsWith(this) ?? new HashSet <Point3D>());
        }