Esempio n. 1
0
 def advance_positions(self, lerp_value, eps=1e-2):
     line_segment = LineSegment(self.position, self.target_position)
     if line_segment.Length() < eps:
         self.position = self.target_position
     else:
         self.position = line_segment.Lerp(lerp_value)
     for child in self.child_list:
         child.advance_positions(lerp_value)
Esempio n. 2
0
 def Interpolate(self, value):
     from math2d_line_segment import LineSegment
     point_list = [point for point in self.point_list]
     while len(point_list) > 1:
         new_point_list = []
         for i in range(len(point_list) - 1):
             line_segment = LineSegment(point_list[i], point_list[i + 1])
             new_point_list.append(line_segment.Lerp(value))
         point_list = new_point_list
     return point_list[0]
Esempio n. 3
0
 def Interpolate(self, value, length=None):
     from math2d_line_segment import LineSegment
     if length is None:
         length = self.Length()
     distance = length * value
     if distance < 0.0 or distance > length:
         raise Exception('Invalid parameter value.')
     i = 0
     point = None
     while distance >= 0.0:
         point = self.point_list[i]
         line_segment = LineSegment(self.point_list[i],
                                    self.point_list[i + 1])
         segment_length = line_segment.Lenght()
         if segment_length < distance:
             distance -= segment_length
             i += 1
         else:
             lerp_value = segment_length / distance
             point = line_segment.Lerp(lerp_value)
             break
     return point
Esempio n. 4
0
    def GenerateSymmetries(self):
        reflection_list = []
        center_reflection_list = []
        center = self.AveragePoint()
        for i in range(len(self.point_list)):
            for j in range(i + 1, len(self.point_list)):
                line_segment = LineSegment(self.point_list[i],
                                           self.point_list[j])
                mid_point = line_segment.Lerp(0.5)
                normal = line_segment.Direction().Normalized().RotatedCCW90()
                reflection = AffineTransform()
                reflection.Reflection(mid_point, normal)
                center_reflected = reflection.Transform(center)
                if center_reflected.IsPoint(center):
                    center_reflection_list.append({
                        'reflection': reflection,
                        'normal': normal
                    })
                is_symmetry, total_error = self.IsSymmetry(reflection)
                if is_symmetry:
                    new_entry = {
                        'reflection': reflection,
                        'total_error': total_error,
                        'center': mid_point,
                        'normal': normal
                    }
                    for k, entry in enumerate(reflection_list):
                        if entry['reflection'].IsTransform(reflection):
                            if entry['total_error'] > total_error:
                                reflection_list[k] = new_entry
                            break
                    else:
                        reflection_list.append(new_entry)

        # Rotations are just double-reflections.  We return here a CCW rotational symmetry that generates
        # the sub-group of rotational symmetries of the overall group of symmetries of the cloud.  We also
        # return its inverse for convenience.  Of course, not all point clouds have any rotational symmetry.
        epsilon = 1e-7

        def SortKey(entry):
            if entry['normal'].y <= -epsilon:
                entry['normal'] = -entry['normal']
            angle = Vector(1.0, 0.0).SignedAngleBetween(entry['normal'])
            if angle < 0.0:
                angle += 2.0 * math.pi
            return angle

        ccw_rotation = None
        cw_rotation = None
        if len(reflection_list) >= 2:
            reflection_list.sort(key=SortKey)
            # Any 2 consecutive axes should be as close in angle between each other as possible.
            reflection_a = reflection_list[0]['reflection']
            reflection_b = reflection_list[1]['reflection']
            ccw_rotation = reflection_a * reflection_b
            cw_rotation = reflection_b * reflection_a
            # The following are just sanity checks.
            is_symmetry, total_error = self.IsSymmetry(ccw_rotation)
            if not is_symmetry:
                raise Exception('Failed to generate CCW rotational symmetry.')
            is_symmetry, total_error = self.IsSymmetry(cw_rotation)
            if not is_symmetry:
                raise Exception('Failed to generate CW rotational symmetry.')
        elif len(reflection_list) == 1:
            # If we found exactly one reflection, then I believe the cloud has no rotational symmetry.
            # Note that the identity transform is not considered a symmetry.
            pass
        else:
            # If we found no reflective symmetry, the cloud may still have rotational symmetry.
            # Furthermore, if it does, it must rotate about the average point.  I think there is a way
            # to prove this using strong induction.  Note that the statement holds for all point-clouds
            # made from vertices taken from regular polygons.  Now for any given point-cloud with any
            # given rotational symmetry, consider 1 point of that cloud.  Removing that point along
            # with the minimum number of other points necessary to keep the given rotational symmetry,
            # we must remove points making up a regular polygon's vertices.  By inductive hypothesis,
            # the remaining cloud has its average point at the center of the rotational symmetry.  Now
            # see that adding the removed points back does not change the average point of the cloud.
            # Is it true that every line of symmetry of the cloud contains the average point?  I believe
            # the answer is yes.  Take any point-cloud with a reflective symmetry and consider all but
            # 2 of its points that reflect into one another along that symmetry.  If the cloud were just
            # these 2 points, then the average point is on the line of symmetry.  Now notice that as you
            # add back points by pairs, each pair reflecting into one another, the average point of the
            # cloud remains on the line of symmetry.
            center_reflection_list.sort(key=SortKey)
            found = False
            for i in range(len(center_reflection_list)):
                for j in range(i + 1, len(center_reflection_list)):
                    ccw_rotation = center_reflection_list[i][
                        'reflection'] * center_reflection_list[j]['reflection']
                    is_symmetry, total_error = self.IsSymmetry(ccw_rotation)
                    if is_symmetry:
                        # By stopping at the first one we find, we should be minimizing the angle of rotation.
                        found = True
                        break
                if found:
                    break
            if found:
                cw_rotation = ccw_rotation.Inverted()
            else:
                ccw_rotation = None

        return reflection_list, ccw_rotation, cw_rotation