Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enabling Bundles and intersections with Bundles, produced in StreetGenerator #104

Open
polarkernel opened this issue Jul 24, 2024 · 93 comments

Comments

@polarkernel
Copy link
Collaborator

Let me use an example that is not as clean as those created in Berlin, Karl-Marx-Allee, to illustrate some initial issues to be discussed (from /osm_extracts/facade_visibility/moscow_leningradski_prospekt.osm, slightly rotated):

In green, there is a bundle of way-sections, classified as 'parallel' by the current algorithm (created in the method createParallelSections). The ways in green, that are perpendicular to this bundle, do not belong to it, that's just an effect of the random color generator. In my opinion, the selected sections reasonably belong to this bundle.

Programmatically, a bundle of ways, classified as 'parallel', is collected as a set of way-sections. The connections between them have to be reconstructed.

Some initial observations:

  • None of these lines passes through the bundle without being interrupted by at least one intersection.
  • Some way-sections look like diagonals, although they are still almost parallel. What to do with these, and how to recognize them?
  • There may be gaps in the lines (center of the image above, the bottom line in the bundle).
  • There may be extra parallel ways, that maybe should not belong to the bundle (on the right, bottom line).
  • The bundle may have ends that are spread out over large distances (see the left end of the green bundle above, or the right end of the magenta bundle in the image below).
@vvoovv
Copy link
Member

vvoovv commented Jul 25, 2024

I added footway, cycleway and path to ExcludedWayTags:

ExcludedWayTags = ['steps', 'footway', 'cycleway', 'path']

Is it the right place for excluding some tags used in generating Bundles?

Now it looks better:

image

Why is there a black segment?

image

I hope to post more thoughts later.

@polarkernel
Copy link
Collaborator Author

Is it the right place for excluding some tags used in generating Bundles?

No. There you exclude them from the network completely. A restriction is made in the function canPair (/defs/way_cluster_parrams), which controls possible pairing combinations of way categories. Another parameter is searchDist (same file), which determines the search distance for parallelism, different for different categories.

If you like to experiment with exclusions of categories from the bundles, you may insert the following instruction at line 613 (current empty):

    if section.category in ['steps', 'footway', 'cycleway', 'path']:
        continue

However, I suggest that we do not change these criteria for the time being. I spent a lot of time fine-tuning them to get the best possible results. No matter what you do, you will always find another instance in some scene where it doesn't work. You will always find one of the observations I presented above, or another unexpected case. At least, that's my experience.

By the way, parts of the algorithm are explained here.

Why is there a black segment?

There is a length limit in line 645. But to be honest, I don't remember the reason for that. Maybe to avoid short segments within intersections.

@vvoovv
Copy link
Member

vvoovv commented Jul 30, 2024

I suggest that we consider for now only bundles with constant number of ways. For example a Bundle with 2 ways start at an intersection. The same 2 ways enter another intersection where the Bundle ends.

Also I suggest that some intersections with the predefined conditions do not break a Street into 2 Streets. Here are some examples of those conditions:

  • intersection of a major road and a footway
  • intersection of a major road and a cycleway
  • intersection of a major road and a road with the combination of the tags highway=service and service=driveway

@vvoovv
Copy link
Member

vvoovv commented Jul 30, 2024

Also I suggest that some intersections with the predefined conditions do not break a Street into 2 Streets.

Those intersections are local to the Street and can be collected in a list as a property of the Street. They are not included to the global list of intersections.

@vvoovv
Copy link
Member

vvoovv commented Jul 30, 2024

I excluded the following categories in the line 614 of the method createParallelSections(..) of the module bloms.action.generate_streets.

  if section.category in ('steps', 'footway', 'cycleway', 'path', 'service'):
      continue

@polarkernel
Copy link
Collaborator Author

polarkernel commented Aug 8, 2024

I committed a debug version to help understand the current state of development and discuss our proposals. This feature can be enabled in line 722 of /action/generate_streets.py, by setting inBundles to True. When run in script mode, it will plot a bundle of parallel sections, as found by createParallelSections(), one after the other onto the road network (unfortunately slow). Note, that the order of these sections is not yet sorted, they are just stored as a set of Section objects. The title of the plots shows the identification number of such a set, to facilitate identification during our discussions. The intersections between and at the ends of these sections are shown as green circles.

It takes some patience to locate the interesting cases, but I think it's worth it. Scenes with a lot of interesting cases are:

/osm_extracts/facade_visibility/bratislava_old_town.osm
/osm_extracts/streets/milano_01.osm
/osm_extracts/facade_visibility/moscow_leningradski_prospekt.osm

@vvoovv
Copy link
Member

vvoovv commented Aug 8, 2024

Thanks. BTW, /osm_extracts/facade_visibility/bratislava_old_town.osm is mentioned twice in your previous message.

@vvoovv
Copy link
Member

vvoovv commented Aug 8, 2024

What do you think about my proposal of ignoring some intersections that satisfy the predefined conditions?

@polarkernel
Copy link
Collaborator Author

BTW, /osm_extracts/facade_visibility/bratislava_old_town.osm is mentioned twice in your previous message.

Uuups, should have been /osm_extracts/facade_visibility/moscow_leningradski_prospekt.osm. I'll edit it in the original post.

@polarkernel
Copy link
Collaborator Author

What do you think about my proposal of ignoring some intersections that satisfy the predefined conditions?

-- I suggest that we consider for now only bundles with constant number of ways.

I agree.

-- Also I suggest that some intersections with the predefined conditions do not break a Street into 2 Streets.

I see the idea. This would definitively extend the bundle's lengths.

-- Those intersections are local to the Street and can be collected in a list as a property of the Street. They are not included to the global list of intersections.

OK, for the bundle, but what happens with the intersections of these streets, when they leave the bundle, so that the intersection at one end is in this global list, while the other end is outside the bundle? What, if both ends are inside the bundle? Remove those ways? I am not sure if I understand your suggestion.

I am currently studying the solutions I already found a long time ago, where the code is still in the class StreetGenerator. In the (currently commented) methods createLongClusterWays, createClippedClusterEnds and cleanCoveredWays, it took a total of about 1200 lines of code to find some heuristics, that at least worked in many cases. We are now approaching a very complicated part of the project.

What is new, however, are the possibilities opened up by the use of geometric nodes. So solving your requirements may lead us to other, as yet undiscovered solutions.

@vvoovv
Copy link
Member

vvoovv commented Aug 9, 2024

I am not sure if I understand your suggestion.

I suggest dividing our intersections into global and local ones. The global intersections are those in the existing data structure for the intersections. The global intersections define a street configuration on the ground. Typically a street configuration with the global intersections is very rarely changed on the ground.

On the contrary, the local intersections do not change the street configuration on the ground and can be easily created on the ground. For example, a driveway to a new house, or a new pedestrian crossing in the middle of a street.

A driveway (blue) on the image below does not change the street configuration (red)

image

This would definitively extend the bundle's lengths.

It would also extend the length of ordinary streets (non-bundles).

OK, for the bundle, but what happens with the intersections of these streets, when they leave the bundle, so that the intersection at one end is in this global list, while the other end is outside the bundle? What, if both ends are inside the bundle? Remove those ways?

I don't see any problems here.

@polarkernel
Copy link
Collaborator Author

My problem may become more visible if I illustrate the situation in terms of structures in the way network of the scene. As a simple example, the following part of this network could exist:

The red points are instances of Intersection and form the nodes of the network, while the lines between them are instances of Street and form the edges of the network. The streets can have different categories, classified here as major or minor, according to your definitions above. Now let our algorithm decide that the major streets are parallel and can be packed as a Bundle:

The bundle is a kind of list of all roads, and the internal intersections (circles) are collected in another list of the bundle. The geometric node algorithm will construct cluster intersections from the ends of the bundle.

But what about the minor roads? The network structure can't be used anymore. The nodes and edges used for the bundle must be removed. But what shall be done with the end of the left minor road? Will it just be provided as an instance of Street with src or dst set to None? Should the minor street on the right be removed?

@vvoovv
Copy link
Member

vvoovv commented Aug 10, 2024

But what shall be done with the end of the left minor road? Will it just be provided as an instance of Street with src or dst set to None?

The intersection of the minor road and the upper Street in the Bundle will be included in the local list of intersections (or another appropriate data structure) of the upper Street in the Bundle. The intersection won't be available in global data structure of intersections.

The upper Street should be compose of 3 Sections since the sections are separated by the local intersections.

It will be provided as an instance of Street.

Should the minor street on the right be removed?

Both ends of this minor street constitute local intersections in the same Bundle. So this minor street is also local to the Bundle.
A Bundle can have a list of connections between its streets. So a possible solution would be to include the Street into list of local connections in the Bundle and not include the Street in global data structure of Streets.

@polarkernel
Copy link
Collaborator Author

Maybe, my understanding now comes closer to your ideas. Let me explain, what I got until now. Starting point is the current state:

We have Street instances, stored in manager.waymap, then Intersection instances, stored in the list manager.intersections, and finally SideLane and SymLane instances, stored in the lists manager.transitionSideLanes and manager.transitionSymLanes. Let me call these mainItems.

Most of these mainItems will remain as they are, only a few items will need to be collected into a Bundle using the createParallelSections() method (and more code, not yet developed).

As I understand it, the contents of such a Bundle are:

  • A local list majorStreeets of (parallel) instances of Street (green). The end links tail and head of these instances still point to the instances of IntConnector of the intersections, contained in the bundle.
  • A local list majorIntersections of instances of Intersection (red). These are the intersections at the ends of the bundle.
  • A local list minorIntersections of instances of Intersection (circles). These are the intermediate intersections between major streets.
  • A local list minorStreets, containing the internal streets, that are not parallel to the bundle, but belong to it completely. The red minor street at the right of my illustration above is an example. Also, the diagonal streets, as they appear for example in moscow_leningradski_prospekt.osm, could possibly be stored there (to be decided later):

All these items are removed from the mainItems.

The upper Street should be compose of 3 Sections since the sections are separated by the local intersections.

These 3 streets were meant to illustrate the remaining mainItems. A problem is only the street, that points down and has now lost its connection (tail or head) to the connector of the intersection. This has now become a minor intersection of the bundle and will no longer belong to the list manager.intersections.

@vvoovv
Copy link
Member

vvoovv commented Aug 12, 2024

First a note. All these concepts also apply to single Streets (non-Bundles).


We have Street instances ...

The Bundle is composed of 2 Streets. The upper Street is composed of 3 Sections separated by the minor intersections. The lower Street is composed of 2 Sections separated by the minor intersections.

Only a few items will need to be collected into a Bundle

I think they should be in a related Street:

  1. in a linked list of Sections, minor intersections and transitions
  2. in a Python list minorIntersections

The end links tail and head of these instances still point to the instances of IntConnector of the intersections, contained in the bundle.

Shouldn't the tail and head point to the Bundle Intersection?

A local list majorIntersections of instances of Intersection (red). These are the intersections at the ends of the bundle.

Currently a Street does not have a local list majorIntersections. I am not sure if it will be need for Bundles.

A local list minorIntersections of instances of Intersection (circles). These are the intermediate intersections between major streets.

As noted above, Minor Intersections belong to a Street rather than to a Bundle. The Minor Intersections are inserted into the linked list of a Street.

A problem is only the street, that points down and has now lost its connection (tail or head) to the connector of the intersection.

I don't understand, why it is to lose its connection to the intersection. A Minor Intersection should have the same data structure as the Major one.

@polarkernel
Copy link
Collaborator Author

First a note. All these concepts also apply to single Streets (non-Bundles).

Aha. So your idea is to first concatenate instances of Section to an instance of Street to make it as long as possible, and then construct bundles. So, minor intersections can only consist of two major sections and one (or more?) minor sections (of the categories footway, cycleway or the combination of the tags highway=service and service=driveway).

The class Street must be adapted to contain a list of these minor intersections (Python list minorIntersections). Within the Street, the links between the sections and the (minor) intersections can in principle remain. However, they are thought to be links between Streets and not Sections (I don't know yet what effect this will have):

Shouldn't the tail and head point to the Bundle Intersection?

That's another open question. Not all bundles end in a (clustered) intersection. An example is the South-East end of the moscow_leningradski_prospekt (another interesting task for geometric nodes):

Currently a Street does not have a local list majorIntersections. I am not sure if it will be need for Bundles.

I don't know either. The only case I can see where it might make sense are intersections of Streets that are completely inside the Bundle:.

I don't understand, why it is to lose its connection to the intersection. A Minor Intersection should have the same data structure as the Major one.

You are right. I was too entrenched in my network structure (graph).

@polarkernel
Copy link
Collaborator Author

I committed a version that should help to illustrate the discussion on real scenes. Running as script, a first plot (before the plot with the parallel ways) shows the classification, as proposed:

The minor sections (of the categories footway, cycleway or the combination of the tags highway=service and service=driveway) are shown in blue, and the remaining major sections in red. Minor intersections (those with two major sections and one or more minor sections) are marked with a red cross. Major intersections (those with more than two major sections) are shown as red dots. The remaining intersections are marked with a small cyan dot.

Collecting minor sections into long Streets across intersections would eventually be possible. But then, their directions would need to be matched.

@polarkernel
Copy link
Collaborator Author

I wonder what the GN algorithm requires to construct a minor intersection. Given are the position of the intersection and the two major sections of the Street. The minor sections can leave the long Street, that is concatenated from the major sections, to the left or to the right. Could it be a solution, to have one list of minor sections on the right, in the order they leave, and another list of those, that leave on the left? For example, a new class MinorIntersection could be embedded like a SymLane into the double-linked list of Sections:

This MinorIntersection could be very similar to the Intersection we introduced earlier. Instead of a circular linked list, two linear linked lists would be created, held by toRight and toLeft. Additionally, for the integration into Street, the links pred and succ are added (here more detailed, but not all subtleties drawn):

@vvoovv
Copy link
Member

vvoovv commented Aug 13, 2024

Aha. So your idea is to first concatenate instances of Section to an instance of Street to make it as long as possible, and then construct bundles. So, minor intersections can only consist of two major sections and one (or more?) minor sections (of the categories footway, cycleway or the combination of the tags highway=service and service=driveway).

Yes. I suggest using the tag highway=service without the tag service=driveway, since people often forget to include the supplementary tag service=driveway

However, they are thought to be links between Streets and not Sections (I don't know yet what effect this will have):

Sorry, I can't figure out what's new in the scheme.

Not all bundles end in a (clustered) intersection.

If a Bundle is not connected to an Intersection, lets the attributes succ or pred of its Streets to None for now.

@vvoovv
Copy link
Member

vvoovv commented Aug 13, 2024

Collecting minor sections into long Streets across intersections would eventually be possible. But then, their directions would need to be matched.

Both major and minor Sections with minor Intersections should be collected into longer Streets. Are there examples of major Sections which direction do not match?

@polarkernel
Copy link
Collaborator Author

Both major and minor Sections with minor Intersections should be collected into longer Streets. Are there examples of major Sections which direction do not match?

I don't think so. What I meant was the concatenation of minor sections into Streets, using minor intersections. For example, the sections marked with a green sideline in the image below could be concatenated, because they have almost the same direction. The sections marked with a yellow sideline, on the other hand, have quite sharp angles and should not, in my opinion, be concatenated.

@vvoovv
Copy link
Member

vvoovv commented Aug 13, 2024

For example, a new class MinorIntersection could be embedded like a SymLane into the double-linked list of Sections:

I really like your proposal!

@vvoovv
Copy link
Member

vvoovv commented Aug 13, 2024

What I meant was the concatenation of minor sections into Streets, using minor intersections.

For now, I suggest concatenating the major sections and NOT concatenating the minor sections.

@polarkernel
Copy link
Collaborator Author

I really like your proposal!

Fine! If you agree, then I will start developing this part so that we can test the effect.

@vvoovv
Copy link
Member

vvoovv commented Aug 14, 2024

Fine! If you agree, then I will start developing this part so that we can test the effect.

I certainly agree. I will continue to work on Geometry Nodes setups for all those street elements.

@polarkernel
Copy link
Collaborator Author

I committed the version with the new class MinorIntersection. Given an instance of Street, running from left to right on the following image, an instance of MinorIntersection is integrated into the double-linked list by succ and pred, like the other items, intended to exist in a Street:

The linear linked lists of connectors are held by the attribute leftHead of MinorIntersection, for the minor streets to the left of the street, and rightHead for those on the right. The references of the tails (leftTail and rightTail) only increase the speed of appending these connectors. The connectors are of the IntConnector class, identical to those in normal Intersection instances. The attribute location (not drawn in this image) holds the position of the intersection.

The static method iterate_from of MinorIntersection returns an iterator for the linear lists. For example, the left list can be traversed by

            for conn in MinorIntersection.iterate_from(item.leftHead):
                 ...

@polarkernel
Copy link
Collaborator Author

After years of experiments, the code in the StreetGenerator class became a confusing mess. Many of the methods in it are no longer needed (including a number of imported classes). I wonder if I should do a thorough cleanup to make the whole thing more manageable again. I would just need to keep the current code in a safe place in case one or the other idea comes back later.

What do you think?

@vvoovv
Copy link
Member

vvoovv commented Aug 15, 2024

What do you think?

Yes, the code cleanup is desirable. A folder legacy can be used for the old code.

@polarkernel
Copy link
Collaborator Author

Yes, the code cleanup is desirable. A folder legacy can be used for the old code.

OK. I will start by commenting out unused code, so don't wonder about a series of commits. The functionality should always remain the same.

@polarkernel
Copy link
Collaborator Author

polarkernel commented Aug 15, 2024

The cleaning of StreetGenerator and some files around it is done. Its length has been reduced from 2578 to 585 lines. Since the intersection areas can now be calculated by GNs, I removed the attribute area and its computation from Intersection and index from IntConnector. If they are needed again later, they can easily be reintegrated.

I will now rewrite the method createParallelSections to createParallelStreets, and try to find the now longer parallel streets instead of sections. This as a first step towards Bundles. At the same time, we can continue our discussion here and try to find rules for them.

@vvoovv
Copy link
Member

vvoovv commented Sep 16, 2024

I am no longer sure that this is a good solution. Here I made another suggestion. I think the solution should be determined by the way it is handled by GNs. Do you have a suggestion?

I need to experiment with the Bundles and Geometry Nodes. For now I suggest using the solution from here.

@vvoovv
Copy link
Member

vvoovv commented Sep 16, 2024

Earlier I suggested setting Street.pred and Street.succ to Bundle's IntConnector for consistency. Again, the experiments with the Bundles and GN will show if that's really needed.

@vvoovv
Copy link
Member

vvoovv commented Sep 16, 2024

So now I will try to use the Bundles and Bundle Intersections with the Geometry Nodes.

@polarkernel
Copy link
Collaborator Author

So now I will try to use the Bundles and Bundle Intersections with the Geometry Nodes.

Fine! If you want me to modify the current code to fit your experiments, let me know.

The current state of the code is as follows:

  • The ends of single Bundles, that end in normal streets, are unprocessed and do not yet create Intersections. They just keep pred==None or succ==None at their end.
  • The ends of Bundle streets (pred and succ) are unprocessed (they still keep the reference to the former IntConnector).
  • Streets that are in the area of a Bundle, but do not belong to it, have an attribute self.bundle, that references their Bundle,

@vvoovv
Copy link
Member

vvoovv commented Sep 16, 2024

I couldn't find the iterator manager.iterBundles().

@polarkernel
Copy link
Collaborator Author

I couldn't find the iterator manager.iterBundles().

There was once another idea:

manager.iterStreets() can also return an instance of the class Bundle. To distinguish a Bundle from a Street, both classes can have an attribute isBundle.

and

Shouldn't we use isinstance(street,Bundle) to save the space used by isBundle?

but if you are better served by manager.iterBundles(), this is easy to implement.

@vvoovv
Copy link
Member

vvoovv commented Sep 17, 2024

I'd prefer manager.iterBundles().

@polarkernel
Copy link
Collaborator Author

polarkernel commented Sep 17, 2024

I'd prefer manager.iterBundles().

Implemented and committed. Additionally, the ends of single Bundles, that end in normal streets, are processed now and create Intersections.

Intersections have an attribute self.connectsBundles, that is True, when one or more Bundles are in the intersection. I required that for my implementation.

EDIT:
I forgot to change the script renderer for manager.iterBundles(). There is a second commit, with a bug fix, that corrects that.

@polarkernel
Copy link
Collaborator Author

polarkernel commented Sep 17, 2024

Just to illustrate what "counter-clockwise" means for end-intersections with bundles. As an example, the intersection at the top end of the Friedenstraße has connectors to a bundle (1) and to six streets (2-7):

The location of the Intersection instance is the center of gravity of the bundle's endpoints (center of the circle). The connectsBundles attribute is set to True. Specifically, the items of the IntConnectors are:

Nr.  Type      ID    leaving
----------------------------
 1   Bundle    13    False
 2   Street   240    True
 3   Street   239    True
 4   Street   255    False
 5   Street   255    True
 6   Street   560    False
 7   Street   564    False

The street with ID 255 shows, that "counter-clockwise" is no longer based on angles around the location. Please check, if this solution (currently implemented) meets your requirements.

@polarkernel
Copy link
Collaborator Author

I forgot to mention, that since a while there is a method in the code for finding roundabouts. It is simply based on tests for the tags junction=circular or junction=roundabout. As far as I know, all roundabouts in our test scenes are reliably detected. To get an impression, just uncomment self.circularStreets() in line 86 of /action/generate_streets.py and run it in script mode.

I don't know if and how you want to get this information in the produced data, to remove parts of the sidewalks in roundabouts.

@vvoovv
Copy link
Member

vvoovv commented Sep 19, 2024

I am not that far in the GN-development to care of roundabouts :)

@vvoovv
Copy link
Member

vvoovv commented Sep 19, 2024

Maybe I am missing something, but I could not find any connector.item of the type Bundle when I iterate through the connectors of all intersections.

@polarkernel
Copy link
Collaborator Author

Maybe I am missing something, but I could find any connector.item of the type Bundle when I iterate through the connectors of all intersections.

Sorry, it was me that missed something. I drew these intersections, but didn't put them in the intersection container. Fixed now and committed along with some further development, not active for Karl-Marx-Street.

@vvoovv
Copy link
Member

vvoovv commented Sep 20, 2024

Maybe I am missing something, but I could not find any connector.item of the type Bundle when I iterate through the connectors of all intersections.

Still the same problem.

Here is the code I am using to iterate through the connectors:

def processIntersection(intersection)
        connector = intersection.startConnector
        while True:
            item = connector.item
            
            process(intersection, item)

            connector = connector.succ
            if connector is intersection.startConnector:
                break

@polarkernel
Copy link
Collaborator Author

polarkernel commented Sep 21, 2024

Still the same problem.
Here is the code I am using to iterate through the connectors:

I don't know where you got intersection from. The class Intersection has a built-in iterator __iter__(), which allows iterating its IntConnectors just by calling for connector in intersection:. Here are two ways, I was able to find intersections with Bundles. The first accesses the dictionary of major intersections. Intersections have an attribute connectsBundles, that is True, when one or more Bundles are in the intersection. I required that for my implementation.

        for location,intersection in manager.majorIntersections.items():
            if intersection.connectsBundles:
               for connector in intersection:
                    print(intersection.id, type(connector.item), connector.item.id)
               print(' ')

        Output:
        1000 <class 'way.item.bundle.Bundle'> 6
        1000 <class 'way.item.bundle.Bundle'> 2
        1000 <class 'way.item.bundle.Bundle'> 14
        1000 <class 'way.item.bundle.Bundle'> 5

        1001 <class 'way.item.bundle.Bundle'> 2
        1001 <class 'way.item.street.Street'> 215
        1001 <class 'way.item.bundle.Bundle'> 12

        ...

The second method looks for streets, that have IntConnectors at their ends, that connect to an intersection with bundles. This method will not find all these intersections, because in our scene there is one that has only Bundles and no Streets.

      for street in manager.iterStreets():
           if street.pred and isinstance(street.pred,IntConnector):
               intersection = street.pred.intersection
               if intersection.connectsBundles:
                   for connector in intersection:
                       print(street.id,intersection.id, type(connector.item), connector.item.id)
           if street.succ and isinstance(street.succ,IntConnector):
               intersection = street.succ.intersection
               if intersection.connectsBundles:
                   for connector in intersection:
                       print(street.id,intersection.id, type(connector.item), connector.item.id)

       Output, manually separated by stree
       524 1002 <class 'way.item.bundle.Bundle'> 8
       524 1002 <class 'way.item.street.Street'> 527
       524 1002 <class 'way.item.bundle.Bundle'> 14
       524 1002 <class 'way.item.street.Street'> 524

       527 1002 <class 'way.item.bundle.Bundle'> 8
       527 1002 <class 'way.item.street.Street'> 527
       527 1002 <class 'way.item.bundle.Bundle'> 14
       527 1002 <class 'way.item.street.Street'> 524

       ...

@vvoovv
Copy link
Member

vvoovv commented Sep 21, 2024

Still the same problem.

The reason for that issue is clear for me now.

At the moment I process only intersection with intersection.order == 4. However intersection.order == 0 for intersection.id == 1000. That doesn't look to be correct.

@polarkernel
Copy link
Collaborator Author

At the moment I process only intersection with intersection.order == 4. However intersection.order == 0 for intersection.id == 1000. That doesn't look to be correct.

Now fixed. The initial way to construct Intersections uses "leaving ways", which then are sorted counterclockwise. Then the property order counted the number of these ways. After the introduction of minor intersections and intersections with bundles, this was no longer valid.

@polarkernel
Copy link
Collaborator Author

I was able to make some progress. There are situations, like in the scene /streets/taipei.osm, where the algorithm of createParallelStreets() passes an intersection, as shown here for the blue and green groups. Both go through the intersection and must be split.

I found a method to resolve these situations, so in this example, a normal intersection (id==897) is created with four bundles:

Although the scene /streets/taipei.osm is not yet fully resolved, this intersection can already be used as a test example for an intersection of bundles with more than 2 streets.

A big problem remains with inner streets that end at the ends of the bundle, such as the yellow streets indicated by the green arrow:

I have big problems even to detect and collect them reliably, because their intersections are not minor. Also the construction of the bundle intersection at the end indicated by the blue arrow is difficult, because one street becomes an inner street.

@vvoovv
Copy link
Member

vvoovv commented Sep 23, 2024

I found a method to resolve these situations, so in this example, a normal intersection (id==897) is created with four bundles:

Is it just an occasion that those 4 Bundles were drawn with the same green color?

@vvoovv
Copy link
Member

vvoovv commented Sep 23, 2024

A big problem remains with inner streets that end at the ends of the bundle, such as the yellow streets indicated by the green arrow:

Are those inner yellow streets detected as a part of the red horizontal Bundle?

@polarkernel
Copy link
Collaborator Author

Is it just an occasion that those 4 Bundles were drawn with the same green color?

No, in the final plot, all Bundles are drawn in green, while in the intermediate plot, I used random colors. In the final plot, colors are used to distinguish street classes.

Are those inner yellow streets detected as a part of the red horizontal Bundle?

No. They are detected as a combination of two final bundles. See the first image: All green streets are detected at once and must be split into the two final bundles.

@polarkernel
Copy link
Collaborator Author

The next step is committed. I was able to detect and extract inner streets that end at the ends of a bundle, as discussed above. Additionally, intersections with multiple bundles and standard streets are now constructed correctly, as for instance for the intersection 895 at the left of the image below. As far as I could test, the scene /streets/taipei.osm should be built correctly.

In the final plot generated by the mpl renderer, inner streets are drawn as golden lines. Those in the image above form a set of inner streets that belongs to bundle 7. This means that the streets attribute bundle refers to bundle 7. Unlike the inner streets as they appear in /facade_visibility/berlin_karl_marx_allee.osm, where such streets are connected to minor intersections of the streets in the bundle, the ends of these streets are not connected to any intersection. This means that in the image below, the golden inner streets are not connected to intersection 895. I don't know if this makes sense to you or not.

@vvoovv
Copy link
Member

vvoovv commented Sep 24, 2024

Earlier I suggested setting Street.pred and Street.succ to Bundle's IntConnector for consistency. Again, the experiments with the Bundles and GN will show if that's really needed.

Currently they are set to IntConnectors of "local" Intersections that aren't used anymore after building bundled Intersections.

Setting Street.pred and Street.succ to Bundle's IntConnectors will make it possible to determine if a Street is leaving or entering a bundled Intersection.

@polarkernel
Copy link
Collaborator Author

Setting Street.pred and Street.succ to Bundle's IntConnectors will make it possible to determine if a Street is leaving or entering a bundled Intersection.

Implemented and committed.

@vvoovv
Copy link
Member

vvoovv commented Sep 25, 2024

Some progress in rendering of bundled Intersections.

The most difficult and time consuming part (geometry for connectors and minor intersections) is ahead.

image

image

@polarkernel
Copy link
Collaborator Author

Some bugs were fixed, and the result is committed. A major enhancement is the handling of intersections within a bundle. For example, the scene /streets/rotterdam_01.osm now runs correctly:

The head of the bundle is at the bottom and its streetsHead attribute holds the streets S120, S40, S35 and S119. All four end at the intersections 75 and 83. The streetsTail attribute holds the streets S113 and S114, which end at the same intersections. Note that these intersections are still stored as major intersections outside the bundle, because Bundle has no means to store them.

@vvoovv
Copy link
Member

vvoovv commented Sep 27, 2024

Could you please add an id in the drawings for intersections with Bundles?

@vvoovv
Copy link
Member

vvoovv commented Sep 27, 2024

Could you please explain again, when an orange circle is drawn and why is the orange circle at the center of taipei.osm so huge?

@polarkernel
Copy link
Collaborator Author

Could you please add an id in the drawings for intersections with Bundles?

Done and committed. Streets in bundles and intersections with bundles now always get an ID printed. If you want to get all IDs for the scene, add --debugStreetRendering to the command line.

Could you please explain again, when an orange circle is drawn and why is the orange circle at the center of taipei.osm so huge?

Orange circles show Intersections of single Bundles with normal Streets. So there is one single IntConnector with the Bundle and one or more IntConnectors with the street(s). This post explains an example of such an intersection in detail.

In contrast, Bundles that end without normal Streets, such as Bundle 1 in the scene /streets/taipei.osm, where it intersects with the scene boundary at the bottom, do not have an Intersection. They just end with pred==None or succ==None.

The huge circle you observed was a bug caused by the changes I made to the handling of intersections within a bundle (see my last post). I have commented them out for now until I have a solution.

@polarkernel
Copy link
Collaborator Author

The handling of intersections within a bundle has been fixed. Using the committed version, the following scenes containing bundles should (in my opinion) produce consistent results:

        /facade_visibility/berlin_karl_marx_allee.osm
        /streets/rotterdam_01.osm
        /streets/taipei.osm
        /streets/piestany_north.osm
        /streets/prague_vinohrady.osm            # Ends wide apart on one side
        /streets/berlin_friedrichstrasse.osm
        /streets/alsenstrasse.osm
        /facade_visibility/manhattan_01.osm

In the remaining scenes, I continue to find solutions for handling other problems.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants