Jump to content

Check if a point is within various defined closed shapes.


Malkey
 Share

Recommended Posts

This is an example showing the use of, and accuracy of the following functions.

 

_PointInEllipse()

_WinAPI_PtInRectEx()

_PointInPoly()

 

All functions return true if the specified point is witin the closed area of the shape, And, False if the specified point is outside the shape.

 

A circle can be used with _PointInEllipse() function. A circle being an equal sided ellipse.

A triangle can be used with _PointInPoly(). A triangle being a three sided polygon.

For right angle rectangle shape use _WinAPI_PtInRectEx(). Similar to the one in WinAPI.au3, include file.

For a parallelogram, rhombus, or any other quadrilateral shape or other multi-straight-line-sided closed figure use _PointInPoly() function.

 

In the example the graphics area on the GUI has been shorten. This shows that the graphics displaying the shapes are not necessary for the functions to work. Although, the graphics are necessary for checking their accuracy.

 

The tool tip will show true for the shape the cursor is inside, and false for all the other shapes.

 

The shapes are clickable.

 

Notice the tool tip when the the cursor is over the button.. The button is within the circle, The button, when pressed, shows the button pressed message as opposed to the 'in cirlce shape' message.

 

Cllick below or above the button, but still within the cirle area, and the 'in cirlce shape' message works.

 

The two functions

The _CentroidPoly() function which returns the x, y position of the centroid of a polygon, and

the _AreaPoly() function which returns the area of a closed polygon,

have been included. Someone might find a use for them oneday.

 

If nothing else, this example will tell you the names of different shapes. Although that is not its purpose.

 

Hopefully, you can find a use for these functions in your own script.

 

#include <GuiConstantsEx.au3>
#include <GDIPlus.au3>
#include <WinAPI.au3>
#include <WindowsConstants.au3>

Opt('MustDeclareVars', 1)
Opt("MouseCoordMode", 2);1=absolute, 0=relative, 2=client

Global $hGUI, $hBMPBuff, $hGraphicGUI, $hGraphic

_Main()

Func _Main()
    Local $msg, $aPos, $GuiSizeX = 400, $GuiSizeY = 300
    Local $aPoints[7][2], $aTriangle[5][2]
    Local $hButton
; Create GUI
    $hGUI = GUICreate("GDI+", $GuiSizeX, $GuiSizeY)

    GUISetState()

    _GDIPlus_Startup()
;Double Buffer
    $hGraphicGUI = _GDIPlus_GraphicsCreateFromHWND($hGUI)
    $hBMPBuff = _GDIPlus_BitmapCreateFromGraphics($GuiSizeX, $GuiSizeY - 65, $hGraphicGUI)
    $hGraphic = _GDIPlus_ImageGetGraphicsContext($hBMPBuff)
;End Double Buffer add-on 1 of 3

    _GDIPlus_GraphicsClear($hGraphic, 0xFFE8FFEF)

    $aPoints[0][0] = 5; Number of  sides of Polygon
    $aPoints[1][0] = 100
    $aPoints[1][1] = 100
    $aPoints[2][0] = 200
    $aPoints[2][1] = 150
    $aPoints[3][0] = 200
    $aPoints[3][1] = 200
    $aPoints[4][0] = 150
    $aPoints[4][1] = 100
    $aPoints[5][0] = 70
    $aPoints[5][1] = 200
    $aPoints[6][0] = 100;Last point same as 1st point. Polygon is closed
    $aPoints[6][1] = 100
    _GDIPlus_GraphicsDrawPolygon($hGraphic, $aPoints)

    Local $iRectX = 220, $iRectY = 25, $iRectWidth = 100, $iRectHth = 50
    _GDIPlus_GraphicsDrawRect($hGraphic, $iRectX, $iRectY, $iRectWidth, $iRectHth)

    Local $iElpsX = 220, $iElpsY = 180, $iElpsWidth = 130, $iElpsHth = 70
    _GDIPlus_GraphicsDrawEllipse($hGraphic, $iElpsX, $iElpsY, $iElpsWidth, $iElpsHth)

    $aTriangle[0][0] = 3; Number of  sides of Polygon
    $aTriangle[1][0] = 30
    $aTriangle[1][1] = 30
    $aTriangle[2][0] = 150
    $aTriangle[2][1] = 40
    $aTriangle[3][0] = 50
    $aTriangle[3][1] = 100
    $aTriangle[4][0] = 30;Last point same as 1st point. Polygon is closed
    $aTriangle[4][1] = 30
    _GDIPlus_GraphicsDrawPolygon($hGraphic, $aTriangle)

    $hButton = GUICtrlCreateButton("In Circle", 22, 240, 75, 20)

    Local $iCircleX = 20, $iCircleY = 210, $iCircleWidth = 80, $iCircleHth = 80
    _GDIPlus_GraphicsDrawEllipse($hGraphic, $iCircleX, $iCircleY, $iCircleWidth, $iCircleHth)

    ConsoleWrite("Area of Polygon = " & _AreaPoly($aPoints) & @CRLF)
    Local $aCent = _CentroidPoly($aPoints)
    ConsoleWrite("Centroid of Polygon:  cX = " & $aCent[0] & "   cY = " & $aCent[1] & @CRLF)

; Create Double Buffer, doesn't need to be repainted on PAINT-Event
    GUIRegisterMsg(0xF, "MY_PAINT"); Register PAINT-Event 0x000F = $WM_PAINT (WindowsConstants.au3)
    GUIRegisterMsg(0x85, "MY_PAINT"); $WM_NCPAINT = 0x0085 (WindowsConstants.au3)Restore after Minimize.
    _GDIPlus_GraphicsDrawImage($hGraphicGUI, $hBMPBuff, 0, 0)
;End Double Buffer add-on 2 of 3

    While 1
        $msg = GUIGetMsg()
        Switch $msg
            Case $GUI_EVENT_CLOSE
                _GDIPlus_GraphicsDispose($hGraphic)
                _GDIPlus_GraphicsDispose($hGraphicGUI)
                _WinAPI_DeleteObject($hBMPBuff)
                _GDIPlus_Shutdown()
                Exit
            Case $hButton
                MsgBox(0, "", "Button Pressed. ")
            Case $GUI_EVENT_MOUSEMOVE
                $aPos = MouseGetPos()
                ToolTip("Mouse Position X:  " & $aPos[0] & "   Y: " & $aPos[1] & @CRLF & @CRLF & _
                        "Cursor in Polygon: " & _PointInPoly($aPos[0], $aPos[1], $aPoints) & @CRLF & _
                        "Cursor in Triangle: " & _PointInPoly($aPos[0], $aPos[1], $aTriangle) & @CRLF & _
                        "Cursor in Ellipse: " & _PointInEllipse($aPos[0], $aPos[1], $iElpsX, $iElpsY, _
                        $iElpsWidth, $iElpsHth) & @CRLF & _
                        "Cursor in Circle: " & _PointInEllipse($aPos[0], $aPos[1], $iCircleX, $iCircleY, _
                        $iCircleWidth, $iCircleHth) & @CRLF & _
                        "Cursor in Rectangle: " & _WinAPI_PtInRectEx($aPos[0], $aPos[1], $iRectX, $iRectY, _
                        $iRectX + $iRectWidth, $iRectY + $iRectHth) & @CRLF)
            Case $GUI_EVENT_PRIMARYUP
                $aPos = MouseGetPos()
                Select
                    Case _PointInPoly($aPos[0], $aPos[1], $aPoints)
                        ToolTip("")
                        MsgBox(0, "", "Clicked in PolyGon")
                    Case _WinAPI_PtInRectEx($aPos[0], $aPos[1], $iRectX, $iRectY, $iRectX + $iRectWidth, _
                            $iRectY + $iRectHth)
                        ToolTip("")
                        MsgBox(0, "", "Clicked in Rectangle")
                    Case _PointInEllipse($aPos[0], $aPos[1], $iElpsX, $iElpsY, $iElpsWidth, $iElpsHth)
                        ToolTip("")
                        MsgBox(0, "", "Clicked in Ellipse")
                    Case _PointInPoly($aPos[0], $aPos[1], $aTriangle)
                        ToolTip("")
                        MsgBox(0, "", "Clicked in Triangle")
                    Case _PointInEllipse($aPos[0], $aPos[1], $iCircleX, $iCircleY, $iCircleWidth, $iCircleHth)
                        ToolTip("")
                        MsgBox(0, "", "Clicked in Invisible Circle")

                EndSelect
        EndSwitch
    WEnd
EndFunc  ;==>_Main

; Returns the area of a polygon
Func _AreaPoly($aPoints)
    Local $Med
    For $n = 1 To UBound($aPoints) - 2
        $Med += $aPoints[$n][0] * $aPoints[$n + 1][1] - $aPoints[$n + 1][0] * $aPoints[$n][1]
    Next
    Return $Med / 2
EndFunc  ;==>_AreaPoly

; Returns an array containing the x, y position of the centroid of a polygon.
Func _CentroidPoly($aPoints)
    Local $Med, $aRet[2], $MedX, $MedY, $Area
    For $n = 1 To UBound($aPoints) - 2
        $MedX += ($aPoints[$n][0] + $aPoints[$n + 1][0]) * ($aPoints[$n][0] * $aPoints[$n + 1][1] - _
                $aPoints[$n + 1][0] * $aPoints[$n][1])
        $MedY += ($aPoints[$n][1] + $aPoints[$n + 1][1]) * ($aPoints[$n][0] * $aPoints[$n + 1][1] - _
                $aPoints[$n + 1][0] * $aPoints[$n][1])
    Next
    $Area = _AreaPoly($aPoints)
    $aRet[0] = $MedX / ($Area * 6)
    $aRet[1] = $MedY / ($Area * 6)
    Return $aRet
EndFunc  ;==>_CentroidPoly

; ($xPt, $yPt) - x, y position of the point to check
;  $xTL, $yTL,  Top left x Pos, top left Y position of the rectangle encompassing the ellipse.
; $w, $h - The width an height of ellipse
; Method: The distance from the 1st focal point to a point on the perimeter plus the distance from
; the second focal point to the same point on the perimeter is a constant and equals the width of
; the ellipse, the major axis. So, if the sum of the two distances form the point to check to the
; two foci is greater than the major axis, then the point is outside the ellipse.
Func _PointInEllipse($xPt, $yPt, $xTL, $yTL, $w, $h)
    Local $bInside = False, $a = $w / 2, $b = $h / 2
    Local $c1X, $c2X, $dist, $xc = $xTL + $a, $yc = $yTL + $b
    $c1X = $xc - ($a ^ 2 - $b ^ 2) ^ (1 / 2); 1st focal point x position
    $c2X = $xc + ($a ^ 2 - $b ^ 2) ^ (1 / 2); 2nd focal point x position
    $dist = (($xPt - $c1X) ^ 2 + ($yPt - $yc) ^ 2) ^ 0.5 + (($xPt - $c2X) ^ 2 + ($yPt - $yc) ^ 2) ^ 0.5
    If $dist <= $w Then $bInside = Not $bInside
    Return $bInside
EndFunc  ;==>_PointInEllipse


; ($iX, $iY)          - x, y position of the point to check
; ($iLeft, $iTop)    - x, y position of the top left corner of rectangle
; ($iRight, $iBottom) - x, y position of the bottom right corner of rectangle
;
Func _WinAPI_PtInRectExA($iX, $iY, $iLeft, $iTop, $iRight, $iBottom)
    Local $aResult
    Local $tRect = DllStructCreate($tagRECT)
    DllStructSetData($tRect, "Left", $iLeft)
    DllStructSetData($tRect, "Top", $iTop)
    DllStructSetData($tRect, "Right", $iRight)
    DllStructSetData($tRect, "Bottom", $iBottom)
    $aResult = DllCall("User32.dll", "int", "PtInRect", "ptr", DllStructGetPtr($tRect), "int", $iX, "int", $iY)
    If @error Then Return SetError(@error, 0, False)
    Return $aResult[0] <> 0
EndFunc  ;==>_WinAPI_PtInRectEx

; ($x, $y)        - x, y position of the point to check
; $aPoints - An array of x,y values representing the nodes of a polygon.
; Finds the individual x values of the interestion of the individual sides of the polygon with the
; line y = $y (parallel with x-axis). If the number of x values found greater than $x is even, then
; the ($x, $y) point is outside the closed polygon. Plus, if $y is beyond the y values of the end
; points of individual sides of the polygon, the y = $y line will not interest with that side and will
; not be counted. Returns equivalent of, even number of intersections false, and, odd true(inside polygon).
; Requires Iif()function
Func _PointInPoly($x, $y, $aPoints)
    Local $bEvenNum = False, $xOnLine, $yMin, $yMax
    For $i = 1 To $aPoints[0][0]
        $yMin = Iif($aPoints[$i + 1][1] < $aPoints[$i][1], $aPoints[$i + 1][1], $aPoints[$i][1])
        $yMax = Iif($aPoints[$i + 1][1] > $aPoints[$i][1], $aPoints[$i + 1][1], $aPoints[$i][1])
        $xOnLine = -($y * $aPoints[$i + 1][0] - $y * $aPoints[$i][0] - $aPoints[$i][1] * $aPoints[$i + 1][0] + _
                $aPoints[$i][0] * $aPoints[$i + 1][1]) / (-$aPoints[$i + 1][1] + $aPoints[$i][1])
        If ($x < $xOnLine) And ($y > $yMin) And ($y <= $yMax) Then $bEvenNum = Not $bEvenNum
    Next
    Return $bEvenNum
EndFunc  ;==>_PointInPoly

; Same as _Iif() function from Misc.au3 include file
Func Iif($fTest, $vTrueVal, $vFalseVal)
    If $fTest Then
        Return $vTrueVal
    Else
        Return $vFalseVal
    EndIf
EndFunc  ;==>Iif

;Func to redraw on PAINT MSG
Func MY_PAINT($hWnd, $msg, $wParam, $lParam)
; Check, if the GUI with the Graphic should be repainted
    _GDIPlus_GraphicsDrawImage($hGraphicGUI, $hBMPBuff, 0, 0)
    _WinAPI_RedrawWindow($hGUI, "", "", BitOR($RDW_INVALIDATE, $RDW_UPDATENOW, $RDW_FRAME));,$RDW_ALLCHILDREN
    Return $GUI_RUNDEFMSG
EndFunc  ;==>MY_PAINT

 

Edit: Another example of the use of _PointInEllipse() function is at

http://www.autoitscript.com/forum/index.ph...st&p=639811

 

Edit:8thFeb2008

Changed _PointInPoly() to correct wrong return when the conditions point out by martin, post#5, occurred.

Edit:8thFeb2008 10hr later

Changed _PointInPoly() to correct wrong return when the conditions point out by martin, post#7, occurred.

Edit:8thFeb2008

Changed _PointInPoly() to simplify conditional statement as mentioned in posts #9 and #10.

Edited by Malkey
_WinAPI_PtInRectEx was duplicated. "A" added to overcome duplication.
Link to comment
Share on other sites

  • Moderators

Malkey,

Very nice script. Thank you for putting in the effort to write it. I can already think of a number of uses - as you know!

M23

Public_Domain.png.2d871819fcb9957cf44f4514551a2935.png Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind

Open spoiler to see my UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Link to comment
Share on other sites

Goog job, maybe useful for later GDI+ projects... :)

Thanks for sharing knowledge !

UEZ

Please don't send me any personal message and ask for support! I will not reply!

Selection of finest graphical examples at Codepen.io

The own fart smells best!
Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!
¯\_(ツ)_/¯  ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ

Link to comment
Share on other sites

Melba23

Thanks for this routine at

http://www.autoitscript.com/forum/index.ph...st&p=639816

$iOldOpt = Opt("MouseCoordMode", 2)
 $aPos = MouseGetPos()
 If _PointInEllipse($aPos[0], $aPos[1], 90, 90, 21, 21) Then MsgBox(0, "", "Hit")
 Opt("MouseCoordMode", $iOldOpt )

It could be useful, when "MouseCoordMode" needs to be other than 2 elsewhere in a script.

UEZ

I hope the use of these functions can make any of your project easier to fulfill.

Below is a smaller example showing a possible use of the _WinAPI_PtInRectEx() function.

; Example of dividing up a GUI control into clickable areas
; requires Opt("MouseCoordMode", 2)

Opt("MouseCoordMode", 2) ;1=absolute, 0=relative, 2=client

Example()

Func Example()
    Local $Button_1, $msg, $aPos
    GUICreate("My GUI Button") ; will create a dialog box that when displayed is centered

    Opt("GUICoordMode", 2)

    $Button_1 = GUICtrlCreateButton(" Left   Middle   Right ", 10, 30, 120, 20)

    GUISetState() 

    ; Run the GUI until the dialog is closed
    While 1
        $msg = GUIGetMsg()
        Select
            Case $msg = -3 ; $GUI_EVENT_CLOSE from #include <GUIConstantsEx.au3>
                ExitLoop
            Case $msg = $Button_1
                $aPos = MouseGetPos()
                If _WinAPI_PtInRectEx($aPos[0], $aPos[1], 10, 30, 40, 20) Then MsgBox(0, "", "Left Side of Button")
                If _WinAPI_PtInRectEx($aPos[0], $aPos[1], 50, 30, 40, 20) Then MsgBox(0, "", "Middle  of Button")
                If _WinAPI_PtInRectEx($aPos[0], $aPos[1], 90, 30, 40, 20) Then MsgBox(0, "", "Right Side of Button")
        EndSelect
    WEnd
EndFunc   ;==>Example


; Note this_WinAPI_PtInRectEx() Not the same as 1st post.
; Here Width & height used, NOT Bottom right corner position.
; Also, declared $tagREC.  $tagRECT required WinAPI.au3 to be included.
Func _WinAPI_PtInRectEx($iX, $iY, $iLeft, $iTop, $iWidth, $iHeight)
    Local $aResult, $tagREC = "int Left;int Top;int Right;int Bottom"
    Local $tRect = DllStructCreate($tagREC)
    DllStructSetData($tRect, "Left", $iLeft)
    DllStructSetData($tRect, "Top", $iTop)
    DllStructSetData($tRect, "Right", $iLeft + $iWidth)
    DllStructSetData($tRect, "Bottom", $iTop + $iHeight)
    $aResult = DllCall("User32.dll", "int", "PtInRect", "ptr", DllStructGetPtr($tRect), "int", $iX, "int", $iY)
    If @error Then Return SetError(@error, 0, False)
    Return $aResult[0] <> 0
EndFunc   ;==>_WinAPI_PtInRectEx
Link to comment
Share on other sites

Malkey, nice functions. Your inside poly needs a small change because you count the point of an intersection twice, so if you have a polygon like this

$aPoints[0][0] = 5; Number of  sides of Polygon
     $aPoints[1][0] = 100
     $aPoints[1][1] = 100;
     $aPoints[2][0] = 200
     $aPoints[2][1] = 80;
     $aPoints[3][0] = 200
     $aPoints[3][1] = 200;
     $aPoints[4][0] = 100
     $aPoints[4][1] = 170;
     $aPoints[5][0] = 170
     $aPoints[5][1] = 140;
     $aPoints[6][0] = 100;Last point same as 1st point. Polygon is closed
     $aPoints[6][1] = 100

then when the cursor is at the same y coordinate as a node it will think the cursor is inside the polygone when it might be outside to the left.

Edited by martin
Serial port communications UDF Includes functions for binary transmission and reception.printing UDF Useful for graphs, forms, labels, reports etc.Add User Call Tips to SciTE for functions in UDFs not included with AutoIt and for your own scripts.Functions with parameters in OnEvent mode and for Hot Keys One function replaces GuiSetOnEvent, GuiCtrlSetOnEvent and HotKeySet.UDF IsConnected2 for notification of status of connected state of many urls or IPs, without slowing the script.
Link to comment
Share on other sites

Malkey, nice functions. Your inside poly needs a small change because you count the point of an intersection twice, so if you have a polygon like this

$aPoints[0][0] = 5; Number of  sides of Polygon
     $aPoints[1][0] = 100
     $aPoints[1][1] = 100;
     $aPoints[2][0] = 200
     $aPoints[2][1] = 80;
     $aPoints[3][0] = 200
     $aPoints[3][1] = 200;
     $aPoints[4][0] = 100
     $aPoints[4][1] = 170;
     $aPoints[5][0] = 170
     $aPoints[5][1] = 140;
     $aPoints[6][0] = 100;Last point same as 1st point. Polygon is closed
     $aPoints[6][1] = 100

then when the cursor is at the same y coordinate as a node it will think the cursor is inside the polygon when it might be outside to the left.

Thank-you for that. I appreciate your diligences.

I have updated the first post to correct the wrong return when the y = $y line passed through a node. There is now a check for no duplicate x values which indicates a node.

If you, martin or any one else finds a problem or a better way of doing this, please make it known.

Link to comment
Share on other sites

Thank-you for that. I appreciate your diligences.

I have updated the first post to correct the wrong return when the y = $y line passed through a node. There is now a check for no duplicate x values which indicates a node.

If you, martin or any one else finds a problem or a better way of doing this, please make it known.

It's better but not right yet. If you try the shape I used and set the cursor to the left of the lowest node on the polygon then it says inside when it isn't.

Maybe you need to have some condition like this:

If the cursor Y position is at the Y coord for a node, and the Y coord for that node is the minimum Y for both lines meeting at the node, or it is the maximum for both lines then ignore this node.

Serial port communications UDF Includes functions for binary transmission and reception.printing UDF Useful for graphs, forms, labels, reports etc.Add User Call Tips to SciTE for functions in UDFs not included with AutoIt and for your own scripts.Functions with parameters in OnEvent mode and for Hot Keys One function replaces GuiSetOnEvent, GuiCtrlSetOnEvent and HotKeySet.UDF IsConnected2 for notification of status of connected state of many urls or IPs, without slowing the script.
Link to comment
Share on other sites

It's better but not right yet. If you try the shape I used and set the cursor to the left of the lowest node on the polygon then it says inside when it isn't.

Maybe you need to have some condition like this:

If the cursor Y position is at the Y coord for a node, and the Y coord for that node is the minimum Y for both lines meeting at the node, or it is the maximum for both lines then ignore this node.

martin

You are good at this. Thanks again.

I have updated first post again.

Adding this," And (($y <> $yMin) Or (StringInStr($sXIntersects, $xOnLine) = 0))" seems to have fix the V shape node problem..

If you find them, keep them coming.

Link to comment
Share on other sites

martin

You are good at this. Thanks again.

I have updated first post again.

Adding this," And (($y <> $yMin) Or (StringInStr($sXIntersects, $xOnLine) = 0))" seems to have fix the V shape node problem..

If you find them, keep them coming.

Yes it's fixed now :)

But you have added a condition which isn't needed I think.

If ($x < $xOnLine) And ($y > $yMin) And ($y <= $yMax) And (($y <> $yMin) Or _
                 (StringInStr($sXIntersects, $xOnLine) = 0)) Then $sXIntersects &= $xOnLine & ","

If

$y > $yMin

then

($y <> $yMin)

will always be true so

(($y <> $yMin) Or (StringInStr($sXIntersects, $xOnLine) = 0))

will always be true so the test is really

If ($x < $xOnLine) And ($y > $yMin) And ($y <= $yMax) Then $sXIntersects &= $xOnLine & ","

In fact all that matters is that the cursor is to the left and you count only one end of the line, so this would also work

If ($x < $xOnLine) And ($y >= $yMin) And ($y < $yMax) Then $sXIntersects &= $xOnLine & ","
Edited by martin
Serial port communications UDF Includes functions for binary transmission and reception.printing UDF Useful for graphs, forms, labels, reports etc.Add User Call Tips to SciTE for functions in UDFs not included with AutoIt and for your own scripts.Functions with parameters in OnEvent mode and for Hot Keys One function replaces GuiSetOnEvent, GuiCtrlSetOnEvent and HotKeySet.UDF IsConnected2 for notification of status of connected state of many urls or IPs, without slowing the script.
Link to comment
Share on other sites

  • 2 weeks later...

This is the first post example converted to a Opt("GUIOnEventMode", 1) ;OnEvent mode enabled type.

Both scripts rely on mouse events being detected.

This script uses _IsPressed("01") and GUIRegisterMsg(0x0200, "_MouseMove") methods.

Using DllCallbackRegister(), as an after thought, could possibly be a better way of detecting mouse events. And, I am curious to know if the paint events can be handled also.

At this stage, the shapes not covered are the closed bezier curve and the closed curve. The pie shape could be used with the combination of _PointInEllipse() and NOT _PointInPoly(). And text has a defined rectangle which can be used.

I don't know if this is the best way for GDI+ graphics to be OnEvent sensitive. It is the only way I can think of. There always seems to be more than one way of doing the same thing.

The GUI has to be the active window for the toolTip to work correctly.

And, the shapes are able to be clicked.

#include <GuiConstantsEx.au3>
#include <GDIPlus.au3>
#include <WinAPI.au3>
#include <WindowsConstants.au3>
#include <Misc.au3>
#include <Constants.au3>

Opt('MustDeclareVars', 1)
Opt("MouseCoordMode", 2);1=absolute, 0=relative, 2=client
Opt("GUIOnEventMode", 1)

Global $hGUI, $hBMPBuff, $hGraphicGUI, $hGraphic, $wProcNew, $wProcOld
Global $aPoints[7][2], $aTriangle[5][2], $iCircleX, $iCircleY, $iCircleWidth, $iCircleHth
Global $hButton, $iElpsWidth, $iElpsHth, $iElpsX, $iElpsY, $iRectX, $iRectY, $iRectWidth, $iRectHth
Global $user32 = DllOpen("user32.dll")
_Main()

Func _Main()
    Local $msg, $aPos, $GuiSizeX = 400, $GuiSizeY = 300

; Create GUI
    $hGUI = GUICreate("GDI+ On Event", $GuiSizeX, $GuiSizeY)
    GUISetOnEvent($GUI_EVENT_CLOSE, "close")

    GUISetState()

    _GDIPlus_Startup()
;Double Buffer
    $hGraphicGUI = _GDIPlus_GraphicsCreateFromHWND($hGUI)
    $hBMPBuff = _GDIPlus_BitmapCreateFromGraphics($GuiSizeX, $GuiSizeY - 65, $hGraphicGUI)
    $hGraphic = _GDIPlus_ImageGetGraphicsContext($hBMPBuff)
;End Double Buffer add-on 1 of 3

    _GDIPlus_GraphicsClear($hGraphic, 0xFFE8FFEF)

    $aPoints[0][0] = 5; Number of  sides of Polygon
    $aPoints[1][0] = 100
    $aPoints[1][1] = 100
    $aPoints[2][0] = 200
    $aPoints[2][1] = 150
    $aPoints[3][0] = 200
    $aPoints[3][1] = 200
    $aPoints[4][0] = 150
    $aPoints[4][1] = 100
    $aPoints[5][0] = 70
    $aPoints[5][1] = 200
    $aPoints[6][0] = 100;Last point same as 1st point. Polygon is closed
    $aPoints[6][1] = 100
    _GDIPlus_GraphicsDrawPolygon($hGraphic, $aPoints)

    $iRectX = 220
    $iRectY = 25
    $iRectWidth = 100
    $iRectHth = 50
    _GDIPlus_GraphicsDrawRect($hGraphic, $iRectX, $iRectY, $iRectWidth, $iRectHth)

    $iElpsX = 220
    $iElpsY = 180
    $iElpsWidth = 130
    $iElpsHth = 70
    _GDIPlus_GraphicsDrawEllipse($hGraphic, $iElpsX, $iElpsY, $iElpsWidth, $iElpsHth)

    $aTriangle[0][0] = 3; Number of  sides of Polygon
    $aTriangle[1][0] = 30
    $aTriangle[1][1] = 30
    $aTriangle[2][0] = 150
    $aTriangle[2][1] = 40
    $aTriangle[3][0] = 50
    $aTriangle[3][1] = 100
    $aTriangle[4][0] = 30;Last point same as 1st point. Polygon is closed
    $aTriangle[4][1] = 30
    _GDIPlus_GraphicsDrawPolygon($hGraphic, $aTriangle)

    $hButton = GUICtrlCreateButton("In Circle", 22, 240, 75, 20)
    GUICtrlSetOnEvent($hButton, "_InCirle")
    $iCircleX = 20
    $iCircleY = 210
    $iCircleWidth = 80
    $iCircleHth = 80
    _GDIPlus_GraphicsDrawEllipse($hGraphic, $iCircleX, $iCircleY, $iCircleWidth, $iCircleHth)

; Create Double Buffer, doesn't need to be repainted on PAINT-Event
    GUIRegisterMsg(0xF, "MY_PAINT"); Register PAINT-Event 0x000F = $WM_PAINT (WindowsConstants.au3)
    GUIRegisterMsg(0x85, "MY_PAINT"); $WM_NCPAINT = 0x0085 (WindowsConstants.au3)Restore after Minimize.
    GUIRegisterMsg(0x0200, "_MouseMove"); For ToolTip
    _GDIPlus_GraphicsDrawImage($hGraphicGUI, $hBMPBuff, 0, 0)
;End Double Buffer add-on 2 of 3

    While 1
        Sleep(60)
        If _IsPressed("01", $user32) Then;And WinActive($hGUI) Then
            $aPos = MouseGetPos()
            Select
                Case _PointInPoly($aPos[0], $aPos[1], $aPoints)
                    ToolTip("")
                    MsgBox(0, "", "Clicked in PolyGon")
                Case _WinAPI_PtInRectEx($aPos[0], $aPos[1], $iRectX, $iRectY, $iRectX + $iRectWidth, _
                        $iRectY + $iRectHth)
                    ToolTip("")
                    MsgBox(0, "", "Clicked in Rectangle")
                Case _PointInEllipse($aPos[0], $aPos[1], $iElpsX, $iElpsY, $iElpsWidth, $iElpsHth)
                    ToolTip("")
                    MsgBox(0, "", "Clicked in Ellipse")
                Case _PointInPoly($aPos[0], $aPos[1], $aTriangle)
                    ToolTip("")
                    MsgBox(0, "", "Clicked in Triangle")
                Case _PointInEllipse($aPos[0], $aPos[1], $iCircleX, $iCircleY, $iCircleWidth, $iCircleHth)
                    ToolTip("")
                    MsgBox(0, "", "Clicked in Invisible Circle")
            EndSelect
            
        EndIf
    WEnd
EndFunc  ;==>_Main

Func _PointInEllipse($xPt, $yPt, $xTL, $yTL, $w, $h)
    Local $bInside = False, $a = $w / 2, $b = $h / 2
    Local $c1X, $c2X, $dist, $xc = $xTL + $a, $yc = $yTL + $b
    $c1X = $xc - ($a ^ 2 - $b ^ 2) ^ (1 / 2); 1st focal point x position
    $c2X = $xc + ($a ^ 2 - $b ^ 2) ^ (1 / 2); 2nd focal point x position
    $dist = (($xPt - $c1X) ^ 2 + ($yPt - $yc) ^ 2) ^ 0.5 + (($xPt - $c2X) ^ 2 + ($yPt - $yc) ^ 2) ^ 0.5
    If $dist <= $w Then $bInside = Not $bInside
    Return $bInside
EndFunc  ;==>_PointInEllipse

Func _WinAPI_PtInRectEx($iX, $iY, $iLeft, $iTop, $iRight, $iBottom)
    Local $aResult
    Local $tRect = DllStructCreate($tagRECT)
    DllStructSetData($tRect, "Left", $iLeft)
    DllStructSetData($tRect, "Top", $iTop)
    DllStructSetData($tRect, "Right", $iRight)
    DllStructSetData($tRect, "Bottom", $iBottom)
    $aResult = DllCall("User32.dll", "int", "PtInRect", "ptr", DllStructGetPtr($tRect), "int", $iX, "int", $iY)
    If @error Then Return SetError(@error, 0, False)
    Return $aResult[0] <> 0
EndFunc  ;==>_WinAPI_PtInRectEx

; Requires Iif()function
Func _PointInPoly($x, $y, $aPoints)
    Local $bEvenNum = False, $xOnLine, $yMin, $yMax
    For $i = 1 To $aPoints[0][0]
        $yMin = Iif($aPoints[$i + 1][1] < $aPoints[$i][1], $aPoints[$i + 1][1], $aPoints[$i][1])
        $yMax = Iif($aPoints[$i + 1][1] > $aPoints[$i][1], $aPoints[$i + 1][1], $aPoints[$i][1])
        $xOnLine = -($y * $aPoints[$i + 1][0] - $y * $aPoints[$i][0] - $aPoints[$i][1] * $aPoints[$i + 1][0] + _
                $aPoints[$i][0] * $aPoints[$i + 1][1]) / (-$aPoints[$i + 1][1] + $aPoints[$i][1])
        If ($x < $xOnLine) And ($y > $yMin) And ($y <= $yMax) Then $bEvenNum = Not $bEvenNum
    Next
    Return $bEvenNum
EndFunc  ;==>_PointInPoly

; Same as _Iif() function from Misc.au3 include file
Func Iif($fTest, $vTrueVal, $vFalseVal)
    If $fTest Then
        Return $vTrueVal
    Else
        Return $vFalseVal
    EndIf
EndFunc  ;==>Iif

;Func to redraw on PAINT MSG
Func MY_PAINT($hWnd, $msg, $wParam, $lParam)
; Check, if the GUI with the Graphic should be repainted
    _GDIPlus_GraphicsDrawImage($hGraphicGUI, $hBMPBuff, 0, 0)
    _WinAPI_RedrawWindow($hGUI, "", "", BitOR($RDW_INVALIDATE, $RDW_UPDATENOW, $RDW_FRAME));,$RDW_ALLCHILDREN
    Return $GUI_RUNDEFMSG
EndFunc  ;==>MY_PAINT

Func close()
    DllClose($user32)
    _GDIPlus_GraphicsDispose($hGraphic)
    _GDIPlus_GraphicsDispose($hGraphicGUI)
    _WinAPI_DeleteObject($hBMPBuff)
    _GDIPlus_Shutdown()
    Exit
EndFunc  ;==>close

Func _InCirle()
    MsgBox(0, "", "Button Pressed")
EndFunc  ;==>_InCirle

Func _MouseMove()
    Local $aPos = MouseGetPos()
    ToolTip("Mouse Position X:  " & $aPos[0] & "   Y: " & $aPos[1] & @CRLF & @CRLF & _
            "Cursor in Polygon: " & _PointInPoly($aPos[0], $aPos[1], $aPoints) & @CRLF & _
            "Cursor in Triangle: " & _PointInPoly($aPos[0], $aPos[1], $aTriangle) & @CRLF & _
            "Cursor in Ellipse: " & _PointInEllipse($aPos[0], $aPos[1], $iElpsX, $iElpsY, _
            $iElpsWidth, $iElpsHth) & @CRLF & _
            "Cursor in Circle: " & _PointInEllipse($aPos[0], $aPos[1], $iCircleX, $iCircleY, _
            $iCircleWidth, $iCircleHth) & @CRLF & _
            "Cursor in Rectangle: " & _WinAPI_PtInRectEx($aPos[0], $aPos[1], $iRectX, $iRectY, _
            $iRectX + $iRectWidth, $iRectY + $iRectHth) & @CRLF)

EndFunc  ;==>_MouseMove
Link to comment
Share on other sites

  • 3 weeks later...

@Malkey

Good script, I can see myself using this for collision detecting, but I am wondering, is there a reason to use a dll for the rectangle instead of pure math as the others?

Link to comment
Share on other sites

@Malkey

Good script, I can see myself using this for collision detecting, but I am wondering, is there a reason to use a dll for the rectangle instead of pure math as the others?

AdmiralAlkex

When determining whether a specified point lies within the specified rectangle, if the point is in a $tagPOINT structure, I would use the _WinAPI_PtInRect function from the WinAPI.au3 include file. The $tagPOINT structure is the data type returned from _WinAPI_GetMousePos.

Most times I use the built in function WinGetPos. So it was a no-brainer to copy the _WinAPI_PtInRect wrapper from the WinAPI.au3 file, modify it to accept WinGetPos type output, and call it _WinAPI_PtInRectEx.

Plus, I assumed rightly or wrongly, that by using the PtInRect function from the User32.dll file, this wrapper would operate faster than a mathematical approach.

Here, http://www.autoitscript.com/forum/index.ph...st&p=640845 , is a modified version of _WinAPI_PtInRectEx.using $iLeft, $iTop, $iWidth, $iHeight to define the rectangle. This made it easier to work with GUICtrlCreateButton by having the same parameters. Another no-brainer enhancement.

Malkey

Link to comment
Share on other sites

This is a very good script - I like it a lot. I could see at least 3 uses for it in my gui app. I'll play around with it and test out some scenarios.

Thanks mate.

My Projects: [topic="89413"]GoogleHack Search[/topic], [topic="67095"]Swiss File Knife GUI[/topic], [topic="69072"]Mouse Location Pointer[/topic], [topic="86040"]Standard Deviation Calculator[/topic]

Link to comment
Share on other sites

  • 1 year later...

I sometimes deal with enclosed shapes but they are often composed of a combination of straight lines and arc. There has been no function for deciding if a point is in an arc and I think I might need that.

I prefer to consider ellipses to be based on one center rather than two foci. Because of that I wrote a different way to detect a point is inside an ellipse. I also wanted different parameters to the ones Malkey developed so it doesn't fit in very well, and so below I have also included a function which uses the same parameters as Malkey's.

;IsPtInEllipse
;Returns True if inside else false
;point is at $x,$y
;centre of ellipse or circle is $Rx, $Ry
;Horizontal radius is $Rh, vertical radius is $Rv
;The "major" axis of the ellipse must be vertical or horizontal
;Author: martin
Func _IsPtInEllipse($x, $y, $rx, $ry, $rh, $rv)

    return ($x - $rx) ^ 2 + (($y - $ry) * $rh / $rv) ^ 2 < $rh ^ 2

EndFunc   ;==>_IsPtInEllipse

This one is compatible with Malkey's

Func _PointInEllipseB($xPt, $yPt, $xTL, $yTL, $w, $h);($x,$y,$rx,$ry,$rh,$rv)
    Local $rx = $xTL + $w / 2, $ry = $yTL + $h / 2

    return ($xPt - $rx) ^ 2 + (($yPt - $ry) * $w / $h) ^ 2 < $w ^ 2 / 4

EndFunc   ;==>_PointInEllipseB

I'm fairly sure they are ok but if they don't make sense then I can add some explanations.

This is my first attempt to detect a point is in an arc.

;is pt in arc
;Parameters $xPt, $yPt the coords of the point
;           $xR, $yR the centre of the arc
;           $Rad the arc radius
;           $StAngle, $EndAngle the start and end anglke in degrees
;Only deals with circular arcs though same approach can be used with elliptical arcs.
;The arc is drawn from start angle to end angle counter clockwise
;Returns True if a horizontal line draw from the point to the right cuts the arc
;  once, otherwise returns false
;Author - martin
Func _PointInEllipse($xPt, $yPt, $xTL, $yTL, $w, $h)
    Local $bInside = False, $a = $w / 2, $b = $h / 2
    Local $c1X, $c2X, $dist, $xc = $xTL + $a, $yc = $yTL + $b
    $c1X = $xc - ($a ^ 2 - $b ^ 2) ^ (1 / 2); 1st focal point x position
    $c2X = $xc + ($a ^ 2 - $b ^ 2) ^ (1 / 2); 2nd focal point x position
    $dist = (($xPt - $c1X) ^ 2 + ($yPt - $yc) ^ 2) ^ 0.5 + (($xPt - $c2X) ^ 2 + ($yPt - $yc) ^ 2) ^ 0.5
    If $dist <= $w Then $bInside = Not $bInside
    Return $bInside
EndFunc   ;==>_PointInEllipse

;IsPtInEllipse
;Returns True if inside else false
;point is at $x,$y
;centre of ellipse or circle is $Rx, $Ry
;Horizontal radius is $Rh, vertical radius is $Rv
;The "major" axis of the ellipse must be vertical or horizontal
;Author: martin
Func _IsPtInEllipse($x, $y, $rx, $ry, $rh, $rv)

    return ($x - $rx) ^ 2 + (($y - $ry) * $rh / $rv) ^ 2 < $rh ^ 2

EndFunc   ;==>_IsPtInEllipse

Func _PointInEllipseB($xPt, $yPt, $xTL, $yTL, $w, $h);($x,$y,$rx,$ry,$rh,$rv)
    Local $rx = $xTL + $w / 2, $ry = $yTL + $h / 2

    return ($xPt - $rx) ^ 2 + (($yPt - $ry) * $w / $h) ^ 2 < $w ^ 2 / 4

EndFunc   ;==>_PointInEllipseB


;is pt in arc
;Parameters $xPt, $yPt the coords of the point
;           $xR, $yR the centre of the arc
;           $Rad the arc radius
;           $StAngle, $EndAngle the start and end anglke in degrees
;Only deals with circular arcs though same approach can be used with elliptical arcs.
;The arc is drawn from start angle to end angle counter clockwise
;Returns True if a horizontal line draw from the point to the right cuts the arc
;  once, otherwise returns false
;Author - martin
Func _IsPtInArc($xPt, $yPt, $xR, $yR, $Rad, $StAngle, $EndAngle)
    Local $pi = 4 * ATan(1), $Alpha1, $Alpha2, $Result1 = False, $Result2 = False
    Local $Deg2Rad = $pi / 180

    ;ensure sensible angles
    While $StAngle > 360;2*$pi
        $StAngle -= 360;2*$pi
    WEnd

    While $EndAngle > 360;2*$pi
        $EndAngle -= 360;2*$pi
    WEnd

While $StAngle < 0
        $StAngle += 360;2*$pi
    WEnd

    While $EndAngle < 0;2*$pi
        $EndAngle += 360;2*$pi
    WEnd
    If $EndAngle <= $StAngle Then $EndAngle += 360;2*$pi



    ;check obvious cases
    If $xPt - $xR >= $Rad Then Return False
    If Abs($yPt - $yR) >= $Rad Then Return False


    ;find the angle to the point where horizontal line cuts the circle from centre of circle
    $Alpha1 = ASin(Abs(($yPt - $yR) / $Rad)) / $Deg2Rad
    Select
        Case $yPt <= $yR
            $Alpha2 = 180 - $Alpha1
        Case $yPt > $yR
            $Alpha2 = 360 - $Alpha1
            $Alpha1 = 180 + $Alpha1
    EndSelect


    If ($Alpha1 > $StAngle And $Alpha1 <= $EndAngle) Then
        $Result1 = $xPt < ($Rad * Cos($Alpha1 * $Deg2Rad) + $xR)

    EndIf

    If ($Alpha2 > $StAngle And $Alpha2 <= $EndAngle) Or _
            ($Alpha2 + 360 > $StAngle And $Alpha2 + 360 <= $EndAngle) Then
        $Result2 = $xPt < ($Rad * Cos($Alpha2 * $Deg2Rad) + $xR)
    EndIf

    Return BitXOR($Result1, $Result2) = 1


EndFunc   ;==>_IsPtInArc

I think this works.

There is a potential problem where the ends of one line can be counted as well as the start of the next line and this has to be avoided. Malkey has dealt with this problem in his functions but I am unsure how to deal with it with arcs. I think I would have the array of lines organised so that from the start to the end of the array the lines would all be in the correct order and the correct direction so that a pen could draw them in turn without needing to be lifted. In that case I would say the start point of each line is ignored and the end point of each line is not ignored, or vica versa. This means that the function I showed would have to be developed to deal with clockwise and counter clockwise arcs.

[waffle]

My interest is in routing, or rather I'm thinking about making a routing machine. If I need to route a hole then I need to know the diameter of the tool (ToolDia) and create a path for the tool which is ToolDia/2 inside the required shape. So I need to know that the points I am choosing are inside the finished shape. If I'm routing the outside edges of something then I need to choose points which are outside the shape of course.

[/waffle]**

In case anyone wants to try out the functions above, here is a copy of Malkey's example in his first post in this thread with some bits added which I did for testing.

;by Malkey see http://www.autoitscript.com/forum/index....=&showtopic=89034&view=findpos
#include <GuiConstantsEx.au3>
#include <GDIPlus.au3>
#include <WinAPI.au3>
#include <WindowsConstants.au3>
Global $a1, $a2
Opt('MustDeclareVars', 1)
Opt("MouseCoordMode", 2);1=absolute, 0=relative, 2=client

Global $hGUI, $hBMPBuff, $hGraphicGUI, $hGraphic

_Main()

Func _Main()
    Local $msg, $aPos, $GuiSizeX = 400, $GuiSizeY = 300
    Local $aPoints[7][2], $aTriangle[5][2]
    Local $hButton
    ; Create GUI
    $hGUI = GUICreate("GDI+", $GuiSizeX, $GuiSizeY)

    GUISetState()

    _GDIPlus_Startup()
    ;Double Buffer
    $hGraphicGUI = _GDIPlus_GraphicsCreateFromHWND($hGUI)
    $hBMPBuff = _GDIPlus_BitmapCreateFromGraphics($GuiSizeX, $GuiSizeY, $hGraphicGUI)
    $hGraphic = _GDIPlus_ImageGetGraphicsContext($hBMPBuff)
    ;End Double Buffer add-on 1 of 3

    _GDIPlus_GraphicsClear($hGraphic, 0xFFE8FFEF)

    $aPoints[0][0] = 5; Number of  sides of Polygon
    $aPoints[1][0] = 100
    $aPoints[1][1] = 100;
    $aPoints[2][0] = 200
    $aPoints[2][1] = 80;
    $aPoints[3][0] = 200
    $aPoints[3][1] = 200;
    $aPoints[4][0] = 100
    $aPoints[4][1] = 170;
    $aPoints[5][0] = 170
    $aPoints[5][1] = 140;
    $aPoints[6][0] = 100;Last point same as 1st point. Polygon is closed
    $aPoints[6][1] = 100
    _GDIPlus_GraphicsDrawPolygon($hGraphic, $aPoints)

    Local $iRectX = 220, $iRectY = 25, $iRectWidth = 100, $iRectHth = 50
    _GDIPlus_GraphicsDrawRect($hGraphic, $iRectX, $iRectY, $iRectWidth, $iRectHth)

    Local $iElpsX = 220, $iElpsY = 180, $iElpsWidth = 130, $iElpsHth = 70
    _GDIPlus_GraphicsDrawEllipse($hGraphic, $iElpsX, $iElpsY, $iElpsWidth, $iElpsHth)

    $aTriangle[0][0] = 3; Number of  sides of Polygon
    $aTriangle[1][0] = 30
    $aTriangle[1][1] = 30
    $aTriangle[2][0] = 150
    $aTriangle[2][1] = 40
    $aTriangle[3][0] = 50
    $aTriangle[3][1] = 100
    $aTriangle[4][0] = 30;Last point same as 1st point. Polygon is closed
    $aTriangle[4][1] = 30
    _GDIPlus_GraphicsDrawPolygon($hGraphic, $aTriangle)

    $hButton = GUICtrlCreateButton("In Circle", 22, 240, 75, 20)

    Local $iCircleX = 20, $iCircleY = 210, $iCircleWidth = 80, $iCircleHth = 80
    _GDIPlus_GraphicsDrawEllipse($hGraphic, $iCircleX, $iCircleY, $iCircleWidth, $iCircleHth)

    Local $iCircleX = 20, $iCircleY = 210, $iCircleWidth = 80, $iCircleHth = 80
    _GDIPlus_GraphicsDrawArc($hGraphic, $iCircleX + 220, $iCircleY - 110, $iCircleWidth, $iCircleHth, -30, -170)


    ConsoleWrite("Area of Polygon = " & _AreaPoly($aPoints) & @CRLF)
    Local $aCent = _CentroidPoly($aPoints)
    ConsoleWrite("Centroid of Polygon:  cX = " & $aCent[0] & "   cY = " & $aCent[1] & @CRLF)

    ; Create Double Buffer, doesn't need to be repainted on PAINT-Event
    GUIRegisterMsg(0xF, "MY_PAINT"); Register PAINT-Event 0x000F = $WM_PAINT (WindowsConstants.au3)
    GUIRegisterMsg(0x85, "MY_PAINT"); $WM_NCPAINT = 0x0085 (WindowsConstants.au3)Restore after Minimize.
    _GDIPlus_GraphicsDrawImage($hGraphicGUI, $hBMPBuff, 0, 0)
    ;End Double Buffer add-on 2 of 3

    While 1
        $msg = GUIGetMsg()
        Switch $msg
            Case $GUI_EVENT_CLOSE
                _GDIPlus_GraphicsDispose($hGraphic)
                _GDIPlus_GraphicsDispose($hGraphicGUI)
                _WinAPI_DeleteObject($hBMPBuff)
                _GDIPlus_Shutdown()
                Exit
            Case $hButton
                MsgBox(0, "", "Button Pressed. ")
            Case $GUI_EVENT_MOUSEMOVE
                $aPos = MouseGetPos()
                ToolTip("Mouse Position X:  " & $aPos[0] & "   Y: " & $aPos[1] & @CRLF & @CRLF & _
                        "Cursor in Polygon: " & _PointInPoly($aPos[0], $aPos[1], $aPoints) & @CRLF & _
                        "" & _  ;"Cursor in Triangle: " & _PointInPoly($aPos[0], $aPos[1], $aTriangle) & @CRLF & _
                        "Cursor in Ellipse: " & _PointInEllipseB($aPos[0], $aPos[1], $iElpsX, $iElpsY, _
                        $iElpsWidth, $iElpsHth) & @CRLF & _
                        "Cursor in mgEllipse: " & _IsPtInEllipse($aPos[0], $aPos[1], $iElpsX + $iElpsWidth / 2, $iElpsY + $iElpsHth / 2, _
                        $iElpsWidth / 2, $iElpsHth / 2) & @CRLF & _
                        "Cursor in Circle: " & _PointInEllipseB($aPos[0], $aPos[1], $iCircleX, $iCircleY, _
                        $iCircleWidth, $iCircleHth) & @CRLF & _
                        "Cursor in mgCircle: " & _IsPtInEllipse($aPos[0], $aPos[1], $iCircleX + $iCircleWidth / 2, $iCircleY + $iCircleHth / 2, _
                        $iCircleWidth / 2, $iCircleHth / 2) & @CRLF & _
                        "Cursor in Rectangle: " & _WinAPI_PtInRectEx($aPos[0], $aPos[1], $iRectX, $iRectY, _
                        $iRectX + $iRectWidth, $iRectY + $iRectHth) & @CRLF & _
                        "Cursor in Arc: " & _IsPtInArc($aPos[0], $aPos[1], 220 + $iCircleX + $iCircleWidth / 2, $iCircleY + $iCircleHth / 2 - 110, _
                        $iCircleWidth / 2, 30, 200))

            Case $GUI_EVENT_PRIMARYUP
                $aPos = MouseGetPos()
                Select
                    Case _PointInPoly($aPos[0], $aPos[1], $aPoints)
                        ToolTip("")
                        MsgBox(0, "", "Clicked in PolyGon")
                    Case _WinAPI_PtInRectEx($aPos[0], $aPos[1], $iRectX, $iRectY, $iRectX + $iRectWidth, _
                            $iRectY + $iRectHth)
                        ToolTip("")
                        MsgBox(0, "", "Clicked in Rectangle")
                    Case _PointInEllipse($aPos[0], $aPos[1], $iElpsX, $iElpsY, $iElpsWidth, $iElpsHth)
                        ToolTip("")
                        MsgBox(0, "", "Clicked in Ellipse")
                    Case _PointInPoly($aPos[0], $aPos[1], $aTriangle)
                        ToolTip("")
                        MsgBox(0, "", "Clicked in Triangle")
                    Case _PointInEllipse($aPos[0], $aPos[1], $iCircleX, $iCircleY, $iCircleWidth, $iCircleHth)
                        ToolTip("")
                        MsgBox(0, "", "Clicked in Invisible Circle")

                EndSelect
        EndSwitch
    WEnd
EndFunc   ;==>_Main

; Returns the area of a polygon
Func _AreaPoly($aPoints)
    Local $Med
    For $n = 1 To UBound($aPoints) - 2
        $Med += $aPoints[$n][0] * $aPoints[$n + 1][1] - $aPoints[$n + 1][0] * $aPoints[$n][1]
    Next
    Return $Med / 2
EndFunc   ;==>_AreaPoly

; Returns an array containing the x, y position of the centroid of a polygon.
Func _CentroidPoly($aPoints)
    Local $Med, $aRet[2], $MedX, $MedY, $Area
    For $n = 1 To UBound($aPoints) - 2
        $MedX += ($aPoints[$n][0] + $aPoints[$n + 1][0]) * ($aPoints[$n][0] * $aPoints[$n + 1][1] - _
                $aPoints[$n + 1][0] * $aPoints[$n][1])
        $MedY += ($aPoints[$n][1] + $aPoints[$n + 1][1]) * ($aPoints[$n][0] * $aPoints[$n + 1][1] - _
                $aPoints[$n + 1][0] * $aPoints[$n][1])
    Next
    $Area = _AreaPoly($aPoints)
    $aRet[0] = $MedX / ($Area * 6)
    $aRet[1] = $MedY / ($Area * 6)
    Return $aRet
EndFunc   ;==>_CentroidPoly

; ($xPt, $yPt) - x, y position of the point to check
;  $xTL, $yTL,  Top left x Pos, top left Y position of the rectangle encompassing the ellipse.
; $w, $h - The width an height of ellipse
; Method: The distance from the 1st focal point to a point on the perimeter plus the distance from
; the second focal point to the same point on the perimeter is a constant and equals the width of
; the ellipse, the major axis. So, if the sum of the two distances form the point to check to the
; two foci is greater than the major axis, then the point is outside the ellipse.
Func _PointInEllipse($xPt, $yPt, $xTL, $yTL, $w, $h)
    Local $bInside = False, $a = $w / 2, $b = $h / 2
    Local $c1X, $c2X, $dist, $xc = $xTL + $a, $yc = $yTL + $b
    $c1X = $xc - ($a ^ 2 - $b ^ 2) ^ (1 / 2); 1st focal point x position
    $c2X = $xc + ($a ^ 2 - $b ^ 2) ^ (1 / 2); 2nd focal point x position
    $dist = (($xPt - $c1X) ^ 2 + ($yPt - $yc) ^ 2) ^ 0.5 + (($xPt - $c2X) ^ 2 + ($yPt - $yc) ^ 2) ^ 0.5
    If $dist <= $w Then $bInside = Not $bInside
    Return $bInside
EndFunc   ;==>_PointInEllipse

;IsPtInEllipse
;Returns True if inside else false
;point is at $x,$y
;centre of ellipse or circle is $Rx, $Ry
;Horizontal radius is $Rh, vertical radius is $Rv
;The "major" axis of the ellipse must be vertical or horizontal
;Author: martin
Func _IsPtInEllipse($x, $y, $rx, $ry, $rh, $rv)

    return ($x - $rx) ^ 2 + (($y - $ry) * $rh / $rv) ^ 2 < $rh ^ 2

EndFunc   ;==>_IsPtInEllipse

Func _PointInEllipseB($xPt, $yPt, $xTL, $yTL, $w, $h);($x,$y,$rx,$ry,$rh,$rv)
    Local $rx = $xTL + $w / 2, $ry = $yTL + $h / 2

    return ($xPt - $rx) ^ 2 + (($yPt - $ry) * $w / $h) ^ 2 < $w ^ 2 / 4

EndFunc   ;==>_PointInEllipseB





;is pt in arc
;Parameters $xPt, $yPt the coords of the point
;           $xR, $yR the centre of the arc
;           $Rad the arc radius
;           $StAngle, $EndAngle the start and end anglke in degrees
;Only deals with circular arcs though same approach can be used with elliptical arcs.
;The arc is drawn from start angle to end angle counter clockwise
;Returns True if a horizontal line draw from the point to the right cuts the arc
;  once, otherwise returns false
;Author - martin
Func _IsPtInArc($xPt, $yPt, $xR, $yR, $Rad, $StAngle, $EndAngle)
    Local $pi = 4 * ATan(1), $Alpha1, $Alpha2, $Result1 = False, $Result2 = False
    Local $Deg2Rad = $pi / 180

    ;ensure sensible angles
    While $StAngle > 360;2*$pi
        $StAngle -= 360;2*$pi
    WEnd

    While $EndAngle > 360;2*$pi
        $EndAngle -= 360;2*$pi
    WEnd

 While $StAngle < 0
        $StAngle += 360;2*$pi
    WEnd

    While $EndAngle < 0;2*$pi
        $EndAngle += 360;2*$pi
    WEnd
    If $EndAngle <= $StAngle Then $EndAngle += 360;2*$pi



    ;check obvious cases
    If $xPt - $xR >= $Rad Then Return False
    If Abs($yPt - $yR) >= $Rad Then Return False


    ;find the angle to the point where horizontal line cuts the circle from centre of circle
    $Alpha1 = ASin(Abs(($yPt - $yR) / $Rad)) / $Deg2Rad
    Select
        Case $yPt <= $yR
            $Alpha2 = 180 - $Alpha1
        Case $yPt > $yR
            $Alpha2 = 360 - $Alpha1
            $Alpha1 = 180 + $Alpha1
    EndSelect


    If ($Alpha1 > $StAngle And $Alpha1 <= $EndAngle) Then
        $Result1 = $xPt < ($Rad * Cos($Alpha1 * $Deg2Rad) + $xR)

    EndIf

    If ($Alpha2 > $StAngle And $Alpha2 <= $EndAngle) Or _
            ($Alpha2 + 360 > $StAngle And $Alpha2 + 360 <= $EndAngle) Then
        $Result2 = $xPt < ($Rad * Cos($Alpha2 * $Deg2Rad) + $xR)
    EndIf

    Return BitXOR($Result1, $Result2) = 1


EndFunc   ;==>_IsPtInArc



; ($iX, $iY)        - x, y position of the point to check
; ($iLeft, $iTop)   - x, y position of the top left corner of rectangle
; ($iRight, $iBottom) - x, y position of the bottom right corner of rectangle
;
Func _WinAPI_PtInRectEx($iX, $iY, $iLeft, $iTop, $iRight, $iBottom)
    Local $aResult
    Local $tRect = DllStructCreate($tagRECT)
    DllStructSetData($tRect, "Left", $iLeft)
    DllStructSetData($tRect, "Top", $iTop)
    DllStructSetData($tRect, "Right", $iRight)
    DllStructSetData($tRect, "Bottom", $iBottom)
    $aResult = DllCall("User32.dll", "int", "PtInRect", "ptr", DllStructGetPtr($tRect), "int", $iX, "int", $iY)
    If @error Then Return SetError(@error, 0, False)
    Return $aResult[0] <> 0
EndFunc   ;==>_WinAPI_PtInRectEx

; ($x, $y)          - x, y position of the point to check
; $aPoints - An array of x,y values representing the nodes of a polygon.
; Finds the individual x values of the interestion of the individual sides of the polygon with the
; line y = $y (parallel with x-axis). If the number of x values found greater than $x is even, then
; the ($x, $y) point is outside the closed polygon. Plus, if $y is beyond the y values of the end
; points of individual sides of the polygon, the y = $y line will not interest with that side and will
; not be counted. Returns equivalent of, even number of intersections false, and, odd true(inside polygon).
; Requires Iif()function
Func _PointInPoly($x, $y, $aPoints)
    Local $iNumOfXs, $xOnLine, $yMin, $yMax, $sXIntersects = " "
    For $i = 1 To $aPoints[0][0]
        $yMin = Iif($aPoints[$i + 1][1] < $aPoints[$i][1], $aPoints[$i + 1][1], $aPoints[$i][1])
        $yMax = Iif($aPoints[$i + 1][1] > $aPoints[$i][1], $aPoints[$i + 1][1], $aPoints[$i][1])
        $xOnLine = -($y * $aPoints[$i + 1][0] - $y * $aPoints[$i][0] - $aPoints[$i][1] * $aPoints[$i + 1][0] + _
                $aPoints[$i][0] * $aPoints[$i + 1][1]) / (-$aPoints[$i + 1][1] + $aPoints[$i][1])
        ; If ($x < $xOnLine) And ($y > $yMin) And ($y <= $yMax) And (($y <> $yMin) Or _
        ;       (StringInStr($sXIntersects, $xOnLine) = 0)) Then $sXIntersects &= $xOnLine & ","
        If ($x < $xOnLine) And ($y >= $yMin) And ($y < $yMax) Then $sXIntersects &= $xOnLine & ","
    Next
    StringReplace($sXIntersects, ",", ",")
    $iNumOfXs = @extended
    Return Iif(Mod($iNumOfXs, 2) = 0, False, True)
EndFunc   ;==>_PointInPoly

; Same as _Iif() function from Misc.au3 include file
Func Iif($fTest, $vTrueVal, $vFalseVal)
    If $fTest Then
        Return $vTrueVal
    Else
        Return $vFalseVal
    EndIf
EndFunc   ;==>Iif

;Func to redraw on PAINT MSG
Func MY_PAINT($hWnd, $msg, $wParam, $lParam)
    ; Check, if the GUI with the Graphic should be repainted
    _GDIPlus_GraphicsDrawImage($hGraphicGUI, $hBMPBuff, 0, 0)
    _WinAPI_RedrawWindow($hGUI, "", "", BitOR($RDW_INVALIDATE, $RDW_UPDATENOW, $RDW_FRAME));,$RDW_ALLCHILDREN
    Return $GUI_RUNDEFMSG
EndFunc   ;==>MY_PAINT

** Maybe "waffle" is not understood outside the UK, so the definition that matches my understanding is

British informal - to talk or write using a lot of words but without saying anything interesting or important.

EDIT:

Corrected double pasting of functions into script.

EDIT 2: See post 21 for a later, hopefully better, version of _IsPtInArc.

Edited by martin
Serial port communications UDF Includes functions for binary transmission and reception.printing UDF Useful for graphs, forms, labels, reports etc.Add User Call Tips to SciTE for functions in UDFs not included with AutoIt and for your own scripts.Functions with parameters in OnEvent mode and for Hot Keys One function replaces GuiSetOnEvent, GuiCtrlSetOnEvent and HotKeySet.UDF IsConnected2 for notification of status of connected state of many urls or IPs, without slowing the script.
Link to comment
Share on other sites

[waffle]

Looking at the bigger picture, when _IspointLeftOfLine() function is created, it would be possible to tell if a point is inside a valid shape constructed with connecting lines and arcs using :-

BitXOR(_IspointLeftOfLine(...), _IsPtInArc(...), _IspointLeftOfLine(...)) , a possible pie shape example.

BitXOR would be used to join the individual building blocks of the shape together, like arc, bezier, curve and/or line (when they all exits).

To add a little more complexity, the individual completed shapes can be combined using BitXOR, BitOR, and BitAND.

Example

#include <GuiConstantsEx.au3>
#include <GDIPlus.au3>
#include <WinAPI.au3>
#include <WindowsConstants.au3>
Global $a1, $a2
Opt('MustDeclareVars', 1)
Opt("MouseCoordMode", 2);1=absolute, 0=relative, 2=client

Global $hGUI, $hBMPBuff, $hGraphicGUI, $hGraphic

_Main()

Func _Main()
    Local $msg, $aPos, $GuiSizeX = 400, $GuiSizeY = 300
    Local $aPoints[7][2]
    ; Create GUI
    $hGUI = GUICreate("Combining Shapes", $GuiSizeX, $GuiSizeY)

    GUISetState()

    _GDIPlus_Startup()
    ;Double Buffer
    $hGraphicGUI = _GDIPlus_GraphicsCreateFromHWND($hGUI)
    $hBMPBuff = _GDIPlus_BitmapCreateFromGraphics($GuiSizeX, $GuiSizeY, $hGraphicGUI)
    $hGraphic = _GDIPlus_ImageGetGraphicsContext($hBMPBuff)
    ;End Double Buffer add-on 1 of 3

    _GDIPlus_GraphicsClear($hGraphic, 0xFFE8FFEF)

    $aPoints[0][0] = 5; Number of  sides of Polygon
    $aPoints[1][0] = 100
    $aPoints[1][1] = 100;
    $aPoints[2][0] = 200
    $aPoints[2][1] = 80;
    $aPoints[3][0] = 200
    $aPoints[3][1] = 200;
    $aPoints[4][0] = 100
    $aPoints[4][1] = 170;
    $aPoints[5][0] = 170
    $aPoints[5][1] = 140;
    $aPoints[6][0] = 100;Last point same as 1st point. Polygon is closed
    $aPoints[6][1] = 100
    _GDIPlus_GraphicsDrawPolygon($hGraphic, $aPoints)

    Local $iRectX = 135, $iRectY = 108, $iRectWidth = 100, $iRectHth = 50
    _GDIPlus_GraphicsDrawRect($hGraphic, $iRectX, $iRectY, $iRectWidth, $iRectHth)

    ; Create Double Buffer, doesn't need to be repainted on PAINT-Event
    GUIRegisterMsg(0xF, "MY_PAINT"); Register PAINT-Event 0x000F = $WM_PAINT (WindowsConstants.au3)
    GUIRegisterMsg(0x85, "MY_PAINT"); $WM_NCPAINT = 0x0085 (WindowsConstants.au3)Restore after Minimize.
    _GDIPlus_GraphicsDrawImage($hGraphicGUI, $hBMPBuff, 0, 0)
    ;End Double Buffer add-on 2 of 3

    While 1
        $msg = GUIGetMsg()
        Switch $msg
            Case $GUI_EVENT_CLOSE
                _GDIPlus_GraphicsDispose($hGraphic)
                _GDIPlus_GraphicsDispose($hGraphicGUI)
                _WinAPI_DeleteObject($hBMPBuff)
                _GDIPlus_Shutdown()
                Exit

            Case $GUI_EVENT_MOUSEMOVE
                $aPos = MouseGetPos()
                ToolTip("Mouse Position X:  " & $aPos[0] & "   Y: " & $aPos[1] & @CRLF & @CRLF & _
                        "Cursor in Polygon: " & _PointInPoly($aPos[0], $aPos[1], $aPoints) & @CRLF & _
                        "Cursor in Rectangle: " & _WinAPI_PtInRectEx($aPos[0], $aPos[1], $iRectX, $iRectY, _
                        $iRectX + $iRectWidth, $iRectY + $iRectHth) & @CRLF & _
                        "Cursor in BitXor(Rectangle,Polygon) : " & (BitXOR(_WinAPI_PtInRectEx($aPos[0], $aPos[1], $iRectX, $iRectY, $iRectX + $iRectWidth, $iRectY + $iRectHth), _
                        _PointInPoly($aPos[0], $aPos[1], $aPoints)) = 1) & @CRLF & _
                        "Cursor in BitOR(Rectangle,Polygon) : " & (BitOR(_WinAPI_PtInRectEx($aPos[0], $aPos[1], $iRectX, $iRectY, $iRectX + $iRectWidth, $iRectY + $iRectHth), _
                        _PointInPoly($aPos[0], $aPos[1], $aPoints)) = 1) & @CRLF & _
                        "Cursor in BitAND(Rectangle,Polygon) : " & (BitAND(_WinAPI_PtInRectEx($aPos[0], $aPos[1], $iRectX, $iRectY, $iRectX + $iRectWidth, $iRectY + $iRectHth), _
                        _PointInPoly($aPos[0], $aPos[1], $aPoints)) = 1))
        EndSwitch
    WEnd
EndFunc   ;==>_Main


; ($iX, $iY)        - x, y position of the point to check
; ($iLeft, $iTop)   - x, y position of the top left corner of rectangle
; ($iRight, $iBottom) - x, y position of the bottom right corner of rectangle
;
Func _WinAPI_PtInRectEx($iX, $iY, $iLeft, $iTop, $iRight, $iBottom)
    Local $aResult
    Local $tRect = DllStructCreate($tagRECT)
    DllStructSetData($tRect, "Left", $iLeft)
    DllStructSetData($tRect, "Top", $iTop)
    DllStructSetData($tRect, "Right", $iRight)
    DllStructSetData($tRect, "Bottom", $iBottom)
    $aResult = DllCall("User32.dll", "int", "PtInRect", "ptr", DllStructGetPtr($tRect), "int", $iX, "int", $iY)
    If @error Then Return SetError(@error, 0, False)
    Return $aResult[0] <> 0
EndFunc   ;==>_WinAPI_PtInRectEx

; ($x, $y)          - x, y position of the point to check
; $aPoints - An array of x,y values representing the nodes of a polygon.
; Finds the individual x values of the intersection of the individual sides of the polygon with the
; line y = $y (parallel with x-axis). If the number of x values found greater than $x is even, then
; the ($x, $y) point is outside the closed polygon. Plus, if $y is beyond the y values of the end
; points of individual sides of the polygon, the y = $y line will not interest with that side and will
; not be counted. Returns equivalent of, even number of intersections false, and, odd true(inside polygon).
; Requires Iif()function
Func _PointInPoly($x, $y, $aPoints)
    Local $iNumOfXs, $xOnLine, $yMin, $yMax, $sXIntersects = " "
    For $i = 1 To $aPoints[0][0]
        $yMin = Iif($aPoints[$i + 1][1] < $aPoints[$i][1], $aPoints[$i + 1][1], $aPoints[$i][1])
        $yMax = Iif($aPoints[$i + 1][1] > $aPoints[$i][1], $aPoints[$i + 1][1], $aPoints[$i][1])
        $xOnLine = -($y * $aPoints[$i + 1][0] - $y * $aPoints[$i][0] - $aPoints[$i][1] * $aPoints[$i + 1][0] + _
                $aPoints[$i][0] * $aPoints[$i + 1][1]) / (-$aPoints[$i + 1][1] + $aPoints[$i][1])
        ; If ($x < $xOnLine) And ($y > $yMin) And ($y <= $yMax) And (($y <> $yMin) Or _
        ;       (StringInStr($sXIntersects, $xOnLine) = 0)) Then $sXIntersects &= $xOnLine & ","
        If ($x < $xOnLine) And ($y >= $yMin) And ($y < $yMax) Then $sXIntersects &= $xOnLine & ","
    Next
    StringReplace($sXIntersects, ",", ",")
    $iNumOfXs = @extended
    Return Iif(Mod($iNumOfXs, 2) = 0, False, True)
EndFunc   ;==>_PointInPoly

; Same as _Iif() function from Misc.au3 include file
Func Iif($fTest, $vTrueVal, $vFalseVal)
    If $fTest Then
        Return $vTrueVal
    Else
        Return $vFalseVal
    EndIf
EndFunc   ;==>Iif

;Func to redraw on PAINT MSG
Func MY_PAINT($hWnd, $msg, $wParam, $lParam)
    ; Check, if the GUI with the Graphic should be repainted
    _GDIPlus_GraphicsDrawImage($hGraphicGUI, $hBMPBuff, 0, 0)
    _WinAPI_RedrawWindow($hGUI, "", "", BitOR($RDW_INVALIDATE, $RDW_UPDATENOW, $RDW_FRAME));,$RDW_ALLCHILDREN
    Return $GUI_RUNDEFMSG
EndFunc   ;==>MY_PAINT

[Prerequisite]

A mental picture that is required is imagine a point traveling in a horizontal line to the right. If the point crosses a shape's boundary once or an odd number of times then the point is inside the shape.

If the point crosses a shape's boundary no times, twice or an even number of times then the point is outside the shape.

A point traveling to the left, up, or down also works, but the maths is different.

BitXOR(0, 0, 0) = 0
BitXOR(0, 0, 1) = 1
BitXOR(0, 1, 0) = 1
BitXOR(0, 1, 1) = 0
BitXOR(1, 0, 0) = 1
BitXOR(1, 0, 1) = 0
BitXOR(1, 1, 0) = 0
BitXOR(1, 1, 1) = 1

BitOR(0, 0) = 0
BitOR(0, 1) = 1
BitOR(1, 0) = 1
BitOR(1, 1) = 1

BitAND(0, 0) = 0
BitAND(0, 1) = 0
BitAND(1, 0) = 0
BitAND(1, 1) = 1

[script comment]

Try Mod()

Local $StAngle = 2841
While $StAngle > 360;2*$pi
    $StAngle -= 360;2*$pi
WEnd
ConsoleWrite($StAngle & @CRLF)

; or

Local $StAngle = 2841
$StAngle = Mod($StAngle, 360)
ConsoleWrite($StAngle & @CRLF)

[To Martin]

Your routing machine waffle adds a different slant, more meaning, to this thread.

Any ideas on a line function?

Malkey

Link to comment
Share on other sites

..

...

[To Martin]

Any ideas on a line function?

Malkey

I'll study your post when I have more time - it looks like some thinking might be needed which always slows me down.

When you say "a line function" I assume you mean some way to describe a line like a Bezier curve? ( Which I know almost nothing about.)

Serial port communications UDF Includes functions for binary transmission and reception.printing UDF Useful for graphs, forms, labels, reports etc.Add User Call Tips to SciTE for functions in UDFs not included with AutoIt and for your own scripts.Functions with parameters in OnEvent mode and for Hot Keys One function replaces GuiSetOnEvent, GuiCtrlSetOnEvent and HotKeySet.UDF IsConnected2 for notification of status of connected state of many urls or IPs, without slowing the script.
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...