View Full Version : clicking on Geometry Figures
Hi
clicking on hot spots in a map to triger action can be fun, this example uses circles and rectangles as hot spots, so the problem is if a point (x,y) is inside a circle or outside, inside a rectangle or outside.
checking if a point inside a circle or not is just to check if the distance from the point to the circle center is less than or equal the circle radius.
implemented below this procedure to make a hot spots on the canvas so when you move the cursor over a circle it will change the cursor and will display if it is red, yellow ...etc and when you click on it using the sapi module to speak its name.
there is also an implicit circle inside the bug picture to serve as a hot spot.
it is said that square root is costly, so it is enough to check squared values , but this is when the number of figures to be checked are big.
second: checking if a point is inside a rectangle or outside by using api function PtInRect , look ref 1.
also checking if a point is inside a triangle or a rectangle (without using api) is another math issue, the references for this are listed below.
as i am using windows xp/sp2 the sapi voice is "Microsoft Sam", there is'nt "Anna" voice as in windows 7, i have checked windows 7 which i am using rarely, and in my version there is no "Sam" voice.
References:
1- example by Eros how to use Api function "PtInRect" in the article "mouse over":
http://www.thinbasic.com/community/showthread.php?8506-mouse-over
2- example by Petr DrawingMaskedImage.zip if you want to use masked pictures :
http://www.thinbasic.com/community/showthread.php?11037-creating-a-shape
3- Get Pixel Color from a Picture:
http://www.thinbasic.com/community/showthread.php?11064-Get-Pixel-Color-from-a-Picture look also at the references in this article.
4- to check if a point inside a triangle see this good article with a working and successfull flash file, look inside Temprary internet Files for the file app[1].swf ( 2Kb )
http://www.blackpawn.com/texts/pointinpoly/default.html
Uses "UI" ,"SAPI"
Declare Function GetPixel Lib "gdi32" Alias "GetPixel" (ByVal hdc As Long, ByVal x As Long, ByVal y As Long) As Long
'Declare Function SetPixelV Lib "gdi32" Alias "SetPixelV" (ByVal hdc As Long, ByVal x As Long, ByVal y As Long, ByVal crColor As Long) As Long
Declare Function PtInRect Lib "USER32.DLL" Alias "PtInRect" (lpRect As RECT, ByVal ptx As Long, ByVal pty As Long) As Long
Declare Function GetWindowRect Lib "USER32.DLL" Alias "GetWindowRect" (ByVal hWnd As DWord, lpRect As RECT) As Long
Type RECT
nLeft As Long
nTop As Long
nRight As Long
nBottom As Long
End Type
Dim circlesPos(8,3) As Long
Dim circlesColors(8) As Long
Dim circlesNames(8) As String
circlesPos(1,1) = 200,100,20, 250,200,30, 320,200,10, 86,53,13, 24,22,5, 76,252,24, 260,280,40, 350,120,45
circlesNames(1) = "red", "green", "blue", "yellow", "magenta", "white", "gold", "bug"
circlesColors(1) = Rgb(255, 0, 0),Rgb(0, 255, 0),Rgb(0, 0, 255),Rgb(255, 255, 0),Rgb(255, 0, 255),Rgb(255, 255, 255),Rgb(255,215,0),Rgb(0,0,0)
' -- ID numbers of controls
Begin Const
%bClose
%canv
%txtbox
End Const
Global hDlg, i, j, isCursorInsideCircle,isCursorInsideRect, t,x,y As Long
Global radius As Double
' -- Create dialog here
Function TBMain()
Local nWidth, nHeight As Long
Dialog New Pixels,0,"click on canvas Figures (circles & rectangles) ",0,0,600,400,%WS_SYSMENU Or %WS_MINIMIZEBOX Or %WS_CAPTION To hDlg
' -- Place controls here
Control Add Canvas, hDlg, %canv, "", 0, 0, 475, 326
Control Add Button, hDlg, %bClose, " close", 510, 340, 80, 30, Call bCloseProc
Control Add Textbox , hDlg, %txtbox, " " ,480 ,30 ,115 ,30
Canvas_Attach(hDlg, %canv, TRUE)
' -- Make sure coordinate system is per pixel
Canvas_Scale Pixels
Canvas_BitmapGetFileInfo(APP_SourcePath+"bug.bmp", nWidth, nHeight)
Canvas_Clear(Rgb(255,226,255))
Canvas_BitmapRender(APP_SourcePath+"bug.bmp", 0+300,0+70,nWidth+300,nHeight+70)
Canvas_Box (340,200,340+nWidth,200+nHeight,5,Rgb(255,255,0),Rgb(255,255,0),%CANVAS_FILLSTYLE_SOLID)
Canvas_Redraw
For i = 1 To 8
x = circlesPos(i,1): y = circlesPos(i,2)
radius = circlesPos(i,3)
If i=8 Then Exit For
Circle(x, y, radius, Rgb(0, 0, 0), circlesColors(i))
Next i
Dialog Show Modal hDlg, Call dlgProc
End Function
' -- Callback for dialog
CallBack Function dlgProc()
Dim mousePosition As POINTAPI
Dim rc As RECT
Dim locX, locY, myX, myY As Long
Dim distance As Double
' -- Test for messages
Select Case CBMSG
Case %WM_INITDIALOG
' -- Put code to be executed after dialog creation here
Canvas_Attach(CBHNDL, %canv, %FALSE)
Canvas_Scale Pixels
Case %WM_MOUSEMOVE
Control Get Loc CBHNDL, %canv To locX, locY
Win_GetCursorPos(mousePosition)
Win_ScreenToClient(CBHNDL, mousePosition)
mousePosition.x -= locX
mousePosition.y -= locY
isCursorInsideCircle = 0
isCursorInsideRect = 0
For i = 1 To 8 'number of circles drawn or implicit
x = circlesPos(i,1): y = circlesPos(i,2) 'coordinates for every circle
radius = circlesPos(i,3) 'radius for every circle
myX = mousePosition.x : myY = mousePosition.y
distance = Sqr((myX - x)^2 + (myY - y)^2) 'phythagorus theorem
If distance <= radius Then
Control Set Text CBHNDL, %txtbox, circlesNames(i)
MousePtr 5 'using another cursor
isCursorInsideCircle = 1 : t = i
isCursorInsideRect = 0
Exit For
ElseIf distance > radius Then
Control Set Text CBHNDL, %txtbox, "no use "
End If
rc.nLeft = 340
rc.nTop = 200
rc.nRight = 340+100
rc.nBottom = 200+100
If ptInRect(rc,myX,myY) Then
Control Set Text CBHNDL, %txtbox, "yellow rectangle"
MousePtr 5 'using another cursor
isCursorInsideRect = 1
isCursorInsideCircle = 0
Exit For
End If
Next i
Case %WM_LBUTTONDOWN 'when clicking left mouse button
If isCursorInsideCircle = 1 Then
Control Set Text CBHNDL, %txtbox, "okay " + circlesNames(t)
SAPI_Speak(circlesNames(t))
isCursorInsideCircle = 0
End If
If isCursorInsideRect = 1 Then
Control Set Text CBHNDL, %txtbox, "okay " + "yellow rect"
SAPI_Speak("yellow")
isCursorInsideRect = 0
End If
Case %WM_CLOSE
' -- Put code to be executed before dialog end here
End Select
End Function
' -- Callback for close button
CallBack Function bCloseProc()
If CBMSG = %WM_COMMAND Then
If CBCTLMSG = %BN_CLICKED Then
' -- Closes the dialog
Dialog End CBHNDL
End If
End If
End Function
Function Circle(x As Long, y As Long, r As Long, colr, colrFill)
Canvas_Ellipse(x-r, y-r, x+r, y+r, colr, colrFill)
End Function
http://i55.tinypic.com/ftln6d.png
danbaron
24-03-2011, 08:10
You did a lot of work, zak.
It looks nice. I like the colors. I will have to try the program.
In the meantime, I think the general problem of determining whether a point is inside or outside a particular area or volume can be quite difficult. Try drawing a highly irregular shape on a piece of paper, one which curves back and forth in all directions (but does not cross itself), and looks like it is composed of many tentacles. Is there a general method that will work for any possible shape?
:?: :idea:
Hi Dan
i remember a vb6 program which enable the user to define an irregular shape like countries borders as a hot spots , i will search for it in my oldest pc.
my approach i am not satisfied for it because it is a checking all 8 circles to find just the one the cursor on, what if the number are much bigger. i am certain there is a more A.I way to restrict the search to a minimum. i guess that this problem related to the math and computer science.
Charles Pegge
24-03-2011, 09:53
Excellent demo Zak. :)
You can make circular proximity much cheaper by eliminating the exponents and square root, which becomes important when you have a larger number of objects.
Exponent and square root are very expensive in clock cycles for the FPU. - at least 100 apiece. The solution is to compare the squares. Multiplication is only 1 or 2 clocks.
The test goes something like this:
xd=x2-x1
yd=y2-y1
rsq=r1*r1
if rsq>yd*yd+xd*xd then ...
Dan,
I'm familiar with the techniques we use in Opengl for checking whether any position in the viewport coincides with a projected 3d shape. The basic idea is to render all the visible geometry and let Opengl tell you whether you score a hit or not. This is not mathematically elegant but very practical. There is no limitation on the complexity of the shape. But testing for the coincidence of multiple objects with complex shapes remains a challenge and for collision detection in 3d games a simplified "envelope" shape has to be used.
Charles
danbaron
24-03-2011, 10:28
I don't know, maybe OpenGL tags a pixel when it is part of an object, and, of course each pixel corresponds to a coordinate. Or, maybe OpenGL uses some complex numerical method.
I think I understand what you mean about the, "envelopes". The real irregular shape, which has no mathematical equation, is approximated by one or more regular shapes, by ellipses, etc.
But, like I tried to indicate, there is no limit on the possible complexity of regions. Just think about an irregular region which contain multiple irregular holes. I think making a general method for determining an interior point in the general case, is hard.
:cry:
Charles Pegge
24-03-2011, 11:26
For the purposes of hit detection, Opengl renders down to triangles. The shading and pixel rendering stages are not required.
I think the most efficient approach, when dealing with complex shapes is successive approximation. Using a series of simple envelopes you focus down on ever smaller parts of the shape. The same approach applies to large numbers of shapes.
For example, one of my projects is an Opengl text editor. Each letter is a 3d shape. It could be of any size and position in space. A page of text could contain 2-4000 characters and the task is to identify the location of the cursor in a document when the mouse points to a location on the screen. To break this task down into stages I first render each line as a rectangle with an id number and ask Opengl to return the id of the rectangle where the mouse pointer is located. Then I render each word on the line as individual rectangles tagged with an id. Then I do the same for each character in the word. Once the character rectangle is identified, the task is done. and there is no need to go any further and render the geometry of the character itself
Charles
thank you Charles for your suggestions. it is good Dan have mentioned the irregular shapes topic. i have searched my old pc for the vb6 files about this topic, and i found two project. one of them are using vb6 + api functions. and i will post it for speculation after checking it .
ErosOlmi
24-03-2011, 13:52
Very interesting.
Maybe attached example (Canvas Drag and Drop) can help to add more ideas.
Note:
RECT (http://www.thinbasic.com/public/products/thinBasic/help/html/rect.htm) UDT (like other classic structures) is automatically recognized by thinBasic UI module as native UDT so no need to define it in script.
Ciao
Eros
Petr Schreiber
24-03-2011, 14:02
Zak,
thanks for nice demo! It is one of the programs which have bug in it but it is not a mistake :)
Charles, do you use opengl selection mode? I had some issues with it on newer ATi cards
Petr
thank you Eros for the example another source for ideas. indeed my example is just an artistic reformulation of the code you and Petr have posted in the forum before.
i attach for the ideas only an old 2 vb6 source codes i have downloaded in the ancient times, the first one i remember was working on windows 95 or 98, but now it is running but it can't show the hotspot, anyway it is a great source of ideas since it is using :
Declare Function WinCreatePolygonRgn Lib "gdi32 ...
Declare Function WinPtInRegion Lib "gdi32" ....
and in thinbasic there is a Canvas_Polygon to design a complex polygon.
the program let you design irregular points which you want to accomodate some map and then save the designed points in a *.mdb file, i have used it to design a clickable world map to show flags and anthems.
the second example geostates are more complex ,it display the US states and can display every state upon click, but it is not correct, i attach it for ideas.
all those codes are lost forever, why the people do not maintain their free codes ??!!.
Petr , i was about to choose "Jodie Foster" actress picture, but retrogrades in the last minute.
Charles Pegge
24-03-2011, 17:56
Yes Petr,
This is the sequence I use for going into Opengl select mode: (just about everything is reinitialised)
'--------------------
sub PickPrep() as sys
'====================
'
glInitNames()
glSelectBuffer (SelectBufSize, selectBuf)
'
glRenderMode(GL_SELECT)
'
glPushName(-1) 'an arbitrary value
'
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
gluPickMatrix( mposx, mposy, 2.0, 2.0, & viewport) 'pixel selection zone 2x2
orthopersp projmode 'call to setup glPerspective ...
glMatrixMode(GL_MODELVIEW)
glpushmatrix
end sub
then procede to render the required part of the scene
Charles
danbaron
27-03-2011, 07:26
Just for fun.
How could you numerically determine if a point is part of the blue area?
7112
y
^
|
|
|------> x
:oops: :evil: :p
Charles Pegge
27-03-2011, 09:40
Can you provide us with the formula for the shape Dan? :D
Charles
seems like an Aliens map with australia or africa at center. i have searched yesterday about the subject ,i have collected some interesting references but can't follow these days, you may find it useful:
an article "Determining if a point lies on the interior of a polygon" Paul Bourke 1987:
http://paulbourke.net/geometry/insidepoly/
this article have a C code with figures and strategies.
in powerbasic forum site there is an interesting subject with title :"Inside or outside a polygonal region", 3 pages, from the discussions it seems the most successfull code is by Charles Dietz here:
http://www.powerbasic.com/support/pbforums/showthread.php?t=41388&page=2
with improvements by Arie Verheul, the first user seems a mathematician , i can see that many powerbasic users are scientists and mathematicians.
danbaron
27-03-2011, 11:08
There are two boundaries, outer and inner.
The only way I can think of to mathematically describe them, is similar to surveying. For each boundary, you start somewhere, turn an angle, and measure a distance. You keep doing that, until you return to the point at which you started. Then, you measure the distance and angle from the outer boundary starting point to the inner boundary starting point. Now, both boundaries are defined and are related to each other.
Then, you know that in order for a point to be part of the figure, it must be on or inside the outer boundary, and on or outside the inner boundary.
What to do next is not clear to me.
(I didn't see zak's post, until I finished this post.)
:cry:
ErosOlmi
27-03-2011, 11:50
My little contribution to this interesting thread.
I've recoded zak initial example (thanks zak) in order to use UDT instead of global arrays. This should improve possibility to develop this example with more type of geometrical figures in an organized way.
It would be nice to have the possibility to:
draw new figures,
load and save figured data on disk
Hope this can help
Eros
Uses "UI" ,"SAPI", "INI"
#MINVERSION 1.8.6.0
Global nWidth, nHeight As Long
Global IniFile As String Value APP_SourcePath & "Click_On_Figure.ini"
Begin Const
%tFigure_None
%tFigure_Circle
%tFigure_Rect
%tFigure_Image
End Const
Type tFigure
lType As Integer
x As Double
y As Double
width As Double
height As Double
radius As Double
lColor As Long
lFillColor As Long
sName As Asciiz * 64
sImageName As Asciiz * %MAX_PATH
End Type
Dim Figures() As tFigure
' -- ID numbers of controls
Begin ControlID
%bClose
%canv
%txtGeneralInfo
%txtMouseInfo
End ControlID
' -- Create dialog here
Function TBMain()
Local hDlg As Long
Local Looper As Long
' -- Make sure coordinate system is per pixel
Canvas_Scale Pixels
Dialog New Pixels,0,"click on canvas Figures (circles & rectangles) ",-1,-1,640,480,%WS_SYSMENU Or %WS_MINIMIZEBOX Or %WS_CAPTION To hDlg
' -- Place controls here
Control Add Canvas , hDlg, %canv , "" , 0, 0, 500, 400
Control Add Button , hDlg, %bClose , " close", 510, 340, 90, 30, Call bCloseProc
Control Add Textbox , hDlg, %txtMouseInfo , "" , 510, 10, 90, 25
Control Add Textbox , hDlg, %txtGeneralInfo , "" , 510, 40, 90, 25
Canvas_Attach(hDlg, %canv, TRUE)
Canvas_Clear(Rgb(255, 255, 255))
'---Draw canvas lines
For Looper = 1 To 25
'---Vertical lines
Canvas_Line( (Looper*20, 00), (Looper*20, 400), Rgb(236,236,236))
'---Hor line
Canvas_Line( (00, Looper*20), (500, Looper*20), Rgb(236,236,236))
Next
'---Load figures from INI file
Figures_FromIniFile(Figures)
'---Draw all figures
For Looper = 1 To UBound(Figures)
Figure_Draw(Figures(Looper))
Next
'---Save figures to INI file (as an exercise to show how it can be possibly be done)
Figures_ToIniFile(Figures)
Canvas_Redraw
Dialog Show Modal hDlg, Call dlgProc
End Function
' -- Callback for dialog
CallBack Function dlgProc() As Long
Local lItem As Long
Local Looper As Long
Local MousePosition As POINTAPI
' -- Test for messages
Select Case CBMSG
Case %WM_INITDIALOG
' -- Put code to be executed after dialog creation here
Canvas_Attach(CBHNDL, %canv, %FALSE)
Canvas_Scale Pixels
Case %WM_MOUSEMOVE
MousePosition.x = LOINT(CBLPARAM)
MousePosition.y = HIINT(CBLPARAM)
Control Set Text CBHNDL, %txtMouseInfo, "(" & MousePosition.x & "-" & MousePosition.y & ")"
lItem = MouseGetPositionInFigure(MousePosition)
If lItem Then
Control Set Text CBHNDL, %txtGeneralInfo, Figures(lItem).sName
MousePtr 5 'using another cursor
Else
Control Set Text CBHNDL, %txtGeneralInfo, ""
End If
Case %WM_LBUTTONDOWN
MousePosition.x = LOINT(CBLPARAM)
MousePosition.y = HIINT(CBLPARAM)
lItem = MouseGetPositionInFigure(MousePosition)
If lItem Then
Control Set Text CBHNDL, %txtGeneralInfo, "Got figure " & Figures(lItem).sName
SAPI_Speak("Got " & Figure_TypeToTypeName(Figures(lItem).lType) & " whose name is " & Figures(lItem).sName & ".")
Else
SAPI_Speak("Missed!")
End If
Case %WM_CLOSE
' -- Put code to be executed before dialog end here
End Select
End Function
'------------------
' -- Callback for close button
CallBack Function bCloseProc() As Long
'------------------
If CBMSG = %WM_COMMAND Then
If CBCTLMSG = %BN_CLICKED Then
' -- Closes the dialog
Dialog End CBHNDL
End If
End If
End Function
'------------------
Function MouseGetPositionInFigure(ByRef MousePosition As POINTAPI) As Long
'------------------
Local Looper As Long
Local nItems As Long
nItems = UBound(Figures())
'---Check from top to bottom
For Looper = nItems To 1 Step -1
If Figure_MouseInside(Figures(Looper), MousePosition) Then
Function = Looper
Exit For
End If
Next
End Function
'------------------
Function Circle(ByVal x As Long, ByVal y As Long, ByVal r As Long, colr, colrFill)
'------------------
Canvas_Ellipse(x-r, y-r, x+r, y+r, colr, colrFill)
End Function
'------------------
Function Figure_Draw(ByRef lFigure As tFigure) As Long
'------------------
Select Case lFigure.lType
Case %tFigure_None
'---Do nothing
Case %tFigure_Circle
Circle(lFigure.x, lFigure.y, lFigure.radius, Rgb(0, 0, 0), lFigure.lFillColor)
Case %tFigure_Rect
Canvas_Box(lFigure.x, lFigure.y, lFigure.x + lFigure.width, lFigure.y + lFigure.height, 0, Rgb(0, 0, 0), lFigure.lFillColor, %CANVAS_FILLSTYLE_SOLID)
Case %tFigure_Image
Canvas_BitmapRender(APP_SourcePath + "Images\" + lFigure.sImageName, lFigure.x, lFigure.y, lFigure.x + lFigure.width, lFigure.y + lFigure.height)
End Select
End Function
'------------------
Function Figure_MouseInside(ByRef lFigure As tFigure, ByRef MousePosition As POINTAPI) As Long
'------------------
Local lDistance As Double
Select Case lFigure.lType
Case %tFigure_None
'---Do nothing
Case %tFigure_Circle
lDistance = Sqr((MousePosition.x - lFigure.x)^2 + (MousePosition.y - lFigure.y)^2)
If lDistance <= lFigure.radius Then
Function = %TRUE
End If
Case %tFigure_Rect
If Inside(MousePosition.x, lFigure.x, lFigure.x + lFigure.width) And _
Inside(MousePosition.y, lFigure.y, lFigure.y + lFigure.height) Then
Function = %TRUE
End If
Case %tFigure_Image
If Inside(MousePosition.x, lFigure.x, lFigure.x + lFigure.width) And _
Inside(MousePosition.y, lFigure.y, lFigure.y + lFigure.height) Then
Function = %TRUE
End If
End Select
End Function
'------------------
Function Figure_TypeToTypeName(ByVal lType As Long) As String
'------------------
Select Case lType
Case %tFigure_None
Function = "None"
Case %tFigure_Circle
Function = "Circle"
Case %tFigure_Rect
Function = "Rectangle"
Case %tFigure_Image
Function = "Image"
End Select
End Function
'------------------
Function Figure_TypeNameToType(ByVal TypeName As String) As Long
'------------------
Select Case LCase$(TypeName)
Case "none"
Function = %tFigure_None
Case "circle"
Function = %tFigure_Circle
Case "rectangle"
Function = %tFigure_Rect
Case "image"
Function = %tFigure_Image
End Select
End Function
'------------------
Function Figures_ToIniFile(ByRef lFigures() As tFigure) As Long
'------------------
Local Looper As Long
Local nItems As Long
nItems = UBound(lFigures)
INI_SetKey(IniFile, "General", "NumberOfItems", nItems)
For Looper = 1 To nItems
INI_SetKey(IniFile, Looper, "Type", Figure_TypeToTypeName(lFigures(Looper).lType) )
INI_SetKey(IniFile, Looper, "x", lFigures(Looper).x )
INI_SetKey(IniFile, Looper, "y", lFigures(Looper).y )
INI_SetKey(IniFile, Looper, "Width", lFigures(Looper).width )
INI_SetKey(IniFile, Looper, "Height", lFigures(Looper).height )
INI_SetKey(IniFile, Looper, "Radius", lFigures(Looper).radius )
INI_SetKey(IniFile, Looper, "Color", lFigures(Looper).lColor )
INI_SetKey(IniFile, Looper, "FillColor", lFigures(Looper).lFillColor)
INI_SetKey(IniFile, Looper, "Name", lFigures(Looper).sName )
INI_SetKey(IniFile, Looper, "ImageName", lFigures(Looper).sImageName)
Next
End Function
'------------------
Function Figures_FromIniFile(ByRef lFigures() As tFigure) As Long
'------------------
Local Looper As Long
Local nItems As Long
nItems = INI_GetKey(IniFile, "General", "NumberOfItems", 0)
ReDim lFigures(nItems)
For Looper = 1 To nItems
lFigures(Looper).lType = Figure_TypeNameToType(INI_GetKey(IniFile, Looper, "Type"))
lFigures(Looper).x = INI_GetKey(IniFile, Looper, "x" )
lFigures(Looper).y = INI_GetKey(IniFile, Looper, "y" )
lFigures(Looper).width = INI_GetKey(IniFile, Looper, "Width" )
lFigures(Looper).height = INI_GetKey(IniFile, Looper, "Height" )
lFigures(Looper).radius = INI_GetKey(IniFile, Looper, "Radius" )
lFigures(Looper).lColor = INI_GetKey(IniFile, Looper, "Color" )
lFigures(Looper).lFillColor = INI_GetKey(IniFile, Looper, "FillColor" )
lFigures(Looper).sName = INI_GetKey(IniFile, Looper, "Name" )
lFigures(Looper).sImageName = INI_GetKey(IniFile, Looper, "ImageName" )
Next
End Function
very neat example Eros, i like the squared paper arrangement and color, like the old days arithmetic class, also the "tactics" used to define and draw the figures, sure i will use in the future. i don't know about the "inside" function it is usefull. i am still have to study the example more and more, i am too slow.
thank you
This is what I like.
Cool programming and fine source codes
super programed by Eros, and he has great knowledges about that what he is doing.
And so can the show go on, and we see more fine programs of this kind.
Thank you.
ErosOlmi
27-03-2011, 17:21
Thanks peter.
I thought zak code was perfect example to be used for showing few concept and possibly add it as example in next release once it will be improved.
Updated my example just above.
Removed figures setup in source code and added loading/saving data from file. I've used INI structure for file in such a way it can be easily understandable and possibly changed by hand. Included an INI file with figures.
danbaron
28-03-2011, 01:03
Wow, Eros is like a programming machine!
I was thinking about how to determine whether a point is contained within an arbitrary shape. I can think of one way to do it. You have to know one point inside the region, which you use as a reference point. If the point you are testing is part of the region, then, you will be able to find some path from it to the reference point, without crossing the region's boundary. Below, in the picture, the yellow circle is the reference point, and the two red circles are test points. You can see that for the interior test point, a path exists which connects it to the reference point and does not cross the region's boundary; but for the exterior test point, there is no such path. (I'm not trying to imply that this procedure would be easy to numerically implement.)
:grrrr: :bom:
7116
Charles Pegge
28-03-2011, 14:44
I think this one might be simpler Dan:
1 make a list of all the line segments that comprise the boundary of the shape.
Get the y coordinate of your point.
Identify those lines which intersect the y line
Get the x values of all those intersections
Sort the lines into ascending value of x intersection
Assume the first line denotes the transition from an exterior to an interior space.
Then the second line can be assumed to be an interior to exterior transition, and so on
Now it is possible to determine whether the x point is placed between the boundary lines of an exterior or an interior space.
You will need additional rules if the point coincides with a boundary line.
Charles
danbaron
28-03-2011, 21:22
I think you are right, Charles - in, out, in, out, in, out,..
Very simple. Very good.
(The one qualification being, that a curved boundary must first be approximated by line segments. But, for numerical methods, in the general case, we should not hope to ever get exact answers, right?)
:( :| :arrow: :p
ErosOlmi
28-03-2011, 21:54
New version attached. Added following improvements:
code quite completely rewritten
main window is now modeless
main window is fully resizable
canvas area now fully fill main window client are
canvas area is fully resizable (well killed and recreated)
added main menu for easy future implementations
file with figures can be loaded from disk (INI format) using File/Open menu
right click on a figure shows a popup menu with figure info
right click in canvas free space just add a new random figure
Tested till up to 200 figures seem still working quickly.
I will stop for a while due to heavy work load. If someone has some spare time to add more options or just suggest features. I will try to have more time next days.
To add
complete file load/change/save process
a toolbox
new kind of figures
drag/drop
figures grip (handlers)
...
Eros
danbaron
29-03-2011, 07:29
Here is a modification of Charles' method (above) for numerically determining if a point is interior to (part of) or exterior to (not part of) a region. You have to know one point inside the region, which you use as a reference point. You construct a straight line segment from the test point to the reference point. Then, you count the number of times the segment crosses the region's boundary/boundaries. If the number is even, the test point is interior to the region, else, the test point is exterior to the region. Below, in the picture, the yellow circle is the reference point, and the red circles are test points. The number of boundary crossings is labeled for each of the test point line segments.
:x :?: :|
7124
ErosOlmi
29-03-2011, 12:54
Just noted that on slow computers my last example is flickering a lot (mainly because CANVAS control is not resizable so at every refresh it has to be deleted and created again)
To avoid this flickering just add the following 2 lines into main window callback SELECT/END SELECT:
Case %WM_ERASEBKGND
Function = %TRUE
Next update will be better:D
Petr Schreiber
29-03-2011, 17:59
Here is the version with flicker free redraw :)
Really nice proggie!
Petr