SSGET two perpendicular pline

SSGET two perpendicular pline

Anonymous
Not applicable
3,631 Views
40 Replies
Message 1 of 41

SSGET two perpendicular pline

Anonymous
Not applicable

Hi all,

 

I have been working on a drawing which contains numerous number of exploded EARTH blocks. Apart from their rotation angle, they are all the same i.e. they are all plines, they have same color, same layer, etc.

 

See screenshot below (other stuff are frozen):

 

1.jpg

 

 

I was wondering if I could use SSGET and replace them with their correspondent block (their angle should be maintained). Again, please see screenshot below:

 

Capture.JPG

 

My idea was to grab all pline objects which are on layer Existing Symbol and have the length of "1". And then check whether there is another pline with the same layer and length of "3" perpendicular to that. From there I would be pretty certain that I have successfully identified an instance of exploded symbol. Next I am going to do another SSGET with "W" option to somehow grab the entire thing, delete it and replace it by the block.

 

That's my plan but for beginning, I am not sure how to do test whether two plines are perpendicular.

 

Can anyone help please?

 

 

Regards

 

 

 

0 Likes
Accepted solutions (1)
3,632 Views
40 Replies
Replies (40)
Message 2 of 41

Kent1Cooper
Consultant
Consultant

[You'll miss them all if you check for Polylines with a length of 1 -- those shorter ones are 1.5 units long.  I checked because the difference between the stepping-length ones looks equal, but the 1-, 3- & 4-unit Dimensions aren't equal differences.  You need to increase the precision on your Dimension Style's text content.]

 

What you want to do is probably achievable, but might there ever by some that are close enough to other things that a crossing window relative to the 1.5-unit one could find something that doesn't belong?

Kent Cooper, AIA
0 Likes
Message 3 of 41

Anonymous
Not applicable

Can you upload those files in another version? I use Acad 2010...

0 Likes
Message 4 of 41

Anonymous
Not applicable

2010 version files attached.

 

Thanks

0 Likes
Message 5 of 41

Anonymous
Not applicable

Good pick ! I didn't realise that at the time.

 

Here is the new screenshot:

 

[img]https://i.imgur.com/slUex0y.jpg[/img]

 

 

(sorry for the external image link. Forum seems to be under maintanance at the time of this post)

 

 

Re- to your comment, you are probably right and I might miss come other things wy window selection but I am willing to make that sacrifice. Getting tens or perhaps hundreds of exploded symbols fixed worth it !

 

 

0 Likes
Message 6 of 41

ActivistInvestor
Mentor
Mentor

@Anonymous wrote:

 

 

My idea was to grab all pline objects which are on layer Existing Symbol and have the length of "1". And then check whether there is another pline with the same layer and length of "3" perpendicular to that. From there I would be pretty certain that I have successfully identified an instance of exploded symbol. Next I am going to do another SSGET with "W" option to somehow grab the entire thing, delete it and replace it by the block.

 

 


The problem is actually much easier to solve than that.

 

When a block is exploded, AutoCAD copies the objects in the block's definition into the current space, one at a time, starting with the first object in the block's definition, through to the last one. IOW, the copies are created in the same relative order as the objects in the block's definition. 

 

So, if you can identify an exploded instance of the first object in the block's definition (in your example block, it is the line that is perpendicular to the other 3 parallel lines), you can find the remaining exploded copies by simply doing an (entnext), and passing the entity name of the first exploded copy..  

 

So, if there are 4 objects in the block, and you have the entity name of the first exploded copy, then:

 

   (setq exploded_entities nil)

   (setq first_exploded_copy  <<the entity name of the first exploded copy>>.)

   (setq block_entity_count <<number of entities in the block>>)

   (setq e first_exploded_entity)
   (setq exploded_entities (cons e exploded_entities))
   (repeat (1- block_entity_count)
      (setq e (entnext e))
      (setq exploded_entities (cons e exploded_entities))
   )

       

 

After that, exploded_entities should contain all of the entities produced by exploding an insertion of the block.

 

The difficult part is identifying the first exploded entity (you can examine the first entity in the block, and look for entities that match its geometric properties exactly), and of course this presumes that all of the insertions that were exploded were inserted at the default scale factor (1,1). Otherwise, it becomes a bit more complicated.

This also presumes that the exploded entities have not been fiddled with after that fact. Otherwise, all bets are off..

0 Likes
Message 7 of 41

Anonymous
Not applicable

@Activist_Investor wrote:

This also presumes that the exploded entities have not been fiddled with after that fact. Otherwise, all bets are off..


How could I possibly know that?! Our company is probabaly the thrid or fouth sub-contractor of a big government job. Lots of other hands have been on these drawings before they land on my desk.

 

Tnx for the contribution anyway.

0 Likes
Message 8 of 41

dbroad
Mentor
Mentor

Since the earth blocks are poorly drafted and since there is a variation in the length of the stem lengths of the exploded earth blocks within the tolerance of many other symbol line lengths, it cannot be automated without considerable effort.  The best you could do would be to create a command that would allow the user to select each earth block stem.  You could use the 4 element nature of the blocks to replace those groupings.

Architect, Registered NC, VA, SC, & GA.
0 Likes
Message 9 of 41

ActivistInvestor
Mentor
Mentor

@Anonymous wrote:

@Activist_Investor wrote:

This also presumes that the exploded entities have not been fiddled with after that fact. Otherwise, all bets are off..


How could I possibly know that?! Our company is probabaly the thrid or fouth sub-contractor of a big government job. Lots of other hands have been on these drawings before they land on my desk.

 

Tnx for the contribution anyway.


If the objects resulting from exploding the blocks have been edited after the fact, then they should not be replaced with an insertion of the block in the first place,.and there's no algorithm that can identify them, given the infinite number of ways they could have been edited.

 

If you don't know if the objects could have been edited, you can still find those that haven't been edited using the method I suggested, along with a pattern-matching algorithm. That is, assuming you have the original block definition to examine. If it's not in the drawing then you have to insert it.

 

The basic process is to walk the entire model space of the drawing, and examine each object to see if it 'matches' the first object in the block definition (for example, if the first object in the block definition is a line 3 units long, then you look for lines of that length, and reject everything else). Once you have a list of all lines that are 3 units long (or whatever the length of the first line in the block definition is), you then step through that list, and for each line, you use (entnext <line>) to get the entity that follows it. If that entity matches the second entity in the block's definition, then you again use (entnext) to look at the entity that follows that one, to see if it matches the third entity in the block's definition, and so on...until you've compared each successive entity to all the entities in the block's definition, in which case you've found an exploded copy.

 

Also note that in spite of what @dbroad says, whether the geometry is imprecise or not is irrelevant if using the algorithm I just described, because it doesn't rely on whether or not objects are poorly- or imprecisely-drawn. The algorithm performs relative-but-precise comparison between each original entity in the block's definition and the corresponding copy of it that was produced by exploding an insertion of the block.

 

I know that works because I spent months developing a solution (in ObjectARX) that does exactly that (find exploded remnants of block insertions and replace them with insertions of the block). It only replaces remnants of exploded blocks that haven't been edited, because those that have been edited shouldn't be replaced. That work was produced for a paying customer and I'm not at liberty to share it.

 

 

0 Likes
Message 10 of 41

dbroad
Mentor
Mentor

The first entity of each exploded block in the sample drawing is ever so slightly different in length from both the first block entity in the definition and also from every other copy. One would think that if they were only exploded, then every copy of the block would be exactly the same except for rotation. So now, you need to look for approximate relationships between sequences of 4 polylines that resemble the original instead of precise comparisons between a set of copies and a pattern. You must do this without being overly aggressive changing similar symbols.  Changes or variations to all the original block entities on the order of 10e-10 mean that you can't just look for a line that is exactly the same length as the block or even exactly as long as the next copy but there should be approximately parallel and perpendicular relationships and a specific but only approximate sequence of reducing line lengths. Everything looks accurate in the properties palette but that lies.

 

I didn't say it was impossible to do but such a task shouldn't be expected to be served up free. Seems you might agree.

Architect, Registered NC, VA, SC, & GA.
0 Likes
Message 11 of 41

Anonymous
Not applicable
I agree with dbroad, they are all slighly different. What i usually do is convert the values im evaluating to text with RTOS, and rounding from that; i think 2 decimal would work in your case. Its not the best way but works often. Agreed too with the complexity of the task, i dont think someone would do such an effort for free... But we are all here to give you our ideas 🙂
0 Likes
Message 12 of 41

Anonymous
Not applicable

@Anonymous wrote:
I agree with dbroad, they are all slighly different. What i usually do is convert the values im evaluating to text with RTOS, and rounding from that; i think 2 decimal would work in your case. Its not the best way but works often. Agreed too with the complexity of the task, i dont think someone would do such an effort for free... But we are all here to give you our ideas 🙂

Tnx to all.

 

How about if we all "assume" that pline have consistent length throughout the entire drawing? Would that still be too difficult?

I just need some simple code as to be my starting point. I might be able to gradually develop it by myself afterward. I really appreciate all your assistance in advance Heart.

0 Likes
Message 13 of 41

Anonymous
Not applicable
I would start this way (SETQ pllist (Ssalst (SSGET "_X" '((0 . "LWPOLYLINE")(8 . "Existing Symbols")(410 . "Model"))))) (FOREACH i pllist (SETQ obj (ENTGET i)) (IF (/= "4.50" (RTOS (DISTANCE (CDR (ASSOC 10 obj)) (CDR (ASSOC 10 (CDR(MEMBER (ASSOC 10 obj) obj))))) 2 2)) (SETQ pllst (VL-REMOVE i pllst)) ) ) So in pllist you would have a list with enames of all polylines with a lenght of 4.50 in their first segment. From there i would get the middle point of ech polyline in that list and ssget in a little radius around that point, to get the corner polilyne. Next, get the opposite node of that "corner" polyline, there is your block insertion point, and with ANGLE between that point and the middle of the first polilyne you can get the angle. That's not erasing any polilyne, so you could select all blocks and copy them to the main drawing or make a visual control of the results. I dont know if its a good idea but you can start from there This converts a given selection set to a list of enames (DEFUN Ssalst (sset / lst) (REPEAT (SSLENGTH sset) (SETQ lst (CONS (SSNAME sset 0) lst)) (SETQ sset (SSDEL (SSNAME sset 0) sset)) ) (SETQ lst lst) )
0 Likes
Message 14 of 41

ActivistInvestor
Mentor
Mentor

@Anonymous wrote:

The first entity of each exploded block in the sample drawing is ever so slightly different in length from both the first block entity in the definition and also from every other copy. One would think that if they were only exploded, then every copy of the block would be exactly the same except for rotation. So now, you need to look for approximate relationships between sequences of 4 polylines that resemble the original instead of precise comparisons between a set of copies and a pattern. You must do this without being overly aggressive changing similar symbols.  Changes or variations to all the original block entities on the order of 10e-10 mean that you can't just look for a line that is exactly the same length as the block or even exactly as long as the next copy but there should be approximately parallel and perpendicular relationships and a specific but only approximate sequence of reducing line lengths. Everything looks accurate in the properties palette but that lies.

 

I didn't say it was impossible to do but such a task shouldn't be expected to be served up free. Seems you might agree.


All of what you say above seems to be hanging on my use of the word 'precise'. Well there is no such thing as absolute precision in floating point comparisons, because the location of the objects and the number of significant digits to the left of decimal point of their coordinates determines how precise a distance calculation is. And in fact, 'precisely' comparing two lines that are exactly the same length, but have very different locations (one being very close to the origin, and the other being very far from same) can fail if no tolerance is used, even if one of the lines was created by copying the other.

 

The variation in the case of the sample drawing is well beyond the reasonable tolerance that would be used for any floating point comparisons. Most competent developers will tell you that floating point comparisons are always done using a tolerance that's suitable to the application. 

 

The possibility that there may be other lines in the drawing with the exact same length, that are not exploded copies of the first entity in the block is of no importance when doing pattern matching, because that involves comparing multiple objects, not just one. So, if after finding a line/polyline with the same exact or nearly-exact length as the first polyline in the Earth Block, the comparison of the objects that follow it, with the remaining objects in the Earth Block will fail if they are not parts of an exploded earth block.

 

 

0 Likes
Message 15 of 41

Anonymous
Not applicable

So looking at attached photo and considering your code below, you are suggesting to get all plines which have been marked with the blue tag "B" . Then find center point "1":

 

(SETQ pllist (Ssalst (SSGET "_X"
			    '((0 . "LWPOLYLINE")
			      (8 . "Existing Symbols")
			      (410 . "Model")
			     )
		     )
	     )
)
(FOREACH i pllist
  (SETQ obj (ENTGET i))
  (IF
    (/=
      "4.50"
      (RTOS (DISTANCE (CDR (ASSOC 10 obj))
		      (CDR (ASSOC 10 (CDR (MEMBER (ASSOC 10 obj) obj))))
	    )
	    2
	    2
      )
    )
     (SETQ pllst (VL-REMOVE i pllst))
  )
)

My question is, at this point I should be able to get the coordinates of point "2". Shouldn't I? I know the length of pline "A", I know pline "A" is perpendicular to pline "B". Hence, point "2" is reachable. Why should I go with your circle option?

 

PS. It's so annoying that I can't insert pictures in the post at the moment (technical forum issue).

0 Likes
Message 16 of 41

ActivistInvestor
Mentor
Mentor

You really don't have to assume anything. You should always use a reasonable tolerance when comparing floating point values such as lengths and angles, but the solution you envision is more complicated than what I had suggested, because it can't rely on the relative ordering of the objects, so you must discretely search for every object instead, which is actually far more complicated. 

 

As far as some simple code as a starting point, the problem you're trying to solve is not simple, and neither is any reasonably-good solution. It requires some fairly-intricate coding, and all of the code that I've written to address this problem is in written in another language that wouldn't help you much., sorry.

 

Hopefully someone else here who takes this as a challenge and has the time to spare, might be able to get you started with some code.

 


@Anonymous wrote:

@Anonymous wrote:
I agree with dbroad, they are all slighly different. What i usually do is convert the values im evaluating to text with RTOS, and rounding from that; i think 2 decimal would work in your case. Its not the best way but works often. Agreed too with the complexity of the task, i dont think someone would do such an effort for free... But we are all here to give you our ideas 🙂

Tnx to all.

 

How about if we all "assume" that pline have consistent length throughout the entire drawing? Would that still be too difficult?

I just need some simple code as to be my starting point. I might be able to gradually develop it by myself afterward. I really appreciate all your assistance in advance Heart.


 

0 Likes
Message 17 of 41

ActivistInvestor
Mentor
Mentor

@Anonymous wrote:

So looking at attached photo and considering your code below, you are suggesting to get all plines which have been marked with the blue tag "B" . Then find center point "1":

 

(SETQ pllist (Ssalst (SSGET "_X"
			    '((0 . "LWPOLYLINE")
			      (8 . "Existing Symbols")
			      (410 . "Model")
			     )
		     )
	     )
)
(FOREACH i pllist
  (SETQ obj (ENTGET i))
  (IF
    (/=
      "4.50"
      (RTOS (DISTANCE (CDR (ASSOC 10 obj))
		      (CDR (ASSOC 10 (CDR (MEMBER (ASSOC 10 obj) obj))))
	    )
	    2
	    2
      )
    )
     (SETQ pllst (VL-REMOVE i pllst))
  )
)

My question is, at this point I should be able to get the coordinates of point "2". Shouldn't I? I know the length of pline "A", I know pline "A" is perpendicular to pline "B". Hence, point "2" is reachable. Why should I go with your circle option?

 

PS. It's so annoying that I can't insert pictures in the post at the moment (technical forum issue).


Your code doesn't filter out polylines based on the number of vertices. If there are polylines with more than one segment, you should ignore them.

 

The (equal) function is a better way to compare doubles with a tolerance/fuzz factor:

 

 

(not 
   (equal 
      4.50 
      (distance 
         (cdr (assoc 10 obj)) 
         (cdr (assoc 10 (cdr (member (assoc 10 obj) obj))))
      )
      0.001   ;; (equal) returns true if the values are within 0.001 of each other
   )
)
0 Likes
Message 18 of 41

ActivistInvestor
Mentor
Mentor

@Anonymous wrote:

 

Changes or variations to all the original block entities on the order of 10e-10 mean that you can't just look for a line that is exactly the same length as the block or even exactly as long as the next copy but there should be approximately parallel and perpendicular relationships and a specific but only approximate sequence of reducing line lengths.

 


And one more thing:

 

A good algorithm would not look for 'parallel and perpendicular relationships' and 'approximate sequence of reducing line lengths', because that amounts to coupling the algorithm to a specific block, rather than using a generic algorithm that would work on any block. When doing this sort of thing, you don't take into account specifics of any block, you just perform relative comparisons of the block entities with each sequence of suspect objects in non-specific/generic ways, and that should work with any block, not just the one presented in this problem case.

 

That requires the transformation of each suspect entity into the coordinate system defined by the first entity in the block (e.g., if it is a polyline, the coordinate system's origin is the polyline's start point, and the polyline's endpoint is on the positive x-axis). That's necessary to account for different rotation angles of the original insertions, and to make it simpler to compare angle/direction in a generic way, rather than specifically looking for perpendicular or parallel lines.

 

 

0 Likes
Message 19 of 41

dbroad
Mentor
Mentor

Good strategy. But that would still require a relatively exact transformed match between the block geometry and the geometry of the copies, wouldn't it?  Only an approximate match is available in the sample and that might be fooled by other similar symbols.  As I said, even the copies are dissimilar from one another to some degree, not just rotationally.

Architect, Registered NC, VA, SC, & GA.
0 Likes
Message 20 of 41

john.uhden
Mentor
Mentor

I'm just picking up on this, but it seems you need to find only the two plines that intersect, being one that's 3 units long and one that's 4 units long, then determine at which end of the 3-unit one is intersected, and the other end is the insertion point.  The remaining shorter lines parallel to the 4-unit have no value at all.

 

To do this I think I would weed out a selection set of all the 3-units, and another for all the 4-units.  Then cycle through them all looking for the correct conditions.  With each match I would entmake the block insertion and remove the entity names from each list (or selection set) to reduce processing time.  At the end I would vla-selete all the polylines.

 

The approach may or may not be slower than performing an (ssget "C") at each end of the 3-units, but the amount of coding is quite manageable since you would be using the same comparison function over and over.  We don't want any blisters on your fingers.

 

I would write it but my work takes a lot away from my fun time.  🙂

John F. Uhden

0 Likes