Есть ли способ написать условие для обнаружения, если точка принадлежит области более коротким способом? - PullRequest
1 голос
/ 19 октября 2019

Я должен определить, принадлежит ли точка данной области (изображение прикреплено). Условие, которое я написал, кажется слишком длинным. Я почти уверен, что есть способ написать это более простым способом, но я просто не знаю как. Единственный успешный код из всех, что я пробовал, представлен ниже.

float x, y;   int a = 2, b = 1, r = 3;
printf("x = ", x);
scanf ("%f", &x);
printf("y = ", y);
scanf ("%f", &y);
if ( ((pow((x-a), 2) + pow((y-b), 2) <= pow(r,2)) && ((pow((x-a), 2) + pow((y-b),2) >= 1)) && (x <= 2) && (x >= -3) && (y >= -1) && (y <= 4)) || fabs(x) <= 1 && fabs(y) <=1 || (y == x+2 && y >= -1 && x >= -3))
    {
     printf ("Belongs to the area");
    }
else
    {
     printf ("Doesn't belong to the area");
    }

Вывод правильный, поэтому я ожидаю, что он будет таким же.

Ответы [ 4 ]

3 голосов
/ 19 октября 2019

Может быть, это:

Areas

  1. (необязательно) Если он находится за пределами белого прямоугольника, вернуть false.

  2. Если он в красном треугольнике, вернуть true.

  3. Если он в желтом круге, вернуть false.

  4. Если он находится в зеленом прямоугольнике, вернуть true.

  5. Если он находится за пределами розового круга, вернуть false.

  6. Если этовнутри синего прямоугольника верните true.

  7. Если ничего из вышеперечисленного не возвращается, верните false.

Первый шаг необязателен для сохранениянесколько проверок. Это улучшило бы производительность, если бы значительная часть ваших контрольных точек находилась далеко от вашего района.

Пример кода (непроверенный, на самом деле не парень с C):

bool point_in_rectangle(double x, double y, double min_x, double max_x, double min_y, double max_y) {
    if (x < min_x) return false;
    if (x > max_x) return false;
    if (y < min_y) return false;
    if (y > max_y) return false;
    return true;
}

// "easy" means it's properly aligned and has height equal to width
bool point_in_easy_triangle(double x, double y, double min_x, double max_x, double base_y) {
    if (x < min_x) return false;
    if (x > max_x) return false;
    if (y < base_y) return false;
    if (x - min_x < y - base_y) return false;
    return true;
}

bool point_in_circle(double x, double y, double center_x, double center_y, double radius) {
    double distance_x = x - center_x;
    double distance_y = y - center_y;
    double distance_squared = distance_x * distance_x + distance_y * distance_y;
    return distance_squared < (radius * radius);
}

bool point_in_my_area(double x, double y) {
    if (!point_in_rectangle(x, y, -3, 2, -1, 4)) return false;
    // etc...
}
3 голосов
/ 19 октября 2019

Я бы не беспокоился о длине как таковой и беспокоился бы о ясности и удобстве обслуживания,

С этой целью я бы описал требование как

  • выше линии y = -1
  • слева от линии x = 2
  • вне радиуса окружности 1 @ (2,1)

И либо

  • внутри большего круга
  • ниже диагональной линии

Затем выразите эти условия в функциях (используйте вход / выход изпроверяйте окружность!) и напишите свой if с этими функциями.

—-

В более общем смысле такой подход является основой конструктивной плоской геометрии. Вам понадобятся следующие термины поиска: «конструктивная геометрия твердого тела» и «функции расстояния со знаком».

2 голосов
/ 19 октября 2019

Это зависит от вашей конечной цели и от того, насколько усердно вы хотите работать.

Это правда, что у вас есть выражение «слишком длинное». Я сомневаюсь, что вы можете существенно сократить его, но вы, безусловно, можете уточнить это, и в то же время, возможно, упростить это. Некоторые предложения, в порядке возрастания сложности, общности, но и сложности:

  1. Разбейте это огромное выражение на несколько строк, чтобы читателю было легче следовать (или сделать возможнымчитатель с узким окном даже на см. !). Затем вы можете поместить комментарий рядом с каждой частью выражения, чтобы объяснить, что он делает.
  2. Разбейте различные части выражения на совершенно отдельные функции. Таким образом, имена, которые вы выбираете для функций, могут одновременно являться документами.
  3. Сделайте эти отдельные функции общими, чтобы они могли работать с произвольными фигурами. (То есть вместо функции in_circle(x, y), которая проверяет, находится ли точка x,y внутри того круга, который вас интересует, напишите что-то более похожее на in_circle(x, y, x0, y0, r), которая проверяет, находится ли точка x,y внутри окружности с центромв x0,y0 с радиусом r.)
  4. Реализуйте схему для описания произвольных фигур (возможно, с подробностями, считываемыми из файла данных), так что нет ничего об одной конкретной области, встроенной в программу.
  5. Реализация полностью универсальной функции in_polygon, которая позволяет описывать многоугольник только на основе отрезков, составляющих его окружность, а не в виде набора простых, перекрывающихся подполигонов. (Это, очевидно, потребует использования совершенно другого алгоритма.)
1 голос
/ 19 октября 2019

Разбить задачу на под-тесты более простых форм - вот путь.

Проблемы с краями: "внешний" тест с использованием !inside() является проблемой, когда точка находится на краю формы.

Чтобы использовать тест в форме формы как "внутри", так и "снаружи", верните 1 из 3 значений

int test_rectangle(double x0, double y0, double x1, double y1, double px, double py) {
  if (x1 < x0) {
    double t = x1; x1 = x0; x0 = t;
  } 
  if (y1 < y0) {
    double t = y1; y1 = y0; y0 = t;
  } 
  if (px < x0 || px > x1 || py < y0 || py > y1) return 1; // outside
  if (px > x0 && px < x1 && py > y0 && py < y1) return -1; // inside
  return 0; // edge
}

Тест по кругу более сложный. Хотя стандартная функция hypot() может обеспечить более точные результаты, чем sqrt(x*x + y*y), вычитания и hypot() могут вызвать ошибку округления, при которой вопросы выбирают результаты случая ребра.

int test_circle(double x, double y, double radius, double px, double py) {
  double hyp = hypot(x - px, y - py);
  if (hyp > radius) return 1;  // outside
  if (hyp < radius) return -1; // inside
  return 0;  // edge
}
...