public bool ContainInArea(myVertex vertex) { if (ContainVertex(vertex,0) != -1) return true; double x_max = vertexes[0].X; for (int i = 1; i < vertexes.Count - 1; i++) if (vertexes[i].X > x_max) x_max = vertexes[i].X; x_max += 10; mySection luch = new mySection(vertex, new myVertex(x_max,vertex.Y)); int k = 0; for (int i = 0; i < vertexes.Count - 1; i++ ) { mySection section = new mySection(vertexes[i], vertexes[i + 1]); myVertex intersection = luch.Intersect(section); if (intersection != null) { k++; if (this.ContainVertex(intersection,0) != -1) i++; } } if (k>0 && k % 2 == 1) return true; else return false; }
public myVertex Intersect(mySection section) { myVertex result = null; //если вектора не коллинеарны - просто найдем координаты точки пересечения double dx = right.X - left.X; double dy = right.Y - left.Y; double sdx = section.right.X - section.left.X; double sdy = section.right.Y - section.left.Y; //проверяем вектора на коллинеарность if (dx * sdy - dy * sdx != 0) { /* * если они не коллинеарны, тогда точки пересечения отрезков либо нет, либо она одна * * x_l + a * dx = s_x_l + b * sdx | * sdy * y_l + a * dy = s_y_l + b * sdy | * sdx * * sdy*x_l + sdy*a*dx = sdy*s_x_l + sdy*b*sdx (1) * sdx*y_l + sdx*a*dy = sdx*s_y_l + sdx*b*sdy (2) * * (1)-(2) = sdy*(x_l-y_l) + a*(sdy*dx - sdx*dy) = sdy*s_x_l - sdx*s_y_l; * a = ( sdy*s_x_l - sdx*s_y_l - sdy*(x_l-y_l) )/(sdy*dx - sdx*dy); * таким образом вычислим параметр а * */ double a = (sdy * section.left.X - sdx * section.left.Y - (sdy * left.X - sdx * left.Y)) / (sdy * dx - sdx * dy); /* * x_l + a * dx = s_x_l + b * sdx | * dy * y_l + a * dy = s_y_l + b * sdy | * dx * * dy*x_l + dy*a*dx = dy*s_x_l + dy*b*sdx (1) * dx*y_l + dx*a*dy = dx*s_y_l + dx*b*sdy (2) * * (1)-(2) = dy*x_l - dx*y_l = b * (dy*sdx - dx*sdy) + (dy*s_x_l - dx*s_y_l) * b = (dy*x_l - dx*y_l - (dy*s_x_l - dx*s_y_l))/(dy*sdx - dx*sdy) * таким образом вычислим параметр b */ double b = (dy * left.X - dx * left.Y - (dy * section.left.X - dx * section.left.Y)) / (dy * sdx - dx * sdy); //если оба параметра лежат на [0;1], тогда точка пересечения отрезков - лежит на отрезков (!) if (a >= 0 && a <= 1 && b >= 0 && b <= 1) result = new myVertex(left.X + a * dx, left.Y + a * dy); } else { /* * теперь рассмоотрим случай с коллинеарными векторами * 1) dx != 0 * 2) dy != 0 * 3) а если и то и то 0, тогда это не отрезок, а точка - таких в данном случае сработает алгоритм заполнения полигона * * суть метода: * найдем какая точка из концов отсекающего отрезка наиболее приближена к правой границе со стороны левой * она и будет результатом (если конечно она попадает на [0;1] */ if (dx != 0) { double t_left = (section.left.X - left.X) / (dx); double t_right = (section.right.X - left.X) / (dx); double result_t = -1; if (t_left <= 1 && t_left > result_t) result_t = t_left; if (t_right <= 1 && t_right > result_t) result_t = t_right; //теперь проверим, а точно ли точка лежит на отрезке if (result_t != -1 && (left.Y + result_t * dy == section.left.Y || left.Y + t_right * dy == section.right.Y)) result = new myVertex(left.X + result_t * dx, left.Y + result_t * dy); } else if (dy != 0) { //всё то же, что и в предыдущем пункте, но с dy double t_left = (section.left.Y - left.Y) / (dy); double t_right = (section.right.Y - left.Y) / (dy); double result_t = -1; if (t_left <= 1 && t_left > result_t) result_t = t_left; if (t_right <= 1 && t_right > result_t) result_t = t_right; //теперь проверим, а точно ли точка лежит на отрезке if (result_t != -1 && (left.X + result_t * dx == section.left.X || left.X + t_right * dx == section.right.X)) result = new myVertex(left.X + result_t * dx, left.Y + result_t * dy); } else throw new Exception("Ошибка при поиске пересечения отрезков:\ndx == dy == 0"); } return result; }
public bool Intersect(mySection section) { for (int i = 1; i < vertexes.Count; i++) { myVertex intersection = new mySection(vertexes[i - 1], vertexes[i]).Intersect(section); if ( intersection != null) { if (!intersection.Equals(section.Left)) return true; else continue; } } return false; }
private myPolygon GetIntersectionWith(myPolygon polygon) { //создадим результирующий многоугольник myPolygon result = new myPolygon(); for (int i = 0; i < vertexes.Count - 1; i++) { //добавим в него текущую вершину result.vertexes.Add(vertexes[i]); //создадим ребро, из текущей и следующей вершины mySection i_section = new mySection(vertexes[i], vertexes[i + 1]); //а так же список добавляемых вершин List<myVertex> vertexes_to_add = new List<myVertex>(); //будем искать пересечения for (int j = 0; j < polygon.vertexes.Count - 1; j++) { //текущее ребро во втором многоугольнике mySection j_section = new mySection(polygon.vertexes[j], polygon.vertexes[j + 1]); //если есть пересечение - добавим в список myVertex intersection = i_section.Intersect(j_section); if (intersection != null && result.ContainVertex(intersection,0) == -1 && !vertexes_to_add.Contains(intersection)) vertexes_to_add.Add(intersection); } //теперь нужно отсортировать список по удалению от начала отрезка //параллельно добавляя их в многоугольник-результат for (int j = 0; j < vertexes_to_add.Count; j++) { double min_distance = result.vertexes[result.vertexes.Count - 1].DistanceTo(vertexes_to_add[j]); for (int k = j + 1; k < vertexes_to_add.Count; k++) { double distance = result.vertexes[result.vertexes.Count - 1].DistanceTo(vertexes_to_add[k]); if (distance < min_distance) { myVertex temp = vertexes_to_add[j]; vertexes_to_add[j] = vertexes_to_add[k]; vertexes_to_add[k] = temp; min_distance = distance; } } result.vertexes.Add(vertexes_to_add[j]); } } //не забудем добавить самую первую точку result.vertexes.Add(result.vertexes[0]); return result; }
private void MainForm_MouseDown(object sender, MouseEventArgs e) { button1.Enabled = true; if (painted) { graphics.Clear(Color.White); first_ended = second_ended = painted = false; first = null; second = null; checkBox1.Checked = false; checkBox2.Checked = false; checkBox4.Checked = false; } if (!first_ended && e.Button == System.Windows.Forms.MouseButtons.Left) { if (first == null) first = new myPolygon(new myVertex(e.X, e.Y), graphics, new Pen(Color.Red, 2)); else { mySection attention = new mySection(first.GetLastVertex(), new myVertex(e.X, e.Y)); if (first.Intersect(attention)) MessageBox.Show("Самопересечения не допускаются. Будьте внимательнее!"); else if (!first.AddVertex(new myVertex(e.X, e.Y), graphics, new Pen(Color.Red, 2))) { first_ended = true; checkBox1.Checked = true; } } } else if (!second_ended && e.Button == System.Windows.Forms.MouseButtons.Right) { if (second == null) second = new myPolygon(new myVertex(e.X, e.Y), graphics, new Pen(Color.Green, 2)); else { mySection attention = new mySection(second.GetLastVertex(), new myVertex(e.X, e.Y)); if (second.Intersect(attention)) MessageBox.Show("Самопересечения не допускаются. Будьте внимательнее!"); else if (!second.AddVertex(new myVertex(e.X, e.Y), graphics, new Pen(Color.Green, 2))) { second_ended = true; checkBox2.Checked = true; } } } else { graphics.Clear(Color.White); if (first_ended && second_ended) first.GetUnionWith(second, graphics, new Pen(Color.Brown,3), checkBox4.Checked); painted = true; MessageBox.Show("Для того, чтобы выполнить процедуру с новыми многоугольниками\n кликните мышкой по введенным многоугольникам."); } }