/// <summary> /// Proiezione di un punto su un arco /// </summary> /// <param name="p">Punto</param> /// <param name="a">Arco</param> /// <param name="projection">Proiezione (parametro out)</param> /// <param name="bInside">true se richiesta appartenenza proiezione all'interno dell'arco</param> /// <returns>true se trovata</returns> public static bool Projection( Point2D p, Arc2D a, out Point2D projection, bool bInside = false) { Point2D proj = null; // La proiezione, se trovata Point2D dir = p - a.Center; // Calcola il vettore dal centro al punto if(dir.Normalize()) // Lo normalizza. Se nessun errore... { Point2D proj1 = a.Center + a.Radius * dir; // Calcola le due proiezioni sul cerchio. Point2D proj2 = a.Center - a.Radius * dir; double d1 = Function2D.Distance(proj1, p); // e le distanze tra punto e proiezione double d2 = Function2D.Distance(proj2, p); bool app1, app2; // Appartenenza all'arco delle due proiezione app1 = app2 = true; if( bInside == true) // Verifica le appartenenze all'arco { double alfa; if(a.Alfa(proj1, out alfa)) // calcola l'angolo del primo e del secondo punto proiettato { // scarta, se non appartiene all'arco if(!a.Belongs(alfa)) app1 = false; } if(a.Alfa(proj2, out alfa)) { if(!a.Belongs(alfa)) app2 = false; } } if( (app1==true) && (app2==true) ) // Se entrambi appartengono all'arco { // scarta quello con distanza maggiore if(d1 >= d2) app1 = false; else app2 = false; } if(app1) // Imposta proj con la proiezione valida... proj = proj1; // ...se c'e` else if(app2) proj = proj2; } if(proj != null) // Se trovata proiezione, esce con true... { projection = proj; return true; } projection = new Point2D(); return false; // ...se non trovata, esce con false + punto vuoto. }
/// <summary> /// Intersezioni tra linea ed arco /// </summary> /// <param name="l1">Linea</param> /// <param name="a2">Arco</param> /// <param name="bCheckInside1">Richiesta intersezione interna alla linea</param> /// <param name="bCheckInside2">Richiesta intersezione interna all'arco</param> /// <returns></returns> public static List<Intersection> Intersect( Line2D l1, Arc2D a2, bool bCheckInside1 = false, bool bCheckInside2 = false) { double[] t = new double[2]; double[] a = new double[2]; Point2D[] p = new Point2D[2]; bool[] ok = new bool[2]; // soluzione trovata e valida bool[] tg = new bool[2]; // intersezione doppia List<Intersection> intersezioni = new List<Intersection>(); // P = P1 + t (P2 - P1) equazione della retta del segmento // P = C + r (cos a, sin a) oppure equazione della circonferenza // || P - C ||^2 = r^2 altra equazione della circonferenza // || P1 - C + t (P2 - P1) ||^2 = r^2 Intersezione: punto su entrambi // A = P1 - C; B = P2 - P1 Sostituzioni // || V || = V.x^2 + V.y^2 = V ^ V (scalare) Definizione di modulo // || A + t B ||^2 = r^2 Intersezione, sostituendo... // (A.x + t B.x)^2 + (A.y + t B.y)^2 - r^2 = 0 ... // A.x^2 + t^2 B.x^2 + 2 t A.x B.x + A.y^2 + t^2 B.y^2 + 2 t A.y B.y - r^2 = 0 ... // A.x^2 + A.y^2 + t^2 ( B.x^2 + B.y^2) + 2 t ( A.y B.y + A.x B.x) - r^2 = 0 ... // t^2(B^B) + 2 t (A^B) + A^A - r^2 = 0 Equazione di secondo grado da risolvere // a=B^B 2b=2*A^B c=A^A-r^2 in a*t^2 + 2*b*t + c = 0 Coefficienti // t12 = [-2b +- sqr( (2b)^2 - 4ac) ] / 2a = [-2b +- 2sqr( b^2 - ac) ] / 2a Formula completa... // t1 = [-b +- sqr(b^2-ac)]/a ...e ridotta Point2D A = l1.P1 - a2.Center; Point2D B = l1.P2 - l1.P1; double r = a2.Radius; ok[0] = ok[1] = false; // Imposta i flag tg[0] = tg[1] = false; double aEq, bEq, cEq, dEq24, dEq2; // Calcola con formula ridotta ERRORE NELLA FORMULA ??? aEq = B^B; bEq = A^B; cEq = (A^A) - r*r; dEq24 = bEq*bEq - aEq*cEq; if(dEq24 >= 0.0) // Cerca le soluzioni, memorizza valori ed imposta i flag { // Se ci sono soluzioni if(Math.Abs(dEq24) < Function2D.epsilon) // Delta = 0, una soluzione { t[0] = -bEq / aEq; p[0] = l1.P1 + t[0] * (l1.P2 - l1.P1); if(a2.Alfa(p[0], out a[0])) // Calcola alfa dell'arco e imposta flag della soluzione { ok[0] = true; tg[0] = true; // tangente, soluzione doppia } } else // Delta > 0, due soluzioni { dEq2 = Math.Sqrt(dEq24); // Radice di delta t[0] = (-bEq - dEq2) / aEq; t[1] = (-bEq + dEq2) / aEq; p[0] = l1.P1 + t[0] * (l1.P2 - l1.P1); p[1] = l1.P1 + t[1] * (l1.P2 - l1.P1); if(a2.Alfa(p[0], out a[0])) // Calcola alfa e flag delle due soluzioni ok[0] = true; if(a2.Alfa(p[1], out a[1])) ok[1] = true; } } for(int i=0; i<2; i++) // Verifica, se richieste, le appartenenze a segmento e arco { if(ok[i]) // Esamina, se c'e', la soluzione { if(bCheckInside1) // Se richiesto punto interno verifica... { if( (t[i] < 0.0) || (t[i] > 1.0) ) // Se t trovato indica che e` esterno, imposta a false ok[i] = false; } if(bCheckInside2) // Idem per l'arco... { if(!a2.Belongs(a[i])) ok[i] = false; } } } for(int i=0; i<2; i++) // Riesamina le soluzione { if(ok[i]) // Se trovata, aggiunge intersezione alla lista { intersezioni.Add(new Intersection(p[i], t[i], a[i], l1, a2, false, tg[i])); } } return intersezioni; // Restituisce il rif. alla lista }