Malkey Posted February 5, 2009 Share Posted February 5, 2009 (edited) 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 functionsThe _CentroidPoly() function which returns the x, y position of the centroid of a polygon, andthe _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. expandcollapse popup#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 athttp://www.autoitscript.com/forum/index.ph...st&p=639811 Edit:8thFeb2008Changed _PointInPoly() to correct wrong return when the conditions point out by martin, post#5, occurred.Edit:8thFeb2008 10hr laterChanged _PointInPoly() to correct wrong return when the conditions point out by martin, post#7, occurred.Edit:8thFeb2008Changed _PointInPoly() to simplify conditional statement as mentioned in posts #9 and #10. Edited December 11, 2015 by Malkey _WinAPI_PtInRectEx was duplicated. "A" added to overcome duplication. jaberwacky 1 Link to comment Share on other sites More sharing options...
Moderators Melba23 Posted February 5, 2009 Moderators Share Posted February 5, 2009 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 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 columnsChooseFileFolder ---- Single and multiple selections from specified path treeview listingDate_Time_Convert -- Easily convert date/time formats, including the language usedExtMsgBox --------- A highly customisable replacement for MsgBoxGUIExtender -------- Extend and retract multiple sections within a GUIGUIFrame ---------- Subdivide GUIs into many adjustable framesGUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView itemsGUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeViewMarquee ----------- Scrolling tickertape GUIsNoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxesNotify ------------- Small notifications on the edge of the displayScrollbars ----------Automatically sized scrollbars with a single commandStringSize ---------- Automatically size controls to fit textToast -------------- Small GUIs which pop out of the notification area Link to comment Share on other sites More sharing options...
UEZ Posted February 5, 2009 Share Posted February 5, 2009 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 More sharing options...
Malkey Posted February 7, 2009 Author Share Posted February 7, 2009 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.UEZI 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.expandcollapse popup; 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 More sharing options...
martin Posted February 7, 2009 Share Posted February 7, 2009 (edited) 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 February 7, 2009 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 More sharing options...
Malkey Posted February 7, 2009 Author Share Posted February 7, 2009 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 More sharing options...
martin Posted February 7, 2009 Share Posted February 7, 2009 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 More sharing options...
Malkey Posted February 8, 2009 Author Share Posted February 8, 2009 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.martinYou 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 More sharing options...
martin Posted February 8, 2009 Share Posted February 8, 2009 (edited) 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 February 8, 2009 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 More sharing options...
trancexx Posted February 8, 2009 Share Posted February 8, 2009 If that's so, then it could be handled like this maybe: If ($x < $xOnLine) And ($y > $yMin) And ($y <= $yMax) Then $sXIntersects += 1 ;Next $iNumOfXs = $sXIntersects ;Return Iif(Mod($iNumOfXs, 2) = 0, False, True) ♡♡♡ . eMyvnE Link to comment Share on other sites More sharing options...
BrettF Posted February 8, 2009 Share Posted February 8, 2009 Sweet! Great job! Brett Vist my blog!UDFs: Opens The Default Mail Client | _LoginBox | Convert Reg to AU3 | BASS.au3 (BASS.dll) (Includes various BASS Libraries) | MultiLang.au3 (Multi-Language GUIs!)Example Scripts: Computer Info Telnet Server | "Secure" HTTP Server (Based on Manadar's Server)Software: AAMP- Advanced AutoIt Media Player | WorldCam | AYTU - Youtube Uploader Tutorials: Learning to Script with AutoIt V3Projects (Hardware + AutoIt): ArduinoUseful Links: AutoIt 1-2-3 | The AutoIt Downloads Section: | SciTE4AutoIt3 Full Version! Link to comment Share on other sites More sharing options...
Malkey Posted February 8, 2009 Author Share Posted February 8, 2009 Nice and simple. That's great. Updated first post. Link to comment Share on other sites More sharing options...
Malkey Posted February 20, 2009 Author Share Posted February 20, 2009 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. expandcollapse popup#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 More sharing options...
AdmiralAlkex Posted March 9, 2009 Share Posted March 9, 2009 @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? .Some of my scripts: ShiftER, Codec-Control, Resolution switcher for HTC ShiftSome of my UDFs: SDL UDF, SetDefaultDllDirectories, Converting GDI+ Bitmap/Image to SDL Surface Link to comment Share on other sites More sharing options...
Malkey Posted March 10, 2009 Author Share Posted March 10, 2009 @MalkeyGood 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?AdmiralAlkexWhen 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 More sharing options...
AdmiralAlkex Posted March 10, 2009 Share Posted March 10, 2009 You doesn't seem to like brains . But seriously, thank you very much, I get it now. .Some of my scripts: ShiftER, Codec-Control, Resolution switcher for HTC ShiftSome of my UDFs: SDL UDF, SetDefaultDllDirectories, Converting GDI+ Bitmap/Image to SDL Surface Link to comment Share on other sites More sharing options...
Ealric Posted March 10, 2009 Share Posted March 10, 2009 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 More sharing options...
martin Posted March 8, 2011 Share Posted March 8, 2011 (edited) 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. expandcollapse popup;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. expandcollapse popup;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 March 21, 2011 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 More sharing options...
Malkey Posted March 9, 2011 Author Share Posted March 9, 2011 [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 expandcollapse popup#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 More sharing options...
martin Posted March 10, 2011 Share Posted March 10, 2011 .. ... [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 More sharing options...
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now