public static List <V2> GetPointsList(List <float> x, List <float> y) { ThrowUtils.ThrowIf_NullArgument(x, y); ThrowUtils.ThrowIf_True(x.Count != y.Count, "x.Count != y.Count"); List <V2> points = new List <V2>(); for (int i = 0; i < x.Count(); i++) { V2 point = new V2(x[i], y[i]); points.Add(point); } return(points); }
/// <summary> /// /// </summary> /// <param name="sourceValues"></param> /// <param name="pointProvider">current source sequence element index; current element value</param> /// <returns></returns> public static List <V2> ToPointsList(this List <float> sourceValues, Func <int, float, V2> pointProvider) { ThrowUtils.ThrowIf_NullArgument(sourceValues); ThrowUtils.ThrowIf_NullArgument(pointProvider); List <V2> points = new List <V2>(); for (int i = 0; i < sourceValues.Count(); i++) { V2 point = pointProvider(i, sourceValues[i]); points.Add(point); } return(points); }
public bool Contains(V2 point, bool strict) { if (strict) { return(point.X > Origin.X && point.X < Destination.X && point.Y > Origin.Y && point.Y < Destination.Y); } else { return(point.X >= Origin.X && point.X <= Destination.X && point.Y >= Origin.Y && point.Y <= Destination.Y); } }
/// <summary> /// /// </summary> /// <param name="vertices">It must be a convex shape!</param> /// <param name="width">Shouldn't be too big comparing to the size of the <paramref name="vertices"/> /// or overlapping will occur!</param> /// <returns>Doesn't check calculated <see cref="Polygon"/> for overlapping!</returns> //public static Polygon CreateClosedPolygonFromCurve(IEnumerable<V2> vertices, double width) //{ // if (!vertices.CountNotLessOrEqual(3)) // { // throw new ArgumentException("Must be at least 3 vertices"); // } // vertices = vertices.MakeCached(); // return new Polygon(getPolygonVertices()); // IEnumerable<V2> getPolygonVertices() // { // var pushLength = width / 2; // foreach (var normal in getResultantNormals()) // { // } // } // // Returns normal for each point. It's implied that normal to the point - // // is resultant between same directed normals to two edges it's located between. // IEnumerable<V2> getResultantNormals() // { // var outerNormalsBuffer = new DisplaceCollection<V2>(2); // var outerNormals = getOuterNormals(); // var firstNormal = outerNormals.FirstItem(); // outerNormalsBuffer.Add(firstNormal); // foreach (var normal in outerNormals.SkipFirstItem().Concat(firstNormal)) // { // outerNormalsBuffer.Add(normal); // var resultantNormal = (outerNormalsBuffer[0] + outerNormalsBuffer[1]).Norm; // yield return resultantNormal; // } // IEnumerable<V2> getOuterNormals() // { // var center = new Polygon(vertices).Center; // var edgePoints = new DisplaceCollection<V2>(2); // edgePoints.Add(vertices.FirstItem()); // foreach (var verticle in vertices.SkipFirstItem().Concat(vertices.FirstItem())) // { // edgePoints.Add(verticle); // var edge = new Edge(edgePoints[0], edgePoints[1]); // yield return edge.GetOuterNormal(center); // } // } // } //} //#region ##### TRANSFORMATION ##### //public void Rotate(float angle, V2 rotPoint) //{ // int VLeng = Vertices.Length; // for (int i = 0; i < VLeng; i++) // { // V2 V = Vertices[i]; // Vertices[i].X = rotPoint.X + (V.X - rotPoint.X) * Math.Cos(angle) - (V.Y - rotPoint.Y) * Math.Sin(angle); // Vertices[i].Y = rotPoint.Y + (V.Y - rotPoint.Y) * Math.Cos(angle) + (V.X - rotPoint.X) * Math.Sin(angle); // } //} //public void Resize(V2 scale) //{ // int VLeng = Vertices.Length; // for (int i = 0; i < VLeng; i++) Vertices[i] *= scale; //} //public void Add(V2 vertex) //{ // if (Vertices == null) Vertices = new V2[0] { }; // int VLeng = Vertices.Length; // Array.Resize<V2>(ref Vertices, VLeng + 1); // Vertices[VLeng] = vertex; //} //public void Add(V2[] vertices) //{ // if (Vertices == null) Vertices = new V2[0] { }; // int VLeng = Vertices.Length; // Array.Resize<V2>(ref Vertices, VLeng + vertices.Length); // Array.Copy(vertices, 0, Vertices, VLeng, Vertices.Length); //} //public void Remove(int index) //{ // if (index > Vertices.Length) throw new ArgumentOutOfRangeException("index"); // int VLeng = Vertices.Length; // V2[] Buff = new V2[] { }; // Array.Resize<V2>(ref Buff, VLeng - 1); // Array.Copy(Vertices, Buff, VLeng - (VLeng - index)); // Array.Copy(Vertices, index + 1, Buff, index, VLeng - index - 1); // Vertices = Buff; //} //public void Insert(int index, V2 vertex) //{ // if (index > Vertices.Length) throw new ArgumentOutOfRangeException("index"); // Array.Resize<V2>(ref Vertices, Vertices.Length + 1); // Array.Copy(Vertices, index, Vertices, index + 1, Vertices.Length - 1 - index); // Vertices[index] = vertex; //} //public void AddOffcet(V2 off) //{ // for (int i = 0; i < Vertices.Length; i++) Vertices[i] += off; //} //#endregion #region ##### HELPERS ##### public RelPoint Contains(V2 point) { int parity = 0; for (int i = 0; i < Edges.Length; i++) { Edge e = Edges[i]; switch (e.DeterminePountPos(point)) { case Edge.PointRelativePos.TOUCHING: return(RelPoint.BOUNDARY); case Edge.PointRelativePos.CROSSING: parity = 1 - parity; break; } } return(parity == 1 ? RelPoint.INSIDE : RelPoint.OUTSIDE); }
public RelativePos Classify(V2 p0, V2 p1) { V2 @this = new V2(X, Y); V2 a = p1 - p0; V2 b = @this - p0; double sa = a.X * b.Y - b.X * a.Y; if (sa > 0) { return(RelativePos.LEFT); } else if (sa < 0) { return(RelativePos.RIGHT); } else if ((a.X * b.X < 0) || (a.Y * b.Y < 0)) { return(RelativePos.BEHIND); } else if (a.Len < b.Len) { return(RelativePos.BEYOND); } else if (p0 == @this) { return(RelativePos.ORIGIN); } else if (p1 == @this) { return(RelativePos.DESTINATION); } else { return(RelativePos.BETWEEN); } }
public double AcosRad(V2 secondV2) { return(Math.Acos(Dot(secondV2) / (Len * secondV2.Len))); }
public V3(V2 xy, double z) { X = xy.X; Y = xy.Y; Z = z; }
public Polygon(IEnumerable <V2> vertices) { Vertices = vertices.ToArray(); Edges = extractEdges(); Center = calcCenter(); Rect = calcRect(); Edge[] extractEdges() { if (Vertices.Length < 2) { return(new Edge[0]); } V2 LastVert = Vertices[0]; V2 CurrVert = V2.Zero; Edge[] Buff = new Edge[] { }; Array.Resize(ref Buff, Vertices.Length); for (int i = 0; i < Vertices.Length - 1; i++) { CurrVert = Vertices[i + 1]; Buff[i] = new Edge(LastVert, CurrVert); LastVert = CurrVert; } CurrVert = Vertices[0]; Buff[Vertices.Length - 1] = new Edge(LastVert, CurrVert); LastVert = CurrVert; return(Buff); } V2 calcCenter() { //POINT, MASS Dictionary <V2, double> Mass = new Dictionary <V2, double>(); Edge E; for (int i = 0; i < Edges.Length; i++) { E = Edges[i]; Mass.Add(E.Middle, E.Len); } double X = 0; double Y = 0; foreach (KeyValuePair <V2, double> KVP in Mass) { X += KVP.Key.X; Y += KVP.Key.Y; } X /= Edges.Length; Y /= Edges.Length; return(new V2(X, Y)); } V4 calcRect() { if (Vertices.Length == 0) { return(V4.Zero); } V2 V = Vertices[0]; var MinX = V.X; var MinY = V.Y; var MaxX = V.X; var MaxY = V.Y; for (int i = 1; i < Vertices.Length; i++) { V = Vertices[i]; if (V.X < MinX) { MinX = V.X; } else if (V.X > MaxX) { MaxX = V.X; } if (V.Y < MinY) { MinY = V.Y; } else if (V.Y > MaxY) { MaxY = V.Y; } } return(new V4(MinX, MinY, MaxX - MinX, MaxY - MinY)); } }
public bool Equals(V2 v2) { return(v2.X == X && v2.Y == Y); }
/// <summary> /// Возвращает угол между this и secondV2 образовынный при движении по часовой стрелке /// </summary> /// <returns>[0; 360]</returns> public double AngleDegClockwise(V2 secondV2) { return(360 - AngleDegCounterclockwise(secondV2)); }
/// <summary> /// Возвращает минимальный по модулю угол между this и secondV2, с учетом направления обсчета. /// </summary> /// <returns>(-PI; PI]</returns> public double AngleRadSigned(V2 secondV2) { return(Math.Atan2(X * secondV2.Y - secondV2.X * Y, X * secondV2.X + Y * secondV2.Y)); }
public double AngleTan(V2 secondV2) { return((X * secondV2.Y - Y * secondV2.X) / (X * secondV2.X + Y * secondV2.Y)); }
public V2 Mul(V2 k) { return(this * k); }
public V2 Sub(V2 anotherVector) { return(this - anotherVector); }
public V2 Add(V2 anotherVector) { return(this + anotherVector); }
public double Cross(V2 second) { return(X * second.Y - Y * second.X); }
public double Dot(V2 secondV2) { return(X * secondV2.X + Y * secondV2.Y); }
public double AngleCos(V2 secondV2) { return(Dot(secondV2) / (Len * secondV2.Len)); }
public double AngleSin(V2 secondV2) { return(Cross(secondV2) / (Len * secondV2.Len)); }
public V2 Div(V2 k) { return(this / k); }
/// <summary> /// Возвращает минимальный по модулю угол между this и secondV2, с учетом направления обсчета. /// </summary> /// <returns>(-180; 180]</returns> public double AngleDegSigned(V2 secondV2) { return(AngleRadSigned(secondV2) * RAD_TO_DEG); }
/// <summary> /// Составляющая вектора this сонаправленная с second /// </summary> /// <param name="second"></param> /// <returns></returns> public V2 Projection(V2 second) { return(second.Norm * (this * Dot(second.Norm) / Len).Len); }
/// <summary> /// Возвращает угол между this и secondV2 образовынный при движении против часовой стрелки /// </summary> /// <returns>[0; 360]</returns> public double AngleDegCounterclockwise(V2 secondV2) { return(AngleRadCounterclockwise(secondV2) * RAD_TO_DEG); }
public static V2 Max(V2 first, V2 second) { return(first.Len > second.Len ? first : second); }
/// <summary> /// Возвращает угол между this и secondV2 образовынный при движении по часовой стрелке /// </summary> /// <returns>[0; 360]</returns> public double AngleRadClockwise(V2 secondV2) { return(PIPI - AngleRadCounterclockwise(secondV2)); }
public static V2 Min(V2 first, V2 second) { return(first.Len < second.Len ? first : second); }
public V3(double x, V2 yz) { X = x; Y = yz.X; Z = yz.Y; }
/// <summary> /// Возвращает минимальный угол между векторами, направление обсчета не учитывается. /// </summary> /// <returns>[0; 180]</returns> public double AcosDeg(V2 secondV2) { return(180 * AcosRad(secondV2) / RAD_TO_DEG); }
/// <summary> /// Векторное произведение текущего вектора на вектор second Z = 0 /// </ summary > /// < param name="second"></param> /// <returns></returns> public V3 VectMull(V2 second) { float z = X * second.Y - Y * second.X; return(new V3(0, 0, z)); }
public V3(V2 xy, float z) { X = xy.X; Y = xy.Y; Z = z; }