Уроки, алгоритмы, программы, примеры

Вход на сайт

Материалы по разделам

Построения
на плоскости (2D)
Графика
в пространстве (3D)
Вычислительная
геометрия
Физическое
моделирование
Фрактальная
графика

Новые комментарии

torrvic, возможно, Вам нужно добавить -lGLU
Извините за тупой вопрос. У меня при сборке Вашего примера выходит ошибка: "undefined reference to gluLookAt". Не могу найти в какой библиотеке находится эта функция. У меня задано: -lGL -lglut ... Искал в /usr/lib таким образом: nm lib*so* | grep...
Здравствуйте. Спасибо за проект. У меня вопрос, по какой причине определение принадлежности точки многоугольнику работает некорректно, если координаты из больших чисел состоят, например: int[] vertex = new int[] {...
Сейчас проверила нашла причину не запускания // Создание контекста воспроизведения OpenGL и привязка его к панели на форме OpenGLControl1:=TOpenGLControl.Create(Self); with OpenGLControl1 do begin Name:='OpenGLControl1'; //вот тут...
Ну..кажется что то пошло не так http://pp.usera...

Счетчики и рейтинг

Рейтинг@Mail.ru
Скриншот к примеру
Среда программирования: 
Visual Studio 2015

Перед нами стоит следующая задача:
Создать класс многоугольника и обеспечить его методом проверки попадания точки в этот многоугольник.

Программа рисует один многоугольник и реагирует на щелчок мыши. Если щелчок был произведен по многоугольнику, меняем его цвет.

Код программы: 

Класс Polygon представляет собой многоугольник. Он служит для хранения вершин, отрисовки себя на Graphics и определения попадания точки внутрь.

Описание работы методов edgeType(Point, Point, Point) и pointInPolygon(Point) смотрите в статье Метод трассировки лучом.

Polygon:

using System;
using System.Drawing;
using System.Drawing.Drawing2D;
 
namespace TanyaLab
{
    class Polygon
    {
        private Point[] points; //вершины многоугольника
        private GraphicsPath path; //служит для отрисовки многоугольника
        private int minX, maxX, minY, maxY;
 
        public Polygon(int[] points)
        {
            if (points.Length < 6 || points.Length % 2 == 1)
                throw new Exception();
 
            minX = minY = int.MaxValue;
            maxX = maxY = int.MinValue;
 
            this.points = new Point[points.Length / 2];
            for (int i = 0; i<points.Length; i += 2) {
                minX = Math.Min(minX, points[i]);
                maxX = Math.Max(maxX, points[i]);
                minY = Math.Min(minY, points[i + 1]);
                maxY = Math.Max(maxY, points[i + 1]);
 
                this.points[i / 2] = new Point(points[i], points[i + 1]);
            }
 
            path = new GraphicsPath();
        }
 
        public Point[] getPoints()
        {
            return points;
        }
 
        public void fill(Graphics g, SolidBrush brush, float translateX, float translateY, float scale) //отрисовка многоугольника в точке (translateX, translateY) и масштабом scale
        {
            path.Reset();
 
            float lastX = (points[0].X - minX) * scale + translateX;
            float lastY = (points[0].Y - minY) * scale + translateY;
 
            for (int i = 1; i < points.Length; i++)
            {
                float x = (points[i].X - minX) * scale + translateX;
                float y = (points[i].Y - minY) * scale + translateY;
 
                path.AddLine(lastX, lastY, x, y);
 
                lastX = x;
                lastY = y;
            }
 
            g.FillPath(brush, path);
        }
 
        private PointOverEdge classify(Point p, Point v, Point w) //положение точки p относительно отрезка vw
        {
            //коэффициенты уравнения прямой
            int a = v.Y - w.Y;
            int b = w.X - v.X;
            int c = v.X * w.Y - w.X * v.Y;
 
            //подставим точку в уравнение прямой
            int f = a * p.X + b * p.Y + c;
            if (f > 0)
                return PointOverEdge.RIGHT; //точка лежит справа от отрезка
            if (f < 0)
                return PointOverEdge.LEFT; //слева от отрезка
 
            int minX = Math.Min(v.X, w.X);
            int maxX = Math.Max(v.X, w.X);
            int minY = Math.Min(v.Y, w.Y);
            int maxY = Math.Max(v.Y, w.Y);
 
            if (minX <= p.X && p.X <= maxX && minY <= p.Y && p.Y <= maxY)
                return PointOverEdge.BETWEEN; //точка лежит на отрезке
            return PointOverEdge.OUTSIDE; //точка лежит на прямой, но не на отрезке
        }
 
        private EdgeType edgeType(Point a, Point v, Point w) //тип ребра vw для точки a
        {
            switch (classify(a, v, w))
            {
                case PointOverEdge.LEFT:
                    return ((v.Y < a.Y) && (a.Y <= w.Y)) ? EdgeType.CROSSING : EdgeType.INESSENTIAL;
                case PointOverEdge.RIGHT:
                    return ((w.Y < a.Y) && (a.Y <= v.Y)) ? EdgeType.CROSSING : EdgeType.INESSENTIAL;
                case PointOverEdge.BETWEEN:
                    return EdgeType.TOUCHING;
                default:
                    return EdgeType.INESSENTIAL;
            }
        }
 
        public PointInPolygon pointInPolygon(Point a) //положение точки в многоугольнике
        {
            bool parity = true;
            for (int i = 0; i < points.Length; i++)
            {
                Point v = points[i];
                Point w = points[(i + 1) % points.Length];
 
                switch (edgeType(a, v, w))
                {
                    case EdgeType.TOUCHING:
                        return PointInPolygon.BOUNDARY;
                    case EdgeType.CROSSING:
                        parity = !parity;
                        break;
                }
            }
 
            return parity ? PointInPolygon.OUTSIDE : PointInPolygon.INSIDE;
        }
 
        public int MinX()
        {
            return minX;
        }
 
        public int MaxX()
        {
            return maxX;
        }
 
        public int MinY()
        {
            return minY;
        }
 
        public int MaxY()
        {
            return maxY;
        }
 
        public int width() //ширина
        {
            return maxX - minX;
        }
 
        public int height() //высота
        {
            return maxY - minY;
        }
 
        public enum PointInPolygon { INSIDE, OUTSIDE, BOUNDARY } //положение точки в многоугольнике
 
        private enum EdgeType { TOUCHING, CROSSING, INESSENTIAL } //положение ребра
 
        private enum PointOverEdge { LEFT, RIGHT, BETWEEN, OUTSIDE } //положение точки относительно отрезка
 
    }
}

Form1:

using System;
using System.Drawing;
using System.Windows.Forms;
 
namespace TanyaLab
{
    public partial class Form1 : Form
    {
        private Bitmap bitmap;
        private Graphics g;
 
        private int width, height; //ширина и высота области рисования
        private float scale; //коэффициент масштабирования
        private float translateX, translateY; //смещение по х и у
 
        private SolidBrush brush; //служит для закрашивания многоугольника
        private Random random; //служит для выбора случайных цветов
 
        private Polygon polygon;
 
        public Form1()
        {
            InitializeComponent();
        }
 
        private void draw()
        {
            g.Clear(Color.White);
            polygon.fill(g, brush, translateX, translateY, scale);
        }
 
        private void pictureBox_MouseClick(object sender, MouseEventArgs e)
        {
            //так как наш Polygon проверяет попадания без учета translate и scale, преобразуем х и у координаты
            float x = (e.X - translateX) / scale + polygon.MinX();
            float y = (e.Y - translateY) / scale + polygon.MinY();
 
            Point p = new Point((int)x, (int)y);
 
            //изменяем цвет многоугольника при попадании
            if (touch(polygon, p))
            {
                brush.Color = randomColor();
                draw();
                pictureBox.Invalidate();
            }
        }
 
        private bool touch(Polygon polygon, Point a) //проверка попадания точки в Polygon
        {
            Polygon.PointInPolygon touch = polygon.pointInPolygon(a);
            return touch == Polygon.PointInPolygon.INSIDE || touch == Polygon.PointInPolygon.BOUNDARY;
        }
 
        private Color randomColor() //возвращает случайный цвет
        {
            if (random == null)
                random = new Random();
            return Color.FromArgb(random.Next(25, 225), random.Next(25, 225), random.Next(25, 225)); //случайный цвет
        }
 
        private void Form1_Load(object sender, EventArgs e)
        {
            bitmap = new Bitmap(pictureBox.Width, pictureBox.Height);
            pictureBox.Image = bitmap;
 
            g = Graphics.FromImage(bitmap);
            g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
 
            width = bitmap.Width;
            height = bitmap.Height;
 
            //выбираем случайный цвет закрашивания
            brush = new SolidBrush(randomColor());
 
            //создаем многоугольник
            int[] vertex = new int[]
            {
                370, 279,
                160, 106,
                262, 390,
                61, 433,
                358, 530,
                160, 869,
                412, 624,
                439, 942,
                528, 601,
                672, 797,
                598, 425,
                673, 276,
                427, 420,
                660, 124,
                358, 356,
                507, 95
            }; //х и y координаты многоугольника против часовой стрелки
            polygon = new Polygon(vertex);
 
            //растягимаем многоугольник на всю область рисования и устанавливаем в центре
            scale = Math.Min(pictureBox.Width / (float)polygon.width(), pictureBox.Height / (float)polygon.height());
            translateX = (pictureBox.Width - polygon.width() * scale) / 2;
            translateY = (pictureBox.Height - polygon.height() * scale) / 2;
 
            draw();
        }
 
 
    }
}

Прикрепленный файлРазмер
point_in_polygon.zip61.49 кб

Комментарии

overdose аватар
Опубликовано overdose в 21. Июнь 2017 - 19:35.

Здравствуйте.
Спасибо за проект.

У меня вопрос, по какой причине определение принадлежности точки многоугольнику работает некорректно, если координаты из больших чисел состоят, например:

int[] vertex = new int[]
{
181793, 1306,
200345, 8580,
222066, 11229,
232582, 27101,
217603, 44974,
221515, 70963,
230365, 83562,
236273, 97545,
}; //х и y координаты многоугольника против часовой стрелки

Отрисовка на форме не используется, просто проверяется принадлежность точки.
С такими координатами не работает.
Если разделить на 1000 каждое число и соответственно координаты точки, тогда все работает)) Иначе нет.
В чем может быть загвоздка?