Wyznaczanie punktu na dwusiecznej

0

Witam

Zadanie jest następujące:
Dane mam punkty A, B, C, oraz dystans pomiędzy punktami B i D, wyznaczyć taki punkt D aby spełniał warunki:

  • leżał na dwusiecznej kąta ABC
  • był w zadanej odległości od punktu B

Algorytm jaki obrałem do rozwiązania tego zadania to:

  1. wyznaczam równania prostych AB i BC
  2. wyznaczam równanie prostej dwusiecznej kąta ABC (kąta tworzonego przez proste AB i BC, są dwie dwusieczne ale sprawdzam warunek czy wspolczynnik kierunkowy dwusiecznej zawiera sięmiędzy współczynnikami kierunkowymi prostych AB i BC
  3. z układu równań: równania prostej dwusiecznej oraz równania okręgu o środku w punkcie B i promieniu długości zadanego dystansu pomiędzy punktami BD wyznaczam wspolrzedne punktu D (tu tez są dwa rozwiązania, jeszcze nie wiem jakimi warunkami szukac tego wlasciwego punktu ale problem mam z czym innym po drodze)

Dlaczego w wizualizacji po zmianie wspolrzednych punktów A, B lub C zmienia mi sie dlugość odcinka BD? Juz dwa razy wyprowadzalem wzory, moze mam blad w rozumowaniu i algorytm jest zly?

Zadanie to wprawka w programowaniu, gdzieś kiedyś przeczytane na którymś forum,
Nie moge rozszyfrować dlaczego zmieniając wspolrzędne punktów A, B i C zmienia mi się dystans BD. jeżeli ktoś wie gdzie może być błąd prosiłbym o pomoc.
Klikając na punkt i przytrzymując lkm można punkt przesuwać i wtedy właśnie dzieją się jaja.

1

Co prawda w Delphi ale się połapiesz:

if (A.x-B.x)*(C.y-B.y)<>(A.y-B.y)*(C.x-B.x) then
begin
  dx:=A.x-B.x;
  dy:=A.y-B.y;
  LA:=sqrt(dx*dx+dy*dy);
  dx:=C.x-B.x;
  dy:=C.y-B.y;
  LC:=sqrt(dx*dx+dy*dy);
  px:=(A.x+B.x+(C.x-B.x)*LA/LC)/2-B.x; // współrzędna X punktu P leżącego na promieniu B->C w odległości |BA| od B , ale od tego już odjęto B.x
  py:=(A.y+B.y+(C.y-B.y)*LA/LC)/2-B.y;
  L:=sqrt(px*px+py*py); // odległość |BP| 
  D.x:=Round(B.x+px*Radius/L); // współrzędna X punktu D  leżącego na promieniu B->P w odległości Radius od B
  D.y:=Round(B.y+py*Radius/L);
end
else // A B C nie stanowią trójkątu
1

offtopic: popatrzyłem troszkę w twój kod i w RownanieProstej znalzałem coś takiego:

public bool CzyPunktNalezyDoProstej(double x, double y)
        {
            if ((A*x + B*y + C)==0)
            {
                return true;
            }
            else
            {
                return false;
            }            
        }

tak się nie porównuje wartości zmiennoprzecinkowych. Pamiętaj o błędach zaokrągleń.
Powinno być raczej:

private const double EPSILON = 1E-9; // klasa Double nie ma stałej opisującej tą wartość, chodzi o najmniejszą dodatnią niezerową różnicę jaką można uzyskać odejmując jedynkę

public bool CzyPunktNalezyDoProstej(double x, double y)
        {
            return Math.Abs(A*x+B*y+C)<EPSILON*C; // "*C" jest potrzebne by uwzględnić jakim zakresem wartości się posługujemy
        }
0

Dzięki za rady,

@_13th_Dragon jak wróce z pracy to postaram się rozszyfrować co robisię w 5 ostatnich linijkach Twojego kodu,

@MarekR22 dzieki za radę, czyli to:

EPSILON*C
 

to czyta się jako coś mozliwie małego ale jeszcze nie zerowego dla typu double? tak?
(coś małego, bliskiego zero ale nie zero) x (cokolwiek) = (coś bliskiego zero) na tym to polega?

Edit:

 
private PunktRys ZnajdzSzukanyPunktD()
        {
            //metoda _13th_Dragon
            PunktRys buforek = SzukanyD;

            if ((zadanyA.WspX-zadanyB.WspX)*(zadanyC.WspY-zadanyB.WspY)
                !=(zadanyA.WspY-zadanyB.WspY)*(zadanyC.WspX-zadanyB.WspX))
            {
                int dx = zadanyA.WspX - zadanyB.WspX;
                int dy = zadanyA.WspY - zadanyB.WspY;
                double LA = Math.Sqrt(dx * dx + dy * dy);

                int dx2 = zadanyC.WspX - zadanyB.WspX;
                int dy2 = zadanyC.WspY - zadanyB.WspY;
                double LC = Math.Sqrt(dx2 * dx2 + dy2 * dy2); 

                double px = (zadanyA.WspX + zadanyB.WspX + (zadanyC.WspX - zadanyB.WspX) * LA / LC) / 2 - zadanyB.WspX;
                double py = (zadanyA.WspY + zadanyB.WspY + (zadanyC.WspY - zadanyB.WspY) * LA / LC) / 2 - zadanyB.WspY;
                double L = Math.Sqrt(px * px + py * py);

                return new PunktRys(
                    new Point(
                            (int) (zadanyB.WspX + px * zadanyDystansBD / L),
                            (int) (zadanyB.WspY + py * zadanyDystansBD / L)),
                    "Dragon");

            }    
            else
            {
                return buforek;
            }   
        }

no i działa, odleglosc BD jest zachowana, pozostało mi jeszcze pare przypadków szczególnych obsłużyć bo w paru miejscach jeszcze się krzaczy (przejscie przez kąt 180st).

Ostatnie pytanie, co to robi, ale tak matematycznie? Bo z samego wzoru nie mogę dojść, tym bardziej nie moge sobie tego wyobrazic na rysunku.
Bede wdzieczny za wyjasnienie.

 
  px:=(A.x+B.x+(C.x-B.x)*LA/LC)/2-B.x; // współrzędna X punktu P leżącego na promieniu B->C w odległości |BA| od B , ale od tego już odjęto B.x
  py:=(A.y+B.y+(C.y-B.y)*LA/LC)/2-B.y;
  L:=sqrt(px*px+py*py); // odległość |BP| 
double px = (zadanyA.WspX + zadanyB.WspX + (zadanyC.WspX - zadanyB.WspX) * LA / LC) / 2 - zadanyB.WspX;
double py = (zadanyA.WspY + zadanyB.WspY + (zadanyC.WspY - zadanyB.WspY) * LA / LC) / 2 - zadanyB.WspY;
double L = Math.Sqrt(px * px + py * py); 
1

generalnie chodzi o to, że masz ileś cyfr wiodących. Porównując 1.42342342345 z 1.42342342341 spokojnie można zastosować czyste EPSILON=0.000000001. Jednak jak porównujesz 14234234.2345 z 14234234.2341 to te same EPSILON nie ma sensu.

1

user image
Najpierw wyliczamy punkt T, jako kontynuacja B->C o długości |AB|
T.x=B.x+(B.x-C.x)*|AB|/|BC|; T.y - analogicznie.
Potem wyliczamy P jako punkt pomiędzy A i T
P.x=(A.x+T.x)/2; P.y - analogicznie.
Teraz wyliczamy D, jako kontynuacja B->P o długości Radius
D.x=B.x+(B.x-P.x)*Radius/|BP|; D.y - analogicznie.

Tak a propos możesz dokonać pewnych optymalizacji:

                double px = (zadanyA.WspX - zadanyB.WspX)*LC + (zadanyC.WspX - zadanyB.WspX) * LA;
                double py = (zadanyA.WspY - zadanyB.WspY)*LC + (zadanyC.WspY - zadanyB.WspY) * LA;
                double L = Math.Sqrt(px * px + py * py);
                if(!L)
                  {
                   px=zadanyA.WspY-zadanyC.WspY;
                   py=zadanyC.WspX-zadanyA.WspX;
                   L = Math.Sqrt(px * px + py * py);
                   if(!L) return buforek;
                  }

Oraz wywalasz warunek na początku, w wyniku czego nie znajdzie takiego punktu tylko jeżeli A=B=C.

1 użytkowników online, w tym zalogowanych: 0, gości: 1