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

Вход на сайт

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

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

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

Не получается, емаё
огромное спасибо за подробное объяснение про 3д графику на питоне, в интернете очень мало подобной информации
dobryj den, popytalas otkryt prikreplionnyj fail ctoby posmotret kak rabotaet, no mne ego ne pokazyvaet vydajet osibku. Pochemu?
Очень интересно! ии сайт крутой жалко что умирает(
У Вас число превысит максимальное число int. Можно использовать в Вашем случае uint, но лучше все переписать на double.

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

Рейтинг@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 каждое число и соответственно координаты точки, тогда все работает)) Иначе нет.
В чем может быть загвоздка?

DSimbu аватар
Опубликовано DSimbu в 19. Ноябрь 2020 - 5:51.

У Вас число превысит максимальное число int. Можно использовать в Вашем случае uint, но лучше все переписать на double.