Radar scanner

A forum dedicated to WinForms version of LightningChart Ultimate.

Moderator: Queue Moderators

Post Reply
lethanh
Posts: 3
Joined: Tue Sep 09, 2014 5:35 am

Radar scanner

Post by lethanh » Tue Sep 09, 2014 5:46 am

Hi,

We are researching in Radar device. We need to build a software which displays Radar information and targets like this:
Image

especially scanning effect.

Does your SDK meet this need? (maybe more complex)

The polar chart like your screenshot is good for sample? Could you pls make a sample for radar effect?

Image

Thanks,

User avatar
ArctionPasi
Posts: 1367
Joined: Tue Mar 26, 2013 10:57 pm
Location: Finland
Contact:

Re: Radar scanner

Post by ArctionPasi » Tue Sep 09, 2014 2:59 pm

Hi,

thanks for asking. We'll try to provide a working example with source code this week.
LightningChart Support Team, PT

lethanh
Posts: 3
Joined: Tue Sep 09, 2014 5:35 am

Re: Radar scanner

Post by lethanh » Wed Sep 10, 2014 7:14 am

ArctionPasi wrote:Hi,

thanks for asking. We'll try to provide a working example with source code this week.
thanks you in advance,

User avatar
ArctionPasi
Posts: 1367
Joined: Tue Mar 26, 2013 10:57 pm
Location: Finland
Contact:

Re: Radar scanner

Post by ArctionPasi » Sun Sep 14, 2014 2:52 pm

Ok, made a radar simulation.

Just create a UserControl on your project and place that on your form. Use this code for the UserControl.

Set System.Windows.Forms.Timer with 10 ms interval to your UserControl as well, and set timerScanUpdater_Tick as its Tick event handler.

Code: Select all

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
using System.Diagnostics; 
using Arction.LightningChartUltimate;
using Arction.LightningChartUltimate.Axes;
using Arction.LightningChartUltimate.SeriesPolar;
using Arction.LightningChartUltimate.EventMarkers; 
using Arction.LightningChartUltimate.Views.ViewPolar; 

namespace DemoAppWinForms
{
    /// <summary>
    /// Polar radar example. 
    /// </summary>
    public partial class ExamplePolarRadar : UserControl
    {

        //Chart
        private LightningChartUltimate m_chart = null;

        private List<MovingObject> m_listMovingObjects = new List<MovingObject>(); 


        private const double RotationDegreesPerSec = 90;

        //Time that it takes to rotate full 360 degrees 
        private const double SweepTime = 360.0 / RotationDegreesPerSec;

        private Stopwatch m_stopWatchTimeLineAnim = new Stopwatch();
        private const int SectorCountInSweep = 45; 
        
        private const double RangeKm = 20;
        private static Color SweepColorBegin = Color.FromArgb(100, Color.Lime);
        private static Color SweepColorEnd = Color.FromArgb(0, 0, 0, 0);

        private const int MovingObjectCount = 10; 
        
        
        /// <summary>
        /// Constructor.
        /// </summary>
        public ExamplePolarRadar()
        {
            InitializeComponent();

            CreateChart();
            
            //Start animation time line
            m_stopWatchTimeLineAnim.Reset();
            m_stopWatchTimeLineAnim.Start();

            //Create a couple of moving objects 
            CreateMovingObjects(); 

            //Start the timer which updates the objects 
            this.timerScanUpdater.Start(); 
        }

        /// <summary>
        /// Create chart
        /// </summary>
        private void CreateChart()
        {
            //Create new chart
            m_chart = new LightningChartUltimate();

            //Disable rendering, strongly recommended before updating chart properties
            m_chart.BeginUpdate();

            //Set active view
            m_chart.ActiveView = ActiveView.ViewPolar;

            //Chart parent must be set
            m_chart.Parent = this;

            //Fill parent area with chart
            m_chart.Dock = DockStyle.Fill;

            //Chart name
            m_chart.Name = "ChartPolarRadar";

            m_chart.Title.Text = "Scanning radar chart, radius "+RangeKm.ToString()+ " km"; 

            //Get 1st polar axis and set it up
            AxisPolar axis = m_chart.ViewPolar.Axes[0];
            axis.MajorGrid.Visible = true;
            axis.MinorGrid.Visible = true;
            axis.TickMarkLocation = PolarGridTickmarkLocation.Outside;
            axis.Reversed = true;
            axis.InnerCircleRadiusPercentage = 0;
            axis.MajorDivCount = 4;
            axis.MinAmplitude = 0;
            axis.MaxAmplitude = RangeKm;
            axis.MouseScaling = true;
            axis.MouseScrolling = true;
            axis.Title.Visible = false; 
            axis.Visible = true; 
            axis.Units.RadialOffsetPercentage = 100;
            axis.AmplitudeAxisLineVisible = false;
            axis.LabelsFont = new Font("Tahoma", 25f, FontStyle.Regular);
            axis.MinorGrid.Visible = false;
            axis.AngularGrid.Visible = true;
            axis.AngleOrigin = -90;
            axis.AngularAxisCircleVisible = false;
            axis.AngularGrid.Color = Color.FromArgb(50, 0, 160, 120); 
            axis.AngularGrid.LineWidth = 2;
            axis.MajorGrid.Color = Color.FromArgb(50, 0, 160, 120); 

            //Remove existing PointLineSeries
            m_chart.ViewPolar.PointLineSeries.Clear();

            //Direction vector 
            PointLineSeriesPolar directionVec = new PointLineSeriesPolar(m_chart.ViewPolar, axis);
            directionVec.LineStyle.Width = 3;
            directionVec.LineStyle.Color = Color.White;
            directionVec.MouseInteraction = false; 
            m_chart.ViewPolar.PointLineSeries.Add(directionVec);

            m_chart.ViewPolar.GraphBackground.Color = Color.FromArgb(0, 32, 0);
            m_chart.ViewPolar.GraphBackground.GradientFill = GradientFill.Radial; 

            //Create sectors for gradient sweep 
            
            for (int iSector = 0; iSector < SectorCountInSweep; iSector++)
            {
                Sector sector = new Sector(m_chart.ViewPolar, axis);
                sector.Behind = true;
                sector.MinAmplitude = 0;
                sector.MaxAmplitude = RangeKm;
                sector.BorderlineStyle.Width = 0;
                sector.BorderlineStyle.Color = Color.Transparent;
                sector.Fill.GradientFill = GradientFill.Solid;
                sector.Fill.Color = ChartTools.CalcGradient(SweepColorBegin, SweepColorEnd, 100.0 * (double)iSector / (double)SectorCountInSweep);
                sector.Title.ShowInLegendBox = false;
                sector.MouseInteraction = false; 
                m_chart.ViewPolar.Sectors.Add(sector);
            }

            m_chart.ViewPolar.LegendBox.Visible = false;


            //Allow chart rendering
            m_chart.EndUpdate();

            m_chart.SizeChanged += new EventHandler(m_chart_SizeChanged);
        }

        /// <summary>
        /// Size has been changed
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void m_chart_SizeChanged(object sender, EventArgs e)
        {
            m_chart.BeginUpdate(); 
            
            //Update the moving objects to correct screen coordinates based on their polar angle and amplitude info
            foreach (MovingObject mo in m_listMovingObjects)
            {
                int iXCoord, iYCoord; 
                m_chart.ViewPolar.Axes[0].ValueToCoord(mo.PolarAngle, mo.PolarAmplitude,out iXCoord, out iYCoord);

                mo.PositionX = iXCoord;
                mo.PositionY = iYCoord;
            }
            m_chart.EndUpdate(); 
        }

        /// <summary>
        /// Create bunch of moving objects
        /// </summary>
        private void CreateMovingObjects()
        {
            double dWidth = m_chart.ClientSize.Width; 
            double dHeight = m_chart.ClientSize.Height;
            int iCoordX, iCoordY; 
            Random rand = new Random(); 
            int iCenterX, iCenterY, iDiameter;
            
            m_chart.ViewPolar.GetChartDiameterAndCenter(out iDiameter, out iCenterX, out iCenterY); 

            for (int i=0;i<MovingObjectCount; i++)
            {
             
                iCoordX = iCenterX - iDiameter/4 + (int)(rand.NextDouble() * (double) iDiameter/2);
                iCoordY = iCenterY - iDiameter/4 + (int)(rand.NextDouble() * (double) iDiameter/2); 
                
                double dKph =  500 + rand.NextDouble() * 1500.0; //Simulate jet fighter speeds

                m_listMovingObjects.Add(new MovingObject(m_chart.ViewPolar, iCoordX, iCoordY,
                    m_stopWatchTimeLineAnim.ElapsedMilliseconds / 1000.0, rand.NextDouble() * 360.0, dKph, SweepTime * 2.0));

            }
        } 

        /// <summary>
        /// Timer that updates the scanning effect, object positions and fading.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void timerScanUpdater_Tick(object sender, EventArgs e)
        {
            if (m_chart == null)
                return;

            m_chart.BeginUpdate(); 
            
            double dTimeSec = m_stopWatchTimeLineAnim.ElapsedMilliseconds / 1000.0;
            double dCurrentAngleDeg = (RotationDegreesPerSec * dTimeSec); 
            if(dCurrentAngleDeg < 0)
                dCurrentAngleDeg += 360.0; 
            dCurrentAngleDeg %= 360.0;

            //Update the beam direction vector
            PointLineSeriesPolar directionVec = m_chart.ViewPolar.PointLineSeries[0];
            directionVec.Points = new PolarSeriesPoint[]
                { new PolarSeriesPoint(dCurrentAngleDeg, 0), new PolarSeriesPoint(dCurrentAngleDeg, RangeKm) };


            //Update the sweep sectors 
            double dSectorStepDeg = 45.0 / (double)SectorCountInSweep; 

            for (int iSector = 0; iSector < SectorCountInSweep; iSector++)
            {
                Sector sector = m_chart.ViewPolar.Sectors[iSector];
                sector.BeginAngle = dCurrentAngleDeg - (double)iSector * dSectorStepDeg;
                sector.EndAngle = dCurrentAngleDeg - (double)(iSector+1) * dSectorStepDeg; 
            }

            //Update the targets  
            UpdateMovingObjects(dCurrentAngleDeg, dTimeSec); 

            m_chart.EndUpdate(); 
        }


        /// <summary>
        /// Update moving objects
        /// </summary>
        /// <param name="currentAngleDeg"></param>
        /// <param name="timeSec"></param>
        void UpdateMovingObjects(double currentAngleDeg, double timeSec)
        {
            AxisPolar axis = m_chart.ViewPolar.Axes[0]; 
            
            foreach(MovingObject mo in m_listMovingObjects)
            {
                bool bStartNow = false; 
                //axis.CoordToValue((int) mo.PositionX, (int)mo.PositionY, out dObjectAngle, out dObjectDistance);
                mo.UpdatePosition(timeSec); 

                if (mo.Started == false)
                {
                    //if(m_chart.ViewPolar.Sectors[0].IsMouseOver((int)mo.PositionX, (int)mo.PositionY))
                    if (currentAngleDeg >= mo.PolarAngle && currentAngleDeg <= mo.PolarAngle + 10)
                        bStartNow = true;
                }
                else
                {
                    if (
                        //((timeSec - mo.AnimTimeLineTimeStartedSec) > (0.5 * SweepTime))
                        //&& //(m_chart.ViewPolar.Sectors[0].IsMouseOver((int)mo.PositionX, (int)mo.PositionY)))
                        (currentAngleDeg >= mo.PolarAngle && currentAngleDeg <= mo.PolarAngle + 10))
                    {
                        bStartNow = true; 
                    }
                }
                
                if (bStartNow)
                {
                    mo.StartFadeaway(timeSec); 
                }
                mo.UpdateFadeaway(timeSec);
            }

        }

       
    }

    /// <summary>
    /// Moving object class. This object represtents an object on the radar. 
    /// </summary>
    public class MovingObject
    {
        static Color MovingObjectCenter = Color.FromArgb(255, 0, 255, 255); 
        static Color MovingObjectEdge = Color.FromArgb(100, MovingObjectCenter);

        public double PositionX;
        public double PositionY;
        public double AnimTimeLineTimeStartedSec;
        public double CartesianHeadingAngle;
        public double CartesianVelocityKph;
        public double AnimTimeLineSecsWhenLastPosUpdated; 
        public bool Started = false;
        public double FadeAwayDuration; 
        public PolarEventMarker Marker;
        public AxisPolar Axis;
        public ViewPolar ChartView; 
        public double PolarAngle;
        public double PolarAmplitude; 

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="chartView">Owner polar view</param>
        /// <param name="x">X position as screen coordinates</param>
        /// <param name="y">Y position as screen coordinates</param>
        /// <param name="createdSeconds">Creating timestamp in seconds</param>
        /// <param name="cartesianHeading">Heading in screen coordinates</param>
        /// <param name="cartesianVelocityKph">Velocity, km/h</param>
        /// <param name="totalSweepDuration">Sweep duration in seconds</param>
        public MovingObject(ViewPolar chartView,
            double x, double y, double createdSeconds, double cartesianHeading, double cartesianVelocityKph, double totalSweepDuration)
        {
            PositionX = x;
            PositionY = y;
            AnimTimeLineTimeStartedSec = createdSeconds;
            CartesianHeadingAngle = cartesianHeading;
            CartesianVelocityKph = cartesianVelocityKph;
            AnimTimeLineSecsWhenLastPosUpdated = createdSeconds;
            FadeAwayDuration = totalSweepDuration; 

            //Add a marker that represents the moving object
            Axis = chartView.Axes[0];
            Marker = new PolarEventMarker();

            double dAngle, dAmplitude; 
            Axis.CoordToValue((int) x,(int) y,out dAngle, out dAmplitude);
            Marker.AngleValue = dAngle;
            Marker.Amplitude = dAmplitude;
            Marker.Symbol.Shape = Shape.Circle;
            Marker.Symbol.Color1 = MovingObjectCenter;
            Marker.Symbol.Color2 = MovingObjectEdge;
            Marker.Symbol.Width = 17;
            Marker.Symbol.Height = 17;
            Marker.Symbol.BorderWidth = 0;
            Marker.Label.Visible = false;
            Marker.Visible = false;
            Marker.MouseInteraction = false; 
            chartView.Markers.Add(Marker); 

            PolarAmplitude = dAmplitude;
            PolarAngle = dAngle;
            
            ChartView = chartView;
            

        }

        /// <summary>
        /// Start fadeaway animation
        /// </summary>
        /// <param name="timeSec">Time in seconds</param>
        public void StartFadeaway(double timeSec)
        {
            Started = true;
            AnimTimeLineTimeStartedSec = timeSec;
            Marker.Visible = true; 
            double dAngle, dAmplitude;
            Axis.CoordToValue((int)PositionX, (int)PositionY, out dAngle, out dAmplitude);
            Marker.AngleValue = dAngle;
            Marker.Amplitude = dAmplitude;
            
            Marker.Visible = dAmplitude <= Axis.MaxAmplitude;

            if (Marker.Visible == false)
                CartesianHeadingAngle += 180.0;//Get it back to screen by reversing its heading
                
        }

        /// <summary>
        /// Update object position
        /// </summary>
        /// <param name="timeSec">Time in seconds</param>
        public void UpdatePosition(double timeSec)
        {
            double dAngleRad = MathRoutines.DegreesAsRadians(CartesianHeadingAngle);
            double dPixelsPerKm = GetPixelsPerKm();

            double dMoveNowPixels = dPixelsPerKm * (timeSec - AnimTimeLineSecsWhenLastPosUpdated) * CartesianVelocityKph / 3600.0;

            PositionX += dMoveNowPixels * Math.Cos(dAngleRad);
            PositionY -= dMoveNowPixels * Math.Sin(dAngleRad);

            double dAngle, dAmplitude;
            Axis.CoordToValue((int)PositionX, (int)PositionY, out dAngle, out dAmplitude);
            PolarAngle = dAngle;
            PolarAmplitude = dAmplitude;

            AnimTimeLineSecsWhenLastPosUpdated = timeSec;
        }


        /// <summary>
        /// Calculate how many pixels represent 1 km
        /// </summary>
        /// <returns>Pixels per km</returns>
        private double GetPixelsPerKm()
        {
            int iXMax, iYMax;
            Axis.ValueToCoord(0, Axis.MaxAmplitude, out iXMax, out iYMax);
            double dXMax = (double)iXMax;
            double dYMax = (double)iYMax;

            int iXMin, iYMin;
            Axis.ValueToCoord(0, Axis.MinAmplitude, out iXMin, out iYMin);
            double dXMin = (double)iXMin;
            double dYMin = (double)iYMin;

            return Math.Sqrt((dXMax - dXMin) * (dXMax - dXMin) + (dYMax - dYMin) * (dYMax - dYMin)) / Axis.MaxAmplitude;

        }

        /// <summary>
        /// Update fadeaway
        /// </summary>
        /// <param name="timeSec">Time in seconds</param>
        public void UpdateFadeaway(double timeSec)
        {
            double dAnimPosPercents = (timeSec - AnimTimeLineTimeStartedSec) / FadeAwayDuration * 100.0;
            Marker.Symbol.Color1 = ChartTools.CalcGradient(MovingObjectCenter, Color.FromArgb(0, 0, 0, 0), dAnimPosPercents);
            Marker.Symbol.Color2 = ChartTools.CalcGradient(MovingObjectEdge, Color.FromArgb(0, 0, 0, 0), dAnimPosPercents);
            Marker.Symbol.Width = (float)(11.0 + (100 - dAnimPosPercents) * 17.0 / 100.0);
            Marker.Symbol.Height = (float)(11.0 + (100 - dAnimPosPercents) * 17.0 / 100.0);
        }
    }

}

Thet it makes a live simulation, using jet fighter level object speeds.
Radar scanner chart
Radar scanner chart
radar scanner.jpg (109.62 KiB) Viewed 11667 times
LightningChart Support Team, PT

lethanh
Posts: 3
Joined: Tue Sep 09, 2014 5:35 am

Re: Radar scanner

Post by lethanh » Mon Sep 15, 2014 3:44 am

Awesome supports, we will add LightningChart to our project. Thanks

Post Reply