def delauney(self):
        segments = []
        combos = list(itertools.combinations(self.graph.nodes, 3))
        #print "combinations: ", len(combos)
        for a, b, c in combos:
            centre = self.triangle_circumcenter(a, b, c)

            distance2 = (Vector2(a.x, a.y) - centre).magnitude_squared()

            smaller_found = False
            for node in self.graph.nodes:
                if node in [a, b, c]:
                    continue

                if (Vector2(node.x, node.y) -
                        centre).magnitude_squared() < distance2:
                    smaller_found = True
                    break

            if not smaller_found:
                segments.extend(list(itertools.combinations([a, b, c], 2)))

        for segment in segments:
            order = sorted(segment, key=lambda node: node.x + node.y)
            segment = (order[0], order[1])

        segments = set(segments)

        return segments
예제 #2
0
    def __init__(self):
        graphics.Scene.__init__(self)
        self.segments = []

        # we should redo the boxes when window gets resized
        self.proximity_radius = 10
        self.proximities = LQProximityStore(Vector2(0, 0), Vector2(600, 400),
                                            self.proximity_radius)
        self.flock = []
        self.frame = 0

        self.connect("on-click", self.on_mouse_click)
        self.connect("on-enter-frame", self.on_enter_frame)
예제 #3
0
    def on_enter_frame(self, scene, context):
        c_graphics = graphics.Graphics(context)

        if len(self.flock) < 80:
            for i in range(2):
                self.flock.append(
                    Boid(Vector2(self.width / 2, self.height / 2), 2.0, 0.05))

        # main loop (i should rename this to something more obvious)
        c_graphics.set_line_style(width=0.8)
        c_graphics.set_color("#666")

        for boid in self.flock:
            neighbours = []
            if self.frame % 2 == 0:  #recalculate direction every second frame
                neighbours = self.proximities.find_neighbours(boid, 40)

            boid.run(neighbours)
            self.wrap(boid)
            self.proximities.update_position(boid)

            self.draw_boid(context, boid)

        self.frame += 1

        context.stroke()

        self.redraw()
예제 #4
0
 def update(self, context):
     self.current_frame +=1
     if self.current_frame == self.frames:
         self.current_frame = 0
         if self.boids:
             boid = self.boids.pop(0)
             boid.location = Vector2(self.location.x, self.location.y)
             self.move_on(boid)
예제 #5
0
    def update(self, context):
        if len(self.boids) == self.bucket_size:
            self.boids_out = list(self.boids)
            self.boids = []


        self.rotation_angle += 0.02

        if self.incremental_angle:
            nodes = len(self.boids) or 1
        else:
            nodes = self.bucket_size - 1

        angle_step = math.pi * 2 / nodes
        current_angle = 0

        i = 0

        points = []
        while i < (math.pi * 2):
            x = self.location.x + math.cos(self.rotation_angle + i) * self.radius
            y = self.location.y + math.sin(self.rotation_angle + i) * self.radius

            points.append(Vector2(x,y))
            i += angle_step



        context.stroke()

        for boid in self.boids:
            distance = None
            closest_point = None
            for point in points:
                point_distance = (boid.location - point).magnitude_squared()
                if not distance or point_distance < distance:
                    closest_point = point
                    distance = point_distance

            if closest_point:
                target = boid.seek(closest_point)
                #if target.magnitude_squared() < 1:
                #    boid.flight_angle = (self.location - boid.location).cross().heading()

                boid.acceleration *= 8
                points.remove(closest_point) # taken
            else:
                boid.velocity *= .9

        context.stroke()

        if self.boids_out:
            for boid in self.boids_out:
                self.move_on(boid)
                boid.acceleration = -(self.location - boid.location) * 2
                boid.flight_angle = 0

            self.boids_out = []
예제 #6
0
    def __init__(self):
        graphics.Scene.__init__(self)


        # we should redo the boxes when window gets resized
        box_size = 10
        self.proximities = LQProximityStore(Vector2(0,0), Vector2(600,400), box_size)

        self.waypoints = []
        self.waypoints = [QueueingWaypoint(100, 100, 70),
                          BucketWaypoint(500, 100, 10),
                          GrowWaypoint(500, 500, 10),
                          QueueingWaypoint(300, 500, 70),
                          BucketWaypoint(100, 500, 10),
                          GrowWaypoint(100, 300, 3),
                          ]

        for waypoint in self.waypoints:
            self.add_child(waypoint)

        # link them together
        for curr, next in zip(self.waypoints, self.waypoints[1:]):
            curr.next = next
            next.previous = curr

        self.waypoints[0].previous = self.waypoints[-1]
        self.waypoints[-1].next = self.waypoints[0]



        self.boids = [Boid(Vector2(100,100), 2.0) for i in range(15)]

        for i, boid in enumerate(self.boids):
            boid.target(self.waypoints[0])
            self.add_child(boid)

        self.mouse_node = None

        # some debug variables
        self.debug_radius = False
        self.debug_awareness = False

        self.connect("on-enter-frame", self.on_enter_frame)
예제 #7
0
 def on_click(*args):
     for centre in self.canvas.centres:
         if abs(centre) < 2000:
             point = Vector2(centre.x, centre.y)
             self.canvas.points.append(point)
             node = Node(point.x, point.y, point)
             self.canvas.nodes.append(node)
             self.canvas.add_child(node)
     self.canvas.centres = []
     self.canvas.redraw()
예제 #8
0
    def __init__(self, x, y):
        graphics.Sprite.__init__(self, x, y, draggable = True)

        self.graphics.set_color("#999")
        self.graphics.rectangle(-4, -4, 8, 8, 2)
        self.graphics.fill()

        self.connect("on-drag", self.on_drag)

        self.location = Vector2(x, y)
        self.debug = False
예제 #9
0
    def on_mouse_click(self, area, event, target):
        if not target:
            point = Vector2(event.x, event.y)
            self.points.append(point)

            node = Node(event.x, event.y, point)
            self.nodes.append(node)
            self.add_child(node)
            self.centres = []

            self.triangulate()

            self.redraw()
예제 #10
0
    def voronoi(self):
        segments = []
        centres = {}
        for a, b, c in itertools.combinations(self.nodes, 3):
            centre = self.triangle_circumcenter(a, b, c)

            distance2 = (Vector2(a.x, a.y) - centre).magnitude_squared()

            smaller_found = False
            for node in self.nodes:
                if node in [a, b, c]:
                    continue

                if (Vector2(node.x, node.y) -
                        centre).magnitude_squared() < distance2:
                    smaller_found = True
                    break

            if not smaller_found:
                order = sorted([a, b, c], key=lambda node: node.x + node.y)
                for a1, b1 in itertools.combinations(order, 2):
                    centres.setdefault((a1, b1), []).append(centre)

        #return centres for all points that share more than one
        #centres = set([c[0] for c in centres.values() if len(c) > 1])

        res = []
        for key in centres:
            if len(centres[key]) > 1:
                for node, node2 in zip(centres[key], centres[key][1:]):
                    res.append((node, node2))

                if len(centres[key]) > 2:
                    res.append((centres[key][-1], centres[key][0]))

        res = set(res)

        return res
예제 #11
0
    def on_enter_frame(self, scene, context):
        c_graphics = graphics.Graphics(context)
        c_graphics.set_line_style(width=0.5)
        c_graphics.set_color("#AA00FF")

        if len(self.flock) < 40:
            self.flock.append(Boid(Vector2(100, 100), 2.0, 0.05))

        for boid in self.flock:
            boid.run(self.flock, context)

        context.stroke()
        context.fill()
        self.redraw()
예제 #12
0
    def align(self, boids):
        sum = Vector2()
        in_zone = 0.0

        for boid, d in boids:
            if 0 < d < self.neighbour_distance:
                sum += boid.velocity
                in_zone += 1

        if in_zone:
            sum = sum / in_zone  # weight by neighbour count
            sum.limit(self.max_force)

        return sum
예제 #13
0
    def steer(self, target, slow_down):
        steer = Vector2()

        desired = target - self.location  # A vector pointing from the location to the target

        d = desired.magnitude()

        if d > 0:
            desired.normalize()

            # Two options for desired vector magnitude (1 -- based on distance, 2 -- maxspeed)
            if slow_down and d < 100:
                desired *= self.max_speed * (
                    d / 100.0)  # This damping is somewhat arbitrary
            else:
                desired *= self.max_speed

            steer = desired - self.velocity  # Steering = Desired minus Velocity
            steer.limit(self.max_force)  # Limit to maximum steering force
        else:
            steer = Vector2()

        return steer
예제 #14
0
    def triangle_circumcenter(self, a, b, c):
        """shockingly, the circumcenter math has been taken from wikipedia
           we move the triangle to 0,0 coordinates to simplify math"""

        p_a = Vector2(a.x, a.y)
        p_b = Vector2(b.x, b.y) - p_a
        p_c = Vector2(c.x, c.y) - p_a

        p_b2 = p_b.magnitude_squared()
        p_c2 = p_c.magnitude_squared()

        d = 2 * (p_b.x * p_c.y - p_b.y * p_c.x)

        if d < 0:
            d = min(d, EPSILON)
        else:
            d = max(d, EPSILON)

        centre_x = (p_c.y * p_b2 - p_b.y * p_c2) / d
        centre_y = (p_b.x * p_c2 - p_c.x * p_b2) / d

        centre = p_a + Vector2(centre_x, centre_y)
        return centre
예제 #15
0
    def __init__(self, location, max_speed = 2.0):
        graphics.Sprite.__init__(self, snap_to_pixel=False)

        self.visible = True
        self.radius = 3
        self.acceleration = Vector2()
        self.brake = Vector2()
        self.velocity = Vector2(random.random() * 2 - 1, random.random() * 2 - 1)
        self.location = location
        self.max_speed = max_speed
        self.max_force = 0.03
        self.positions = []
        self.message = None # a message that waypoint has set perhaps
        self.flight_angle = 0

        self.data = {}
        self.virus = None

        self.radio = self.radius * 5

        self.target_waypoint = None

        self.connect("on-render", self.on_render)
예제 #16
0
    def align(self, boids):
        neighbour_distance = 50.0
        sum = Vector2()
        in_zone = 0.0

        for boid in boids:
            d = (self.location - boid.location).magnitude()
            if 0 < d < neighbour_distance:
                sum += boid.velocity
                in_zone += 1

        if in_zone:
            sum = sum / in_zone  # weight by neighbour count
            sum.limit(self.max_force)

        return sum
예제 #17
0
    def separate(self, boids):
        sum = Vector2()
        in_zone = 0.0

        for boid, d in boids:
            if 0 < d < self.desired_separation:
                diff = self.location - boid.location
                diff.normalize()
                diff = diff / math.sqrt(d)  # Weight by distance
                sum += diff
                in_zone += 1

        if in_zone:
            sum = sum / in_zone

        return sum
예제 #18
0
    def steer(self, target, slow_down):
        desired = target - self.location  # A vector pointing from the location to the target

        d = desired.magnitude_squared()
        if d > 0:  # this means that we have a target
            desired.normalize()

            # Two options for desired vector magnitude (1 -- based on distance, 2 -- maxspeed)
            if slow_down and d > self.braking_distance:
                desired *= self.max_speed * d / self.braking_distance  # This damping is somewhat arbitrary
            else:
                desired *= self.max_speed

            steer = desired - self.velocity  # Steering = Desired minus Velocity
            steer.limit(self.max_force)  # Limit to maximum steering force
            return steer
        else:
            return Vector2()
예제 #19
0
    def update_position(self, w, h):
        distance = 0
        if self.target:
            distance = (self.target - self.location).magnitude_squared()

        if not self.target or self.prev_distance and distance > self.prev_distance:
            self.prev_distance = w * w + h * h
            self.target = Vector2(randint(0, w), randint(0, h))

        target = (self.target - self.location)

        self.acceleration = (target - self.velocity).normalize() * 2
        self.velocity += self.acceleration

        self.velocity.limit(20)

        self.prev_distance = distance

        self.location += self.velocity
예제 #20
0
    def separate(self, boids):
        desired_separation = 25.0
        sum = Vector2()
        in_zone = 0.0

        for boid in boids:
            d = (self.location - boid.location).magnitude()

            if 0 < d < desired_separation:
                diff = self.location - boid.location
                diff.normalize()
                diff = diff / d  # Weight by distance
                sum += diff
                in_zone += 1

        if in_zone:
            sum = sum / in_zone

        return sum
예제 #21
0
    def cohesion(self, boids):
        """ For the average location (i.e. center) of all nearby boids,
            calculate steering vector towards that location"""

        neighbour_distance = 50.0
        sum = Vector2()
        in_zone = 0.0

        for boid in boids:
            d = (self.location - boid.location).magnitude()

            if 0 < d < neighbour_distance:
                sum += boid.location
                in_zone += 1

        if in_zone:
            sum = sum / in_zone
            return self.steer(sum, False)

        return sum
예제 #22
0
    def cohesion(
        self,
        boids,
    ):
        """ For the average location (i.e. center) of all nearby boids,
            calculate steering vector towards that location"""

        sum = Vector2()
        in_zone = 0

        for boid, d in boids:
            if 0 < d < self.neighbour_distance:
                sum = sum + boid.location
                in_zone += 1

        if in_zone:
            sum = sum / float(in_zone)
            return self.steer(sum, True)

        return sum
예제 #23
0
    def separate(self, boids):
        sum = Vector2()
        in_zone = 0.0

        for boid, d in boids:
            if not boid.visible:
                continue

            if 0 < d < self.radius * 5 * self.radius * 5:
                diff = self.location - boid.location
                diff.normalize()
                diff = diff / math.sqrt(d)  # Weight by distance
                sum += diff
                in_zone += 1

        if in_zone:
            sum = sum / in_zone

        sum.limit(self.max_force)
        return sum
예제 #24
0
    def draw_tangent(self):
        tangent = self.tangent
        tangent.graphics.clear()

        tangent.graphics.set_line_style(width=0.5)

        band_radius = 30

        v1 = Vector2(self.circle1.x, self.circle1.y)
        v2 = Vector2(self.circle2.x, self.circle2.y)

        distance = abs(v1 - v2)

        tangent.graphics.set_color("#000")
        #tangent.graphics.move_to(v1.x, v1.y)
        #tangent.graphics.line_to(v2.x, v2.y)

        c = distance
        distance = 100

        a = distance + self.circle2.radius
        b = distance + self.circle1.radius

        orientation = (v2 - v1).heading()

        # errrm, well, basically the one is in the other
        if (b**2 + c**2 - a**2) / (2.0 * b * c) >= 1:
            tangent.graphics.arc(
                v1.x, v1.y,
                max(self.circle1.radius, self.circle2.radius) + band_radius, 0,
                math.pi * 2)
            tangent.graphics.stroke()
            return

        # we have to figure out the angle for the vector that is pointing
        # towards the point C (which will help as to draw that tangent)
        left_angle = math.acos((b**2 + c**2 - a**2) / (2.0 * b * c))
        arc_angle = math.acos((a**2 + b**2 - c**2) / (2.0 * a * b))

        # arc on the one side
        a1 = left_angle + orientation
        x, y = math.cos(a1) * b, math.sin(a1) * b

        v3_1 = Vector2(v1.x + x, v1.y + y)
        tangent.graphics.arc(v3_1.x, v3_1.y, distance - band_radius,
                             (v1 - v3_1).heading(), (v2 - v3_1).heading())
        tangent.graphics.stroke()

        # arc on the other side (could as well flip at the orientation axis, too dumb to do that though)
        a2 = -left_angle + orientation
        x, y = math.cos(a2) * b, math.sin(a2) * b
        v3_2 = Vector2(v1.x + x, v1.y + y)

        tangent.graphics.arc(v3_2.x, v3_2.y, distance - band_radius,
                             (v2 - v3_2).heading(), (v1 - v3_2).heading())
        tangent.graphics.stroke()

        # the rest of the circle
        tangent.graphics.arc(v1.x, v1.y, self.circle1.radius + band_radius,
                             (v3_1 - v1).heading(), (v3_2 - v1).heading())
        tangent.graphics.stroke()

        tangent.graphics.arc_negative(v2.x, v2.y,
                                      self.circle2.radius + band_radius,
                                      (v3_1 - v2).heading(),
                                      (v3_2 - v2).heading())
        tangent.graphics.stroke()
예제 #25
0
 def __init__(self):
     self.acceleration = Vector2()
     self.velocity = Vector2()
     self.location = Vector2(150, 150)
예제 #26
0
 def on_mouse_click(self, widget, event, target):
     self.flock.append(Boid(Vector2(event.x, event.y), 2.0, 0.05))
예제 #27
0
 def __init__(self, location, max_speed, max_force):
     self.acceleration = Vector2()
     self.velocity = Vector2(random() * 2 - 1, random() * 2 - 1)
     self.location = location
     self.max_speed = max_speed
     self.max_force = max_force