2008-09-25 13 views
36

Mam linię, którą rysuję w oknie i pozwalam użytkownikowi ją przeciągnąć. Tak więc, moja linia jest określona przez dwa punkty: (x1, y1) i (x2, y2). Ale teraz chciałbym narysować "czapki" na końcu mojej linii, czyli krótkie prostopadłe linie na każdym z moich punktów końcowych. Czapki powinny mieć długość N pikseli.Jak znaleźć punkt w danej prostopadłej odległości od linii?

Tak więc, aby narysować linię "czapki" w punkcie końcowym (x1, y1), muszę znaleźć dwa punkty, które tworzą prostopadłą linię i gdzie każdy z jej punktów znajduje się N/2 piksele od punktu (x1 , y1).

Jak więc obliczyć punkt (x3, y3), biorąc pod uwagę, że musi być na prostopadłej odległości N/2 od punktu końcowego (x1, y1) znanej linii, tj. Linii zdefiniowanej przez (x1 , y1) i (x2, y2)?

+0

Aby uzyskać szczegółowe, opracowane rozwiązanie, [patrz tutaj] (http://stackoverflow.com/a/17195324/183120). – legends2k

Odpowiedz

72

Musisz obliczyć wektor jednostkowy, który jest prostopadły do ​​segmentu linii. Unikaj obliczania nachylenia, ponieważ może to prowadzić do dzielenia przez zero błędów.

dx = x1-x2 
dy = y1-y2 
dist = sqrt(dx*dx + dy*dy) 
dx /= dist 
dy /= dist 
x3 = x1 + (N/2)*dy 
y3 = y1 - (N/2)*dx 
x4 = x1 - (N/2)*dy 
y4 = y1 + (N/2)*dx 
+1

Ciągle myślę, że musi istnieć sposób na uniknięcie tego paskudnego sqrt, prawdopodobnie przy użyciu Linii Breshenham, ale nie mogę o tym myśleć. –

+2

Myślę, że masz błąd znakowy w swoich obliczeniach lub punktach 3 i 4. Użyj (+ - - +) lub (- + + -) w ostatnich czterech liniach, nie? – dmckee

+6

Dzięki, to działa świetnie! – AZDean

5

Wystarczy ocenić prostopadły versor i pomnożyć przez N/2

vx = x2-x1 
vy = y2-y1 
len = sqrt(vx*vx + vy*vy) 
ux = -vy/len 
uy = vx/len 

x3 = x1 + N/2 * ux 
Y3 = y1 + N/2 * uy 

x4 = x1 - N/2 * ux 
Y4 = y1 - N/2 * uy 
1

Jeśli chcesz uniknąć sqrt, wykonaj następujące czynności:

in: line_length, cap_length, rotation, position of line centre 

define points: 
    tl (-line_length/2, cap_length) 
    tr (line_length/2, cap_length) 
    bl (-line_length/2, -cap_length) 
    br (line_length/2, -cap_length) 

rotate the four points by 'rotation' 
offset four points by 'position' 

drawline (midpoint tl,bl to midpoint tr,br) 
drawline (tl to bl) 
drawline (tr to br) 
3

Ponieważ wektory z 2 do 1 i 1 do 3 są prostopadłe, ich iloczyn jest 0.

To pozostawia ci dwie niewiadome: x od 1 do 3 (x 1 3) i y od 1 do 3 (y13)

Użyj twierdzenia Pitagorasa, aby uzyskać inne równanie dla tych niewiadomych.

rozwiązać za każdy nieznany przez podstawienie ...

wymaga kwadratury i unsquaring, więc tracisz znak związany ze swoimi równań.

Aby określić znak, należy rozważyć:

while x21 is negative, y13 will be positive 
while x21 is positive, y13 will be negative 
while y21 is positive, x13 will be positive 
while y21 is negative, x13 will be negative 

znane: Punkt 1: X1, Y1

znana: Punkt 2: x2, y2

x21 = x1 - x2 
y21 = y1 - y2 

znane: odległość | 1 -> 3 | N/2

Równanie: Pitagorasa

x13^2 + y13^2 = |1->3|^2 
x13^2 + y13^2 = (N/2)^2 

Znane angle 2-1-3: kątowe

wektory 2-> 1 i 1> 3 są prostopadłe

2-> 1 kropka 1-> 3 0

równanie b: iloczyn skalarny = 0

x21*x13 + y21*y13 = 2->1 dot 1->3 
x21*x13 + y21*y13 = 0 

stosunek b/X13 i Y13:

x21*x13 = -y21*y13 
x13 = -(y21/x21)y13 

x13 = -phi*y13 

Równanie: rozwiązane za Y13 w stosunku

plug x13 into a 
phi^2*y13^2 + y13^2 = |1->3|^2 

    factor out y13 
y13^2 * (phi^2 + 1) = 

    plug in phi 
y13^2 * (y21^2/x21^2 + 1) = 

    multiply both sides by x21^2 
y13^2 * (y21^2 + x21^2) = |1->3|^2 * x21^2 

    plug in Pythagorean theorem of 2->1 
y13^2 * |2->1|^2 = |1->3|^2 * x21^2 

    take square root of both sides 
y13 * |2->1| = |1->3| * x21 

    divide both sides by the length of 1->2 
y13 = (|1->3|/|2->1|) *x21 

    lets call the ratio of 1->3 to 2->1 lengths psi 
y13 = psi * x21 

    check the signs 
    when x21 is negative, y13 will be positive 
    when x21 is positive, y13 will be negative 

y13 = -psi * x21 

Równanie: rozwiązane za X13 w stosunku

plug y13 into a 
x13^2 + x13^2/phi^2 = |1->3|^2 

    factor out x13 
x13^2 * (1 + 1/phi^2) = 

    plug in phi 
x13^2 * (1 + x21^2/y21^2) = 

    multiply both sides by y21^2 
x13^2 * (y21^2 + x21^2) = |1->3|^2 * y21^2 

    plug in Pythagorean theorem of 2->1 
x13^2 * |2->1|^2 = |1->3|^2 * y21^2 

    take square root of both sides 
x13 * |2->1| = |1->3| * y21 

    divide both sides by the length of 2->1 
x13 = (|1->3|/|2->1|) *y21 

    lets call the ratio of |1->3| to |2->1| psi 
x13 = psi * y21 

    check the signs 
    when y21 is negative, x13 will be negative 
    when y21 is positive, x13 will be negative 

x13 = psi * y21 

skondensować

x21 = x1 - x2 
y21 = y1 - y2 

|2->1| = sqrt(x21^2 + y^21^2) 
|1->3| = N/2 

psi = |1->3|/|2->1| 

y13 = -psi * x21 
x13 = psi * y21 

Zwykle nie zrobiłbym tego, ale rozwiązałem go w pracy i pomyślałem, że dokładne wyjaśnienie pomoże mi utrwalić moją wiedzę.

Powiązane problemy