private Vector2D GetCircumcenter(List <Vector3D> points) { float u_ray; Line2D line1 = new Line2D(points[0], points[1]); Line2D line2 = new Line2D(points[2], points[0]); // Perpendicular bisectors Line2D bisector1 = new Line2D(line1.GetCoordinatesAt(0.5f), line1.GetCoordinatesAt(0.5f) + line1.GetPerpendicular()); Line2D bisector2 = new Line2D(line2.GetCoordinatesAt(0.5f), line2.GetCoordinatesAt(0.5f) + line2.GetPerpendicular()); bisector1.GetIntersection(bisector2, out u_ray); return(bisector1.GetCoordinatesAt(u_ray)); }
// returns true/false, u_line, u_ray public DynValue GetIntersection(float x3, float y3, float x4, float y4) { DynValue[] output = new DynValue[3]; float u_line = 0.0f; float u_ray = 0.0f; bool intersecting = l2d.GetIntersection(x3, y3, x4, y4, out u_ray, out u_line); if (float.IsInfinity(u_ray) || float.IsNaN(u_ray)) { u_ray = -1f; } if (float.IsInfinity(u_line) || float.IsNaN(u_line)) { u_line = -1f; } output[0] = DynValue.NewBoolean(intersecting); output[1] = DynValue.NewNumber(u_ray); output[2] = DynValue.NewNumber(u_line); return(DynValue.NewTuple(output)); }
/// <summary> /// Crop a polygon by a split line /// </summary> private static void CropPolygon(List <Vector2D> poly, Split split) { if (poly.Count == 0) { return; } Vector2D prev = poly[poly.Count - 1]; float side1 = (prev.y - split.pos.y) * split.delta.x - (prev.x - split.pos.x) * split.delta.y; List <Vector2D> newp = new List <Vector2D>(poly.Count); for (int i = 0; i < poly.Count; i++) { // Fetch vertex and determine side Vector2D cur = poly[i]; float side2 = (cur.y - split.pos.y) * split.delta.x - (cur.x - split.pos.x) * split.delta.y; // Front? if (side2 < -EPSILON) { if (side1 > EPSILON) { // Split line with plane and insert the vertex float u; Line2D.GetIntersection(split.pos, split.pos + split.delta, prev.x, prev.y, cur.x, cur.y, out u, false); Vector2D newv = prev + (cur - prev) * u; newp.Add(newv); } newp.Add(cur); } // Back? else if (side2 > EPSILON) { if (side1 < -EPSILON) { // Split line with plane and insert the vertex float u; Line2D.GetIntersection(split.pos, split.pos + split.delta, prev.x, prev.y, cur.x, cur.y, out u, false); Vector2D newv = prev + (cur - prev) * u; newp.Add(newv); } } else { // On the plane newp.Add(cur); } // Next prev = cur; side1 = side2; } poly.Clear(); poly.AddRange(newp); // The code below would be more efficient, because it modifies the polygon in place... // but it has a bug, some polygons are corrupted. /* * bool prevremoved = false; * float prevside = (prev.y - split.pos.y) * split.delta.x - (prev.x - split.pos.x) * split.delta.y; * int i = 0; * while(i < poly.Count) * { * Vector2D cur = poly[i]; * float curside = (cur.y - split.pos.y) * split.delta.x - (cur.x - split.pos.x) * split.delta.y; * * // Point is in FRONT of the split? * if(curside < -EPSILON) * { * if(prevside > EPSILON) * { * // Previous point was BEHIND the split * // Line crosses the split, we need to add the intersection point * float u; * Line2D.GetIntersection(split.pos, split.pos + split.delta, prev.x, prev.y, cur.x, cur.y, out u); * Vector2D newv = prev + (cur - prev) * u; * poly.Insert(i, newv); * i++; * } * else if(prevside < -EPSILON) * { * // Previous point was also in FRONT of the split * // We don't need to do anything * } * else * { * // Previous point was ON the split * // If the previous point was removed, we have to add it again * if(prevremoved) * { * poly.Insert(i, prev); * i++; * } * } * * i++; * prevremoved = false; * } * // Point is BEHIND the split? * else if(curside > EPSILON) * { * if(prevside < -EPSILON) * { * // Previous point was in FRONT of the split * // Line crosses the split, so we must add the intersection point * float u; * Line2D.GetIntersection(split.pos, split.pos + split.delta, prev.x, prev.y, cur.x, cur.y, out u); * Vector2D newv = prev + (cur - prev) * u; * poly.Insert(i, newv); * i++; * } * else if(prevside > EPSILON) * { * // Previous point was also BEHIND the split * // We don't need to do anything, this point will be removed * } * else * { * // Previous point was ON the split * // We don't need to do anything, this point will be removed * } * * poly.RemoveAt(i); * prevremoved = true; * } * // Point is ON the split? * else * { * if(prevside > EPSILON) * { * // Previous point was BEHIND the split * // Remove this point * poly.RemoveAt(i); * prevremoved = true; * } * else if(prevside < -EPSILON) * { * // Previous point was in FRONT of the split * // We want to keep this point * prevremoved = false; * i++; * } * else * { * // Previous point is ON the split * // Only if the previous point was also removed, we remove this one as well * if(prevremoved) * poly.RemoveAt(i); * else * i++; * } * } * * prev = cur; * prevside = curside; * } */ }
// This runs the check public override void Run() { BlockMap <BlockEntry> blockmap = BuilderPlug.Me.ErrorCheckForm.BlockMap; int progress = 0; int stepprogress = 0; float maxradius = 0; Dictionary <int, HashSet <int> > processedthingpairs = new Dictionary <int, HashSet <int> >(); //mxd foreach (ThingTypeInfo tti in General.Map.Data.ThingTypes) { if (tti.Radius > maxradius) { maxradius = tti.Radius; } } // Go for all the things foreach (Thing t in General.Map.Map.Things) { ThingTypeInfo info = General.Map.Data.GetThingInfo(t.Type); bool stuck = false; // Check this thing for getting stuck? if ((info.ErrorCheck == ThingTypeInfo.THING_ERROR_INSIDE_STUCK) && (info.Blocking > ThingTypeInfo.THING_BLOCKING_NONE)) { // Make square coordinates from thing float blockingsize = t.Size - ALLOWED_STUCK_DISTANCE; Vector2D lt = new Vector2D(t.Position.x - blockingsize, t.Position.y - blockingsize); Vector2D rb = new Vector2D(t.Position.x + blockingsize, t.Position.y + blockingsize); Vector2D bmlt = new Vector2D(t.Position.x - maxradius, t.Position.y - maxradius); Vector2D bmrb = new Vector2D(t.Position.x + maxradius, t.Position.y + maxradius); // Go for all the lines to see if this thing is stuck List <BlockEntry> blocks = blockmap.GetSquareRange(new RectangleF(bmlt.x, bmlt.y, (bmrb.x - bmlt.x), (bmrb.y - bmlt.y))); Dictionary <Linedef, Linedef> doneblocklines = new Dictionary <Linedef, Linedef>(blocks.Count * 3); foreach (BlockEntry b in blocks) { foreach (Linedef l in b.Lines) { // Only test when sinlge-sided, two-sided + impassable and not already checked if (((l.Back == null) || l.IsFlagSet(General.Map.Config.ImpassableFlag)) && !doneblocklines.ContainsKey(l)) { // Test if line ends are inside the thing if (PointInRect(lt, rb, l.Start.Position) || PointInRect(lt, rb, l.End.Position)) { // Thing stuck in line! stuck = true; SubmitResult(new ResultStuckThingInLine(t, l)); } // Test if the line intersects the square else if (Line2D.GetIntersection(l.Start.Position, l.End.Position, lt.x, lt.y, rb.x, lt.y) || Line2D.GetIntersection(l.Start.Position, l.End.Position, rb.x, lt.y, rb.x, rb.y) || Line2D.GetIntersection(l.Start.Position, l.End.Position, rb.x, rb.y, lt.x, rb.y) || Line2D.GetIntersection(l.Start.Position, l.End.Position, lt.x, rb.y, lt.x, lt.y)) { // Thing stuck in line! stuck = true; SubmitResult(new ResultStuckThingInLine(t, l)); } // Checked doneblocklines.Add(l, l); } } // Check if thing is stuck in other things if (info.Blocking != ThingTypeInfo.THING_BLOCKING_NONE) { foreach (Thing ot in b.Things) { // Don't compare the thing with itself if (t.Index == ot.Index) { continue; } // mxd. Don't compare already processed stuff if (processedthingpairs.ContainsKey(t.Index) && processedthingpairs[t.Index].Contains(ot.Index)) { continue; } // Only check of items that can block if (General.Map.Data.GetThingInfo(ot.Type).Blocking == ThingTypeInfo.THING_BLOCKING_NONE) { continue; } // need to compare the flags if (FlagsOverlap(t, ot) && ThingsOverlap(t, ot)) { stuck = true; SubmitResult(new ResultStuckThingInThing(t, ot)); } //mxd. Prepare collections if (!processedthingpairs.ContainsKey(t.Index)) { processedthingpairs.Add(t.Index, new HashSet <int>()); } if (!processedthingpairs.ContainsKey(ot.Index)) { processedthingpairs.Add(ot.Index, new HashSet <int>()); } //mxd. Add both ways processedthingpairs[t.Index].Add(ot.Index); processedthingpairs[ot.Index].Add(t.Index); } } } } // Check this thing for being outside the map? if (!stuck && info.ErrorCheck >= ThingTypeInfo.THING_ERROR_INSIDE) { // Get the nearest line to see if the thing is outside the map bool outside; Linedef l = General.Map.Map.NearestLinedef(t.Position); if (l.SideOfLine(t.Position) <= 0) { outside = (l.Front == null); } else { outside = (l.Back == null); } // Outside the map? if (outside) { // Make result SubmitResult(new ResultThingOutside(t)); } } // Handle thread interruption try { Thread.Sleep(0); } catch (ThreadInterruptedException) { return; } // We are making progress! if ((++progress / PROGRESS_STEP) > stepprogress) { stepprogress = (progress / PROGRESS_STEP); AddProgress(1); } } }
// This runs the check public override void Run() { BlockMap <BlockEntry> blockmap = BuilderPlug.Me.ErrorCheckForm.BlockMap; int progress = 0; int stepprogress = 0; // Go for all the things foreach (Thing t in General.Map.Map.Things) { ThingTypeInfo info = General.Map.Data.GetThingInfo(t.Type); bool stucked = false; // Check this thing for getting stucked? if ((info.ErrorCheck == ThingTypeInfo.THING_ERROR_INSIDE_STUCKED) && (info.Blocking > ThingTypeInfo.THING_BLOCKING_NONE)) { // Make square coordinates from thing float blockingsize = t.Size - ALLOWED_STUCK_DISTANCE; Vector2D lt = new Vector2D(t.Position.x - blockingsize, t.Position.y - blockingsize); Vector2D rb = new Vector2D(t.Position.x + blockingsize, t.Position.y + blockingsize); // Go for all the lines to see if this thing is stucked List <BlockEntry> blocks = blockmap.GetSquareRange(new RectangleF(lt.x, lt.y, (rb.x - lt.x), (rb.y - lt.y))); Dictionary <Linedef, Linedef> doneblocklines = new Dictionary <Linedef, Linedef>(blocks.Count * 3); foreach (BlockEntry b in blocks) { foreach (Linedef l in b.Lines) { // Only test when sinlge-sided and not already checked if ((l.Back == null) && !doneblocklines.ContainsKey(l)) { // Test if line ends are inside the thing if (PointInRect(lt, rb, l.Start.Position) || PointInRect(lt, rb, l.End.Position)) { // Thing stucked in line! stucked = true; } // Test if the line intersects the square else if (Line2D.GetIntersection(l.Start.Position, l.End.Position, lt.x, lt.y, rb.x, lt.y) || Line2D.GetIntersection(l.Start.Position, l.End.Position, rb.x, lt.y, rb.x, rb.y) || Line2D.GetIntersection(l.Start.Position, l.End.Position, rb.x, rb.y, lt.x, rb.y) || Line2D.GetIntersection(l.Start.Position, l.End.Position, lt.x, rb.y, lt.x, lt.y)) { // Thing stucked in line! stucked = true; } // Checked doneblocklines.Add(l, l); } } } } // Stucked? if (stucked) { // Make result SubmitResult(new ResultStuckedThing(t)); } else { // Check this thing for being outside the map? if (info.ErrorCheck >= ThingTypeInfo.THING_ERROR_INSIDE) { // Get the nearest line to see if the thing is outside the map bool outside = false; Linedef l = General.Map.Map.NearestLinedef(t.Position); if (l.SideOfLine(t.Position) <= 0) { outside = (l.Front == null); } else { outside = (l.Back == null); } // Outside the map? if (outside) { // Make result SubmitResult(new ResultThingOutside(t)); } } } // Handle thread interruption try { Thread.Sleep(0); } catch (ThreadInterruptedException) { return; } // We are making progress! if ((++progress / PROGRESS_STEP) > stepprogress) { stepprogress = (progress / PROGRESS_STEP); AddProgress(1); } } }
public bool GetIntersection(Line2D ray, out float u_ray, out float u_line) { return(Line2D.GetIntersection(v1, v2, ray.v1.x, ray.v1.y, ray.v2.x, ray.v2.y, out u_ray, out u_line)); }
public bool GetIntersection(Line2D ray) { return(Line2D.GetIntersection(v1, v2, ray.v1.x, ray.v1.y, ray.v2.x, ray.v2.y)); }
public bool GetIntersection(float x3, float y3, float x4, float y4, out float u_ray, out float u_line) { return(Line2D.GetIntersection(v1, v2, x3, y3, x4, y4, out u_ray, out u_line)); }
public bool GetIntersection(float x3, float y3, float x4, float y4) { return(Line2D.GetIntersection(v1, v2, x3, y3, x4, y4)); }
// This checks if a line is inside a triangle (touching the triangle is allowed) // NOTE: We already know p1 is on an edge segment of the triangle private static bool LineInsideTriangle(EarClipVertex[] t, Vector2D p1, Vector2D p2) { float s01 = Line2D.GetSideOfLine(t[0].Position, t[1].Position, p2); float s12 = Line2D.GetSideOfLine(t[1].Position, t[2].Position, p2); float s20 = Line2D.GetSideOfLine(t[2].Position, t[0].Position, p2); float p2_on_edge = 2.0f; // somewhere outside the 0 .. 1 range float p1_on_same_edge = 2.0f; // Test if p2 is inside the triangle if ((s01 < 0.0f) && (s12 < 0.0f) && (s20 < 0.0f)) { // Line is inside triangle, because p2 is return(true); } // Test if p2 is on an edge of the triangle and if it is we would // like to know where on the edge segment p2 is if (s01 == 0.0f) { p2_on_edge = Line2D.GetNearestOnLine(t[0].Position, t[1].Position, p2); p1_on_same_edge = Line2D.GetSideOfLine(t[0].Position, t[1].Position, p1); } else if (s12 == 0.0f) { p2_on_edge = Line2D.GetNearestOnLine(t[1].Position, t[2].Position, p2); p1_on_same_edge = Line2D.GetSideOfLine(t[1].Position, t[2].Position, p1); } else if (s20 == 0.0f) { p2_on_edge = Line2D.GetNearestOnLine(t[2].Position, t[0].Position, p2); p1_on_same_edge = Line2D.GetSideOfLine(t[2].Position, t[0].Position, p1); } // Is p2 actually on the edge segment? if ((p2_on_edge >= 0.0f) && (p2_on_edge <= 1.0f)) { // If p1 is on the same edge (or the unlimited line of that edge) // then the line is not inside this triangle. if (p1_on_same_edge == 0.0f) { return(false); } } // Do a complete line-triangle intersection test // We already know p1 is not inside the triangle (possibly on an edge) Line2D p = new Line2D(p1, p2); Line2D t01 = new Line2D(t[0].Position, t[1].Position); Line2D t12 = new Line2D(t[1].Position, t[2].Position); Line2D t20 = new Line2D(t[2].Position, t[0].Position); float pu, pt; //mxd. Test intersections if (t01.GetIntersection(p, out pu, out pt)) { return(true); } if (t12.GetIntersection(p, out pu, out pt)) { return(true); } if (t20.GetIntersection(p, out pu, out pt)) { return(true); } return(false); }
// This finds the cut coordinates and splits the other poly with inner vertices private static void SplitOuterWithInner(LinkedListNode <EarClipVertex> start, EarClipPolygon p) { LinkedListNode <EarClipVertex> insertbefore = null; float foundu = float.MaxValue; Vector2D foundpos = new Vector2D(); // Create a line from start that goes beyond the right most vertex of p LinkedListNode <EarClipVertex> pr = FindRightMostVertex(p); float startx = start.Value.Position.x; float endx = pr.Value.Position.x + 10.0f; Line2D starttoright = new Line2D(start.Value.Position, new Vector2D(endx, start.Value.Position.y)); // Calculate a small bonus (0.1 mappixel) float bonus = starttoright.GetNearestOnLine(new Vector2D(start.Value.Position.x + 0.1f, start.Value.Position.y)); // Go for all lines in the outer polygon LinkedListNode <EarClipVertex> v1 = p.Last; LinkedListNode <EarClipVertex> v2 = p.First; while (v2 != null) { // Check if the line goes between startx and endx if ((v1.Value.Position.x > startx || v2.Value.Position.x > startx) && (v1.Value.Position.x < endx || v2.Value.Position.x < endx)) { // Find intersection Line2D pl = new Line2D(v1.Value.Position, v2.Value.Position); float u, ul; pl.GetIntersection(starttoright, out u, out ul); if (float.IsNaN(u)) { // We have found a line that is perfectly horizontal // (parallel to the cut scan line) Check if the line // is overlapping the cut scan line. if (v1.Value.Position.y == start.Value.Position.y) { // This is an exceptional situation which causes a bit of a problem, because // this could be a previously made cut, which overlaps another line from the // same cut and we have to determine which of the two we will join with. If we // pick the wrong one, the polygon is no longer valid and triangulation will fail. // Calculate distance of each vertex in units u = starttoright.GetNearestOnLine(v1.Value.Position); ul = starttoright.GetNearestOnLine(v2.Value.Position); // Rule out vertices before the scan line if (u < 0.0f) { u = float.MaxValue; } if (ul < 0.0f) { ul = float.MaxValue; } float insert_u = Math.Min(u, ul); Vector2D inserpos = starttoright.GetCoordinatesAt(insert_u); // Check in which direction the line goes. if (v1.Value.Position.x > v2.Value.Position.x) { // The line goes from right to left (towards our start point) // so we must always insert our cut after this line. // If the next line goes up, we consider this a better candidate than // a horizontal line that goes from left to right (the other cut line) // so we give it a small bonus. LinkedListNode <EarClipVertex> v3 = v2.Next ?? v2.List.First; if (v3.Value.Position.y < v2.Value.Position.y) { insert_u -= bonus; } // Remember this when it is a closer match if (insert_u <= foundu) { insertbefore = v2.Next ?? v2.List.First; foundu = insert_u; foundpos = inserpos; } } else { // The line goes from left to right (away from our start point) // so we must always insert our cut before this line. // If the previous line goes down, we consider this a better candidate than // a horizontal line that goes from right to left (the other cut line) // so we give it a small bonus. LinkedListNode <EarClipVertex> v3 = v1.Previous ?? v1.List.Last; if (v3.Value.Position.y > v1.Value.Position.y) { insert_u -= bonus; } // Remember this when it is a closer match if (insert_u <= foundu) { insertbefore = v2; foundu = insert_u; foundpos = inserpos; } } } } // Found a closer match? else if ((ul >= 0.0f) && (ul <= 1.0f) && (u > 0.0f) && (u <= foundu)) { // Found a closer intersection insertbefore = v2; foundu = u; foundpos = starttoright.GetCoordinatesAt(u); } } // Next v1 = v2; v2 = v2.Next; } // Found anything? if (insertbefore != null) { Sidedef sd = (insertbefore.Previous == null) ? insertbefore.List.Last.Value.Sidedef : insertbefore.Previous.Value.Sidedef; // Find the position where we have to split the outer polygon EarClipVertex split = new EarClipVertex(foundpos, null); // Insert manual split vertices p.AddBefore(insertbefore, new EarClipVertex(split, sd)); // Start inserting from the start (do I make sense this time?) v1 = start; do { // Insert inner polygon vertex p.AddBefore(insertbefore, new EarClipVertex(v1.Value)); v1 = (v1.Next ?? v1.List.First); } while (v1 != start); // Insert manual split vertices p.AddBefore(insertbefore, new EarClipVertex(start.Value, sd)); if (split.Position != insertbefore.Value.Position) { p.AddBefore(insertbefore, new EarClipVertex(split, sd)); } } }