Closed vvoovv closed 5 months ago
Have you implemented a method to split a section?
No, not yet, but I can do it quickly. Once, an interface has been proposed:
def split(self, nodeIndex, item, itemLength):
# The method splits the section at the <nodeIndex> and inserts the <item> which has
# the length <itemLength>. The attributes centerline, pred, succ of the items in question
# are changed or set accordingly.
pass # to be implemented
Is this still valid? What was the idea behind itemLength
? Should the section be shortened by this value? In a straight line or along the centerline? This could lead to exceptions if this value is too large. How should these be handled? Please define your requirements and I will implement it as soon as possible.
I suggest implementing two methods of the class Section
.
splitFromStart(length, item)
splitFromEnd(length, item)
length
: the length of the newly created polyline after the split.
item
: the newly created polyline after the split will be assigned to the item
.
A possible optimization could be keeping the original centerline
and providing an index of the point of the original centerline after which the split occurred and the coordinates of the split. If the split occured right at an existing vertex of the original polyline, the coordinates are set to None. An additional attribute centerlineData
can be used to store the index and the coordinates as a tuple.
I am not sure though if that optimization is worth at all.
The class PolyLine, which is used for the centerline, already implements two types of parameters, that could be used to describe split positions. The line parameter t
uses the number of vertices and the percentage of the interval between them:
# The line parameter <t> describes a position onto the line. It is
# constructed ba a compound of the last vertex number and the percentage
# of the following segment. <t> measures the distance from the start
# vertex, given by the <view> of the polyline. The vertex at the position
# can be found by the method t2v().
#
# t=1.4 (fwd) t= 2.8 (rev)
# ------------> <--------------------------
# | | | |
# | V V |
# o---------o---x-----o-x-------o---------o---------o
# 0 1 2 3 4 5
Just to be clear, Polyline
implements two views, forward (fwd
) and reverse (rev
). But Sections
handle that automatically, so we don't need to worry about it. .
The other line parameter d
describes the length of the line (in meters) from the start vertex to the split point:
# The line parameter <d> describes a position onto the line. It measures
# the cumulated length of the polyline from the start vertex, given by
# the <view> of the polyline. to the position. The vertex at the position
# can be found by the method d2v().
#
# d (fwd) d (rev)
# ----------------> <----------------------
# | | | |
# | V V |
# o-------------o---x-----o-x-------o-----o---------o
# 0 1 2 3 4 5
Some methods allow interchangeability between them and the computation of the splitting vertex:
def t2v(self,t):
# Computes the vertex given by the line parameter <t>.
def d2v(self,d):
# Computes the vertex given by the line parameter <d>.
def d2t(self,d):
def t2d(self,d):
In the class Section
, the parameter t
is already used to trim the ends of a section at intersections:
self.trimS = 0. # trim factor for start
self.trimT = len(self.polyline)-1 # trim factor for target
The trimming itself is done at the very end of the module generate_streets
in the method finalizeOutput
. PolyLine
provides a method trimmed
, which returns a trimmed instance of PolyLine
:
section.centerline = section.polyline.trimmed(section.trimS,section.trimT)
Each of these parameters (t
or d
) could be used to describe a split point. A new method split
of the class PolyLine
could return both parts of the split centerline. In any case, we should define what to do with the trim parameters. They may conflict with the splitting for short sections.
Suppose there is a section
, and the method section.splitFromStart(length, item)
or section.splitFromEnd(length, item)
is called.
If the parameter length
supplied in splitFromStart
or splitFromEnd
is equal to or larger than the length of the section
, then the section
will be completely replaced by the supplied parameter item
. A reference to the replaced section
will be kept: item.replacedItem = section
. For now I suggest considering only an adjacent section, even if the parameter lengh
is much longer than the length of that section.
What else would be required to implement the methods splitFromStart(length, item)
and splitFromEnd(length, item)
?
What else would be required to implement the methods
splitFromStart(length, item)
andsplitFromEnd(length, item)
?
Well, I am not sure yet, what the result of these operations shall be. I assume that the sections are embedded in a Street
. Let's take first splitFromStart(length, item)
. If I understand correctly, the result would be a piece of the section with the length length
from its start, linked by succ
to item
(and item
by prev
to the trimmed section) while the original reference succ
of the section becomes succ
of item
.
What irritates me is the term split. When I split something, I expect to get two parts, and not just the left or right end.
Before a split: section
After the split: item
followed by section
, i.e. section was shortened by length
item.succ == section
section.prev == item
The signature of the method can be changed to better fit the term split in the following way.
splitFromStart(length, itemForSection1, itemForSection2)
where
itemForSection1.succ == itemForSection2
itemForSection2.prev == itemForSection1
What irritates me is the term split.
I decided to change the term. I have implemented and committed methods of Section
with the following signatures:
def insertAfter(self, length, item):
# Shortens the section to the length <length> and appends <item> after it. <length> is
# the physical length in meters. After the split the section is followed by <item>. The
# method returns True, if item is successfully inserted and False else.
# For now, the method returns False, when <length> is larger than the length of the section.
# <item> is inserted into the linked list by:
# section.succ.pred = item # if pred exists
# item.succ = section.succ
# section.succ = item
# item. pred = section
def insertBefore(self, length, item):
# Shortens the section so that it starts after the length <length> and remains until its end.
# <length> is the physical length in meters. After the split the item is followed by the
# remaining section. The method returns True, if <item> is successfully inserted and False else.
# For now, the method returns False, when <length> is larger than the length of the section.
# <item> is inserted into the linked list by:
# section.pred.succ = item # if succ exists
# item.pred = section.pred
# item.succ = section
# section.pred = item
To use them, import way/item/section.py. For now, the methods returns False
, when length
is larger than the length of the section. We may adapt this behavior later, after first experiences.
To use them, import way/item/section.py.
Why is it necessary to import the module way.item.section
? The methods insertAfter(..) and insertBefore(..) aren't static.
Why is it necessary to import the module
way.item.section
?
Uuups. This was an effect of decades of projects with C++. There, an appropriate include statement was always required. Python is different, I will learn it once.
def insertAfter(self, length, item): def insertBefore(self, length, item):
Would it be possible to add an attribute centerline
to the item
after the modification of the section?
Would it be possible to add an attribute
centerline
to theitem
after the modification of the section?
Sure. Should this attribute centerline
be the remaining part of the section's centerline? What about the order of the vertices? Use the same direction as the section had at that part?
Both affected sections (self
and item
) should have the attribute centerline
. The direction is the same as the original section had.
Both affected sections (
self
anditem
) should have the attribute centerline. The direction is the same as the original section had.
Implemented and committed. There is no assumption made, that item
is a Section
. It just gets the centerline
and no additional adjustments are made, that would be required for a Section
(for example, for trim values).
I called the methodinsertBefore(..)
for the section.id == 115
with the parameter length == 10
and got the result below:
The length of the gap is 10. The white point on the screenshot must be on the right end of the current gap.
The length of the gap is 10. The white point on the screenshot must be on the right end of the current gap.
Bug fixed and committed.
Bug fixed and committed.
Thank. It works now.
I added the parameter updateNeighbors
for the methods insertAfter
and insertBefore
. All affected items already have the appropriate values for attributes pred
and succ
. Setting them in those methods leads to incorrect values for the attributes pred
and succ
.
I'd like to split a section with a side lane transition. I think the split should happen in the renderer code. The split is needed for a more straightforward rendering.
Have you implemented a method to split a section?