/// <summary> /// Applies the slopes to the sectors. /// /// We have: /// - theta /// - offset angle ("offset") /// - horizontal line length ("length") /// /// What we need to compute: /// - x coordinate where the line starts in the circle ("left", this is cos(theta + offset angle)) /// - x coordinate where the line ends in the circle ("middle", this is cos(offset angle)) /// /// With this data we can calculate some more required variables: /// - radius: length / (middle - left) /// - left delimiter: cos(offset + theta) * radius /// - right delimiter: cos(rotation) * radius (should be same as left delimiter + length) /// - section start, in map units: cos(offset + theta) * radius /// - base height offset (where the slope starts) /// /// Then we can simply use pythagoras to compute the y position for an x position on the length /// </summary> public void ApplySlope() { double left = Math.Cos(theta + offsetangle); double middle = Math.Cos(offsetangle); double radius = length / (middle - left); double leftdelimiter = Math.Cos(offsetangle + theta); double rightdelimiter = Math.Cos(offsetangle); double sectionstart = Math.Cos(offsetangle + theta) * radius; baseheightoffset = Math.Sqrt(radius * radius - sectionstart * sectionstart) * scale; foreach (BaseVisualGeometrySector bvgs in sectors) { HashSet <Vertex> vertices = new HashSet <Vertex>(bvgs.Sector.Sides.Count * 2); double u1 = 1.0; double u2 = 0.0; foreach (Sidedef sd in bvgs.Sector.Sides.Keys) { vertices.Add(sd.Line.Start); vertices.Add(sd.Line.End); } // Get the two points that are the furthest apart on the line between the slope handles foreach (Vertex v in vertices) { double intersection = handleline.GetNearestOnLine(v.Position); if (intersection < u1) { u1 = intersection; } if (intersection > u2) { u2 = intersection; } } // Compute the x position and the corrosponding height of the coordinates double xpos1 = sectionstart + (u1 * length); double xpos2 = sectionstart + (u2 * length); double height1 = Math.Sqrt(radius * radius - xpos1 * xpos1) * scale; double height2 = Math.Sqrt(radius * radius - xpos2 * xpos2) * scale; if (double.IsNaN(height1)) { height1 = 0.0; } if (double.IsNaN(height2)) { height2 = 0.0; } // Adjust the heights height1 = height1 - baseheightoffset + baseheight + heightoffset; height2 = height2 - baseheightoffset + baseheight + heightoffset; // Get the angle of the slope. We cheat a bit and substitute the y value of the vectors with the height of the points double slopeangle = Vector2D.GetAngle(new Vector2D(xpos1, height1), new Vector2D(xpos2, height2)); // Always let the plane point up, VisualSidedefSlope.ApplySlope will invert it if necessary Plane plane = new Plane(new Vector3D(handleline.GetCoordinatesAt(u1), height1), handleline.GetAngle() + Angle2D.PIHALF, slopeangle, true); VisualSidedefSlope.ApplySlope(bvgs.Level, plane, mode); bvgs.Sector.UpdateSectorGeometry(true); } }
// This clips a polygon and returns the triangles // The polygon may not have any holes or islands // See: http://www.geometrictools.com/Documentation/TriangulationByEarClipping.pdf private int DoEarClip(EarClipPolygon poly, List <Vector2D> verticeslist, List <Sidedef> sidedefslist) { LinkedList <EarClipVertex> verts = new LinkedList <EarClipVertex>(); List <EarClipVertex> convexes = new List <EarClipVertex>(poly.Count); LinkedList <EarClipVertex> reflexes = new LinkedList <EarClipVertex>(); LinkedList <EarClipVertex> eartips = new LinkedList <EarClipVertex>(); LinkedListNode <EarClipVertex> n2; EarClipVertex[] t; int countvertices = 0; // Go for all vertices to fill list foreach (EarClipVertex vec in poly) { vec.SetVertsLink(verts.AddLast(vec)); } // Remove any zero-length lines, these will give problems LinkedListNode <EarClipVertex> n1 = verts.First; do { // Continue until adjacent zero-length lines are removed n2 = n1.Next ?? verts.First; Vector2D d = n1.Value.Position - n2.Value.Position; while ((Math.Abs(d.x) < 0.00001f) && (Math.Abs(d.y) < 0.00001f)) { n2.Value.Remove(); n2 = n1.Next ?? verts.First; if (n2 != null) { d = n1.Value.Position - n2.Value.Position; } else { break; } } // Next! n1 = n2; }while (n1 != verts.First); // Optimization: Vertices which have lines with the // same angle are useless. Remove them! n1 = verts.First; while (n1 != null) { // Get the next vertex n2 = n1.Next; // Get triangle for v t = GetTriangle(n1.Value); // Check if both lines have the same angle Line2D a = new Line2D(t[0].Position, t[1].Position); Line2D b = new Line2D(t[1].Position, t[2].Position); if (Math.Abs(Angle2D.Difference(a.GetAngle(), b.GetAngle())) < 0.00001f) { // Same angles, remove vertex n1.Value.Remove(); } // Next! n1 = n2; } // Go for all vertices to determine reflex or convex foreach (EarClipVertex vv in verts) { // Add to reflex or convex list if (IsReflex(GetTriangle(vv))) { vv.AddReflex(reflexes); } else { convexes.Add(vv); } } // Go for all convex vertices to see if they are ear tips foreach (EarClipVertex cv in convexes) { // Add when this is a valid ear t = GetTriangle(cv); if (CheckValidEar(t, reflexes)) { cv.AddEarTip(eartips); } } /*#if DEBUG * if (OnShowPolygon != null) OnShowPolygon(verts); #endif*/ // Process ears until done while ((eartips.Count > 0) && (verts.Count > 2)) { // Get next ear EarClipVertex v = eartips.First.Value; t = GetTriangle(v); // Only save this triangle when it has an area if (TriangleHasArea(t)) { // Add ear as triangle AddTriangleToList(t, verticeslist, sidedefslist, (verts.Count == 3)); countvertices += 3; } // Remove this ear from all lists v.Remove(); EarClipVertex v1 = t[0]; EarClipVertex v2 = t[2]; /*#if DEBUG * if (TriangleHasArea(t)) * { * if (OnShowEarClip != null) OnShowEarClip(t, verts); * } #endif*/ // Test first neighbour EarClipVertex[] t1 = GetTriangle(v1); //bool t1a = true; //TriangleHasArea(t1); if (/*t1a && */ IsReflex(t1)) { // List as reflex if not listed yet if (!v1.IsReflex) { v1.AddReflex(reflexes); } v1.RemoveEarTip(); } else { // Remove from reflexes v1.RemoveReflex(); } // Test second neighbour EarClipVertex[] t2 = GetTriangle(v2); //bool t2a = true; //TriangleHasArea(t2); if (/*t2a && */ IsReflex(t2)) { // List as reflex if not listed yet if (!v2.IsReflex) { v2.AddReflex(reflexes); } v2.RemoveEarTip(); } else { // Remove from reflexes v2.RemoveReflex(); } // Check if any neightbour have become a valid or invalid ear if (!v1.IsReflex && (/*!t1a || */ CheckValidEar(t1, reflexes))) { v1.AddEarTip(eartips); } else { v1.RemoveEarTip(); } if (!v2.IsReflex && (/*!t2a || */ CheckValidEar(t2, reflexes))) { v2.AddEarTip(eartips); } else { v2.RemoveEarTip(); } } /*#if DEBUG * if (OnShowRemaining != null) OnShowRemaining(verts); #endif*/ // Dispose remaining vertices foreach (EarClipVertex ecv in verts) { ecv.Dispose(); } // Return the number of vertices in the result return(countvertices); }
public float GetAngle() { return(l2d.GetAngle()); }
// This generates the vertices to split the line with, from start to end private List<Vector2D> GenerateCurve(Line2D line, int vertices, float angle, bool backwards, float distance, bool fixedcurve) { // Make list List<Vector2D> points = new List<Vector2D>(vertices); //Added by Anders Åstrand 2008-05-18 //The formulas used are taken from http://mathworld.wolfram.com/CircularSegment.html //c and theta are known (length of line and angle parameter). d, R and h are //calculated from those two //If the curve is not supposed to be a circular segment it's simply deformed to fit //the value set for distance. //The vertices are generated to be evenly distributed (by angle) along the curve //and lastly they are rotated and moved to fit with the original line //calculate some identities of a circle segment (refer to the graph in the url above) double c = line.GetLength(); double theta = angle; double d = (c / Math.Tan(theta / 2)) / 2; double R = d / Math.Cos(theta / 2); double h = R - d; double yDeform = fixedcurve ? 1 : distance / h; if (backwards) yDeform = -yDeform; double a, x, y; Vector2D vertex; for (int v = 1; v <= vertices; v++) { //calculate the angle for this vertex //the curve starts at PI/2 - theta/2 and is segmented into vertices+1 segments //this assumes the line is horisontal and on y = 0, the point is rotated and moved later a = (Math.PI - theta) / 2 + v * (theta / (vertices + 1)); //calculate the coordinates of the point, and distort the y coordinate //using the deform factor calculated above x = Math.Cos(a) * R; y = (Math.Sin(a) * R - d) * yDeform; //rotate and transform to fit original line vertex = new Vector2D((float)x, (float)y).GetRotated(line.GetAngle() + Angle2D.PIHALF); vertex = vertex.GetTransformed(line.GetCoordinatesAt(0.5f).x, line.GetCoordinatesAt(0.5f).y, 1, 1); points.Add(vertex); } // Done return points; }