protected void MaskOnData() { if (_coherency == null || _selectionData == null) { return; } //Renderer.Singleton.Remove(_graph); //float dataRange = 80; //float rangeOffset = dataRange * 0.5f; //Graph2D[] maskGraph = new Graph2D[_coherency.Length]; //for (int angle = 0; angle < maskGraph.Length; ++angle) // maskGraph[angle] = Graph2D.Operate(_coherency[angle], _selectionData[angle], (b, a) => (Math.Max(0, a + rangeOffset + 1/*b*/ * (2 * dataRange)))); //LineSet maskedLines = FieldAnalysis.WriteGraphToSun(maskGraph, new Vector3(_selection.X, _selection.Y, SliceTimeMain)); //_graph = new LineBall(_graphPlane, maskedLines, LineBall.RenderEffect.HEIGHT, Colormap, true, SliceTimeMain); //_graph.LowerBound = SliceTimeMain; //_graph.UpperBound = SliceTimeMain + 4 * dataRange; //_graph.UsedMap = Colormap.ParulaSegmentation; LineSet lines = FieldAnalysis.WriteGraphToSun(_coherency, new Vector3(_selection.X, _selection.Y, SliceTimeMain)); _graph = new LineBall(_graphPlane, lines, LineBall.RenderEffect.HEIGHT, Colormap.Parula, true, SliceTimeMain); _graph.LowerBound = SliceTimeMain; _graph.UpperBound = SliceTimeMain + 80; // Compute area coherency. float overallCoherency = ComputeCoherency(_coherency, _selectionData); Console.WriteLine(String.Format("=== {0} Coherency is {1} / 80 = {2}===", _currentFileName, overallCoherency, overallCoherency / 80)); }
protected void MaskOnData() { if (_dataGraph == null || _selectionData == null) { return; } Renderer.Singleton.Remove(_graph); float rangeOffset = _rangeGraphData * 0.5f; Graph2D[] maskGraph = new Graph2D[_dataGraph.Length]; for (int angle = 0; angle < maskGraph.Length; ++angle) { maskGraph[angle] = Graph2D.Operate(_dataGraph[angle], _selectionData[angle], (b, a) => (Math.Max(0, a + rangeOffset + b * (2 * _rangeGraphData)))); } LineSet maskedLines = FieldAnalysis.WriteGraphToSun(maskGraph, new Vector3(_selection.X, _selection.Y, SliceTimeMain)); _graph = new LineBall(_graphPlane, maskedLines, LineBall.RenderEffect.HEIGHT, Colormap, true, SliceTimeMain); _graph.LowerBound = _minGraphData; _graph.UpperBound = _minGraphData + 4 * _rangeGraphData; _graph.UsedMap = Colormap.ParulaSegmentation; Renderer.Singleton.AddRenderable(_graph); }
public override void EndSelection(Vector2[] corners) { if (_selectionData == null) { return; } _selectionLines = FieldAnalysis.WriteGraphToSun(_selectionData, new Vector3(_selection.X, _selection.Y, SliceTimeMain)); WriteGraph(_currentFileName + "Selection", _selectedCore, _selectionData, _selectionLines); Renderer.Singleton.Remove(_mouseCloud); _mouseCircle = null; }
public PathlineLengthMapper(VectorFieldUnsteady velocity, Plane plane) : base(plane, velocity.Size.ToInt2()) { Velocity = velocity; Mapping = ShowPaths; Plane = plane; int time = velocity.Size.T; _intersectTimeSlices = new PointSet <EndPoint> [time]; _pathlineSegments = new LineSet[time - 1]; _intersectTimeSlices[0] = FieldAnalysis.ValidDataPoints <EndPoint>(velocity.GetTimeSlice(0));//FieldAnalysis.SomePoints2D<EndPoint>(velocity, 100);// _points = new PointCloud[velocity.Size.T]; _points[0] = new PointCloud(Plane, _intersectTimeSlices[0].ToBasicSet()); _fieldPositionOfValidCell = new int[_intersectTimeSlices[0].Length]; for (int i = 0; i < _fieldPositionOfValidCell.Length; ++i) { Vector3 pos = _intersectTimeSlices[0].Points[i].Position; _fieldPositionOfValidCell[i] = (int)(pos.X + 0.5) + (int)(pos.Y + 0.5) * Velocity.Size[0]; } }
public List <Renderable> EditorMap() { List <Renderable> renderables = new List <Renderable>(10); int numLines = LineX; #region BackgroundPlanes if (_lastSetting == null || MeasureChanged || SliceTimeMainChanged || MemberMainChanged || CoreChanged) { if (_lastSetting == null && _cores == null || CoreChanged || MemberMainChanged) { // Trace / load cores. TraceCore(MemberMain, SliceTimeMain); if (_selectedCore >= 0) { ClickSelection(_selection); } } // Computing which field to load as background. int totalTime = Math.Min(RedSea.Singleton.NumSubstepsTotal, SliceTimeMain); int time = (totalTime * _everyNthTimestep) / RedSea.Singleton.NumSubsteps; int subtime = (totalTime * _everyNthTimestep) % RedSea.Singleton.NumSubsteps; _timeSlice = LoadPlane(MemberMain, time, subtime, true); _intersectionPlane = _timeSlice.GetIntersectionPlane(); } if (_lastSetting == null || SliceTimeReferenceChanged) { // Reference slice. int totalTime = Math.Min(RedSea.Singleton.NumSubstepsTotal, SliceTimeReference); int time = (totalTime * _everyNthTimestep) / RedSea.Singleton.NumSubsteps; int subtime = (totalTime * _everyNthTimestep) % RedSea.Singleton.NumSubsteps; _compareSlice = LoadPlane(MemberMain, time, subtime, true); } if (_lastSetting == null || ColormapChanged || ShaderChanged || WindowStartChanged || WindowWidthChanged) { _timeSlice.SetRenderEffect(Shader); _timeSlice.UsedMap = Colormap; _timeSlice.LowerBound = WindowStart; _timeSlice.UpperBound = WindowWidth + WindowStart; _compareSlice.SetRenderEffect(Shader); _compareSlice.UsedMap = Colormap; _compareSlice.LowerBound = WindowStart; _compareSlice.UpperBound = WindowWidth + WindowStart; } // First item in list: plane. renderables.Add(_timeSlice); #endregion BackgroundPlanes // Add Point to indicate clicked position. renderables.Add(new PointCloud(_linePlane, new PointSet <Point>(new Point[] { new Point() { Position = new Vector3(_selection, SliceTimeMain), Color = new Vector3(0.7f), Radius = 0.4f } }))); bool rebuilt = false; // Recompute lines if necessary. if (numLines > 0 && ( _lastSetting == null || NumLinesChanged || OffsetRadiusChanged || _selectionChanged || SliceTimeMainChanged || DiffusionMeasureChanged)) { switch (DiffusionMeasure) { case RedSea.DiffusionMeasure.FTLE: _currentFileName = "FTLE"; _rangeGraphData = 0.095f; break; case RedSea.DiffusionMeasure.Direction: _currentFileName = "Okubo"; _rangeGraphData = 0.2f; break; default: _currentFileName = "Concentric"; _rangeGraphData = 20; break; } _graph = null; // Load computed data. if (LoadGraph(_currentFileName, out _dataGraph)) { // Is there a drawing saved? If not, make a new empty graph. if (!LoadGraph(_currentFileName + "Selection", _selectedCore, out _selectionData, out _selectionLines)) { if (_selectionData == null || _selectionData.Length != _dataGraph.Length) { _selectionData = new Graph2D[_dataGraph.Length]; } for (int angle = 0; angle < _selectionData.Length; ++angle) { _selectionData[angle] = new Graph2D(_dataGraph[angle].Length); for (int rad = 0; rad < _selectionData[angle].Length; ++rad) { _selectionData[angle].X[rad] = _dataGraph[angle].X[rad]; _selectionData[angle].Fx[rad] = 0; } } //_selectionLines = FieldAnalysis.WriteGraphToSun(_selectionData, new Vector3(_selection.X, _selection.Y, SliceTimeMain)); } // Some weird things happening, maybe this solves offset drawing... _graphData = FieldAnalysis.WriteGraphToSun(_dataGraph, new Vector3(_selection.X, _selection.Y, SliceTimeMain)); var dataRange = _graphData.GetRange(2); //_rangeGraphData = dataRange.Item2 - SliceTimeMain; _minGraphData = SliceTimeMain; MaskOnData(); } _selectionChanged = false; rebuilt = true; } // Add the lineball. if (_pathlines != null) { renderables.Add(_pathlines); } if (_graph != null) // && !Graph && !Flat) { renderables.Add(_graph); } //if (_selectionGraph != null && (Graph || Flat)) // renderables.Add(_selectionGraph); if (_boundaryBallSpacetime != null && !Graph)// && Graph && !Flat) { renderables.Add(_boundaryBallSpacetime); } if (SliceTimeMain != SliceTimeReference) { renderables.Add(_compareSlice); } if (_boundaryCloud != null)// && Graph) { renderables.Add(_boundaryCloud); } if (_specialObject != null) { renderables.Add(_specialObject); } if (_selectedCore >= 0 && _coreBall != null && !Flat) { renderables.Add(_coreBall); } return(renderables); }
public List <Renderable> CoherencyMap() { List <Renderable> renderables = new List <Renderable>(10); int numLines = LineX; #region BackgroundPlanes if (_lastSetting == null || MeasureChanged || SliceTimeMainChanged || MemberMainChanged || CoreChanged) { if (_lastSetting == null && _cores == null || CoreChanged || MemberMainChanged) { // Trace / load cores. TraceCore(MemberMain, SliceTimeMain); if (_selectedCore >= 0) { ClickSelection(_selection); } } // Computing which field to load as background. int totalTime = Math.Min(RedSea.Singleton.NumSubstepsTotal, SliceTimeMain); int time = (totalTime * _everyNthTimestep) / RedSea.Singleton.NumSubsteps; int subtime = (totalTime * _everyNthTimestep) % RedSea.Singleton.NumSubsteps; _timeSlice = LoadPlane(MemberMain, time, subtime, true); _intersectionPlane = _timeSlice.GetIntersectionPlane(); } if (_lastSetting == null || SliceTimeReferenceChanged) { // Reference slice. int totalTime = Math.Min(RedSea.Singleton.NumSubstepsTotal, SliceTimeReference); int time = (totalTime * _everyNthTimestep) / RedSea.Singleton.NumSubsteps; int subtime = (totalTime * _everyNthTimestep) % RedSea.Singleton.NumSubsteps; _compareSlice = LoadPlane(MemberMain, time, subtime, true); } if (_lastSetting == null || ColormapChanged || ShaderChanged || WindowStartChanged || WindowWidthChanged) { _timeSlice.SetRenderEffect(Shader); _timeSlice.UsedMap = Colormap; _timeSlice.LowerBound = WindowStart; _timeSlice.UpperBound = WindowWidth + WindowStart; _compareSlice.SetRenderEffect(Shader); _compareSlice.UsedMap = Colormap; _compareSlice.LowerBound = WindowStart; _compareSlice.UpperBound = WindowWidth + WindowStart; } // First item in list: plane. renderables.Add(_timeSlice); #endregion BackgroundPlanes // Add Point to indicate clicked position. //renderables.Add(new PointCloud(_linePlane, new PointSet<Point>(new Point[] { new Point() { Position = new Vector3(_selection, SliceTimeMain), Color = new Vector3(0.7f), Radius = 0.4f } }))); bool rebuilt = false; if (_lastSetting == null || DiffusionMeasureChanged) { switch (DiffusionMeasure) { case RedSea.DiffusionMeasure.FTLE: _currentFileName = "FTLE"; break; case RedSea.DiffusionMeasure.Direction: _currentFileName = "Okubo"; break; default: _currentFileName = "Concentric"; break; } } // Recompute lines if necessary. if (numLines > 0 && ( _lastSetting == null || NumLinesChanged || _selectionChanged || SliceTimeMainChanged || DiffusionMeasureChanged)) { _graph = null; // Load selection if (LoadGraph(_currentFileName + "Selection", out _selectionData)) { // Is there a drawing saved? If not, make a new empty graph. if (!LoadGraph(_currentFileName + "Coherency", _selectedCore, out _coherency, out _graphData)) { if (_coherency == null || _coherency.Length != _selectionData.Length) { _coherency = new Graph2D[_selectionData.Length]; } for (int angle = 0; angle < _coherency.Length; ++angle) { _coherency[angle] = new Graph2D(_selectionData[angle].Length); for (int rad = 0; rad < _coherency[angle].Length; ++rad) { _coherency[angle].X[rad] = _selectionData[angle].X[rad]; _coherency[angle].Fx[rad] = 0; } } IntegrateLines(); } else { _stencilPathlines = new List <LineSet>(8); for (int toTime = 10; toTime <= 80; toTime += 10) { string pathlineName = RedSea.Singleton.DiskFileName + _currentFileName + string.Format("Pathlines_{0}_{1}.pathlines", SliceTimeMain, toTime); LineSet paths; GeometryWriter.ReadFromFile(pathlineName, out paths); _stencilPathlines.Add(paths); } } // Some weird things happening, maybe this solves offset drawing... It does. LineSet coherencyLines = FieldAnalysis.WriteGraphToSun(_coherency, new Vector3(_selection.X, _selection.Y, SliceTimeMain)); _coherencyDisk = new LineBall(_graphPlane, coherencyLines, LineBall.RenderEffect.HEIGHT, Colormap, true, SliceTimeMain); //_coherencyDisk.LowerBound = SliceTimeMain; //_coherencyDisk.UpperBound = SliceTimeMain + 80; MaskOnData(); } _selectionChanged = false; rebuilt = true; } // Recompute lines if necessary. if (numLines > 0 && ( _lastSetting == null || NumLinesChanged || FlatChanged || _selectionChanged || SliceTimeReferenceChanged || DiffusionMeasureChanged)) { _selectionDistRef = null; // Load selection if (LoadGraph(_currentFileName + "Selection", _selectedCore, out _selectionDataRef, out _graphData, SliceTimeReference)) { // Some weird things happening, maybe this solves offset drawing... It does. LineSet selectionLines = FieldAnalysis.WriteGraphToSun(_selectionDataRef, new Vector3(_selection.X, _selection.Y, SliceTimeReference)); _selectionDistRef = new LineBall(_graphPlane, selectionLines, LineBall.RenderEffect.HEIGHT, Colormap.Gray, true, SliceTimeReference); _selectionDistRef.LowerBound = SliceTimeReference; _selectionDistRef.UpperBound = SliceTimeReference + 1; if (SliceTimeReference % 10 == 0 && SliceTimeReference != 0) { _pathlinesTime = _stencilPathlines[SliceTimeReference / 10 - 1]; _pathlines = new LineBall(_graphPlane, _pathlinesTime, LineBall.RenderEffect.HEIGHT, Colormap.Heat, false); _pathlines.LowerBound = SliceTimeMain; _pathlines.UpperBound = 80; } } _selectionChanged = false; rebuilt = true; } // Add the lineball. if (_pathlines != null && !Flat) { renderables.Add(_pathlines); } if (_graph != null) { renderables.Add(_graph); } if (_selectionDistRef != null) { renderables.Add(_selectionDistRef); } //if (_coherencyDisk != null) // && !Graph && !Flat) // renderables.Add(_coherencyDisk); // if (_selectionDistRef != null && (Graph || Flat)) // renderables.Add(_selectionDistRef); //if (SliceTimeMain != SliceTimeReference) // renderables.Add(_compareSlice); if (_selectedCore >= 0 && _coreBall != null && !Flat) { renderables.Add(_coreBall); } return(renderables); }
protected void IntegrateLines() { LineSet seeds = FieldAnalysis.WriteGraphToSun(_coherency, new Vector3(_selection.X, _selection.Y, SliceTimeMain)); _stencilPathlines = new List <LineSet>(8); // ~~~~~~~~~~~~~~~~~~~~~~~~ Integrate Pathlines and Adapt ~~~~~~~~~~~~~~~~~~~~~~~~ \\ // Setup integrator. Integrator pathlineIntegrator = Integrator.CreateIntegrator(null, IntegrationType, _cores[_selectedCore], _repulsion); pathlineIntegrator.Direction = Sign.POSITIVE; pathlineIntegrator.StepSize = StepSize; // Count out the runs for debugging. int run = 0; // ~~~~~~~~~~~~~~~~~~~~~~~~ Integrate Pathlines ~~~~~~~~~~~~~~~~~~~~~~~~ \\ #region IntegratePathlines // Do we need to load a field first? if (_velocity.TimeOrigin > 0 || _velocity.TimeOrigin + _velocity.Size.T < 11) { LoadField(0, MemberMain, 11); } // Integrate first few steps. pathlineIntegrator.Field = _velocity; _stencilPathlines.Add(pathlineIntegrator.Integrate(seeds.ToPointSet(), false)[0]); //List<Tuple<Int2, Line>> indexedPathlines = new List<Tuple<Int2, Line>>(); List <Int2> pathlineIndices = new List <Int2>(); for (int a = 0; a < _coherency.Length; a++) { for (int r = 0; r < _coherency[0].Length; r++) { pathlineIndices.Add(new Int2(a, r)); } } // ~~~~~~~~~~~~~~~~~~~~~~~~ Filter and Repeat ~~~~~~~~~~~~~~~~~~~~~~~~ \\ Graph2D[] interimSlice; for (int toTime = 10; toTime <= 80; toTime += 10) { if (!LoadGraph(_currentFileName + "Selection", _selectedCore, out interimSlice, out _graphData, toTime)) { continue; } Vector3 corePoint = (Vector3)_cores.Lines[_selectedCore].SampleZ(toTime); // ~~~~~~~~~~~~~~~~~~~~~~~~ Keep Only Those Inside ~~~~~~~~~~~~~~~~~~~~~~~~ \\ List <Line> shrunkenLineSet = new List <Line>(); List <Int2> shrunkenIndexSet = new List <Int2>(); Line[] lastLines = _stencilPathlines[_stencilPathlines.Count - 1].Lines; for (int lineIdx = 0; lineIdx < lastLines.Length; ++lineIdx) { Line pathLine = lastLines[lineIdx]; Int2 lineIdx2 = pathlineIndices[lineIdx]; if (pathLine.Length < 1) { continue; } Vector2 endPos = new Vector2(pathLine.Last.X, pathLine.Last.Y); Int2 indexInSun = GetClosestIndex(interimSlice, new Vector2(corePoint.X, corePoint.Y), endPos); if (indexInSun.X < 0 || indexInSun.X >= interimSlice.Length || indexInSun.Y < 0 || indexInSun.Y >= interimSlice[0].Length) { continue; } // Check against stencil data. if (interimSlice[indexInSun.X].Fx[indexInSun.Y] != 1) { continue; } // Keep this pathline. shrunkenLineSet.Add(pathLine); shrunkenIndexSet.Add(lineIdx2); // Update coherency map. Use max in case we ever add more in-between slices. //Vector2 startPos = new Vector2(pathLine[0].X, pathLine[0].Y); //indexInSun = GetClosestIndex(interimSlice, _selection, startPos); //_coherency[indexInSun.X].Fx[indexInSun.Y] = Math.Max(_coherency[indexInSun.X].Fx[indexInSun.Y], toTime); _coherency[lineIdx2.X].Fx[lineIdx2.Y] = Math.Max(_coherency[lineIdx2.X].Fx[lineIdx2.Y], toTime); } // Replace last line set in list with new, filtered version. _stencilPathlines[_stencilPathlines.Count - 1] = new LineSet(shrunkenLineSet.ToArray()); pathlineIndices = shrunkenIndexSet; string pathlineName = RedSea.Singleton.DiskFileName + _currentFileName + string.Format("Pathlines_{0}_{1}.pathlines", SliceTimeMain, toTime); GeometryWriter.WriteToFile(pathlineName, _stencilPathlines[_stencilPathlines.Count - 1]); if (toTime == 80) { break; } // Append integrated lines of next loaded vectorfield time slices. LoadField(toTime, MemberMain, 11); // Integrate further. pathlineIntegrator.Field = _velocity; _stencilPathlines.Add(new LineSet(_stencilPathlines[_stencilPathlines.Count - 1])); pathlineIntegrator.IntegrateFurther(_stencilPathlines[_stencilPathlines.Count - 1]); #endregion IntegratePathlines } // ~~~~~~~~~~~~~~~~~~~~~~~~ Write New Coherency Map to Disk ~~~~~~~~~~~~~~~~~~~~~~~~ \\ LineSet coherencyLines = FieldAnalysis.WriteGraphToSun(_coherency, new Vector3(_selection, SliceTimeMain)); WriteGraph(_currentFileName + "Coherency", _selectedCore, _coherency, coherencyLines); }
public float SquaredError(FieldAnalysis.StraightLine line, int? length = null) { int end = length ?? Length; float sum = 0; for (int x = 0; x < end; ++x) { float diff = line[_x[x]] - _fx[x]; sum += diff * diff; } sum /= end; return sum; }
public List <Renderable> ComputeStatistics() { List <Renderable> result = new List <Renderable>(200); result.Add(new FieldPlane(Plane, Velocity.GetTimeSlice(_currentSetting.SliceTimeMain), _currentSetting.Shader, _currentSetting.Colormap)); if (!_initialized) { return(result); } result.Add(new LineBall(Plane, new LineSet(new Line[] { new Line() { Positions = new Vector3[] { _startSelection, _endSelection } } }))); bool completelyNew = false; // ~~~~~~~~~~~~~~ Get new Start Points ~~~~~~~~~~~~~~ // if (_lastSetting == null || SliceTimeMainChanged || LineXChanged || _selectionChanged) { int numPoints = _startSelection == null ? 0 : Math.Max(2, _currentSetting.LineX + 1); Point[] startPoints = new Point[numPoints]; // Compute point positions (linear interpolation). for (int x = 0; x < numPoints; ++x) { float t = (float)x / (numPoints - 1); startPoints[x] = new Point() { Position = _startSelection * (1.0f - t) + _endSelection * t }; } _linePoints = new PointSet <Point>(startPoints); _values = new float[_linePoints.Length]; completelyNew = true; } // ~~~~~~~~~~~~ Compute Selected Measure ~~~~~~~~~~~~ // if (completelyNew || MeasureChanged || FlatChanged || IntegrationTimeChanged || IntegrationTypeChanged || StepSizeChanged) { // ~~~~~~~~~~~~~ Compute Scalar FIeld ~~~~~~~~~~~~~~~ // ScalarField measure = null; switch (_currentSetting.Measure) { // Velocity Length / Pathline Length. case RedSea.Measure.VELOCITY: measure = new VectorField(Velocity.GetTimeSlice(_currentSetting.SliceTimeMain), FieldAnalysis.VFLength, 1).Scalars[0] as ScalarField; break; case RedSea.Measure.SURFACE_HEIGHT: break; case RedSea.Measure.SALINITY: break; case RedSea.Measure.TEMPERATURE: break; case RedSea.Measure.DIVERGENCE: measure = new VectorField(Velocity.GetTimeSlice(_currentSetting.SliceTimeMain), FieldAnalysis.Divergence, 1).Scalars[0] as ScalarField; break; // Closeness of Pathline. case RedSea.Measure.DIVERGENCE_2D: break; case RedSea.Measure.VORTICITY: measure = new VectorField(Velocity.GetTimeSlice(_currentSetting.SliceTimeMain), FieldAnalysis.Vorticity, 1).Scalars[0] as ScalarField; break; case RedSea.Measure.SHEAR: measure = new VectorField(Velocity.GetTimeSlice(_currentSetting.SliceTimeMain), FieldAnalysis.Shear, 1).Scalars[0] as ScalarField; break; } // ~~~~~~~~~~~~~~~~ Sample Field ~~~~~~~~~~~~~~~~~~~ // switch (_currentSetting.Measure) { // Velocity Length / Pathline Length. case RedSea.Measure.VELOCITY: if (_currentSetting.IntegrationTime == 0) { for (int index = 0; index < _values.Length; ++index) { _values[index] = measure.Sample(((Vec3)_linePoints.Points[index].Position).ToVec2()); } } else { VectorField.Integrator integrator = VectorField.Integrator.CreateIntegrator(Velocity, _currentSetting.IntegrationType); integrator.Direction = Sign.POSITIVE; integrator.StepSize = _currentSetting.StepSize; LineSet line = integrator.Integrate(_linePoints, _currentSetting.Flat, _currentSetting.IntegrationTime)[0]; for (int index = 0; index < _values.Length; ++index) { _values[index] = line.Lines[index].LineLength; } result.Add(new LineBall(Plane, line)); } break; // Simply sample a field. case RedSea.Measure.SURFACE_HEIGHT: case RedSea.Measure.SALINITY: case RedSea.Measure.TEMPERATURE: case RedSea.Measure.DIVERGENCE: case RedSea.Measure.VORTICITY: case RedSea.Measure.SHEAR: for (int index = 0; index < _values.Length; ++index) { _values[index] = measure.Sample(((Vec3)_linePoints.Points[index].Position).ToVec2()); } break; // Closeness of Pathline. case RedSea.Measure.DIVERGENCE_2D: break; } completelyNew = true; } //if (completelyNew || // AlphaStableChanged || // LineSettingChanged) //{ // ~~~~~~~~~~~~~~~~ Display the Graph ~~~~~~~~~~~~~~~ // result.Add(FieldAnalysis.BuildGraph(Plane, _linePoints, _values, _currentSetting.AlphaStable, _currentSetting.LineSetting)); //} _selectionChanged = false; return(result); }
public override void ClickSelection(Vector2 point) { if (LineX > 0) { _lastSelection = (_lastSelection + 1) % LineX; Vec3 vec = new Vec3((Vec2)point, 0); if (_velocity.Grid.InGrid(vec)) { Vector3[] line = _integrator.IntegrateLineForRendering(vec).Points.ToArray(); Line newLine = new Line() { Positions = line }; var set = new LineSet(new Line[] { newLine }) { Color = _flipColor? Vector3.UnitX : Vector3.UnitZ }; set.Thickness *= 3; var ball = new LineBall(Plane, set, LineBall.RenderEffect.DEFAULT, Colormap, false); _selections.Add(ball); if (_selections.Count > LineX) { _selections.RemoveAt(0); _selectionsAngle.RemoveAt(0); _steadySelection.RemoveAt(0); } Graph2D[] angle = FieldAnalysis.GetDistanceToAngle(_core, Vector2.Zero, new LineSet(new Line[] { newLine })); Debug.Assert(angle.Length == 1); for (int p = 0; p < newLine.Length; ++p) { Vector3 sph = FieldAnalysis.SphericalPosition(_core[0], (float)(angle[0].X[p] * 0.5f / Math.PI), angle[0].Fx[p]); newLine[p] = new Vector3(sph.X, sph.Y, angle[0].X[p] - angle[0].X[0]); } set = new LineSet(new Line[] { newLine }) { Color = _flipColor ? Vector3.UnitX : Vector3.UnitZ }; set.Thickness *= 3; ball = new LineBall(Plane, set, LineBall.RenderEffect.DEFAULT, Colormap, false); _selectionsAngle.Add(ball); _integrator.Field = _steadyField; _integrator.MaxNumSteps = 50; line = _integrator.IntegrateLineForRendering(new Vec2(vec.X, vec.Y)).Points.ToArray(); newLine = new Line() { Positions = line }; set = new LineSet(new Line[] { newLine }) { Color = _flipColor ? Vector3.UnitX : Vector3.UnitZ }; set.Thickness *= 3; ball = new LineBall(new Plane(Plane, Vector3.UnitZ * 0.1f), set, LineBall.RenderEffect.DEFAULT, Colormap, false); _steadySelection.Add(ball); _integrator.Field = _velocity; _integrator.MaxNumSteps = 10000; _flipColor = !_flipColor; //var set = new LineSet(_selections.ToArray()) { Color = _selections.Count % 2 == 0 ? Vector3.UnitX : Vector3.UnitY }; //_lines = new LineBall(Plane, set, LineBall.RenderEffect.DEFAULT, Colormap, false); } } }
protected void BuildGraph() { // Compute ftle. if (LineX == 0) { return; } _graphData = FieldAnalysis.WriteGraphToSun(_okubo, new Vector3(_selection.X, _selection.Y, 0)); _graph = new LineBall(_graphPlane, _graphData, LineBall.RenderEffect.HEIGHT, Colormap, Flat, SliceTimeMain); _graph.LowerBound = -0.05f; _graph.UpperBound = 0.05f; _rebuilt = false; // Load or compute selection by floodfill. Graph2D[] okuboSelection; LineSet okuboLines; if (LoadGraph("OkuboSelection", _selectedCore, out okuboSelection, out okuboLines)) { return; } // Floodfill. int numAngles = _okubo.Length; int numRadii = _okubo[0].Length; HashSet <Int2> toFlood = new HashSet <Int2>(); okuboSelection = new Graph2D[numAngles]; for (int angle = 0; angle < numAngles; ++angle) { toFlood.Add(new Int2(angle, 0)); okuboSelection[angle] = new Graph2D(numRadii); for (int r = 1; r < numRadii; ++r) { okuboSelection[angle].Fx[r] = 0; okuboSelection[angle].X[r] = _okubo[angle].X[r]; } } while (toFlood.Count > 0) { Int2 current = toFlood.Last(); toFlood.Remove(current); okuboSelection[current.X].Fx[current.Y] = 1; // In each direction, go negative and positive. for (int dim = 0; dim < 2; ++dim) { for (int sign = -1; sign <= 1; sign += 2) { Int2 neighbor = new Int2(current); neighbor[dim] += sign; // Wrap angle around. neighbor[0] = (neighbor[0] + numAngles) % numAngles; if (neighbor.Y >= 0 && neighbor.Y < numRadii && _okubo[neighbor.X].Fx[neighbor.Y] <= 0 && okuboSelection[neighbor.X].Fx[neighbor.Y] == 0) { toFlood.Add(neighbor); } } } } LineSet sun = FieldAnalysis.WriteGraphToSun(okuboSelection, new Vector3(_selection, SliceTimeMain)); WriteGraph("OkuboSelection", _selectedCore, okuboSelection, sun); }