Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Общие вопросы по .NET и C# > Как найти отрезок перпендикулярный данной прямой?


Автор: GenkaRu 4.5.2010, 01:16
 Для чего мне это нужно:  На чертеже изображена стена дома в виде прямой, определённой двумя точками, она содержит две стороны (могут принадлежать разным комнатам), содержать разную отделку и т.д. Необходимо реализовать подсветку конкретной стороны по наведению курсора, ну и выбор по клику, ну и подсветку при выборе стороны стены в списке объектов, чтобы пользователь видел какую конкретно сторону стенки он будет модифицировать.

  Для варианта подсветки при выборе стороны в списке объетов я пробовал искать отрезок - перпендикуляр через середину стены, чтобы потом через нужную его конечную точку проводить линию "подсветки", но не получилось его ограничить (скажем 3мя пикселами).
 
 Ещё как вариант можно было бы переделать алгоритм определения принадлежности курсора прямой для определения принадлежности курсора заданному корридору в те же 3 пиксела, но тоже не выходит пока.. Этот алгоритм я скопировал отсюда: 
http://forum.sources.ru/index.php?showtopic=211642&view=showall

он такой:

           
Код

 bool online;
            int sqrl12, hlfl12;
            
            int x = pointerPosition.X, x1 = wallPosition.Point1.X,
                x2 = wallPosition.Point2.X, y = pointerPosition.Y,
                y1 = wallPosition.Point1.Y, y2 = wallPosition.Point2.Y;
            
            sqrl12 = (int)(Math.Pow((x2-x1), 2) + Math.Pow((y2-y1),2));
            hlfl12 = (int)Math.Truncate(Math.Sqrt(sqrl12)/2);

             online = (Math.Abs((y1-y2)*(x-x1)+(x2-x1)*(y-y1)) <= hlfl12) &&

            (Math.Abs((2*x-x1-x2)*(x2-x1)+(2*y-y1-y2)*(y2-y1)) <= sqrl12);
            return online;


 Если кто-то знает хорошие решения или наставит на путь истинный в поисках оных буду очень признателен!

Автор: GenkaRu 4.5.2010, 16:10
По идее проблему должна решить следующая последовательность действий: 1) Из уравнения прямой, перпендикулярной данной прямой, получить координаты точки их пересечения 2) Проверить лежит ли точка пересечения на вожделенном отрезке 3) Проверить в какой полуплоскости относительно нашего отрезка был сделан клик, и определить с какой стороны рисовать подсветку. Код получился вот такой, вызывается по MouseMove:

Код

public int WallSideHighlighted(Wall wall, Point pointer)
        {
            double x, y; //Координаты точки пересечения перпендикуляра и отрезка (нашей стены)
            double x1 = wall.Position.Point1.X, x2=wall.Position.Point2.X, y1=wall.Position.Point1.Y, y2=wall.Position.Point2.Y, //координаты      точек отрезка
                x3 = pointer.X, y3 = pointer.Y; //Координаты курсора
            double length = 0;
            int distance = 3; // граница коридора
            bool onSegment;     //лежит ли точка пересечения перпендикуляра на отрезке
            if(x1 == x2)  //случай с вертикальным отрезком
            {
                x = x2;
                y = y3;

                length = Math.Abs(x3 - x2);
                onSegment = (Math.Abs(y2 - y1) == (Math.Abs(y3 - y1) + Math.Abs(y2 - y3)));
            }
            else if(y1 == y2)  //с горизонтальным
            {
                x = x3;
                y = y2;

                length = Math.Abs(y3 - y1);
                onSegment = (Math.Abs(x2 - x1) == Math.Abs(x1 - x3) + Math.Abs(x2 - x3));
            }
            else // общий случай с как попало лежащим отрезком
            {
                x = ((x2 - x1)/(y2 - y1)*x3 + y3 - y1 + ((x1*y2) - (x1*y1))/(x2 - x1))/
                    ((y2 - y1)/(x2 - x1) + (x1 - x2)/(y2 - y1));
                y = x*(y2 - y1)/(x2 - x1) - ((x1*y2) - (x1*y1))/(x2 - x1) + y1;         //координаты точки пересечения прямой, на которой лежит отрезок, и опущенного на неё перпендикуляра

                length = (int)Math.Sqrt(Math.Pow((x3 - x), 2)+Math.Pow((y3-y),2));   //расстояние от точки клика до точки пересечения

                onSegment = (int)Math.Sqrt(Math.Pow((x2 - x1), 2) + Math.Pow((y2 - y1), 2)) ==   //лежит ли точка пересечения на отрезке
                            (int)Math.Sqrt(Math.Pow((x1 - x), 2) + Math.Pow((y1 - y), 2)) +
                            (int)Math.Sqrt(Math.Pow((x2 - x), 2) + Math.Pow((y2 - y), 2));
            }
            if(length<=distance && onSegment)
            {
                MessageBox.Show("Huraa", "The pointer is within the corridor");
            }

            return 0;
        }


Проблема в том, что перпендикуляр строится избирательно, для большинства прямых - неверно, уходит куда-то под уклоном к ним за пределы экрана, но к некоторым строится верно. Баловство со знаками приводило к нужным результатам для одних прямых, и к неприемлемым к другим. Особенно, кажется, проблемны прямые близкие к вертикальным или горизонтальным, но таковыми не являющиеся. Буду пока пересчитывать, либо есть ошибка в вычислениях, либо чего-то не учёл..

Автор: GenkaRu 4.5.2010, 17:11
Ураа, координаты надо считать вот так, sweet Mary mother of Jesus оно работает, всем спасибо!))

Код

x = ((x1 - x2) * x3 / (y2 - y1) - (y2 - y1) * x1 / (x2 - x1) + y1 - y3 ) /
                    ((x1 - x2) / (y2 - y1) - (y2 - y1) / (x2 - x1));
                
 y = (x1 - x2)*x/(y2 - y1) - (x1 - x2)*x3/(y2 - y1) + y3;

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)