I'm trying to use LibGit2Sharp to recreate the functionality of git show-brach --independent which, according to the docs does this: Among the <reference>s given, display only the ones that cannot be reached from any other <reference>.
My best attempt so far is the following:
List<Commit> GetIndependent(IRepository repo, IEnumerable<Commit> commits)
{
var indep = new List<Commit>();
foreach (var commit in commits)
{
if (repo.Commits.QueryBy(new CommitFilter
{
FirstParentOnly = false,
IncludeReachableFrom = commit,
ExcludeReachableFrom = commits.Where(x => x.Equals(commit) == false)
}).Any())
{
indep.Add(commit);
}
}
return indep;
}
Unfortunately, this becomes astronomically slow as the amount of history increases. It's actually much faster for me to exec git directly, parse the output, and have LibGit2Sharp lookup the resulting SHAs than to use the above code. I assume this has to do with some optimization that Git has but LibGit2 does not. Is this even doing what I want? If so, is there a better way to achieve this in LibGit2Sharp?
I finally found a better way that utilizes merge bases, thanks to this question pointing me in the right direction.
Here's the new code:
/// <summary>
/// Implementation of `git show-branch --indepenent`
///
/// "Among the <reference>s given, display only the ones that cannot be reached from any other <reference>"
/// </summary>
/// <param name="commitsToCheck"></param>
/// <returns></returns>
private List<Commit> GetIndependent(IRepository repo, IEnumerable<Commit> commitsToCheck)
{
var commitList = commitsToCheck.ToList();
for (var i = commitList.Count - 1; i > 0; --i)
{
var first = commitList[i];
for (var j = commitList.Count - 1; j >= 0; --j)
{
if (i == j) continue;
var second = commitList[j];
var mergeBase = repo.ObjectDatabase.FindMergeBase(first, second);
if (first.Equals(mergeBase))
{
// First commit (i) is reachable from second (j), so drop i
commitList.RemoveAt(i);
// No reason to check anything else against this commit
j = -1;
} else if (second.Equals(mergeBase))
{
// Second (j) is reachable from first, so drop j
commitList.RemoveAt(j);
// If this was at a lower index than i, dec i since we shifted one down
if (j < i)
{
--i;
}
}
}
}
return commitList;
}
Related
Hi guys im trying to learn permutation and recurtion. And im looking for a way how can i use bought at the same time.
MAIN:
namespace Recursive_Permutation
{
class Program
{
static void Main(string[] args)
{
int[] array = new int[5] { 0, 0, 0, 0, 0 };
CalPermutations CP = new CalPermutations();
CP.Run(array, array.Length-1);
}
}
}
Here is my Simple code:
namespace Recursive_Permutation
{
public class CalPermutations
{
public int Run(int[] array,int indexer)
{
if (indexer > array.Length)
{
return 1;
}
else
{
for (int i = 0; i <= array.Length; i++)
{
array[indexer] = i;
Display(array);
}
Run(array, indexer-1);
}
return indexer;
}
public void Display(int[] array)
{
foreach (int num in array)
{
Console.Write(num);
}
Console.WriteLine();
}
}
}
And here is the Output of the program:
Question:
it might be simple to other but im kind of confuse now in how can i manipulate it that it still count the first digit (position [0]) 1 to 5 and go next position and (position 1) and add 1 and go back to [0] and start count again till it reaches 5.
i hope that my explanation is understandable.. thx.
I put together this simpler example of using recursion and permutation. It uses strings internally, but produces the same result.
Its for proof of concept only, since nobody will us recursion for this simple stuff in a professional environment. Recursion can have a big memory impact, but makes describing some problems in a simple way possible.
If I had to choose between iterative and recursive solutions, I would take the iterative one most of the time.
// Main entrance
public void DoStuff()
{
// define variations
List<string> possibilities = new List<string>() { "0", "1", "2", "3", "4", "5" };
// resultlist, will be filled later
List<string> permutations = new List<string>();
// how many values will be taken from the possibilities
int digits = 5;
//do the work
Permute(permutations, possibilities, digits, "");
// display the work
foreach (var item in permutations)
{
Console.WriteLine(item);
}
}
/// <summary>
/// generates a List of permuted strings
/// </summary>
/// <param name="permutations">resultlist</param>
/// <param name="possibilities">possible values of the digit</param>
/// <param name="digitsLeft">how many digits shall be appended</param>
/// <param name="current">the current value of the unfinished result</param>
private void Permute(List<string> permutations, List<string> possibilities, int digitsLeft, string current)
{
// uncomment to see how it works in detail
//Console.WriteLine("step:"+current);
// most important: define Stop conditions for the recursion
// safety stop
if (digitsLeft < 0)
{// end of digits :), normally we never end up here
return;
}
// normal stop
if (digitsLeft == 0)
{// normal endpoint, add the found permutation to the resultlist
permutations.Add(current);
return;
}
// now prepare the recursion, try each possibility
foreach (var item in possibilities)
{
// digitsLeft need to be decreased, since we add a concrete digit to the current value (current+item)
// important: (current + item) generates a new string in memory, the old values won't be touched, permutations possibilities are references, so no memory impact here
Permute(permutations, possibilities, digitsLeft - 1, current + item);
}
}
Update: added comments on each method as per comment.
public class Program
{
public static void Main(string[] args)
{
int[] array = new int[] { 0, 0, 0, 0, 0};
CalPermutations CP = new CalPermutations();
CP.Run(array, 0);
}
}
public class CalPermutations
{
// Prints all the permutations of array, starting at the specified index.
public void Run(int[] array, int indexer)
{
if (indexer < 0 || indexer >= array.Length)
return;
// Keep [0, indexer] combination constant, change combination on right i.e. (indexer, Array.length).
Run(array, indexer+1);
// All the elements on right have finished, increment current element.
array[indexer]++;
// Check if current combination is STILL valid.
if(array[indexer] <= array.Length)
{
// since current combination is still valid, display it, and execute the process again on the new combination.
Display(array);
Run(array, indexer);
}
else
{
// Since current element is out of range, reset it.
array[indexer] = 1;
}
}
// Prints all the elements in array.
public void Display(int[] array)
{
foreach (int num in array)
Console.Write(num);
Console.WriteLine();
}
}
this is my very first post here on StackOverflow so please tell me if I did anything wrong, also english is not my native language, forgive me if there is any gramatical errors.
My question is how can I permutate the items of an array of type "Location", I need to get all possible permutations of waypoints given by the user to then calculate the best route based on time or distance. (I don't want to use the normal route calculation)
I've searched for algorithms but all of them when I put the array of type "Location[]" in the function's parameter I get the error that the object needs to be IEnumerable and I don't know how to convert to that if is even possible, I never worked with IEnumerable.
If it is of any help this is my code for calculating the route:
//Gets the waypoints from a listBox provided by the user, "mode" selects between best time and best distance
//backgroundworker so the UI dont freezes, and return the optimal waypoint order
public Location[] CalcularRota(Location[] waypoints, int mode, BackgroundWorker work, DoWorkEventArgs e)
{
//Declarations
string origem = "";
string destino = "";
Rota[] prop = new Rota[100]; //this index is the number of times the algorithm will be executed, more equals accuracy but much more time to complete
Rota bestDist = new Rota();
Rota bestTime = new Rota();
DirectionService serv = new DirectionService();
DirectionRequest reqs = new DirectionRequest();
DirectionResponse resp;
Random rnd = new Random();
Location[] rndWays;
int dist = 0;
int ti = 0;
bestDist.Distance = 1000000000; //put higher values for the first comparation to be true (end of code)
bestTime.Time = 1000000000;
if (waypoints != null)
{
reqs.Sensor = false;
reqs.Mode = TravelMode.driving;
for (int i = 0; i < prop.Length; i++) //initializes prop
prop[i] = new Rota();
for (int i = 0; i < prop.Length; i++)
{
rndWays = waypoints.OrderBy(x => rnd.Next()).ToArray(); //randomizes the order, I want to get all permutations and then test
//but I dont know how so I've been using randomized
dist = ti = 0;
origem = prop[0].ToString(); //save this particular waypoint's origin and destination
destino = prop[1].ToString();
reqs.Origin = origem;
reqs.Destination = destino;
if (waypoints.Length > 0)
reqs.Waypoints = rndWays;
resp = serv.GetResponse(reqs); //request the route with X order of waypoints to google
if (resp.Status == ServiceResponseStatus.Ok) //wait the response otherwise the program crashes
{
for (int j = 0; j < resp.Routes[0].Legs.Length; j++) //gets the distance and time of this particular order
{
ti += int.Parse(resp.Routes[0].Legs[j].Duration.Value);
dist += int.Parse(resp.Routes[0].Legs[j].Distance.Value);
}
}
prop[i].Origem = origem; //saves this waypoints order details for further comparison
prop[i].Destino = destino;
prop[i].Distance = dist;
prop[i].Time = ti;
prop[i].Order = rndWays;
work.ReportProgress(i); //report the progress
}
for (int i = 0; i < prop.Length; i++) //gets the best distance and time
{
if (bestDist.Distance > prop[i].Distance)
{
bestDist.Distance = prop[i].Distance;
bestDist.Time = prop[i].Time;
bestDist.Order = prop[i].Order;
bestDist.Origem = prop[i].Origem;
bestDist.Destino = prop[i].Destino;
}
if (bestTime.Time > prop[i].Time)
{
bestTime.Distance = prop[i].Distance;
bestTime.Time = prop[i].Time;
bestTime.Order = prop[i].Order;
bestTime.Origem = prop[i].Origem;
bestTime.Destino = prop[i].Destino;
}
}
if (bestDist.Order == bestTime.Order) //if the same waypoint order has the same time and distance
return bestDist.Order; // returns whatever bestDist.Order or bestTime.Order
else if (bestDist.Order != bestTime.Order) //if different returns corresponding to the mode selected
{
if (mode == 1) return bestDist.Order;
if (mode == 2) return bestTime.Order;
}
}
return null;
}
What I want is to permutate the waypoints given and test each permutation, I've been struggling with this for a time, if u guys could help me with any way possible would be great.
Ty.
EDIT.
I found this function here on StackOverflow:
public static bool NextPermutation<T>(T[] elements) where T : IComparable<T>
{
var count = elements.Length;
var done = true;
for (var i = count - 1; i > 0; i--)
{
var curr = elements[i];
// Check if the current element is less than the one before it
if (curr.CompareTo(elements[i - 1]) < 0)
{
continue;
}
// An element bigger than the one before it has been found,
// so this isn't the last lexicographic permutation.
done = false;
// Save the previous (bigger) element in a variable for more efficiency.
var prev = elements[i - 1];
// Have a variable to hold the index of the element to swap
// with the previous element (the to-swap element would be
// the smallest element that comes after the previous element
// and is bigger than the previous element), initializing it
// as the current index of the current item (curr).
var currIndex = i;
// Go through the array from the element after the current one to last
for (var j = i + 1; j < count; j++)
{
// Save into variable for more efficiency
var tmp = elements[j];
// Check if tmp suits the "next swap" conditions:
// Smallest, but bigger than the "prev" element
if (tmp.CompareTo(curr) < 0 && tmp.CompareTo(prev) > 0)
{
curr = tmp;
currIndex = j;
}
}
// Swap the "prev" with the new "curr" (the swap-with element)
elements[currIndex] = prev;
elements[i - 1] = curr;
// Reverse the order of the tail, in order to reset it's lexicographic order
for (var j = count - 1; j > i; j--, i++)
{
var tmp = elements[j];
elements[j] = elements[i];
elements[i] = tmp;
}
// Break since we have got the next permutation
// The reason to have all the logic inside the loop is
// to prevent the need of an extra variable indicating "i" when
// the next needed swap is found (moving "i" outside the loop is a
// bad practice, and isn't very readable, so I preferred not doing
// that as well).
break;
}
// Return whether this has been the last lexicographic permutation.
return done;
}
The usage is:
NextPermutation(array);
Doing this and putting my array (rndWays) as overload I get the following error:
The type 'Google.Maps.Location' cannot be used as type parameter 'T' in the generic type or method 'Form1.NextPermutation< T >(T[])'. There is no implicit reference conversion from 'Google.Maps.Location' to 'System.IComparable< Google.Maps.Location >'.
The problem is that Location does not implement the IComparable interface.
Change:
public static bool NextPermutation<T>(T[] elements) where T : IComparable<T>
to:
public static bool NextPermutation(Location[] elements)
And replace each CompareTo() with your own comparison function.
I have a method with some loops inside:
private void RefreshListBox()
{
int i = 0, j = 0, index, count;
Boolean bl = false;
index = listBox1.SelectedIndex;
count = windowsHandles.Count;
for (i = 0; i < count; i++)
{
if (!Constants.IsWindow(windowsHandles[j]))
{
windowsHandles.RemoveAt(j);
windowsText.RemoveAt(j);
windowsBitmaps.RemoveAt(j);
rectanglesList.RemoveAt(j);
isCroppedList.RemoveAt(j);
canDrawNormallyList.RemoveAt(j);
if (j < index)
{
index--;
}
else if (j == index)
{
}
else
{
}
}
else { j++; }
}
if (index == windowsHandles.Count)
{
index--;
}
for (int x = 0; x < windows.Count; x++)
{
for (j = 0; j < windowsHandles.Count; j++)
{
if (windowsHandles[j] == windows[x].Handle) { bl = true; break; }
}
if (bl == false && Constants.IsIconic(windows[x].Handle))
{
windowsHandles.Add(windows[x].Handle);
windowsText.Add(windows[x].Title);
windowsBitmaps.Add(null);
rectanglesList.Add(new Rectangle(0, 0, 0, 0));
isCroppedList.Add(false);
canDrawNormallyList.Add(false);
}
bl = false;
}
if (windowsHandles.Count > 0 && index == -1)
{
index = 0;
}
if (listBox1.Items.Count > 0) { listBox1.Items.Clear(); }
for (i = 0; i < windowsHandles.Count; i++)
{
listBox1.Items.Add(windowsText[i]);
}
if (index != -1)
{
listBox1.SelectedIndex = index;
}
textBoxIndex.Text = windowsHandles.Count.ToString();
drawPicBox(index);
}
private void listBox1_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
var item = listBox1.IndexFromPoint(e.Location);
if (item >= 0)
{
listBox1.SelectedIndex = item;
drawPicBox(listBox1.SelectedIndex);
}
}
}
The problem start when it's getting to the loop at this line:
for (int x = 0; x < windows.Count; x++)
The Count of windows List is 21 in this case.
Then it's entering first time but if i put a break point on this line and click continue all the time i see that x is 0.
When i put a break point on this line:
windowsHandles.Add(windows[x].Handle);
It stop there each time i click on continue but then i see that the variable x it's value is 20 all the time. And the List windowsHandles contain only 1 item.
Then i put a break point on the line:
listBox1.Items.Add(windowsText[i]);
And when i make continue it stop on the line but even if it does the line there are no items on the listBox1.
If i don't use any break points and just make continue to let it run it's never show/get to the form it's like stuck somewhere in this method can't figure out where and why.
In the constructor i'm calling two methods.
First GetWindows then RefreshList
GetWindows();
RefreshListBox();
In GetWindows:
private List<Window> windows = new List<Window>();
private void GetWindows()
{
windows = new List<Window>();
Constants.EnumWindows(Callback, 0);
}
private bool Callback(IntPtr hwnd, int lParam)
{
try
{
if (this.Handle != hwnd && (Constants.GetWindowLongA(hwnd, Constants.GWL_STYLE) & Constants.TARGETWINDOW) == Constants.TARGETWINDOW)
{
StringBuilder sb = new StringBuilder(100);
Constants.GetWindowText(hwnd, sb, sb.Capacity);
Window t = new Window();
t.Handle = hwnd;
t.Title = sb.ToString();
windows.Add(t);
}
}
catch(Exception err)
{
StreamWriter w = new StreamWriter(#"e:\errors.txt");
w.Write(err.ToString());
w.Close();
}
return true;
}
In the end of the GetWindows operation i see that windows contain 21 items.
The problem seems to be somewhere in the RefreshList method but i can't figure out where is the problem.
The goal of all this in the end is to add all the items in windowsText to the listBox1.
I just noticed something else:
windowsHandles.Add(windows[x].Handle);
windowsText.Add(windows[x].Title);
windowsBitmaps.Add(null); // <------
rectanglesList.Add(new Rectangle(0, 0, 0, 0));
isCroppedList.Add(false);
canDrawNormallyList.Add(false);
Is this a correct guess - The reason you're adding a null to windowsBitmaps is so that all six of these collections stay in sync. The items across each collection are related somehow if they have the same index.
It would be much easier if you created one class with properties for windowsHandle, windowsText, windowsBitmaps, etc, and then had a collection of that type. That way instead of managing six collections and trying to keep them in sync you only have one.
This isn't a direct answer, but I think it's a necessary step if you're going to get to the answer: break this up into smaller methods.
You could start with the loops. You could put each of those loops in a separate method and name the method very clearly so that it indicates what it's doing and what it's doing it to. (It might even be worthwhile to put some of the functions in separate classes.)
One of the reasons is that no one - not you or the programmer who works on this later - can expect to be able to hold the complexity of one long method in their head and follow through 'what if this happens, what if that happens.'
Same thing for variable names. It's okay if variable names and method names are long if they help make it clear what they are for. I find myself seeing x and having to scroll back up to see what x is, and then I lose track of where I was.
I know that's not a direct answer. But if you do that then the answer will likely be easier to see. If you break it up into smaller functions (or even write separate classes) then you can also write unit tests. That way instead of running the whole thing from top to bottom you can just test one part at a time.
More directly related
Somewhat more directly related to the code: If you do need to iterate through a collection and possibly remove items as you go, it's better to start from the Count and work backwards. That way your index stays in bounds.
An even easier way is to use Linq to query the elements and create a new collection. For example
Thing[] arrayOfSomething = GetAnArrayOfSomething();
var arrayWithElementsRemoved = arrayOfSomething.Where(
item => !item.DeleteThisOne).ToArray();
The second statement takes an array of Thing and returns a new array containing only the ones where DeleteThisOne is false. It's all in one statement, no looping or bounds to worry about.
I have a very simple algorithm that clusters blobs based on their x and y distance to each other. I ported the same to use Parallel.For with thread-local data but the results were incorrect. In other words, I may not have used synchronization properly to isolate each thread.
Simply cannot figure out why the results of the two implementations are different. Any thoughts would be appreciated.
I wanted to post fully compilable code but the objects used are too tightly integrated to the project context. Since the algorithm is very simeple, hopefully that will not get in the way.
Class level declerations:
/// <summary>
/// Contains the master blobl collection to be clustered.
/// </summary>
public List<Blob> Blobs { get; private set; }
/// <summary>
/// List of clusters to be computed.
/// </summary>
public List<Cluster> Clusters { get; private set; }
Linear Example (Works fine):
Cluster cluster = null;
for (int i = 0; i < this.Blobs.Count; i++)
{
cluster = new Cluster();
cluster.Id = i;
if (this.Blobs [i].ClusterId == 0)
{
cluster.Blobs.Add(this.Blobs [i], i);
for (int j = 0; j < this.Blobs.Count; j++)
{
if (this.Blobs [j].ClusterId == 0)
{
if (this.Blobs [i].Rectangle.IntersectsWith(this.Blobs [j].Rectangle))
{
cluster.Blobs.Add(this.Blobs [j], i);
}
else if (this.Blobs [i].Rectangle.IsCloseTo(this.Blobs [j].Rectangle, distanceThreshold))
{
cluster.Blobs.Add(this.Blobs [j], i);
}
}
}
}
if (cluster.Blobs.Count > 2)
{
this.Clusters.Add(cluster);
}
}
Parallel Port (Incorrect clusters):
System.Threading.Tasks.Parallel.For<Cluster>
(
0,
this.Blobs.Count,
new ParallelOptions() { MaxDegreeOfParallelism = degreeOfParallelism },
() => new Cluster(),
(i, loop, cluster) =>
{
cluster.Id = i;
if (this.Blobs [i].ClusterId == 0)
{
cluster.Blobs.Add(this.Blobs [i], i);
for (int j = 0; j < this.Blobs.Count; j++)
{
if (this.Blobs [j].ClusterId == 0)
{
if (this.Blobs [i].Rectangle.IntersectsWith(this.Blobs [j].Rectangle))
{
cluster.Blobs.Add(this.Blobs [j], i);
}
else if (this.Blobs [i].Rectangle.IsCloseTo(this.Blobs [j].Rectangle, distanceThreshold))
{
cluster.Blobs.Add(this.Blobs [j], i);
}
}
}
}
return (cluster);
},
(cluster) =>
{
lock (this.Clusters)
{
if (cluster.Blobs.Count > 2)
{
this.Clusters.Add(cluster);
}
}
}
);
I think your problem is misunderstanding of that “thread-local data”. According to the documentation of Parallel.For(), it's:
[…] some local state that may be shared amongst iterations that execute on the same thread.
What this means is that some iterations of your loop will share the same Cluster object, which will cause incorrect results for you. If the localInit and localFinally executed for each iteration, then they would be useless, because you could do exactly the same thing by moving their code to the beginning and end of the loop.
The reason why the delegates are there is that you can use them for optimization. With them, you don't have to access shared state (in your case this.Clusters) as often, which can improve performance.
If you don't need this optimization, don't use the two delegates and instead write the body of your loop like this:
i =>
{
var cluster = new Cluster { Id = i };
// rest of the loop here
if (cluster.Blobs.Count > 2)
{
lock (this.Clusters)
{
this.Clusters.Add(cluster);
}
}
}
(In the above code, I also switched the lock with the if as an optimization.)
If you think the optimization using thread-local data would be useful for you (i.e. it would actually speed things up), you can use it. But the data in question would have to be a list of Clusters, not just a single Cluster. Something like:
() => new List<Cluster>(),
(i, loop, clusters) =>
{
var cluster = new Cluster { Id = i };
// rest of the loop here
if (cluster.Blobs.Count > 2)
clusters.Add(cluster);
return clusters;
},
clusters =>
{
lock (this.Clusters)
{
this.Clusters.AddRange(clusters);
}
}
this is being used in a motion detection problem.
Basically, I perform a motion detection algorithm on an image, and get a list of blobs, where each blob hopefully corresponds to an object that has moved. However, we have to merge these blobs as there might be many small ones touching each other that should be one large blob.
I merge the blobs together using this algorithm.
//Expand all blobs by 1x1 to ensure that we can use intersection
//blobs is a List<blob>
foreach (Blob blob in blobs)
{
blob.BoundingBox.Inflate(1, 1);
}
bool needToRestartMerging = true;
while (needToRestartMerging == true)
{
int count = blobs.Count;
needToRestartMerging = false;
for (int i = 0; i < count - 1; i++)
{
for (int j = i + 1; j < count; j++)
{
//BoundingBox is a simple System.Drawing.Rectangle
if (blobs[i].BoundingBox.IntersectsWith(blobs[j].BoundingBox))
{
Blob newBlob = blobs[i].Merge(blobs[j]);
blobs.RemoveAt(i);
blobs.RemoveAt(j-1);
blobs.Add(newBlob);
needToRestartMerging = true;
count = blobs.Count;
}
}
}
}
This is how I merge the blobs:
/// <summary>
/// Given a Pixel Location, we resize the Blob so that it is included in the BoundingBox
/// </summary>
/// <param name="x">Pixel XCoordinate</param>
/// <param name="y">Pixel YCoordinate</param>
public void ResizeToPixelLocation(int x, int y)
{
numPixels++;
if (x >= _boundingBox.Right)
{
_boundingBox.Width = x - _boundingBox.X;
}
if (y >= _boundingBox.Bottom)
{
_boundingBox.Height = y - _boundingBox.Y;
}
if (x <= _boundingBox.Left)
{
int oldLeft = _boundingBox.Left;
int xOffset = x - _boundingBox.Left;
_boundingBox.Offset(xOffset, 0);
_boundingBox.Width += (oldLeft - x);
}
if (y <= _boundingBox.Top)
{
int oldTop = _boundingBox.Top;
int yOffset = y - _boundingBox.Top;
_boundingBox.Offset(0, yOffset);
_boundingBox.Height += (oldTop - y);
}
}
/// <summary>
/// Merge this blob with another blob
/// </summary>
/// <param name="blob2">The second blob</param>
/// <returns></returns>
public Blob Merge(Blob blob2)
{
Blob newBlob = new Blob(BoundingBox.X, BoundingBox.Y);
newBlob.ThreadID = this.ThreadID;
newBlob.numPixels = NumPixels + blob2.NumPixels;
newBlob.BoundingBox = BoundingBox;
newBlob.ResizeToPixelLocation(blob2.BoundingBox.X, blob2.BoundingBox.Y);
newBlob.ResizeToPixelLocation(blob2.BoundingBox.Right, blob2.BoundingBox.Bottom);
return newBlob;
}
I may have about 0-150 blobs in all. I'd like to know if there's a faster way to do a blob merging.
Thanks
I would suggest something along the lines of:
mergeConnected(input):
output = new RectangleSet
while input.length > 0 do
nextRect = input.pop()
intersected = output.findIntersected(nextRect)
if intersected then
output.remove(intersected)
input.push(nextRect.merge(intersected))
else
output.insert(nextRect)
done
return output
Every loop iteration either removes from output or adds to output and removes from input, so the total number of loop iterations is no larger than twice the number of output rectangles.
To improve the performance of output.findIntersected, you can represent your set of rectangles as a data structure optimized for intersection searching (as opposed to a plain list). For instance, you can keep a data structure sorted by the maximum X of your rectangles to cull several of them, and then insert rectangles sorted by minimum X. Plain classic solutions, such as kd-trees or adaptive binary trees, could also work, but the insertion/removal time might adversely affect performance.