.NET
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

How to select entity with in a line closed AND not using editor.

9 REPLIES 9
SOLVED
Reply
Message 1 of 10
AubelecBE
892 Views, 9 Replies

How to select entity with in a line closed AND not using editor.

I want to load file with database.ReadDwgFile

i dont want use editor (i don't want use CommandFlags.Session)

 

after the load in the database (see my code for xdb), i want to select all bloc within a closed line entity (within the xdb)

but how to do that whitout editor (editor..SelectWindowPolygon )

 

here my code for load each file , and mémorize all block for each file

 

 Dim CollDocOuvert As New Collection
        For Each NomFichier In Fenetre.CollFichier
            'recherche et extraction des blocs
            Dim Fichier As New IO.FileInfo(NomFichier)
            If Fichier.Exists = True Then

                GestionAUTOCAD.TxtOnLigneCOmmande("Gestion du fichier : " & Fichier.Name & vbCrLf)
                'ed.WriteMessage(vbCrLf & "Gestion du fichier : " & Fichier.Name)
                StatusLabelBas.Text = "Gestion de : " & NomFichier
                Me.Refresh()
                'Application.doevent()
                System.Threading.Thread.Sleep(1)

                If CollDocOuvert.Contains(NomFichier.ToUpper) = False Then
                    Dim xdb As Database = New Database(False, True)
                    Using (xdb)
                        Try
                            xdb.ReadDwgFile(NomFichier, System.IO.FileShare.Read, False, "")
                            'Attention(s) 'il n'y a pas de doc ouvert, ne pas utiliser la fonction debug
                            Dim CollBlocRef As New Collection
                            'Attention ici les liens BlockReferences sont inutilisable !
                            GestionBloc.GetDecompteBlocAvecAtt(False, CollBlocRef, False, False, False, "", True, xdb)
                            Dim El(0 To 1) As Object
                            El(0) = NomFichier
                            El(1) = CollBlocRef
                            CollGlobale.Add(El)

                        Catch ex As System.Exception
                            MsgBox("Impossible d'ouvrir le fichier : " & vbCrLf & NomFichier, MsgBoxStyle.Information, "Erreur :")
                        End Try
                    End Using
                Else
                    Dim Dbo As Database = CollDocOuvert.Item(NomFichier.ToUpper).database

                    'le fichier est ouvert !
                    Dim CollBlocRef As New Collection
                    GestionBloc.GetDecompteBlocAvecAtt(False, CollBlocRef, False, False, False, "", True, Dbo)
                    Dim El(0 To 1) As Object
                    El(0) = NomFichier
                    El(1) = CollBlocRef
                    CollGlobale.Add(El)

                End If

                StatusLabelBas.Text = ""
            Else
                GestionAUTOCAD.TxtOnLigneCOmmande("Fichier introuvable: " & Fichier.Name & vbCrLf)
                'ed.WriteMessage(vbCrLf & "Fichier introuvable: " & Fichier.Name)
            End If
        Next

        CollDocOuvert.Clear()
        CollDocOuvert = Nothing

GestionBloc.GetDecompteBlocAvecAtt  --> function for count and retrieve block from the xdb

GestionAutocad.TxtOnLigneCommand --> sub for write msg on editor.

CollGlobal is a collection

 

StatusLabelBar is a component of my form for write msg. is use me.refresh and a timer (1s) for refresh my form. (a trick i have found for do this [if you have better trick i take it.])

 

and for all : Happy New Year

 

 

9 REPLIES 9
Message 2 of 10
Alfred.NESWADBA
in reply to: AubelecBE

Hi,

 

here you can find methods for evaluating if a point (blockreference insertion point) is inside or outside a polygon: >>>click<<<

(be careful with the ray method as this might fail with AutoCAD calculation of intersection points in some (rare) situations).

 

HTH, - alfred -

------------------------------------------------------------------------------------
Alfred NESWADBA
Ingenieur Studio HOLLAUS ... www.hollaus.at ... blog.hollaus.at ... CDay 2024
------------------------------------------------------------------------------------
(not an Autodesk consultant)
Message 3 of 10
AubelecBE
in reply to: AubelecBE

so thanks. i find this. :

 

Here is a "C++" implementation of the winding number algorithm for the inclusion of a point in polygon. We just give the 2D case, and use the simplest structures for a point and a polygon which may differ in your application.

// Copyright 2000 softSurfer, 2012 Dan Sunday
// This code may be freely used and modified for any purpose
// providing that this copyright notice is included with it.
// SoftSurfer makes no warranty for this code, and cannot be held
// liable for any real or imagined damage resulting from its use.
// Users of this code must verify correctness for their application.
 

// a Point is defined by its coordinates {int x, y;}
//===================================================================
 

// isLeft(): tests if a point is Left|On|Right of an infinite line.
//    Input:  three points P0, P1, and P2
//    Return: >0 for P2 left of the line through P0 and P1
//            =0 for P2  on the line
//            <0 for P2  right of the line
//    See: Algorithm 1 "Area of Triangles and Polygons"
inline int
isLeft( Point P0, Point P1, Point P2 )
{
    return ( (P1.x - P0.x) * (P2.y - P0.y)
            - (P2.x -  P0.x) * (P1.y - P0.y) );
}
//===================================================================


// cn_PnPoly(): crossing number test for a point in a polygon
//      Input:   P = a point,
//               V[] = vertex points of a polygon V[n+1] with V[n]=V[0]
//      Return:  0 = outside, 1 = inside
// This code is patterned after [Franklin, 2000]
int
cn_PnPoly( Point P, Point* V, int n )
{
    int    cn = 0;    // the  crossing number counter

    // loop through all edges of the polygon
    for (int i=0; i<n; i++) {    // edge from V[i]  to V[i+1]
       if (((V[i].y <= P.y) && (V[i+1].y > P.y))     // an upward crossing
        || ((V[i].y > P.y) && (V[i+1].y <=  P.y))) { // a downward crossing
            // compute  the actual edge-ray intersect x-coordinate
            float vt = (float)(P.y  - V[i].y) / (V[i+1].y - V[i].y);
            if (P.x <  V[i].x + vt * (V[i+1].x - V[i].x)) // P.x < intersect
                 ++cn;   // a valid crossing of y=P.y right of P.x
        }
    }
    return (cn&1);    // 0 if even (out), and 1 if  odd (in)

}
//===================================================================


// wn_PnPoly(): winding number test for a point in a polygon
//      Input:   P = a point,
//               V[] = vertex points of a polygon V[n+1] with V[n]=V[0]
//      Return:  wn = the winding number (=0 only when P is outside)
int
wn_PnPoly( Point P, Point* V, int n )
{
    int    wn = 0;    // the  winding number counter

    // loop through all edges of the polygon
    for (int i=0; i<n; i++) {   // edge from V[i] to  V[i+1]
        if (V[i].y <= P.y) {          // start y <= P.y
            if (V[i+1].y  > P.y)      // an upward crossing
                 if (isLeft( V[i], V[i+1], P) > 0)  // P left of  edge
                     ++wn;            // have  a valid up intersect
        }
        else {                        // start y > P.y (no test needed)
            if (V[i+1].y  <= P.y)     // a downward crossing
                 if (isLeft( V[i], V[i+1], P) < 0)  // P right of  edge
                     --wn;            // have  a valid down intersect
        }
    }
    return wn;
}
//===================================================================

 i can translate the function isLeft but the other no .

how to convert a line (or point3DCollection)   to a V[] = vertex points of a polygon

 

Message 4 of 10
SENL1362
in reply to: AubelecBE

Simple 2D VB implementation

' xypoly(0..n)(0)=Xi, xypoly(0..n)(1)=Yi
' pnt(0)=Xp, pnt(1)=Yp
Public Function IsInside2DPolyline(ByVal xyPoly As Variant, ByVal xPnt As Double, ByVal yPnt As Double) As Boolean
Dim i As Long
Dim inside As Boolean
Dim xNew As Double, yNew As Double, xOld As Double, yOld As Double
Dim x1 As Double, y1 As Double, x2 As Double, y2 As Double





inside = False
xOld = xyPoly(UBound(xyPoly) - 1)
yOld = xyPoly(UBound(xyPoly))
For i = LBound(xyPoly) To UBound(xyPoly) - 1 Step 2
xNew = xyPoly(i)
yNew = xyPoly(i + 1)

If xNew > xOld Then
x1 = xOld
y1 = yOld
x2 = xNew
y2 = yNew

Else
x1 = xNew
y1 = yNew
x2 = xOld
y2 = yOld
End If

If (xNew < xPnt) = (xPnt <= xOld) And _
((yPnt - y1) * (x2 - x1)) < ((y2 - y1) * (xPnt - x1)) Then
inside = Not inside
End If

xOld = xNew
yOld = yNew
Next


IsInside2DPolyline = inside


End Function
Message 5 of 10
AubelecBE
in reply to: AubelecBE

here my solution.

 

so the final code for the function (in vb.net) :

'**************************************************************************************
    'isLeft(): tests if a point is Left|On|Right of an infinite line.
    '//    Input:  three points P0, P1, and P2
    '//    Return: >0 for P2 left of the line through P0 and P1
    '//            =0 for P2  on the line
    '//            <0 for P2  right of the line
    '//    See: Algorithm 1 "Area of Triangles and Polygons"
    Private Function isLeft(ByVal P0 As Point2d, ByVal P1 As Point2d, ByVal P2 As Point2d) As Double
        Return ((P1.X - P0.X) * (P2.Y - P0.Y) - (P2.X - P0.X) * (P1.Y - P0.Y))
    End Function
    '**************************************************************************************

    '**************************************************************************************
    '// wn_PnPoly(): winding number test for a point in a polygon
    '//      Input:   P = a point,
    '//               V[] = vertex points of a polygon V[n+1] with V[n]=V[0]
    '//      Return:  wn = the winding number (=0 only when P is outside)
    'int
    Public Function wn_PnPoly(ByVal Pbloc As Point3d, ByVal V() As Point2d, ByVal n As Double) As Double
        Dim wn As Double = 0    '// the  winding number counter
        Dim P As New Point2d(Pbloc.X, Pbloc.Y)
        '// loop through all edges of the polygon
        For i As Integer = 0 To n - 1
            'for (int i=0; i<n; i++) {   
            If (V(i).Y <= P.Y) Then                         '// edge from V[i] to  V[i+1]
                '// start y <= P.y
                If (V(i + 1).Y > P.Y) Then                  '// an upward crossing
                    If (isLeft(V(i), V(i + 1), P) > 0) Then  '// P left of  edge
                        wn = wn + 1                         '// have  a valid up intersect
                    End If
                End If

            Else                                            '// start y > P.y (no test needed)
                If (V(i + 1).Y <= P.Y) Then                 '// a downward crossing
                    If (isLeft(V(i), V(i + 1), P) < 0) Then  '// P right of  edge
                        wn = wn - 1                         '// have  a valid down intersect
                    End If
                End If
            End If
        Next
        Return wn
    End Function
    '**************************************************************************************

 

and the test code for this function :

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Me.Hide()

        Dim doc As Document = Application.DocumentManager.MdiActiveDocument
        Dim db As Database = doc.Database
        Dim ed As Editor = doc.Editor
        Dim tr As Transaction = db.TransactionManager.StartTransaction()
        Try
            Dim per As PromptEntityResult = ed.GetEntity("Select a polyline")
            Dim OkContinue As Boolean = True
            If per.Status = PromptStatus.OK Then
                Dim lwp As Polyline = Nothing
                Try
                    lwp = tr.GetObject(per.ObjectId, OpenMode.ForRead)
                Catch ex As Exception
                    ed.WriteMessage(vbCrLf + "Not a polyline" & vbCrLf)
                    OkContinue = False
                End Try

                If OkContinue = True Then
                    Dim vn As Integer = lwp.NumberOfVertices
                    Dim colpt() As Point2d = Nothing
                    ReDim colpt(vn)
                    For i As Integer = 0 To vn - 1
                        '// Could also get the 3D point here
                        Dim pt As Point2d = lwp.GetPoint2dAt(i)
                        colpt(i) = pt
                        ed.WriteMessage(vbCrLf + pt.ToString())
                    Next
                    colpt(vn) = lwp.GetPoint2dAt(0)

                    ed.WriteMessage(vbCrLf + "FIN" + vbCrLf)

                    Dim per2 As PromptEntityResult = ed.GetEntity("Select a Bloc")
                    If per2.Status = PromptStatus.OK Then
                        Dim bloc As BlockReference
                        Try
                            bloc = tr.GetObject(per2.ObjectId, OpenMode.ForRead)
                            Dim x As Double
                            x = GestionAutocadEntite.wn_PnPoly(bloc.Position, colpt, vn)
                            ed.WriteMessage(vbCrLf + "sortie : " & x.ToString)

                        Catch ex As Exception
                            ed.WriteMessage(vbCrLf + "Not a bloc" & vbCrLf)

                        End Try

                    Else
                        ed.WriteMessage(vbCrLf + "Pas d'entité selectionnée !" & vbCrLf)
                    End If

                End If
            Else
                ed.WriteMessage(vbCrLf + "Pas d'entité selectionnée !" & vbCrLf)
            End If

        Finally
            tr.Commit()
            tr.Dispose()
        End Try
    End Sub

 

the function return 0 if the bloc selected is not in the polyline.

But warning : if the bloc is in a line of the polyline, the function say : out of the polyline..

 

i tested this, work fine. I have modify the entry of P for a point3D (BlockReference)

 

 

Thanks for your help

 

 

 

Message 6 of 10

Have a look here, which can be used to solve the more general problem (any closed boundry that can be used to create a region):

 

http://www.theswamp.org/index.php?topic=43572.msg488632#msg488632

Message 7 of 10

i have see this thanks but  in the commentary :

  • /// Note that the sample code was designed to work with
  •      /// regions that lie in the WCS XY plane and points that
  •      /// lie in the same plane.

So. me i need a code for all polyline in WCS or UCS.

but it is a good example for the

  • using Autodesk.AutoCAD.BoundaryRepresentation; // acdbmgdbrep.dll

i need to upgrade my code, i see my fonction return false when the point is on à line of my polyline. So i have to adjuste the check if the point is on my polyline. 🙂

 

Message 8 of 10
AubelecBE
in reply to: AubelecBE

here my final function using wn_Poly :

 

 '***********************************************************************
    '**  procedure de détection si un point est dans une région(polyline) **
    '***********************************************************************
    '** ENTREE :                                                          **
    '**   - Ligne  : la polyline                                          **
    '**                Attention vérifier avant que la polyligne ne se    **
    '**                  croise pas elle-même (IsPolylineSelfIntercept)   **
    '**   - Bloc   : Le bloc a tester                                     **
    '** SORTIE :                                                          **
    '**   - True si dedans sinon false                                    **
    '***********************************************************************
    Public Function IsBlocInZoneFromPolyline(ByRef Bloc As BlockReference, ByRef Ligne As Polyline) As Boolean
        Dim OkRetour As Boolean = False
        '===========================================================================
        'Gestion des erreurs d'entrée :
        'Si pas définit
        If IsNothing(Bloc) = True Or IsNothing(Ligne) = True Then Return OkRetour
        'Si ligne non fermée
        If Ligne.Closed = False Then Return False
        '===========================================================================

        '===========================================================================
        'génération des points d'entrée de la fonction de calcul + vérification simple
        '  si le point est sur la polyligne

        'du point de test
        Dim pt As New Point2d(Bloc.Position.X, Bloc.Position.Y)

        'pt de la ligne
        Dim vn As Integer = Ligne.NumberOfVertices
        Dim colpt() As Point2d = Nothing
        ReDim colpt(vn)
        For i As Integer = 0 To vn - 1
            '// Could also get the 3D point here
            Dim pts As Point2d = Ligne.GetPoint2dAt(i)
            colpt(i) = New Point2d(pts.X, pts.Y)


            'Test si le point est sur un segment de la polyline si oui exit !
            Dim seg As Curve2d = Nothing
            Dim segType As SegmentType = Ligne.GetSegmentType(i)
            If (segType = SegmentType.Arc) Then
                seg = Ligne.GetArcSegment2dAt(i)
            ElseIf (segType = SegmentType.Line) Then
                seg = Ligne.GetLineSegment2dAt (i)
            End If
            If IsNothing(seg) = False Then
                OkRetour = seg.IsOn(pt)
                If OkRetour = True Then
                    Return True
                End If
            End If
        Next
        'ajout du point [0] pour finir la boucle !
        colpt(vn) = Ligne.GetPoint2dAt(0)

        '===========================================================================

        Dim RetFonction As Double
        RetFonction = wn_PnPoly(pt, colpt, vn)

        If RetFonction = 0 Then
            OkRetour = False
        Else
            OkRetour = True
        End If

        Return OkRetour
    End Function

 and for the completion : the function needed for check if polyline dont intercept :

 

 '***********************************************************************
    '**  procedure de détection si une polyline se recoupe                **
    '***********************************************************************
    '** ENTREE :                                                          **
    '**   - Ligne  : la polyline                                          **
    '** SORTIE :                                                          **
    '**   - True si croisement                                            **
    '***********************************************************************
    Public Function IsPolylineSelfIntercept(ByRef Ligne As Polyline) As Boolean
        Dim OkRetour As Boolean = False
        'Dim doc As Document = Application.DocumentManager.MdiActiveDocument
        'Dim db As Database = doc.Database
        'Dim ed As Autodesk.AutoCAD.EditorInput.Editor = doc.Editor

        Dim entities As DBObjectCollection = New DBObjectCollection()
        'explosion des entités constituant la polyline
        Ligne.Explode(entities)

        For i As Integer = 0 To entities.Count - 1
            For j As Integer = i + 1 To entities.Count - 1

                Dim curve1 As Curve = entities(i)
                Dim curve2 As Curve = entities(j)
                Dim points As Point3dCollection = New Point3dCollection()

                curve1.IntersectWith(curve2, Intersect.OnBothOperands, points, IntPtr.Zero, IntPtr.Zero)

                For Each point As Point3d In points
                    '// Make a check to skip the start/end points
                    '// since they are connected vertices
                    If (point = curve1.StartPoint Or _
                        point = curve1.EndPoint) Then
                        If (point = curve2.StartPoint Or _
                            point = curve2.EndPoint) Then
                            Continue For
                        End If
                    End If
                    '// If two consecutive segments, then skip
                    If (j = i + 1) Then
                        Continue For
                    End If
                    ' ed.WriteMessage(vbCrLf & "Intersection point: " + point.ToString())
                    OkRetour = True

                Next

            Next
            '// Need to be disposed explicitely
            '// since entities are not DB resident
            entities(i).Dispose()

        Next

        Return OkRetour
    End Function

 

Message 9 of 10


@AubelecBE wrote:

i have see this thanks but  in the commentary :

  • /// Note that the sample code was designed to work with
  •      /// regions that lie in the WCS XY plane and points that
  •      /// lie in the same plane.

So. me i need a code for all polyline in WCS or UCS.

but it is a good example for the

  • using Autodesk.AutoCAD.BoundaryRepresentation; // acdbmgdbrep.dll

i need to upgrade my code, i see my fonction return false when the point is on à line of my polyline. So i have to adjuste the check if the point is on my polyline. 🙂

 


The sample shows the basic operation, which is inherintly a 2D computation,

and requires that candidate points lie exactly on the plane of the boundary,

so you would obviously need to project them onto boundary plane if they are

not already there.

 

If the candidate point is in the plane of the boundary, the code

should correctly indicate if the point lies exactly on an edge.

 

 

Message 10 of 10

yes. but this code is already a little too hard for me. 😛 so to translate region on WCS to UCS. i know the basic only. I learn but only with code understandable for me.  And with all this, i have to translate all my code from VB.net for Autocad V2010 to Autocad V2014 soon.

 

thanks for your help.

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

Autodesk DevCon in Munich May 28-29th


Autodesk Design & Make Report

”Boost