Esempio n. 1
0
def update_dual_roaming(j,n_fixed,n_roam,j_prime):
    jp_seg=g_prime.nodes['x'][g_prime.edges['nodes'][j_prime]]
    jp_vec=jp_seg[1,:] - jp_seg[0,:]
    jp_vec=jp_vec / utils.mag(jp_vec)
    vec_perp=np.array([jp_vec[1],-jp_vec[0]])

    f_roam=lambda d: g_dual.nodes['x'][n_fixed] + d*vec_perp
    d0=np.dot(vec_perp,g_dual.nodes['x'][n_roam]-g_dual.nodes['x'][n_fixed])
    if d0<0: # clarify orientation
        d0*=-1
        vec_perp*=-1

    # rather than maintaining length of the original edge, better
    # to relationship with prime's nodes.
    # I think this equivalent to making the length double the
    # distance from n_fixed to the edge j_prime (or distance
    # to one of j_prime's nodes, projected onto vec_perp
    if 1:
        # preserve prime's nodes
        delta=jp_seg[0,:] - g_dual.nodes['x'][n_fixed]
        d_target=2*np.dot(delta,vec_perp)
        new_roam=f_roam(d_target)
    else:
        # preserves length of the edge:
        new_roam=f_roam(d0)

    # just move it halfway - seems like going all the way causes
    # oscillations
    new_roam=0.5*(new_roam+g_dual.nodes['x'][n_roam])
    g_dual.modify_node(n_roam,x=new_roam)
Esempio n. 2
0
def link_cost_angle(g,j):
    vc=g.cells_center()

    c1,c2=g.edges['cells'][j]
    n1,n2=g.edges['nodes'][j]

    assert c1>=0
    assert c2>=0

    vec_norm=vc[c2]-vc[c1]
    vec_tan =g.nodes['x'][n1]- g.nodes['x'][n2]

    vec_norm=vec_norm/utils.mag(vec_norm)
    vec_tan =vec_tan/utils.mag(vec_tan)

    parallel=(vec_norm*vec_tan).sum()
    return np.abs(parallel) # |cos(theta)|
Esempio n. 3
0
    def get_output_vector(self, game_tick_packet):
        s = EasyGameState(game_tick_packet, self.team, self.index)
        speed = mag(s.car_vel)
        turn_rate = game_tick_packet.gamecars[
            self.index].AngularVelocity.Z  # rad/s
        turn_radius = speed / max(turn_rate, 0.001)

        if self.start_time is None:
            self.start_time = s.time
        time_elapsed = s.time - self.start_time
        desired_speed = 10 + time_elapsed * 100

        too_slow = desired_speed > speed
        should_boost = desired_speed > 1000 and too_slow
        pedal = too_slow
        if desired_speed < 500: pedal *= 0.5

        trace(speed)
        # trace(turn_rate)
        trace(turn_radius)
        # trace(desired_speed)
        trace(turn_radius - estimate_turn_radius(speed))

        output_vector = [
            pedal,  # fThrottle
            1,  # fSteer
            0,  # fPitch
            0,  # fYaw
            0,  # fRoll
            0,  # bJump
            should_boost,  # bBoost
            0,  # bHandbrake
        ]

        if not controller.hat_toggle_west:
            if self.measurements:
                print('TADA:')
                print(repr(self.measurements))
            output_vector = (
                round(controller.fThrottle),
                round(controller.fSteer),
                round(controller.fPitch),
                round(controller.fYaw),
                round(controller.fRoll),
                round(controller.bJump),
                round(controller.bBoost),
                round(controller.bHandbrake),
            )
            self.start_time = None
            self.measurements = []
        else:
            # self.start_time = s.time
            self.measurements.append((desired_speed, turn_radius))

        return sanitize_output_vector(output_vector)
Esempio n. 4
0
def cell_edges_signed_distance(g,c):
    vc=g.cells_center()[c]
    nodes=g.cell_to_nodes(c)
    L=np.sqrt(g.cells_area()[c])
    dists=[]
    for a,b in utils.circular_pairs(g.nodes['x'][nodes]):
        ab=b-a
        ab/=utils.mag(ab)
        norm=[-ab[1],ab[0]]
        c_ab=np.dot(vc-a,norm)
        dists.append( c_ab/L )
    return np.array(dists)
Esempio n. 5
0
def nudge_dual_to_constrained(dual_c,prime_n):
    dual_ns=g_dual.cell_to_nodes(dual_c)
    center=g_prime.nodes['x'][prime_n]

    vecs=g_dual.nodes['x'][dual_ns] - center
    radii=utils.mag(vecs)
    mean_r=radii.mean()

    for n,rad,vec in zip(dual_ns,radii,vecs):
        print n,rad
        new_x=center+vec*mean_r/rad
        g_dual.nodes['x'][n]=new_x
    g_dual.cells_center(refresh=True,mode='sequential')
Esempio n. 6
0
    def cost(x):
        g_mod=modified_node_grid(g,n,x)
        # This one sucked:
        if 0:
            cost=np.sum([link_cost(g_mod,j)
                         for j in links])

        # mimic report_orthogonality()
        cost=0
        if 1:
            nsi=4 # quads only right now...
            centers=g_mod.cells_center(mode='sequential')
            # this is somehow making the mean and max circumcenter error larger!
            offsets = g_mod.nodes['x'][g_mod.cells['nodes'][cells,:nsi]] - centers[cells,None,:]
            dists = utils.mag(offsets)

            # maybe lets small cells take over too much
            # cost += np.mean( np.std(dists,axis=1) / np.mean(dists,axis=1) )
            # different, but not much better
            # cost += np.mean( np.std(dists,axis=1) )
            base_cost=np.max( np.std(dists,axis=1)  )
            if verbose:
                print "   Circum. cost: %f"%(base_cost)
            cost += base_cost
            
        if w_area>0 and len(links):
            # this helps a bit, but sometimes getting good areas
            # means distorting the shapes
            A=g_mod.cells_area()
            pairs=A[ g.edges['cells'][links] ]
            diffs=(pairs[:,0]-pairs[:,1])/pairs.mean(axis=1)
            area_cost=w_area*np.sum(diffs**2)
            if verbose:
                print "   Area cost: %f"%area_cost
            cost+=area_cost
        if w_length>0:
            # if it's not too far off, this makes it look nicer at
            # the expense of circ. errors
            l_cost=0
            g_mod.update_cell_edges()
            lengths=g_mod.edges_length()
            for c in cells:
                e=g_mod.cell_to_edges(c)
                if 0:
                    # maybe that's too much leeway, and
                    # the user should have to specify aspect ratios
                    if len(e)==4:
                        a,b,c,d=lengths[e]
                        l_cost+=( ((a-c)/(a+c))**2 +
                                  ((b-d)/(b+d))**2 )
                else:
                    lmean=lengths.mean()
                    l_cost+= np.sum( (lengths-lmean)**2 )
            if verbose:
                print "   Length cost: %f"%( w_length*l_cost )
            cost+=w_length*l_cost
        if w_angle>0:
            # interior angle of cells
            deltas=np.diff(g_mod.nodes['x'][triples],axis=1)
            angles=np.diff( np.arctan2( deltas[:,:,1], deltas[:,:,0] ),axis=1) % (2*np.pi) * 180/np.pi
            angle_cost=w_angle*np.sum( (angles-90)**2 )
            if verbose:
                print "   Angle cost: %f"%angle_cost
            cost+=angle_cost
        if w_cangle>0:
            cangle_cost=0
            for c in cells:
                nodes=g.cell_to_nodes(c)
                deltas=g_mod.nodes['x'][nodes] - g_mod.cells_center()[c]
                angles=np.arctan2(deltas[:,1],deltas[:,0]) * 180/np.pi
                cds=utils.cdiff(angles) % 360.
                cangle_cost+=np.sum( (cds-90)**4 )
            if verbose:
                print "   CAngle cost: %f"%( w_cangle*cangle_cost )
            cost+=w_cangle*cangle_cost
                
        return cost
Esempio n. 7
0
    def get_output_vector(self, game_tick_packet):
        my_car = game_tick_packet.gamecars[self.index]

        player_pos = np.array([
            my_car.Location.X,
            my_car.Location.Y,
        ])
        player_vel = np.array([
            my_car.Velocity.X,
            my_car.Velocity.Y,
        ])
        pitch = URotationToRadians * float(my_car.Rotation.Pitch)
        yaw = URotationToRadians * float(my_car.Rotation.Yaw)
        player_facing_dir = np.array([
            math.cos(pitch) * math.cos(yaw),
            math.cos(pitch) * math.sin(yaw)
        ])
        player_right = -clockwise90degrees(player_facing_dir)

        # score should be positive if going counter clockwise
        target_pos = np.array([0, 0])
        circle_outward = player_pos - target_pos
        circle_outward_dir = normalize(circle_outward)
        circle_forward_dir = clockwise90degrees(circle_outward_dir)
        drifting_score = player_vel.dot(player_right)
        going_around_target_score = circle_forward_dir.dot(player_vel)
        score = going_around_target_score * drifting_score

        steer = controller.fSteer
        steer = round(steer)
        # trace(drifting_score)
        # trace(-steer)
        # trace(player_pos)

        circle_facing_dir = np.array([
            player_facing_dir.dot(circle_outward_dir),
            player_facing_dir.dot(circle_forward_dir),
        ])

        # trace(player_facing_dir.dot(circle_forward_dir))
        # trace(player_facing_dir.dot(circle_outward_dir))
        circle_facing_angle = vec2angle(circle_facing_dir)  # 0=outward, tau/4=forward
        # trace(circle_facing_angle)

        boost = 1

        outward_dist = mag(circle_outward)
        steer_dist_inner = 400 if boost else 0
        steer_dist_outer = 2500 if boost else 1500
        should_hard_steer = 1-clamp01((outward_dist - steer_dist_inner) / (steer_dist_outer - steer_dist_inner))
        # trace(outward_dist)
        # trace(should_hard_steer)
        # trace(outward_dist-steer_dist_inner)
        desired_angle = lerp(tau*.37, tau*.51, should_hard_steer)

        if controller.hat_toggle_north:
            return [
                controller.fThrottle,
                steer,
                controller.fPitch,
                controller.fYaw,
                controller.fRoll,
                controller.bJump,
                controller.bBoost,
                controller.bHandbrake,
            ]



        steer = closest180(circle_facing_angle - desired_angle) * 4
        turning_rate = my_car.AngularVelocity.Z
        PID_vel_thingy = 0.8 if boost else 0.5
        steer -= PID_vel_thingy * turning_rate  # PID loop, essentially

        return [
            1.0,    # fThrottle
            clamp11(steer),   # fSteer
            0.0,    # fPitch
            0.0,    # fYaw
            0.0,    # fRoll
            0,      # bJump
            boost,      # bBoost
            1       # bHandbrake
        ]
Esempio n. 8
0
def createPoints():
    ## ROUNDED OBTUSE CORNERS
    # Loop over intersections
    # On inside of turn, find where entering/exiting lines meet, use point
    # On outside of turn...
    # * stop at same length of acute line
    # * next point is intersection normal, at dist of line width
    # * subdivide if desired
    eastPoints = list()
    eastConstructionLines = list()
    westPoints = list()
    westConstructionLines = list()
    for i in range(len(lineVecs)):
        #print("\ni = %d" % i)
        #print("ith Point: %f,%f" % (points[i][0], points[i][1]))
        prever = i - 2
        prev = i - 1
        current = i
        v1 = utils.normalize(lineVecs[prever])
        v2 = utils.normalize(lineVecs[prev])
        position = v1[0] * v2[1] - v1[1] * v2[0]
        if (position == 0):
            print("i=%d, straight ahead" % prever)
            # ignore points here... let prev vector dictate them
            continue
        elif (position > 0):
            # Left turn, west border is acute

            p1, p2, p3, p4 = utils.calcParallelLinePoints(halfLineWidth,
                                                          points[prever],
                                                          points[prev],
                                                          points[current],
                                                          eastSide=False)

            ## Calculate WEST acute points
            line1Norm = (lineNormals[prever][0] * halfLineWidth,
                         lineNormals[prever][1] * halfLineWidth)
            # wX1 = points[prever][0] + line1Norm[0]
            # wY1 = points[prever][1] + line1Norm[1]
            # # Vector from current point, into intersection
            # v1 = (points[prev][0]-points[prever][0], points[prev][1]-points[prever][1])
            # # Point on line parallel to line leaving intersection point
            line2Norm = (lineNormals[prev][0] * halfLineWidth,
                         lineNormals[prev][1] * halfLineWidth)
            # wX2 = points[current][0] + line2Norm[0]
            # wY2 = points[current][1] + line2Norm[1]
            # # Vector from point after intersection, pointing back into it
            # v2 = (points[prev][0]-points[current][0], points[prev][1]-points[current][1])
            # # Gives
            # p1 = (wX1, wY1)
            # p2 = (wX1+v1[0], wY1+v1[1])
            # # and
            # p3 = (wX2, wY2)
            # p4 = (wX2+v2[0], wY2+v2[1])
            xInter, yInter = utils.calcLineIntersection(p1, p2, p3, p4)
            westPoints.append((xInter, yInter))
            westConstructionLines.extend([p1, p2, p3, p4])

            ## Calculate EAST obtuse points
            # Outer corner fans out from point on line
            fanCentre = points[prev]
            # Uses point i+1 (i.e. prev) as this process is working out the termination points for the end of the prev vector
            eX1 = points[prever][0] - line1Norm[0]
            eY1 = points[prever][1] - line1Norm[1]
            #drawVector(batch, points[prev], line1Norm)
            eX2 = points[current][0] - line2Norm[0]
            eY2 = points[current][1] - line2Norm[1]
            #drawVector(batch, points[current], line2Norm, (50, 50, 50))
            # Gives
            p1 = (eX1, eY1)  # Not required for calculation
            p2 = (eX1 + v1[0], eY1 + v1[1])
            # and
            p3 = (eX2, eY2)  # Not required for calculation
            p4 = (eX2 + v2[0], eY2 + v2[1])
            # 'Cap' is straight line from p2 to p4
            capVec = (p4[0] - p2[0], p4[1] - p2[1])

            # DRAWS BLUE TO ENTRY
            #drawLine(fanCentre, p2, (0,0,200))
            # DRAWS WHITE TO EXIT
            #drawLine(fanCentre, p4)
            # DRAWS BROWN CAP
            #drawVector(batch, p2, capVec, (120,80,50))

            capDist = utils.mag(capVec)
            capNorm = utils.normalize(capVec)
            divGap = capDist / (numBevelDivisions + 1)
            currentDiv = divGap
            #eastPoints.append(p2)

            # Temporary increasing colour for diagnosis
            colourIncrease = int(255 / (numBevelDivisions + 2))

            # The +2 is to include the start and end points too
            for dIndex in range(numBevelDivisions + 2):
                # t is one minus the increment so triangle fan starts at correct end
                t = 1 - (1 / (numBevelDivisions + 1)) * dIndex
                vX = fanCentre[0] - (p2[0] + capVec[0] * t)
                vY = fanCentre[1] - (p2[1] + capVec[1] * t)
                # Vector reaches straight line chord, but must be halfLineWidth long
                normalizedRadius = utils.normalize((vX, vY))
                x = fanCentre[0] + normalizedRadius[0] * halfLineWidth
                y = fanCentre[1] + normalizedRadius[1] * halfLineWidth

                # Draw diagnostic line for fan radii
                #print("Radius %d, increasing colour: %d" % (dIndex, colourIncrease))
                #drawLine(fanCentre, (x, y), [0, colourIncrease*(dIndex+1), 0])

                currentDiv += divGap
                # Append next fan-point location
                eastPoints.append((x, y))
                if dIndex % 2 == 0 and dIndex != numBevelDivisions:
                    # Append fan centre
                    eastPoints.append(points[prev])
                    pass
                else:
                    # Append next fan-point location again to create degenerate triangles
                    eastPoints.append((x, y))

            eastConstructionLines.extend([p1, p2])
        else:
            # Right turn, east border is acute

            ## Calculate EAST acute points
            # Inverted normal to get normal on east side
            line1Norm = (lineNormals[prever][0] * halfLineWidth,
                         lineNormals[prever][1] * halfLineWidth)
            eX1 = points[prever][0] - line1Norm[0]
            eY1 = points[prever][1] - line1Norm[1]
            # Vector from current point, into intersection
            v1 = (points[prev][0] - points[prever][0],
                  points[prev][1] - points[prever][1])
            # Point on line parallel to line leaving intersection point
            line2Norm = (lineNormals[prev][0] * halfLineWidth,
                         lineNormals[prev][1] * halfLineWidth)
            eX2 = points[current][0] - line2Norm[0]
            eY2 = points[current][1] - line2Norm[1]
            # Vector from point after intersection, pointing back into it
            v2 = (points[prev][0] - points[current][0],
                  points[prev][1] - points[current][1])
            # Gives
            p1 = (eX1, eY1)
            p2 = (eX1 + v1[0], eY1 + v1[1])
            # and
            p3 = (eX2, eY2)
            p4 = (eX2 + v2[0], eY2 + v2[1])
            xInter, yInter = utils.calcLineIntersection(p1, p2, p3, p4)
            eastPoints.append((xInter, yInter))
            # Append point on entering line
            eastPoints.append((xInter + line1Norm[0], yInter + line1Norm[1]))
            eastPoints.append(points[prev])
            # Append a second time to create degenerate triangle
            eastPoints.append(points[prev])
            # Append intersection again
            eastPoints.append((xInter, yInter))
            # Append point on exiting line
            eastPoints.append((xInter + line2Norm[0], yInter + line2Norm[1]))
            eastConstructionLines.extend([p1, p2, p3, p4])

            ## Calculate WEST obtuse points
            # Uses point i+1 (i.e. prev) as this process is working out the termination points for the end of the prev vector
            wX1 = points[prever][0] + line1Norm[0]
            wY1 = points[prever][1] + line1Norm[1]
            #drawVector(batch, points[prev], line1Norm)
            wX2 = points[current][0] + line2Norm[0]
            wY2 = points[current][1] + line2Norm[1]
            #drawVector(batch, points[current], line2Norm, (50, 50, 50))
            # Gives
            p1 = (wX1, wY1)
            p2 = (wX1 + v1[0], wY1 + v1[1])
            # and
            p3 = (wX2, wY2)
            p4 = (wX2 + v2[0], wY2 + v2[1])
            xInter, yInter = utils.calcLineIntersection(p1, p2, p3, p4)
            westPoints.append((xInter, yInter))
            westConstructionLines.extend([p1, p2])
            pass

    if drawEastMitreConstructionLines:
        east_acute_construction_vertex_list = batch.add(
            len(eastConstructionLines), pyglet.gl.GL_LINES,
            next(utils.renderGroupGenerator),
            ('v2f/static', list(chain.from_iterable(eastConstructionLines))),
            ('c3B/static', [25, 180, 60] * len(eastConstructionLines)))
    if drawEastMitrePointLines:
        east_acute_vertex_list = batch.add(
            len(eastPoints), pyglet.gl.GL_LINE_LOOP,
            next(utils.renderGroupGenerator),
            ('v2f/static', list(chain.from_iterable(eastPoints))),
            ('c3B/static', [200, 0, 0] * len(eastPoints)))
    if drawWestMitreConstructionLines:
        west_acute_construction_vertex_list = batch.add(
            len(westConstructionLines), pyglet.gl.GL_LINES,
            next(utils.renderGroupGenerator),
            ('v2f/static', list(chain.from_iterable(westConstructionLines))),
            ('c3B/static', [25, 180, 60] * len(westConstructionLines)))
    if drawWestMitrePointLines:
        west_acute_vertex_list = batch.add(
            len(westPoints), pyglet.gl.GL_LINE_LOOP,
            next(utils.renderGroupGenerator),
            ('v2f/static', list(chain.from_iterable(westPoints))),
            ('c3B/static', [0, 0, 200] * len(westPoints)))

    if drawRoundedMitring:
        #Construct wide-line triangles
        # # West triangles
        # westTrianglePoints = list()
        # for pIndex in range(len(points)):
        #     westTrianglePoints.append(points[pIndex-1])
        #     westTrianglePoints.append(westPoints[pIndex])
        # westTrianglePoints.append(points[-1])
        # westTrianglePoints.append(westPoints[0])
        # col = list()
        # for n in range(len(westTrianglePoints)):
        #     col.extend([random.randint(0,255), random.randint(0,255), random.randint(0,255)])
        # west_acute_vertex_list = batch.add(len(westTrianglePoints), pyglet.gl.GL_TRIANGLE_STRIP, next(utils.renderGroupGenerator),
        #     ('v2f/static', list(chain.from_iterable(westTrianglePoints))),
        #     ('c3B/static', col)
        # )

        #East triangles uses a deep copy of east points
        eastTrianglePoints = list(eastPoints)
        # Add start as end to create loop
        eastTrianglePoints.append(eastPoints[0])
        eastTrianglePoints.append(eastPoints[1])

        colLines = list()
        colTris = list()
        for n in range(len(eastTrianglePoints)):
            #col.extend([random.randint(0,255), random.randint(0,255), random.randint(0,255)])
            colTris.extend([0.9, 0, 0, 0.5])
            colLines.extend([0, 0.2, 0.7, 0.8])
        east_acute_tris_list = batch.add(
            len(eastTrianglePoints), pyglet.gl.GL_TRIANGLE_STRIP,
            next(utils.renderGroupGenerator),
            ('v2f/static', list(chain.from_iterable(eastTrianglePoints))),
            ('c4f/static', colTris))
        east_acute_lines_list = batch.add(
            len(eastTrianglePoints), pyglet.gl.GL_LINE_LOOP,
            next(utils.renderGroupGenerator),
            ('v2f/static', list(chain.from_iterable(eastTrianglePoints))),
            ('c4f/static', colLines))
        pass
Esempio n. 9
0
def createPoints():
    ## ROUNDED OBTUSE CORNERS
    # Loop over intersections
    # On inside of turn, find where entering/exiting lines meet, use point
    # On outside of turn...
    # * stop at same length of acute line
    # * next point is intersection normal, at dist of line width
    # * subdivide if desired
    eastPoints = list()
    eastConstructionLines = list()
    westPoints = list()
    westConstructionLines = list()
    for i in range(len(lineVecs)):
        #print("\ni = %d" % i)
        #print("ith Point: %f,%f" % (points[i][0], points[i][1]))
        prever = i-2
        prev = i-1
        current = i
        v1 = utils.normalize(lineVecs[prever])
        v2 = utils.normalize(lineVecs[prev])
        position = v1[0]*v2[1] - v1[1]*v2[0]
        if (position == 0):
            print("i=%d, straight ahead" % prever)
            # ignore points here... let prev vector dictate them
            continue
        elif (position > 0):
            # Left turn, west border is acute

            p1, p2, p3, p4 = utils.calcParallelLinePoints(halfLineWidth, points[prever], points[prev], points[current], eastSide=False)

            ## Calculate WEST acute points
            line1Norm = (lineNormals[prever][0]*halfLineWidth, lineNormals[prever][1]*halfLineWidth)
            # wX1 = points[prever][0] + line1Norm[0]
            # wY1 = points[prever][1] + line1Norm[1]
            # # Vector from current point, into intersection
            # v1 = (points[prev][0]-points[prever][0], points[prev][1]-points[prever][1])
            # # Point on line parallel to line leaving intersection point
            line2Norm = (lineNormals[prev][0]*halfLineWidth, lineNormals[prev][1]*halfLineWidth)
            # wX2 = points[current][0] + line2Norm[0]
            # wY2 = points[current][1] + line2Norm[1]
            # # Vector from point after intersection, pointing back into it
            # v2 = (points[prev][0]-points[current][0], points[prev][1]-points[current][1])
            # # Gives
            # p1 = (wX1, wY1)
            # p2 = (wX1+v1[0], wY1+v1[1])
            # # and
            # p3 = (wX2, wY2)
            # p4 = (wX2+v2[0], wY2+v2[1])
            xInter, yInter = utils.calcLineIntersection(p1, p2, p3, p4)
            westPoints.append((xInter, yInter))
            westConstructionLines.extend([p1, p2, p3, p4])

            ## Calculate EAST obtuse points
            # Outer corner fans out from point on line
            fanCentre = points[prev]
            # Uses point i+1 (i.e. prev) as this process is working out the termination points for the end of the prev vector
            eX1 = points[prever][0] - line1Norm[0]
            eY1 = points[prever][1] - line1Norm[1]
            #drawVector(batch, points[prev], line1Norm)
            eX2 = points[current][0] - line2Norm[0]
            eY2 = points[current][1] - line2Norm[1]
            #drawVector(batch, points[current], line2Norm, (50, 50, 50))
            # Gives
            p1 = (eX1, eY1) # Not required for calculation
            p2 = (eX1+v1[0], eY1+v1[1])
            # and
            p3 = (eX2, eY2) # Not required for calculation
            p4 = (eX2+v2[0], eY2+v2[1])
            # 'Cap' is straight line from p2 to p4
            capVec = (p4[0]-p2[0], p4[1]-p2[1])

            # DRAWS BLUE TO ENTRY
            #drawLine(fanCentre, p2, (0,0,200))
            # DRAWS WHITE TO EXIT
            #drawLine(fanCentre, p4)
            # DRAWS BROWN CAP
            #drawVector(batch, p2, capVec, (120,80,50))

            capDist = utils.mag(capVec)
            capNorm = utils.normalize(capVec)
            divGap = capDist / (numBevelDivisions+1)
            currentDiv = divGap
            #eastPoints.append(p2)

            # Temporary increasing colour for diagnosis
            colourIncrease = int(255/(numBevelDivisions+2))

            # The +2 is to include the start and end points too
            for dIndex in range(numBevelDivisions+2):
                # t is one minus the increment so triangle fan starts at correct end
                t = 1 - (1/(numBevelDivisions+1))*dIndex
                vX = fanCentre[0] - (p2[0]+capVec[0]*t)
                vY = fanCentre[1] - (p2[1]+capVec[1]*t)
                # Vector reaches straight line chord, but must be halfLineWidth long
                normalizedRadius = utils.normalize((vX, vY))
                x = fanCentre[0] + normalizedRadius[0]*halfLineWidth
                y = fanCentre[1] + normalizedRadius[1]*halfLineWidth

                # Draw diagnostic line for fan radii
                #print("Radius %d, increasing colour: %d" % (dIndex, colourIncrease))
                #drawLine(fanCentre, (x, y), [0, colourIncrease*(dIndex+1), 0])

                currentDiv += divGap
                # Append next fan-point location
                eastPoints.append((x, y))
                if dIndex%2 == 0 and dIndex != numBevelDivisions:
                    # Append fan centre
                    eastPoints.append(points[prev])
                    pass
                else:
                    # Append next fan-point location again to create degenerate triangles
                    eastPoints.append((x, y))

            eastConstructionLines.extend([p1, p2])
        else:
            # Right turn, east border is acute

            ## Calculate EAST acute points
            # Inverted normal to get normal on east side
            line1Norm = (lineNormals[prever][0]*halfLineWidth, lineNormals[prever][1]*halfLineWidth)
            eX1 = points[prever][0]-line1Norm[0]
            eY1 = points[prever][1]-line1Norm[1]
            # Vector from current point, into intersection
            v1 = (points[prev][0]-points[prever][0], points[prev][1]-points[prever][1])
            # Point on line parallel to line leaving intersection point
            line2Norm = (lineNormals[prev][0]*halfLineWidth, lineNormals[prev][1]*halfLineWidth)
            eX2 = points[current][0]-line2Norm[0]
            eY2 = points[current][1]-line2Norm[1]
            # Vector from point after intersection, pointing back into it
            v2 = (points[prev][0]-points[current][0], points[prev][1]-points[current][1])
            # Gives
            p1 = (eX1, eY1)
            p2 = (eX1+v1[0], eY1+v1[1])
            # and
            p3 = (eX2, eY2)
            p4 = (eX2+v2[0], eY2+v2[1])
            xInter, yInter = utils.calcLineIntersection(p1, p2, p3, p4)
            eastPoints.append((xInter, yInter))
            # Append point on entering line
            eastPoints.append((xInter+line1Norm[0], yInter+line1Norm[1]))
            eastPoints.append(points[prev])
            # Append a second time to create degenerate triangle
            eastPoints.append(points[prev])
            # Append intersection again
            eastPoints.append((xInter, yInter))
            # Append point on exiting line
            eastPoints.append((xInter+line2Norm[0], yInter+line2Norm[1]))
            eastConstructionLines.extend([p1, p2, p3, p4])

            ## Calculate WEST obtuse points
            # Uses point i+1 (i.e. prev) as this process is working out the termination points for the end of the prev vector
            wX1 = points[prever][0] + line1Norm[0]
            wY1 = points[prever][1] + line1Norm[1]
            #drawVector(batch, points[prev], line1Norm)
            wX2 = points[current][0] + line2Norm[0]
            wY2 = points[current][1] + line2Norm[1]
            #drawVector(batch, points[current], line2Norm, (50, 50, 50))
            # Gives
            p1 = (wX1, wY1)
            p2 = (wX1+v1[0], wY1+v1[1])
            # and
            p3 = (wX2, wY2)
            p4 = (wX2+v2[0], wY2+v2[1])
            xInter, yInter = utils.calcLineIntersection(p1, p2, p3, p4)
            westPoints.append((xInter, yInter))
            westConstructionLines.extend([p1, p2])
            pass

    if drawEastMitreConstructionLines:
        east_acute_construction_vertex_list = batch.add(len(eastConstructionLines), pyglet.gl.GL_LINES, next(utils.renderGroupGenerator),
            ('v2f/static', list(chain.from_iterable(eastConstructionLines))),
            ('c3B/static', [25, 180, 60]*len(eastConstructionLines))
        )
    if drawEastMitrePointLines:
        east_acute_vertex_list = batch.add(len(eastPoints), pyglet.gl.GL_LINE_LOOP, next(utils.renderGroupGenerator),
            ('v2f/static', list(chain.from_iterable(eastPoints))),
            ('c3B/static', [200, 0, 0]*len(eastPoints))
        )
    if drawWestMitreConstructionLines:
        west_acute_construction_vertex_list = batch.add(len(westConstructionLines), pyglet.gl.GL_LINES, next(utils.renderGroupGenerator),
            ('v2f/static', list(chain.from_iterable(westConstructionLines))),
            ('c3B/static', [25, 180, 60]*len(westConstructionLines))
        )
    if drawWestMitrePointLines:
        west_acute_vertex_list = batch.add(len(westPoints), pyglet.gl.GL_LINE_LOOP, next(utils.renderGroupGenerator),
            ('v2f/static', list(chain.from_iterable(westPoints))),
            ('c3B/static', [0, 0, 200]*len(westPoints))
        )

    if drawRoundedMitring:
        #Construct wide-line triangles
        # # West triangles
        # westTrianglePoints = list()
        # for pIndex in range(len(points)):
        #     westTrianglePoints.append(points[pIndex-1])
        #     westTrianglePoints.append(westPoints[pIndex])
        # westTrianglePoints.append(points[-1])
        # westTrianglePoints.append(westPoints[0])
        # col = list()
        # for n in range(len(westTrianglePoints)):
        #     col.extend([random.randint(0,255), random.randint(0,255), random.randint(0,255)])
        # west_acute_vertex_list = batch.add(len(westTrianglePoints), pyglet.gl.GL_TRIANGLE_STRIP, next(utils.renderGroupGenerator),
        #     ('v2f/static', list(chain.from_iterable(westTrianglePoints))),
        #     ('c3B/static', col)
        # )

        #East triangles uses a deep copy of east points
        eastTrianglePoints = list(eastPoints)
        # Add start as end to create loop
        eastTrianglePoints.append(eastPoints[0])
        eastTrianglePoints.append(eastPoints[1])

        colLines = list()
        colTris = list()
        for n in range(len(eastTrianglePoints)):
            #col.extend([random.randint(0,255), random.randint(0,255), random.randint(0,255)])
            colTris.extend([0.9,0,0,0.5])
            colLines.extend([0,0.2,0.7,0.8])
        east_acute_tris_list = batch.add(len(eastTrianglePoints), pyglet.gl.GL_TRIANGLE_STRIP, next(utils.renderGroupGenerator),
            ('v2f/static', list(chain.from_iterable(eastTrianglePoints))),
            ('c4f/static', colTris)
        )
        east_acute_lines_list = batch.add(len(eastTrianglePoints), pyglet.gl.GL_LINE_LOOP, next(utils.renderGroupGenerator),
            ('v2f/static', list(chain.from_iterable(eastTrianglePoints))),
            ('c4f/static', colLines)
        )
        pass