powered by simpleCommunicator - 2.0.49     © 2025 Programmizd 02
Форумы / WinForms, .Net Framework [игнор отключен] [закрыт для гостей] / Вопрос про расчет
11 сообщений из 11, страница 1 из 1
Вопрос про расчет
    #39938895
ferzmikk
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Здравствуйте!

Есть такая задачка про координатную плоскость. Даны 2 отрезка с конкретными точками на плоскости XY. Нужно найти точку пересечения этих двух отрезков. Решение (то есть формула) нахождения точки пересечения есть.

Возьмем пример:
Начало первого отрезка: x1: 270, y1: 80
Конец первого отрезка: x2: 400, y2: 50
Начало второго отрезка: x3: 300, y3: 50
Конец второго отрезка: x4: 500, y4: 50

Видим, что второй отрезок горизонтальный и очевидно, что заданным данным есть пересечение в точке X = 400 и Y = 50.
...
Рейтинг: 0 / 0
Вопрос про расчет
    #39938897
ferzmikk
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Вначале решал в excel-ом файле и по формуле (используется частный случай, когда два отрезка не вертикальны) получаем, что отрезки пересекаются.
...
Рейтинг: 0 / 0
Вопрос про расчет
    #39938898
ferzmikk
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
...
Рейтинг: 0 / 0
Вопрос про расчет
    #39938900
ferzmikk
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Далее пишу консольное приложение на C#
C#
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
using System;

namespace Test102
{
    public struct PointStruct
    {
        public double X;
        public double Y;

        public PointStruct(double x, double y)
        {
            X = x;
            Y = y;
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            PointStruct p1 = new PointStruct(270, 80);
            PointStruct p2 = new PointStruct(400, 50);
            PointStruct p3 = new PointStruct(300, 50);
            PointStruct p4 = new PointStruct(500, 50);

            double Xa;
            double Ya;
            double A1;
            double A2;
            double b1;
            double b2;

            //Должно выполняться условие p1.x <= p2.x и p3.x <= p4.x.
            if (p2.X < p1.X)
            {
                PointStruct tmp = p1;
                p1 = p2;
                p2 = tmp;
            }

            if (p4.X < p3.X)
            {
                PointStruct tmp = p3;
                p3 = p4;
                p4 = tmp;
            }

            //Для частного случая, если оба отрезка не вертикальны
            A1 = (double)(p1.Y - p2.Y) / (p1.X - p2.X);
            A2 = (double)(p3.Y - p4.Y) / (p3.X - p4.X);
            b1 = (double)p1.Y - A1 * p1.X;
            b2 = (double)p3.Y - A2 * p3.X;

            Console.WriteLine("A1: " + A1);
            Console.WriteLine("A2: " + A2);
            Console.WriteLine("b1: " + b1);
            Console.WriteLine("b2: " + b2);

            Console.WriteLine();

            if (A1 == A2)
            {
                Console.WriteLine("Отрезки параллельны");
            }
            else
            {
                Xa = (double)(b2 - b1) / (A1 - A2);
                Ya = (double)A1 * Xa + b1;
                Console.WriteLine("Xa: " + Xa);
                Console.WriteLine("Ya: " + Ya);

                Console.WriteLine();

                if ((Xa < Math.Max(p1.X, p3.X)) || (Xa > Math.Min(p2.X, p4.X)))
                {
                    Console.WriteLine("Не пересекаются");
                }
                else
                {
                    Console.WriteLine("Пересекаются");
                }
            }                     

            Console.ReadKey();
        }
    }
}

то для такого примера выдает, что отрезки не пересекаются. Фишка в том, что Xa в контрольных значениях отображает как 400.0000000000000 6 . А в Excel как 400.
...
Рейтинг: 0 / 0
Вопрос про расчет
    #39938901
ferzmikk
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
...
Рейтинг: 0 / 0
Вопрос про расчет
    #39938902
ferzmikk
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Учитывая, что в C# иcпользуется тип данных double.

Почему так? По логике же есть пересечение отрезков. Как будто на C# неправильно считает. Как следовало правильно написать для таких случаев? Или тут надо выделять отдельный частный случай, когда один из отрезков не вертикальный, а второй - горизонтальный? Или искать другую формулу для пересечения отрезков?
...
Рейтинг: 0 / 0
Вопрос про расчет
    #39938906
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Тип double нельзя сравнивать на равно, можно на почти равно, т.е.
Код: c#
1.
abs(a-b) < epsilon
...
Рейтинг: 0 / 0
Вопрос про расчет
    #39938913
Roman Mejtes
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
потому, что надо было вычислительную математику учить
...
Рейтинг: 0 / 0
Вопрос про расчет
    #39938939
ferzmikk
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima T
Тип double нельзя сравнивать на равно, можно на почти равно, т.е.
Код: c#
1.
abs(a-b) < epsilon

Если так написать
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
...
    public static class DoubleExtensions
    {
        const double epsilon = 0.001;        

        public static bool Smaller(this double left, double right)
        {
            return Math.Abs(left - right) < epsilon;
        }               
    }
...
                //if ((Xa < Math.Max(p1.X, p3.X)) || (Math.Min(p2.X, p4.X) < Xa))
                if (DoubleExtensions.Smaller(Xa, Math.Max(p1.X, p3.X)) || DoubleExtensions.Smaller(Math.Max(p1.X, p3.X), Xa))
                {
                    Console.WriteLine("Не пересекаются");
                }
                else
                {
                    Console.WriteLine("Пересекаются");
                }
...

то теперь в консоле пишет что пересекаются отрезки.

Можно еще добавить для оператора <=
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
    public static class DoubleExtensions
    {
        ...
        public static bool LessThanOrEqualTo(this double left, double right)
        {
            return Math.Abs(left - right) <= epsilon;
        }        
    }


Как вариант можно выполнить округление до заданного знака (Math.Round(double, int32) ) и уже после этого выполнить сравнение.

В коде много подобных выражений сравнении и каждая корректировка может быть ошибочной. Чтобы их не трогать, то возможно сделать как в виде перегрузки оператора <(double left, double right) ? Понятно что в структуре PointStruct не сделаешь так, за исключением если первый входной параметр в перегрузке оператора будет как PointStruct , но тут входные параметры получаются такие как PointStruct.X и PointStruct.Y .
...
Рейтинг: 0 / 0
Вопрос про расчет
    #39939059
ferzmikk
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ferzmikk
Dima T
Тип double нельзя сравнивать на равно, можно на почти равно, т.е.
Код: c#
1.
abs(a-b) < epsilon

Если так написать
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
...
    public static class DoubleExtensions
    {
        const double epsilon = 0.001;        

        public static bool Smaller(this double left, double right)
        {
            return Math.Abs(left - right) < epsilon;
        }               
    }
...
                //if ((Xa < Math.Max(p1.X, p3.X)) || (Math.Min(p2.X, p4.X) < Xa))
                if (DoubleExtensions.Smaller(Xa, Math.Max(p1.X, p3.X)) || DoubleExtensions.Smaller(Math.Min(p2.X, p4.X), Xa))
                {
                    Console.WriteLine("Не пересекаются");
                }
                else
                {
                    Console.WriteLine("Пересекаются");
                }
...

Не правильная формула, возвращает false. Получается, что разница между двумя входящими числами больше epsilon. Тут акцент не "почти равно/не равно" между двумя числами, а сравнить между ними с определенной точностью.

Только такой следующий вариант рабочий, с использованием округлении с заданным количеством дробных разрядов в возвращаемом значении, но без использования epsilon:
Код: c#
1.
2.
3.
4.
public static bool Smaller(this double left, double right)
        {
            return Math.Round(left, 4) < Math.Round(right, 4);
        }
...
Рейтинг: 0 / 0
Вопрос про расчет
    #39939069
Roman Mejtes
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
пихать во все щели Extension методы, это плохая идея, лично я бы такое завернул.
...
Рейтинг: 0 / 0
11 сообщений из 11, страница 1 из 1
Форумы / WinForms, .Net Framework [игнор отключен] [закрыт для гостей] / Вопрос про расчет
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]