martin Posted March 21, 2011 Share Posted March 21, 2011 (edited) I think I misunderstood what you meant by a line function Malkey. I've had another play and here is an example of detecting if a point is within an enclosed shape. The shape is only straight lines and circular arcs. I modified my _IsPtInArc function because I don't think it was correct, and I've altered the way it was used and simplified it. It has a problem which I expected that it detects the end of a line twice so I will have to work out how to deal with that, but it's fairly close otherwise. expandcollapse popup;using code 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 Global $pi = 4 * ATan(1) Global $Deg2Rad = 180 / $pi 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 = 380 Local $aPoints[11][8], $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) ;set data in array for shape $aPoints[0][0] = 10; Number of lines of Polygon $aPoints[1][0] = 1;st line $aPoints[1][1] = 10;x1 $aPoints[1][2] = 30;y1 $aPoints[1][3] = 10;x2 $aPoints[1][4] = 290;y2 $aPoints[2][0] = 2; arc $aPoints[2][1] = 30;center x $aPoints[2][2] = 290;centre y $aPoints[2][3] = 20;rad $aPoints[2][4] = 180;st angle $aPoints[2][5] = -90; sweep $aPoints[3][0] = 1;st line $aPoints[3][1] = 30; $aPoints[3][2] = 310 $aPoints[3][3] = 190; $aPoints[3][4] = 310 $aPoints[4][0] = 2; arc $aPoints[4][1] = 190;center x $aPoints[4][2] = 290;center y $aPoints[4][3] = 20;rad $aPoints[4][4] = 90;st angle $aPoints[4][5] = -90; sweep $aPoints[5][0] = 1;st line $aPoints[5][1] = 210; $aPoints[5][2] = 290 $aPoints[5][3] = 210; $aPoints[5][4] = 230 $aPoints[6][0] = 2; arc $aPoints[6][1] = 250;center x $aPoints[6][2] = 230;center y $aPoints[6][3] = 40;rad $aPoints[6][4] = 180;st angle $aPoints[6][5] = 90; sweep $aPoints[7][0] = 2; arc $aPoints[7][1] = 250;center x $aPoints[7][2] = 100;center y $aPoints[7][3] = 90;rad $aPoints[7][4] = 90;st angle $aPoints[7][5] = -180;sweep $aPoints[8][0] = 1;st line $aPoints[8][1] = 250; $aPoints[8][2] = 10 $aPoints[8][3] = 30; $aPoints[8][4] = 10 $aPoints[9][0] = 2; arc - closes shape $aPoints[9][1] = 30;center x $aPoints[9][2] = 30;center y $aPoints[9][3] = 20;rad $aPoints[9][4] = 270; st angle $aPoints[9][5] = -90; sweep $aPoints[10][0] = 2; arc - closes shape $aPoints[10][1] = 130;center x $aPoints[10][2] = 130;center y $aPoints[10][3] = 40;rad $aPoints[10][4] = 0; st angle $aPoints[10][5] = 360; sweep _DrawPolyLineArc($aPoints, $hGraphic); draw the shape ; 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 shape: " & _PointInLineArcPoly($aPos[0], $aPos[1], $aPoints)) EndSwitch WEnd EndFunc ;==>_Main Func _PointInLineArcPoly($Px, $Py, $aP) Local $Res = 0, $j For $j = 1 To $aP[0][0] Switch $aP[$j][0] Case 1 If _IsPtLeftOfLine($Px, $Py, $aP[$j][1], $aP[$j][2], $aP[$j][3], $aP[$j][4]) Then $Res += 1 Case 2 If _IsPtInArc($Px, $Py, $aP[$j][1], $aP[$j][2], $aP[$j][3], $aP[$j][4], $aP[$j][5]) Then $Res += 1 EndSwitch Next Return Mod($Res, 2) = 1 EndFunc ;==>_PointInLineArcPoly Func _IsPtLeftOfLine($rx, $Ry, $X1, $Y1, $X2, $Y2) If $Ry >= Max($Y1, $Y2) Or $Ry < Min($Y1, $Y2) Then Return False EndIf Return $rx < ($Ry - $Y1) * ($X2 - $X1) / ($Y2 - $Y1) + $X1 EndFunc ;==>IsPtLeftOfLine Func _DrawPolyLineArc($aP, $hGr) For $j = 1 To $aP[0][0] Switch $aP[$j][0] Case 1 _DrawStLine($aP, $j, $hGr) Case 2 _DrawArc($aP, $j, $hGr) EndSwitch Next EndFunc ;==>DrawPolyLineArc Func _DrawStLine($aK, $i, $graphic) _GDIPlus_GraphicsDrawLine($graphic, $aK[$i][1], $aK[$i][2], $aK[$i][3], $aK[$i][4]) EndFunc ;==>drawStLine Func _DrawArc($aM, $i, $graphic) _GDIPlus_GraphicsDrawArc($graphic, $aM[$i][1] - $aM[$i][3], $aM[$i][2] - $aM[$i][3], $aM[$i][3] * 2, $aM[$i][3] * 2, $aM[$i][4], $aM[$i][5]) EndFunc ;==>drawArc ;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 ;version 2 Func _IsPtInArc($xPt, $yPt, $xR, $yR, $Rad, $StAngle, $sw) Local $EndAngle, $Alpha1, $Alpha2, $Result1 = False, $Result2 = False Local $way = 1, $Atemp, $beta ;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 $beta = ASin(Abs(($yPt - $yR) / $Rad)) $Alpha1 = $beta * $Deg2Rad Select Case $yPt > $yR $Alpha2 = 180 - $Alpha1 Case $yPt <= $yR $Alpha2 = 180 + $Alpha1 $Alpha1 = 360 - $Alpha1 EndSelect $Result1 = _AngleInRange($Alpha1, $StAngle, $sw) And ($Rad * Abs(Cos($beta)) + $xR) > $xPt $Result2 = _AngleInRange($Alpha2, $StAngle, $sw) And (-$Rad * Abs(Cos($beta)) + $xR) > $xPt Return BitXOR($Result1, $Result2) = 1 EndFunc ;==>_IsPtInArc Func _AngleInRange($ang, $startA, $sweepA) Local $S1, $E1, $Temp If $sweepA < 0 Then $S1 = $startA + $sweepA $E1 = $startA Else $S1 = $startA $E1 = $startA + $sweepA EndIf While $S1 < 0 $S1 += 360 $E1 += 360 WEnd While $ang < $S1 $ang += 360 WEnd While $ang > $E1 $ang -= 360 WEnd ;maybe some conditions here to decide >= or > etc Return $ang >= $S1 And $ang < $E1 EndFunc ;==>_AngleInRange ;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 Max($a, $b) If $a >= $b Then Return $a Return $b EndFunc ;==>Max Func Min($a, $b) If $a >= $b Then Return $b Return $a EndFunc ;==>Min EDIT I've added a colour parameter to my line and arc functions. When I've fixed the problem I'll post them. Edited March 26, 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...
martin Posted March 22, 2011 Share Posted March 22, 2011 (edited) I've worked out a way to decide if a point is inside when there is a combination a line types. The problem is deciding whether to include the end points of lines or not so that you don't get duplicates. With straight lines you can say just ignore the top point. With arcs what is the top point of a circle? And if I ignore the top point of an arc what if it joins the top point of another arc? In that case I have ignored a point I shouldn't ignore.So I decided that every point on the line should be considered. If the point is left of the line then give a true result but also return the points on the line that were to the right of the point we are looking at. Then add any unique points to another array $aG. Then if the number of points in the array $aG is odd it means the point is inside the shape. If the number of points is even or zero we are outside the shape.After struggling with how to do this I think that I should have stayed with Malkey's idea. Malkey's method was to ignore the bottom point of a straight line so that a point didn't get counted twice. The same can be applied to curves if we say that if the curve moves upwards away from an end then ignore that end. This means that a curve can have 2 'bottoms' or it could have 2 'tops' or it could have a top and a bottom. Now I can't think of an example where this doesn't work so I've removed the examples I had below and I'll post them again when I've applied this better idea. Edited March 24, 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...
Mrtn Posted March 24, 2011 Share Posted March 24, 2011 the _AreaPoly() function which returns the area of a closed polygon,have been included. Someone might find a use for them oneday.Hi, i'm following this topic a little bit.Currently i'm trying to make a GUI with area info of calculated geometry.I rewrote the _AreaPoly() a little bit so it is of use (for me) with the GDI+ polygons.Func _AreaPoly(ByRef $aPoints) Local $Med, $size $size = UBound($aPoints) Local $sPolygon[$size][2] $aPolygon = $aPoints ReDim $aPolygon[$size + 1][2] $aPolygon[$size][0] = $aPolygon[1][0] $aPolygon[$size][1] = $aPolygon[1][1] For $n = 1 To UBound($aPolygon) - 2 $Med += $aPolygon[$n][0] * $aPolygon[$n + 1][1] - $aPolygon[$n + 1][0] * $aPolygon[$n][1] Next $Med /= 2 Return $Med EndFunc ;==>_AreaPoly Link to comment Share on other sites More sharing options...
martin Posted March 24, 2011 Share Posted March 24, 2011 (edited) the _AreaPoly() function which returns the area of a closed polygon, have been included. Someone might find a use for them oneday. .. That's a good addition Mrtn, can you make it include arcs? Welcome to the forums Here are the examples I posted before I removed removed them because I think I have a better approach to finding a point in an arc now. It can probably be simplified but I'm fairly confident it works for all situations. (fairly) Example 1 - an enclosed shape made of arcs and straight lines. expandcollapse popup;using code 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> #include <array.au3> ;HotKeySet("{F6}","showarray"); for debugging Global $a1, $a2 Global $pi = 4 * ATan(1) Global $Deg2Rad = 180 / $pi Global $aG[20][2] Opt('MustDeclareVars', 1) Opt("MouseCoordMode", 2);1=absolute, 0=relative, 2=client Global $hGUI, $hBMPBuff, $hGraphicGUI, $hGraphic _Main() Func showarray() _ArrayDisplay($aG) EndFunc ;==>showarray Func _Main() Local $msg, $aPos, $GuiSizeX = 400, $GuiSizeY = 380 Local $aPoints[11][6], $aTriangle[5][2] Local $hButton, $MinsMaxs ; 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) ;set data in array for shape $aPoints[0][0] = 10; Number of lines of Polygon $aPoints[1][0] = 1;st line $aPoints[1][1] = 10;x1 $aPoints[1][2] = 30;y1 $aPoints[1][3] = 10;x2 $aPoints[1][4] = 290;y2 $aPoints[2][0] = 2; arc $aPoints[2][1] = 30;center x $aPoints[2][2] = 290;centre y $aPoints[2][3] = 20;rad $aPoints[2][4] = 180;st angle $aPoints[2][5] = -90; sweep $aPoints[3][0] = 1;st line $aPoints[3][1] = 30; $aPoints[3][2] = 310 $aPoints[3][3] = 190; $aPoints[3][4] = 310 $aPoints[4][0] = 2; arc $aPoints[4][1] = 190;center x $aPoints[4][2] = 290;center y $aPoints[4][3] = 20;rad $aPoints[4][4] = 90;st angle $aPoints[4][5] = -90; sweep $aPoints[5][0] = 1;st line $aPoints[5][1] = 210; $aPoints[5][2] = 290 $aPoints[5][3] = 210; $aPoints[5][4] = 230 $aPoints[6][0] = 2; arc $aPoints[6][1] = 250;center x $aPoints[6][2] = 230;center y $aPoints[6][3] = 40;rad $aPoints[6][4] = 180;st angle $aPoints[6][5] = 90; sweep $aPoints[7][0] = 2; arc $aPoints[7][1] = 250;center x $aPoints[7][2] = 100;center y $aPoints[7][3] = 90;rad $aPoints[7][4] = 90;st angle $aPoints[7][5] = -180;sweep $aPoints[8][0] = 1;st line $aPoints[8][1] = 250; $aPoints[8][2] = 10 $aPoints[8][3] = 30; $aPoints[8][4] = 10 $aPoints[9][0] = 2; arc - closes shape $aPoints[9][1] = 30;center x $aPoints[9][2] = 30;center y $aPoints[9][3] = 20;rad $aPoints[9][4] = 270; st angle $aPoints[9][5] = -90; sweep $aPoints[10][0] = 2; arc - closes shape $aPoints[10][1] = 130;center x $aPoints[10][2] = 130;center y $aPoints[10][3] = 40;rad $aPoints[10][4] = 0; st angle $aPoints[10][5] = 360; sweep _DrawPolyLineArc($aPoints, $hGraphic); draw the shape ; 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 shape: " & _PointInLineArcPoly($aPos[0], $aPos[1], $aPoints)) EndSwitch WEnd EndFunc ;==>_Main #region drawing functions------------------------------------------ Func _DrawPolyLineArc($aP, $hGr) For $j = 1 To $aP[0][0] Switch $aP[$j][0] Case 1 _DrawStLine($aP, $j, $hGr) Case 2 _DrawArc($aP, $j, $hGr) EndSwitch Next EndFunc ;==>_DrawPolyLineArc Func _DrawStLine($aK, $i, $graphic) _GDIPlus_GraphicsDrawLine($graphic, $aK[$i][1], $aK[$i][2], $aK[$i][3], $aK[$i][4]) EndFunc ;==>_DrawStLine Func _DrawArc($aM, $i, $graphic) _GDIPlus_GraphicsDrawArc($graphic, $aM[$i][1] - $aM[$i][3], $aM[$i][2] - $aM[$i][3], $aM[$i][3] * 2, $aM[$i][3] * 2, $aM[$i][4], $aM[$i][5]) EndFunc ;==>_DrawArc #endregion drawing functions ----------------------------------------------------------- #region checking point functions ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Func _PointInLineArcPoly($Px, $Py, $aP) Local $Res = 0, $j For $j = 1 To $aP[0][0] ;If $j = 10 Then Switch $aP[$j][0] Case 1 If _IsPtLeftOfLine($Px, $Py, $aP[$j][1], $aP[$j][2], $aP[$j][3], $aP[$j][4]) Then $Res += 1 EndIf Case 2 If _IsPtInArc($Px, $Py, $aP[$j][1], $aP[$j][2], $aP[$j][3], $aP[$j][4], $aP[$j][5]) Then $Res += 1 EndIf EndSwitch ;EndIf Next Return Mod($Res, 2) = 1 EndFunc ;==>_PointInLineArcPoly Func _IsPtLeftOfLine($Rx, $Ry, $X1, $Y1, $X2, $Y2) If $Ry >= Max($Y1, $Y2) Or $Ry < Min($Y1, $Y2) Then Return False EndIf Return $Rx < ($Ry - $Y1) * ($X2 - $X1) / ($Y2 - $Y1) + $X1 EndFunc ;==>_IsPtLeftOfLine ;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 start angle plus sweep ;Returns True if a horizontal line draw from the point to the right cuts the arc ; once. If the horizontal line hits an end of the arc then it returns true only if that end is a top. A top end means ; the arc moves down away from that end. ; If the horizontal line is a tangent to the arc then it returns false. ;Author - martin ;version 3 Func _IsPtInArc($xPt, $yPt, $xR, $yR, $Rad, $StAngle, $Sw) Local $EndAngle, $Alpha1, $Alpha2, $Result1 = False, $Result2 = False Local $way = 1, $Atemp, $beta, $j ;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 $beta = ASin(Abs(($yPt - $yR) / $Rad)) $Alpha1 = $beta * $Deg2Rad Select Case $yPt > $yR $Alpha2 = 180 - $Alpha1 Case $yPt <= $yR $Alpha2 = 180 + $Alpha1 $Alpha1 = 360 - $Alpha1 EndSelect $Result1 = _AngleInRange($Alpha1, $StAngle, $Sw) And ($Rad * Abs(Cos($beta)) + $xR) > $xPt ;ConsoleWrite("$yPt,$Alpha1, $StAngle, $Sw = " & $yPt & ', ' & $Alpha1 & ", " & $StAngle & ', ' & $Sw & @CRLF) ;if alpha2 is 90 or 270 then alpha1 is as well and we mustn't count the same point twice if it's the end of the arc ;but we only have to check 270 because 90 is the bottom which is always false if it's an end of the arc If $Alpha2 = 270 and _OneIsSameAngle($StAngle,$StAngle + $sw,270) Then $result2 = False Else $Result2 = _AngleInRange($Alpha2, $StAngle, $Sw) And (-$Rad * Abs(Cos($beta)) + $xR) > $xPt EndIf ;ConsoleWrite("$result1, $result2 = " & $Result1 & $Result2 & @CRLF) Return BitXOR($Result1, $Result2) = 1 EndFunc ;==>_IsPtInArc func _OneIsSameANgle($A,$B,$C) _SetAngle($A) _SetAngle($B) Return BitXOR( ($A = $C), ($B = $C)) EndFunc ;=== SetAngle ========== ;converts the angle to be in range 0 to 360 func _SetAngle(ByRef $aS) while $aS < 0 $aS += 360 WEnd while $aS > 360 $aS -= 360 WEnd EndFunc Func _AngleInRange($ang, $startA, $sweepA) Local $S1, $E1, $Temp Local $aa, $bb If $sweepA >= 360 Then Return True $aa = $startA _SetAngle($aa) $bb = $startA + $sweepA _SetAngle($bb) If $ang = $aa Then;check if start a top or bottom type of end If $sweepA > 0 Then return ($ang >= 270 And $ang <= 360) Or ($ang >= 0 And $ang < 90) EndIf If $sweepA < 0 Then Return $ang > 90 And $ang <= 270 EndIf EndIf If $ang = $bb Then; is end a top or bottom type If $sweepA < 0 Then return ($ang >= 270 And $ang <= 360) Or ($ang >= 0 And $ang < 90) EndIf If $sweepA > 0 Then Return $ang > 90 And $ang <= 270 EndIf EndIf If $sweepA < 0 Then $S1 = $startA + $sweepA $E1 = $startA Else $S1 = $startA $E1 = $startA + $sweepA EndIf While $S1 < 0 $S1 += 360 $E1 += 360 WEnd While $ang < $S1 $ang += 360 WEnd While $ang > $E1 $ang -= 360 WEnd Return $ang >= $S1 And $ang <= $E1 EndFunc ;==>_AngleInRange #endregion checking point functions ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ;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 Max($a, $b) If $a >= $b Then Return $a Return $b EndFunc ;==>Max Func Min($a, $b) If $a >= $b Then Return $b Return $a EndFunc ;==>Min Example 2, a pie chart with a tooltip which depends on which section the cursor is over. expandcollapse popup;using code 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> #include <array.au3> Global $a1, $a2 Global $pi = 4 * ATan(1) Global $Deg2Rad = 180 / $pi 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 = 380 Local $aPts, $aTriangle[5][2] Local $hButton, $ShapeCount, $ANgleSum Local $sText[8] = ["place the cursor over the pie chart", "people who don't understand pie charts", "thank you William Playfair " & @CRLF & " and Florence Nightingale", "people who have no running water", "People who can't ride a bicycle", _ "people who have blond hair", "people who don't own shoes", "people who never work"] ; 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) ;set data in array for shape Dim $Segments[7] = [20, 80, 50, 70, 10, 40, 90] Global $AllShapes[UBound($Segments)] $ANgleSum = 0 For $ShapeCount = 0 To UBound($Segments) - 1 $AllShapes[$ShapeCount] = _PieShape(150, 150, 100, $ANgleSum, $Segments[$ShapeCount], $hGraphic) _DrawPolyLineArc($AllShapes[$ShapeCount], $hGraphic); draw the shape $ANgleSum += $Segments[$ShapeCount] ;_GDIPlus_GraphicsDrawImage($hGraphicGUI, $hBMPBuff, 0, 0) ;sleep(3000) Next ; 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 segment: " & _PointInPie($aPos[0], $aPos[1], $AllShapes)) ToolTip($sText[_PointInPie($aPos[0], $aPos[1], $AllShapes)]) EndSwitch WEnd EndFunc ;==>_Main Func _PointInPie($x, $y, $aP) Local $n For $n = 0 To UBound($aP) - 1 If _PointInLineArcPoly($x, $y, $aP[$n]) Then Return $n + 1 Next EndFunc ;==>_PointInPie Func _PieShape($Rx, $Ry, $Rad, $StartAng, $Sweep, $hG) Local $aPoints[4][6] Local $hBr = _GDIPlus_BrushCreateSolid(0xff000000 + Random(20, 200, 1) * 2 ^ 16 + Random(20, 200, 1) * 2 ^ 8 + Random(20, 200, 1)) _GDIPlus_GraphicsFillPie($hG, $Rx - $Rad, $Ry - $Rad, $Rad * 2, $Rad * 2, $StartAng, $Sweep, $hBr) _GDIPlus_BrushDispose($hBr) $aPoints[0][0] = 3;3 lines $aPoints[1][0] = 2;line is an arc $aPoints[1][1] = $Rx;center x $aPoints[1][2] = $Ry;centre y $aPoints[1][3] = $Rad;rad $aPoints[1][4] = $StartAng;st angle $aPoints[1][5] = $Sweep; sweep $aPoints[2][0] = 1;st line $aPoints[2][1] = $Rx; $aPoints[2][2] = $Ry $aPoints[2][3] = $Rx + $Rad * Cos($StartAng / $Deg2Rad); $aPoints[2][4] = $Ry + $Rad * Sin($StartAng / $Deg2Rad); $aPoints[3][0] = 1;st line $aPoints[3][1] = $Rx; $aPoints[3][2] = $Ry $aPoints[3][3] = $Rx + $Rad * Cos(($StartAng + $Sweep) / $Deg2Rad); $aPoints[3][4] = $Ry + $Rad * Sin(($StartAng + $Sweep) / $Deg2Rad); Return $aPoints EndFunc ;==>_PieShape #region drawing functions Func _DrawPolyLineArc($aP, $hGr) For $j = 1 To $aP[0][0] Switch $aP[$j][0] Case 1 _DrawStLine($aP, $j, $hGr) Case 2 _DrawArc($aP, $j, $hGr) EndSwitch Next EndFunc ;==>_DrawPolyLineArc Func _DrawStLine($aK, $i, $graphic) _GDIPlus_GraphicsDrawLine($graphic, $aK[$i][1], $aK[$i][2], $aK[$i][3], $aK[$i][4]) EndFunc ;==>_DrawStLine Func _DrawArc($aM, $i, $graphic) _GDIPlus_GraphicsDrawArc($graphic, $aM[$i][1] - $aM[$i][3], $aM[$i][2] - $aM[$i][3], $aM[$i][3] * 2, $aM[$i][3] * 2, $aM[$i][4], $aM[$i][5]) EndFunc ;==>_DrawArc #endregion drawing functions #region checking point functions Func _PointInLineArcPoly($Px, $Py, $aP) Local $Res = 0, $j For $j = 1 To $aP[0][0] ;If $j = 10 Then Switch $aP[$j][0] Case 1 If _IsPtLeftOfLine($Px, $Py, $aP[$j][1], $aP[$j][2], $aP[$j][3], $aP[$j][4]) Then $Res += 1 EndIf Case 2 If _IsPtInArc($Px, $Py, $aP[$j][1], $aP[$j][2], $aP[$j][3], $aP[$j][4], $aP[$j][5]) Then $Res += 1 EndIf EndSwitch ;EndIf Next Return Mod($Res, 2) = 1 EndFunc ;==>_PointInLineArcPoly Func _IsPtLeftOfLine($Rx, $Ry, $X1, $Y1, $X2, $Y2) If $Ry >= Max($Y1, $Y2) Or $Ry < Min($Y1, $Y2) Then Return False EndIf Return $Rx < ($Ry - $Y1) * ($X2 - $X1) / ($Y2 - $Y1) + $X1 EndFunc ;==>_IsPtLeftOfLine ;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 start angle plus sweep ;Returns True if a horizontal line draw from the point to the right cuts the arc ; once. If the horizontal line hits an end of the arc then it returns true only if that end is a top. A top end means ; the arc moves down away from that end. ; If the horizontal line is a tangent to the arc then it returns false. ;Author - martin ;version 3 Func _IsPtInArc($xPt, $yPt, $xR, $yR, $Rad, $StAngle, $Sw) Local $EndAngle, $Alpha1, $Alpha2, $Result1 = False, $Result2 = False Local $way = 1, $Atemp, $beta, $j ;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 $beta = ASin(Abs(($yPt - $yR) / $Rad)) $Alpha1 = $beta * $Deg2Rad Select Case $yPt > $yR $Alpha2 = 180 - $Alpha1 Case $yPt <= $yR $Alpha2 = 180 + $Alpha1 $Alpha1 = 360 - $Alpha1 EndSelect $Result1 = _AngleInRange($Alpha1, $StAngle, $Sw) And ($Rad * Abs(Cos($beta)) + $xR) > $xPt ;ConsoleWrite("$yPt,$Alpha1, $StAngle, $Sw = " & $yPt & ', ' & $Alpha1 & ", " & $StAngle & ', ' & $Sw & @CRLF) ;if alpha2 is 90 or 270 then alpha1 is as well and we mustn't count the same point twice if it's the end of the arc ;but we only have to check 270 because 90 is the bottom which is always false if it's an end of the arc If $Alpha2 = 270 and _OneIsSameAngle($StAngle,$StAngle + $sw,270) Then $result2 = False Else $Result2 = _AngleInRange($Alpha2, $StAngle, $Sw) And (-$Rad * Abs(Cos($beta)) + $xR) > $xPt EndIf ;ConsoleWrite("$result1, $result2 = " & $Result1 & $Result2 & @CRLF) Return BitXOR($Result1, $Result2) = 1 EndFunc ;==>_IsPtInArc func _OneIsSameANgle($A,$B,$C) _SetAngle($A) _SetAngle($B) if $A = $C or $B = $C then return True return False EndFunc ;=== SetAngle ========== ;converts the angle to be in range 0 to 360 func _SetAngle(ByRef $aS) while $aS < 0 $aS += 360 WEnd while $aS > 360 $aS -= 360 WEnd EndFunc Func _AngleInRange($ang, $startA, $sweepA) Local $S1, $E1, $Temp Local $aa, $bb If $sweepA >= 360 Then Return True $aa = $startA _SetAngle($aa) $bb = $startA + $sweepA _SetAngle($bb) If $ang = $aa Then;check if start a top or bottom type of end If $sweepA > 0 Then return ($ang >= 270 And $ang <= 360) Or ($ang >= 0 And $ang < 90) EndIf If $sweepA < 0 Then Return $ang > 90 And $ang <= 270 EndIf EndIf If $ang = $bb Then; is end a top or bottom type If $sweepA < 0 Then return ($ang >= 270 And $ang <= 360) Or ($ang >= 0 And $ang < 90) EndIf If $sweepA > 0 Then Return $ang > 90 And $ang <= 270 EndIf EndIf If $sweepA < 0 Then $S1 = $startA + $sweepA $E1 = $startA Else $S1 = $startA $E1 = $startA + $sweepA EndIf While $S1 < 0 $S1 += 360 $E1 += 360 WEnd While $ang < $S1 $ang += 360 WEnd While $ang > $E1 $ang -= 360 WEnd Return $ang >= $S1 And $ang <= $E1 EndFunc ;==>_AngleInRange #endregion checking point functions ;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 Max($a, $b) If $a >= $b Then Return $a Return $b EndFunc ;==>Max Func Min($a, $b) If $a >= $b Then Return $b Return $a EndFunc ;==>Min EDIT: Correct error in _SetAngle function. (-= was +=), and changed _OneIsSame to return BitXOR rather than Or. Edited March 24, 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...
martin Posted March 25, 2011 Share Posted March 25, 2011 (edited) Now I can calculate the path for my routing tool expandcollapse popup;using code 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> #include <array.au3> ;HotKeySet("{F6}","showarray"); for debugging Global $a1, $a2 Global $pi = 4 * ATan(1) Global $Rad2Deg = 180 / $pi Global $aG[20][2] Opt('MustDeclareVars', 1) Opt("MouseCoordMode", 2);1=absolute, 0=relative, 2=client Global $hGUI, $hBMPBuff, $hGraphicGUI, $hGraphic _Main() Func showarray() _ArrayDisplay($aG) EndFunc ;==>showarray Func _Main() Local $msg, $aPos, $GuiSizeX = 400, $GuiSizeY = 380 Local $aPoints[11][6], $aTriangle[5][2] Local $hButton1, $hButton2, $MinsMaxs,$dx,$dy, $beta Local $marg = 8 ; Create GUI $hGUI = GUICreate("GDI+", $GuiSizeX, $GuiSizeY + 50) $hButton1 = GUICtrlCreateButton("Create Inside Path", 80, 400) $hButton2 = GUICtrlCreateButton("Create Outside Path", 200, 400) 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) ;set data in array for shape $aPoints[0][0] = 10; Number of lines of Polygon ;calculate bits for the end start angle of left hand corners and the positions of the end of the left-hand straight edge $beta = atan(40/260) $dx = 20 * cos($beta) $dy = 20 * sin($beta) ConsoleWrite($beta*$Rad2Deg & @CRLF) $aPoints[1][0] = 1;st line $aPoints[1][1] = 70 - $dx;x1 $aPoints[1][2] = 30 - $dy;y1 $aPoints[1][3] = 30 - $dx;x2 $aPoints[1][4] = 290 - $dy;y2 $aPoints[2][0] = 2; arc $aPoints[2][1] = 30;center x $aPoints[2][2] = 290;centre y $aPoints[2][3] = 20;rad $aPoints[2][4] = 90;st angle $aPoints[2][5] = 90+$beta*$Rad2Deg; sweep $aPoints[3][0] = 1;st line $aPoints[3][1] = 30; $aPoints[3][2] = 310 $aPoints[3][3] = 190; $aPoints[3][4] = 310 $aPoints[4][0] = 2; arc $aPoints[4][1] = 190;center x $aPoints[4][2] = 290;center y $aPoints[4][3] = 20;rad $aPoints[4][4] = 90;st angle $aPoints[4][5] = -90; sweep $aPoints[5][0] = 1;st line $aPoints[5][1] = 210; $aPoints[5][2] = 290 $aPoints[5][3] = 210; $aPoints[5][4] = 230 $aPoints[6][0] = 2; arc $aPoints[6][1] = 250;center x $aPoints[6][2] = 230;center y $aPoints[6][3] = 40;rad $aPoints[6][4] = 180;st angle $aPoints[6][5] = 90; sweep $aPoints[7][0] = 2; arc $aPoints[7][1] = 250;center x $aPoints[7][2] = 100;center y $aPoints[7][3] = 90;rad $aPoints[7][4] = 90;st angle $aPoints[7][5] = -180;sweep $aPoints[8][0] = 1;st line $aPoints[8][1] = 250; $aPoints[8][2] = 10 $aPoints[8][3] = 70; $aPoints[8][4] = 10 $aPoints[9][0] = 2; arc - closes shape $aPoints[9][1] = 70;center x $aPoints[9][2] = 30;center y $aPoints[9][3] = 20;rad $aPoints[9][4] = 270; st angle $aPoints[9][5] = -90 + $beta*$Rad2Deg; sweep $aPoints[10][0] = 2; arc - $aPoints[10][1] = 300;center x $aPoints[10][2] = 260;center y $aPoints[10][3] = 60;rad $aPoints[10][4] = 270; st angle $aPoints[10][5] = 360; sweep _DrawPolyLineArc($aPoints, $hGraphic); draw the shape ; 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 $hButton1 _DrawPolyLineArc(_CreateInnerOuterCopy($aPoints, $hGraphic, $marg), $hGraphic, 0xff0000) _GDIPlus_GraphicsDrawImage($hGraphicGUI, $hBMPBuff, 0, 0) Case $hButton2 _DrawPolyLineArc(_CreateInnerOuterCopy($aPoints, $hGraphic, -$marg), $hGraphic, 0x00ff00) _GDIPlus_GraphicsDrawImage($hGraphicGUI, $hBMPBuff, 0, 0) Case $GUI_EVENT_MOUSEMOVE $aPos = MouseGetPos() ToolTip("Mouse Position X: " & $aPos[0] & " Y: " & $aPos[1] & @CRLF & @CRLF & _ "Cursor in shape: " & _PointInLineArcPoly($aPos[0], $aPos[1], $aPoints)) EndSwitch WEnd EndFunc ;==>_Main ;======= _CreateInsideCopy =================== ;version 2 ;Version 1 assumes arcs start and end at 90 degree multiples and straight lines are vertical or horizontal. ;Version 2 allows for lines at any angle but assumes lines join arcs at a tangent. ;assumes the margin is less than the radius of the smallest arc ;so very limited. ;returns an array of the new shape ;if margin is > 0 then inner copy ;if $margin < 0 then outer copy Func _CreateInnerOuterCopy($aPts, $hGr, $margin) Local $aPoints[UBound($aPts, 1)][6], $n, $posx, $posy, $use, $alpha, $x1, $y1 $aPoints[0][0] = $aPts[0][0] For $n = 1 To UBound($aPts) - 1 Switch $aPts[$n][0] ;line type Case 1;straight line $aPoints[$n][0] = 1 ConsoleWrite($aPts[$n][1] & ', ' & $aPts[$n][2] & ', ' & $aPts[$n][3] & ', ' & $aPts[$n][4] & ', ' & @CRLF) ;get a point at the end of a paralle line $margin away If $aPts[$n][1] = $aPts[$n][3] Then;vertical line ConsoleWrite("vertical" & @CRLF) $alpha = $pi / 2 Else $alpha = ATan(($aPts[$n][4] - $aPts[$n][2]) / ($aPts[$n][3] - $aPts[$n][1])) EndIf $x1 = $aPts[$n][1] + $margin * Sin($alpha) $y1 = $aPts[$n][2] - $margin * Cos($alpha) If BitXOR(_PointInLineArcPoly($x1, $y1, $aPts), $margin < 0) Then $aPoints[$n][1] = $x1 $aPoints[$n][2] = $y1 $aPoints[$n][3] = $aPts[$n][3] + $margin * Sin($alpha) $aPoints[$n][4] = $aPts[$n][4] - $margin * Cos($alpha) Else $aPoints[$n][1] = $aPts[$n][1] - $margin * Sin($alpha) $aPoints[$n][2] = $aPts[$n][2] + $margin * Cos($alpha) $aPoints[$n][3] = $aPts[$n][3] - $margin * Sin($alpha) $aPoints[$n][4] = $aPts[$n][4] + $margin * Cos($alpha) EndIf Case 2 ; arc $aPoints[$n][0] = 2 $aPoints[$n][1] = $aPts[$n][1] $aPoints[$n][2] = $aPts[$n][2] $aPoints[$n][4] = $aPts[$n][4] $aPoints[$n][5] = $aPts[$n][5] $posx = $aPts[$n][1] + ($aPts[$n][3] - $margin) * Cos($aPts[$n][4] / $Rad2Deg) $posy = $aPts[$n][2] + ($aPts[$n][3] - $margin) * Sin($aPts[$n][4] / $Rad2Deg) ConsoleWrite("posx, posy = " & $posx & ', ' & $posy & @CRLF) If BitXOR(_PointInLineArcPoly($posx, $posy, $aPts), $margin < 0) Then ConsoleWrite("is inside" & @CRLF) $aPoints[$n][3] = $aPts[$n][3] - $margin Else $aPoints[$n][3] = $aPts[$n][3] + $margin EndIf EndSwitch Next ;_ArrayDisplay($aPoints) Return $aPoints EndFunc ;==>_CreateInnerOuterCopy ;=========== _GetParallelStLines ====================== ;returns an array containing the end points for 2 parallel lines to $x1, $y1 to $x2, $y2 ; the lines are either side of the given line displaced by a distance $gap measured at right angles to the line. Func _GetParallelStLine($x1, $y1, $x2, $y2, $gap) Local $slope, $alpha, $Beta, $n Dim $Res[4] ;get angle of line in radians $alpha = ATan(($y2 - $y1) / ($x2 - $x1)) $Res[0] = $x1 + $gap * Cos($alpha) $Res[2] = $x2 + $gap * Cos($alpha) $Res[1] = $x1 + $gap * Sin($alpha) $Res[3] = $x2 + $gap * Sin($alpha) EndFunc ;==>_GetParallelStLine #region drawing functions Func _DrawPolyLineArc($aP, $hGr, $colour = 0) Local $hPen = _GDIPlus_PenCreate(0xff000000 + $colour) For $j = 1 To $aP[0][0] Switch $aP[$j][0] Case 1 _DrawStLine($aP, $j, $hGr, $hPen) Case 2 _DrawArc($aP, $j, $hGr, $hPen) EndSwitch Next _GDIPlus_PenDispose($hPen) EndFunc ;==>_DrawPolyLineArc Func _DrawStLine($aK, $i, $graphic, $hPen = 0) _GDIPlus_GraphicsDrawLine($graphic, $aK[$i][1], $aK[$i][2], $aK[$i][3], $aK[$i][4], $hPen) EndFunc ;==>_DrawStLine Func _DrawArc($aM, $i, $graphic, $hPen = 0) _GDIPlus_GraphicsDrawArc($graphic, $aM[$i][1] - $aM[$i][3], $aM[$i][2] - $aM[$i][3], $aM[$i][3] * 2, $aM[$i][3] * 2, $aM[$i][4], $aM[$i][5], $hPen) EndFunc ;==>_DrawArc #endregion drawing functions #region checking point functions Func _PointInLineArcPoly($Px, $Py, $aP) Local $Res = 0, $j For $j = 1 To $aP[0][0] ;If $j = 10 Then Switch $aP[$j][0] Case 1 If _IsPtLeftOfLine($Px, $Py, $aP[$j][1], $aP[$j][2], $aP[$j][3], $aP[$j][4]) Then $Res += 1 EndIf Case 2 If _IsPtInArc($Px, $Py, $aP[$j][1], $aP[$j][2], $aP[$j][3], $aP[$j][4], $aP[$j][5]) Then $Res += 1 EndIf EndSwitch ;EndIf Next Return Mod($Res, 2) = 1 EndFunc ;==>_PointInLineArcPoly Func _IsPtLeftOfLine($Rx, $Ry, $x1, $y1, $x2, $y2) If $Ry >= Max($y1, $y2) Or $Ry < Min($y1, $y2) Then Return False EndIf Return $Rx < ($Ry - $y1) * ($x2 - $x1) / ($y2 - $y1) + $x1 EndFunc ;==>_IsPtLeftOfLine ;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 start angle plus sweep ;Returns True if a horizontal line draw from the point to the right cuts the arc ; once. If the horizontal line hits an end of the arc then it returns true only if that end is a top. A top end means ; the arc moves down away from that end. ; If the horizontal line is a tangent to the arc then it returns false. ;Author - martin ;version 3 Func _IsPtInArc($xPt, $yPt, $xR, $yR, $Rad, $StAngle, $Sw) Local $EndAngle, $Alpha1, $Alpha2, $Result1 = False, $Result2 = False Local $way = 1, $Atemp, $Beta, $j ;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 $Beta = ASin(Abs(($yPt - $yR) / $Rad)) $Alpha1 = $Beta * $Rad2Deg Select Case $yPt > $yR $Alpha2 = 180 - $Alpha1 Case $yPt <= $yR $Alpha2 = 180 + $Alpha1 $Alpha1 = 360 - $Alpha1 EndSelect $Result1 = _AngleInRange($Alpha1, $StAngle, $Sw) And ($Rad * Abs(Cos($Beta)) + $xR) > $xPt ;ConsoleWrite("$yPt,$Alpha1, $StAngle, $Sw = " & $yPt & ', ' & $Alpha1 & ", " & $StAngle & ', ' & $Sw & @CRLF) ;if alpha2 is 90 or 270 then alpha1 is as well and we mustn't count the same point twice if it's the end of the arc ;but we only have to check 270 because 90 is the bottom which is always false if it's an end of the arc If $Alpha2 = 270 And _OneIsSameAngle($StAngle, $StAngle + $Sw, 270) Then $Result2 = False Else $Result2 = _AngleInRange($Alpha2, $StAngle, $Sw) And (-$Rad * Abs(Cos($Beta)) + $xR) > $xPt EndIf ;ConsoleWrite("$result1, $result2 = " & $Result1 & $Result2 & @CRLF) Return BitXOR($Result1, $Result2) = 1 EndFunc ;==>_IsPtInArc Func _OneIsSameANgle($A, $B, $C) _SetAngle($A) _SetAngle($B) Return BitXOR(($A = $C), ($B = $C)) EndFunc ;==>_OneIsSameANgle ;=== SetAngle ========== ;converts the angle to be in range 0 to 360 Func _SetAngle(ByRef $aS) While $aS < 0 $aS += 360 WEnd While $aS > 360 $aS -= 360 WEnd EndFunc ;==>_SetAngle Func _AngleInRange($ang, $startA, $sweepA) Local $S1, $E1, $Temp Local $aa, $bb If $sweepA >= 360 Then Return True $aa = $startA _SetAngle($aa) $bb = $startA + $sweepA _SetAngle($bb) If $ang = $aa Then;check if start a top or bottom type of end If $sweepA > 0 Then return ($ang >= 270 And $ang <= 360) Or ($ang >= 0 And $ang < 90) EndIf If $sweepA < 0 Then Return $ang > 90 And $ang <= 270 EndIf EndIf If $ang = $bb Then; is end a top or bottom type If $sweepA < 0 Then return ($ang >= 270 And $ang <= 360) Or ($ang >= 0 And $ang < 90) EndIf If $sweepA > 0 Then Return $ang > 90 And $ang <= 270 EndIf EndIf If $sweepA < 0 Then $S1 = $startA + $sweepA $E1 = $startA Else $S1 = $startA $E1 = $startA + $sweepA EndIf While $S1 < 0 $S1 += 360 $E1 += 360 WEnd While $ang < $S1 $ang += 360 WEnd While $ang > $E1 $ang -= 360 WEnd Return $ang >= $S1 And $ang <= $E1 EndFunc ;==>_AngleInRange #endregion checking point functions ;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));,$RDW_ALLCHILDREN Return $GUI_RUNDEFMSG EndFunc ;==>MY_PAINT Func Max($A, $B) If $A >= $B Then Return $A Return $B EndFunc ;==>Max Func Min($A, $B) If $A >= $B Then Return $B Return $A EndFunc ;==>Min I couldn't resist showing this effect expandcollapse popup;using code 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> #include <array.au3> ;HotKeySet("{F6}","showarray"); for debugging Global $a1, $a2 Global $pi = 4 * ATan(1) Global $Rad2Deg = 180 / $pi Global $aG[20][2] Opt('MustDeclareVars', 1) Opt("MouseCoordMode", 2);1=absolute, 0=relative, 2=client Global $hGUI, $hBMPBuff, $hGraphicGUI, $hGraphic _Main() Func showarray() _ArrayDisplay($aG) EndFunc ;==>showarray Func _Main() Local $msg, $aPos, $GuiSizeX = 400, $GuiSizeY = 430 Local $aPoints[11][6], $aTriangle[5][2] Local $hButton1, $hButton2, $ed, $MinsMaxs, $dx, $dy, $beta, $col Local $marg = 8, $InOrOut = 1 ; Create GUI $hGUI = GUICreate("GDI+", $GuiSizeX, $GuiSizeY) $hButton1 = GUICtrlCreateButton("Convert to Pipes", 80, 400) ; $hButton2 = GUICtrlCreateButton("Create Outside Path", 200, 400) ;$ed = GUICtrlCreateinput("",130,360) GUISetState() _GDIPlus_Startup() ;Double Buffer $hGraphicGUI = _GDIPlus_GraphicsCreateFromHWND($hGUI) $hBMPBuff = _GDIPlus_BitmapCreateFromGraphics($GuiSizeX, $GuiSizeY - 70, $hGraphicGUI) $hGraphic = _GDIPlus_ImageGetGraphicsContext($hBMPBuff) _GDIPlus_GraphicsSetSmoothingMode($hGraphic,2) ;End Double Buffer add-on 1 of 3 _GDIPlus_GraphicsClear($hGraphic, 0xFFE8FFEF) ;set data in array for shape $aPoints[0][0] = 10; Number of lines of Polygon ;calculate bits for the end start angle of left hand corners and the positions of the end of the left-hand straight edge $beta = ATan(40 / 260) $dx = 20 * Cos($beta) $dy = 20 * Sin($beta) ConsoleWrite($beta * $Rad2Deg & @CRLF) $aPoints[1][0] = 1;st line $aPoints[1][1] = 70 - $dx;x1 $aPoints[1][2] = 30 - $dy;y1 $aPoints[1][3] = 30 - $dx;x2 $aPoints[1][4] = 290 - $dy;y2 $aPoints[2][0] = 2; arc $aPoints[2][1] = 30;center x $aPoints[2][2] = 290;centre y $aPoints[2][3] = 20;rad $aPoints[2][4] = 90;st angle $aPoints[2][5] = 90 + $beta * $Rad2Deg; sweep $aPoints[3][0] = 1;st line $aPoints[3][1] = 30; $aPoints[3][2] = 310 $aPoints[3][3] = 191; $aPoints[3][4] = 310 $aPoints[4][0] = 2; arc $aPoints[4][1] = 190;center x $aPoints[4][2] = 290;center y $aPoints[4][3] = 20;rad $aPoints[4][4] = 90;st angle $aPoints[4][5] = -90; sweep $aPoints[5][0] = 1;st line $aPoints[5][1] = 210; $aPoints[5][2] = 291 $aPoints[5][3] = 210; $aPoints[5][4] = 230 $aPoints[6][0] = 2; arc $aPoints[6][1] = 250;center x $aPoints[6][2] = 230;center y $aPoints[6][3] = 40;rad $aPoints[6][4] = 180;st angle $aPoints[6][5] = 90; sweep $aPoints[7][0] = 2; arc $aPoints[7][1] = 250;center x $aPoints[7][2] = 100;center y $aPoints[7][3] = 90;rad $aPoints[7][4] = 90;st angle $aPoints[7][5] = -180;sweep $aPoints[8][0] = 1;st line $aPoints[8][1] = 251; $aPoints[8][2] = 10 $aPoints[8][3] = 70; $aPoints[8][4] = 10 $aPoints[9][0] = 2; arc - closes shape $aPoints[9][1] = 70;center x $aPoints[9][2] = 30;center y $aPoints[9][3] = 20;rad $aPoints[9][4] = 270; st angle $aPoints[9][5] = -90 + $beta * $Rad2Deg; sweep $aPoints[10][0] = 2; arc - $aPoints[10][1] = 330;center x $aPoints[10][2] = 290;center y $aPoints[10][3] = 60;rad $aPoints[10][4] = 270; st angle $aPoints[10][5] = 360; sweep _DrawPolyLineArc($aPoints, $hGraphic); draw the shape ; 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 $hButton1 For $marg = 0 To 20 $col = 5* (20-$marg) + 4 * (20-$marg) * 2 ^ 8 + 3* (20-$marg) * 2 ^ 16 + 0x774422 _DrawPolyLineArc(_CreateInnerOuterCopy($aPoints, $hGraphic, $marg * $InOrOut), $hGraphic, $col, 2) _DrawPolyLineArc(_CreateInnerOuterCopy($aPoints, $hGraphic, -$marg * $InOrOut), $hGraphic, $col, 2) _GDIPlus_GraphicsDrawImage($hGraphicGUI, $hBMPBuff, 0, 0) Next Case $GUI_EVENT_MOUSEMOVE $aPos = MouseGetPos() If $aPos[1] < 360 Then ToolTip("Mouse Position X: " & $aPos[0] & " Y: " & $aPos[1] & @CRLF & @CRLF & _ "Cursor in shape: " & _PointInLineArcPoly($aPos[0], $aPos[1], $aPoints)) Else ToolTip("") EndIf EndSwitch WEnd EndFunc ;==>_Main ;======= _CreateInsideCopy =================== ;version 2 ;Version 1 assumes arcs start and end at 90 degree multiples and straight lines are vertical or horizontal. ;Version 2 allows for lines at any angle but assumes lines join arcs at a tangent. ;assumes the margin is less than the radius of the smallest arc ;so very limited. ;returns an array of the new shape ;if margin is > 0 then inner copy ;if $margin < 0 then outer copy Func _CreateInnerOuterCopy($aPts, $hGr, $margin) Local $aPoints[UBound($aPts, 1)][6], $n, $posx, $posy, $use, $alpha, $x1, $y1 $aPoints[0][0] = $aPts[0][0] For $n = 1 To UBound($aPts) - 1 Switch $aPts[$n][0] ;line type Case 1;straight line $aPoints[$n][0] = 1 ConsoleWrite($aPts[$n][1] & ', ' & $aPts[$n][2] & ', ' & $aPts[$n][3] & ', ' & $aPts[$n][4] & ', ' & @CRLF) ;get a point at the end of a paralle line $margin away If $aPts[$n][1] = $aPts[$n][3] Then;vertical line ConsoleWrite("vertical" & @CRLF) $alpha = $pi / 2 Else $alpha = ATan(($aPts[$n][4] - $aPts[$n][2]) / ($aPts[$n][3] - $aPts[$n][1])) EndIf $x1 = $aPts[$n][1] + $margin * Sin($alpha) $y1 = $aPts[$n][2] - $margin * Cos($alpha) If BitXOR(_PointInLineArcPoly($x1, $y1, $aPts), $margin < 0) Then $aPoints[$n][1] = $x1 $aPoints[$n][2] = $y1 $aPoints[$n][3] = $aPts[$n][3] + $margin * Sin($alpha) $aPoints[$n][4] = $aPts[$n][4] - $margin * Cos($alpha) Else $aPoints[$n][1] = $aPts[$n][1] - $margin * Sin($alpha) $aPoints[$n][2] = $aPts[$n][2] + $margin * Cos($alpha) $aPoints[$n][3] = $aPts[$n][3] - $margin * Sin($alpha) $aPoints[$n][4] = $aPts[$n][4] + $margin * Cos($alpha) EndIf Case 2 ; arc $aPoints[$n][0] = 2 $aPoints[$n][1] = $aPts[$n][1] $aPoints[$n][2] = $aPts[$n][2] $aPoints[$n][4] = $aPts[$n][4] $aPoints[$n][5] = $aPts[$n][5] $posx = $aPts[$n][1] + ($aPts[$n][3] - $margin) * Cos($aPts[$n][4] / $Rad2Deg) $posy = $aPts[$n][2] + ($aPts[$n][3] - $margin) * Sin($aPts[$n][4] / $Rad2Deg) ConsoleWrite("posx, posy = " & $posx & ', ' & $posy & @CRLF) If BitXOR(_PointInLineArcPoly($posx, $posy, $aPts), $margin < 0) Then ConsoleWrite("is inside" & @CRLF) $aPoints[$n][3] = $aPts[$n][3] - $margin Else $aPoints[$n][3] = $aPts[$n][3] + $margin EndIf EndSwitch Next ;_ArrayDisplay($aPoints) Return $aPoints EndFunc ;==>_CreateInnerOuterCopy ;=========== _GetParallelStLines ====================== ;returns an array containing the end points for 2 parallel lines to $x1, $y1 to $x2, $y2 ; the lines are either side of the given line displaced by a distance $gap measured at right angles to the line. Func _GetParallelStLine($x1, $y1, $x2, $y2, $gap) Local $slope, $alpha, $beta, $n Dim $Res[4] ;get angle of line in radians $alpha = ATan(($y2 - $y1) / ($x2 - $x1)) $Res[0] = $x1 + $gap * Cos($alpha) $Res[2] = $x2 + $gap * Cos($alpha) $Res[1] = $x1 + $gap * Sin($alpha) $Res[3] = $x2 + $gap * Sin($alpha) EndFunc ;==>_GetParallelStLine #region drawing functions Func _DrawPolyLineArc($aP, $hGr, $colour = 0, $lineWid = 1) Local $hPen = _GDIPlus_PenCreate(0xff000000 + $colour, $lineWid) For $j = 1 To $aP[0][0] Switch $aP[$j][0] Case 1 _DrawStLine($aP, $j, $hGr, $hPen) Case 2 _DrawArc($aP, $j, $hGr, $hPen) EndSwitch Next _GDIPlus_PenDispose($hPen) EndFunc ;==>_DrawPolyLineArc Func _DrawStLine($aK, $i, $graphic, $hPen = 0) _GDIPlus_GraphicsDrawLine($graphic, $aK[$i][1], $aK[$i][2], $aK[$i][3], $aK[$i][4], $hPen) EndFunc ;==>_DrawStLine Func _DrawArc($aM, $i, $graphic, $hPen = 0) _GDIPlus_GraphicsDrawArc($graphic, $aM[$i][1] - $aM[$i][3], $aM[$i][2] - $aM[$i][3], $aM[$i][3] * 2, $aM[$i][3] * 2, $aM[$i][4], $aM[$i][5], $hPen) EndFunc ;==>_DrawArc #endregion drawing functions #region checking point functions Func _PointInLineArcPoly($Px, $Py, $aP) Local $Res = 0, $j For $j = 1 To $aP[0][0] ;If $j = 10 Then Switch $aP[$j][0] Case 1 If _IsPtLeftOfLine($Px, $Py, $aP[$j][1], $aP[$j][2], $aP[$j][3], $aP[$j][4]) Then $Res += 1 EndIf Case 2 If _IsPtInArc($Px, $Py, $aP[$j][1], $aP[$j][2], $aP[$j][3], $aP[$j][4], $aP[$j][5]) Then $Res += 1 EndIf EndSwitch ;EndIf Next Return Mod($Res, 2) = 1 EndFunc ;==>_PointInLineArcPoly Func _IsPtLeftOfLine($Rx, $Ry, $x1, $y1, $x2, $y2) If $Ry >= Max($y1, $y2) Or $Ry < Min($y1, $y2) Then Return False EndIf Return $Rx < ($Ry - $y1) * ($x2 - $x1) / ($y2 - $y1) + $x1 EndFunc ;==>_IsPtLeftOfLine ;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 start angle plus sweep ;Returns True if a horizontal line draw from the point to the right cuts the arc ; once. If the horizontal line hits an end of the arc then it returns true only if that end is a top. A top end means ; the arc moves down away from that end. ; If the horizontal line is a tangent to the arc then it returns false. ;Author - martin ;version 3 Func _IsPtInArc($xPt, $yPt, $xR, $yR, $Rad, $StAngle, $Sw) Local $EndAngle, $Alpha1, $Alpha2, $Result1 = False, $Result2 = False Local $way = 1, $Atemp, $beta, $j ;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 $beta = ASin(Abs(($yPt - $yR) / $Rad)) $Alpha1 = $beta * $Rad2Deg Select Case $yPt > $yR $Alpha2 = 180 - $Alpha1 Case $yPt <= $yR $Alpha2 = 180 + $Alpha1 $Alpha1 = 360 - $Alpha1 EndSelect $Result1 = _AngleInRange($Alpha1, $StAngle, $Sw) And ($Rad * Abs(Cos($beta)) + $xR) > $xPt ;ConsoleWrite("$yPt,$Alpha1, $StAngle, $Sw = " & $yPt & ', ' & $Alpha1 & ", " & $StAngle & ', ' & $Sw & @CRLF) ;if alpha2 is 90 or 270 then alpha1 is as well and we mustn't count the same point twice if it's the end of the arc ;but we only have to check 270 because 90 is the bottom which is always false if it's an end of the arc If $Alpha2 = 270 And _OneIsSameAngle($StAngle, $StAngle + $Sw, 270) Then $Result2 = False Else $Result2 = _AngleInRange($Alpha2, $StAngle, $Sw) And (-$Rad * Abs(Cos($beta)) + $xR) > $xPt EndIf ;ConsoleWrite("$result1, $result2 = " & $Result1 & $Result2 & @CRLF) Return BitXOR($Result1, $Result2) = 1 EndFunc ;==>_IsPtInArc Func _OneIsSameANgle($A, $B, $C) _SetAngle($A) _SetAngle($B) Return BitXOR(($A = $C), ($B = $C)) EndFunc ;==>_OneIsSameANgle ;=== SetAngle ========== ;converts the angle to be in range 0 to 360 Func _SetAngle(ByRef $aS) While $aS < 0 $aS += 360 WEnd While $aS > 360 $aS -= 360 WEnd EndFunc ;==>_SetAngle Func _AngleInRange($ang, $startA, $sweepA) Local $S1, $E1, $Temp Local $aa, $bb If $sweepA >= 360 Then Return True $aa = $startA _SetAngle($aa) $bb = $startA + $sweepA _SetAngle($bb) If $ang = $aa Then;check if start a top or bottom type of end If $sweepA > 0 Then return ($ang >= 270 And $ang <= 360) Or ($ang >= 0 And $ang < 90) EndIf If $sweepA < 0 Then Return $ang > 90 And $ang <= 270 EndIf EndIf If $ang = $bb Then; is end a top or bottom type If $sweepA < 0 Then return ($ang >= 270 And $ang <= 360) Or ($ang >= 0 And $ang < 90) EndIf If $sweepA > 0 Then Return $ang > 90 And $ang <= 270 EndIf EndIf If $sweepA < 0 Then $S1 = $startA + $sweepA $E1 = $startA Else $S1 = $startA $E1 = $startA + $sweepA EndIf While $S1 < 0 $S1 += 360 $E1 += 360 WEnd While $ang < $S1 $ang += 360 WEnd While $ang > $E1 $ang -= 360 WEnd Return $ang >= $S1 And $ang <= $E1 EndFunc ;==>_AngleInRange #endregion checking point functions ;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));,$RDW_ALLCHILDREN Return $GUI_RUNDEFMSG EndFunc ;==>MY_PAINT Func Max($A, $B) If $A >= $B Then Return $A Return $B EndFunc ;==>Max Func Min($A, $B) If $A >= $B Then Return $B Return $A EndFunc ;==>Min EDIT 26th March 2011 - Added colour parameter to line drawing functions. Added ability of _CreateInnerOuterCopy to deal with straight lines at any angle provided they join arcs at a tangent. Added an example of converting lines in a shape to pipes. Edited March 27, 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 25, 2011 Author Share Posted March 25, 2011 Mrtn The good news is your _AreaPoly() function returns the same result as the _AreaPoly() function in the first post #1, this thread. And again, welcome to the forums. Martin Using your example for the routing tool path, post #25, I used this Case $hButton1 For $i = 5 To 120 Step 5 _DrawPolyLineArc(_CreateInnerOuterCopy($aPoints, $hGraphic, $i), $hGraphic) _GDIPlus_GraphicsDrawImage($hGraphicGUI, $hBMPBuff, 0, 0) Next The objective being to route the entire area within the shape. I am not certain what the parameter "$Sw" in IsPtInArc() stands for, $EndAngle or $fSweepAngle? [A thought] Just as "$Rx, $Ry" replaces "$hGraphics" in _GDIPlus_GraphicsDrawLine($hGraphics, $iX1, $iY1, $iX2, $iY2[, $hPen = 0]) to get the _IsPtLeftOfLine($Rx, $Ry, $iX1, $iY1, $iX2, $iY2) function, I thought from _GDIPlus_GraphicsDrawArc($hGraphics, $iX, $iY, $iWidth, $iHeight, $fStartAngle, $fSweepAngle[, $hPen = 0]) the function _IsPtInArc($Rx, $Ry, $iX, $iY, $iWidth, $iHeight, $fStartAngle, $fSweepAngle) would be a logical step - having matching parameters. Or more correctly, it should be called _IsPtLeftOfArc(). [Theory] If a specific shape is made-up of a number of connecting lines and arcs, then, with the same number of appropiate _IsPtLeftOfLine()'s and _IsPtLeftOfArc()'s combined with BitXOR(), it can be determinined if a point is inside or outside of that specific shape. Because, as mention before, imagine a point traveling in a horizontal line from right to left. 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. [Progress] Using your old _IsPtInArc() function, determining if a point is in or outside the "arc and chord" shape works. However, determining a point on the two pie shapes do not work correctly. Using your new _IsPtInArc() function in my example, none of the shapes worked correctly. Here is the example I have been trying to get to work. expandcollapse popup#include <GuiConstantsEx.au3> #include <GDIPlus.au3> #include <WinAPI.au3> #include <WindowsConstants.au3> #include <Array.au3> Global $a1, $a2 Opt('MustDeclareVars', 1) Opt("MouseCoordMode", 2);1=absolute, 0=relative, 2=client Global $hGUI, $hBMPBuff, $hGraphicGUI, $hGraphic, $hBrush1 _Main() Func _Main() Local $msg, $aPos, $GuiSizeX = 400, $GuiSizeY = 300 ; Create GUI $hGUI = GUICreate("GDI+", $GuiSizeX, $GuiSizeY) GUISetState() _GDIPlus_Startup() $hGraphicGUI = _GDIPlus_GraphicsCreateFromHWND($hGUI) $hBMPBuff = _GDIPlus_BitmapCreateFromGraphics($GuiSizeX, $GuiSizeY, $hGraphicGUI) $hGraphic = _GDIPlus_ImageGetGraphicsContext($hBMPBuff) _GDIPlus_GraphicsClear($hGraphic, 0xFFE8FFEF) ;arc and chord shape Local $iCircleX = 240, $iCircleY = 100, $iCircleWidth = 80, $iCircleHth = 80 _GDIPlus_GraphicsDrawArc($hGraphic, $iCircleX, $iCircleY, $iCircleWidth, $iCircleHth, -30, -170) Local $aChPt = _ArcChord($iCircleX, $iCircleY, $iCircleWidth, $iCircleHth, -30, -170) _GDIPlus_GraphicsDrawLine($hGraphic, $aChPt[0], $aChPt[1], $aChPt[2], $aChPt[3]) $hBrush1 = _GDIPlus_BrushCreateSolid(0xFFFF0000) ; Red centre of circle _GDIPlus_GraphicsFillEllipse($hGraphic, 278, 138, 4, 4, $hBrush1) ;missing pie slice shape Local $iCX = 60, $iCY = 10, $iCWidth = 100, $iCHth = 100, $iStartAng = 130, $iSweepAngle = 330 _GDIPlus_GraphicsDrawArc($hGraphic, $iCX, $iCY, $iCWidth, $iCHth, $iStartAng, $iSweepAngle) Local $aChPt1 = _ArcChord($iCX, $iCY, $iCWidth, $iCHth, $iStartAng, $iSweepAngle) ;_ArrayDisplay($aChPt1) Local $iCentX = $iCX + $iCWidth / 2, $iCentY = $iCY + $iCHth / 2 _GDIPlus_GraphicsDrawLine($hGraphic, $aChPt1[0], $aChPt1[1], $iCentX, $iCentY) _GDIPlus_GraphicsDrawLine($hGraphic, $iCentX, $iCentY, $aChPt1[2], $aChPt1[3]) ;Pie slice shape Local $iCX2 = 40, $iCY2 = 120, $iCWidth2 = 300, $iCHth2 = 300, $iStartAng2 = 190, $iSweepAngle2 = 50 ; or $iStartAng2 = -170, _GDIPlus_GraphicsDrawArc($hGraphic, $iCX2, $iCY2, $iCWidth2, $iCHth2, $iStartAng2, $iSweepAngle2) Local $aChPt2 = _ArcChord($iCX2, $iCY2, $iCWidth2, $iCHth2, $iStartAng2, $iSweepAngle2) Local $iCentX2 = $iCX2 + $iCWidth2 / 2, $iCentY2 = $iCY2 + $iCHth2 / 2 _GDIPlus_GraphicsDrawLine($hGraphic, $aChPt2[0], $aChPt2[1], $iCentX2, $iCentY2) _GDIPlus_GraphicsDrawLine($hGraphic, $iCentX2, $iCentY2, $aChPt2[2], $aChPt2[3]) 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) While 1 $msg = GUIGetMsg() Switch $msg Case $GUI_EVENT_CLOSE _GDIPlus_GraphicsDispose($hGraphic) _GDIPlus_GraphicsDispose($hGraphicGUI) _WinAPI_DeleteObject($hBMPBuff) _GDIPlus_BrushDispose($hBrush1) _GDIPlus_Shutdown() Exit Case $GUI_EVENT_MOUSEMOVE $aPos = MouseGetPos() ToolTip("Mouse Position X: " & $aPos[0] & " Y: " & $aPos[1] & @CRLF & @CRLF & _ "Cursor left of Ist Line missing pie slice: " & _ _IsPtLeftOfLine($aPos[0], $aPos[1], $iCentX, $iCentY, $aChPt1[2], $aChPt1[3]) & @CRLF & _ "Cursor left of 2nd Line missing pie slice: " & _ _IsPtLeftOfLine($aPos[0], $aPos[1], $aChPt1[0], $aChPt1[1], $iCentX, $iCentY) & @CRLF & _ "Cursor left of arc: " & _ _IsPtInArc($aPos[0], $aPos[1], $iCentX, $iCentY, $iCWidth / 2, 290, 260) & @CRLF & _ "Cursor in missing pie slice shape: " & _ BitXOR(_IsPtLeftOfLine($aPos[0], $aPos[1], $iCentX, $iCentY, $aChPt1[2], $aChPt1[3]), _ _IsPtLeftOfLine($aPos[0], $aPos[1], $aChPt1[0], $aChPt1[1], $iCentX, $iCentY), _ _IsPtInArc($aPos[0], $aPos[1], $iCentX, $iCentY, $iCWidth / 2, 290, 260)) & @CRLF & @CRLF & _ "Cursor in Pie slice shape: " & _ BitXOR(_IsPtLeftOfLine($aPos[0], $aPos[1], $aChPt2[0], $aChPt2[1], $iCentX2, $iCentY2), _ _IsPtLeftOfLine($aPos[0], $aPos[1], $iCentX2, $iCentY2, $aChPt2[2], $aChPt2[3]), _ _IsPtInArc($aPos[0], $aPos[1], $iCentX2, $iCentY2, $iCWidth2 / 2, 240, 190)) & @CRLF & _ _IsPtLeftOfLine($aPos[0], $aPos[1], $aChPt2[0], $aChPt2[1], $iCentX2, $iCentY2) & " " & _ _IsPtLeftOfLine($aPos[0], $aPos[1], $iCentX2, $iCentY2, $aChPt2[2], $aChPt2[3]) & " " & _ _IsPtInArc($aPos[0], $aPos[1], $iCentX2, $iCentY2, $iCWidth2 / 2, 120, 170) & @CRLF & @CRLF & _ "Cursor in arc and chord: " & _ BitXOR(_IsPtLeftOfLine($aPos[0], $aPos[1], $aChPt[0], $aChPt[1], $aChPt[2], $aChPt[3]), _ _IsPtInArc($aPos[0], $aPos[1], $iCircleX + $iCircleWidth / 2, $iCircleY + $iCircleHth / 2, $iCircleWidth / 2, 30, 200)) & @CRLF & _ "Cursor left of line: " & _IsPtLeftOfLine($aPos[0], $aPos[1], $aChPt[0], $aChPt[1], $aChPt[2], $aChPt[3]) & @CRLF & _ "Cursor in Arc: " & _IsPtInArc($aPos[0], $aPos[1], $iCircleX + $iCircleWidth / 2, $iCircleY + $iCircleHth / 2, _ $iCircleWidth / 2, 30, 200) & @CRLF) Case $GUI_EVENT_PRIMARYUP $aPos = MouseGetPos() EndSwitch WEnd EndFunc ;==>_Main ;Parameter:- ; $x, $y - coordinates of point to be checked. ; $x1, $y1 - coordinates of one end of the line. ; $x2, $y2 - coordinates of the other end of the line. ; Returns True if check point is left of line, else false. ; Remarks:- ;I. quadrant 0 to pi/2 ;II. quadrant pi/2 to pi ;III.quadrant pi to -pi/2 ;IV. quadrant -pi/2 to 0 ; ; -pi/2 [270] ; III | IV ; | ; pi [180] -----|----> 0 or 2*pi [360](X positive axis) ; | ; II | I ; pi/2 [90] (Y positive axis) ; ; Author - Malkey Func _IsPtLeftOfLine($x, $y, $x1, $y1, $x2, $y2) ;Local $Maxy = Iif($y1 > $y2, $y1, $y2) ; $y must be below $Maxy; and, ;Local $Miny = Iif($y1 <= $y2, $y1, $y2) ; $y must be above $Miny to be true (vertically). ; $x on the line = (-$y * $x2 + $y * $x1 + $y1 * $x2 - $x1 * $y2) / (-$y2 + $y1) (horizontally) Return ($x < (-$y * $x2 + $y * $x1 + $y1 * $x2 - $x1 * $y2) / (-$y2 + $y1) And _ $y < Iif($y1 > $y2, $y1, $y2) And $y > Iif($y1 <= $y2, $y1, $y2)) EndFunc ;==>_IsPtLeftOfLine ;Parameters:- ; $xL - The X coordinate of the upper left corner of the rectangle that bounds the ellipse in which to draw the arc. ; $yT - The Y coordinate of the upper left corner of the rectangle that bounds the ellipse in which to draw the arc. ; $iCircleWidth - The width of the rectangle that bounds the ellipse in which to draw the arc. ; $iCircleHth - The height of the rectangle that bounds the ellipse in which to draw the arc. ; $StAngle - The angle between the X axis and the starting point of the arc. ; $EndAngle - The angle between the starting and ending points of the arc. ;Returns an array:- ; $aRet[0]=$x1, $aRet[1]=$y1, $aRet[2]=$x2, $aRet[3]=$y2 where points ($x1, $y1) and ($x2, $y2) are the ; start and end coordinates of arc. ; ;Author - Malkey Func _ArcChord($xL, $yT, $iCircleWidth, $iCircleHth, $StAngle, $iSweepAngle) Local $xR = $xL + $iCircleWidth / 2 Local $yR = $yT + $iCircleHth / 2 Local $Rad = $iCircleWidth / 2 Local $pi = 4 * ATan(1), $aRet[4] $aRet[0] = Round($Rad * Cos($StAngle * $pi / 180) + $xR) $aRet[1] = Round($Rad * Sin($StAngle * $pi / 180) + $yR) $aRet[2] = Round($Rad * Cos(($StAngle + $iSweepAngle) * $pi / 180) + $xR) $aRet[3] = Round($Rad * Sin(($StAngle + $iSweepAngle) * $pi / 180) + $yR) Return $aRet ;ConsoleWrite($aRet[0] & ", " & $aRet[1] & ", " & $aRet[2] & ", " & $aRet[3] & @CRLF) EndFunc ;==>_ArcChord ;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 angle 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 ; $xPt, $yPt, $xR, $yR, $Rad, $StAngle, $Sw) 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 < 0 $StAngle = Mod($StAngle, 360) WEnd While $EndAngle < 0 $EndAngle = Mod($EndAngle, 360) 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 ;=============================================================== Func _IsPtInArcNew($xPt, $yPt, $xR, $yR, $Rad, $StAngle, $Sw) ; <====== $Sw ????????????? ====== Local $EndAngle, $Alpha1, $Alpha2, $Result1 = False, $Result2 = False Local $way = 1, $Atemp, $beta, $j Local $pi = 4 * ATan(1), $Deg2Rad = 180 / $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 $beta = ASin(Abs(($yPt - $yR) / $Rad)) $Alpha1 = $beta * $Deg2Rad Select Case $yPt > $yR $Alpha2 = 180 - $Alpha1 Case $yPt <= $yR $Alpha2 = 180 + $Alpha1 $Alpha1 = 360 - $Alpha1 EndSelect $Result1 = _AngleInRange($Alpha1, $StAngle, $Sw) And ($Rad * Abs(Cos($beta)) + $xR) > $xPt ;ConsoleWrite("$yPt,$Alpha1, $StAngle, $Sw = " & $yPt & ', ' & $Alpha1 & ", " & $StAngle & ', ' & $Sw & @CRLF) ;if alpha2 is 90 or 270 then alpha1 is as well and we mustn't count the same point twice if it's the end of the arc ;but we only have to check 270 because 90 is the bottom which is always false if it's an end of the arc If $Alpha2 = 270 and _OneIsSameAngle($StAngle,$StAngle + $sw,270) Then $result2 = False Else $Result2 = _AngleInRange($Alpha2, $StAngle, $Sw) And (-$Rad * Abs(Cos($beta)) + $xR) > $xPt EndIf ;ConsoleWrite("$result1, $result2 = " & $Result1 & $Result2 & @CRLF) Return BitXOR($Result1, $Result2) = 1 EndFunc ;==>_IsPtInArc ;=== SetAngle ========== ;converts the angle to be in range 0 to 360 func _SetAngle(ByRef $aS) while $aS < 0 $aS += 360 WEnd while $aS > 360 $aS -= 360 ; <======= Corrected this ========== WEnd EndFunc Func _AngleInRange($ang, $startA, $sweepA) Local $S1, $E1, $Temp Local $aa, $bb If $sweepA >= 360 Then Return True $aa = $startA _SetAngle($aa) $bb = $startA + $sweepA _SetAngle($bb) If $ang = $aa Then;check if start a top or bottom type of end If $sweepA > 0 Then return ($ang >= 270 And $ang <= 360) Or ($ang >= 0 And $ang < 90) EndIf If $sweepA < 0 Then Return $ang > 90 And $ang <= 270 EndIf EndIf If $ang = $bb Then; is end a top or bottom type If $sweepA < 0 Then return ($ang >= 270 And $ang <= 360) Or ($ang >= 0 And $ang < 90) EndIf If $sweepA > 0 Then Return $ang > 90 And $ang <= 270 EndIf EndIf If $sweepA < 0 Then $S1 = $startA + $sweepA $E1 = $startA Else $S1 = $startA $E1 = $startA + $sweepA EndIf While $S1 < 0 $S1 += 360 $E1 += 360 WEnd While $ang < $S1 $ang += 360 WEnd While $ang > $E1 $ang -= 360 WEnd Return $ang >= $S1 And $ang <= $E1 EndFunc ;==>_AngleInRange func _OneIsSameANgle($A,$B,$C) _SetAngle($A) _SetAngle($B) if $A = $C or $B = $C then return True return False EndFunc ;=============================================================== ; 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 [Conclusion] Seeing your example is working correctly and my approach is not working, I will be using your method until something better comes along. Malkey Link to comment Share on other sites More sharing options...
martin Posted March 25, 2011 Share Posted March 25, 2011 (edited) I am not certain what the parameter "$Sw" in IsPtInArc() stands for, $EndAngle or $fSweepAngle? $Sw is the sweep. I did have it as the endangle but changed it and then forgot to change the comments.I prefer point in arc rather than point left of arc. If the arc is a circle and the point is inside the circle then it is obvious that the function is telling you the point is inside the arc. If the point is to the left of the circle it returns false which you wouldn't expect if it was called IsPtToLeftOfArc. If the arc is only say from 180 to 450 then it is not obvious that the point is in the arc if the function returns true when the point is far away to the left but below the centre of the circle. The function returns true if the horizontal line from the point to + infinity cuts the arc once. Maybe I should think of a better name. The function is "is the height of the point between the highest and lowest points of the arc that exist for values of x greater than the x position of the point".I'll have a look at your example tonight and see if I can see why it doesn't work.EDIT. Adding a pen parameter to the functions would be sensible so I'll do that. Edited March 25, 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...
martin Posted March 25, 2011 Share Posted March 25, 2011 (edited) Malkey, here is your example but modified. I changed the angles in your _IsPtInArc commands, I changed the _IsPtInArc function to the latest version I have used in my previous examples, and I commented out your IsPtLeftOfLine and used my version because yours seemed to give the wrong result when the cursor was at the top of the line in the arc and chord shape, but I didn't spend the time to see what the difference is. expandcollapse popup#include <GuiConstantsEx.au3> #include <GDIPlus.au3> #include <WinAPI.au3> #include <WindowsConstants.au3> #include <Array.au3> Global $a1, $a2 Global $pi = 4 * ATan(1) Global $Rad2Deg = 180 / $pi Opt('MustDeclareVars', 1) Opt("MouseCoordMode", 2);1=absolute, 0=relative, 2=client Global $hGUI, $hBMPBuff, $hGraphicGUI, $hGraphic, $hBrush1 _Main() Func _Main() Local $msg, $aPos, $GuiSizeX = 400, $GuiSizeY = 300 ; Create GUI $hGUI = GUICreate("GDI+", $GuiSizeX, $GuiSizeY) GUISetState() _GDIPlus_Startup() $hGraphicGUI = _GDIPlus_GraphicsCreateFromHWND($hGUI) $hBMPBuff = _GDIPlus_BitmapCreateFromGraphics($GuiSizeX, $GuiSizeY, $hGraphicGUI) $hGraphic = _GDIPlus_ImageGetGraphicsContext($hBMPBuff) _GDIPlus_GraphicsClear($hGraphic, 0xFFE8FFEF) ;arc and chord shape Local $iCircleX = 240, $iCircleY = 100, $iCircleWidth = 80, $iCircleHth = 80 _GDIPlus_GraphicsDrawArc($hGraphic, $iCircleX, $iCircleY, $iCircleWidth, $iCircleHth, -30, -170) Local $aChPt = _ArcChord($iCircleX, $iCircleY, $iCircleWidth, $iCircleHth, -30, -170) _GDIPlus_GraphicsDrawLine($hGraphic, $aChPt[0], $aChPt[1], $aChPt[2], $aChPt[3]) $hBrush1 = _GDIPlus_BrushCreateSolid(0xFFFF0000) ; Red centre of circle _GDIPlus_GraphicsFillEllipse($hGraphic, 278, 138, 4, 4, $hBrush1) ;missing pie slice shape Local $iCX = 60, $iCY = 10, $iCWidth = 100, $iCHth = 100, $iStartAng = 130, $iSweepAngle = 330 _GDIPlus_GraphicsDrawArc($hGraphic, $iCX, $iCY, $iCWidth, $iCHth, $iStartAng, $iSweepAngle) Local $aChPt1 = _ArcChord($iCX, $iCY, $iCWidth, $iCHth, $iStartAng, $iSweepAngle) ;_ArrayDisplay($aChPt1) Local $iCentX = $iCX + $iCWidth / 2, $iCentY = $iCY + $iCHth / 2 _GDIPlus_GraphicsDrawLine($hGraphic, $aChPt1[0], $aChPt1[1], $iCentX, $iCentY) _GDIPlus_GraphicsDrawLine($hGraphic, $iCentX, $iCentY, $aChPt1[2], $aChPt1[3]) ;Pie slice shape Local $iCX2 = 40, $iCY2 = 120, $iCWidth2 = 300, $iCHth2 = 300, $iStartAng2 = 190, $iSweepAngle2 = 50 ; or $iStartAng2 = -170, _GDIPlus_GraphicsDrawArc($hGraphic, $iCX2, $iCY2, $iCWidth2, $iCHth2, $iStartAng2, $iSweepAngle2) Local $aChPt2 = _ArcChord($iCX2, $iCY2, $iCWidth2, $iCHth2, $iStartAng2, $iSweepAngle2) Local $iCentX2 = $iCX2 + $iCWidth2 / 2, $iCentY2 = $iCY2 + $iCHth2 / 2 _GDIPlus_GraphicsDrawLine($hGraphic, $aChPt2[0], $aChPt2[1], $iCentX2, $iCentY2) _GDIPlus_GraphicsDrawLine($hGraphic, $iCentX2, $iCentY2, $aChPt2[2], $aChPt2[3]) 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) While 1 $msg = GUIGetMsg() Switch $msg Case $GUI_EVENT_CLOSE _GDIPlus_GraphicsDispose($hGraphic) _GDIPlus_GraphicsDispose($hGraphicGUI) _WinAPI_DeleteObject($hBMPBuff) _GDIPlus_BrushDispose($hBrush1) _GDIPlus_Shutdown() Exit Case $GUI_EVENT_MOUSEMOVE $aPos = MouseGetPos() ToolTip("Mouse Position X: " & $aPos[0] & " Y: " & $aPos[1] & @CRLF & @CRLF & _ "Cursor in pie : " & _ BitXOR( _IsPtLeftOfLine($aPos[0], $aPos[1], $iCentX, $iCentY, $aChPt1[2], $aChPt1[3]), _ _IsPtLeftOfLine($aPos[0], $aPos[1], $aChPt1[0], $aChPt1[1], $iCentX, $iCentY), _ _IsPtInArc($aPos[0], $aPos[1], $iCentX, $iCentY, $iCWidth / 2, 130, 330)) & @CRLF & _ "Cursor left of Ist Line missing pie slice: " & _ _IsPtLeftOfLine($aPos[0], $aPos[1], $iCentX, $iCentY, $aChPt1[2], $aChPt1[3]) & @CRLF & _ "Cursor left of 2nd Line missing pie slice: " & _ _IsPtLeftOfLine($aPos[0], $aPos[1], $aChPt1[0], $aChPt1[1], $iCentX, $iCentY) & @CRLF & _ "Cursor left of arc: " & _ _IsPtInArc($aPos[0], $aPos[1], $iCentX, $iCentY, $iCWidth / 2, 130, 330) & @CRLF & _ "Cursor in missing pie slice shape: " & _ BitXOR(_IsPtLeftOfLine($aPos[0], $aPos[1], $iCentX, $iCentY, $aChPt1[2], $aChPt1[3]), _ _IsPtLeftOfLine($aPos[0], $aPos[1], $aChPt1[0], $aChPt1[1], $iCentX, $iCentY), _ _IsPtInArc($aPos[0], $aPos[1], $iCentX, $iCentY, $iCWidth / 2, 100, 30)) & @CRLF & @CRLF & _ "Cursor in Pie slice shape: " & _ BitXOR(_IsPtLeftOfLine($aPos[0], $aPos[1], $aChPt2[0], $aChPt2[1], $iCentX2, $iCentY2), _ _IsPtLeftOfLine($aPos[0], $aPos[1], $iCentX2, $iCentY2, $aChPt2[2], $aChPt2[3]), _ _IsPtInArc($aPos[0], $aPos[1], $iCentX2, $iCentY2, $iCWidth2 / 2, $iStartAng2, $iSweepAngle2)) & @CRLF & _ _IsPtLeftOfLine($aPos[0], $aPos[1], $aChPt2[0], $aChPt2[1], $iCentX2, $iCentY2) & " " & _ _IsPtLeftOfLine($aPos[0], $aPos[1], $iCentX2, $iCentY2, $aChPt2[2], $aChPt2[3]) & " " & _ _IsPtInArc($aPos[0], $aPos[1], $iCentX2, $iCentY2, $iCWidth2 / 2, 190, 50) & @CRLF & @CRLF & _ "Cursor in arc and chord: " & _ BitXOR(_IsPtLeftOfLine($aPos[0], $aPos[1], $aChPt[0], $aChPt[1], $aChPt[2], $aChPt[3]), _ _IsPtInArc($aPos[0], $aPos[1], $iCircleX + $iCircleWidth / 2, $iCircleY + $iCircleHth / 2, $iCircleWidth / 2, -30, -170)) & @CRLF & _ "Cursor left of line: " & _IsPtLeftOfLine($aPos[0], $aPos[1], $aChPt[0], $aChPt[1], $aChPt[2], $aChPt[3]) & @CRLF & _ "Cursor in Arc: " & _IsPtInArc($aPos[0], $aPos[1], $iCircleX + $iCircleWidth / 2, $iCircleY + $iCircleHth / 2, _ $iCircleWidth / 2, -30, -170) & @CRLF) Case $GUI_EVENT_PRIMARYUP $aPos = MouseGetPos() EndSwitch WEnd EndFunc ;==>_Main #cs ;Parameter:- ; $x, $y - coordinates of point to be checked. ; $x1, $y1 - coordinates of one end of the line. ; $x2, $y2 - coordinates of the other end of the line. ; Returns True if check point is left of line, else false. ; Remarks:- ;I. quadrant 0 to pi/2 ;II. quadrant pi/2 to pi ;III.quadrant pi to -pi/2 ;IV. quadrant -pi/2 to 0 ; ; -pi/2 [270] ; III | IV ; | ; pi [180] -----|----> 0 or 2*pi [360](X positive axis) ; | ; II | I ; pi/2 [90] (Y positive axis) ; ; Author - Malkey Func _IsPtLeftOfLine($x, $y, $x1, $y1, $x2, $y2) ;Local $Maxy = Iif($y1 > $y2, $y1, $y2) ; $y must be below $Maxy; and, ;Local $Miny = Iif($y1 <= $y2, $y1, $y2) ; $y must be above $Miny to be true (vertically). ; $x on the line = (-$y * $x2 + $y * $x1 + $y1 * $x2 - $x1 * $y2) / (-$y2 + $y1) (horizontally) Return ($x < (-$y * $x2 + $y * $x1 + $y1 * $x2 - $x1 * $y2) / (-$y2 + $y1) And _ $y < Iif($y1 > $y2, $y1, $y2) And $y > Iif($y1 <= $y2, $y1, $y2)) EndFunc ;==>_IsPtLeftOfLine #ce Func _IsPtLeftOfLine($Rx, $Ry, $X1, $Y1, $X2, $Y2) If $Ry >= Max($Y1, $Y2) Or $Ry < Min($Y1, $Y2) Then Return False EndIf Return $Rx < ($Ry - $Y1) * ($X2 - $X1) / ($Y2 - $Y1) + $X1 EndFunc ;==>_IsPtLeftOfLine ;Parameters:- ; $xL - The X coordinate of the upper left corner of the rectangle that bounds the ellipse in which to draw the arc. ; $yT - The Y coordinate of the upper left corner of the rectangle that bounds the ellipse in which to draw the arc. ; $iCircleWidth - The width of the rectangle that bounds the ellipse in which to draw the arc. ; $iCircleHth - The height of the rectangle that bounds the ellipse in which to draw the arc. ; $StAngle - The angle between the X axis and the starting point of the arc. ; $EndAngle - The angle between the starting and ending points of the arc. ;Returns an array:- ; $aRet[0]=$x1, $aRet[1]=$y1, $aRet[2]=$x2, $aRet[3]=$y2 where points ($x1, $y1) and ($x2, $y2) are the ; start and end coordinates of arc. ; ;Author - Malkey Func _ArcChord($xL, $yT, $iCircleWidth, $iCircleHth, $StAngle, $iSweepAngle) Local $xR = $xL + $iCircleWidth / 2 Local $yR = $yT + $iCircleHth / 2 Local $Rad = $iCircleWidth / 2 Local $pi = 4 * ATan(1), $aRet[4] $aRet[0] = Round($Rad * Cos($StAngle * $pi / 180) + $xR) $aRet[1] = Round($Rad * Sin($StAngle * $pi / 180) + $yR) $aRet[2] = Round($Rad * Cos(($StAngle + $iSweepAngle) * $pi / 180) + $xR) $aRet[3] = Round($Rad * Sin(($StAngle + $iSweepAngle) * $pi / 180) + $yR) Return $aRet ;ConsoleWrite($aRet[0] & ", " & $aRet[1] & ", " & $aRet[2] & ", " & $aRet[3] & @CRLF) EndFunc ;==>_ArcChord ;is pt in arc ;Parameters $xPt, $yPt the coords of the point ; $xR, $yR the centre of the arc ; $Rad the arc radius ; $StAngle, $sw the start and sweep angle in degrees ;Only deals with circular arcs though same approach can be used with elliptical arcs. ;The arc is drawn from start angle to start angle plus sweep ;Returns True if a horizontal line draw from the point to the right cuts the arc ; once. If the horizontal line hits an end of the arc then it returns true only if that end is a top. A top end means ; the arc moves down away from that end. ; If the horizontal line is a tangent to the arc then it returns false. ;Author - martin ;version 3 Func _IsPtInArc($xPt, $yPt, $xR, $yR, $Rad, $StAngle, $Sw) Local $EndAngle, $Alpha1, $Alpha2, $Result1 = False, $Result2 = False Local $way = 1, $Atemp, $beta, $j ;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 $beta = ASin(Abs(($yPt - $yR) / $Rad)) $Alpha1 = $beta * $Rad2Deg Select Case $yPt > $yR $Alpha2 = 180 - $Alpha1 Case $yPt <= $yR $Alpha2 = 180 + $Alpha1 $Alpha1 = 360 - $Alpha1 EndSelect $Result1 = _AngleInRange($Alpha1, $StAngle, $Sw) And ($Rad * Abs(Cos($beta)) + $xR) > $xPt ;ConsoleWrite("$yPt,$Alpha1, $StAngle, $Sw = " & $yPt & ', ' & $Alpha1 & ", " & $StAngle & ', ' & $Sw & @CRLF) ;if alpha2 is 90 or 270 then alpha1 is as well and we mustn't count the same point twice if it's the end of the arc ;but we only have to check 270 because 90 is the bottom which is always false if it's an end of the arc If $Alpha2 = 270 And _OneIsSameAngle($StAngle, $StAngle + $Sw, 270) Then $Result2 = False Else $Result2 = _AngleInRange($Alpha2, $StAngle, $Sw) And (-$Rad * Abs(Cos($beta)) + $xR) > $xPt EndIf ;ConsoleWrite("$result1, $result2 = " & $Result1 & $Result2 & @CRLF) Return BitXOR($Result1, $Result2) = 1 EndFunc ;==>_IsPtInArc ;=============================================================== Func _IsPtInArcNew($xPt, $yPt, $xR, $yR, $Rad, $StAngle, $Sw) ; <====== $Sw ????????????? ====== Local $EndAngle, $Alpha1, $Alpha2, $Result1 = False, $Result2 = False Local $way = 1, $Atemp, $beta, $j Local $pi = 4 * ATan(1), $Deg2Rad = 180 / $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 $beta = ASin(Abs(($yPt - $yR) / $Rad)) $Alpha1 = $beta * $Deg2Rad Select Case $yPt > $yR $Alpha2 = 180 - $Alpha1 Case $yPt <= $yR $Alpha2 = 180 + $Alpha1 $Alpha1 = 360 - $Alpha1 EndSelect $Result1 = _AngleInRange($Alpha1, $StAngle, $Sw) And ($Rad * Abs(Cos($beta)) + $xR) > $xPt ;ConsoleWrite("$yPt,$Alpha1, $StAngle, $Sw = " & $yPt & ', ' & $Alpha1 & ", " & $StAngle & ', ' & $Sw & @CRLF) ;if alpha2 is 90 or 270 then alpha1 is as well and we mustn't count the same point twice if it's the end of the arc ;but we only have to check 270 because 90 is the bottom which is always false if it's an end of the arc If $Alpha2 = 270 and _OneIsSameAngle($StAngle,$StAngle + $sw,270) Then $result2 = False Else $Result2 = _AngleInRange($Alpha2, $StAngle, $Sw) And (-$Rad * Abs(Cos($beta)) + $xR) > $xPt EndIf ;ConsoleWrite("$result1, $result2 = " & $Result1 & $Result2 & @CRLF) Return BitXOR($Result1, $Result2) = 1 EndFunc ;==>_IsPtInArc ;=== SetAngle ========== ;converts the angle to be in range 0 to 360 func _SetAngle(ByRef $aS) while $aS < 0 $aS += 360 WEnd while $aS > 360 $aS -= 360 ; <======= Corrected this ========== WEnd EndFunc Func _AngleInRange($ang, $startA, $sweepA) Local $S1, $E1, $Temp Local $aa, $bb If $sweepA >= 360 Then Return True $aa = $startA _SetAngle($aa) $bb = $startA + $sweepA _SetAngle($bb) If $ang = $aa Then;check if start a top or bottom type of end If $sweepA > 0 Then return ($ang >= 270 And $ang <= 360) Or ($ang >= 0 And $ang < 90) EndIf If $sweepA < 0 Then Return $ang > 90 And $ang <= 270 EndIf EndIf If $ang = $bb Then; is end a top or bottom type If $sweepA < 0 Then return ($ang >= 270 And $ang <= 360) Or ($ang >= 0 And $ang < 90) EndIf If $sweepA > 0 Then Return $ang > 90 And $ang <= 270 EndIf EndIf If $sweepA < 0 Then $S1 = $startA + $sweepA $E1 = $startA Else $S1 = $startA $E1 = $startA + $sweepA EndIf While $S1 < 0 $S1 += 360 $E1 += 360 WEnd While $ang < $S1 $ang += 360 WEnd While $ang > $E1 $ang -= 360 WEnd Return $ang >= $S1 And $ang <= $E1 EndFunc ;==>_AngleInRange func _OneIsSameANgle($A,$B,$C) _SetAngle($A) _SetAngle($B) Return BitXOR(($A = $C), ($B = $C)) EndFunc ;=============================================================== ; 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 Max($A, $B) If $A >= $B Then Return $A Return $B EndFunc ;==>Max Func Min($A, $B) If $A >= $B Then Return $B Return $A EndFunc ;==>Min Edited March 25, 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 26, 2011 Author Share Posted March 26, 2011 Func _IsPtLeftOfLine($Rx, $Ry, $X1, $Y1, $X2, $Y2) ;If $Ry >= Max($Y1, $Y2) Or $Ry < Min($Y1, $Y2) Then ;~~~~~~~~~~~~^ (Removed Equal sign) If $Ry > Max($Y1, $Y2) Or $Ry < Min($Y1, $Y2) Then Return False EndIf Return $Rx < ($Ry - $Y1) * ($X2 - $X1) / ($Y2 - $Y1) + $X1 EndFunc ;==>_IsPtLeftOfLine Martin Using this in your corrected version of my script that you posted in Post #28, I find this modified, corrected script is working totally as intended. Thanks Martin. Link to comment Share on other sites More sharing options...
martin Posted March 26, 2011 Share Posted March 26, 2011 (edited) Func _IsPtLeftOfLine($Rx, $Ry, $X1, $Y1, $X2, $Y2) ;If $Ry >= Max($Y1, $Y2) Or $Ry < Min($Y1, $Y2) Then ;~~~~~~~~~~~~^ (Removed Equal sign) If $Ry > Max($Y1, $Y2) Or $Ry < Min($Y1, $Y2) Then Return False EndIf Return $Rx < ($Ry - $Y1) * ($X2 - $X1) / ($Y2 - $Y1) + $X1 EndFunc ;==>_IsPtLeftOfLine Martin Using this in your corrected version of my script that you posted in Post #28, I find this modified, corrected script is working totally as intended. Thanks Martin. I don't think that was wrong. Your _ArcChord function rounds the coordinates, and that means the ends of the straight lines are not at the ends of the arc and so there are gaps or cross-overs. If you remove the Round bits then it works again. I've added a colour parameter to the line drawing functions in post #25 and improved the ability of the _CreateInnerOuterCopy function so it can deal with straight lines at any angle, but straight lines must still join arcs at a tangent, The next step is to allow straight lines and arc to join at any angle. Also in post #25 I added an example of converting lines in a shape to pipes which is an unplanned ability of the functions. Edited March 26, 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...
nullschritt Posted March 17, 2015 Share Posted March 17, 2015 Seriously useful for detecting clicks in GDI+ rendered windows, awesome job. Link to comment Share on other sites More sharing options...
UEZ Posted March 17, 2015 Share Posted March 17, 2015 Check out _GDIPlus_PathIsVisiblePoint _GDIPlus_PathIsOutlineVisiblePoint in the help file for another way in GDI+. 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...
JohnOne Posted March 17, 2015 Share Posted March 17, 2015 [optional] Pointer to a Graphics object that specifies a world-to-device transformation. If 0, the test isIs What? AutoIt Absolute Beginners Require a serial Pause Script Video Tutorials by Morthawt ipify Monkey's are, like, natures humans. Link to comment Share on other sites More sharing options...
UEZ Posted March 17, 2015 Share Posted March 17, 2015 (edited) expandcollapse popup; #FUNCTION# ==================================================================================================================== ; Name...........: _GDIPlus_PathIsOutlineVisiblePoint ; Description ...: Determines whether a specified point touches the outline of a path with the specified Graphics and Pen ; Syntax.........: _GDIPlus_PathIsOutlineVisiblePoint($hPath, $fX, $fY[, $hPen = 0[, $hGraphics = 0]]) ; Parameters ....: $hPath - Pointer to a GraphicsPath object ; $fX - X coordinate of the point to test ; $fY - Y coordinate of the point to test ; $hPen - Pointer to a Pen object that define the width of point to test. If 0, a solid black pen with a ; +width of 1 will be used ; $hGraphics - Pointer to a Graphics object that specifies a world-to-device transformation. If 0, the test is ; +done in world coordinates; otherwise, the test is done in device coordinates ; Return values .: Success - True if the point touches the outline of the path, False otherwise ; Failure - -1 ; Author ........: Authenticity ; Modified.......: Eukalyptus ; Remarks .......: None ; Related .......: None ; Link ..........; @@MsdnLink@@ GdipIsOutlineVisiblePathPoint ; Example .......; Yes ; =============================================================================================================================== ; #FUNCTION# ==================================================================================================================== ; Name...........: _GDIPlus_PathIsVisiblePoint ; Description ...: Determines whether a specified point lies in the area that is filled when a path is filled by a specified ; +Graphics object ; Syntax.........: _GDIPlus_PathIsVisiblePoint($hPath, $fX, $fY[, $hGraphics = 0]) ; Parameters ....: $hPath - Pointer to a GraphicsPath object ; $fX - X coordinate of the point to test ; $fY - Y coordinate of the point to test ; $hGraphics - Pointer to a Graphics object that specifies a world-to-device transformation. If 0, the test is ; +done in world coordinates; otherwise, the test is done in device coordinates ; Return values .: Success - True if the point lies in the interior of the path, False otherwise ; Failure - -1 ; Author ........: Authenticity ; Modified.......: Eukalyptus ; Remarks .......: None ; Related .......: None ; Link ..........; @@MsdnLink@@ GdipIsVisiblePathPoint ; Example .......; Yes ; =============================================================================================================================== -> https://msdn.microsoft.com/en-us/library/windows/desktop/ms535578(v=vs.85).aspx?f=255&MSPPError=-2147217396 Edited March 17, 2015 by 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...
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