Exemplo n.º 1
0
    def extract_bed(self, bed1_id, bed2_id):
        """
        @brief: Extract coordinates of a portion of a cross-section between 2 limits
            /!\ bed1_id and bed2_id should be "ordered" correctly, otherwise an exception is raised
        @return <Bed>: structured array with columns ('X', 'Y', 'Xt', 'xt')
        """
        limit1 = self.get_limit_by_id(bed1_id)
        limit2 = self.get_limit_by_id(bed2_id)

        Xt1 = limit1['Xt_section']
        Xt2 = limit2['Xt_section']

        # Check that Xt are increasing from bed1_id to bed2_id
        if Xt1 > Xt2:
            raise TatooineException(
                "Order of beds {} and {} leads to decreasing Xt values for {}".
                format(bed1_id, bed2_id, self))

        Xt_section = self.coord.array['Xt']
        sub_coord = self.coord.array[np.logical_and(Xt_section >= Xt1,
                                                    Xt_section <= Xt2)]

        # Add starting point if necessary
        if Xt1 not in Xt_section:
            row = np.array([
                tuple(limit1[var] if var not in ('Xt', 'xt') else Xt1
                      for var in sub_coord.dtype.names)
            ],
                           dtype=sub_coord.dtype)
            row['xt'] = 0.0
            sub_coord = np.insert(sub_coord, 0, row)

        # Add last point if necessary
        if Xt2 not in Xt_section:
            row = np.array([
                tuple(limit2[var] if var not in ('Xt', 'xt') else Xt2
                      for var in sub_coord.dtype.names)
            ],
                           dtype=sub_coord.dtype)
            row['xt'] = 1.0
            sub_coord = np.append(sub_coord, row)

        # Check order of points
        if not strictly_increasing(sub_coord['Xt']):
            logger.debug("/!\ Xt values are not strictly increasing"
                         )  # FIXME: It should not happen!
            logger.debug(sub_coord['Xt'])
            logger.debug("Please check the following limits below:")
            logger.debug(limit1)
            logger.debug(limit2)
            points_to_keep = np.ediff1d(sub_coord['Xt'], to_begin=1.) != 0.
            sub_coord = sub_coord[points_to_keep]

        return Bed(sub_coord, ['xt'])
Exemplo n.º 2
0
    def find_and_add_limits(self, constraint_lines, dist_max):
        """
        @param constraint_lines <[ConstraintLine]>: list of constraint lines
        @param dist_max <float>: maximum search distance to rescue intersections for limits
        """
        logger.info("~> Looking for limits")
        for i, section in enumerate(self):
            for constraint_line in constraint_lines:
                section.find_and_add_limit(constraint_line, dist_max)
            section.sort_limits()

            limits = section.limits.keys()  # only to print
            logger.debug("> {}".format(section))
            logger.debug("{} limits found with lines {}".format(
                len(limits), list(limits)))
Exemplo n.º 3
0
    def find_and_add_limit(self, constraint_line, dist_max=None):
        """
        @param constraint_line <shapely.geometry.LineString>: 2D constraint line
        @param dist_max <float>: maximum search distance to rescue intersections for limits
        """
        if self.geom.intersects(constraint_line.geom):
            intersection = self.geom.intersection(constraint_line.geom)

            if isinstance(intersection, MultiPoint):
                logger.warn(
                    "Intersection between '{}' and '{}' contains multiple points, "
                    "only the first is kept.".format(self, constraint_line))
                intersection = intersection[0]

            if isinstance(intersection, Point):
                # Compute projections
                Xt_section = self.geom.project(intersection)
                Xt_line = constraint_line.geom.project(intersection)
                self.add_limit(constraint_line.id, Xt_section, Xt_line,
                               intersection)

            else:
                raise TatooineException(
                    "Intersection between '{}' and '{}' is empty or not supported: {}"
                    .format(self, constraint_line, type(intersection)))
        else:
            if dist_max is not None:
                distance = self.geom.distance(constraint_line.geom)
                if distance < dist_max:
                    for i, coord in enumerate(constraint_line.coord):
                        # Try to find a point of the constraint line which is in the vicinity of the current section
                        point = Point(coord)
                        dist = self.geom.distance(point)
                        if dist < dist_max:
                            # A point is found and is considered
                            Xt_line = constraint_line.geom.project(point)
                            Xt_section = self.geom.project(point)
                            intersection = self.geom.interpolate(Xt_section)
                            self.add_limit(constraint_line.id, Xt_section,
                                           Xt_line, intersection)
                            logger.debug(
                                "Add a limit with the line {} after {} iterations (distance = {})"
                                .format(constraint_line.id, i, dist))
                            break
Exemplo n.º 4
0
    def build_interp(self, constraint_lines, long_step, constant_long_disc):
        """
        Build interpolation, add points and segments

        @param constraint_lines <[ConstraintLine]>: list of constraint lines
        @param long_step <float>: longitudinal space step
        @param constant_long_disc <bool>
        """
        nb_pts_inter = 0
        self.build_initial_profiles()

        # LOOP ON ZONES (between 2 consecutive cross-sections)
        logger.info("~> Building mesh per zone and then per bed")

        for i, (prev_section, next_section) in enumerate(
                zip(self.section_seq, self.section_seq[1:])):
            logger.debug("> Zone n°{} : between {} and {}".format(
                i, prev_section, next_section))

            if constant_long_disc:
                nb_pts_inter = prev_section.compute_nb_pts_inter(
                    next_section, long_step)
                Xp_adm_list = np.linspace(0.0, 1.0, num=nb_pts_inter + 2)[1:-1]

            # Looking for common limits between cross-sections
            common_limits_id = prev_section.common_limits(
                next_section.limits.keys())
            logger.debug("Common limits: {}".format(list(common_limits_id)))

            if len(common_limits_id) < 2:
                raise TatooineException(
                    "No interpolation in the interval %i, between %s and %s (%i common limits)"
                    % (i, prev_section, next_section, len(common_limits_id)))

            else:
                first_bed = True
                # LOOP ON BEDS
                for j, (id1, id2) in enumerate(
                        zip(common_limits_id, common_limits_id[1:])):
                    pt_list_L1 = []
                    pt_list_L2 = []

                    logger.debug("Bed {}-{}".format(id1, id2))

                    # Extraction of cross-section portions (= beds)
                    bed_1 = prev_section.extract_bed(id1, id2)
                    bed_2 = next_section.extract_bed(id1, id2)

                    # Curvilinear abscissa along constraint lines
                    (Xp_profil1_L1,
                     Xp_profil1_L2) = prev_section.get_Xt_lines(id1, id2)
                    (Xp_profil2_L1,
                     Xp_profil2_L2) = next_section.get_Xt_lines(id1, id2)
                    dXp_L1 = Xp_profil2_L1 - Xp_profil1_L1
                    dXp_L2 = Xp_profil2_L2 - Xp_profil1_L2

                    if dXp_L1 < 0:
                        raise TatooineException(
                            "The constraint line {} is not oriented correctly".
                            format(id1))
                    if dXp_L2 < 0:
                        raise TatooineException(
                            "The constraint line {} is not oriented correctly".
                            format(id2))

                    if not constant_long_disc:
                        nb_pts_inter = math.ceil(
                            min(dXp_L1, dXp_L2) / long_step) - 1
                        Xp_adm_list = np.linspace(0.0,
                                                  1.0,
                                                  num=nb_pts_inter + 2)[1:-1]

                    L1_coord_int = constraint_lines[
                        id1].coord_sampling_along_line(Xp_profil1_L1,
                                                       Xp_profil2_L1,
                                                       Xp_adm_list)
                    L2_coord_int = constraint_lines[
                        id2].coord_sampling_along_line(Xp_profil1_L2,
                                                       Xp_profil2_L2,
                                                       Xp_adm_list)

                    # LOOP ON INTERMEDIATE CROSS-SECTIONS
                    for k in range(nb_pts_inter):
                        Xp = Xp_adm_list[k]
                        P1 = Point(tuple(L1_coord_int[k]))
                        P2 = Point(tuple(L2_coord_int[k]))

                        if self.nb_pts_lat is None:
                            nb_pts_lat = math.ceil(
                                P1.distance(P2) / self.lat_step) + 1
                        else:
                            nb_pts_lat = self.nb_pts_lat
                        array = bed_1.interp_coord_linear(
                            bed_2, Xp, nb_pts_lat)
                        bed_int = Bed(array, ['Xt', 'xt'])
                        bed_int.move_between_targets(P1, P2)
                        coord_int = bed_int.array[[
                            'X', 'Y', 'xt', 'Xt_upstream', 'Xt_downstream'
                        ]]  # Ignore `Xt`
                        pt_list_L1.append(self.i_pt + 1)

                        if not first_bed:
                            # ignore first point because the constraint line was already considered
                            coord_int = coord_int[1:]

                        self.add_points(coord_int, i, Xp, j)

                        pt_list_L2.append(self.i_pt)

                    pt_list_L2 = np.array(
                        [prev_section.get_limit_by_id(id2)['id_pt']] +
                        pt_list_L2 +
                        [next_section.get_limit_by_id(id2)['id_pt']])
                    self.add_segments_from_node_list(pt_list_L2)

                    if first_bed:
                        pt_list_L1 = np.array(
                            [prev_section.get_limit_by_id(id1)['id_pt']] +
                            pt_list_L1 +
                            [next_section.get_limit_by_id(id1)['id_pt']])
                        self.add_segments_from_node_list(pt_list_L1)
                        first_bed = False
Exemplo n.º 5
0
    def build_initial_profiles(self):
        logger.info(
            "~> Interpolate initial cross-sections taking into account limits")
        for i in range(len(self.section_seq)):
            curr_profile = self.section_seq[i]
            logger.debug(curr_profile)

            # Looking for upstream common limits
            if i == 0:
                common_limits_id_1 = curr_profile.limits.keys()
            else:
                common_limits_id_1 = curr_profile.common_limits(
                    self.section_seq[i - 1].limits.keys())

            # Looking for downstream common limits
            if i == len(self.section_seq) - 1:
                common_limits_id_2 = curr_profile.limits.keys()
            else:
                common_limits_id_2 = curr_profile.common_limits(
                    self.section_seq[i + 1].limits.keys())

            # Ordered union of upstream and downstream limits
            limits_id = curr_profile.common_limits(
                list(set(common_limits_id_1).union(common_limits_id_2)))

            first_bed = True
            for j, (id1, id2) in enumerate(zip(limits_id, limits_id[1:])):
                bed = curr_profile.extract_bed(id1, id2)
                coord_int = bed.interp_coord_along_bed_auto(
                    self.lat_step, self.nb_pts_lat)

                if first_bed:
                    curr_profile.get_limit_by_id(id1)['id_pt'] = self.i_pt + 1
                else:
                    coord_int = coord_int[1:]

                if i == 0:
                    coord_int = rename_fields(coord_int, {'Xt': 'Xt_upstream'})
                    coord_int = append_fields(coord_int,
                                              'Xt_downstream',
                                              np.zeros(len(coord_int)),
                                              usemask=False)
                    self.add_points(coord_int, i, 0.0, j)
                else:
                    coord_int = rename_fields(coord_int,
                                              {'Xt': 'Xt_downstream'})
                    coord_int = append_fields(coord_int,
                                              'Xt_upstream',
                                              np.zeros(len(coord_int)),
                                              usemask=False)
                    self.add_points(coord_int, i - 1, 1.0, j)

                curr_profile.get_limit_by_id(id2)['id_pt'] = self.i_pt

                # Add new segments
                new_i_pt = np.arange(
                    curr_profile.get_limit_by_id(id1)['id_pt'],
                    curr_profile.get_limit_by_id(id2)['id_pt'] + 1)
                self.add_segments_from_node_list(new_i_pt)

                if first_bed:
                    first_bed = False