Пример #1
0
def collision_checking(world, est_config_list, density):
    """

    :param world: {Klampt.WorldModel} -- the world model
    :param est_config_list: {list} -- the list of calibration configuration set
    :param density: {float} -- the interpolation step, for example: 0.001
    :return: path: {list or bool} -- if it is list, this is the path of the calibration. If it is bool(False), this
                                     means that the path has collision
    """
    robot = world.robot(0)
    q_0 = robot.getConfig()
    inter_len = int(1. / density)
    path = []
    for i in range(len(est_config_list)):
        for j in range(1, inter_len + 1):
            if i == 0:
                milestone = vectorops.interpolate(q_0, est_config_list[i],
                                                  j * density)
            else:
                milestone = vectorops.interpolate(est_config_list[i - 1],
                                                  est_config_list[i],
                                                  j * density)
            robot.setConfig(milestone)
            if robot.selfCollides() is True:
                return False
            else:
                path.append(milestone)
    return path
Пример #2
0
def workspace_interpolate(a, b, u):
    """Interpolates either in R^n or SE(3) between points a and b.  If len(a)<=3, 
	this will do cartesian interpolation.  Otherwise, len(a)==6 is required and
	this will do SE(3) interpolation."""
    if len(a) <= 3:
        return vectorops.interpolate(a, b, u)
    assert len(a) == 6, "Can only interpolate in R2, R3, or SE(3)"
    Ra, Rb = so3.from_moment(a[3:]), so3.from_moment(b[3:])
    R = so3.interpolate(Ra, Rb, u)
    return vectorops.interpolate(a[:3], b[:3], u) + so3.moment(R)
Пример #3
0
def segment_segment_intersection(seg1, seg2, umin=0, umax=1, vmin=0, vmax=1):
    """Given 2 2D segments (a1,b1) and (a2,b2) returns whether the portion of
	seg1 in the range [umin,umax] overlaps seg2 in the range [vmin,vmax].

	Returns the point of intersection or None if no intersection exists
	"""
    a1, b1 = seg1
    a2, b2 = seg2
    assert len(a1) == 2
    assert len(b1) == 2
    assert len(a2) == 2
    assert len(b2) == 2
    d = vectorops.sub(b1, a1)
    a, b = vectorops.sub(a2, a1), vectorops.sub(b2, a1)
    #now it's centered at a1
    #u*d = a + v*(b-a)
    e = vectorops.sub(b2, a2)
    A = np.array([d, vectorops.mul(e, -1)]).T
    try:
        uv = np.dot(np.linalg.inv(A), a)
    except np.linalg.linalg.LinAlgError:
        return None
    u, v = uv
    if u < umin or u > umax:
        return None
    if v < umin or v > umax:
        return None
    return vectorops.interpolate(a1, b1, u)
Пример #4
0
def segment_point_distance(a, b, x):
    """Returns (distance, parameter) pair between segment (a,b) and point x"""
    d = vectorops.sub(b, a)
    u = vectorops.dot(vectorops.sub(x, a), d) / vectorops.dot(d, d)
    u = min(1.0, max(u, 0.0))
    d = vectorops.distance(x, vectorops.interpolate(a, b, u))
    return (d, u)
Пример #5
0
 def partway_open_config(self,amount):
     """Returns a finger configuration partway open, with amount in the
     range [0 (closed),1 (fully open)].
     """
     if self.closed_config is None or self.open_config is None:
         raise ValueError("Can't get an opening configuration on a robot that does not define it")
     return vectorops.interpolate(self.closed_config,self.open_config,amount)
Пример #6
0
def bbox(bmin,
         bmax,
         R=None,
         t=None,
         world=None,
         name=None,
         mass=float('inf'),
         type='TriangleMesh'):
    """Makes a box from bounds [bmin,bmax].

    Args:
        bmin (list of 3 floats): the lower corner of the box
        center (list of 3 floats): the upper corner of the box
        R,t (se3 transform, optional): if given, the box's world coordinates
            will be rotated and shifted by this transform.
        world (WorldModel, optional): If given, then the box will be a
            RigidObjectModel or TerrainModel will be created in this world
        name (str, optional): If world is given, this is the name of the object. 
            Default is 'box'.
        mass (float, optional): If world is given and this is inf, then a
            TerrainModel will be created. Otherwise, a RigidObjectModel
            will be created with automatically determined inertia.
        type (str, optional): the geometry type.  Defaults to 'TriangleMesh',
            but also 'GeometricPrimitive' and 'VolumeGrid' are accepted.

    Returns:
        Geometry3D, RigidObjectModel, or TerrainModel: A representation
        of the box.  If a world is given, then either a RigidObjectModel
        or TerrainModel is added to the world and returned.
    """
    w, d, h = vectorops.sub(bmax, bmin)
    center = vectorops.interpolate(bmin, bmax, 0.5)
    return box(w, d, h, center, R, t, world, name, mass, type)
Пример #7
0
def grasp_from_contacts(contact1,contact2):
    """Helper: if you have two contacts, this returns an AntipodalGrasp"""
    d = vectorops.unit(vectorops.sub(contact2.x,contact1.x))
    grasp = AntipodalGrasp(vectorops.interpolate(contact1.x,contact2.x,0.5),d)
    grasp.finger_width = vectorops.distance(contact1.x,contact2.x)
    grasp.contact1 = contact1
    grasp.contact2 = contact2
    return grasp
Пример #8
0
 def interpolate(self, a, b, u):
     """TODO: Implement this interpolation function.
     Inputs:
     - a: the start configuration
     - b: the end configuration
     - u: the interpolation parameter in the range from 0 to 1 
     Out: the interpolated configuration
     """
     interpolate_result = vectorops.interpolate(a[0:2], b[0:2], u)
     interpolate_angle = interpolateAngle(a[2], b[2], u)
     interpolate_result.append(interpolate_angle)
     return interpolate_result
 def idle(self):
     t0 = time.time()
     if self.movie_frame is not None:
         numframes = 180
         if self.movie_rotate:
             self.window.program.view.camera.rot[
                 2] += math.pi * 2 / numframes
         self.window.program.save_screen("frame%03d.ppm" %
                                         (self.movie_frame))
         self.movie_frame += 1
         if self.movie_rotate and self.movie_frame >= numframes:
             self.movie_frame = None
     if self.walk_path != None:
         self.walk_progress += 0.02
         if self.walk_progress >= self.walk_path.times[-1]:
             self.configs = [self.walk_path.milestones[-1]]
             self.walk_path = None
         else:
             #self.configs = [self.walk_path.eval(self.walk_progress)]
             self.configs = [
                 self.resolution.eval(
                     self.walk_workspace_path.eval(self.walk_progress))
             ]
             if self.configs[0] == None:
                 self.configs = []
             u = self.walk_progress / self.walk_path.times[-1]
             qstraight = self.resolution.solve(
                 self.temp_config,
                 vectorops.interpolate(
                     self.walk_workspace_path.milestones[0],
                     self.walk_workspace_path.milestones[-1], u),
                 testfeasibility=False)
             if qstraight and (
                     self.resolution.ikTemplate.feasibilityTest == None or
                     self.resolution.ikTemplate.feasibilityTest(qstraight)):
                 self.temp_config = qstraight
         self.refresh()
         t1 = time.time()
         if t1 - t0 < 0.02:
             time.sleep(0.02 - (t1 - t0))
Пример #10
0
    def addBillboard(self,
                     name="Billboard",
                     image=[[]],
                     format='auto',
                     crange=[0, 1],
                     colormap='auto',
                     filter='linear',
                     size=(1, 1)):
        """Adds a 2D billboard to the world.  The image is a 2D array of
        values, which is texure-mapped to a quad. 

        By default, the billboard is centered at (0,0,0) and faces up. 
        To modify its location or orientation, call ``setTransform`` on it.

        Args:
            name (str): the name used to refer to this item
            
            image (list of lists or str): a 2D array of single-channel values, (r,g,b) tuples, or (r,g,b,a)
                tuples. Rows are listed top to bottom, rows from left to right.  Or, can also be a URL.
            
            format (str, optional): The image format.  Can be:

                * 'auto': autodetect the type from the image. If the image contains values, the format is 'value'.
                * 'value': the values are mapped through either 'opacity', 'rainbow', or gradient
                  color mapping.
                * 'rgb': if the image contains values, they are interpreted as RGB values packed in 24 bit
                  integers. Otherwise, the first 3 channels of the tuple are used.
                * 'rgba': if the image contains values, they are interpreted as RGB values packed in 32 bit
                  integers. Otherwise, they are assumed to be (r,g,b,a) tuples

            crange (pair of numbers, optional): the range of the given values / channels. By default [0,1], but if you are using uint8
                encoding this should be set to [0,255].
            
            colormap (optional): how the color of the billboard should be set based on the image.  Valid values are:

                * 'auto': if the image contains values, the gradient ((0,0,0),(1,1,1)) is used.  Otherwise
                  'replace' is used.
                * (color1,color2): interpolates between the two given (r,g,b) or (r,g,b,a) tuples.
                * 'opacity': sets the alpha channel only.
                * 'modulate': the value / rgb / rgba texture modulates the billboard color as set by setColor

            filter (str, optional): how values between pixels are interpolated.  Either 'nearest' or 'linear'.
            
            size (pair of numbers, optional): the (width,height) pair of the billboard, in world units.

        """
        if not isinstance(image, str):
            import struct
            import base64
            bytes = []
            w, h = None, None
            h = len(image)
            for row in image:
                if w == None:
                    w = len(row)
                else:
                    assert w == len(row), "Image is not a 2D array"
            pixel = image[0][0]
            if format == 'auto':
                if hasattr(pixel, '__iter__'):
                    if len(pixel) == 4:
                        format = 'rgba'
                    else:
                        format = 'rgb'
                else:
                    format = 'value'
            else:
                if not hasattr(pixel, '__iter__'):
                    format = 'p' + format
            gradient = (type(colormap) != str)
            for row in image:
                for pixel in row:
                    if format == 'value':
                        u = min(
                            1,
                            max(0,
                                (pixel - crange[0]) / (crange[1] - crange[0])))
                        if gradient:
                            color = vectorops.interpolate(
                                gradient[0], gradient[1], u)
                            r = 0xff * min(1, max(0, color[0]))
                            g = 0xff * min(1, max(0, color[1]))
                            b = 0xff * min(1, max(0, color[2]))
                            packed = (0xff << 24) | (int(b) << 16) | (
                                int(g) << 8) | int(r)
                            bytes.append(struct.pack('<I', packed))
                        else:
                            val = 0xff * u
                            bytes.append(struct.pack('B', val))
                    elif format == 'prgb' or format == 'prgba':
                        bytes.append(struct.pack('<I', pixel))
                    elif format == 'rgb':
                        r = 0xff * min(
                            1,
                            max(0, (pixel[0] - crange[0]) /
                                (crange[1] - crange[0])))
                        g = 0xff * min(
                            1,
                            max(0, (pixel[1] - crange[0]) /
                                (crange[1] - crange[0])))
                        b = 0xff * min(
                            1,
                            max(0, (pixel[2] - crange[0]) /
                                (crange[1] - crange[0])))
                        packed = (0xff << 24) | (int(b) << 16) | (
                            int(g) << 8) | int(r)
                        bytes.append(struct.pack('<I', packed))
                    elif format == 'rgba':
                        r = 0xff * min(
                            1,
                            max(0, (pixel[0] - crange[0]) /
                                (crange[1] - crange[0])))
                        g = 0xff * min(
                            1,
                            max(0, (pixel[1] - crange[0]) /
                                (crange[1] - crange[0])))
                        b = 0xff * min(
                            1,
                            max(0, (pixel[2] - crange[0]) /
                                (crange[1] - crange[0])))
                        a = 0xff * min(
                            1,
                            max(0, (pixel[3] - crange[0]) /
                                (crange[1] - crange[0])))
                        packed = (int(a) << 24) | (int(b) << 16) | (
                            int(g) << 8) | int(r)
                        bytes.append(struct.pack('<I', packed))
                    else:
                        raise ValueError("Invalid format " + format)
            image = base64.b64encode(''.join(bytes))
            self._do_rpc({
                'type': 'add_billboard',
                'name': name,
                'imagedata': image,
                'width': w,
                'height': h,
                'size': size,
                'filter': filter,
                'colormap': colormap
            })
        else:
            self._do_rpc({
                'type': 'add_billboard',
                'name': name,
                'image': image,
                'size': size,
                'filter': filter,
                'colormap': colormap
            })
        self._extras[name] = ('Billboard', image)
 def interpolate(self, a, b, u):
     return vectorops.interpolate(a[:2], b[:2],
                                  u) + [a[2] + u * so2.diff(b[2], a[2])]
Пример #12
0
    def addBillboard(self,name="Billboard",image=[[]],format='auto',crange=[0,1],colormap='auto',filter='linear',size=(1,1)):
        """Adds a 2D billboard to the world.  The image is a 2D array of
        values, which is texure-mapped to a quad. 

        By default, the billboard is centered at (0,0,0) and faces up. 
        To modify its location or orientation, call ``setTransform`` on it.

        Args:
            name (str): the name used to refer to this item
            
            image (list of lists or str): a 2D array of single-channel values, (r,g,b) tuples, or (r,g,b,a)
                tuples. Rows are listed top to bottom, rows from left to right.  Or, can also be a URL.
            
            format (str, optional): The image format.  Can be:

                * 'auto': autodetect the type from the image. If the image contains values, the format is 'value'.
                * 'value': the values are mapped through either 'opacity', 'rainbow', or gradient
                  color mapping.
                * 'rgb': if the image contains values, they are interpreted as RGB values packed in 24 bit
                  integers. Otherwise, the first 3 channels of the tuple are used.
                * 'rgba': if the image contains values, they are interpreted as RGB values packed in 32 bit
                  integers. Otherwise, they are assumed to be (r,g,b,a) tuples

            crange (pair of numbers, optional): the range of the given values / channels. By default [0,1], but if you are using uint8
                encoding this should be set to [0,255].
            
            colormap (optional): how the color of the billboard should be set based on the image.  Valid values are:

                * 'auto': if the image contains values, the gradient ((0,0,0),(1,1,1)) is used.  Otherwise
                  'replace' is used.
                * (color1,color2): interpolates between the two given (r,g,b) or (r,g,b,a) tuples.
                * 'opacity': sets the alpha channel only.
                * 'modulate': the value / rgb / rgba texture modulates the billboard color as set by setColor

            filter (str, optional): how values between pixels are interpolated.  Either 'nearest' or 'linear'.
            
            size (pair of numbers, optional): the (width,height) pair of the billboard, in world units.

        """
        if not isinstance(image,str):
            import struct
            import base64
            bytes = []
            w,h = None,None
            h = len(image)
            for row in image:
                if w == None:
                    w = len(row)
                else:
                    assert w == len(row),"Image is not a 2D array"
            pixel = image[0][0]
            if format == 'auto':
                if hasattr(pixel,'__iter__'):
                    if len(pixel) == 4:
                        format = 'rgba'
                    else:
                        format = 'rgb'
                else:
                    format = 'value'
            else:
                if not hasattr(pixel,'__iter__'):
                    format = 'p'+format
            gradient = (type(colormap) != str)
            for row in image:
                for pixel in row:
                    if format == 'value':
                        u = min(1,max(0,(pixel - crange[0]) / (crange[1]-crange[0])))
                        if gradient:
                            color = vectorops.interpolate(gradient[0],gradient[1],u)
                            r = 0xff * min(1,max(0,color[0]))
                            g = 0xff * min(1,max(0,color[1]))
                            b = 0xff * min(1,max(0,color[2]))
                            packed = (0xff << 24) | (int(b) << 16) | (int(g) << 8) | int(r)
                            bytes.append(struct.pack('<I',packed))
                        else:
                            val = 0xff * u
                            bytes.append(struct.pack('B',val))
                    elif format == 'prgb' or format == 'prgba':
                        bytes.append(struct.pack('<I', pixel))
                    elif format == 'rgb':
                        r = 0xff * min(1,max(0,(pixel[0] - crange[0]) / (crange[1]-crange[0])))
                        g = 0xff * min(1,max(0,(pixel[1] - crange[0]) / (crange[1]-crange[0])))
                        b = 0xff * min(1,max(0,(pixel[2] - crange[0]) / (crange[1]-crange[0])))
                        packed = (0xff << 24) | (int(b) << 16) | (int(g) << 8) | int(r)
                        bytes.append(struct.pack('<I', packed))
                    elif format == 'rgba':
                        r = 0xff * min(1,max(0,(pixel[0] - crange[0]) / (crange[1]-crange[0])))
                        g = 0xff * min(1,max(0,(pixel[1] - crange[0]) / (crange[1]-crange[0])))
                        b = 0xff * min(1,max(0,(pixel[2] - crange[0]) / (crange[1]-crange[0])))
                        a = 0xff * min(1,max(0,(pixel[3] - crange[0]) / (crange[1]-crange[0])))
                        packed = (int(a) << 24) | (int(b) << 16) | (int(g) << 8) | int(r)
                        bytes.append(struct.pack('<I', packed))
                    else:
                        raise ValueError("Invalid format "+format)
            image = base64.b64encode(''.join(bytes))
            self._do_rpc({'type':'add_billboard','name':name,'imagedata':image,'width':w,'height':h,'size':size,'filter':filter,'colormap':colormap})
        else:
            self._do_rpc({'type':'add_billboard','name':name,'image':image,'size':size,'filter':filter,'colormap':colormap})
        self._extras[name] = ('Billboard',image)
Пример #13
0
def getTorque(t, q, dq):
    """ TODO: implement me
    Returns a 4-element torque vector given the current time t, the configuration q, and the joint velocities dq to drive
    the robot so that it traces out the desired curves.
    
    Recommended order of operations:
    1. Monitor and update the current status and stroke
    2. Update the stroke_progress, making sure to perform smooth interpolating trajectories
    3. Determine a desired configuration given current state using IK
    4. Send qdes, dqdes to PID controller
    """
    global robot, status, current_stroke, current_stroke_progress, current_frac, stroke_list
    # ### PID Implementation Arc Test
    # qdes = [0,0,0,0]
    # dqdes = [0,0,0,0]
    # if t > 0.5:
    #     #move up
    #     qdes[1] = 0.3
    # if t > 1.5:
    #     #drop the last link down
    #     qdes[3] = 0.04
    #     # print(q, qdes)
    # if t > 2.0:
    #     #move down
    #     qdes[1] = -0.3
    # kP = [20,6,10,4]
    # kI = [9,4,5,3]
    # kD = [15,2,0.4,2]
    # print(q)
    # ###

    ### Draw Strokes
    kP = [25, 6, 10, 9]
    kI = [10, 3.5, 5, 2]
    kD = [15, 2, 0.4, 2]
    joint_max_vel = 0.0
    small_error_limit = 10**-2.2  # To see fast process set to 10**-1.0
    large_error_limit = 10**-1.75  # To see fast process set to 10**-0.85
    lift_h = 0.01
    write_h = -0.0001
    num_frac = 50.0
    dqdes = [0, 0, 0, 0]
    # State Machine
    if status == 'lift up':
        cur_target = addDim(stroke_list[current_stroke][-1], lift_h)
        qdes = configSolver(cur_target)
        if isArrive(q, qdes, dq, dqdes, large_error_limit, large_error_limit):
            current_stroke += 1
            status = 'move to above'
    elif status == 'move to above':
        cur_target = addDim(stroke_list[current_stroke][0], lift_h)
        qdes = configSolver(cur_target)
        if isArrive(q, qdes, dq, dqdes, large_error_limit, large_error_limit):
            status = 'push down'
    elif status == 'push down':
        cur_target = addDim(stroke_list[current_stroke][0], write_h)
        qdes = configSolver(cur_target)
        if isArrive(q, qdes, dq, dqdes, small_error_limit, small_error_limit):
            status = 'writting stroke'
    elif status == 'writting stroke':
        start_point = addDim(
            stroke_list[current_stroke][current_stroke_progress - 1], write_h)
        end_point = addDim(
            stroke_list[current_stroke][current_stroke_progress], write_h)
        cur_target = vectorops.interpolate(start_point, end_point,
                                           1 / num_frac * current_frac)
        qdes = configSolver(cur_target)
        if isArrive(q, qdes, dq, dqdes, small_error_limit, small_error_limit):
            current_frac += 1
            if current_frac > num_frac:
                current_frac = 0
                if current_stroke_progress < len(
                        stroke_list[current_stroke]) - 1:
                    current_stroke_progress += 1
                else:
                    current_stroke_progress = 1
                    if current_stroke == len(stroke_list) - 1:
                        status = 'finish'
                        print('finish')
                    else:
                        status = 'lift up'
    elif status == 'finish':
        hold_point = addDim(stroke_list[current_stroke][-1], lift_h)
        qdes = configSolver(hold_point)
    ###

    ### Test Print
    # print('Status: ' +  status + " ")
    # print('Current Stroke: ',current_stroke)
    # print('Stroke Progress: ', current_stroke_progress)
    # print('Current frac: ', current_frac)
    # print('Current pen tip ', q[3])
    # print('Target pen tip  ', dqdes[3])
    # print('Current pen vel ', dq)
    # print('Current target pen vel ', dqdes)
    # print('---------------------------')
    ###
    return getPIDTorqueAndAdvance(q, dq, qdes, dqdes, kP, kI, kD,
                                  pid_integrators, dt)
Пример #14
0
    def display(self):
        if self.configs == None:
            self.robot.drawGL()
        else:
            for q in self.configs:
                self.robot.setConfig(q)
                self.robot.drawGL()

        if self.walk_workspace_path != None:
            if self.temp_config:
                self.robot.setConfig(self.temp_config)
                glEnable(GL_BLEND)
                #glDisable(GL_DEPTH_TEST)
                for i in xrange(self.robot.numLinks()):
                    self.robot.link(i).appearance().setColor(1, 0, 0, 0.5)
                self.robot.drawGL()
                for i in xrange(self.robot.numLinks()):
                    self.robot.link(i).appearance().setColor(0.5, 0.5, 0.5, 1)
                #glEnable(GL_DEPTH_TEST)
                glDisable(GL_BLEND)
            glColor3f(1, 1, 0)
            glLineWidth(5.0)
            glBegin(GL_LINE_STRIP)
            for w in self.walk_workspace_path.milestones:
                if len(w) == 2:
                    glVertex2f(w[0], w[1])
                else:
                    glVertex3f(w[0], w[1], w[2])
            glEnd()
            glLineWidth(1.0)

        assert len(
            self.resolution.ikTaskSpace) == 1, "Can only do one task for now"
        task = self.resolution.ikTaskSpace[0]

        #DEBUG
        if hasattr(self.resolution, 'delaunay'):
            delaunay = self.resolution.delaunay
            delaunay_pts = self.resolution.delaunay_pts
            delaunay_epts = self.resolution.delaunay_epts
            delaunay_others = self.resolution.delaunay_others
            ptset = set(tuple(v) for v in delaunay_pts)
            assert len(ptset) == len(
                delaunay_pts), "Duplicate points! %d unique / %d" % (
                    len(ptset), len(delaunay_pts))
            glDisable(GL_LIGHTING)
            glDisable(GL_DEPTH_TEST)
            glColor3f(0, 0, 0)
            glLineWidth(1.0)
            import random
            for s in delaunay.simplices:
                """
                glBegin(GL_LINE_LOOP)
                for v in s:
                    glVertex3fv(delaunay_pts[v])
                glEnd()
                """
                centroid = vectorops.div(
                    vectorops.add(*[delaunay_pts[v] for v in s]), len(s))
                assert len(s) == 3
                glBegin(GL_LINES)
                for i, v in enumerate(s):
                    neighbors = [w for j, w in enumerate(s) if i < j]
                    for w in neighbors:
                        if (v in delaunay_epts and w in delaunay_others) or (
                                w in delaunay_epts and v in delaunay_others):
                            glColor3f(1, 1, 1)
                        else:
                            glColor3f(0, 0, 0)
                        glVertex3fv(
                            vectorops.interpolate(delaunay_pts[v], centroid,
                                                  0.1))
                        glVertex3fv(
                            vectorops.interpolate(delaunay_pts[w], centroid,
                                                  0.1))
                glEnd()
            glColor3f(0, 1, 0)
            glPointSize(5.0)
            glBegin(GL_POINTS)
            for v in delaunay_epts:
                glVertex3fv(delaunay_pts[v])
            glEnd()
            glColor3f(0, 0, 1)
            glPointSize(5.0)
            glBegin(GL_POINTS)
            for v in delaunay_others:
                glVertex3fv(delaunay_pts[v])
            glEnd()
            glEnable(GL_DEPTH_TEST)

        #draw workspace graph
        if self.drawWorkspaceRoadmap:

            def drawWorkspaceRoadmap(orientation=None):
                G = self.resolution.Gw
                if orientation is not None:
                    Rclosest, G = self.resolution.extractOrientedSubgraph(
                        orientation)
                    print G.number_of_nodes()
                if not self.resolution.hasResolution():
                    glDisable(GL_LIGHTING)
                    glPointSize(5.0)
                    glColor3f(1, 0, 0)
                    glBegin(GL_POINTS)
                    for n, d in G.nodes_iter(data=True):
                        glVertex3fv(self.workspaceToPoint(d['params']))
                    glEnd()
                    glColor3f(1, 0.5, 0)
                    glBegin(GL_LINES)
                    for (i, j) in G.edges_iter():
                        glVertex3fv(self.workspaceToPoint(G.node[i]['params']))
                        glVertex3fv(self.workspaceToPoint(G.node[j]['params']))
                    glEnd()
                else:
                    #maxn = max(len(d['qlist']) for n,d in G.nodes_iter(data=True))
                    #maxe = max(len(d['qlist']) for i,j,d in G.edges_iter(data=True))
                    #maxn = max(maxn,1)
                    #maxe = max(maxe,1)
                    glDisable(GL_LIGHTING)
                    glPointSize(5.0)
                    glBegin(GL_POINTS)
                    for n, d in G.nodes_iter(data=True):
                        if not self.resolution.isResolvedNode(n):
                            continue
                        #u = float(len(d['qlist']))/float(maxn)
                        #nsubset = sum(1 for iq in d['qlist'] if iq in self.rr.Qsubgraph)
                        #if nsubset > 1:
                        #   glColor3f(1,0,1)
                        #else:
                        #   glColor3f(u,nsubset*0.5,0)
                        glColor3f(1, 0.5, 0)
                        glVertex3fv(self.workspaceToPoint(d['params']))
                    glEnd()
                    glBegin(GL_LINES)
                    for (i, j, d) in G.edges_iter(data=True):
                        if not self.resolution.isResolvedNode(
                                i) or not self.resolution.isResolvedNode(j):
                            continue
                        #nsubset = sum(1 for (ia,ib) in d['qlist'] if (ia in self.Qsubgraph and ib in self.Qsubgraph))
                        #u = float(len(d['qlist']))/float(maxe)
                        r, g, b = 1, 1, 0
                        if not self.resolution.isResolvedEdge(i, j):
                            r, g, b = 1, 0, 1
                        else:
                            qd = self.robot.distance(G.node[i]['config'],
                                                     G.node[j]['config'])
                            wd = self.resolution.workspaceDistance(
                                G.node[i]['params'], G.node[j]['params'])
                            u = 1.0 - math.exp(-max(0.0, 2.0 * qd / wd - 1.0))
                            if u > 0.8:
                                r, g, b = 1, 1.0 - u * 5.0, 0.0
                            else:
                                r, g, b = u / 0.8, 1, 0.0
                        #assert (nsubset >=1) == self.resolution.isResolvedEdge(i,j),"Mismatch between Qsubgraph and resolution?"
                        glColor3f(r, g, b)
                        glVertex3fv(self.workspaceToPoint(G.node[i]['params']))
                        glVertex3fv(self.workspaceToPoint(G.node[j]['params']))
                    glEnd()
                    """
                    glEnable(GL_LIGHTING)
                    q0 = self.robot.getConfig()
                    for iw,d in self.rr.Gw.nodes_iter(data=True):
                        qs = [iq for iq in d['qlist'] if iq in self.rr.Qsubgraph]
                        if len(qs) > 1:
                            for iq in qs:
                                self.robot.setConfig(self.rr.Gq.node[iq]['config'])
                                self.robot.drawGL()
                    self.robot.setConfig(q0)
                    glDisable(GL_LIGHTING)
                    """

            if task.numConstraints > 3:
                if not hasattr(self, 'roadmapDisplayLists_by_orientation'):
                    self.roadmapDisplayLists_by_orientation = dict()
                    self.lastROrientation = None
                    self.lastRMbest = None

                orientation = self.xformWidget.get()[0]
                if orientation != self.lastROrientation:
                    mbest = self.resolution.closestOrientation(orientation)
                    self.lastRMbest = mbest
                else:
                    mbest = self.lastRMbest
                if mbest not in self.roadmapDisplayLists_by_orientation:
                    print "Drawing new display list for moment", mbest
                    self.roadmapDisplayLists_by_orientation[
                        mbest] = CachedGLObject()
                self.roadmapDisplayLists_by_orientation[mbest].draw(
                    drawWorkspaceRoadmap, args=(orientation, ))
            else:
                #there looks to be a bug in GL display lists for drawing lines...
                #self.roadmapDisplayList.draw(drawWorkspaceRoadmap)
                drawWorkspaceRoadmap()
        else:
            #render boundaries only
            def drawDisconnections(orientation=None):
                bmin, bmax = self.resolution.domain
                active = [
                    i for i, (a, b) in enumerate(zip(bmin, bmax)[:3]) if b != a
                ]
                if self.useboundary == None:
                    self.useboundary = (len(active) == 2)
                verts, faces = self.resolution.computeDiscontinuities(
                    self.useboundary, orientation)

                if len(active) == 3:
                    glEnable(GL_LIGHTING)
                    glEnable(GL_BLEND)
                    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
                    glDisable(GL_CULL_FACE)
                    #if self.walk_workspace_path != None:
                    #   gldraw.setcolor(1,0,1,0.25)
                    #else:
                    #   gldraw.setcolor(1,0,1,0.5)

                    for tri in faces:
                        tverts = [verts[v] for v in tri]
                        centroid = vectorops.div(vectorops.add(*tverts),
                                                 len(tri))
                        params = [
                            (x - a) / (b - a)
                            for (x, a,
                                 b) in zip(centroid, self.resolution.domain[0],
                                           self.resolution.domain[1])
                        ]
                        if self.walk_workspace_path != None:
                            gldraw.setcolor(params[0], params[1], params[2],
                                            0.25)
                        else:
                            gldraw.setcolor(params[0], params[1], params[2],
                                            1.0)
                        gldraw.triangle(*tverts)
                    glEnable(GL_CULL_FACE)
                else:
                    glDisable(GL_LIGHTING)
                    glEnable(GL_BLEND)
                    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
                    glColor4f(1, 0, 1, 0.5)

                    glLineWidth(4.0)
                    glBegin(GL_LINES)
                    for s in faces:
                        spts = verts[s[0]], verts[s[1]]
                        glVertex3f(spts[0][0], 0, spts[0][1])
                        glVertex3f(spts[1][0], 0, spts[1][1])
                    glEnd()
                    glLineWidth(1.0)

            #draw stabbing lines
            """
            glDisable(GL_LIGHTING)
            glColor3f(1,0,0)
            glBegin(GL_LINES)
            for (i,j,d) in self.resolution.Gw.edges_iter(data=True):
                if self.resolution.isResolvedEdge(i,j):
                    continue
                if not self.resolution.isResolvedNode(i) or not self.resolution.isResolvedNode(j):
                    continue
                glVertex3fv(self.workspaceToPoint(self.resolution.Gw.node[i]['params']))
                glVertex3fv(self.workspaceToPoint(self.resolution.Gw.node[j]['params']))
            glEnd()
            """
            if task.numConstraints > 3:
                if not hasattr(self,
                               'disconnectionDisplayLists_by_orientation'):
                    self.disconnectionDisplayLists_by_orientation = dict()
                    self.lastOrientation = None
                    self.lastMbest = None

                orientation = self.xformWidget.get()[0]
                if orientation != self.lastOrientation:
                    mbest = self.resolution.closestOrientation(orientation)
                    self.lastMbest = mbest
                else:
                    mbest = self.lastMbest
                if mbest not in self.disconnectionDisplayLists_by_orientation:
                    self.disconnectionDisplayLists_by_orientation[
                        mbest] = CachedGLObject()
                self.disconnectionDisplayLists_by_orientation[mbest].draw(
                    drawDisconnections, args=(mbest, ))
            else:
                self.disconnectionDisplayList.draw(drawDisconnections)

            bmin, bmax = self.resolution.domain

            #draw workspace bound
            glDisable(GL_LIGHTING)
            glColor3f(1, 0.5, 0)
            gldraw.box(bmin[:3], bmax[:3], lighting=False, filled=False)

        GLWidgetPlugin.display(self)