There are some duplicate curves in a list, so how can we remove them from the list in C# script?
The classic way is to Cluster the crvs (checking start/end pts distances for a given pair within the required double loop). Then you can apply any pick rule you want (working on the items per Cluster [i.e. the Tree branch]). This works for partially overlapping Crvs as well (as is the genaral case).
OR … (general case) use this Method as Clustering criterion:
So the question is: do you have any experience with Clustering? (hard, flat for this case).
Thanks very much for your reply.
The method I used is comparing the length of these curves, and remove the duplicated curves with same length. It seems fine in my script.
That’s not a duplicate criterion by any means: Imagine 2 crvs that yield no Ccx events (are isolated) while they are exactly the same (one is duplicate of the other but in different position in space). So … are these dupes or not? Or Imagine a Curve that “contains” another (i.e. the duplicate is Trimmed).
Anyway for the approach that you have in mind do a double Loop (for (int i = 0 … ), for (int j = i+1 …)) and compare Lengths. Or - better - define some Class with proper Properties and do a single line LINQ query. But that has no rational meaning: see this stupid C# that deals with 24 crvs (overlapping) and returns - obviously - just one (instead of 9 ) using solely a Length comparison:
Anyway the general case has as follows:
- Cluster the collection using a proper criterion.
- Provide action options related with the items per given Cluster branch. This means:
2.1. Sample item with no further questions IF the branch has one item (i.e. an isolated curve) - see 3 as well.
2.2. Reject all.
2.3. Order by Length and take the biggest/smallest/average/whatever (or the first if Length is the same).
- Maybe add a “special” criterion as well: if any isolated has equal Length to any other … this means(?) that are equal (???) … but wait … that’s a a very stupid attempt to deal with equality: a chimera in most of the cases (if we are talking higher order Geometry than pts/lines/circles/rectangles/etc).
Anyway notify if you need a C# that does the Clustering by the book.
Thanks for your reply.
You are right, the length is not the duplicated criterion, but in my case, the duplicated curves must be derived from the same parent curve, which must be duplicated with same length and same location.
I have tried to use the linq query, but it doesn’t work:
list.orderby(x=>x.getlength()).Distinct()
something like this.
If your goal is to remove ANY other item that is “equal” to some reference item … well … we are back to that object equality rabbit hole. As I said: a chimera in most complex Types cases. It works only for primitive Types like a Circle for instance where equality is easy to define. That said there’s ways to attempt to deal with “equality in general” (up to some point) but are rather far and away from the scope of this thread.
So … if you want some rational take on that matter … just Cluster Curves using the “filtering” Method posted above (i.e. Cluster by an Overlap criterion),
Anyway … as I said I could provide an entry level C# … but … it would NOT be the same as the Internal thing captured above (i.e. a much much slower (~30 times) version). Reason is that any high perf Clustering C# is strictly internal (for obvious reasons: these things are weapons in real-life etc etc).
BTW: Imagine 5 Curvs (2 overlaps) as follows:
Then your LINQ would return … er … obviously 5 Curves (Reason? well … the Distinct Method … it’s not what you think that is).
BTW: Define a Class, include suitable Properties and play with LINQ
BTW: This Class is used in the Overlap Clustering shown above (working on CINFO Type objects and then unboxing accordingly) :
Here’s a small tutorial (and a challenge) for your first LINQ steps.
We have 36 crvs (overlaps etc etc). If we do some LINQ like this:
we get the 6 inner (no dupes) crvs:
So … what single line is missing for getting the other 6 crvs? (and no: the First outer is not the Items[1] since there’s 3 overlaps per inner Circle).
You apply the Round method to get the approximate centoids of curve list. And you group it with this criterion, and order the list by the length. Finally, select the first entry in each group.
Your methd is better.
Get the double GroupBy thing (includes the usual challenge: do it solely via LINQ). Note that this is rather an entry level LINQ exercise than a general case dupe Crvs elimination. But … if you replace the 1st GroupBy clause with the Overlap Method posted … things may become serious. But does GroupBy work with a pair? That’s the 1M question.
LINQ_GroupBy_DupeCurvs_ForAmateurs_V1.gh (130.0 KB)
Final Tip: When you face a problem ALWAYS deal with the general case. Plus ALWAYS try to achieve the fastest/neatest solution possible. With these in mind FORGET LINQ and do a proper Clustering using a proper citerion.
There are two very easy solutions
If the curves are far away from each other, therefore are equal in shape and size, but different in world location :
public List<Curve> RemoveDuplicateCurves(List<Curve> curves)
{
List<Curve> uniqueCurves = new List<Curve>();
foreach (Curve curve in curves)
{
bool isDuplicate = false;
foreach (Curve uniqueCurve in uniqueCurves)
{
if (curve.ControlPointCountCount() != uniqueCurve.ControlPointCount()) //make a method to count the control points
{
continue;
}
bool isMatch = true;
for (int i = 0; i < curve.ControlPointCount(); i++)
{
Point3d controlPointA = curve.ControlPoints[i];
Point3d controlPointB = uniqueCurve.ControlPoints[i];
if (controlPointA.DistanceTo(controlPointB) > RhinoMath.ZeroTolerance)
{
isMatch = false;
break;
}
}
if (isMatch)
{
isDuplicate = true;
break;
}
}
if (!isDuplicate)
{
uniqueCurves.Add(curve);
}
}
return uniqueCurves;
}
If we have 2 curves that are on the same space position :
public List<Curve> RemoveDuplicateCurves(List<Curve> curves)
{
Curve[] joinedCurves = Curve.JoinCurves(curves.ToArray()); //join cleans any overlap
return joinedCurves.ToList();
}
Hope this helps cheers.
Thanks for your reply!
It really works well of your script, thanks!