Handling related generic type parameters
You don't need the type parameter on IOrderable:

  public interface IOrderable
  {
    double Ordering();
  }




I don't like that you sort the source vector without notifying the client. In this way mysterious things are going on and the method does more than one thing. At least you should have a flag argument that lets the client determine if the source should be sorted or not before grouping:

public static IEnumerable&lt;IGGrouping&lt;T&gt;&gt; GroupBy&lt;TG, T&gt;(this IEnumerable&lt;T&gt; src, bool sortBeforeGrouping = false) where TG : IGGrouping&lt;T&gt;, new() where T : IOrderable
{
  var groups = new List&lt;IGGrouping&lt;T&gt;&gt;();

  ...
}


Alternatively you should rename the method to SortAndGroupBy(...). But I would let it total up to the client if the source should be sorted or not.



I think the inner of the internal Add(...) function can be simplified a bit:

  void Add(T aT)
  {
    var group = groups.FirstOrDefault(g =&gt; g.BelongsToGroup(aT));
    if (group == null)
    {
      group = new TG();
      groups.Add(group);
    }
    group.Add(aT);
  }




On way to get rid of the custom interfaces is to let the group type implement ICollection&lt;T&gt; and then inject the belongsToGroup function:

public static IEnumerable&lt;TKey&gt; GroupBy&lt;TKey, TElement&gt;(this IEnumerable&lt;TElement&gt; source, Func&lt;TElement, TKey, bool&gt; belongsToGroup) where TKey : ICollection&lt;TElement&gt;, new()
{
  return source.Aggregate(new List&lt;TKey&gt;(), (groups, e) =&gt;
  {
    TKey group = groups.FirstOrDefault(g =&gt; belongsToGroup(e, g));
    if (group == null)
    {
      group = new TKey();
      groups.Add(group);
    }
    group.Add(e);
    return groups;
  });

}


Usage

  Func&lt;Rectangle, RectangleGroup, bool&gt; belongsToGroup = (r, gr) =&gt; gr.BelongsToGroup(r);
  var midPoints = list.OrderBy(r =&gt; r).GroupBy(belongsToGroup).Select(gr =&gt; gr.Middle());
  foreach (var middle in midPoints)
  {
    Console.WriteLine(middle);
  }




If that isn't good enough then you can inject the addToGroup function too:

public static IEnumerable&lt;TKey&gt; GroupBy&lt;TKey, TElement&gt;(this IEnumerable&lt;TElement&gt; source, Func&lt;TElement, TKey, bool&gt; belongsToGroup, Action&lt;TElement, TKey&gt; addToGroup) where TKey : new()
{
  List&lt;TKey&gt; groups = new List&lt;TKey&gt;();

  foreach (TElement element in source)
  {
    TKey group = groups.FirstOrDefault(g =&gt; belongsToGroup(element, g));
    if (group == null)
    {
      group = new TKey();
      groups.Add(group);
    }

    addToGroup(element, group);
  }

  return groups;
}


Usage

  Func&lt;Rectangle, RectangleGroup, bool&gt; belongsToGroup = (r, gr) =&gt; gr.BelongsToGroup(r);
  Action&lt;Rectangle, RectangleGroup&gt; adder = (r, gr) =&gt; gr.Add(r);
  var midPoints= list.OrderBy(r =&gt; r).GroupBy(belongsToGroup, adder).Select(gr =&gt; gr.Middle());
  foreach (var middle in midPoints)
  {
    Console.WriteLine(middle);
  }