public void PerpendicularTest_float() { LineF line1 = new LineF(1, 2, 3, 4); LineF line2 = line1.Perpendicular(5, 6); Assert.AreEqual(-1.0 / line1.M, line2.M); }
public void LocateCollinearReverse() { LineD reverseDiagD = diagD.Reverse(); Assert.AreEqual(LineLocation.End, reverseDiagD.LocateCollinear(new PointD(0, 0))); Assert.AreEqual(LineLocation.Start, reverseDiagD.LocateCollinear(new PointD(2, 2))); Assert.AreEqual(LineLocation.After, reverseDiagD.LocateCollinear(new PointD(-1, -1))); Assert.AreEqual(LineLocation.Between, reverseDiagD.LocateCollinear(new PointD(1, 1))); Assert.AreEqual(LineLocation.Before, reverseDiagD.LocateCollinear(new PointD(3, 3))); Assert.AreEqual(LineLocation.Between, reverseDiagD.LocateCollinear(new PointD(0, 1))); Assert.AreEqual(LineLocation.Between, reverseDiagD.LocateCollinear(new PointD(1, 0))); LineF reverseDiagF = diagF.Reverse(); Assert.AreEqual(LineLocation.End, reverseDiagF.LocateCollinear(new PointF(0, 0))); Assert.AreEqual(LineLocation.Start, reverseDiagF.LocateCollinear(new PointF(2, 2))); Assert.AreEqual(LineLocation.After, reverseDiagF.LocateCollinear(new PointF(-1, -1))); Assert.AreEqual(LineLocation.Between, reverseDiagF.LocateCollinear(new PointF(1, 1))); Assert.AreEqual(LineLocation.Before, reverseDiagF.LocateCollinear(new PointF(3, 3))); Assert.AreEqual(LineLocation.Between, reverseDiagF.LocateCollinear(new PointF(0, 1))); Assert.AreEqual(LineLocation.Between, reverseDiagF.LocateCollinear(new PointF(1, 0))); LineI reverseDiagI = diagI.Reverse(); Assert.AreEqual(LineLocation.End, reverseDiagI.LocateCollinear(new PointI(0, 0))); Assert.AreEqual(LineLocation.Start, reverseDiagI.LocateCollinear(new PointI(2, 2))); Assert.AreEqual(LineLocation.After, reverseDiagI.LocateCollinear(new PointI(-1, -1))); Assert.AreEqual(LineLocation.Between, reverseDiagI.LocateCollinear(new PointI(1, 1))); Assert.AreEqual(LineLocation.Before, reverseDiagI.LocateCollinear(new PointI(3, 3))); Assert.AreEqual(LineLocation.Between, reverseDiagI.LocateCollinear(new PointI(0, 1))); Assert.AreEqual(LineLocation.Between, reverseDiagI.LocateCollinear(new PointI(1, 0))); }
public static WallCoord GetNearestPortalableEdge(IList<IWall> walls, Vector2 point, float maxRadius, float portalSize) { WallCoord wallCoord = null; double distanceMin = -1; for (int i = 0; i < walls.Count; i++) { IList<Vector2> vertices = walls[i].GetWorldVertices(); for (int edgeIndex = 0; edgeIndex < walls[i].Vertices.Count; edgeIndex++) { int edgeIndexNext = (edgeIndex + 1) % vertices.Count; LineF edge = new LineF(vertices[edgeIndex], vertices[edgeIndexNext]); if (!EdgeValidLength(edge.Length, portalSize)) { continue; } Vector2 nearPos = edge.Nearest(point, true); float portalT = edge.NearestT(point, true); portalT = GetValidT(portalT, edge, portalSize); Vector2 portalPos = edge.Lerp(portalT); double distance = (portalPos - point).Length; if (maxRadius < (nearPos - point).Length) { continue; } if (distanceMin == -1 || distance < distanceMin) { wallCoord = new WallCoord(walls[i], edgeIndex, portalT); distanceMin = distance; } } } return wallCoord; }
static void Main(string[] args) { Point p = new Point(10, 30); Point p1 = new Point(10, 45); Point p2 = new Point(10, 60); Point p3 = new Point(10, 85); Point p4 = new Point(10, 100); Point p5 = new Point(30, 100); Point p6 = new Point(50, 100); Point p7 = new Point(50, 70); Point p8 = new Point(50, 50); Point p9 = new Point(0, 50); LineF l01 = new LineF(p, p1); LineF l12 = new LineF(p1, p2); LineF l23 = new LineF(p2, p3); LineF l34 = new LineF(p3, p4); LineF l45 = new LineF(p4, p5); LineF l56 = new LineF(p5, p6); LineF l67 = new LineF(p6, p7); LineF l78 = new LineF(p7, p8); LineF l89 = new LineF(p8, p9); List <Point> output = new List <Point>(); output.Add(p1); output.Add(p2); output.Add(p3); output.Add(p4); output.Add(p5); output.Add(p6); output.Add(p7); output.Add(p8); output.Add(p9); int count = 0; List <LineF> lines = new List <LineF>(); foreach (LineF line in lines) { line.Intersection(line); Console.WriteLine("X:" + line.X1 + " Y:" + line.Y1); Console.WriteLine(count); Console.ReadKey(); } //foreach (Point point in output) //{ // double res = point.X; // double rez = point.Y; // count++; // Console.WriteLine(" X:" + res + " Y:" + rez); //} Console.WriteLine(count); Console.ReadKey(); }
/* * Heal rows by calculating median row height * and splitting bigger rows by that row height */ private List <RowInfo> HealRows(List <RowInfo> rows, List <LineF> horizLines, float leftX, float rightX) { List <float> rowHeights = rows.Select(row => RowHeight(row)).OrderBy(h => h).ToList(); float medianRowHeight = rowHeights[rowHeights.Count / 2]; return(rows.SelectMany(row => { float possibleInnerRows = RowHeight(row) / medianRowHeight; int innerRowCount = (int)Math.Round(possibleInnerRows); float ratio = innerRowCount / possibleInnerRows; if (innerRowCount > 1 && ratio > 0.9 && ratio < 1.1) { // this row can be divided into several smaller ones // because we can fit whole number of median row heights into it float innerRowHeight = RowHeight(row) / innerRowCount; List <LineF> innerRowLines = new List <LineF>(); for (int ir = 1; ir < innerRowCount; ir++) { float irY = row.topLine.p1.Y + ir * innerRowHeight; if (horizLines.Find(hl => Math.Abs(hl.p1.Y - irY) < 5) != null) { // we can find real (sub-threshold) line for this Y, // so we confirm our guess innerRowLines.Add(new LineF(new PointF(leftX, irY), new PointF(rightX, irY))); } } // check that we were able to confirm our guess for all inner lines if (innerRowLines.Count == innerRowCount - 1) { // return guessed rows List <RowInfo> innerRows = new List <RowInfo>(); innerRowLines.Add(row.bottomLine); LineF prevLine = row.topLine; for (int ir = 0; ir < innerRowCount; ir++) { innerRows.Add(new RowInfo { topLine = prevLine, bottomLine = innerRowLines[ir], dividers = new List <float>(row.dividers) }); prevLine = innerRowLines[ir]; } return innerRows; } else { // return orignal row return new List <RowInfo> { row }; } } else { return new List <RowInfo> { row }; } }).ToList()); }
private InsetVertex CombineVectorLines(InsetVertex prev, InsetVertex next, double thickness) { var prevLine = new LineF(prev.Previous, prev.Outer); var nextLine = new LineF(next.Outer, next.Next); var newOuter = prevLine.Intersect(nextLine); return(new InsetVertex(newOuter, prev.Previous, next.Next, thickness)); }
public void ArrayAccessorTest1() { LineF line = new LineF(new Vector2(1f, 5f), new Vector2(100.1f, 2f)); line[0] = new Vector2(9f, 2.2f); line[1] = new Vector2(99f, 92.2f); Assert.IsTrue(line[0] == new Vector2(9f, 2.2f)); Assert.IsTrue(line[1] == new Vector2(99f, 92.2f)); }
private static void AddIfIntersect(LineF first, LineF second, ICollection <PointF> result) { var intersection = first.Intersection(second); if (intersection != null) { result.Add(intersection.Value); } }
static void Main(string[] args) { Point p = new Point(10, 30); Point p1 = new Point(10, 45); Point p2 = new Point(10, 60); Point p3 = new Point(10, 85); Point p4 = new Point(10, 100); Point p5 = new Point(30, 100); Point p6 = new Point(50, 100); Point p7 = new Point(50, 70); Point p8 = new Point(50, 50); Point p9 = new Point(0, 50); LineF l01 = new LineF(p, p1); LineF l12 = new LineF(p1, p2); LineF l23 = new LineF(p2, p3); LineF l34 = new LineF(p3, p4); LineF l45 = new LineF(p4, p5); LineF l56 = new LineF(p5, p6); LineF l67 = new LineF(p6, p7); LineF l78 = new LineF(p7, p8); LineF l89 = new LineF(p8, p9); List<Point> output = new List<Point>(); output.Add(p1); output.Add(p2); output.Add(p3); output.Add(p4); output.Add(p5); output.Add(p6); output.Add(p7); output.Add(p8); output.Add(p9); int count = 0; List<LineF> lines = new List<LineF>(); foreach (LineF line in lines) { line.Intersection(line); Console.WriteLine("X:"+line.X1+" Y:"+line.Y1); Console.WriteLine(count); Console.ReadKey(); } //foreach (Point point in output) //{ // double res = point.X; // double rez = point.Y; // count++; // Console.WriteLine(" X:" + res + " Y:" + rez); //} Console.WriteLine(count); Console.ReadKey(); }
public static void AddLinesWidth(Mesh mesh, LineF[] lines, float width) { for (int i = 0; i < lines.Length; i++) { Vector2 vStart, vEnd; vStart = lines[i][0]; vEnd = lines[i][1]; AddLineWidth(mesh, vStart, vEnd, width); } }
/// <returns> /// false - no intersection, or infinite intersecion /// true - single intersection point /// </returns> public static bool LineIntersectsSgment(LineF line, SegmentF seg, ref PointF intersec) { var segLine = LineF.makeLine(seg.start, seg.end); if (LineIntersectsLine(line, segLine, ref intersec)) { float p = seg.GetProjectionOnLine(intersec); return(p >= 0 && p <= 1); } return(false); }
/// <summary> /// Attach a portal to the nearest valid wall edge along a ray. /// </summary> /// <param name="portal">Portal that will potentially be attached to a wall edge.</param> /// <param name="ray">Portal ray cast. ray[0] is the begin point and ray[1] is the end point.</param> /// <returns>True if a valid edge was found, otherwise false.</returns> public static bool PortalPlace(FixturePortal portal, LineF ray) { WallCoord intersection = RayCast(portal.Scene, ray); if (intersection != null) { intersection = AdjustCoord(intersection, portal.Size); if (intersection != null) { portal.SetPosition(intersection.Wall, new PolygonCoord(intersection.EdgeIndex, intersection.EdgeT)); return true; } } return false; }
public PortalView(PortalView parent, Matrix4 viewMatrix, List<List<IntPoint>> path, LineF[] fovLines, LineF[] fovLinesPrevious, LineF portalLine) { PortalLine = portalLine; FovLines = fovLines; FovLinesPrevious = fovLinesPrevious; Children = new List<PortalView>(); Parent = parent; if (Parent != null) { Parent.Children.Add(this); } ViewMatrix = viewMatrix; Paths = path; }
/// <param name="depth">Number of iterations.</param> /// <param name="clipModels">Adds the ClipModel instances to this list.</param> private static List<ClipModel> _getClipModels(IRenderable entity, Model model, IList<IPortal> portalList, Vector2 centerPoint, IPortal portalEnter, Matrix4 modelMatrix, int depth, int count) { List<ClipModel> clipModels = new List<ClipModel>(); if (depth <= 0) { return clipModels; } List<IPortal> collisions = Portal.GetCollisions( centerPoint, Vector2Ext.Transform(model.GetWorldConvexHull(), entity.GetWorldTransform().GetMatrix() * modelMatrix), portalList, PORTAL_CLIP_MARGIN); List<LineF> clipLines = new List<LineF>(); foreach (IPortal portal in collisions) { Vector2[] pv = Portal.GetWorldVerts(portal); LineF clipLine = new LineF(pv); LineF portalLine = new LineF(pv); Vector2 normal = portal.WorldTransform.GetRight(); if (portal.WorldTransform.MirrorX) { normal = -normal; } Vector2 portalNormal = portal.WorldTransform.Position + normal; if (portalLine.GetSideOf(centerPoint) != portalLine.GetSideOf(portalNormal)) { normal *= Portal.EnterMinDistance; } else { clipLine = clipLine.Reverse(); normal *= -Portal.EnterMinDistance; } clipLines.Add(clipLine); if (portalEnter == null || portal != portalEnter.Linked) { Vector2 centerPointNext = Vector2Ext.Transform(portal.WorldTransform.Position + normal, Portal.GetLinkedMatrix(portal)); clipModels.AddRange(_getClipModels(entity, model, portalList, centerPointNext, portal, modelMatrix * Portal.GetLinkedMatrix(portal), depth - 1, count + 1)); } } clipModels.Add(new ClipModel(entity, model, clipLines.ToArray(), modelMatrix)); return clipModels; }
public static Vector2[] CreateLineWidth(LineF line, float widthStart, float widthEnd) { Debug.Assert(widthStart > 0 && widthEnd > 0, "Line must have positive width."); Vector2 offsetStart = (line[0] - line[1]).PerpendicularLeft.Normalized() * widthStart / 2; Vector2 offsetEnd = (line[0] - line[1]).PerpendicularLeft.Normalized() * widthEnd / 2; Vector2[] lineWidth = new Vector2[] { line[0] - offsetStart, line[0] + offsetStart, line[1] + offsetEnd, line[1] - offsetEnd }; Debug.Assert(PolygonExt.IsInterior(lineWidth)); return lineWidth; }
public float a, b; // a may be float.PositiveInfinity //public PointF p1, p2; public static LineF makeLine(PointF p1, PointF p2) { var l = new LineF(); //l.p1 = p1; //l.p2 = p2; if (p1.X == p2.X) { l.a = float.PositiveInfinity; l.b = p1.X; return(l); } l.a = (p2.Y - p1.Y) / (p2.X - p1.X); l.b = p1.Y - l.a * p1.X; return(l); }
public UnintersectingLine(Point point1, Point point2, List <UnintersectingLine> lines) { LineSegments = new List <LineF>(); From = point1; To = point2; OriginalLine = new LineF(From, To); points.Add(point1); //points.Add(new Point(point1.X + 30, point2.Y - 30)); // Test. Fungerar bra att rita ut linjer som en path. LineF thisline = new LineF(From, To); Console.Out.WriteLine("Ny linje " + From + " till " + To); counter = 0; LineSegments = FindPath(From, To, lines); if (LineSegments == null) { HasErrors = true; return; } /* * foreach(UnintersectingLine otherUnintersectingLine in lines) * { * foreach (LineF otherLine in otherUnintersectingLine.LineSegments) * { * Point? intersection = thisline.Intersection(otherLine); * if(intersection != null) * { * // Vi har en korsning. Lägg till ny punkt istället. * points.Add(otherLine.To); * } * } * } */ points.Add(point2); // Registrera alla segment för framtida kollisionsdetekteringar. Point lastPoint = From; for (int i = 1; i < points.Count; i++) { LineSegments.Add(new LineF(lastPoint, points[i])); lastPoint = points[i]; } }
private PointF?Intersection(LineF other) { var a1 = Y2 - Y1; var b1 = X1 - X2; var c1 = X2 * Y1 - X1 * Y2; var r3 = a1 * other.X1 + b1 * other.Y1 + c1; var r4 = a1 * other.X2 + b1 * other.Y2 + c1; if (r3 != 0 && r4 != 0 && Math.Sign(r3) == Math.Sign(r4)) { return(null); } var a2 = other.Y2 - other.Y1; var b2 = other.X1 - other.X2; var c2 = other.X2 * other.Y1 - other.X1 * other.Y2; var r1 = a2 * X1 + b2 * Y1 + c2; var r2 = a2 * X2 + b2 * Y2 + c2; if (r1 != 0 && r2 != 0 && Math.Sign(r1) == Math.Sign(r2)) { return(null); } var denom = a1 * b2 - a2 * b1; if (denom == 0) { return(null); } var offset = denom < 0 ? -denom / 2 : denom / 2; var num = b1 * c2 - b2 * c1; var x = (num < 0 ? num - offset : num + offset) / denom; num = a2 * c1 - a1 * c2; var y = (num < 0 ? num - offset : num + offset) / denom; return(new PointF(x, y)); }
public void CalculateEdgeLines() { List <PointF> leftEndPoints = rowLines.Select(ln => ln.p1).ToList(); List <PointF> rightEndPoints = rowLines.Select(ln => ln.p2).ToList(); // recalculate X values for left and right table edges (minimizing RMSD from end points) leftEdgeX = leftEndPoints.Select(pt => pt.X).Average(); rightEdgeX = rightEndPoints.Select(pt => pt.X).Average(); PointF leftEdgeTop = new PointF(leftEdgeX, leftEndPoints.First().Y); PointF leftEdgeBottom = new PointF(leftEdgeX, leftEndPoints.Last().Y); leftEdge = new LineF(leftEdgeTop, leftEdgeBottom); PointF rightEdgeTop = new PointF(rightEdgeX, rightEndPoints.First().Y); PointF rightEdgeBottom = new PointF(rightEdgeX, rightEndPoints.Last().Y); rightEdge = new LineF(rightEdgeTop, rightEdgeBottom); }
public static bool LineIntersectsRectTest(LineF line, RectangleF r) { if (line.a == float.PositiveInfinity) { return(r.Left <= line.b && r.Right >= line.b); } var vert = r.getVertices(); bool areBelow = vert[0].Y < line.getY(vert[0].X); for (int i = 1; i < 4; ++i) { if (areBelow != (vert[i].Y < line.getY(vert[i].X))) // some points in rect are below the line, some are above { return(true); } } return(false); }
private void AddLines() { foreach (Line obj in dxf.Lines) { LineF lineF = new LineF(ConvertToGdiX(obj.StartPoint.X), ConvertToGdiY(obj.StartPoint.Y), ConvertToGdiX(obj.EndPoint.X), ConvertToGdiY(obj.EndPoint.Y), IsDotted(obj)); this.lines.Add(lineF); if (dxfMinX > lineF.StartPoint.X) { dxfMinX = lineF.StartPoint.X; } if (dxfMinX > lineF.EndPoint.X) { dxfMinX = lineF.EndPoint.X; } if (dxfMinY > lineF.StartPoint.Y) { dxfMinY = lineF.StartPoint.Y; } if (dxfMinY > lineF.EndPoint.Y) { dxfMinY = lineF.EndPoint.Y; } if (dxfMaxX < lineF.StartPoint.X) { dxfMaxX = lineF.StartPoint.X; } if (dxfMaxX < lineF.EndPoint.X) { dxfMaxX = lineF.EndPoint.X; } if (dxfMaxY < lineF.StartPoint.Y) { dxfMaxY = lineF.StartPoint.Y; } if (dxfMaxY < lineF.EndPoint.Y) { dxfMaxY = lineF.EndPoint.Y; } } }
protected static CoordinateF GetIntersectionPoint(LMFace face, LineF line, bool ignoreDirection = false) { var plane = face.Plane; var intersect = plane.GetIntersectionPoint(line, ignoreDirection); List <CoordinateF> coordinates = face.Vertices.Select(x => x.Location).ToList(); if (intersect == null) { return(null); } BoxF bbox = new BoxF(face.BoundingBox.Start - new CoordinateF(0.5f, 0.5f, 0.5f), face.BoundingBox.End + new CoordinateF(0.5f, 0.5f, 0.5f)); if (!bbox.CoordinateIsInside(intersect)) { return(null); } CoordinateF centerPoint = face.BoundingBox.Center; for (var i = 0; i < coordinates.Count; i++) { var i1 = i; var i2 = (i + 1) % coordinates.Count; var lineMiddle = (coordinates[i1] + coordinates[i2]) * 0.5f; var middleToCenter = centerPoint - lineMiddle; var v = coordinates[i1] - coordinates[i2]; var lineNormal = face.Plane.Normal.Cross(v); if ((middleToCenter - lineNormal).LengthSquared() > (middleToCenter + lineNormal).LengthSquared()) { lineNormal = -lineNormal; } if (lineNormal.Dot(intersect - lineMiddle) < 0.0f) { return(null); } } return(intersect); }
/// <remarks>http://community.topcoder.com/tc?module=Static&d1=tutorials&d2=geometry2</remarks> private PointF?Intersection(LineF other) { const int precision = 8; var a1 = (double)Y2 - Y1; var b1 = (double)X1 - X2; var c1 = a1 * X1 + b1 * Y1; var a2 = (double)other.Y2 - other.Y1; var b2 = (double)other.X1 - other.X2; var c2 = a2 * other.X1 + b2 * other.Y1; var det = a1 * b2 - a2 * b1; if (det == 0) { return(null); } else { var xi = (b2 * c1 - b1 * c2) / det; var yi = (a1 * c2 - a2 * c1) / det; if (Math.Round(Math.Min(X1, X2), precision) <= Math.Round(xi, precision) && Math.Round(xi, precision) <= Math.Round(Math.Max(X1, X2), precision) && Math.Round(Math.Min(Y1, Y2), precision) <= Math.Round(yi, precision) && Math.Round(yi, precision) <= Math.Round(Math.Max(Y1, Y2), precision) && Math.Round(Math.Min(other.X1, other.X2), precision) <= Math.Round(xi, precision) && Math.Round(xi, precision) <= Math.Round(Math.Max(other.X1, other.X2), precision) && Math.Round(Math.Min(other.Y1, other.Y2), precision) <= Math.Round(yi, precision) && Math.Round(yi, precision) <= Math.Round(Math.Max(other.Y1, other.Y2), precision)) { return(new PointF((float)xi, (float)yi)); } else { return(null); } } }
/// <summary> /// /// </summary> /// <param name="line"></param> /// <param name="r"></param> /// <param name="intersects"> /// if return value is true, intersects will have two intersection points (even for infinite case) /// </param> /// <returns> /// false - no intersection /// true - single/ infinite intersection /// </returns> public static bool LineIntersectsRect(LineF line, RectangleF r, out PointF[] intersects) { intersects = new PointF[2]; int intersecIdx = 0; var verts = r.getVertices(); // check intersection with each of the rect's segments for (int i = 0; i < 4 && intersecIdx < 2; ++i) { if (LineIntersectsSgment(line, new SegmentF() { start = verts[i], end = verts[(i + 1) % 4] }, ref intersects[intersecIdx])) { ++intersecIdx; // if 2 intersections were found, the loop breaks } } return(intersecIdx == 2); }
public static Vector2 GetLocalOrigin(Body body) { BodyData data = GetData(body); Vector2 center; //If this isn't the root body then the center point will be just outside of the parent portal. if (data.IsChild) { LineF portalLine = new LineF(Portal.GetWorldVerts(data.BodyParent.Portal.Linked)); Vector2 offset = portalLine.Delta.PerpendicularLeft.Normalized() * 0.01f; center = portalLine.Center + offset; if (portalLine.GetSideOf(center + offset) == portalLine.GetSideOf(body.Position)) { center = portalLine.Center - offset; } } else { center = (Vector2)body.Position; } return center; }
/// <returns> /// false - no intersection, or infinite intersecion /// true - single intersection point /// </returns> public static bool LineIntersectsLine(LineF l1, LineF l2, ref PointF intersec) { if (l1.a == l2.a) { return(false); } if (float.IsInfinity(l1.a)) { intersec = new PointF(l1.b, l2.getY(l1.b)); return(true); } if (float.IsInfinity(l2.a)) { intersec = new PointF(l2.b, l1.getY(l2.b)); return(true); } float x = (l2.b - l1.b) / (l1.a - l2.a); // the solution for the equation between two lines intersec = new PointF(x, l1.getY(x)); return(true); }
private GradientPoints ExpandGradient(ISvgBoundable boundable, PointF specifiedStart, PointF specifiedEnd) { if (!NeedToExpandGradient(boundable, specifiedStart, specifiedEnd)) { Debug.Fail("Unexpectedly expanding gradient when not needed!"); return(new GradientPoints(specifiedStart, specifiedEnd)); } var specifiedLength = CalculateDistance(specifiedStart, specifiedEnd); var specifiedUnitVector = new PointF((specifiedEnd.X - specifiedStart.X) / (float)specifiedLength, (specifiedEnd.Y - specifiedStart.Y) / (float)specifiedLength); var effectiveStart = specifiedStart; var effectiveEnd = specifiedEnd; var elementDiagonal = (float)CalculateDistance(new PointF(boundable.Bounds.Left, boundable.Bounds.Top), new PointF(boundable.Bounds.Right, boundable.Bounds.Bottom)); var expandedStart = MovePointAlongVector(effectiveStart, specifiedUnitVector, -elementDiagonal); var expandedEnd = MovePointAlongVector(effectiveEnd, specifiedUnitVector, elementDiagonal); var intersectionPoints = new LineF(expandedStart.X, expandedStart.Y, expandedEnd.X, expandedEnd.Y).Intersection(boundable.Bounds); if (boundable.Bounds.Contains(specifiedStart)) { effectiveStart = CalculateClosestIntersectionPoint(expandedStart, intersectionPoints); effectiveStart = MovePointAlongVector(effectiveStart, specifiedUnitVector, -1); } if (boundable.Bounds.Contains(specifiedEnd)) { effectiveEnd = CalculateClosestIntersectionPoint(effectiveEnd, intersectionPoints); effectiveEnd = MovePointAlongVector(effectiveEnd, specifiedUnitVector, 1); } return(new GradientPoints(effectiveStart, effectiveEnd)); }
/// <summary> /// Determine a position that is sufficiently far away from all portals so that it isn't ambiguous which side of a /// portal the position is at. /// </summary> /// <param name="portals"></param> /// <param name="portalPrevious">The last portal that was exited.</param> /// <param name="transform"></param> /// <param name="velocity"></param> private static Transform2 AddMargin(IEnumerable<IPortal> portals, IPortal portalPrevious, Transform2 transform, Transform2 velocity) { transform = transform.ShallowClone(); foreach (IPortal p in portals) { if (!Portal.IsValid(p)) { continue; } LineF exitLine = new LineF(Portal.GetWorldVerts(p)); Vector2 position = transform.Position; double distanceToPortal = MathExt.PointLineDistance(position, exitLine, true); if (distanceToPortal < Portal.EnterMinDistance) { Vector2 exitNormal = p.WorldTransform.GetRight(); Side sideOf; if (p == portalPrevious) { sideOf = exitLine.GetSideOf(position + velocity.Position); } else { sideOf = exitLine.GetSideOf(position - velocity.Position); } if (sideOf != exitLine.GetSideOf(exitNormal + p.WorldTransform.Position)) { exitNormal = -exitNormal; } Vector2 pos = exitNormal * (Portal.EnterMinDistance - (float)distanceToPortal); transform.Position += pos; break; } } return transform; }
public static WallCoord RayCast(IScene scene, LineF ray) { WallCoord wallCoord = null; float minDist = -1; foreach (IWall wall in scene.GetAll().OfType<IWall>()) { Vector2[] vertices = wall.GetWorldVertices().ToArray(); for (int i = 0; i < vertices.Length; i++) { int iNext = (i + 1) % vertices.Length; IntersectCoord coord = MathExt.LineLineIntersect(ray, new LineF(vertices[i], vertices[iNext]), false); if (coord.Exists) { float dist = ((Vector2)coord.Position - ray[0]).Length; if ((minDist == -1 || minDist < dist)) { minDist = dist; wallCoord = new WallCoord(wall, i, (float)coord.TLast); } } } } return wallCoord; }
public void GetSideOfTest11() { LineF line = new LineF(new Vector2(-1, 1), new Vector2(0, 0)); Assert.IsFalse(line.GetSideOf(new Vector2(0, -100)) == Side.Left); }
public void NearestTTest2() { LineF line = new LineF(new Vector2(3.3f,-4.9f), new Vector2(-5.3f, -6.1f)); Assert.IsTrue(line.NearestT(new Vector2(-4, 2), false) == 0.722811639f); }
public void NearestTTest1() { LineF line = new LineF(new Vector2(), new Vector2(0, 1)); Assert.IsTrue(line.NearestT(new Vector2(-4, 2), false) == 2); }
public void GetSideOfTest1() { LineF line = new LineF(new Vector2(0, 0), new Vector2(1, 0)); Assert.IsTrue(line.GetSideOf(new Vector2(0, 100)) == Side.Left); }
public void NearestTTest0() { LineF line = new LineF(new Vector2(), new Vector2(1, 0)); Assert.IsTrue(line.NearestT(new Vector2(1, 5), false) == 1); }
public void IsInsideFOVTest9() { float x = -2; float y = 2; for (double i = 0; i < Math.PI * 2; i += Math.PI / 20) { Vector2 viewPoint = new Vector2(x - 1, y); LineF lookLine = new LineF(new Vector2(x + 1, y), (float)i, 1f); LineF line = new LineF(new Vector2(x, y + 0.5f), new Vector2(x, y - 0.5f)); Assert.IsTrue(line.IsInsideFOV(viewPoint, lookLine)); } }
/// <summary> /// Returns the point that this line intersects with this face. /// </summary> /// <param name="line">The intersection line</param> /// <returns>The point of intersection between the face and the line. /// Returns null if the line does not intersect this face.</returns> public virtual CoordinateF GetIntersectionPoint(LineF line) { return(GetIntersectionPoint(this, line)); }
public List <LineF> FindPath(Point from, Point to, List <UnintersectingLine> existingLines) { counter++; if (counter > 20) { Console.Out.WriteLine("Out of moves!"); return(null); } LineF thisline = new LineF(from, to); List <LineF> res = new List <LineF>(); foreach (UnintersectingLine otherUnintersectingLine in existingLines) { foreach (LineF otherLine in otherUnintersectingLine.LineSegments) { Point?intersection = thisline.Intersection(otherLine); if (intersection != null) { float dFrom = (float)Math.Sqrt(Math.Pow(intersection.Value.X - otherLine.From.X, 2) + Math.Pow(intersection.Value.Y - otherLine.From.Y, 2)); float dTo = (float)Math.Sqrt(Math.Pow(intersection.Value.X - otherLine.To.X, 2) + Math.Pow(intersection.Value.Y - otherLine.To.Y, 2)); /* * // Specialare! Om vi är close enough, anse at det var ok. * if( dFrom < 1 || dTo < 1) * { * //Console.Out.WriteLine("Punkten (" + intersection.Value.X + ", " + intersection.Value.Y + ") anses ok."); * //res.Add(new LineF(from, to)); * // return res; * continue; * } */ Point candidate1 = (dFrom < dTo ? otherUnintersectingLine.FirstSegment.ExtendFrom(10) : otherUnintersectingLine.LastSegment.ExtendTo(10)); Point candidate2 = (dFrom >= dTo ? otherUnintersectingLine.FirstSegment.ExtendFrom(10) : otherUnintersectingLine.LastSegment.ExtendTo(10)); // Vi har en korsning. Lägg till ny punkt istället. Kortast väg vinner. // Här verkar det bli avgörande att ibland testa ett andra alternativ. Point p = candidate1; /* * if(TraversedPoints.Contains(candidate1)) * { * p = candidate2; * } */ Console.Out.WriteLine(" Från " + from.ToString() + " till " + p.ToString()); Console.Out.WriteLine(" Sen från " + p.ToString() + " till " + to.ToString()); res = FindPath(from, p, existingLines); if (res != null) { List <LineF> part2 = FindPath(p, to, existingLines); if (part2 != null) { res.AddRange(part2); } else { // Om vi körde fast i förra spåret, testa att gå åt andra hållet. Starta om med 20 nya fräscha försök. counter = 0; Point p2 = (dFrom >= dTo ? otherUnintersectingLine.FirstSegment.ExtendFrom(10) : otherUnintersectingLine.LastSegment.ExtendTo(10)); List <LineF> part2_2 = FindPath(p, to, existingLines); if (part2_2 != null) { res.AddRange(part2_2); } } } return(res); } else { // Keep looking. continue; } } } // Console.Out.WriteLine("Från " + from.ToString() + " till " + to.ToString()); res.Add(new LineF(from, to)); return(res); }
public void EqualsEpsilon() { Assert.IsTrue(LineD.Equals(lineD, new LineD(1.1, 2.9, 3.9, 5.1), 0.2)); Assert.IsTrue(LineF.Equals(lineF, new LineF(1.1f, 2.9f, 3.9f, 5.1f), 0.2f)); }
private static Vector2 GetAngularVelocity(IPortal portal, float intersectT) { Vector2 intersect = new LineF(GetWorldVerts(portal)).Lerp(intersectT); return MathExt.AngularVelocity(intersect, portal.WorldTransform.Position, portal.WorldVelocity.Rotation); }
public static LineF[] GetFovLines(IPortal portal, Vector2 origin, float distance, Transform2 transform) { Vector2[] vertices = GetFov(portal, origin, distance); LineF[] lines = new LineF[] { new LineF(vertices[1], vertices[2]), new LineF(vertices[0], vertices[vertices.Length-1]) }; return lines; }
public void GetSideOfTest14() { float rot = 0; for (int i = 0; i < 10; i++) { Vector2 v0 = new Vector2((float)Math.Cos(rot), (float)Math.Sin(rot)); Vector2 v1 = new Vector2((float)Math.Cos(rot + Math.PI), (float)Math.Sin(rot + Math.PI)); Vector2 v2 = new Vector2((float)Math.Cos(rot + Math.PI/2), (float)Math.Sin(rot + Math.PI/2)); LineF line = new LineF(v0, v1); Assert.IsTrue(line.GetSideOf(v2) == Side.Right); } }
public void GetSideOfTest12() { LineF line = new LineF(new Vector2(-5, 20), new Vector2(20, 0)); Assert.IsFalse(line.GetSideOf(new Vector2(0, 0)) == Side.Left); }
public void IsInsideFOVTest7() { float x = 0; float y = 0; for (double i = 0; i < Math.PI * 2; i += Math.PI / 20) { Scene scene = new Scene(); FloatPortal p0 = new FloatPortal(scene); Entity node = new Entity(scene); Transform2.SetPosition(node, new Vector2(x, y)); Transform2.SetRotation(node, (float)(i + Math.PI / 4)); p0.SetParent(node); PortalCommon.UpdateWorldTransform(scene); Vector2 viewPoint = new Vector2(x + (float)Math.Cos(i), y + (float)Math.Sin(i)); Vector2 lookPoint = new Vector2(x + (float)Math.Cos(i) * 2, y + (float)Math.Sin(i) * 2); LineF line = new LineF(Vector2Ext.Transform(Portal.GetVerts(p0), p0.GetWorldTransform().GetMatrix())); Assert.IsFalse(line.IsInsideFOV(viewPoint, lookPoint)); } }
public void GetSideOfTest13() { LineF line = new LineF(new Vector2(5, 20), new Vector2(10, 25)); LineF lineCheck = new LineF(new Vector2(-25, 10), new Vector2(25, 10)); Assert.IsTrue(line.GetSideOf(lineCheck) == Side.Neither); }
public static void SaveToFile(string filename, Document document, ExportForm form) { var map = document.Map; string filepath = System.IO.Path.GetDirectoryName(filename); filename = System.IO.Path.GetFileName(filename); filename = System.IO.Path.GetFileNameWithoutExtension(filename) + ".rm2"; string lmPath = System.IO.Path.GetFileNameWithoutExtension(filename) + "_lm"; List <Lightmap.LMFace> faces; int lmCount; List <Lightmap.Light> lights; Lightmap.Lightmapper.Render(document, form, out faces, out lmCount); Lightmap.Light.FindLights(map, out lights); IEnumerable <Face> transparentFaces = map.WorldSpawn.Find(x => x is Solid).OfType <Solid>().SelectMany(x => x.Faces).Where(x => { if (x.Texture?.Texture == null) { return(false); } if (!x.Texture.Texture.HasTransparency()) { return(false); } if (x.Texture.Name.Contains("tooltextures")) { return(false); } return(true); }); IEnumerable <Face> invisibleCollisionFaces = map.WorldSpawn.Find(x => x is Solid).OfType <Solid>().SelectMany(x => x.Faces).Where(x => x.Texture.Name.ToLowerInvariant() == "tooltextures/invisible_collision"); Lightmap.Lightmapper.SaveLightmaps(document, lmCount, filepath + "/" + lmPath, true); lmPath = System.IO.Path.GetFileName(lmPath); List <Waypoint> waypoints = map.WorldSpawn.Find(x => x.ClassName != null && x.ClassName.ToLower() == "waypoint").OfType <Entity>().Select(x => new Waypoint(x)).ToList(); IEnumerable <Entity> props = map.WorldSpawn.Find(x => x.ClassName != null && x.ClassName.ToLower() == "model").OfType <Entity>(); form.ProgressLog.Invoke((MethodInvoker)(() => form.ProgressLog.AppendText("\nDetermining waypoint visibility..."))); form.ProgressBar.Invoke((MethodInvoker)(() => form.ProgressBar.Value = 9100)); for (int i = 0; i < waypoints.Count; i++) { for (int j = 0; j < waypoints.Count; j++) { if (j > i) { waypoints[i].Connections.Add(j); } else if (j < i) { if (waypoints[j].Connections.Contains(i)) { waypoints[i].Connections.Add(j); } } } foreach (Lightmap.LMFace face in faces) { for (int j = 0; j < waypoints[i].Connections.Count; j++) { int connection = waypoints[i].Connections[j]; if (connection < i) { continue; } LineF line1 = new LineF(waypoints[i].Location, waypoints[connection].Location); LineF line2 = new LineF(waypoints[connection].Location, waypoints[i].Location); if (face.GetIntersectionPoint(line1) != null || face.GetIntersectionPoint(line2) != null) { waypoints[i].Connections.RemoveAt(j); j--; } } } } FileStream stream = new FileStream(filepath + "/" + filename, FileMode.Create); BinaryWriter br = new BinaryWriter(stream); //header br.Write((byte)'.'); br.Write((byte)'R'); br.Write((byte)'M'); br.Write((byte)'2'); //textures List <Tuple <string, byte> > textures = new List <Tuple <string, byte> >(); byte flag = (byte)RM2TextureLoadFlag.Opaque; foreach (Lightmap.LMFace face in faces) { if (!textures.Any(x => x.Item1 == face.Texture)) { textures.Add(new Tuple <string, byte>(face.Texture, flag)); } } flag = (byte)RM2TextureLoadFlag.Alpha; foreach (Face face in transparentFaces) { if (!textures.Any(x => x.Item1 == face.Texture.Name)) { textures.Add(new Tuple <string, byte>(face.Texture.Name, flag)); } } br.Write((byte)RM2Chunks.Textures); br.Write((byte)lmCount); br.Write((byte)textures.Count); foreach (Tuple <string, byte> tex in textures) { br.WriteByteString(tex.Item1); br.Write(tex.Item2); } //mesh int vertCount; int vertOffset; int triCount; for (int i = 0; i < textures.Count; i++) { for (int lmInd = 0; lmInd < lmCount; lmInd++) { IEnumerable <Lightmap.LMFace> tLmFaces = faces.FindAll(x => x.Texture == textures[i].Item1 && x.LmIndex == lmInd); vertCount = 0; vertOffset = 0; triCount = 0; if (tLmFaces.Count() > 0) { foreach (Lightmap.LMFace face in tLmFaces) { vertCount += face.Vertices.Count; triCount += face.GetTriangleIndices().Count() / 3; } br.Write((byte)RM2Chunks.VisibleGeometry); br.Write((byte)i); if (lmCount > 1) { br.Write((byte)lmInd); } if (vertCount > UInt16.MaxValue) { throw new Exception("Vertex overflow!"); } br.Write((UInt16)vertCount); foreach (Lightmap.LMFace face in tLmFaces) { for (int j = 0; j < face.Vertices.Count; j++) { br.Write(face.Vertices[j].Location.X); br.Write(face.Vertices[j].Location.Z); br.Write(face.Vertices[j].Location.Y); //br.Write((byte)255); //r //br.Write((byte)255); //g //br.Write((byte)255); //b br.Write(face.Vertices[j].DiffU); br.Write(face.Vertices[j].DiffV); float lmMul = (lmCount > 1) ? 2.0f : 1.0f; float uSub = ((lmInd % 2) > 0) ? 0.5f : 0.0f; float vSub = ((lmInd / 2) > 0) ? 0.5f : 0.0f; br.Write((face.Vertices[j].LMU - uSub) * lmMul); br.Write((face.Vertices[j].LMV - vSub) * lmMul); } } br.Write((UInt16)triCount); foreach (Lightmap.LMFace face in tLmFaces) { foreach (uint ind in face.GetTriangleIndices()) { br.Write((UInt16)(ind + vertOffset)); } vertOffset += face.Vertices.Count; } } } IEnumerable <Face> tTrptFaces = transparentFaces.Where(x => x.Texture.Name == textures[i].Item1); vertCount = 0; vertOffset = 0; triCount = 0; if (tTrptFaces.Count() > 0) { foreach (Face face in tTrptFaces) { vertCount += face.Vertices.Count; triCount += face.GetTriangleIndices().Count() / 3; } br.Write((byte)RM2Chunks.VisibleGeometry); br.Write((byte)i); if (vertCount > UInt16.MaxValue) { throw new Exception("Vertex overflow!"); } br.Write((UInt16)vertCount); foreach (Face face in tTrptFaces) { for (int j = 0; j < face.Vertices.Count; j++) { br.Write((float)face.Vertices[j].Location.X); br.Write((float)face.Vertices[j].Location.Z); br.Write((float)face.Vertices[j].Location.Y); //vertex color is not used since we don't do vertex lighting anymore //br.Write((byte)255); //r //br.Write((byte)255); //g //br.Write((byte)255); //b br.Write((float)face.Vertices[j].TextureU); br.Write((float)face.Vertices[j].TextureV); br.Write(0.0f); br.Write(0.0f); } } br.Write((UInt16)triCount); foreach (Face face in tTrptFaces) { foreach (uint ind in face.GetTriangleIndices()) { br.Write((UInt16)(ind + vertOffset)); } vertOffset += face.Vertices.Count; } } } vertCount = 0; vertOffset = 0; triCount = 0; if (invisibleCollisionFaces.Count() > 0) { foreach (Face face in invisibleCollisionFaces) { vertCount += face.Vertices.Count; triCount += face.GetTriangleIndices().Count() / 3; } br.Write((byte)RM2Chunks.InvisibleGeometry); if (vertCount > UInt16.MaxValue) { throw new Exception("Vertex overflow!"); } br.Write((UInt16)vertCount); foreach (Face face in invisibleCollisionFaces) { for (int j = 0; j < face.Vertices.Count; j++) { br.Write((float)face.Vertices[j].Location.X); br.Write((float)face.Vertices[j].Location.Z); br.Write((float)face.Vertices[j].Location.Y); } } br.Write((UInt16)triCount); foreach (Face face in invisibleCollisionFaces) { foreach (uint ind in face.GetTriangleIndices()) { br.Write((UInt16)(ind + vertOffset)); } vertOffset += face.Vertices.Count; } } foreach (Lightmap.Light light in lights) { br.Write((byte)RM2Chunks.PointLight); br.Write(light.Origin.X); br.Write(light.Origin.Z); br.Write(light.Origin.Y); br.Write(light.Range); br.Write((byte)light.Color.X); br.Write((byte)light.Color.Y); br.Write((byte)light.Color.Z); br.Write(light.Intensity); } foreach (Waypoint wp in waypoints) { br.Write((byte)RM2Chunks.Waypoint); br.Write(wp.Location.X); br.Write(wp.Location.Z); br.Write(wp.Location.Y); for (int i = 0; i < wp.Connections.Count; i++) { br.Write((byte)(wp.Connections[i] + 1)); } br.Write((byte)0); } foreach (Entity prop in props) { br.Write((byte)RM2Chunks.Prop); br.WriteByteString(System.IO.Path.GetFileNameWithoutExtension(prop.EntityData.GetPropertyValue("file"))); br.Write((float)prop.Origin.X); br.Write((float)prop.Origin.Z); br.Write((float)prop.Origin.Y); Coordinate rotation = prop.EntityData.GetPropertyCoordinate("angles"); br.Write((float)rotation.X); br.Write((float)rotation.Y); br.Write((float)rotation.Z); Coordinate scale = prop.EntityData.GetPropertyCoordinate("scale"); br.Write((float)scale.X); br.Write((float)scale.Y); br.Write((float)scale.Z); } br.Dispose(); stream.Dispose(); form.ProgressLog.Invoke((MethodInvoker)(() => form.ProgressLog.AppendText("\nDone!"))); form.ProgressBar.Invoke((MethodInvoker)(() => form.ProgressBar.Value = 10000)); }
/// <summary> /// Get all valid portals that collide with a polygon. Portals can occlude eachother. /// </summary> /// <param name="margin">Minimum distance inside of polygon for a portal collision to count. /// Useful for avoiding round off errors.</param> public static List<IPortal> GetCollisions(Vector2 center, IList<Vector2> polygon, IList<IPortal> portals, double margin = 0) { List<IPortal> collisions = new List<IPortal>(); foreach (IPortal p in portals.Where(item => IsValid(item))) { LineF portalLine = new LineF(GetWorldVerts(p)); if (MathExt.LineInPolygon(portalLine, polygon) && (margin == 0 || MathExt.PointPolygonDistance(portalLine[0], polygon) > margin || MathExt.PointPolygonDistance(portalLine[1], polygon) > margin)) { collisions.Add(p); } } var ordered = collisions.OrderBy(item => (item.WorldTransform.Position - center).Length).ToList(); for (int i = 0; i < ordered.Count; i++) { IPortal portal = ordered[i]; for (int j = ordered.Count - 1; j > i; j--) { LineF currentLine = new LineF(GetWorldVerts(ordered[i])); LineF checkLine = new LineF(GetWorldVerts(ordered[j])); Side checkSide = currentLine.GetSideOf(checkLine); if (checkSide != currentLine.GetSideOf(center)) { ordered.RemoveAt(j); } } } return ordered.ToList(); }
public void IntersectTest6() { LineF line0 = new LineF(new Vector2(1f, 1f), new Vector2(2f, 2f)); LineF line1 = new LineF(new Vector2(1.5f, 3f), new Vector2(1.5f, -1.5f)); IntersectCoord intersect = MathExt.LineLineIntersect(line0, line1, false); IntersectCoord comparison = new IntersectCoord(); comparison.Exists = true; comparison.Position = new Vector2d(1.5, 1.5); comparison.TFirst = 0.5; comparison.TLast = 1/(double)3; Assert.IsTrue(intersect.Equals(comparison)); }
/// <summary> /// Returns all the portal intersections for a line in this path. /// TFirst is the t value for the line intersection. /// TLast is the t value for the portal intersection. /// </summary> /// <param name="line"></param> /// <returns></returns> public static IntersectCoord[] PathIntersections(PortalPath path, LineF line) { IntersectCoord[] intersections = new IntersectCoord[path.Portals.Count]; line = line.ShallowClone(); LineF[] portalLines = new LineF[path.Portals.Count]; for (int i = 0; i < path.Portals.Count; i++) { portalLines[i] = new LineF(GetWorldVerts(path.Portals[i])); } for (int i = path.Portals.Count - 1; i >= 0; i--) { Matrix4 mat = GetLinkedMatrix(path.Portals[i].Linked); line[1] = line.Transform(mat)[1]; for (int j = i + 1; j < path.Portals.Count; j++) { portalLines[j] = portalLines[j].Transform(mat); } } for (int i = 0; i < path.Portals.Count; i++) { intersections[i] = MathExt.LineLineIntersect(portalLines[i], line, true); } return intersections; }
public void IntersectTest7() { LineF line0 = new LineF(new Vector2(1f, 1f), new Vector2(2f, 2f)); LineF line1 = new LineF(new Vector2(3f, 9f), new Vector2(12f, -6f)); IntersectCoord intersect = MathExt.LineLineIntersect(line0, line1, true); IntersectCoord comparison = new IntersectCoord(); comparison.Exists = false; Assert.IsTrue(intersect.Equals(comparison)); }
public void FillPolygon(Color Col, ref PointF[] points) { int pCount = points.Count(); int val = Col.ToArgb(); // Add the first point to the end of the array, for easier line access Array.Resize(ref points, points.Length + 1); points[points.Count() - 1] = points[0]; // Convert array of points to an array of Lines LineF[] lines = new LineF[pCount]; int LID = 0; // Get min/max Ys too float FminY = points[0].Y; float FmaxY = points[0].Y; for (int i = 0; i < pCount; i++) { if (points[i].Y < FminY) { FminY = points[i].Y; } else if (points[i].Y > FmaxY) { FmaxY = points[i].Y; } if (points[i].Y == points[i + 1].Y) // Exclude lines that are perfectly horizontal { continue; } if (points[i].Y < points[i + 1].Y) { lines[LID] = new LineF(points[i], points[i + 1]); } else { lines[LID] = new LineF(points[i + 1], points[i]); } LID++; } Array.Resize(ref lines, LID); // Remove last element of points, which was added here Array.Resize(ref points, points.Length - 1); // Array for maximum possible length fill line int[] arr4 = new int[Width]; for (int i = 0; i < arr4.Length; i++) { arr4[i] = val; } // Stay within top/bottom bounds int minY = (int)FminY; int maxY = (int)FmaxY; if (minY < 0) { minY = 0; } if (maxY >= Height) { maxY = Height - 1; } // Lines to Check (for if a new line matches iY) List <int> ltc = new List <int>(); for (int i = 0; i < lines.Length; i++) { ltc.Add(i); } IntPtr YPtr = BLoc + (minY * Stride); List <LineF> intersect = new List <LineF>(); // Lines that went through last loop // Find lines to fill for each Y pixel of any line for (int iY = minY; iY < maxY; iY++) { List <int> Xpos = new List <int>(); // Find lines that still go through iY for (int i2 = 0; i2 < intersect.Count; i2++) { if (intersect[i2].end.Y > iY) { Xpos.Add((int)intersect[i2].XatY(iY)); } else { intersect.RemoveAt(i2); i2--; } } // Find new lines that go through iY for (int i2 = 0; i2 < ltc.Count; i2++) { LineF cL = lines[ltc[i2]]; if (iY >= cL.start.Y) { intersect.Add(cL); ltc.RemoveAt(i2); i2--; if (iY < cL.end.Y) { Xpos.Add((int)cL.XatY(iY)); } } } // Sort by Xpos at iY Xpos.Sort(); // Fill! int iF = 0; for (; iF < Xpos.Count && Xpos[iF] < 0; iF += 2) { Xpos[iF] = 0; if (Xpos[iF + 1] >= 0) { break; } } for (; iF < Xpos.Count; iF += 2) { if (Xpos[iF + 1] >= Width) { Xpos[iF + 1] = Width - 1; if (Xpos[iF] >= Width) { break; } } IntPtr dest = YPtr + (Xpos[iF] * 4); Marshal.Copy(arr4, 0, dest, Xpos[iF + 1] - Xpos[iF]); } YPtr += Stride; } }
/// <summary> /// Calculates intersection - if any - of two lines /// </summary> /// <param name="otherLine"></param> /// <returns>Intersection or null</returns> /// <remarks> </remarks> public Point Intersection(LineF otherLine) { var a1 = Y2 - Y1; var b1 = X1 - X2; var c1 = X2 * Y1 - X1 * Y2; /* Compute r3 and r4. */ var r3 = a1 * otherLine.X1 + b1 * otherLine.Y1 + c1; var r4 = a1 * otherLine.X2 + b1 * otherLine.Y2 + c1; /* Check signs of r3 and r4. If both point 3 and point 4 lie on * same side of line 1, the line segments do not intersect. */ if (r3 != 0 && r4 != 0 && Math.Sign(r3) == Math.Sign(r4)) { return(null); // DONT_INTERSECT } /* Compute a2, b2, c2 */ var a2 = otherLine.Y2 - otherLine.Y1; var b2 = otherLine.X1 - otherLine.X2; var c2 = otherLine.X2 * otherLine.Y1 - otherLine.X1 * otherLine.Y2; /* Compute r1 and r2 */ var r1 = a2 * X1 + b2 * Y1 + c2; var r2 = a2 * X2 + b2 * Y2 + c2; /* Check signs of r1 and r2. If both point 1 and point 2 lie * on same side of second line segment, the line segments do * not intersect. */ if (r1 != 0 && r2 != 0 && Math.Sign(r1) == Math.Sign(r2)) { return(null); // DONT_INTERSECT } /* Line segments intersect: compute intersection point. */ var denom = a1 * b2 - a2 * b1; if (denom == 0) { return(null); //( COLLINEAR ); } var offset = denom < 0 ? -denom / 2 : denom / 2; /* The denom/2 is to get rounding instead of truncating. It * is added or subtracted to the numerator, depending upon the * sign of the numerator. */ var num = b1 * c2 - b2 * c1; var x = (num < 0 ? num - offset : num + offset) / denom; num = a2 * c1 - a1 * c2; var y = (num < 0 ? num - offset : num + offset) / denom; return(new Point(x, y)); }
/// <summary> /// Returns true if a contact should not be disabled due to portal clipping. /// </summary> private bool IsContactValid(Contact contact) { FixtureData[] fixtureData = new FixtureData[2]; fixtureData[0] = FixtureExt.GetData(contact.FixtureA); fixtureData[1] = FixtureExt.GetData(contact.FixtureB); BodyData[] bodyData = new BodyData[2]; bodyData[0] = BodyExt.GetData(contact.FixtureA.Body); bodyData[1] = BodyExt.GetData(contact.FixtureB.Body); Xna.Vector2 normal; FixedArray2<Xna.Vector2> vList; contact.GetWorldManifold(out normal, out vList); if (bodyData[0].IsChild || bodyData[1].IsChild) { if (bodyData[0].IsChild && bodyData[1].IsChild) { //return true; } int childIndex = bodyData[0].IsChild ? 0 : 1; int otherIndex = bodyData[0].IsChild ? 1 : 0; BodyData bodyDataChild = bodyData[childIndex]; BodyData bodyDataOther = bodyData[otherIndex]; FixtureData fixtureDataChild = fixtureData[childIndex]; FixtureData fixtureDataOther = fixtureData[otherIndex]; } //Contact is invalid if it is between two fixtures where one fixture is colliding with a portal on the other fixture. if (fixtureData[0].IsPortalParentless() && fixtureData[1].IsPortalParentless()) { for (int i = 0; i < fixtureData.Length; i++) { int iNext = (i + 1) % fixtureData.Length; var intersection = fixtureData[iNext].GetPortalChildren().Intersect(fixtureData[i].PortalCollisions); if (intersection.Count() > 0) { //Debug.Fail("Fixtures with portal collisions should be filtered."); return false; } } } //Contact is invalid if it is too close to a portal. foreach (IPortal p in Scene.GetPortalList()) { if (!Portal.IsValid(p)) { continue; } FixturePortal portal = p as FixturePortal; if (portal != null) { //Don't consider this portal if its fixtures are part of the contact. if (fixtureData[0].PartOfPortal(portal) || fixtureData[1].PartOfPortal(portal)) { continue; } LineF line = new LineF(Portal.GetWorldVerts(portal)); double[] vDist = new double[] { MathExt.PointLineDistance(vList[0], line, true), MathExt.PointLineDistance(vList[1], line, true) }; //Only consider contacts that are between the fixture this portal is parented too and some other fixture. if (contact.FixtureA == FixtureExt.GetFixtureAttached(portal) || contact.FixtureB == FixtureExt.GetFixtureAttached(portal)) { if (contact.Manifold.PointCount == 1) { if (vDist[0] < FixturePortal.CollisionMargin) { return false; } } else if (vDist[0] < FixturePortal.CollisionMargin && vDist[1] < FixturePortal.CollisionMargin) { return false; } } } } //Contact is invalid if it is on the opposite side of a colliding portal. for (int i = 0; i < fixtureData.Length; i++) { int iNext = (i + 1) % fixtureData.Length; foreach (IPortal portal in fixtureData[i].PortalCollisions) { LineF line = new LineF(Portal.GetWorldVerts(portal)); FixturePortal cast = portal as FixturePortal; if (cast != null) { if (fixtureData[i].PartOfPortal(cast) || fixtureData[iNext].PartOfPortal(cast)) { continue; } } //Contact is invalid if it is on the opposite side of the portal from its body origin. //Xna.Vector2 pos = BodyExt.GetData(fixtureData[i].Fixture.Body).PreviousPosition; Vector2 pos = BodyExt.GetLocalOrigin(fixtureData[i].Fixture.Body); bool oppositeSides0 = line.GetSideOf(vList[0]) != line.GetSideOf(pos); Debug.Assert(contact.Manifold.PointCount > 0); if (contact.Manifold.PointCount == 1) { if (oppositeSides0) { return false; } } else //else if (line.GetSideOf((vList[0] + vList[1])/2) != line.GetSideOf(pos)) { bool oppositeSides1 = line.GetSideOf(vList[1]) != line.GetSideOf(pos); /*if (oppositeSides0 && oppositeSides1) { return false; } if (oppositeSides0) { contact.Manifold.Points[0] = contact.Manifold.Points[1]; } contact.Manifold.PointCount = 1; return true;*/ if (!oppositeSides0 && !oppositeSides1) { continue; } if (!fixtureData[iNext].PortalCollisions.Contains(portal) || !(oppositeSides0 || oppositeSides1)) { return false; } } } } return true; }
public void IntersectTest8() { LineF line0 = new LineF(new Vector2(1f, 1f), new Vector2(2f, 2f)); LineF line1 = new LineF(new Vector2(3f, 9f), new Vector2(12f, -6f)); IntersectCoord intersect = MathExt.LineLineIntersect(line0, line1, false); IntersectCoord comparison = new IntersectCoord(); comparison.Exists = true; comparison.Position = new Vector2d(5.25, 5.25); comparison.TFirst = 4.25; comparison.TLast = 0.25; Assert.IsTrue(intersect.Equals(comparison)); }
private static void RenderLightOntoFace(Document doc, float[][] bitmaps, List <Light> lights, LightmapGroup group, LMFace targetFace, IEnumerable <LMFace> blockerFaces) { Random rand = new Random(); int writeX = group.writeX; int writeY = group.writeY; int textureDims; lock (doc.TextureCollection.Lightmaps) { textureDims = doc.TextureCollection.Lightmaps[0].Width; } lights = lights.FindAll(x => { float range = x.Range; BoxF lightBox = new BoxF(x.Origin - new CoordinateF(range, range, range), x.Origin + new CoordinateF(range, range, range)); return(lightBox.IntersectsWith(targetFace.BoundingBox)); }); float?minX = null; float?maxX = null; float?minY = null; float?maxY = null; foreach (CoordinateF coord in targetFace.Vertices.Select(x => x.Location)) { float x = coord.Dot(group.uAxis); float y = coord.Dot(group.vAxis); if (minX == null || x < minX) { minX = x; } if (minY == null || y < minY) { minY = y; } if (maxX == null || x > maxX) { maxX = x; } if (maxY == null || y > maxY) { maxY = y; } } CoordinateF leewayPoint = group.Plane.PointOnPlane + (group.Plane.Normal * Math.Max(LightmapConfig.DownscaleFactor * 0.25f, 1.5f)); minX -= LightmapConfig.DownscaleFactor; minY -= LightmapConfig.DownscaleFactor; maxX += LightmapConfig.DownscaleFactor; maxY += LightmapConfig.DownscaleFactor; minX /= LightmapConfig.DownscaleFactor; minX = (float)Math.Ceiling(minX.Value); minX *= LightmapConfig.DownscaleFactor; minY /= LightmapConfig.DownscaleFactor; minY = (float)Math.Ceiling(minY.Value); minY *= LightmapConfig.DownscaleFactor; maxX /= LightmapConfig.DownscaleFactor; maxX = (float)Math.Ceiling(maxX.Value); maxX *= LightmapConfig.DownscaleFactor; maxY /= LightmapConfig.DownscaleFactor; maxY = (float)Math.Ceiling(maxY.Value); maxY *= LightmapConfig.DownscaleFactor; foreach (LMFace.Vertex vert in targetFace.Vertices) { float x = vert.Location.Dot(group.uAxis); float y = vert.Location.Dot(group.vAxis); float u = (writeX + 0.5f + (x - group.minTotalX.Value) / LightmapConfig.DownscaleFactor); float v = (writeY + 0.5f + (y - group.minTotalY.Value) / LightmapConfig.DownscaleFactor); targetFace.LmIndex = (u >= LightmapConfig.TextureDims ? 1 : 0) + (v >= LightmapConfig.TextureDims ? 2 : 0); u /= (float)textureDims; v /= (float)textureDims; vert.LMU = u; vert.LMV = v; vert.OriginalVertex.LMU = u; vert.OriginalVertex.LMV = v; } float centerX = (maxX.Value + minX.Value) / 2; float centerY = (maxY.Value + minY.Value) / 2; int iterX = (int)Math.Ceiling((maxX.Value - minX.Value) / LightmapConfig.DownscaleFactor); int iterY = (int)Math.Ceiling((maxY.Value - minY.Value) / LightmapConfig.DownscaleFactor); float[][,] r = new float[4][, ]; r[0] = new float[iterX, iterY]; r[1] = new float[iterX, iterY]; r[2] = new float[iterX, iterY]; r[3] = new float[iterX, iterY]; float[][,] g = new float[4][, ]; g[0] = new float[iterX, iterY]; g[1] = new float[iterX, iterY]; g[2] = new float[iterX, iterY]; g[3] = new float[iterX, iterY]; float[][,] b = new float[4][, ]; b[0] = new float[iterX, iterY]; b[1] = new float[iterX, iterY]; b[2] = new float[iterX, iterY]; b[3] = new float[iterX, iterY]; foreach (Light light in lights) { CoordinateF lightPos = light.Origin; float lightRange = light.Range; CoordinateF lightColor = light.Color * (1.0f / 255.0f) * light.Intensity; BoxF lightBox = new BoxF(new BoxF[] { targetFace.BoundingBox, new BoxF(light.Origin - new CoordinateF(30.0f, 30.0f, 30.0f), light.Origin + new CoordinateF(30.0f, 30.0f, 30.0f)) }); List <LMFace> applicableBlockerFaces = blockerFaces.Where(x => { if (x == targetFace) { return(false); } if (group.Faces.Contains(x)) { return(false); } //return true; if (lightBox.IntersectsWith(x.BoundingBox)) { return(true); } return(false); }).ToList(); bool[,] illuminated = new bool[iterX, iterY]; for (int y = 0; y < iterY; y++) { for (int x = 0; x < iterX; x++) { illuminated[x, y] = true; } } for (int y = 0; y < iterY; y++) { for (int x = 0; x < iterX; x++) { int tX = (int)(writeX + x + (int)(minX - group.minTotalX) / LightmapConfig.DownscaleFactor); int tY = (int)(writeY + y + (int)(minY - group.minTotalY) / LightmapConfig.DownscaleFactor); if (tX >= 0 && tY >= 0 && tX < textureDims && tY < textureDims) { int offset = (tX + tY * textureDims) * Bitmap.GetPixelFormatSize(System.Drawing.Imaging.PixelFormat.Format32bppArgb) / 8; bitmaps[0][offset + 3] = 1.0f; bitmaps[1][offset + 3] = 1.0f; bitmaps[2][offset + 3] = 1.0f; bitmaps[3][offset + 3] = 1.0f; } } } for (int y = 0; y < iterY; y++) { for (int x = 0; x < iterX; x++) { float ttX = minX.Value + (x * LightmapConfig.DownscaleFactor); float ttY = minY.Value + (y * LightmapConfig.DownscaleFactor); CoordinateF pointOnPlane = (ttX - centerX) * group.uAxis + (ttY - centerY) * group.vAxis + targetFace.BoundingBox.Center; /*Entity entity = new Entity(map.IDGenerator.GetNextObjectID()); * entity.Colour = Color.Pink; * entity.Origin = new Coordinate(pointOnPlane); * entity.UpdateBoundingBox(); * entity.SetParent(map.WorldSpawn);*/ int tX = (int)(writeX + x + (int)(minX - group.minTotalX) / LightmapConfig.DownscaleFactor); int tY = (int)(writeY + y + (int)(minY - group.minTotalY) / LightmapConfig.DownscaleFactor); CoordinateF luxelColor0 = new CoordinateF(r[0][x, y], g[0][x, y], b[0][x, y]); CoordinateF luxelColor1 = new CoordinateF(r[1][x, y], g[1][x, y], b[1][x, y]); CoordinateF luxelColor2 = new CoordinateF(r[2][x, y], g[2][x, y], b[2][x, y]); CoordinateF luxelColorNorm = new CoordinateF(r[3][x, y], g[3][x, y], b[3][x, y]); float dotToLight0 = Math.Max((lightPos - pointOnPlane).Normalise().Dot(targetFace.LightBasis0), 0.0f); float dotToLight1 = Math.Max((lightPos - pointOnPlane).Normalise().Dot(targetFace.LightBasis1), 0.0f); float dotToLight2 = Math.Max((lightPos - pointOnPlane).Normalise().Dot(targetFace.LightBasis2), 0.0f); float dotToLightNorm = Math.Max((lightPos - pointOnPlane).Normalise().Dot(targetFace.Normal), 0.0f); if (illuminated[x, y] && (pointOnPlane - lightPos).LengthSquared() < lightRange * lightRange) { #if TRUE LineF lineTester = new LineF(lightPos, pointOnPlane); for (int i = 0; i < applicableBlockerFaces.Count; i++) { LMFace otherFace = applicableBlockerFaces[i]; CoordinateF hit = otherFace.GetIntersectionPoint(lineTester); if (hit != null && ((hit - leewayPoint).Dot(group.Plane.Normal) > 0.0f || (hit - pointOnPlane).LengthSquared() > LightmapConfig.DownscaleFactor * 2f)) { applicableBlockerFaces.RemoveAt(i); applicableBlockerFaces.Insert(0, otherFace); illuminated[x, y] = false; i++; break; } } #endif } else { illuminated[x, y] = false; } if (illuminated[x, y]) { float brightness = (lightRange - (pointOnPlane - lightPos).VectorMagnitude()) / lightRange; if (light.Direction != null) { float directionDot = light.Direction.Dot((pointOnPlane - lightPos).Normalise()); if (directionDot < light.innerCos) { if (directionDot < light.outerCos) { brightness = 0.0f; } else { brightness *= (directionDot - light.outerCos.Value) / (light.innerCos.Value - light.outerCos.Value); } } } float brightness0 = dotToLight0 * brightness * brightness; float brightness1 = dotToLight1 * brightness * brightness; float brightness2 = dotToLight2 * brightness * brightness; float brightnessNorm = dotToLightNorm * brightness * brightness; brightness0 += ((float)rand.NextDouble() - 0.5f) * 0.005f; brightness1 += ((float)rand.NextDouble() - 0.5f) * 0.005f; brightness2 += ((float)rand.NextDouble() - 0.5f) * 0.005f; brightnessNorm += ((float)rand.NextDouble() - 0.5f) * 0.005f; r[0][x, y] += lightColor.Z * brightness0; if (r[0][x, y] > 1.0f) { r[0][x, y] = 1.0f; } if (r[0][x, y] < 0) { r[0][x, y] = 0; } g[0][x, y] += lightColor.Y * brightness0; if (g[0][x, y] > 1.0f) { g[0][x, y] = 1.0f; } if (g[0][x, y] < 0) { g[0][x, y] = 0; } b[0][x, y] += lightColor.X * brightness0; if (b[0][x, y] > 1.0f) { b[0][x, y] = 1.0f; } if (b[0][x, y] < 0) { b[0][x, y] = 0; } r[1][x, y] += lightColor.Z * brightness1; if (r[1][x, y] > 1.0f) { r[1][x, y] = 1.0f; } if (r[1][x, y] < 0) { r[1][x, y] = 0; } g[1][x, y] += lightColor.Y * brightness1; if (g[1][x, y] > 1.0f) { g[1][x, y] = 1.0f; } if (g[1][x, y] < 0) { g[1][x, y] = 0; } b[1][x, y] += lightColor.X * brightness1; if (b[1][x, y] > 1.0f) { b[1][x, y] = 1.0f; } if (b[1][x, y] < 0) { b[1][x, y] = 0; } r[2][x, y] += lightColor.Z * brightness2; if (r[2][x, y] > 1.0f) { r[2][x, y] = 1.0f; } if (r[2][x, y] < 0) { r[2][x, y] = 0; } g[2][x, y] += lightColor.Y * brightness2; if (g[2][x, y] > 1.0f) { g[2][x, y] = 1.0f; } if (g[2][x, y] < 0) { g[2][x, y] = 0; } b[2][x, y] += lightColor.X * brightness2; if (b[2][x, y] > 1.0f) { b[2][x, y] = 1.0f; } if (b[2][x, y] < 0) { b[2][x, y] = 0; } r[3][x, y] += lightColor.Z * brightnessNorm; if (r[3][x, y] > 1.0f) { r[3][x, y] = 1.0f; } if (r[3][x, y] < 0) { r[3][x, y] = 0; } g[3][x, y] += lightColor.Y * brightnessNorm; if (g[3][x, y] > 1.0f) { g[3][x, y] = 1.0f; } if (g[3][x, y] < 0) { g[3][x, y] = 0; } b[3][x, y] += lightColor.X * brightnessNorm; if (b[3][x, y] > 1.0f) { b[3][x, y] = 1.0f; } if (b[3][x, y] < 0) { b[3][x, y] = 0; } luxelColor0 = new CoordinateF(r[0][x, y], g[0][x, y], b[0][x, y]); luxelColor1 = new CoordinateF(r[1][x, y], g[1][x, y], b[1][x, y]); luxelColor2 = new CoordinateF(r[2][x, y], g[2][x, y], b[2][x, y]); luxelColorNorm = new CoordinateF(r[3][x, y], g[3][x, y], b[3][x, y]); if (tX >= 0 && tY >= 0 && tX < textureDims && tY < textureDims) { int offset = (tX + tY * textureDims) * Bitmap.GetPixelFormatSize(System.Drawing.Imaging.PixelFormat.Format32bppArgb) / 8; if (luxelColor0.X + luxelColor0.Y + luxelColor0.Z > bitmaps[0][offset + 2] + bitmaps[0][offset + 1] + bitmaps[0][offset + 0]) { bitmaps[0][offset + 0] = luxelColor0.X; bitmaps[0][offset + 1] = luxelColor0.Y; bitmaps[0][offset + 2] = luxelColor0.Z; } if (luxelColor1.X + luxelColor1.Y + luxelColor1.Z > bitmaps[1][offset + 2] + bitmaps[1][offset + 1] + bitmaps[1][offset + 0]) { bitmaps[1][offset + 0] = luxelColor1.X; bitmaps[1][offset + 1] = luxelColor1.Y; bitmaps[1][offset + 2] = luxelColor1.Z; } if (luxelColor2.X + luxelColor2.Y + luxelColor2.Z > bitmaps[2][offset + 2] + bitmaps[2][offset + 1] + bitmaps[2][offset + 0]) { bitmaps[2][offset + 0] = luxelColor2.X; bitmaps[2][offset + 1] = luxelColor2.Y; bitmaps[2][offset + 2] = luxelColor2.Z; } if (luxelColorNorm.X + luxelColorNorm.Y + luxelColorNorm.Z > bitmaps[3][offset + 2] + bitmaps[3][offset + 1] + bitmaps[3][offset + 0]) { bitmaps[3][offset + 0] = luxelColorNorm.X; bitmaps[3][offset + 1] = luxelColorNorm.Y; bitmaps[3][offset + 2] = luxelColorNorm.Z; } } } } } } }
public void ConstructorTest0() { LineF line = new LineF(); Assert.IsTrue(line[0] == new Vector2()); Assert.IsTrue(line[1] == new Vector2()); }