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); }