def prepare_strokes_lvl2(delimited_stroke_class):
    """Constructs delimited strokes of level 2 for road sections in strokes that could not be matched."""
    not_matched_strokes = session.query(delimited_stroke_class).filter(
        delimited_stroke_class.match_id == None)
    if delimited_stroke_class == DelimitedStrokeRef:
        delimited_strokes = delimited_strokes_ref
    else:
        delimited_strokes = delimited_strokes_target

    for delimited_stroke in not_matched_strokes:
        for road_section in delimited_strokes[delimited_stroke.id]:
            road_section.delimited_stroke = None
        begin_junction = delimited_stroke.begin_junction
        for road_section in delimited_strokes[delimited_stroke.id]:
            if road_section.delimited_stroke is None:
                new_stroke = construct_stroke_from_section(
                    road_section,
                    delimited_stroke_class,
                    level=2,
                    begin_junction=begin_junction)
                extended_stroke = construct_stroke(road_section,
                                                   begin_junction,
                                                   new_stroke,
                                                   level=2)
                begin_junction = extended_stroke.end_junction

    session.query(delimited_stroke_class).filter(
        delimited_stroke_class.level == 1,
        delimited_stroke_class.match_id == None).delete()
Example #2
0
def get_area(geom):
    """Calculates the area (in m2) of a plane."""
    numpoints = session.query(func.st_numpoints(geom))[0][0]
    if numpoints > 2:
        return session.query(
            func.st_area(
                func.st_makepolygon(
                    func.st_addpoint(geom, func.st_startpoint(geom)))))[0][0]
    else:
        return 0
Example #3
0
def angle_at_junction(road_section, junction):
    """Calculates the angle of the line segment of road_section at junction."""
    assert (road_section.begin_junction == junction
            or road_section.end_junction == junction)
    first_point_section = session.query(func.st_startpoint(
        road_section.geom))[0][0]
    if session.query(func.st_equals(first_point_section, junction.geom))[0][0]:
        angle = session.query(
            func.ST_Azimuth(junction.geom,
                            road_section.geom.ST_PointN(2)))[0][0]
    else:
        angle = session.query(
            func.ST_Azimuth(junction.geom,
                            road_section.geom.ST_PointN(-2)))[0][0]
    assert angle is not None
    return angle
def preprocess_target(preprocessing_check):
    """"Handles the preprocessing of the target dataset. Includes classification of junctions and construction of
        delimited strokes at level 1. Set the input preprocessing_check to false if the junctions are already
        classified and saved in the database"""
    session.query(DelimitedStrokeTarget).delete()
    reset_delimited_strokes(session.query(RoadSectionTarget))

    junctions_target = session.query(JunctionTarget)
    if preprocessing_check:
        print("Classifying junctions of the target database.")
        classify_junctions(junctions_target)

    print("Constructing strokes of the target database.")
    construct_strokes(junctions_target, DelimitedStrokeTarget)
    remaining_sections_target = session.query(RoadSectionTarget).filter(
        RoadSectionTarget.delimited_stroke_id == None)
    for road_section in remaining_sections_target:
        construct_stroke_from_section(road_section, DelimitedStrokeTarget)
def generate_output(matches):
    session.query(LinkingTable).delete()
    for match in matches:
        strokes = session.query(DelimitedStrokeRef).filter(
            DelimitedStrokeRef.match_id == match.id)
        if not strokes.first():
            # print('Match', match.id, 'no longer exists')
            continue
        for stroke_ref in match.strokes_ref:
            try:
                for section_ref in delimited_strokes_ref[stroke_ref.id]:
                    for stroke_target in match.strokes_target:
                        for section_target in delimited_strokes_target[
                                stroke_target.id]:
                            link = LinkingTable(
                                nwb_id=section_ref.id,
                                top10nl_id=section_target.id,
                                match_id=match.id,
                                similarity_score=match.similarity_score)
                            session.add(link)
                            session.flush()
            except KeyError:
                print('Stroke', stroke_ref.id,
                      'not recorded in delimited strokes dictionary')
    def set_similarity_score(self):
        """Calculates the similarity score of the match. It is a weighted sum of scaled attributes, which are
        difference in length, difference in distance (hausdorff distance) and difference in area."""
        length_diff = length_difference(self.strokes_ref, self.strokes_target)
        hausdorff = session.query(
            func.st_hausdorffdistance(self.geom_ref, self.geom_target))[0][0]
        area_diff = self.set_area_difference()
        area_diff_normalized = area_diff / get_length(self.strokes_ref)

        weights = [0.5, 0.35, 0.15]  # sum equal to 1
        metrics = [
            length_diff / tolerance_length, hausdorff / tolerance_hausdorff,
            area_diff_normalized / tolerance_area_normalized
        ]
        score = 0

        for index, metric in enumerate(metrics):
            score += weights[index] * (1 - metric)

        return score
def matching_process(level, tolerance_distance):
    """Searches for a match for each delimited stroke in the reference database."""
    strokes_ref = session.query(DelimitedStrokeRef).filter(
        DelimitedStrokeRef.level == level, DelimitedStrokeRef.match_id == None)
    count = 0
    all_matches = []
    for stroke in strokes_ref:
        try:
            matches = find_matching_candidates(stroke, tolerance_distance)
        except AssertionError as e:
            print(e)
            print(traceback.format_exc())
            print('Something went wrong trying to find a match for stroke',
                  stroke.id)
            matches = None
        # TODO add correct Exception, merging looping road sections is not possible

        if matches:
            best_score = 0
            best_match = None
            for match in matches:
                if match.similarity_score >= best_score:
                    best_match = match
                    best_score = match.similarity_score

            if best_match:
                for stroke_ref in best_match.strokes_ref:
                    stroke_ref.match_id = best_match.id
                for stroke_target in best_match.strokes_target:
                    stroke_target.match_id = best_match.id

                all_matches.append(best_match)
        count += 1
        if count % 100 == 0:
            print('Strokes analyzed:', count)

    return all_matches
Example #8
0
def combine_geom(list_of_strokes):
    """Expects a list of strokes, returns a combined geometry of the strokes in the list."""
    geoms = [stroke.geom for stroke in list_of_strokes]
    return session.query(
        func.st_astext(func.st_linemerge(func.st_collect(array(geoms)))))[0][0]
Example #9
0
def get_length(list_of_strokes):
    """Calculates the length (in m) of the input array of strokes."""
    length = 0
    for stroke in list_of_strokes:
        length += session.query(func.st_length(stroke.geom)).first()[0]
    return length
def construct_stroke(road_section, junction, delimited_stroke, level=1):
    """Constructs a delimited stroke from road_section, with junction as its starting point.
    If a delimited_stroke is given as input, the next road_section is added to this delimited_stroke."""
    session.flush()
    # the delimited stroke dictionary use here is based on type of the input stroke
    if type(delimited_stroke) == DelimitedStrokeRef:
        delimited_strokes = delimited_strokes_ref
    else:
        delimited_strokes = delimited_strokes_target
    road_section.delimited_stroke = delimited_stroke

    # determine which from which junction the next road section should be added
    if junction == road_section.begin_junction:
        next_junction = road_section.end_junction
    else:
        next_junction = road_section.begin_junction

    # if the next_junction is the same as the begin_junction of the delimited stroke, it is a loop and can be returned
    if next_junction.id == delimited_stroke.begin_junction_id:
        delimited_stroke.end_junction_id = next_junction.id
        return delimited_stroke

    # if the degree of the next junction is 2, the road section that is not equal to the input is added
    # to the delimited stroke
    if next_junction.degree == 2:
        for next_road_section in next_junction.road_sections:
            if next_road_section != road_section:
                delimited_stroke.geom = session.query(
                    func.st_linemerge(
                        func.st_collect(delimited_stroke.geom,
                                        next_road_section.geom)))
                delimited_strokes[delimited_stroke.id].append(
                    next_road_section)
                return construct_stroke(next_road_section, next_junction,
                                        delimited_stroke, level)

    # only strokes at level 1, are extended with sections that have good continuity
    if level == 1:
        if next_junction.type_k3 == 2:
            current_angle = angle_at_junction(road_section, next_junction)
            if current_angle != next_junction.angle_k3:

                # select the next section that has good continuity
                for next_road_section in next_junction.road_sections:
                    if next_road_section != road_section and next_road_section.delimited_stroke is None:
                        next_angle = angle_at_junction(next_road_section,
                                                       next_junction)
                        if next_angle != next_junction.angle_k3:
                            # if the next section is a loop, it is not added to the delimited stroke
                            if next_road_section.begin_junction == next_road_section.end_junction:
                                delimited_stroke.end_junction_id = next_junction.id
                                return delimited_stroke

                            # merge the selected section with the existing delimited stroke to extend it
                            delimited_stroke.geom = session.query(
                                func.st_linemerge(
                                    func.st_collect(delimited_stroke.geom,
                                                    next_road_section.geom)))
                            delimited_strokes[delimited_stroke.id].append(
                                next_road_section)
                            return construct_stroke(next_road_section,
                                                    next_junction,
                                                    delimited_stroke, level)

    # if the stroke is not extended, the end junction is set
    delimited_stroke.end_junction_id = next_junction.id
    return delimited_stroke
Example #11
0
def get_distance(object_a, object_b):
    """Calculates the distance between two geometries."""
    assert object_a.geom is not None
    assert object_b.geom is not None
    return session.query(func.st_distance(object_a.geom, object_b.geom))[0][0]
Example #12
0
def extend_matching_pair(stroke_ref, stroke_target, junction_ref,
                         junction_target, tolerance_distance):
    """Extends the input delimited strokes with strokes that have good continuity at input junction,
    until a good match is found or if no match is possible. Stroke_ref and stroke_target are both lists of delimited
    strokes."""
    # create local variables of which stroke to extend and which to compare to when a new stroke is added
    if get_length(stroke_ref) < get_length(stroke_target):
        stroke_to_extend = stroke_ref
        stroke_to_compare = stroke_target
        junction_to_extend = junction_ref
        junction_to_compare = junction_target
    else:
        stroke_to_extend = stroke_target
        stroke_to_compare = stroke_ref
        junction_to_extend = junction_target
        junction_to_compare = junction_ref

    new_stroke = None
    # if the junction where the next stroke is added is a W-junction (type 1), select the stroke of the outer road
    # sections to be added
    if junction_to_extend.type_k3 == 1:
        if angle_at_junction(
                stroke_to_extend[-1],
                junction_to_extend) != junction_to_extend.angle_k3:
            for road_section in junction_to_extend.road_sections:
                if road_section.delimited_stroke != stroke_to_extend[-1] and junction_to_extend.angle_k3 != \
                        angle_at_junction(road_section, junction_to_extend):
                    new_stroke = road_section.delimited_stroke

    # for other junctions, select the stroke that has good continuity
    if junction_to_extend.degree > 1:
        for road_section in junction_to_extend.road_sections:
            if road_section.delimited_stroke != stroke_to_extend[
                    -1] and has_good_continuity(road_section,
                                                stroke_to_extend[-1],
                                                junction_to_extend):
                new_stroke = road_section.delimited_stroke

    if new_stroke and (new_stroke.begin_junction == junction_to_extend
                       or new_stroke.end_junction == junction_to_extend):
        stroke_to_extend.append(new_stroke)
        junction_to_extend = other_junction(stroke_to_extend[-1],
                                            junction_to_extend)
        point_distance = session.query(
            func.st_distance(junction_to_extend.geom,
                             junction_to_compare.geom))[0][0]
        if point_distance < tolerance_distance:
            return Match(stroke_ref, stroke_target)
        elif session.query(func.st_distance(junction_to_extend.geom, stroke_to_compare[-1].geom))[0][0] < tolerance_distance or \
                session.query(func.st_distance(junction_to_compare.geom, stroke_to_extend[-1].geom))[0][0] < tolerance_distance:
            if stroke_to_extend == stroke_ref:
                return extend_matching_pair(stroke_ref, stroke_target,
                                            junction_to_extend,
                                            junction_target,
                                            tolerance_distance)
            elif stroke_to_extend == stroke_target:
                return extend_matching_pair(stroke_ref, stroke_target,
                                            junction_ref, junction_to_extend,
                                            tolerance_distance)
            else:
                print('Error: wrong stroke')
    return None
Example #13
0
def nearby_junctions(junction_ref, tolerance_distance):
    """Finds the junctions in the target database that are within the tolerance distance of junction_ref."""
    junctions = session.query(JunctionTarget).filter(
        func.st_dwithin(JunctionTarget.geom, junction_ref.geom,
                        tolerance_distance))
    return junctions