Author Topic: Point Selection  (Read 6387 times)

0 Members and 1 Guest are viewing this topic.

cadpro

  • Guest
Point Selection
« on: June 18, 2011, 01:41:12 PM »
Hi,

I'm actually looking to edit an attribute in a block that contains 2 closed rectangular polylines, and one attribute each inside each rectangle. When the user picks anywhere inside the rectangle, it should detect that particular attribute in the block. I couldn't think of a solution to it. Is it possible to get the area around the picked point, detect the rectangle, and then detect the attribute in the rectangle? For this to work, should the block be exploded programmatically? Please help.
 
Thanks

Keith™

  • Villiage Idiot
  • Seagull
  • Posts: 16899
  • Superior Stupidity at its best
Re: Point Selection
« Reply #1 on: June 18, 2011, 02:32:34 PM »
I wouldn't go through the process of exploding the block. Once upon a time, I had a lisp routine that did something similar.

Consider translating the selected point to the UCS of the block, then programmatically find the rectangle that encompasses that point. Once you know that, you can then select the appropriate attribute and update as needed.

Presumably, the attributes have different tags and are easily identifiable.

Another way would be to simply map the block and filter the point based on the selected location, but that wouldn't be scalable and would break if the block was changed. For example, Presume that the block has attribute A at 1,1 and attribute B at 4,1 and there are two rectangles represented by 0,0:2,2 and 3,0:5,2 with a base of 0,0.

Now, lets say the user picks inside of 11,12 and the block is inserted at 10,10. You would determine that the actual point in relation to the block would be 1,2 and subsequently you would know that attribute A is the one to update.
Proud provider of opinion and arrogance since November 22, 2003 at 09:35:31 am
CadJockey Militia Field Marshal

Find me on https://parler.com @kblackie

cadpro

  • Guest
Re: Point Selection
« Reply #2 on: June 18, 2011, 02:46:16 PM »
Thanks for the reply.

Well, every rectangle in the block reference has a set of attributes and only one of these attributes has to be changed which I can get using the attribute tag.

Could you give me a bit of a sample code of what you have explained?

Thanks

Keith™

  • Villiage Idiot
  • Seagull
  • Posts: 16899
  • Superior Stupidity at its best
Re: Point Selection
« Reply #3 on: June 18, 2011, 02:49:37 PM »
Unfortunately, I don't have anything handy and to be honest, I've not done alot of .net programming with AutoCAD.
Proud provider of opinion and arrogance since November 22, 2003 at 09:35:31 am
CadJockey Militia Field Marshal

Find me on https://parler.com @kblackie

Jeff H

  • Needs a day job
  • Posts: 6150
Re: Point Selection
« Reply #4 on: June 18, 2011, 03:08:28 PM »
Here a little something not as good as Kieth explained but using promptNestedEntity to change attributes.

Just run it and click on a attribute,

Code: [Select]
   <CommandMethod("ChangeAtts")> _
        Public Shared Sub ChangeAtts()
            Dim doc As Document = Application.DocumentManager.MdiActiveDocument
            Dim db As Database = doc.Database
            Dim ed As Editor = doc.Editor

            Using trx As Transaction = db.TransactionManager.StartTransaction()
                Try

                    Dim pner As PromptNestedEntityResult

                    Do
                        pner = ed.GetNestedEntity("Select Attribute")

                        If pner.Status <> PromptStatus.OK Then
                            Exit Do
                        End If

                        If Not pner.ObjectId.ObjectClass.Name = "AcDbAttribute" Then
                            Continue Do
                        End If

                        Dim attref As AttributeReference = trx.GetObject(pner.ObjectId, OpenMode.ForRead)

                        Dim pso As New PromptStringOptions(vbLf & "Enter new Attributr value ")
                        pso.AllowSpaces = True

                        Dim res As PromptResult = ed.GetString(pso)

                        If res.Status <> PromptStatus.OK Then
                            Exit Do
                        End If

                        Dim strvalue As String = res.StringResult
                        attref.UpgradeOpen()
                        attref.TextString = strvalue
                        db.TransactionManager.QueueForGraphicsFlush()

                    Loop While pner.Status = PromptStatus.OK
                    trx.Commit()

                Catch ex As Autodesk.AutoCAD.Runtime.Exception

                    ed.WriteMessage((vbLf + ex.StackTrace & vbLf) + ex.Message)
                End Try
            End Using
        End Sub


The code is basically from here with  little changes http://www.theswamp.org/index.php?topic=35184.0

cadpro

  • Guest
Re: Point Selection
« Reply #5 on: June 18, 2011, 05:28:54 PM »
Thanks very much for the code.

This is what I want, but that works only when there is already an attribute value. If the attribute is empty, I cannot pick the attribute to change. Hence I'm thinking of a way to capture the area around a point that the user picks, which is where I'm stuck. Once I get the area around and inside the rectangle of the picked point, I can loop thought the entities and find the right attribute.

Thanks
« Last Edit: June 18, 2011, 05:51:09 PM by cadpro »

Jeff H

  • Needs a day job
  • Posts: 6150
Re: Point Selection
« Reply #6 on: June 18, 2011, 05:34:28 PM »
Well, every rectangle in the block reference has a set of attributes and only one of these attributes has to be changed which I can get using the attribute tag.
Thanks

Are you sure the tag will always be the same and unique compared to any other tags?
If so I am not sure why you want to do the extra effort, I can see letting the user select which block insertion.

Keith™

  • Villiage Idiot
  • Seagull
  • Posts: 16899
  • Superior Stupidity at its best
Re: Point Selection
« Reply #7 on: June 18, 2011, 05:51:22 PM »
If I were going to attempt this in lisp, I would simply create a point in memory at a distance of X from the selected point (direction is unimportant in a closed polygon) then attempt to find a block reference using those two points as a crossing selection.

Once you have the block reference, you can easily get the attribute that you wish to edit based on the user selected point in relationship to the insertion point of the block reference.

Logically flowing through the steps would make this a much simpler task for you.

1) User selects point
2) create test point at X units in the Y direction
3) create a selection set of all block references matching the target block using a crossing between PT1 and PT2
4) extract the insertion point of the selected block reference.
5) calculate the location of the user selected point in relation to the insertion point
6) using the two closed polygons in the block table for that block reference, determine if the adjusted point is inside of RECT1 or RECT2
7) select appropriate attribute and update

Now that is a fair simplification of the process, and you will need to ensure you error check for the existence of the block reference before attempting to work on it .. if you don't find the block reference using a programmatic crossing selection (entities will need to be visible), you may need to simply select all matching block references in the drawing programmatically, filter them for the one closest to the selected point, translate the user point to the UCS of the block reference and then determine if the point falls within RECT1 or RECT2

I wish I could explain it as clearly as I can see it in my mind.
Proud provider of opinion and arrogance since November 22, 2003 at 09:35:31 am
CadJockey Militia Field Marshal

Find me on https://parler.com @kblackie

cadpro

  • Guest
Re: Point Selection
« Reply #8 on: June 18, 2011, 05:56:16 PM »
I have attached a sample of the drawing with two rectangles and two attributes each in each rectangle in a block.

cadpro

  • Guest
Re: Point Selection
« Reply #9 on: June 18, 2011, 05:58:29 PM »

Are you sure the tag will always be the same and unique compared to any other tags?
If so I am not sure why you want to do the extra effort, I can see letting the user select which block insertion.

Yes, the tags will always be the same, with a number depending on the number of rectangles it contains

cadpro

  • Guest
Re: Point Selection
« Reply #10 on: June 18, 2011, 06:14:24 PM »
Keith, thanks very much for the explanation.

I will try to code that out.

Jeff H

  • Needs a day job
  • Posts: 6150
Re: Point Selection
« Reply #11 on: June 18, 2011, 08:20:47 PM »
To throw some ideas out there if the rectangles are polylines you can get the GeometricExtents of polylines.
You can use the blocktransform of the blocktablerecord to get the transformation.

Extents3d has a AddPoint which you could add the picked point and use Extents3d.IsEqualTo to see if it changed and the attribute inside Poistion would also not change it if enclosed.

I will stop here and maybe Keith or one of the handful of guys that are real good at math with the translations, matrix, etc.. probably have a better idea or tell you whats wrong with this approach.

Keith™

  • Villiage Idiot
  • Seagull
  • Posts: 16899
  • Superior Stupidity at its best
Re: Point Selection
« Reply #12 on: June 19, 2011, 01:20:55 AM »
To throw some ideas out there if the rectangles are polylines you can get the GeometricExtents of polylines.
You can use the blocktransform of the blocktablerecord to get the transformation.

This is pretty much the approach I would take

Extents3d has a AddPoint which you could add the picked point and use Extents3d.IsEqualTo to see if it changed and the attribute inside Poistion would also not change it if enclosed.

I am not sure this would be necessary as long as you have the polyline extents and the transformation of the selected point. A simple check of the values would be sufficient to verify the location is within the boundary.

I will stop here and maybe Keith or one of the handful of guys that are real good at math with the translations, matrix, etc.. probably have a better idea or tell you whats wrong with this approach.

Nothing wrong with the approach ...
Proud provider of opinion and arrogance since November 22, 2003 at 09:35:31 am
CadJockey Militia Field Marshal

Find me on https://parler.com @kblackie

cadpro

  • Guest
Re: Point Selection
« Reply #13 on: June 19, 2011, 10:07:55 AM »

I will stop here and maybe Keith or one of the handful of guys that are real good at math with the translations, matrix, etc.. probably have a better idea or tell you whats wrong with this approach.


Could any of you experts give me a start on this code please?

Is GeometricExtents the four coordinates of the rectangle?

Thanks
« Last Edit: June 19, 2011, 04:52:58 PM by cadpro »

cadpro

  • Guest
Re: Point Selection
« Reply #14 on: June 20, 2011, 06:27:17 AM »
I did get the GeometricExtentsj and can compare with the MinPoint and MaxPoint of the polyline. But how do I get the nearest entity of the picked point?

Keith™

  • Villiage Idiot
  • Seagull
  • Posts: 16899
  • Superior Stupidity at its best
Re: Point Selection
« Reply #15 on: June 20, 2011, 03:37:54 PM »
I have used several methods in the past. The most successful for on screen selection was pretty complex. What I did was:

1) Store the user selected point
2) Generate another point at X distance and 0 degrees from user selected point
3) Repeat #2 substituting an incrementing value for 0 (i.e. 1, 2, 3, etc)
4) Use a selection set with a fence.
5) If the selection set contained no entities, I incremented the value of X and looped back to #2

This approach isn't really useful though and is certainly not the easiest or best approach. One might consider simply obtaining all the points for every entity in the block and calculate which one is closest.
Proud provider of opinion and arrogance since November 22, 2003 at 09:35:31 am
CadJockey Militia Field Marshal

Find me on https://parler.com @kblackie

cadpro

  • Guest
Re: Point Selection
« Reply #16 on: June 20, 2011, 04:22:18 PM »

One might consider simply obtaining all the points for every entity in the block and calculate which one is closest.

But getting to capture the block is where I'm stuck up with. If I get the block within which the point selection is, then I can loop through the block, get all polylines, get the polylines GeometricExtents, compare with the point X and Y values, find the nearest one, then loop through all the attributes inside the polyline and that's done. But don't know how to capture the nearest entity of the point.

Thanks

Bryco

  • Water Moccasin
  • Posts: 1883
Re: Point Selection
« Reply #17 on: June 20, 2011, 09:27:35 PM »
Begin doubleclick gives you a point. If you check for no entity returned you can make a selection set  using 2 corners created by offsetting the picked point the min required distance to trap the blocks, also filter for the blocks you want.

Keith™

  • Villiage Idiot
  • Seagull
  • Posts: 16899
  • Superior Stupidity at its best
Re: Point Selection
« Reply #18 on: June 21, 2011, 12:57:16 AM »

One might consider simply obtaining all the points for every entity in the block and calculate which one is closest.

But getting to capture the block is where I'm stuck up with. If I get the block within which the point selection is, then I can loop through the block, get all polylines, get the polylines GeometricExtents, compare with the point X and Y values, find the nearest one, then loop through all the attributes inside the polyline and that's done. But don't know how to capture the nearest entity of the point.

Thanks

There are two options that come to mind:

1) Use an on-screen selection method using the user selected point as a base and some arbitrary second point calculated as an offset from the selected point. Then use the crossing or fence selection to find the items

2) Select ALL blocks references that are in the drawing filtered by name, build a list of all the insertion points of all block references then compare the insertion point to the selected point using a distance method. This will tell you which block reference is closest to the selection point.
Proud provider of opinion and arrogance since November 22, 2003 at 09:35:31 am
CadJockey Militia Field Marshal

Find me on https://parler.com @kblackie

cadpro

  • Guest
Re: Point Selection
« Reply #19 on: June 21, 2011, 02:16:23 PM »
I'm almost close to what Bryco and Keith suggested. I did get the offset of the picked point, did a SelectionCrossingWindow, found the blocks in it, looped through the blocks to get the polylines inside the block. So far it's fine. Now I have to find out which polyline is close to the point picked. Coded to get the vertex of all the polylines if the NumberOfVertices = 4. Will a GetDistAtPoint work for this? Or is there any solution?

Thanks

Bryco

  • Water Moccasin
  • Posts: 1883
Re: Point Selection
« Reply #20 on: June 21, 2011, 06:11:04 PM »
Just to make sure; you are using the blocktransform matrix to transform the picked pt to the block layout, and then using the distance from each att to find which att you want?

Keith™

  • Villiage Idiot
  • Seagull
  • Posts: 16899
  • Superior Stupidity at its best
Re: Point Selection
« Reply #21 on: June 21, 2011, 09:20:06 PM »
Just to make sure; you are using the blocktransform matrix to transform the picked pt to the block layout, and then using the distance from each att to find which att you want?

+1
Proud provider of opinion and arrogance since November 22, 2003 at 09:35:31 am
CadJockey Militia Field Marshal

Find me on https://parler.com @kblackie

Jeff H

  • Needs a day job
  • Posts: 6150
Re: Point Selection
« Reply #22 on: June 23, 2011, 11:32:11 PM »
Here is a start maybe???

but use a blk1 from test.dwg that you loaded since blk has nested blockreference

This is just an idea or example things are hard-coded and probably will not do you much good just copying and pasting.


This prompts you for point and will turn the rectangle red of which ever rectangle you select a point inside.

Code: [Select]
        <CommandMethod("GetNestedRec")> _
        Public Sub GetNestedRec()
            Dim doc As Document = Application.DocumentManager.MdiActiveDocument
            Dim db As Database = doc.Database
            Dim ed As Editor = doc.Editor

            Using trx As Transaction = db.TransactionManager.StartTransaction()
                Try

                    Dim bt As BlockTable = trx.GetObject(db.BlockTableId, OpenMode.ForRead)


                    Dim getPnt As Point3d = ed.GetPoint("Pick Point").Value

                    Dim psr As PromptSelectionResult = ed.SelectCrossingWindow(getPnt, New Point3d(getPnt.X + 3, getPnt.Y, 0))

                    If psr.Value.Count = 0 Then
                        Exit Sub
                    End If

                    For Each objId As ObjectId In psr.Value.GetObjectIds

                        If Not objId.ObjectClass.Name = "AcDbBlockReference" Then
                            Continue For
                        End If

                        Dim bref As BlockReference = trx.GetObject(objId, OpenMode.ForRead)
                        Dim blk As BlockTableRecord = trx.GetObject(bref.BlockTableRecord, OpenMode.ForRead)

                        For Each entId As ObjectId In blk

                            If Not entId.ObjectClass.Name = "AcDbPolyline" Then
                                Continue For
                            End If

                            Dim poly As Polyline = trx.GetObject(entId, OpenMode.ForRead)

                            Dim tempExtents As Extents3d
                            Dim polyExtents As Extents3d = poly.GeometricExtents
                            polyExtents.TransformBy(bref.BlockTransform)

                            tempExtents = polyExtents
                            tempExtents.AddPoint(getPnt)

                            If polyExtents.IsEqualTo(tempExtents) Then
                                poly.UpgradeOpen()
                                poly.Color = Color.FromColorIndex(ColorMethod.ByAci, 1)
                            End If
                        Next

                    Next

                Catch ex As System.Exception
                    MsgBox("Error")
                End Try
                trx.Commit()
            End Using
            ed.Regen()
        End Sub







Jeff H

  • Needs a day job
  • Posts: 6150
Re: Point Selection
« Reply #23 on: June 24, 2011, 10:45:21 AM »
Another thing for incrementing the value for crossing window like Keith mentioned you could

replace

Code: [Select]
                    Dim psr As PromptSelectionResult = ed.SelectCrossingWindow(getPnt, New Point3d(getPnt.X + 3, getPnt.Y, 0))

                    If psr.Value.Count = 0 Then
                        Exit Sub
                    End If


with

Code: [Select]

                    Dim increment As Vector3d = New Vector3d(0.5, 0, 0)
                    Dim otherPnt As Point3d = getPnt.Add(increment)
                    Dim counter As Integer = 0

                    Dim psr As PromptSelectionResult = ed.SelectCrossingWindow(getPnt, otherPnt)

                    While psr.Status <> PromptStatus.OK OrElse psr.Value.Count < 1
                        If HostApplicationServices.Current.UserBreak OrElse counter = 100 Then
                            Exit Sub
                        End If

                        otherPnt = otherPnt.Add(increment)
                        psr = ed.SelectCrossingWindow(getPnt, otherPnt)
                        counter += 1
                    End While

The counter is for ending while loop in case user selects a point that will not end up selecting any objects
The UserBreak is for ending loop so you will not get stuck in loop if they press escape
It just uses a Vector3d as a incrementing value and keeps adding to the point to increment the window 0.5 units.


Code: [Select]
                            Dim poly As Polyline = trx.GetObject(entId, OpenMode.ForRead)

                            Dim tempExtents As Extents3d
                            Dim polyExtents As Extents3d = poly.GeometricExtents
                            polyExtents.TransformBy(bref.BlockTransform)

                            tempExtents = polyExtents
                            tempExtents.AddPoint(getPnt)

                            If polyExtents.IsEqualTo(tempExtents) Then
                                poly.UpgradeOpen()
                                poly.Color = Color.FromColorIndex(ColorMethod.ByAci, 1)
                            End If


In case you have not figured it out
Once the crossing window selects a object it checks if it is a Blockreference and if it is it gets the BlockTableRecord and loops through it and checks for polylines
then get the polylines Extents.

Then it takes those extents and uses the Extents3d.TransformBy(BlockReference.BlockTransform) to transform it to the BlockReference insertion.

Then assigns a temp extents to same value as transformed extents and adds a point to to temp extents with Extents3d.AddPoint(SelectedPoint)

if that point is inside the extents then polyExtents.IsEqualTo(tempExtents) will be true.

Again there is probably a better way of figuring out if it falls inside a rectangle



cadpro

  • Guest
Re: Point Selection
« Reply #24 on: June 27, 2011, 05:08:26 PM »
The IsPointInside() is what I was exactly looking for!That works fine, but sadly only when the block's rotation angle is 180 degree. If I manually change the rotation angle to 180, it works fine. What could be the reason.

Bryco

  • Water Moccasin
  • Posts: 1883
Re: Point Selection
« Reply #25 on: June 29, 2011, 02:15:08 AM »
why bother with the rectangle, aren't you looking for the att?

kdub_nz

  • Mesozoic keyThumper
  • SuperMod
  • Water Moccasin
  • Posts: 2138
  • class keyThumper<T>:ILazy<T>
Re: Point Selection
« Reply #26 on: June 29, 2011, 04:46:01 AM »

Just an aside :

Why is the block insert so far away from the main block body ?

Called Kerry in my other life
Retired; but they dragged me back in !

I live at UTC + 13.00

---
some people complain about loading the dishwasher.
Sometimes the question is more important than the answer.

cadpro

  • Guest
Re: Point Selection
« Reply #27 on: June 30, 2011, 07:03:15 AM »
Thanks all. That is solved.

Thanks

kdub_nz

  • Mesozoic keyThumper
  • SuperMod
  • Water Moccasin
  • Posts: 2138
  • class keyThumper<T>:ILazy<T>
Re: Point Selection
« Reply #28 on: July 02, 2011, 04:48:34 AM »
Thanks all. That is solved.

Thanks

cadpro,
I'm sure a few people (here and elsewhere) would be interested is seeing the code solution that resolved this problem.
Would you post it.
Called Kerry in my other life
Retired; but they dragged me back in !

I live at UTC + 13.00

---
some people complain about loading the dishwasher.
Sometimes the question is more important than the answer.

Jeff H

  • Needs a day job
  • Posts: 6150
Re: Point Selection
« Reply #29 on: July 02, 2011, 09:12:00 AM »
why bother with the rectangle, aren't you looking for the att?
Look at earlier replies it is brought up and suggested to go just grab attributes, but OP needed that approach for his situation.

Ahhhh!
I just went back and looked and I missed that OP was taking this approach because the attribute might be empty.
If I am correct in OP's intent then all that could of been advoided.

Bryco

  • Water Moccasin
  • Posts: 1883
Re: Point Selection
« Reply #30 on: July 04, 2011, 01:02:47 PM »
y I saw it as att wanted, so no need for rectanglularisation (Bush would probably  spell that with a Z)

cadpro

  • Guest
Re: Point Selection
« Reply #31 on: July 05, 2011, 06:32:02 PM »

cadpro,
I'm sure a few people (here and elsewhere) would be interested is seeing the code solution that resolved this problem.
Would you post it.

I have used the IsPointInside function. I will post the code soon.

Thanks