TheSwamp
Code Red => VB(A) => Topic started by: ReneRam on June 08, 2009, 05:21:50 AM
-
I came out with this discovery, at least for me starting a new program that fills a closed area with blocks. It's just the head start of a bigger thing but usually I give it the first try with VBA since I find faster to develop.
The code that follows creates a sample closed area and then checks if a point, in my case it was the insertion point of the block, is inside the area; a common problem that has different solutions. In my case a simply created a temporary point and checked if it was inside my area, if the result was true then ... insert the block, otherwise skip to next point. Doing my tests I found out that the PointStyle and PointSize variable, that I thought as a graphical display in AutoCAD have real dimensions. I had changed the point style to visually see where my point was going. I you run the code twice commenting on the second run the part where the PDMODE variable is changed, you'll see the differences. Also if you change with the Zoom part before testing if the point is inside you will get different results. I thought a point was was a location with no dimensions. :?
I'm just sharing my discovery in case someone didn't know about it.
Option Explicit
Sub TestPointDimension()
' Draw a closed polyline
Dim points(7) As Double
points(0) = 100#: points(1) = 10#
points(2) = 200#: points(3) = 50#
points(4) = 100#: points(5) = 100#
points(6) = 0#: points(7) = 50#
Dim objLWPoly As AcadLWPolyline
Set objLWPoly = ThisDrawing.ModelSpace.AddLightWeightPolyline(points)
objLWPoly.Closed = True
' Set Spacing of points for the test
' I have set the spacing to 5 just to just to have more false points
' results
Dim XSpacing As Double: XSpacing = 5#
Dim YSpacing As Double: YSpacing = 5#
' Create TestPoint
Dim TestPoint(2) As Double
TestPoint(0) = 0#: TestPoint(1) = 0#: TestPoint(2) = 0#
' Update Viewport
' This is needed to optimize the SelectByPolygon:
' ONLY objects VISIBLE in screen are evaluated
Application.ZoomExtents
Application.Update
' Test with PDMode = 66
ThisDrawing.SetVariable "PDMODE", 66
' I get 419 points Inside the closed area
' and 44 of these are Outside the closed area
' ' Test with PDMode = 0
' ThisDrawing.SetVariable "PDMODE", 0
' ' I get 375 points Inside the closed area
' Star Testing points
Dim objPoint As AcadPoint
' I'm intentionaly going outside the closed area
Do While TestPoint(1) < 150
Do While TestPoint(0) < 250
' Check if element is inside border bounding box
If TestPoint(1) > 150 Then Exit Do
If TestPoint(0) > 250 Then GoTo UpdatePto
' Insert Points
Set objPoint = ThisDrawing.ModelSpace.AddPoint(TestPoint)
Application.Update
' Check if point is inside the closed area
If Not IsInside(objPoint.Coordinates, objLWPoly) Then
' Delete point
objPoint.Delete
End If
UpdatePto:
' Update Insert Point
TestPoint(0) = TestPoint(0) + XSpacing
Loop
' increment row
TestPoint(0) = 0#
TestPoint(1) = TestPoint(1) + YSpacing
TestPoint(2) = TestPoint(2)
Loop
End Sub
' Checks if a Point is inside a lwPolyline
Function IsInside(ByVal acPoint As Variant, lwPoly As AcadLWPolyline) As Boolean
' Initialize Return value
IsInside = False
Dim objSS As AcadSelectionSet ' temporary SelectionSet
Dim initCodes(2) As Integer ' objSS filter codes
Dim varCodeValues(2) As Variant ' objSS filter values
Dim retCoords As Variant ' lwPoly coordinates
Dim PointsArray() As Double ' Array of 3D Points for objSS crossing polygon
Dim retPto As Variant ' coordinates of found point
Dim ent As AcadEntity ' entity
Dim i As Integer ' counter
Dim j As Integer ' counter
' Create SelectionSet
Set objSS = PowerSet("myPolygon")
' DXF Filter
initCodes(0) = -4
varCodeValues(0) = "<AND"
initCodes(1) = 0
varCodeValues(1) = "POINT"
initCodes(2) = -4
varCodeValues(2) = "AND>"
' Retrieve lwPolyline Coordiantes and fill 3D Points for Crossing Polygon
retCoords = lwPoly.Coordinates
ReDim PointsArray((((UBound(retCoords) + 1) / 2) * 3) - 1)
' get the X coordinates
For i = 0 To UBound(PointsArray)
For j = 0 To UBound(retCoords) Step 2
PointsArray(i) = retCoords(j)
i = i + 3
Next j
Next i
' get the Y coordiantes
For i = 1 To UBound(PointsArray)
For j = 1 To UBound(retCoords) Step 2
PointsArray(i) = retCoords(j)
i = i + 3
Next j
Next i
' fill the Z coordinates with 0, lwPolyline doesn't have Z
For i = 2 To UBound(PointsArray) Step 3
PointsArray(i) = 0
Next i
' Fill the objSS
objSS.SelectByPolygon acSelectionSetCrossingPolygon, PointsArray, _
initCodes, varCodeValues
' get ents in objSS
If objSS.Count >= 1 Then
For Each ent In objSS
retPto = ent.Coordinates
If retPto(0) = acPoint(0) And retPto(1) = acPoint(1) Then
IsInside = True
Exit Function
Else
IsInside = False
End If
Next ent
Else
IsInside = False
End If
End Function
'Restituisce un 'SelectionSet' evitando i nomi duplicati
' Credit goes to Randal Rath's Code Troute I think, I use this since (?)
Function PowerSet(setName As String) As AcadSelectionSet
Dim objSS As AcadSelectionSet
Dim objSSCol As AcadSelectionSets
On Error GoTo ErrorHandler
Set objSSCol = ThisDrawing.SelectionSets
For Each objSS In objSSCol
If objSS.Name = setName Then
objSSCol.Item(setName).Delete
Exit For
End If
Next
Set objSS = objSSCol.Add(setName)
Set PowerSet = objSS
ExitHere:
Exit Function
ErrorHandler:
Select Case Err.Number
Case Else
MsgBox Err.Description
Err.Clear
Resume ExitHere
End Select
End Function
I didn't ctry it yet with lisp or .Net, ut guess it will give the same results.
-
You are "checking" based on a crossing selection set which uses VISIBLE objects. When you change the PDMODE & PDSIZE variables the objects are displayed differently, thereby allowing the selection to be able to select more/less depending on how "big" the point is displayed. This is why one of the other IsInside solutions that use mathematical calculations will give far better results.
-
You are "checking" based on a crossing selection set which uses VISIBLE objects.
I agree, What I meant was that I thought the point displayed on the screen was just a graphical thing on the screen and not something AutoCAD could "touch" since it changes zooming. I was convinced that when selecting, even crossing, since it's vectorial drawing and not images, the selection was something pure mathematical.
-
I think anything other than the current behavior would be inconsistent.
Take, for example, C3D Points, which may have labels attached to them, too. If I use a crossing window, I would expect it to select points even if the crossing window only touched part of the label. If points got ignored unless I specifically put the crossing window AROUND the point node, it would be much more annoying, from a user perspective.
It means you can't use that method you are trying to get the results you want, but I think it is consistent with the way a crossing window should work.
-
:| I guess I'm not explaining what I find strange.
If you replace this line in the IsInside function:
' Fill the objSS
objSS.SelectByPolygon acSelectionSetCrossingPolygon, PointsArray, _
initCodes, varCodeValues
with:
' Fill the objSS
objSS.SelectByPolygon acSelectionSetWindowPolygon, PointsArray, _
initCodes, varCodeValues
you're not "crossing", you're using a "window", but in this case the area is filled with holes.
In any case, the method works enough for my purposes, I was just sharing something I thought wasn't much known.