[C#] How do I include other classes in an IComparer?

Started by
2 comments, last by Gorg 13 years ago
If I would like to compare a list of quadrangles by draw depth then I'm currently using the following Comparer:



class SortDrawAscending : IComparer<Quadrangle>
{
static IComparer<Quadrangle> comparer = new SortDrawAscending();

public int Compare(Quadrangle a, Quadrangle b)
{
return Comparer<int>.Default.Compare(a.DrawDepth, b.DrawDepth);
}

public static IComparer<Quadrangle> Comparer
{
get { return comparer; }
}
}


However, if I wish to sort each quadrangle by its distance from the camera then I would need to include the camera class in the comparer:



class SortDrawDistanceDescending : IComparer<Quadrangle>
{
static IComparer<Quadrangle> comparer = new SortDrawDistanceDescending();

public int Compare(Quadrangle a, Quadrangle b)
{
return Comparer<int>.Default.Compare(
Vector3.Dot(a.Position - camera.Position, camera.Forward),
Vector3.Dot(b.Position - camera.Position, camera.Forward)
);
}


public static IComparer<Quadrangle> Comparer
{
get { return comparer; }
}
}


How can this be achieved so I can easily sort a list of quadrangles by their distance from the camera?

I'm currently using the following line to sort all the quadrangles:


Array.Sort(transparentQuadrangles, 0, numTransparentQuadrangles, SortDrawDistanceDescending.Comparer);


If a more suitable method can be used to avoid recalculating the distance for each compare then that would be great also.
Advertisement
Well the obvious answer would be to give your class a constructor that accepts a camera and use new SortDrawDistanceDescending(camera) instead of a static property.
Wouldn't the comparer still be recalculating



Vector3.Dot(a.Position - camera.Position, camera.Forward)
Vector3.Dot(b.Position - camera.Position, camera.Forward)


each time two quadrangles are compared though? How can I make sure the values are only calculated once per quadrangle per frame?

EDIT:

I created a property called DrawDepth and assigned it a value before hand:



// Calculate the quadrangles position from the camera
for (int i = 0; i < numTransparentQuadrangles; ++i)
{
transparentQuadrangles.DrawDepth = Vector3.Dot(transparentQuadrangles.Position - camera.Position, camera.Forward);
}


Now the Comparer is as follows:



class SortDrawDistanceDescending : IComparer<Quadrangle>
{
static IComparer<Quadrangle> comparer = new SortDrawDistanceDescending();

public int Compare(Quadrangle a, Quadrangle b)
{
return Comparer<float>.Default.Compare(a.DrawDepth, b.DrawDepth);
}

public static IComparer<Quadrangle> Comparer
{
get { return comparer; }
}
}


but this still sorts them in ascending order and not descending...

EDIT2:



class SortDrawDistanceDescending : IComparer<Quadrangle>
{
static IComparer<Quadrangle> comparer = new SortDrawDistanceDescending();

public int Compare(Quadrangle a, Quadrangle b)
{
if (a.DrawDepth < b.DrawDepth)
{
return 1;
}
else if (a.DrawDepth > b.DrawDepth)
{
return -1;
}
else
{
return 0;
}
}

public static IComparer<Quadrangle> Comparer
{
get { return comparer; }
}
}


Problem solved.
Since you already have an ascending comparer, you can also just create a new comparer that inverts the comparison of an existing one.



public class ReverseOrderComparer<T> : IComparer<T>
{
public ReverseOrderComparer(IComparer<T> comparer)
{
this.comparer = comparer;
}

IComparer<T> comparer;
public int Compare(T x, T y)
{
return comparer.Compare(y, x);
}
}


You use it like this:



List<int> i = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9 };

i.Sort(new ReverseOrderComparer<int>(Comparer<int>.Default));

This topic is closed to new replies.

Advertisement