Not related to looping but just a thought which might help
The NeigborFinder will add the direction to the matched feature. Could you perhaps use this information? When combined with the number matched the must be a way to figure out which pair go together.
If you set it to match 2 features (within a distance) then you know those which have matched two features need to join with a wall who matched only 1 feature. You can also use the matching direction to help.
Of course looping might also work, however, if they are equal distant then the middle walls might match to the left and right randomly?
Not related to looping but just a thought which might help
The NeigborFinder will add the direction to the matched feature. Could you perhaps use this information? When combined with the number matched the must be a way to figure out which pair go together.
If you set it to match 2 features (within a distance) then you know those which have matched two features need to join with a wall who matched only 1 feature. You can also use the matching direction to help.
Of course looping might also work, however, if they are equal distant then the middle walls might match to the left and right randomly?
Hi @virtualcitymatt ,
That was one of the things I was looking into. I think you mean getting the direction by subtracting the base x or y from candidate x or y (ie. for vertical lines a + number means to the right and vice-versa)?
The problem is that you need to have the directions cancel out to make a pair (ie. +5 + -5=0).
When the NeighborFinder generates a list with two elements, how do you determine which one should be positive and the other negative?
Another thing I tried was to concatenate the _id number with each list{}. _id number into an attribute. If two features contained the same two _id numbers, then they would match. Again, there was a choice between two matching pairs, which of course is random.
That is why I want to try looping or some other way to grab the first two lines (going left to right), set them aside, and loop back to find the next two. There is a lot of documentation on the loop, but I haven't seen anything yet that I can use. I dunno, Python?
Hi @virtualcitymatt ,
That was one of the things I was looking into. I think you mean getting the direction by subtracting the base x or y from candidate x or y (ie. for vertical lines a + number means to the right and vice-versa)?
The problem is that you need to have the directions cancel out to make a pair (ie. +5 + -5=0).
When the NeighborFinder generates a list with two elements, how do you determine which one should be positive and the other negative?
Another thing I tried was to concatenate the _id number with each list{}. _id number into an attribute. If two features contained the same two _id numbers, then they would match. Again, there was a choice between two matching pairs, which of course is random.
That is why I want to try looping or some other way to grab the first two lines (going left to right), set them aside, and loop back to find the next two. There is a lot of documentation on the loop, but I haven't seen anything yet that I can use. I dunno, Python?
I was actually thinking about the _angle, the _angle in the list (not candidate_angle) should be 0 for east and 180 for west. But perhaps it doesn't really help.
Here's another option where you just look for the number matched. The outside lines should only match 1 and the inside should match 2 so you can use the outside lines to create the pair (attached).
If this is not a great option then looping might be a good option as you wanted in your question. For looping you need to make sure that the transformer is Linked (not imbedded). This is because the NeigborFinder is a blocking transformer. It makes development annoying because you can't see the feature flow. But if you can get it to work it's a good option for a few cases where the normal branching FME model can't solve the problem.
Depending on your data there may be a way to distinguish the outer lines from the inner lines by using buffers.
- Make sure each line has a unique ID.
- Shorten the lines on both sides using the Snipper transformer, with a distance slightly more than the distance between two adjacent lines.
- Pass the shortened lines to a NeighborFinder in 'Candidates Only' mode, finding 1 neighbor, and saving the ID's to a list.
- Also buffer the shortened lines with a buffer size slightly more than the distance between two adjacent lines.
- Use the LineOnAreaOverlayer, using the results from the NeighborFinder and the Bufferer. Save the Overlap Count.
- Retain only the lines where the Overlap Count is exactly 2 (i.e. the outer lines).
- These lines have the ID's of the original outer line and the paired inner line in the list attribute.
You will probably have to perform some preprocessing of your data, such as removing intermediate points, and splitting the lines on vertices.
Hi @virtualcitymatt ,
That was one of the things I was looking into. I think you mean getting the direction by subtracting the base x or y from candidate x or y (ie. for vertical lines a + number means to the right and vice-versa)?
The problem is that you need to have the directions cancel out to make a pair (ie. +5 + -5=0).
When the NeighborFinder generates a list with two elements, how do you determine which one should be positive and the other negative?
Another thing I tried was to concatenate the _id number with each list{}. _id number into an attribute. If two features contained the same two _id numbers, then they would match. Again, there was a choice between two matching pairs, which of course is random.
That is why I want to try looping or some other way to grab the first two lines (going left to right), set them aside, and loop back to find the next two. There is a lot of documentation on the loop, but I haven't seen anything yet that I can use. I dunno, Python?
Ok, that makes sense! I did play around with the _angle earlier, but couldn't make it work for me. Will revisit. I wish the documentation would spell it out a little more. The outside 1/inside 2 correlation is looking like a good method though.
Because the NeighborFinder takes in all the features at once before processing, looping would have to be done around it. I may close out this question and focus on filtering instead.
Very interesting. If I can get back the original geometry, that would be worth a try. This project has been very challenging because there are so many different conditions. What works for one group of lines will completely skew another. Thanks for your help
Very interesting. If I can get back the original geometry, that would be worth a try. This project has been very challenging because there are so many different conditions. What works for one group of lines will completely skew another. Thanks for your help
You can get back the original geometry by saving it to an attribute beforehand with GeometryExtractor, and restoring it afterward with GeometryReplacer.
Or it may be easyer to only keep the ID's from the list attribute, and pick up your original lines, as they are already present in your workspace before the Snipper.
Sorry, nothing seems to be working due to the randomness. I am going to close this out and work on better ways to filter the lines. That seems to be the only thing that is working consistently. Thanks for the tips, I did learn a thing or two!
Hi @larue , what a pity!
How random is the randomness? Does a certain solution work on part of the data, and another solution on another part of the data? In that case you may be able to add a dataset with polygons for the different solutions, and pass the data to the right solution depending on the polygon the data overlaps with.
This would no doubt lead to a very complex workspace.
Hi @larue , what a pity!
How random is the randomness? Does a certain solution work on part of the data, and another solution on another part of the data? In that case you may be able to add a dataset with polygons for the different solutions, and pass the data to the right solution depending on the polygon the data overlaps with.
This would no doubt lead to a very complex workspace.
Yes, it is pretty random in the sense that these are CAD floor plans with minimal prep, although they have a uniform layer structure. I have been working on this for over a year, using FME since around January. Some of my workspaces have been 600-900+ transformers! I have been able to deal with 90% of the lines, but the last 10% have been a challenge to the point where I really should work on CAD file preparation. It recently dawned on me that I am spending way too much time chasing those last few walls when I could do refinements upstream. It has been a great learning experience though.
Yes, it is pretty random in the sense that these are CAD floor plans with minimal prep, although they have a uniform layer structure. I have been working on this for over a year, using FME since around January. Some of my workspaces have been 600-900+ transformers! I have been able to deal with 90% of the lines, but the last 10% have been a challenge to the point where I really should work on CAD file preparation. It recently dawned on me that I am spending way too much time chasing those last few walls when I could do refinements upstream. It has been a great learning experience though.
Yeah having a good set of rules during creation can really help. Then having an FME based validation tool can help identify where the drawings are not acceptable and get sent back to the CAD team. Working to purely with geometry based structures can only take you so far. Very much the 80/20 rule with so much of FME.
Hi @virtualcitymatt ,
Yes, good point. The goal has been to do minimal prep to the CAD file before it hits FME. Looking into Lisp routines and scripts, as well as revising my approach in the Workspace. I posted another question yesterday to help with cleaning up centerlines in my new approach.
Most of the postings I see are geared more toward GIS and non-orthographic geometry. If you know of a forum that deals more in CAD and architectural issues that would be great. Appreciate your comments!
Best,
@larue
update: I modified both the Workspace and CAD files, which ended up making it more streamlined and easier prep with the .dwg files. To be clear, the goal was to translate the centerline in every wall.
Using a couple of lisps and workflows, I created as many contiguous lines as possible to convert into areas and donuts. Long, thin spaces work best with the centerlinereplacer. There is the possibility a script could do the whole thing, but still experimenting currently.
In the revised workspace, I used several TopologyBuilders to identify danglers and extract points to make closer and extender lines, before sending them to the area builder and the centerline module.
I don’t know how much it makes a difference, but instead of using CenterlineReplacer, I used FunctionCaller and set the function to “Classic” mode. It seems to make a cleaner line.
Changing things upstream was definitely the way to go for me.