Reputation: 351
I am trying to understand this part of code:
int[] triangles = mesh.triangles;
Color32[] colors = mesh.colors32;
IEnumerable<IGrouping<byte, int>> hierarchyMap = colors
.Select((color, index) => new { color, index })
.GroupBy(c => c.color.g, c => c.index);
IEnumerable<int> leafIndexes = hierarchyMap
.Where(x => x.Key == 255)
.SelectMany(x=>x);
Dictionary<int, HashSet<int>> faces = triangles
.Select((vert, index) => new { vert, index })
.GroupBy(g => g.index / 3, i => i.vert)
.Where(g=> leafIndexes.Any(leaf=>g.Contains(leaf)))
.ToDictionary(g=>g.Key, g=>new HashSet<int>(g));
These code look like magic for me. It seems like "c" represents each element in colors, and type Color32
indeed has a property called color
. But in the last line, triangle
is an array of type int
, how can an int
type have an property called vert
? And both int
and Color32
don't have property index
.
I am so confused on these expressions, I only find some simple example of Lambda expression online. After reading the examples, I am still stuck on these codes.
Upvotes: 0
Views: 160
Reputation: 131384
As I said in the comments, this code is too "clever" for its own good, and very, very slow due to repeated iterations.
The first two queries are redundant, as in the end, leafIndexes
contains just the indexes of color
255, or rather, 0x0000FF
. Select((item,index)=>...)
passes the item and its index to the lambda. Those two queries could be just :
var leafIndexes=colors.Select((color,idx)=>{color,idx})
.Where(color=>color=255)
.Select(pair=>pair.idx)
.ToList();
Or, using an iterator function:
IEnumerable<int> ColorIndexes(IEnumerable<Color32> colors,int color)
{
int i=0;
foreach(var c in colors)
{
if(c==color) yield return i;
i++;
}
}
...
var leafIndexes=ColorIndexes(colors,255).ToList();
The final query tries to batch vertices in threes. An iterator method could also help here, but a better idea would be to use MoreLINQ's Batch operator :
int[] vertices= mesh.triangles;
var triangles=vertices.Batch(3);
After that, the query tries to find which "triangle" values are contained in the leafIndexes list. Each "triangle" is a list of numbers though. We could write:
var finalTriangles=triangles.Where(points=> points.Any(point=>leafIndexes.Contains(point));
Which tries to find if any of the triangle points is contained in the leaf indexes. Or we could use Enumerable.Intersect to see if the the two arrays have any values in common:
var finalTriangles=vertices.Batch(3)
.Where(points=> points.Intersect(leafIndexes).Any());
The final step in the query creates a dictionary with the matching "triangles" whose key is the "triangle" index. Again, this is a job for Select((item,index))
:
int[] vertices= mesh.triangles;
var finalTriangles=vertices.Batch(3)
.Select((triplet,idx)=>{ triplet=triplet.ToList(),
idx})
.Where(pair=> pair.triplet.Intersect(leafIndexes).Any())
.ToDictionary(pair=>pair.idx,
pair=>pair.triplet);
The code uses ToList()
to execute the enumerable just once and return a List. Without it, every time
tripletor
leafIndexes` was used, the query would execute again.
The one thing this code doesn't do is put the points into a HashSet
. This class is meant for fast, set-based, in-place operations. If triplet
was a HashSet, calling IntersectWith
would modify it and leave only the numbers found in leafIndexes
.
Upvotes: 1
Reputation: 90659
how can an int type have an property called vert? And both int and Color32 don't have property index.
You are confusing one thing here: These are no "properties" but iteration variables.
Linq basically almost all the time is a shortcut for a
foreach(var color in colors)
for example. It is totally up to you if you call it color
or item
or anything else!
Honestly I didn't know but apparently the index
you can just include when you need it. It is the index of according element within the list/IEnumerable you are using Linq on.
So in GroupBy
you could actually again call it color
instead of c
.
Also in the later vert
is no property but simply is a name for the current item .. you could also use
Dictionary<int, HashSet<int>> faces = triangles
.Select((v, i) => new { v, i })
and it would do exactly the same thing.
Upvotes: 0