class Wanderer:
    def __init__(self, car, radius):

        self.car = car
        self.predict = Pvector(self.car.location.x, self.car.location.y)
        self.radius = radius

    def generate_target(self):

        if self.car.location.x < 0 or self.car.location.x > 800:
            self.car.velocity.x *= -1
        if self.car.location.y < 0 or self.car.location.y > 800:
            self.car.velocity.y *= -1
        self.predict = Pvector(self.car.location.x, self.car.location.y)
        self.predict.add(self.car.velocity)
        theta = uniform(self.car.velocity.heading() - np.pi / 2,
                        self.car.velocity.heading() + np.pi / 2)
        randvec = Pvector(np.cos(theta), np.sin(theta))
        randvec.mult(self.radius)
        self.predict.add(randvec)

    def display(self):

        self.generate_target()
        self.car.seek(self.predict)
        self.car.update()
        self.car.display()
def get_normal(a,b,v):
    global points
    predict=v.velocity.get()
    predict.setMag(50)
    predict.add(v.location)
    predict.sub(a)
    alongpath=Pvector(b.x-a.x,b.y-a.y)
    alongpath.norm()
    mag=predict.dot(alongpath)
    alongpath.mult(mag)
    alongpath.add(a)
    if  points.points[-1].x>points.points[0].x:
        if alongpath.x>b.x or alongpath.x<a.x:
            alongpath=b.get()
    else:
        if alongpath.x<b.x or alongpath.x>a.x:
            alongpath=b.get()
    return alongpath
 def seperate(self,others):
     sum=Pvector(0,0)
     count=0
     for v in others:
         loc=self.location.get()
         loc.sub(v.location)
         d=loc.magnitude()
         if d>0 and d<50:
             loc.mult(1/d)
             sum.add(loc)
             count=count+1
     if count!=0:    
         sum.mult(1/count)
         sum.norm()
         sum.mult(self.maxspeed)
         sum.sub(self.velocity)
         sum.limit(self.maxforce)
     return sum
def draw():
    global points,vehicles
    #gf.record()
    for v in vehicles:
        worldRecord=100000
        bestPath=None
        if points.points[0].x<points.points[-1].x:    
            if v.location.x>points.points[-1].x:
                v.location.x=points.points[0].x
                v.location.y=points.points[0].y+(v.location.y-points.points[-1].y)
        else:
            if v.location.x<points.points[-1].x:
                v.location.x=points.points[0].x
                v.location.y=points.points[0].y+(v.location.y-points.points[-1].y)
        for i in range(len(points.points)-1):
            a=points.points[i].get()
            b=points.points[i+1].get()
            if points.points[0].x<points.points[-1].x:    
                if b.x<v.location.x:
                    continue
            else:
                if v.location.x<b.x:
                    continue   
            norm=get_normal(a,b,v)
            dist=get_distance(norm.get(),v.location)
            if dist<worldRecord:
                worldRecord=dist
                bestNorm=norm
                bestPath=Pvector(b.x-a.x,b.y-a.y)
        bestPath.setMag(50)
        if worldRecord>50:
            bestNorm.add(bestPath)
            seek=v.seek(bestNorm)
        else:
            bestPath.add(v.location)
            seek=v.seek(bestPath)
        seperate=v.seperate(vehicles)
        seperate.mult(0.8)
        v.applyForce(seek)
        v.applyForce(seperate)
        v.update()
        v.display()
    background(255)
    points.display()
class vehicle:

    def __init__(self,location=(400,400),velocity=(0,0),acceleration=(0,0),maxspeed=10,maxforce=3,field=None): # add field for field followers
        self.location=Pvector(location[0],location[1])
        self.velocity=Pvector(velocity[0],velocity[1])
        self.acceleration=Pvector(acceleration[0],acceleration[1])
        self.maxspeed=maxspeed
        self.maxforce=maxforce
        self.radius=8
        self.field=field
    def seek(self,target):
        desired=Pvector(target.x,target.y)
        desired.sub(self.location)        
        mag=desired.magnitude()
        if mag<100:
            setmag=mag*self.maxspeed/100
            desired.setMag(setmag)
        else:
            desired.setMag(self.maxspeed)
        desired.sub(self.velocity)
        desired.limit(self.maxforce)
        return desired
    def seperate(self,others):
        sum=Pvector(0,0)
        count=0
        for v in others:
            loc=self.location.get()
            loc.sub(v.location)
            d=loc.magnitude()
            if d>0 and d<50:
                loc.mult(1/d)
                sum.add(loc)
                count=count+1
        if count!=0:    
            sum.mult(1/count)
            sum.norm()
            sum.mult(self.maxspeed)
            sum.sub(self.velocity)
            sum.limit(self.maxforce)
        return sum
    def seek_flow(self):
        if self.location.x<0:
            self.location.x=799
        if self.location.x>799:
            self.location.x=0
        if self.location.y<0:
            self.location.y=799
        if self.location.y>799:
            self.location.y=0
        desired=Pvector(self.lookup(self.location).x,self.lookup(self.location).y)
        desired.setMag(self.maxspeed)
        desired.sub(self.velocity)
        desired.limit(self.maxforce)
        self.applyForce(desired)
    def lookup(self,location):
        k=800/self.field.shape[0]
        return self.field[m.floor(location.x/k)][m.floor(location.y/k)]
    def update(self):
        self.velocity.add(self.acceleration)
        self.velocity.limit(self.maxspeed)
        self.location.add(self.velocity)
        self.acceleration.mult(0)
    def applyForce(self,force):
        self.acceleration.add(force)
    def display(self):
        theta=self.velocity.heading()+m.pi/2
        stroke_weight(1)
        stroke(0)
        fill(0)
        push_matrix()
        translate(self.location.x,self.location.y)
        rotate(theta)
        begin_shape()
        vertex(-self.radius,2*self.radius)
        vertex(0,-2*self.radius)
        vertex(self.radius,2*self.radius)
        end_shape(CLOSE)
        pop_matrix()