简体   繁体   中英

Python, sort a list of objects by lowest sub-object attribute

I'm trying to implement depth ordering of surfaces and points but I'm unsure how to do it. I have a Point class which basically contains x,y,z coordinates and these are used to define the center point of circles, the ends of lines and the corners of surfaces (tris and quads) so we have:

class Point(object):
    def __init__(self, x, y z):
        self.x = x
        self.y = y
        self.z = z

class Circle(object):
    def __init__(self, center, radius):
        #center is a point
        self.point_array = [center]
        self.radius = radius

class Line(object):
    def __init__(self, pos1, pos2):
        #pos1, pos2 are points
        self.point_array = [pos1, pos2]

class Tri(object):
    def __init__(self, pos1, pos2, pos3):
        #pos's are Points
        self.point_array = [pos1, pos2, pos3]

class Quad(object):
    def __init__(self, pos1, pos2, pos3, pos4):
        #you get the idea by now...
        self.point_array = [point1, point2, point3, point4]

Now I'm culling the ones not visible and appending the objects to a list to the draw to the screen. What I need to do now is sort the list of objects by each objects lowest z-coordinate but I'm unsure how to go about this.

Create a sort function that extracts the lowest z coordinate per object:

def lowest_z(obj):
    return min(p.z for p in obj.point_array)

sorted(list_of_objects, key=lowest_z)

You can inline that function by using a lambda function, of course:

sorted(list_of_objects, key=lambda o: min(p.z for p in o.point_array))

This assumes there are no Point objects in the list your are sorting, only Quad , Tri , Line and Circle objects.

It could be helpful to add a method to your objects that returns the lowest z coordinate; that way you could adjust how that point is determined based on the type of object; that way your Cicle class, with only a radius and central point, can still calculate the minimum z based on that information:

class Shape(object):
    # subclasses must provide a point_array instance attribute
    @property
    def lowest_z(self):
        return min(p.z for p in self.point_array)

class Line(Shape):
    def __init__(self, pos1, pos2):
        #pos1, pos2 are points
        self.point_array = [pos1, pos2]

class Circle(Shape):
    def __init__(self, center, radius):
        #center is a point
        self.point_array = [center]
        self.radius = radius

    @property
    def lowest_z(self):
        return self.point_array[0].z - self.radius

# etc.

then sort by the point_array property:

sorted(list_of_objects, key=lambda o: o.lowest_z)

or, using operator.attrgetter() :

from operator import attrgetter

sorted(list_of_objects, key=attrgetter('lowest_z'))

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM