示例#1
0
    def add_terrain_point(self, position, normal, variant_index=-1):
        """Adds terrain point to node.

        :param position: position of terrain point
        :type position: tuple | Vector
        :param normal: normal of terrain point
        :type normal: tuple | Vector
        :param variant_index: index of variant from PIT file
        :type variant_index: int
        """

        self.ensure_variant(variant_index)

        # if no position and normal interrupt, also global count remains the same
        if position is None and normal is None:
            return

        # ordering with insertion by position where closest terrain point
        # shall be first in the list and farthest terrain point the last
        i = 0
        while i < len(self.__tp_per_variant[variant_index]):

            pos, normal = self.__tp_per_variant[variant_index][i]
            if get_distance(self.__position, position) < get_distance(
                    self.__position, pos):
                break

            i += 1

        self.__tp_per_variant[variant_index].insert(i, (position, normal))

        Node.__global_tp_counter += 1
示例#2
0
    def add_terrain_point(self, position, normal, variant_index=-1):
        """Adds terrain point to node.

        :param position: position of terrain point
        :type position: tuple | Vector
        :param normal: normal of terrain point
        :type normal: tuple | Vector
        :param variant_index: index of variant from PIT file
        :type variant_index: int
        """

        self.ensure_variant(variant_index)

        # if no position and normal interrupt, also global count remains the same
        if position is None and normal is None:
            return

        # ordering with insertion by position where closest terrain point
        # shall be first in the list and farthest terrain point the last
        i = 0
        while i < len(self.__tp_per_variant[variant_index]):

            pos, normal = self.__tp_per_variant[variant_index][i]
            if get_distance(self.__position, position) < get_distance(self.__position, pos):
                break

            i += 1

        self.__tp_per_variant[variant_index].insert(i, (position, normal))

        Node.__global_tp_counter += 1
示例#3
0
    def get_closest_point(self, point, iterations=_PL_consts.CURVE_CLOSEST_POINT_ITER):
        """Get's closest point on the curve to given point.

        NOTE: length of the curve must be already calculated.

        :param point: point to which closest curve point will be calculated
        :type point: mathutils.Vector
        :param iterations: number of iterastion for halving algorithm
        :type iterations: int
        :return: curve position coeficient of the closest point (0.0 - 1.0)
        :rtype: float
        """

        curve_p1, curve_t1 = self.get_start()
        curve_p2, curve_t2 = self.get_end()

        interval = (0, 0.5, 1)

        while iterations > 0:

            curr_p = _curve_utils.smooth_curve(curve_p1, curve_t1, curve_p2, curve_t2, interval[0])
            p1_distance = _math_utils.get_distance(curr_p, point)

            curr_p = _curve_utils.smooth_curve(curve_p1, curve_t1, curve_p2, curve_t2, interval[2])
            p3_distance = _math_utils.get_distance(curr_p, point)

            if p1_distance < p3_distance:
                interval = (interval[0], (interval[0] + interval[1]) / 2, interval[1])
            else:
                interval = (interval[1], (interval[1] + interval[2]) / 2, interval[2])

            iterations -= 1

        return interval[1]
示例#4
0
    def get_intersection_radius(curve1, curve2, curve1_pos_coef, curve2_pos_coef, curve1_direction=1, curve2_direction=1):
        """Get needed radius for reaching safe point when moving on curves in desired direction.
        In forst case full radius is returned which is the point where curve has no ancestors/children anymore.

        :param curve1: first curve
        :type curve1: io_scs_tools.exp.pip.curve.Curve
        :param curve2: second curve
        :type curve2: io_scs_tools.exp.pip.curve.Curve
        :param curve1_pos_coef: position coeficient of first curve for intersection point
        :type curve1_pos_coef: float
        :param curve2_pos_coef: position coeficient of second curve for intersection point
        :type curve2_pos_coef: float
        :param curve1_direction: first curve scaning direction (forward scaning: 1; backward scaning: -1)
        :type curve1_direction: int
        :param curve2_direction: second curve scaning direction (forward scaning: 1; backward scaning: -1)
        :type curve2_direction: int
        :return: radius; 0 if curves have same fork/joint, depending on their direction
        :rtype: int
        """

        steps = (0.1, 0.1)  # size of the step on curve in each iteration

        curr_c = [curve1, curve2]  # current curves
        curr_pos = [curr_c[0].get_length() * curve1_pos_coef, curr_c[1].get_length() * curve2_pos_coef]  # current curves positions

        # first point and tangent vectors for both curves
        curve_p1 = [Vector(), Vector()]
        curve_t1 = [Vector(), Vector()]

        # second point and tangent vectors for both curves
        curve_p2 = [Vector(), Vector()]
        curve_t2 = [Vector(), Vector()]

        curve_directions = (curve1_direction, curve2_direction)  # stepping directions for both curves

        # current radius and distance between curves
        radius = 0
        distance = 0

        # advance until distance is meet
        while distance <= _PL_consts.SAFE_DISTANCE:

            # get data for both curves
            for i in range(2):

                # go to next position on curve
                old_curr_pos = curr_pos[i]
                if curve_directions[i] == 1:
                    curr_pos[i] = min(curr_pos[i] + steps[i], curr_c[i].get_length())
                else:
                    curr_pos[i] = max(0, curr_pos[i] - steps[i])

                # if we reached end of the curve, try to get on next/previous one or exit
                if old_curr_pos == curr_pos[i]:

                    # step out if no next/previous possible curve
                    if len(curr_c[i].get_next_prev_curves(curve_directions[i] == 1)) < 1:
                        return radius

                    curr_c[i] = curr_c[i].get_next_prev_curves(curve_directions[i] == 1)[0]

                    if curve_directions[i] == 1:
                        curr_pos[i] = min(steps[i], curr_c[i].get_length())
                    else:
                        curr_pos[i] = max(0, curr_c[i].get_length() - steps[i])

                curve_p1[i], curve_t1[i] = curr_c[i].get_start()
                curve_p2[i], curve_t2[i] = curr_c[i].get_end()

            # extra check if curves have same fork/joint;
            # then calculated radius has to be ignored therefore return zero radius
            next_prev_c1 = curr_c[0].get_next_prev_curves(curve_directions[i] == 1)
            next_prev_c2 = curr_c[1].get_next_prev_curves(curve_directions[i] == 1)

            if len(next_prev_c1) == 1 and len(next_prev_c2) == 1:
                if next_prev_c1[0] == next_prev_c2[0]:
                    return 0

            # if everything is okay finally calculate curve points, distance and radius
            curr_p1 = _curve_utils.smooth_curve(curve_p1[0], curve_t1[0], curve_p2[0], curve_t2[0], curr_pos[0] / curr_c[0].get_length())
            curr_p2 = _curve_utils.smooth_curve(curve_p1[1], curve_t1[1], curve_p2[1], curve_t2[1], curr_pos[1] / curr_c[1].get_length())

            distance = _math_utils.get_distance(curr_p1, curr_p2)
            radius += steps[0]

        return radius
示例#5
0
    def get_intersection_radius(curve1,
                                curve2,
                                curve1_pos_coef,
                                curve2_pos_coef,
                                curve1_direction=1,
                                curve2_direction=1):
        """Get needed radius for reaching safe point when moving on curves in desired direction.
        In forst case full radius is returned which is the point where curve has no ancestors/children anymore.

        :param curve1: first curve
        :type curve1: io_scs_tools.exp.pip.curve.Curve
        :param curve2: second curve
        :type curve2: io_scs_tools.exp.pip.curve.Curve
        :param curve1_pos_coef: position coeficient of first curve for intersection point
        :type curve1_pos_coef: float
        :param curve2_pos_coef: position coeficient of second curve for intersection point
        :type curve2_pos_coef: float
        :param curve1_direction: first curve scaning direction (forward scaning: 1; backward scaning: -1)
        :type curve1_direction: int
        :param curve2_direction: second curve scaning direction (forward scaning: 1; backward scaning: -1)
        :type curve2_direction: int
        :return: radius; 0 if curves have same fork/joint, depending on their direction
        :rtype: int
        """

        steps = (0.1, 0.1)  # size of the step on curve in each iteration

        curr_c = [curve1, curve2]  # current curves
        curr_pos = [
            curr_c[0].get_length() * curve1_pos_coef,
            curr_c[1].get_length() * curve2_pos_coef
        ]  # current curves positions

        # first point and tangent vectors for both curves
        curve_p1 = [Vector(), Vector()]
        curve_t1 = [Vector(), Vector()]

        # second point and tangent vectors for both curves
        curve_p2 = [Vector(), Vector()]
        curve_t2 = [Vector(), Vector()]

        curve_directions = (curve1_direction, curve2_direction
                            )  # stepping directions for both curves

        # current radius and distance between curves
        radius = 0
        distance = 0

        # advance until distance is meet
        while distance <= _PL_consts.SAFE_DISTANCE:

            # get data for both curves
            for i in range(2):

                # go to next position on curve
                old_curr_pos = curr_pos[i]
                if curve_directions[i] == 1:
                    curr_pos[i] = min(curr_pos[i] + steps[i],
                                      curr_c[i].get_length())
                else:
                    curr_pos[i] = max(0, curr_pos[i] - steps[i])

                # if we reached end of the curve, try to get on next/previous one or exit
                if old_curr_pos == curr_pos[i]:

                    # step out if no next/previous possible curve
                    if len(curr_c[i].get_next_prev_curves(
                            curve_directions[i] == 1)) < 1:
                        return radius

                    curr_c[i] = curr_c[i].get_next_prev_curves(
                        curve_directions[i] == 1)[0]

                    if curve_directions[i] == 1:
                        curr_pos[i] = min(steps[i], curr_c[i].get_length())
                    else:
                        curr_pos[i] = max(0, curr_c[i].get_length() - steps[i])

                curve_p1[i], curve_t1[i] = curr_c[i].get_start()
                curve_p2[i], curve_t2[i] = curr_c[i].get_end()

            # extra check if curves have same fork/joint;
            # then calculated radius has to be ignored therefore return zero radius
            next_prev_c1 = curr_c[0].get_next_prev_curves(
                curve_directions[i] == 1)
            next_prev_c2 = curr_c[1].get_next_prev_curves(
                curve_directions[i] == 1)

            if len(next_prev_c1) == 1 and len(next_prev_c2) == 1:
                if next_prev_c1[0] == next_prev_c2[0]:
                    return 0

            # if everything is okay finally calculate curve points, distance and radius
            curr_p1 = _curve_utils.smooth_curve(
                curve_p1[0], curve_t1[0], curve_p2[0], curve_t2[0],
                curr_pos[0] / curr_c[0].get_length())
            curr_p2 = _curve_utils.smooth_curve(
                curve_p1[1], curve_t1[1], curve_p2[1], curve_t2[1],
                curr_pos[1] / curr_c[1].get_length())

            distance = _math_utils.get_distance(curr_p1, curr_p2)
            radius += steps[0]

        return radius
示例#6
0
    def add_terrain_point(self, position, normal, variant_index=-1):
        """Adds terrain point to node.

        :param position: position of terrain point
        :type position: tuple | Vector
        :param normal: normal of terrain point
        :type normal: tuple | Vector
        :param variant_index: index of variant from PIT file
        :type variant_index: int
        """

        self.ensure_variant(variant_index)

        # if no position and normal interrupt, also global count remains the same
        if position is None and normal is None:
            return

        # find nearest existing terrain point
        i = 0
        smallest_dist = float("inf")
        smallest_dist_i = 0
        tp_count = len(self.__tp_per_variant[variant_index])
        while i < tp_count:

            pos, normal = self.__tp_per_variant[variant_index][i]
            curr_distance = get_distance(position, pos)
            if curr_distance < smallest_dist:
                smallest_dist = curr_distance
                smallest_dist_i = i

            i += 1

        # depending on distance to closest, previous and next terrain point insert it so that points are sorted already
        if tp_count < 2:  # no terrain points yet or just one just put it at the end

            insert_i = tp_count

        elif smallest_dist_i == 0:  # the nearest is first just put it at start or behind the first one

            next_tp = self.__tp_per_variant[variant_index][smallest_dist_i + 1]
            closest_tp = self.__tp_per_variant[variant_index][smallest_dist_i]

            if get_distance(next_tp[0], position) < get_distance(closest_tp[0], next_tp[0]):
                insert_i = 1
            else:
                insert_i = 0

        elif smallest_dist_i == tp_count - 1:  # last is the nearest put it at the back or before last one

            prev_tp = self.__tp_per_variant[variant_index][smallest_dist_i - 1]
            closest_tp = self.__tp_per_variant[variant_index][smallest_dist_i]

            if get_distance(prev_tp[0], position) < get_distance(closest_tp[0], prev_tp[0]):
                insert_i = smallest_dist_i
            else:
                insert_i = smallest_dist_i + 1

        else:

            # now this is a tricky one: once nearest point is in the middle.
            # With that in mind take previous and next existing points and calculate to which new point is closer.
            # After that also compare distance of next/previous to closest which gives us final answer
            # either point should be inserted before or after closest point.

            prev_tp = self.__tp_per_variant[variant_index][smallest_dist_i - 1]
            closest_tp = self.__tp_per_variant[variant_index][smallest_dist_i]
            next_tp = self.__tp_per_variant[variant_index][smallest_dist_i + 1]

            prev_tp_dist = get_distance(prev_tp[0], position)
            next_tp_dist = get_distance(next_tp[0], position)

            if next_tp_dist < prev_tp_dist and next_tp_dist < get_distance(closest_tp[0], next_tp[0]):
                insert_i = smallest_dist_i + 1
            elif prev_tp_dist > get_distance(closest_tp[0], prev_tp[0]):
                insert_i = smallest_dist_i + 1
            else:
                insert_i = smallest_dist_i

        self.__tp_per_variant[variant_index].insert(insert_i, (position, normal))

        Node.__global_tp_counter += 1