public Vector2 Sample(Vector2 position) { var v = _scalar.Sample(position); var x = _scalar.Sample(new Vector2(position.X + 1, position.Y)); var y = _scalar.Sample(new Vector2(position.X, position.Y + 1)); return(new Vector2( v - x, v - y )); }
private static IEnumerable <Seed> SeedsAlongEdge(Region region, BaseScalarField distanceField, IVector2Field major, IVector2Field minor) { float d = 0; Vector2?previous = null; foreach (var vertex in region.Vertices) { if (previous.HasValue) { var pos = previous.Value; var v = vertex - previous.Value; var length = v.Length(); var dir = v / length; for (int i = 0; i < length; i++) { var separation = distanceField.Sample(pos + dir * i); d += separation; if (d >= separation) { yield return(new Seed(pos + dir * i, major, minor)); d -= separation; } } } previous = vertex; } }
private Seed?RemoveSeed(IMinHeap <KeyValuePair <float, Seed> > seeds, BaseScalarField separation, float cosineSearchAngle, Func <Edge, bool> edgeFilter = null) { Contract.Requires(seeds != null); Contract.Requires(separation != null); while (seeds.Count > 0) { //Get the highest priority seed var s = seeds.RemoveMin().Value; //Check if it's valid var d = s.Field.Sample(s.Point); //Degenerate point? var l = d.Length(); if (l < 0.001f) { continue; } var sep = separation.Sample(s.Point); //Normalize direction d /= l; //Get edges near this point and check if there is a parallel edge if (FindEdges(s.Point, sep).Where(e => edgeFilter == null || edgeFilter(e)).Any(e => Math.Abs(Vector2.Dot(e.Direction, d)) > cosineSearchAngle)) { continue; } return(s); } //No valid seeds found return(null); }
private Streamline Trace(Seed seed, bool reverse, MinHeap <KeyValuePair <float, Seed> > seeds, Func <Vector2, bool> isOutOfBounds, float maxSegmentLength, float mergeDistance, float cosineSearchAngle, BaseScalarField separation) { var maxSegmentLengthSquared = maxSegmentLength * maxSegmentLength; var seedingDistance = float.MaxValue; var direction = Vector2.Zero; var position = seed.Point; var stream = new Streamline(FindOrCreateVertex(position, mergeDistance, cosineSearchAngle)); //This is a weird way to do a for loop! What gives? //This is, in many respects, a better way to do it if you don't want i to be mutated within the loop //In this case I'm using it to pacify a persistent CodeContracts false positive (this loop is too complex for it to analyze, I guess?) foreach (var i in Enumerable.Range(0, 10000)) { direction = seed.Field.TraceVectorField(position, direction, maxSegmentLength); if (i == 0) { direction *= reverse ? -1 : 1; } //degenerate step check var segmentLength = direction.Length(); if (segmentLength < 0.00005f) { break; } //Excessive step check if (segmentLength > maxSegmentLength) { direction /= segmentLength * maxSegmentLength; segmentLength = maxSegmentLength; } //Step along path position += direction; seedingDistance += segmentLength; //Bounds check if (isOutOfBounds(position)) { CreateEdge(stream, position, Vector2.Normalize(direction), maxSegmentLength, maxSegmentLengthSquared, mergeDistance, cosineSearchAngle, skipDistanceCheck: true); break; } //Create the segment and break if it says so if (CreateEdge(stream, position, Vector2.Normalize(direction), maxSegmentLength, maxSegmentLengthSquared, mergeDistance, cosineSearchAngle)) { break; } //Accumulate seeds to trace into the alternative field var seedSeparation = separation.Sample(position); if (seedingDistance > seedSeparation) { seedingDistance = 0; AddSeed(seeds, new Seed(position, seed.AlternativeField, seed.Field)); } } return(stream); }