GDI - Выбрать мышкой нарисованную фигуру
Короче нужно нечто аналогичное для нарисованной фигуры (например линии)
Например на форме нарисованно 5 линий, мне нужно мышкой выделить вторую чтоб удалить.
Все линии сидят в массиве.
Получается нужно проверить каждый пиксель всех линий? А если учесть что линия шириной 1 пиксель
то в нее трудновато попасть мышкой... такую линию нужно проверять и по соседним пикселам.
Хорошо если это линия или окружность, а если кривая - где брать формулу по которой GDI её нарисовал?
Может кто сталкивался с такой фигней и знает более простой подход ?... поделитесь идеей если не сталкивались!
всё просто подставляешь свою координаты в уравнение прямой, решаешь уравнение (знаю, что для программиста это звучит жутко, но по ссылке на пальцах показано - как) и сравниваешь результат с 0 (+- допуск).
С произольной кривой всё сложнее. Тут недурно было бы спросить на gamedev'е - они такими глупостями любят заниматься. Я бы разбил всё пространство на квадраты, каждый квадрат ещё на квадраты и так далее, пока размерз этого квадрата не будет равен допуску. И проверял бы 9 соседних квадратов в районе клика мыши. К сожалению, индексы в этом случае всё равно придётся где-то хранить, тоесть в грубом приближении, каждый мелкий квадратик содержит в себе список прямых, которые через него проходят.
Именно поэтому во всевозможных векторных редакторах нельзя нарисовать произвольную загаглуину, а в каком-нибудь фотошопе выделение происходит по интенсивности цветовой заливки. В том же иллюстраторе, ты можешь изобразить прямоугольник, эллипс, прямую, кривую, но все они подчиняются строгим математическим правилам, зная которые ты можешь расчитать, как и в случае с прямой, лежит ли точка на кривой или нет.
Думаю, что когда встаёт задача аналогичная твоей, строятся дополнительные, невидимые прямые отрезки, загрублённой формы, на основе которых и осуществляется проверка. Так, например, при столкновении двух 3D объектов просчитываются столкновения кубов или сфер, вписанных в них, а не каждого полигона этой модели. :)
С линией
С произольной кривой всё сложнее. Тут недурно было бы спросить на gamedev'е - они такими глупостями любят заниматься. Я бы разбил всё пространство на квадраты, каждый квадрат ещё на квадраты и так далее, пока размерз этого квадрата не будет равен допуску. И проверял бы 9 соседних квадратов в районе клика мыши. К сожалению, индексы в этом случае всё равно придётся где-то хранить, тоесть в грубом приближении, каждый мелкий квадратик содержит в себе список прямых, которые через него проходят.
Именно поэтому во всевозможных векторных редакторах нельзя нарисовать произвольную загаглуину, а в каком-нибудь фотошопе выделение происходит по интенсивности цветовой заливки. В том же иллюстраторе, ты можешь изобразить прямоугольник, эллипс, прямую, кривую, но все они подчиняются строгим математическим правилам, зная которые ты можешь расчитать, как и в случае с прямой, лежит ли точка на кривой или нет.
Думаю, что когда встаёт задача аналогичная твоей, строятся дополнительные, невидимые прямые отрезки, загрублённой формы, на основе которых и осуществляется проверка. Так, например, при столкновении двух 3D объектов просчитываются столкновения кубов или сфер, вписанных в них, а не каждого полигона этой модели. :)
Как-то все очень сложно. Линии рисуются по характеристикам. Стереть линию - это значит нарисовать ее цветом фона. У каждого элемента должен быть ID, изначально заданный в неком массиве, например. Определить, попадает ли точка на линию в определениях растровой графики весьма проблематично. Поэтому все Ваше рисование изначально должно реализовывать идеологию векторов.
Цитата: albeoris
Думаю, что когда встаёт задача аналогичная твоей, строятся дополнительные, невидимые прямые отрезки, загрублённой формы, на основе которых и осуществляется проверка. Так, например, при столкновении двух 3D объектов просчитываются столкновения кубов или сфер, вписанных в них, а не каждого полигона этой модели. :)
Совершенно верно. Т.н. "апроксимация сложной поверхности". Задача, на самом деле, выходит за уровень "hello world". А для каких целей Вам это нужно, если не секрет?
Код:
Public Class Form1
Dim _Lines(9) As s_Line
Private Structure s_Line
Dim P As Pen
Dim X1 As Single
Dim X2 As Single
Dim Y1 As Single
Dim Y2 As Single
End Structure
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Dim R As New Random()
For i As Byte = 0 To _Lines.Length - 1
With _Lines(i)
.P = New Pen(Color.Green, 1)
.X1 = R.Next(0, 500)
.X2 = R.Next(0, 500)
.Y1 = R.Next(0, 500)
.Y2 = R.Next(0, 500)
End With
Next
End Sub
Private Sub Form1_MouseClick(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseClick
For i As Byte = 0 To _Lines.Length - 1
With _Lines(i)
.P = Pens.Green
' вычисляем формулу линии
Dim m, b As Single
m = (.Y2 - .Y1) / (.X2 - .X1)
b = .Y1 - (m * .X1)
If Math.Max(CInt(e.X * m + b), e.Y) - Math.Min(CInt(e.X * m + b), e.Y) < 10 Then .P = Pens.Red
End With
Next
Me.Invalidate()
End Sub
Private Sub Form1_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles Me.Paint
e.Graphics.SmoothingMode = Drawing2D.SmoothingMode.AntiAlias
For i As Byte = 0 To _Lines.Length - 1
With _Lines(i)
e.Graphics.DrawLine(.P, .X1, .Y1, .X2, .Y2)
End With
Next
End Sub
End Class
Dim _Lines(9) As s_Line
Private Structure s_Line
Dim P As Pen
Dim X1 As Single
Dim X2 As Single
Dim Y1 As Single
Dim Y2 As Single
End Structure
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Dim R As New Random()
For i As Byte = 0 To _Lines.Length - 1
With _Lines(i)
.P = New Pen(Color.Green, 1)
.X1 = R.Next(0, 500)
.X2 = R.Next(0, 500)
.Y1 = R.Next(0, 500)
.Y2 = R.Next(0, 500)
End With
Next
End Sub
Private Sub Form1_MouseClick(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseClick
For i As Byte = 0 To _Lines.Length - 1
With _Lines(i)
.P = Pens.Green
' вычисляем формулу линии
Dim m, b As Single
m = (.Y2 - .Y1) / (.X2 - .X1)
b = .Y1 - (m * .X1)
If Math.Max(CInt(e.X * m + b), e.Y) - Math.Min(CInt(e.X * m + b), e.Y) < 10 Then .P = Pens.Red
End With
Next
Me.Invalidate()
End Sub
Private Sub Form1_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles Me.Paint
e.Graphics.SmoothingMode = Drawing2D.SmoothingMode.AntiAlias
For i As Byte = 0 To _Lines.Length - 1
With _Lines(i)
e.Graphics.DrawLine(.P, .X1, .Y1, .X2, .Y2)
End With
Next
End Sub
End Class