/// <summary> /// Gets the set of floating objects within a given prism. /// Both objects used and unused in this simulation step are considered. /// </summary> public FloatingObjectsSet GetObjectsInPrism(Polygon3D basePolygon, Vector3D vector) { FloatingObjectsSet insideObjects = new FloatingObjectsSet(); var topPolygon = basePolygon.Select(vertex => vertex + vector); foreach (var key in KeysInBox(new Box3D(basePolygon.Union(topPolygon)))) { insideObjects.UnionWith(v_Grid[key].OldSet.GetHashSet().Where(fltObject => basePolygon.IntersectsWith(fltObject.Position, fltObject.Position - vector))); insideObjects.UnionWith(v_Grid[key].NewSet.GetHashSet().Where(fltObject => basePolygon.IntersectsWith(fltObject.Position, fltObject.Position - vector))); } return(insideObjects); }
/// <summary> /// True if (a) both polygons lie in the same plane (vertical distance up to Msystem.Tolerance), and /// (b) they overlap (the overlapping horizontal distance exceeds Msystem.Tolerance) /// </summary> public bool OverlapsWith(Polygon3D another) { if (!(Normal.IsParallelTo(another.Normal) && Plane.AbsoluteDistanceTo(another[0]) < MSystem.Tolerance)) { return(false); } // If one polygon contains inside a vertex of another, then they overlap // Border tolerance is allowed for case that they just touch (do not overlap) if (another.Any(t => ContainsPoint(t, MSystem.Tolerance)) || this.Any(t => another.ContainsPoint(t, MSystem.Tolerance))) { return(true); } // Now check the case when no vertex of one polygon lies inside another var intersections = new HashSet <Point3D>(); foreach (var edge1 in Edges) { foreach (var edge2 in another.Edges) { var intersection = edge1.ClosestPointsBetween(edge2, true); if (intersection.Item1.DistanceTo(intersection.Item2) < MSystem.Tolerance) { intersections.Add(intersection.Item1); } } } if (!intersections.Any()) { return(false); } // Again exclude the case when they just touch and do not overlap var c = Point3D.Centroid(intersections); return(ContainsPoint(c, MSystem.Tolerance) || another.ContainsPoint(c, MSystem.Tolerance)); }
/// <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)); }
/// <summary> /// Gives the reference point close to a given position around which we search for / add / remove floating objects /// inside/outside this object. If the object is not 2D, the first argument is returned. /// </summary> /// <param name="position">Position on tiles (typically of connector or protein)</param> /// <param name="side">Side of the tile</param> /// <returns>Reference point corresponding to "inside"/"outside" parameter</returns> public Point3D SidePoint(Point3D position, Tile.SideType side) { Polygon3D polygon = Vertices as Polygon3D; return(polygon?.SidePoint(position, side) ?? position); }