void UpdateGraph1D() { double time = (DateTime.Now - m_startTime).TotalSeconds; if (checkBoxGPU.Checked) { UpdateGraph1D_GPU(time); return; } TestTransform1D(time); m_image.Clear(float4.One); float2 rangeX = new float2(0.0f, SIGNAL_SIZE); float2 rangeY = new float2(-1, 1); // Plot input signal if (checkBoxShowInput.Checked) { // m_image.PlotGraphAutoRangeY( m_black, rangeX, ref rangeY, ( float x ) => { m_image.PlotGraph(m_black, rangeX, rangeY, ( float x ) => { int X = Math.Max(0, Math.Min(SIGNAL_SIZE - 1, (int)x)); return((float)m_signalSource[X].r); }); } // Plot reconstructed signals (Real and Imaginary parts) if (checkBoxShowReconstructedSignal.Checked) { m_image.PlotGraph(m_red, rangeX, rangeY, ( float x ) => { int X = Math.Max(0, Math.Min(SIGNAL_SIZE - 1, (int)x)); return((float)m_signalReconstructed[X].r); }); m_image.PlotGraph(m_blue, rangeX, rangeY, ( float x ) => { int X = Math.Max(0, Math.Min(SIGNAL_SIZE - 1, (int)x)); return((float)m_signalReconstructed[X].i); }); } m_image.PlotAxes(m_black, rangeX, rangeY, 16.0f, 0.1f); ////////////////////////////////////////////////////////////////////////// // Render spectrum as (Real=Red, Imaginary=Blue) vertical lines for each frequency float2 cornerMin = m_image.RangedCoordinates2ImageCoordinates(rangeX, rangeY, new float2(rangeX.x, -1.0f)); float2 cornerMax = m_image.RangedCoordinates2ImageCoordinates(rangeX, rangeY, new float2(rangeX.y, +1.0f)); float2 delta = cornerMax - cornerMin; float zeroY = cornerMin.y + 0.5f * delta.y; float2 Xr0 = new float2(0, zeroY); float2 Xr1 = new float2(0, 0); float2 Xi0 = new float2(0, zeroY); float2 Xi1 = new float2(0, 0); float scale = 10.0f; float4 spectrumColorRe = new float4(1, 0.25f, 0, 1); float4 spectrumColorIm = new float4(0, 0.5f, 1, 1); int size = m_spectrum.Length; int halfSize = size >> 1; for (int i = 0; i < m_spectrum.Length; i++) { float X = cornerMin.x + i * delta.x / m_spectrum.Length; // int frequencyIndex = i; // Show spectrum as output by FFT int frequencyIndex = (i + halfSize) % size; // Show offset spectrum with DC term in the middle Xr0.x = X; Xr1.x = X; Xr1.y = cornerMin.y + 0.5f * (scale * (float)m_spectrum[frequencyIndex].r + 1.0f) * delta.y; Xi0.x = X + 1; Xi1.x = X + 1; Xi1.y = cornerMin.y + 0.5f * (scale * (float)m_spectrum[frequencyIndex].i + 1.0f) * delta.y; m_image.DrawLine(spectrumColorRe, Xr0, Xr1); m_image.DrawLine(spectrumColorIm, Xi0, Xi1); } imagePanel.Bitmap = m_image.AsBitmap; }
/// <summary> /// Computes the radius of the sphere tangent to a vertex given a set of neighbor vertices /// </summary> /// <param name="_P"></param> /// <param name="_N"></param> /// <param name="_neighbors"></param> /// <returns></returns> float ComputeTangentSphereRadius_SUPER_SLOW(float3 _P, float3 _N, float3[] _neighbors) { ImageFile graph = new ImageFile((uint)panelOutputGraph.Width, (uint)panelOutputGraph.Height, PIXEL_FORMAT.BGRA8, new ColorProfile(ColorProfile.STANDARD_PROFILE.sRGB)); graph.Clear(float4.One); Func <float3, float, float3[], float> SquareDistance = (float3 _C, float _R, float3[] _Pns) => { float result = 0.0f; foreach (float3 Pn in _Pns) { result += (Pn - _C).LengthSquared - _R * _R; } return(Math.Abs(result)); }; // Func<float3,float3[],float> SquareDistance = ( float3 _C, float3[] _Pns ) => { float result = 0.0f; foreach ( float3 Pn in _Pns ) result += (Pn - _C).Length; return result / _Pns.Length; }; float2 rangeX = new float2(0, 4), rangeY = new float2(-50, 50); graph.PlotAxes(float4.UnitW, rangeX, rangeY, 0.5f, 5.0f); graph.PlotGraph(float4.UnitW, rangeX, rangeY, ( float x ) => { return(SquareDistance(_P - x * _N, x, _neighbors)); }); const float eps = 0.01f; const float tol = 1e-3f; float previousR = -float.MaxValue; float R = 0.0f; float step = 0.1f; float3 C = _P; int iterationsCount = 0; float previousSqDistance = float.MaxValue; float bestSqDistance = float.MaxValue; float bestR = 0.0f; int bestIterationsCount = 0; while (step > tol && R < 10000.0f && iterationsCount < 1000) { // Compute gradient float sqDistance = SquareDistance(C, R, _neighbors); float sqDistance2 = SquareDistance(C - eps * _N, R + eps, _neighbors); float grad = (sqDistance2 - sqDistance) / eps; if (previousSqDistance < sqDistance) { step *= 0.95f; // Climbing up again, roll down slower... } // Follow opposite gradient direction toward minimum previousR = R; R -= step * grad; C = _P - R * _N; iterationsCount++; previousSqDistance = sqDistance; if (sqDistance < bestSqDistance) { bestSqDistance = sqDistance; bestR = previousR; bestIterationsCount = iterationsCount; } graph.DrawLine(new float4(1, 0, 0, 1), graph.RangedCoordinates2ImageCoordinates(rangeX, rangeY, new float2(previousR, sqDistance)), graph.RangedCoordinates2ImageCoordinates(rangeX, rangeY, new float2(R, SquareDistance(_P - R * _N, R, _neighbors)))); float k = 0.1f; graph.DrawLine(new float4(0, 0.5f, 0, 1), graph.RangedCoordinates2ImageCoordinates(rangeX, rangeY, new float2(previousR, k * (iterationsCount - 1))), graph.RangedCoordinates2ImageCoordinates(rangeX, rangeY, new float2(R, k * iterationsCount))); } // Since we crossed the minimum, take the average for a better result R = 0.5f * (R + previousR); panelOutputGraph.m_bitmap = graph.AsBitmap; panelOutputGraph.Refresh(); labelResult.Text = "R = " + R + " (" + previousSqDistance + ") in " + iterationsCount + " iterations...\r\nBest = " + bestR + " (" + bestSqDistance + ") in " + bestIterationsCount + " iterations..."; return(R); }
void UpdateLevels() { // const uint BUCKETS_PER_LAYER = LEVEL_BUCKETS_COUNT / LAYERS_COUNT; // // float normalizer = 1.0f / (LAYERS_COUNT-1); // uint bucketIndex = 0; // for ( uint layerIndex=0; layerIndex < LAYERS_COUNT; layerIndex++ ) { // for ( uint i=0; i < BUCKETS_PER_LAYER; i++ ) { // float t = (float) i / BUCKETS_PER_LAYER; // m_levels[bucketIndex++] = normalizer * (layerIndex + t); // } // } #if CUBIC_SPLINES float F = 4.0f; float T0 = F * (0 * 1.0f + floatTrackbarControlTangent0.Value); float T1_in = F * (0 * 1.0f + floatTrackbarControlTangent1.Value); float T1_out = checkBoxSplit1.Checked ? F * (0 * 1.0f + floatTrackbarControlTangent1_Out.Value) : T1_in; float T2_in = F * (0 * 1.0f + floatTrackbarControlTangent2.Value); float T2_out = checkBoxSplit2.Checked ? F * (0 * 1.0f + floatTrackbarControlTangent2_Out.Value) : T2_in; float T3 = F * (0 * 1.0f + floatTrackbarControlTangent3.Value); float4[] hermites = new float4[6]; // hermites[0].Set( 0.0f, T0, 1.0f, T1 ); // hermites[1].Set( 0.0f, T1, 1.0f, T2 ); // hermites[2].Set( 0.0f, T2, 1.0f, T3 ); hermites[0].Set(0.0f, T0, 0.5f, -0.5f * (T0 - T1_in)); hermites[1].Set(0.5f, -0.5f * (T0 - T1_in), 1.0f, T1_in); hermites[2].Set(0.0f, T1_out, 0.5f, 0.5f * (T1_out + T2_in)); hermites[3].Set(0.5f, 0.5f * (T1_out + T2_in), 1.0f, T2_in); hermites[4].Set(0.0f, T2_out, 0.5f, 0.5f * (T2_out + T3)); hermites[5].Set(0.5f, 0.5f * (T2_out + T3), 1.0f, T3); #elif POWERS // float[] powers = new float[LAYERS_COUNT-1]; // powers[0] = floatTrackbarControlTangent0.Value; // powers[1] = floatTrackbarControlTangent1.Value; // powers[2] = floatTrackbarControlTangent2.Value; // powers[0] = powers[0] < 0.0f ? 1.0f / (1.0f - 9.0f * powers[0]) : 1.0f + 9.0f * powers[0]; // powers[1] = powers[1] < 0.0f ? 1.0f / (1.0f - 9.0f * powers[1]) : 1.0f + 9.0f * powers[1]; // powers[2] = powers[2] < 0.0f ? 1.0f / (1.0f - 9.0f * powers[2]) : 1.0f + 9.0f * powers[2]; float[] powers = new float[LAYERS_COUNT - 1]; float[] scalesX = new float[LAYERS_COUNT - 1]; float[] scalesY = new float[LAYERS_COUNT - 1]; powers[0] = floatTrackbarControlTangent0.Value; powers[1] = floatTrackbarControlTangent1.Value; powers[2] = floatTrackbarControlTangent2.Value; // powers[0] = powers[0] < 0.0f ? 1.0f / (1.0f - 9.0f * powers[0]) : 1.0f + 9.0f * powers[0]; // powers[1] = powers[1] < 0.0f ? 1.0f / (1.0f - 9.0f * powers[1]) : 1.0f + 9.0f * powers[1]; // powers[2] = powers[2] < 0.0f ? 1.0f / (1.0f - 9.0f * powers[2]) : 1.0f + 9.0f * powers[2]; powers[0] = (float)Math.Pow(10.0, 3.0 * powers[0]); powers[1] = (float)Math.Pow(10.0, 3.0 * powers[1]); powers[2] = (float)Math.Pow(10.0, 3.0 * powers[2]); scalesX[0] = 1.0f; // + 0.5f * Math.Max( 0.0f, floatTrackbarControlTangent0.Value ); scalesY[0] = 1.0f; // + 0.5f * Math.Max( 0.0f, -floatTrackbarControlTangent0.Value ); scalesX[1] = 1.0f; // + 0.5f * Math.Max( 0.0f, floatTrackbarControlTangent1.Value ); scalesY[1] = 1.0f; // + 0.5f * Math.Max( 0.0f, -floatTrackbarControlTangent1.Value ); scalesX[2] = 1.0f; // + 0.5f * Math.Max( 0.0f, floatTrackbarControlTangent2.Value ); scalesY[2] = 1.0f; // + 0.5f * Math.Max( 0.0f, -floatTrackbarControlTangent2.Value ); #endif for (uint bucketIndex = 0; bucketIndex < LEVEL_BUCKETS_COUNT; bucketIndex++) { float maskIn = (float)bucketIndex / (LEVEL_BUCKETS_COUNT - 1); float scaledMask = (LAYERS_COUNT - 1) * maskIn; uint layerStart = Math.Min(LAYERS_COUNT - 2, (uint)Math.Floor(scaledMask)); float t = scaledMask - layerStart; #if CUBIC_SPLINES // Compute Hermite curves // float4 hermite = hermites[layerStart]; // float maskOut = hermite.x * (1+2*t)*(1-t)*(1-t) // + hermite.y * t*(1-t)*(1-t) // + hermite.z * t*t*(3-2*t) // + hermite.w * t*t*(t-1); t = 2.0f * t; uint hermiteIndex = 2 * layerStart; if (t > 1.0f) { hermiteIndex++; t -= 1.0f; } float4 hermite = hermites[hermiteIndex]; float maskOut = hermite.x * (1 + 2 * t) * (1 - t) * (1 - t) + hermite.y * t * (1 - t) * (1 - t) + hermite.z * t * t * (3 - 2 * t) + hermite.w * t * t * (t - 1); #elif POWERS // // Apply curves // float tIn = 2.0f * t - 1.0f; // float tOut = Math.Sign( tIn ) * (float) Math.Pow( Math.Abs( tIn ), powers[layerStart] ); // float maskOut = (layerStart + 0.5f * (1.0f + tOut)) / (LAYERS_COUNT-1); float maskOut = scalesY[layerStart] * (float)Math.Pow(t / scalesX[layerStart], powers[layerStart]); #endif maskOut = Math.Max(0, Math.Min(1, maskOut)); maskOut = (layerStart + maskOut) / (LAYERS_COUNT - 1); m_levels[bucketIndex] = maskOut; } // Redraw levels float2 rangeX = new float2(0, 1); float2 rangeY = new float2(0, 1); m_imageLevels.Clear(float4.One); m_imageLevels.PlotAxes(float4.UnitW, rangeX, rangeY, 1.0f / (LAYERS_COUNT - 1), 1.0f / (LAYERS_COUNT - 1)); m_imageLevels.PlotGraph(float4.UnitW, rangeX, rangeY, ( float x ) => { return(m_levels[Math.Min(LEVEL_BUCKETS_COUNT - 1, (uint)((LEVEL_BUCKETS_COUNT - 1) * x))]); }); for (int layerIndex = 1; layerIndex < LAYERS_COUNT; layerIndex++) { m_imageLevels.DrawLine(new float4(0.2f, 0.5f, 0.75f, 1), m_imageLevels.RangedCoordinates2ImageCoordinates(rangeX, rangeY, new float2((float)layerIndex / (LAYERS_COUNT - 1), 0)), m_imageLevels.RangedCoordinates2ImageCoordinates(rangeX, rangeY, new float2((float)layerIndex / (LAYERS_COUNT - 1), 1))); m_imageLevels.DrawLine(new float4(0.2f, 0.5f, 0.75f, 1), m_imageLevels.RangedCoordinates2ImageCoordinates(rangeX, rangeY, new float2(0, (float)layerIndex / (LAYERS_COUNT - 1))), m_imageLevels.RangedCoordinates2ImageCoordinates(rangeX, rangeY, new float2(1, (float)layerIndex / (LAYERS_COUNT - 1)))); } panelOutputLevels.m_bitmap = m_imageLevels.AsBitmap; panelOutputLevels.Refresh(); }
/// <summary> /// Computes the radius of the sphere tangent to a vertex given a set of neighbor vertices /// </summary> /// <param name="_P"></param> /// <param name="_N"></param> /// <param name="_neighbors"></param> /// <returns></returns> float ComputeTangentSphereRadius(float3 _P, float3 _N, float3[] _neighbors, bool _debugGraph) { Func <float3, double, float3[], double> SquareDistance = (float3 _C, double _R, float3[] _Pns) => { double result = 0.0f; foreach (float3 Pn in _Pns) { result += (Pn - _C).LengthSquared - _R * _R; } return(result); }; float2 rangeX = new float2(-4, 4), rangeY = new float2(-50, 50); if (_debugGraph) { graph.Clear(float4.One); graph.PlotAxes(float4.UnitW, rangeX, rangeY, 0.5f, 5.0f); graph.PlotGraph(float4.UnitW, rangeX, rangeY, ( float x ) => { return((float)SquareDistance(_P - x * _N, x, _neighbors)); }); } const float eps = 0.01f; const double tol = 1e-3; double previousR = -double.MaxValue; double R = 0.0f; float3 C = _P; int iterationsCount = 0; double previousSqDistance = double.MaxValue; double bestSqDistance = double.MaxValue; double bestR = 0.0f; int bestIterationsCount = 0; while (Math.Abs(R) < 10000.0f && iterationsCount < 1000) { // Compute gradient double sqDistance = SquareDistance(C, R, _neighbors); double sqDistance2 = SquareDistance(C - eps * _N, R + eps, _neighbors); double grad = (sqDistance2 - sqDistance) / eps; // Compute intersection with secant Y=0 double t = -sqDistance * (Math.Abs(grad) > 1e-6f ? 1.0f / grad : (Math.Sign(grad) * 1e6)); if (Math.Abs(t) < tol) { break; } previousR = R; R += t; C = _P - (float)R * _N; iterationsCount++; previousSqDistance = sqDistance; if (sqDistance < bestSqDistance) { bestSqDistance = sqDistance; bestR = previousR; bestIterationsCount = iterationsCount; } if (_debugGraph) { graph.DrawLine(new float4(1, 0, 0, 1), graph.RangedCoordinates2ImageCoordinates(rangeX, rangeY, new float2((float)previousR, (float)sqDistance)), graph.RangedCoordinates2ImageCoordinates(rangeX, rangeY, new float2((float)R, (float)SquareDistance(_P - (float)R * _N, R, _neighbors)))); float k = 0.1f; graph.DrawLine(new float4(0, 0.5f, 0, 1), graph.RangedCoordinates2ImageCoordinates(rangeX, rangeY, new float2((float)previousR, k * (iterationsCount - 1))), graph.RangedCoordinates2ImageCoordinates(rangeX, rangeY, new float2((float)R, k * iterationsCount))); } } if (_debugGraph) { panelOutputGraph.m_bitmap = graph.AsBitmap; panelOutputGraph.Refresh(); labelResult.Text = "R = " + R + " (" + previousSqDistance + ") in " + iterationsCount + " iterations...\r\nBest = " + bestR + " (" + bestSqDistance + ") in " + bestIterationsCount + " iterations..."; } // if ( R < 1000.0 ) // throw new Exception( "Maybe R should be Math.Abs()'ed? (neighbors are all lying on a flat plane or in a ?" ); R = Math.Max(-10000.0, Math.Min(10000.0, R)); return((float)R); }