/// <summary> /// oblouk zadany tremi body /// </summary> /// <param name="pt1">pocatecni bod</param> /// <param name="pt2">bod uvnitr oblouku</param> /// <param name="pt3">koncovy bod</param> public Arc2D(Point pt1, Point pt2, Point pt3) { var c = new Circle2D(pt1, pt2, pt3); Begin = pt1; End = pt3; Radius = c.Radius; if (Funcs2D.IsEqual(Radius, 0)) { Clockwise = true; } else { Vector b = pt1.Minus(c.Center); double a1 = Vector.AngleBetween(b, pt2.Minus(c.Center)); double a2 = Vector.AngleBetween(b, pt3.Minus(c.Center)); if (a1 < 0) { a1 = 360 + a1; } if (a2 < 0) { a2 = 360 + a2; } Clockwise = a1 > a2; if ((Clockwise && a2 < 180) || (!Clockwise && a2 > 180)) { Radius *= -1; } } }
//rekurze pro jeden polygon private void f_GetOnePolygonSplit() { List <Point> rpt = new List <Point>(); List <int> rptInx = new List <int>(); int start = -1; if (myPTR.inxLn != -1) { if (!Funcs2D.IsEqual(myPTR.kRel, 1, Funcs2D.Epson)) // zapisu bod pokud neni prusecik na konci usecky { rpt.Add(myPTR.pPt); rptInx.Add(myPTR.inxLn); } start = myPTR.inxLn; } while (f_NextPTR()) // najdu dalsi bod { if (myPTR.IsCrossing && myPTR.inxCrLn == start) { break; // uzavrela se moje smycka } if (myPTR.IsCrossing) { f_GetOnePolygonSplit(); // jdu dovnitr dalsi smycky } if (!Funcs2D.IsEqual(myPTR.kRel, 1, Funcs2D.Epson)) // zapisu bod pokud neni prusecik na konci usecky { rpt.Add(myPTR.pPt); // zapisu bod rptInx.Add(myPTR.inxLn); } } mySplits.Add(rpt); myInxSplits.Add(rptInx); }
/// <summary> /// vrati tri body na oblouku /// </summary> /// <param name="k2">relativni delkova souradnice druheho bodu</param> /// <returns>vrati pole bodu ret[0] = zacatek, ret[1] = bod na oblouku podle k2, ret[2] = konec</returns> public Point[] ThreePoints(double k2 = 0.5) { if (IsEmpty) { return(null); } var ret = new Point[3]; ret[0] = Begin; Circle2D c = Circle2D; Vector b = Begin.Minus(c.Center); double ab = Vector.AngleBetween(new Vector(1, 0), b); double a = Vector.AngleBetween(b, End.Minus(c.Center)); if (ab < 0) { ab = 360 + ab; } if (a < 0) { a = 360 + a; } if (Clockwise) { a -= 360; } a = ab + (a * k2); ret[1] = c.PointOn(Funcs2D.Radian(a)); ret[2] = End; return(ret); }
/// <summary> /// vypocita uhly definovane obloukem, uhly jsou v radianech /// </summary> /// <param name="start">pocatecni uhel oblouku</param> /// <param name="angle">uhel sevreny pocatecnim a koncovym bodem oblouky, zaporny uhel - oblouk je ve smeru hodinovych rucicek</param> /// <returns>pokud je objekt empty vrati false</returns> public Circle2D?GetAngles(out double start, out double angle) { Circle2D c = Circle2D; start = angle = 0; if (c.IsEmpty) { return(null); } Vector b = Begin.Minus(c.Center); double ab = Vector.AngleBetween(new Vector(1, 0), b); double a = Vector.AngleBetween(b, End.Minus(c.Center)); if (ab < 0) { ab = 360 + ab; } if (a < 0) { a = 360 + a; } if (Clockwise) { a -= 360; } start = Funcs2D.Radian(ab); angle = Funcs2D.Radian(a); return(c); }
/// <summary> /// kruznice urcena tremi body na obvodu /// </summary> /// <param name="pt1">prvni bod</param> /// <param name="pt2">druhy bod</param> /// <param name="pt3">treti bod</param> public Circle2D(Point pt1, Point pt2, Point pt3) { Radius = 0; Center = pt1; Point[] p = new Point[2]; Vector[] v = new Vector[2]; p[0].X = (pt1.X + pt2.X) / 2; p[0].Y = (pt1.Y + pt2.Y) / 2; p[1].X = (pt2.X + pt3.X) / 2; p[1].Y = (pt2.Y + pt3.Y) / 2; v[0].X = pt2.Y - pt1.Y; v[0].Y = -(pt2.X - pt1.X); v[1].X = pt3.Y - pt2.Y; v[1].Y = -(pt3.X - pt2.X); TwoLine2D.CrossStatus st = TwoLine2D.CrossStatus.Infinite; if (TwoLine2D.CrossAbs(p[0], st, v[0], st, p[1], st, v[1], st, out Center)) { Radius = Funcs2D.Distance(pt1, Center); } }
public static double[] AnglesCrossLine(Point centre, double r, Point pt1, Point pt2) { Point t = Funcs2D.PointToLine(pt1, pt2, centre); if (Funcs2D.IsEqual(t, centre)) { double an = Funcs2D.LineAngle(pt1, pt2); return(new double[] { Funcs2D.PureRadianAngle(an + Math.PI), an }); } double z = Funcs2D.Distance(centre, t); double a = Funcs2D.LineAngle(centre, t); if (z.IsGreater(r)) { return(null); // mimo } if (z.IsEqual(r)) // tecna { return(new double[] { a }); } //secna double aa = Math.Acos(z / r); // uhel pulky tetivy return(new double[] { Funcs2D.PureRadianAngle(a + aa), Funcs2D.PureRadianAngle(a - aa) }); }
/// <summary> /// otestuje zda prislusny bot lezi na oblouku /// </summary> /// <param name="pt">testovany bod</param> /// <returns></returns> public bool IsPointOn(Point pt) { Circle2D?c = GetAngles(out double st, out double an); if (c == null) { return(false); } if (!Funcs2D.Distance(pt, c.Value.Center).IsEqual(Math.Abs(Radius))) { return(false); } st = Funcs2D.PureRadianAngle(st); double angle = Funcs2D.LineAngle(c.Value.Center, pt); if (an > 0) { an = st + an; return(angle.IsGreaterOrEqual(st) && angle.IsLesserOrEqual(an)); } else { an = st + an; return(angle.IsGreaterOrEqual(an) && angle.IsLesserOrEqual(st)); } }
public static ParallelResult ParallelCheck( Point pta, Vector da, //bod a vektor prvni primky Point ptb, Vector db, //bod a vektor druhe primky out Point retRel, // vraci relativni souradnice ( x = begin, y = end) na prvni primce out bool direct) // smer vektoru primek, true stejny smer, false opacny smer { retRel = new Point(); direct = false; var rr = Funcs2D.IsParallel(da, db); if (rr == 0) { return(ParallelResult.Nothing); } direct = rr > 0; retRel.X = Funcs2D.PointToLine(pta, da, ptb); retRel.Y = Funcs2D.PointToLine(pta, da, ptb.Plus(db)); if (Funcs2D.IsThreePointsOnLine(pta, pta.Plus(da), ptb)) { return(ParallelResult.ParallelOn); } else { return(ParallelResult.ParallelOut); } }
// vypocita rovnobeznou primku public static Point[] LineOffset(Point pt1, Point pt2, double offset) { Vector vv = pt2.Minus(pt1), // vektor nv = Funcs2D.VectorNormal(vv); // kolmy vektor Point[] ret = new Point[2]; if (Funcs2D.IsNull(vv)) { ret[0] = pt1; ret[1] = pt2; return(ret); } ; double len = vv.Length, // delka primky kn = offset / len; // delkovy koeficient offsetu // prvni bod ret[0].X = pt1.X + (kn * nv.X); ret[0].Y = pt1.Y + (kn * nv.Y); // druhy bod ret[1].X = ret[0].X + vv.X; ret[1].Y = ret[0].Y + vv.Y; return(ret); }
public PolygonOffset(IPolygonReader poly, bool isClosed = true, bool isOutline = true) { // testovani a vyhozeni vyjimek if (poly == null) { throw (new ArgumentNullException("PolygonOffset(poly,..)")); } if (poly.Length < (isClosed ? 3 : 2)) { throw (new FormatException("PolygonOffset, small number of points")); } mySrc = new MyPoint[poly.Length]; myRet = null; IsClosed = isClosed; IsOutline = isOutline; // zjistim smer otaceni myIsReversed = Funcs2D.PolygonIsClockwise(poly) == IsOutline; for (int i = 0; i < poly.Length; i++) { poly.GetRow(i, out double x, out double y); mySrc[i].Pt.X = x; mySrc[i].Pt.Y = y; mySrc[i].Id = i; mySrc[i].Offset = 0; } if (!IsClosed) { mySrc[poly.Length - 1].Id = 0; } }
public bool TestCrossing(MyLine src, double[,] p) { if (myEnd == src.myBegin) { return(false); } if (myBegin == src.myEnd) { return(false); } if (!TwoLine2D.CrossRel(new Point(p[myBegin, 0], p[myBegin, 1]), new Point(p[myEnd, 0], p[myEnd, 1]), new Point(p[src.myBegin, 0], p[src.myBegin, 1]), new Point(p[src.myEnd, 0], p[src.myEnd, 1]), out Point t)) { return(false); } if (!TwoLine2D.TestRelOnLine(TwoLine2D.CrossStatus.And, t.X)) { return(false); } if (!TwoLine2D.TestRelOnLine(TwoLine2D.CrossStatus.And, t.Y)) { return(false); } if (Funcs2D.IsEqual(t.X, 0, Funcs2D.Epson) || Funcs2D.IsEqual(t.Y, 0, Funcs2D.Epson)) { return(false); // prusecik je na zacatku usecky, nezapisu } f_AddCross(t.X, src.myBegin); src.f_AddCross(t.Y, myBegin); return(true); }
/// <summary> /// vytvori oblouk zadany pocatecnim bodem, vektorem ve kterm je koncovy bod a zdvihem v poloine usecky /// </summary> /// <param name="pt1">pocatecni bod oblouku</param> /// <param name="v">vektor udavajici koncovy bod oblouky</param> /// <param name="elevation">zdvih oblouku v polovine usecky [pt1,v]</param> /// <returns></returns> public static Arc2D Arc2DElevation(Point pt1, Vector v, double elevation) { Point pt2, pt3 = pt1.Plus(v); pt2 = Funcs2D.PointOnLineLen(Funcs2D.PointOnLine(pt1, v, 0.5), Funcs2D.VectorNormal(v), elevation); return(new Arc2D(pt1, pt2, pt3)); }
public SplitPoly(IPolygonReader poly, List <int> inx) { Poly = poly; Inx = inx; Area = Funcs2D.PolygonArea(poly); IsClkw = Area <= 0; Area = Math.Abs(Area); }
//vypocita kolmy prumet bodu na usecce , vysledek je relativni souradnice usecky public static double PointToLine(Point pt1, Vector v, Point pk) { Vector vn = Funcs2D.VectorNormal(v); TwoLine2D.CrossRel(pt1, v, pk, vn, out Point ret); return(ret.X); }
public static IPolygonReader[] PolygonsInterconnect(IPolygonReader[] polygons, Point pt, Vector v) { IPolygonReader[] ret = null; List <Tuple <double, int, int> > cr = new List <Tuple <double, int, int> >(); bool[] bcr = new bool[polygons.Length]; Point ptt = new Point(); Vector norm = Funcs2D.VectorNormal(v); for (int i = 0; i < polygons.Length; i++) { for (int j = 0; j < polygons[i].Length; j++) { polygons[i].GetRow(j, out double x, out double y); ptt.X = x; ptt.Y = y; if (TwoLine2D.CrossRel(pt, v, ptt, norm, out Point pr)) { if (Funcs2D.IsEqual(pr.Y, 0.0, Funcs2D.Epson)) { cr.Add(new Tuple <double, int, int>(pr.X, i, j)); bcr[i] = true; } } } } if (cr.Count < 2) { return(null); } int k = 1; foreach (var b in bcr) { if (!b) { k++; } } ret = new IPolygonReader[k]; k = 0; for (int i = 0; i < bcr.Length; i++) { if (!bcr[i]) { ret[k++] = polygons[i]; } } // trideni cr.Sort((a, b) => a.Item1.CompareTo(b.Item1)); List <Point> rpt = new List <Point>(); f_InterconnectJoin(0, cr, polygons, rpt); ret[k] = new BoxListPoint(Funcs2D.PolygonPure(new BoxListPoint(rpt), true)); return(ret); }
public Point CrossPoint(int inx, double[,] p) { int i = -1; for (i = 0; i < myCross.Count; i++) { if (myCross[i].Inx == inx) { break; } } return(Funcs2D.PointOnLine(new Point(p[myBegin, 0], p[myBegin, 1]), new Point(p[myEnd, 0], p[myEnd, 1]), myCross[i].Rel)); }
/// <summary> /// vytvori oblouk zadany dvema body a polomerem /// </summary> /// <param name="begin">pocatecni bod</param> /// <param name="end">koncovy bod</param> /// <param name="radius">polomer, + = kratky oblouk , - = dlouhy oblouk</param> /// <param name="clockwise">smer</param> public Arc2D(Point begin, Point end, double radius, bool clockwise) { Begin = begin; End = end; if (Funcs2D.IsEqual(begin, end)) { Radius = 0; } else { Radius = radius; } Clockwise = clockwise; }
/// <summary> /// oblouk zadany stredem , pocatecnim bodem a vektorem ne kterem lezi kocovy bod /// </summary> /// <param name="center">stred</param> /// <param name="pt">pocatecni bod</param> /// <param name="vector">vektor na kterem lezi koncovy bod</param> /// <param name="shortangle">true = kratky oblouk (mezi nulou az 180 stupni), false = dlouhy oblouk (doplnek do 360 stupnu)</param> public Arc2D(Point center, Point pt, Vector vector, bool shortangle = true) { Radius = Funcs2D.Distance(center, pt); Begin = pt; double a = Funcs2D.Radian(Vector.AngleBetween(new Vector(1, 0), vector)); End = Circle2D.PointOn(center, Radius, a); if (!shortangle) { Radius *= -1; } a = Vector.AngleBetween(pt.Minus(center), vector); Clockwise = !(a > 0 && shortangle || a < 0 && !shortangle); }
// zjisti zda jsou usecky korektne zadane, nemaji nulovou delku public int IsNotCorrectLine() { Line2D l = new Line2D(myPoint[0], myPoint[1]); if (Funcs2D.IsEqual(l.Length, 0, Funcs2D.Epson)) { return(1); } l.Begin = myPoint[2]; l.End = myPoint[3]; if (Funcs2D.IsEqual(l.Length, 0, Funcs2D.Epson)) { return(2); } return(0); }
/// <summary> /// kruznice zadana dvema body na obvodu a polomerem /// , pokud je polomer mensi nez polovina vzdalenosti bodu, umisti se stred kruznice do stredoveho bodu tvoriciho obema ridicimi body /// , stred kruznice se umisti do poloroviny urcene ridicimi body, podle znamenka polomeru /// </summary> /// <param name="pt1">prvni bod na obvodu</param> /// <param name="pt2">druhy bod na ovodu</param> /// <param name="r">polomer</param> public Circle2D(Point pt1, Point pt2, double r) { double d = Funcs2D.Distance(pt1, pt2) / 2; if (Math.Abs(r) <= d) { Radius = d; Center = new Point((pt1.X + pt2.X) / 2, (pt1.Y + pt2.Y) / 2); } else { Radius = Math.Abs(r); double v = Math.Sqrt(Math.Pow(Radius, 2) - Math.Pow(d, 2)); Center = Funcs2D.LineRelPtOffset(pt1, pt2, 0.5, r < 0 ? -v : v); } }
public static bool CrossRel(Point pta, Vector da, //bod a vektor prvni primky Point ptb, Vector db, //bod a vektor druhe primky out Point retRel) // vraci relativni souradnice { double t; retRel = new Point(); t = (da.X * db.Y) - (da.Y * db.X); if (Funcs2D.IsEqual(t, 0.0, Funcs2D.Epson)) { return(false); } retRel.X = ((ptb.X * db.Y) - (ptb.Y * db.X) - (pta.X * db.Y) + (pta.Y * db.X)) / t; retRel.Y = ((pta.X * da.Y) - (pta.Y * da.X) - (ptb.X * da.Y) + (ptb.Y * da.X)) / ((db.X * da.Y) - (db.Y * da.X)); return(true); }
/// <summary> /// oblouk zadany stredem , pocatecnim bodem a uhlem /// </summary> /// <param name="center">stred</param> /// <param name="pt">pocatecni bod</param> /// <param name="angle">uhel v radianech , smer podle znamenka ( - = clockwise)</param> public Arc2D(Point center, Point pt, double angle) { Radius = Funcs2D.Distance(center, pt); Begin = pt; if (Math.Abs(angle) > Math.PI * 2) { angle = angle % (Math.PI * 2); } Clockwise = angle < 0; double a = Funcs2D.Radian(Vector.AngleBetween(new Vector(1, 0), pt.Minus(center))); a += angle; End = Circle2D.PointOn(center, Radius, a); if (Math.Abs(angle) > Math.PI) { Radius *= -1; } }
/// <summary> /// otestuje zda poloprimka zadaneho smeru protne oblouk /// </summary> /// <param name="angle">uhel poloprimky</param> /// <returns></returns> public bool IsAngleOn(double angle) { if (GetAngles(out double st, out double an) == null) { return(false); } angle = Funcs2D.PureRadianAngle(angle); if (an > 0) { an = st + an; return(angle.IsGreaterOrEqual(st) && angle.IsLesserOrEqual(an)); } else { an = st + an; return(angle.IsGreaterOrEqual(an) && angle.IsLesserOrEqual(st)); } }
public static Point LineRelPtOffset(Point pt1, Vector vv, double rel, double offset) { Point ret = new Point(); Vector nv = Funcs2D.VectorNormal(vv); // kolmy vektor if (Funcs2D.IsNull(vv)) { return(ret); } double len = vv.Length, // delka primky kn = offset / len; // delkovy koeficient offsetu Point pt = PointOnLine(pt1, vv, rel); ret.X = pt.X + (kn * nv.X); ret.Y = pt.Y + (kn * nv.Y); return(ret); }
// public TwoLine2D() // { // for (int i = 0; i < 4; i++) myPoint[i] = new Point(); // } public static AbscissaStatus AbscissaStatusFromRel(double k, double limit = Funcs2D.Epson) { if (Funcs2D.IsZero(k, limit)) { return(AbscissaStatus.Begin); } if (Funcs2D.IsZero(k - 1, limit)) { return(AbscissaStatus.End); } if (k < 0) { return(AbscissaStatus.Low); } if (k > 1) { return(AbscissaStatus.Hight); } return(AbscissaStatus.Inside); }
//Zkontroluje prubeh zaobleni // return 0 = OK // 1 bit = je mimo prvni usecku // 2 bit = je mimo druhou usecku // 3 bit = body jsou na jedne primce public static int TestRounding(Point pt1, Point pt2, Point pt3, double r) { int ret = 0; double a = Vector.AngleBetween(pt2.Minus(pt1), pt3.Minus(pt2)); if (a > 0) { r = -r; } // vypocitam prusecik offsetovanych primek Point[] p1 = Funcs2D.LineOffset(pt1, pt2, a); if (p1 == null) { ret |= 1; } Point[] p2 = Funcs2D.LineOffset(pt2, pt3, a); if (p2 == null) { ret |= 2; } if (ret != 0) { return(ret); } if (!TwoLine2D.CrossRel(p1[0], p1[1], p2[0], p2[1], out Point rr)) { return(4); } if (!TwoLine2D.TestRelOnLine(TwoLine2D.CrossStatus.And, rr.X)) { ret |= 1; } if (!TwoLine2D.TestRelOnLine(TwoLine2D.CrossStatus.And, rr.Y)) { ret |= 2; } return(ret); }
public static List <int> PolygonParallelEdges(IPolygonReader poly, bool closed, Vector v) { List <int> r = new List <int>(); Point[] p = new BoxArrayPoint(poly).Value; for (int i = 0, j; i < p.Length; i++) { if (i == p.Length - 1) { j = 0; } else { j = i + 1; } if (Funcs2D.IsParallel(v, p[j].Minus(p[i])) != 0) { r.Add(i); } } return(r); }
private static bool testRelEndPt(CrossStatus st, double t) { switch (st) { case CrossStatus.Infinite: break; case CrossStatus.And: if (!(t < 1 || Funcs2D.IsEqual(t, 1.0, Funcs2D.Epson))) { return(false); } break; case CrossStatus.Not: if (Funcs2D.IsEqual(t, 1.0, Funcs2D.Epson)) { return(false); } if (!(t < 1)) { return(false); } break; } return(true); }
public bool NextPoint(ref DataPTR ptr, double[,] p) { //Debug.Assert(ptr.inxPt == myBegin); if (ptr.inxPt == -1) // pocatecni bod { //DODO POZOR muze byt prusecik na zacatku, ptr.inxCrLn = -1; ptr.inxPt = 0; ptr.pPt = BeginPoint(p); ptr.kRel = 0; return(true); } if (IsCrossing && ptr.inxPt < myCross.Count) { ptr.pPt = Funcs2D.PointOnLine(new Point(p[myBegin, 0], p[myBegin, 1]), new Point(p[myEnd, 0], p[myEnd, 1]), myCross[ptr.inxPt].Rel); ptr.kRel = myCross[ptr.inxPt].Rel; ptr.inxCrLn = myCross[ptr.inxPt].Inx; ptr.inxPt++; return(true); } ptr.inxCrLn = -1; ptr.inxPt = -1; return(false); }
public static bool IsNull(Vector v, double limit) // testuje nulovy vektor , s povolenou odchylkou 'limit' { return(IsEqual(v.X, 0, limit) && Funcs2D.IsEqual(v.Y, 0, limit)); }