Using of .shp files in 2D map

A forum dedicated to WinForms version of LightningChart Ultimate.

Moderator: Queue Moderators

Post Reply
hallo888
Posts: 43
Joined: Wed Mar 26, 2014 10:56 am

Using of .shp files in 2D map

Post by hallo888 » Tue Apr 08, 2014 9:12 am

Hi,

I had some .shp files which i have converted in .md format using the converter inside ExampleMaps.cs.

May i know how do i add it to be displayed on top of my existing map? Is what i have done correct?

Code: Select all

//default map
m_chart.ViewXY.Maps.Path = <md path>
m_chart.ViewXY.Maps.Type = Map.MapType.WorldHigh;
m_chart.ViewXY.CityOptions.ShowCities = CityOptions.CityType.Major

//Would like to add a map of holland shape file on top of the default map. The .shp file had been converted into a .md format using the converter inside ExampleMaps.c
Map mapHolland = new Map();
mapHolland.Path = <path to md file>
mapHolland.Filename = "Holland.md";

MapLayer ml = new MapLayer(mapHolland);
ml.Visible = true;
ml.priority = 0;

m_chart.ViewXY.Maps.Layers.SetValue(ml,1);
Can .md files be using in 3D globe as well? Basically i would like to use the information in the .md map to label the countries in the in the 3D globe. Is it possible to do so? Would be great if there are sample codes for such purpose.

Please advise.

Thank you in advance.

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

Re: Using of .shp files in 2D map

Post by ArctionPasi » Wed Apr 09, 2014 6:27 am

The chart can show only one vector map (md file). One md file can have several layers, and their visibility can be controlled, and fill types set etc. So the layers must be defined in the shp import stage.

In contrast, there can be many individual TileLayers, also over the vector maps.

3D scene doesn't support shp/md vector maps or tile layers, they are for 2D only. But these can be captured from the chart's client area as a bitmap, and the bitmap can be set as SurfaceMeshSeries 3D's fill. 2D chart can be next to the 3D chart, or hidden behind it. Mouse-interactivity of the vector maps can't be used though, so you can't point a city or highlight a country by moving mouse over it in 3D globe, at least not directly.
LightningChart Support Team, PT

hallo888
Posts: 43
Joined: Wed Mar 26, 2014 10:56 am

Re: Using of .shp files in 2D map

Post by hallo888 » Thu Apr 10, 2014 6:38 am

Hi,

I have extracted the center location(lat,long) information from the .md file and thinking of using it to mark the countries on the 3D globe. My code are as follows:

Code: Select all

public struct CountryData
{
    public string CountryName;
    public PointFloat centerPoint; //for storing the center location the country retrieve from .md file, modified the   GetCountryData() in the world population example.
}

private void labelCountry()
{
    List<CountryData> listCountries = GetCountryData();
    foreach(CountryData country in listCountries)
    {
       Annotation3D countrylabel = new Annotation3D(m_chart.View3D, Axis3DBinding.Primary, Axis3DBinding.Primary, Axis3DBinding.Primary)
      countrylabel.Text = country.CountryName;
      MapCoordinate mc = new MapCoordinate(country.centerPoint.Y, country.centerPoint.X);
      PointDouble3D p3d = ChartTools.ConvertMapCoordTo3DPointOnSphere(mc,53);

      countrylabel.TargetAxisValue.X = pd3.X;
      countrylabel.TargetAxisValue.Y = pd3.Y;
      countrylabel.TargetAxisValue.Z = pd3.Z;

      countrylabel.LocationCoordinateSystem = CoordinateSystem.RelativeCoordinatesToTarget;
      countrylabel.LocationAxisValue.X = pd3.X;
      countrylabel.LocationAxisValue.Y = pd3.Y;
      countrylabel.LocationAxisValue.Z = pd3.Z;'

      m_chart.View3D.Annotations.Add(countrylabel);
    }
}
Is there any other classes, apart from Annotation3D, to be able to do such labelling? Seems like for annotation3D, even if the country name is supposed to be behind a globe, it also get show up. Basically, I could see all the country names regardless which continent i am at. Is there any settings/properties that control the annotation i can see? I only want to see name of the country that the globe is currently showing. Or is there any other markers that could achieve what i want?

Most importantly, is it feasible to do what i intend to do?

Please advise.

THank you in advance.

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

Re: Using of .shp files in 2D map

Post by ArctionPasi » Thu Apr 10, 2014 2:48 pm

Controlling annotation.Visible state by camera distance or so on would be one solution.
LightningChart Support Team, PT

hallo888
Posts: 43
Joined: Wed Mar 26, 2014 10:56 am

Re: Using of .shp files in 2D map

Post by hallo888 » Fri Apr 11, 2014 1:24 am

ArctionPasi wrote:Controlling annotation.Visible state by camera distance or so on would be one solution.
Hi, sorry but could you explain more on what is meant by controlling annotation.Visible state by camera distance? This setting is done via the camera class or annotation class? I couldn't find any camera related properties setting in Annotation3D class.

May i know which is the class that is use for labelling the country names in ViewXY.Map, that is something that i want to achieve with Annotation3D, where the label is "fixed"/stuck to the location and will not always show up.

Thanks for your advice in advance.

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

Re: Using of .shp files in 2D map

Post by ArctionPasi » Sun Apr 13, 2014 3:08 pm

I modified LC slightly so you can get the camera location, and calculate the distance to center of the globe or annotations.

http://www.arction.com/download/LC_v.5.5.2.7_net4.zip It's a .NET4 LC assemblies pack.

This is ExampleGlobeSurface3D.cs code, which shows route label annotations only if they are in the visible side of globe. When you rotate the globe, annotations' visibility get updated.

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 Arction.LightningChartUltimate;
using Arction.LightningChartUltimate.Series3D;
using Arction.LightningChartUltimate.Views.View3D;
using Arction.LightningChartUltimate.Axes;
using Arction.LightningChartUltimate.Annotations;
using System.Diagnostics;
using System.Reflection;


namespace DemoAppLightningChartUltimate
{
    /// <summary>
    /// Globe surface example
    /// </summary>
    public partial class ExampleGlobeSurface3D : UserControl
    {
        //Chart
        private LightningChartUltimate m_chart = null;

        //2D array of elevation data
        private double[,] m_aElevationData = null;

        //Photo that is shown over the surface
        private Image m_photo = null;

        private const double EarthDiameterKm = 6371;


        /// <summary>
        /// Constructor.
        /// </summary>
        public ExampleGlobeSurface3D()
        {
            InitializeComponent();

            m_photo = Bitmap.FromFile(Application.StartupPath + "\\Resources\\WorldPhoto3600x1800.jpg");

            CreateChart();
        }

        /// <summary> 
        /// Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            if (m_chart != null)
            {
                m_chart.Dispose(); //Chart should be explicitely disposed, to free graphics resources instantly 
                m_chart = null;
            }
            base.Dispose(disposing);
        }

        /// <summary>
        /// Get demo description and source file name.
        /// </summary>
        /// <param name="sourceCodeFilename">Demo source file name</param>
        /// <returns>description</returns>
        public string GetDescription(out string sourceCodeFilename)
        {
            //Resolve source code file name by throwing an exception and investigating the source file name 
            try
            {
                throw new Exception();
            }
            catch (Exception e)
            {
                sourceCodeFilename = ChartTools.GetSourceCodeFilenameFromStackTrace(e.StackTrace);
            }
            return "Globe demo, earth surface is made with SurfaceMeshSeries3D, from manipulated SRTM-90 (CGIAR-CSI) elevation data and a photo (NASA)."
             + "\nFlight routes are calculated with ChartTools methods from city coordinates using shortest Great Circle route. "
             + "PointLineSeries3D and Annotation objects are used to present them.";
        }

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

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

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

            //Chart parent must be set
            m_chart.Parent = splitContainer1.Panel1;

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

            //Chart name
            m_chart.Name = "Globe chart";

            //Hide walls
            List<WallBase> listWalls = m_chart.View3D.GetWalls();
            foreach (WallBase wall in listWalls)
                wall.Visible = false;

            //Set all axis range same
            m_chart.View3D.XAxisPrimary3D.SetRange(-EarthDiameterKm, EarthDiameterKm);
            m_chart.View3D.YAxisPrimary3D.SetRange(-EarthDiameterKm, EarthDiameterKm);
            m_chart.View3D.ZAxisPrimary3D.SetRange(-EarthDiameterKm, EarthDiameterKm);

            //Disable second light
            m_chart.View3D.Lights[1].Enabled = false;
            m_chart.View3D.Lights[1].LocationFromCamera = true;

            //Set enhanced surface rendering mode 
            m_chart.View3D.UsePerPixelLighting = true;

            //Setup dimensions to same value
            m_chart.View3D.Dimensions.X = 200;
            m_chart.View3D.Dimensions.Y = 200;
            m_chart.View3D.Dimensions.Z = 200;

            //Setup camera
            m_chart.View3D.Camera.MinimumViewDistance = 10;
            m_chart.View3D.Camera.SetPredefinedCamera(PredefinedCamera.FrontPerspective);
            m_chart.View3D.Camera.ViewDistance = 200;
            m_chart.View3D.Camera.RotationX = 60;
            m_chart.View3D.Camera.RotationY = -25;

            //Hide legend box
            m_chart.View3D.LegendBox.Visible = false;

            //Don't allow panning because it shifts the center point of rotation
            m_chart.View3D.ZoomPanOptions.RightMouseButtonAction = MouseButtonAction3D.Rotate;

            //Hide all axes
            List<Axis3DBase> listAxes = m_chart.View3D.GetAxes();
            foreach (Axis3DBase axis in listAxes)
                axis.Visible = false;

            //Make data
            MakeElevationData();

            //Create series
            CreateSurfaceSeries();
            CreateRoutes();

            //Set view point
            viewPointEditor1.Chart = m_chart;

            m_chart.View3D.CameraViewChanged += new View3D.CameraViewChangedHandler(View3D_CameraViewChanged);

            UpdateAnnotationsVisiblity();

            //Allow chart rendering
            m_chart.EndUpdate();

        }

        void View3D_CameraViewChanged(Camera3D newCameraViewPoint, View3D view, LightningChartUltimate chart)
        {
            UpdateAnnotationsVisiblity(); 
        }
        
        void UpdateAnnotationsVisiblity()
        {
            //Check if annotations' visibility must be changed. 
            //Don't update their status if not necessary to avoid extra refresh. 
            
            bool bShowLabels = checkBoxShowRouteLabels.Checked; 
            
            PointDouble3D cameraLocation = m_chart.View3D.Camera.GetLocationAs3DWorldCoord();

            //Use any series here that is bound to same axes than the annotations. Surface mesh is in this example.
            SeriesBase3D dummySeries = m_chart.View3D.SurfaceMeshSeries3D[0];
            
            //Camera distance from center of earth 
            double dCamDistFromCenter = CalcDistance(cameraLocation, new PointDouble3D(0, 0, 0));

            bool bOneOrMoreAnnotVisibilityNeedsUpdating = false;

            bool[] aNearEnoughToShow = new bool[m_chart.View3D.Annotations.Count];

            int iAnnotIndex = 0;
            foreach(Annotation3D annot in m_chart.View3D.Annotations)
            {
                PointDouble3D annotLocation = m_chart.View3D.ConvertSeriesValueTo3DWorldCoord(dummySeries, annot.TargetAxisValues.X, annot.TargetAxisValues.Y, annot.TargetAxisValues.Z);
                double dist = CalcDistance(annotLocation, cameraLocation);
                aNearEnoughToShow[iAnnotIndex] = (dist < dCamDistFromCenter) && bShowLabels;
                if (aNearEnoughToShow[iAnnotIndex] != annot.Visible)
                    bOneOrMoreAnnotVisibilityNeedsUpdating = true; 
                iAnnotIndex++;
            }


            if (bOneOrMoreAnnotVisibilityNeedsUpdating)
            {
                m_chart.BeginUpdate();
                iAnnotIndex = 0; 
                foreach (Annotation3D annot in m_chart.View3D.Annotations)
                {
                    annot.Visible = aNearEnoughToShow[iAnnotIndex];
                    iAnnotIndex++;
                }
                m_chart.EndUpdate(); 
            }

        }
        
        /// <summary>
        /// Calculate distance between two points 
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <returns></returns>
        double CalcDistance(PointDouble3D a, PointDouble3D b)
        {
            return Math.Sqrt ((b.X - a.X) * (b.X - a.X) + (b.Y - a.Y) * (b.Y - a.Y) + (b.Z - a.Z) * (b.Z - a.Z));
        }


        /// <summary>
        /// Make elevation data.
        /// </summary>
        private void MakeElevationData()
        {
            //Get surface elevation data from bitmap. In this elevation bitmap, white value represents high elevation, 
            //and dark value low elevation
            Bitmap bitmapElevation = (Bitmap)ChartTools.ImageFromResource("Resources." + "WorldElevation1024x512.png", Assembly.GetExecutingAssembly());

            //Use fast method for getting pixel colors 
            Color[,] aElevationData = ChartTools.GetPixelColors(bitmapElevation);

            int iWidth = aElevationData.GetLength(0);
            int iHeight = aElevationData.GetLength(1);

            m_aElevationData = new double[iWidth, iHeight];

            for (int iColumn = 0; iColumn < iWidth; iColumn++)
            {
                for (int iRow = 0; iRow < iHeight; iRow++)
                {
                    m_aElevationData[iColumn, iRow] = (double)(
                        aElevationData[iColumn, iRow].R +
                        aElevationData[iColumn, iRow].G +
                        aElevationData[iColumn, iRow].B) / (3.0 * 255.0);
                }
            }
        }

        /// <summary>
        /// Create routes.
        /// </summary>
        private void CreateRoutes()
        {
            //Route1 : Helsinki, Finland - New York, USA
            MapCoordinate[] route1WayPoints = new MapCoordinate[2];
            route1WayPoints[0] = new MapCoordinate(60, 10, 0, LatitudePostfix.N, 24, 53, 0, LongitudePostfix.E);
            route1WayPoints[1] = new MapCoordinate(40, 47, 0, LatitudePostfix.N, 73, 58, 0, LongitudePostfix.W);
            CreateRoute(route1WayPoints, Color.Green, new string[] { "Helsinki, Finland", "New York, USA" });

            //Route2: Los Angeles, USA - Tokyo, Japan - Zürich, Switzerland 
            MapCoordinate[] route2WayPoints = new MapCoordinate[3];
            route2WayPoints[0] = new MapCoordinate(34, 37, 4, LatitudePostfix.N, 117, 50, 1, LongitudePostfix.W);
            route2WayPoints[1] = new MapCoordinate(35, 40, 60, LatitudePostfix.N, 139, 46, 0, LongitudePostfix.E);
            route2WayPoints[2] = new MapCoordinate(47, 22, 0, LatitudePostfix.N, 8, 33, 0, LongitudePostfix.E);
            CreateRoute(route2WayPoints, Color.Red, new string[] { "Los Angeles, USA", "Tokyo, Japan", "Zürich, Switzerland" });

            //Melbourne, Australia - Wellington, New Zealand - Sao Paulo, Brazil
            MapCoordinate[] route4WayPoints = new MapCoordinate[3];
            route4WayPoints[0] = new MapCoordinate(37, 48, 49, LatitudePostfix.S, 144, 57, 47, LongitudePostfix.E);
            route4WayPoints[1] = new MapCoordinate(41, 17, 20, LatitudePostfix.S, 174, 46, 38, LongitudePostfix.E);
            route4WayPoints[2] = new MapCoordinate(23, 31, 60, LatitudePostfix.S, 46, 37, 0, LongitudePostfix.W);
            CreateRoute(route4WayPoints, Color.Blue, new string[] { "Melbourne, Australia", "Wellington, New Zealand", "Sao Paulo, Brazil" });
        }

        /// <summary>
        /// Create route as PointLineSeries3D.
        /// </summary>
        /// <param name="wayPoints">Route points</param>
        /// <param name="lineColor">Route color</param>
        /// <param name="wayPointNames">Names of waypoints</param>
        private void CreateRoute(MapCoordinate[] wayPoints, Color lineColor, string[] wayPointNames)
        {
            const double AngleStep = 3.0;
            const double Radius = EarthDiameterKm * 1.02; //above the globe surface

            for (int iLeg = 0; iLeg < wayPoints.Length - 1; iLeg++)
            {
                //Line series per successive route point pair (leg)
                PointLineSeries3D lineSeries = new PointLineSeries3D(m_chart.View3D, Axis3DBinding.Primary, Axis3DBinding.Primary, Axis3DBinding.Primary);
                lineSeries.PointsVisible = false;
                lineSeries.LineVisible = true;
                lineSeries.LineStyle.Width = 3;
                lineSeries.LineStyle.Color = lineColor;

                //Coordinates as "Great Circle route" for current and next point
                MapCoordinate[] aCoords = ChartTools.CalculateSphericalRoute(wayPoints[iLeg], wayPoints[iLeg + 1], Radius, AngleStep);
                if (aCoords != null)
                {
                    int iCoordCount = aCoords.Length;
                    PointDouble3D[] aPoints = new PointDouble3D[iCoordCount];
                    int iPoint = 0;
                    foreach (MapCoordinate coord in aCoords)
                    {
                        aPoints[iPoint++] = ChartTools.ConvertMapCoordTo3DPointOnSphere(coord, Radius);
                    }
                    lineSeries.Points = aPoints;
                    m_chart.View3D.PointLineSeries3D.Add(lineSeries);

                    double dDistanceKm = ChartTools.CalculateMapDistance(wayPoints[iLeg], wayPoints[iLeg + 1]);

                    //Add label to show the statistics of the route 
                    Annotation3D label = new Annotation3D(m_chart.View3D, Axis3DBinding.Primary, Axis3DBinding.Primary, Axis3DBinding.Primary);
                    label.Fill.Style = RectFillStyle.None;
                    label.Shadow.Visible = false;
                    label.BorderVisible = false;
                    label.Style = AnnotationStyle.Rectangle;
                    label.TextStyle.Color = lineColor;
                    label.LocationCoordinateSystem = CoordinateSystem.RelativeCoordinatesToTarget;
                    label.LocationRelativeOffset.SetValues(0, 0);
                    label.MouseInteraction = false;
                    label.TextStyle.Font = new Font(FontFamily.GenericSansSerif, 9, FontStyle.Bold);
                    label.TextStyle.Shadow.Style = TextShadowStyle.HighContrast;
                    label.TextStyle.Shadow.ContrastColor = Color.FromArgb(200, Color.White);
                    label.Text = wayPointNames[iLeg] + " - " + wayPointNames[iLeg + 1] + "\nDistance: " + dDistanceKm.ToString("0") + " km";
                    PointDouble3D midPoint = aPoints[aPoints.Length / 2];
                    label.TargetAxisValues.SetValues(midPoint.X, midPoint.Y, midPoint.Z);
                    label.Visible = false;
                    m_chart.View3D.Annotations.Add(label);

                }
            }

            //Add waypoints separate point line series 
            PointLineSeries3D pointSeries = new PointLineSeries3D(m_chart.View3D, Axis3DBinding.Primary, Axis3DBinding.Primary, Axis3DBinding.Primary);
            pointSeries.PointsVisible = true;
            pointSeries.LineVisible = false;
            pointSeries.PointStyle.Shape = PointShape3D.Sphere;
            pointSeries.PointStyle.Size.SetValues(2, 2, 2);

            PointDouble3D[] aWaypoints3D = new PointDouble3D[wayPoints.Length];
            for (int iWaypoint = 0; iWaypoint < wayPoints.Length; iWaypoint++)
            {
                aWaypoints3D[iWaypoint] = ChartTools.ConvertMapCoordTo3DPointOnSphere(wayPoints[iWaypoint], Radius);
            }
            pointSeries.Points = aWaypoints3D;
            m_chart.View3D.PointLineSeries3D.Add(pointSeries);
        }



        /// <summary>
        /// Delete routes (labels and point line series).
        /// </summary>
        private void DeleteRoutes()
        {
            m_chart.View3D.PointLineSeries3D.Clear();
            m_chart.View3D.Annotations.Clear();
        }

        /// <summary>
        /// Use surface mesh series to represent globe.
        /// </summary>
        private void CreateSurfaceSeries()
        {
            //Remove old series
            if (m_chart.View3D.SurfaceMeshSeries3D.Count > 0)
                m_chart.View3D.SurfaceMeshSeries3D.Clear();

            SurfaceMeshSeries3D surface = new SurfaceMeshSeries3D(m_chart.View3D, Axis3DBinding.Primary, Axis3DBinding.Primary, Axis3DBinding.Primary);
            surface.BitmapFill.Image = m_photo;
            surface.BitmapFill.MirrorHorizontal = false;
            surface.BitmapFill.MirrorVertical = true;
            surface.Fill = SurfaceFillStyle.Bitmap;

            surface.WireframeType = SurfaceWireframeType.None;
            surface.ContourLineType = ContourLineType.None;
            //Lit the other side, as the surface is constructed backwards
            surface.LightedSurface = LightedSurfaceSide.Bottom;
            surface.Material.DiffuseColor = Color.FromArgb(200, 200, 200);
            surface.Material.SpecularPower = 5;
            surface.ColorSaturation = 80;

            int iSlices = m_aElevationData.GetLength(0);
            int iStacks = m_aElevationData.GetLength(1);

            surface.SizeX = iSlices;
            surface.SizeZ = iStacks;

            SurfacePoint[,] data = surface.Data;
            double dRadius = EarthDiameterKm;
            double dX, dY, dZ;
            double dScale;
            double dTheta;
            double dElevation;
            double dPhi;
            double dElevationFactor = (double)trackBarElevation.Value * dRadius / 100.0;
            for (int iStack = 0; iStack < iStacks; iStack++)
            {
                dPhi = Math.PI / 2.0 - (double)iStack * Math.PI / (double)(iStacks - 1);
                for (int iSlice = 0; iSlice < iSlices; iSlice++)
                {
                    dElevation = m_aElevationData[iSlice, iStack] * dElevationFactor;

                    dY = (dRadius + dElevation) * Math.Sin(dPhi);

                    dScale = -Math.Cos(dPhi) * (dRadius + dElevation);

                    dTheta = -(double)iSlice * 2.0 * Math.PI / (double)(iSlices - 1) - Math.PI;

                    dX = dScale * Math.Sin(dTheta);
                    dZ = dScale * Math.Cos(dTheta);

                    data[iSlice, iStack].X = dX;
                    data[iSlice, iStack].Y = dY;
                    data[iSlice, iStack].Z = dZ;
                }
            }
            m_chart.View3D.SurfaceMeshSeries3D.Add(surface);
        }

        /// <summary>
        /// Delete grid.
        /// </summary>
        private void DeleteGrid()
        {
            //Disable rendering, strongly recommended before updating chart properties
            m_chart.BeginUpdate();

            int iCount = m_chart.View3D.PointLineSeries3D.Count;
            for (int iLineSeries = iCount - 1; iLineSeries >= 0; iLineSeries--)
            {
                if (m_chart.View3D.PointLineSeries3D[iLineSeries].Title.Text.IndexOf("LatLon") >= 0)
                {
                    m_chart.View3D.PointLineSeries3D.RemoveAt(iLineSeries);
                }
            }

            //Allow chart rendering
            m_chart.EndUpdate();
        }

        /// <summary>
        /// Create grid.
        /// </summary>
        private void CreateGrid()
        {
            const double Radius = EarthDiameterKm * 1.01;

            Color lineColor = Color.FromArgb(60, Color.Cyan);

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

            //Longitude circles
            int iCircle = 0;
            for (double dLongitude = -180; dLongitude < 0; dLongitude += 15)
            {
                PointLineSeries3D circleSeries = new PointLineSeries3D(m_chart.View3D, Axis3DBinding.Primary, Axis3DBinding.Primary, Axis3DBinding.Primary);
                circleSeries.PointsVisible = false;
                circleSeries.LineStyle.Color = lineColor;
                circleSeries.Title.Text = "LatLon " + iCircle.ToString();
                MapCoordinate[] aCoords = ChartTools.CalculateSphereFullGreatCircleCoords(new MapCoordinate(100, dLongitude), new MapCoordinate(-100, dLongitude), 5);
                int iCount = 0;
                if (aCoords != null)
                {
                    iCount = aCoords.Length;
                    PointDouble3D[] aPoints = new PointDouble3D[iCount];
                    int iPoint = 0;
                    foreach (MapCoordinate coord in aCoords)
                    {
                        aPoints[iPoint++] = ChartTools.ConvertMapCoordTo3DPointOnSphere(coord, Radius);
                    }
                    circleSeries.Points = aPoints;
                }
                m_chart.View3D.PointLineSeries3D.Add(circleSeries);
                iCircle++;
            }

            //Latitude circles 
            //Great circle routine is not valid for this, because the radius center is not in the center of the globe. 
            for (double dLatitude = -75; dLatitude <= 75; dLatitude += 15)
            {
                PointLineSeries3D circleSeries = new PointLineSeries3D(m_chart.View3D, Axis3DBinding.Primary, Axis3DBinding.Primary, Axis3DBinding.Primary);
                circleSeries.PointsVisible = false;
                circleSeries.LineStyle.Color = lineColor;
                circleSeries.Title.Text = "LatLon " + iCircle.ToString();
                PointDouble3D[] aPoints = new PointDouble3D[360 / 5 + 1];
                int iPoint = 0;
                for (double dLongitude = -180; dLongitude <= 180; dLongitude += 5)
                {
                    aPoints[iPoint++] = ChartTools.ConvertMapCoordTo3DPointOnSphere(new MapCoordinate(dLatitude, dLongitude), Radius);
                }
                circleSeries.Points = aPoints;
                m_chart.View3D.PointLineSeries3D.Add(circleSeries);
                iCircle++;
            }

            //Allow chart rendering
            m_chart.EndUpdate();
        }

        /// <summary>
        /// Create new series if elevation changes.
        /// </summary>
        /// <param name="sender">sender</param>
        /// <param name="args">arguments</param>
        private void trackBarElevation_Scroll(object sender, EventArgs e)
        {
            //Disable rendering, strongly recommended before updating chart properties
            m_chart.BeginUpdate();

            CreateSurfaceSeries();

            //Allow chart rendering
            m_chart.EndUpdate();
        }

        /// <summary>
        /// Show/hide routes.
        /// </summary>
        /// <param name="sender">sender</param>
        /// <param name="args">arguments</param>
        private void checkBoxRoute_CheckedChanged(object sender, EventArgs e)
        {
            //Disable rendering, strongly recommended before updating chart properties
            m_chart.BeginUpdate();

            if (checkBoxRoute.Checked)
            {
                CreateRoutes();
            }
            else
            {
                DeleteRoutes();
            }

            //Allow chart rendering
            m_chart.EndUpdate();
        }

        /// <summary>
        /// Toggle route labels visibility.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void checkBoxShowRouteLabels_CheckedChanged(object sender, EventArgs e)
        {
            if (m_chart != null)
            {
                UpdateAnnotationsVisiblity(); 
            }
        }

        /// <summary>
        /// Show/hide lon/lat grid.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void checkBoxLonLatGrid_CheckedChanged(object sender, EventArgs e)
        {
            DeleteGrid();
            if (checkBoxLonLatGrid.Checked)
            {
                CreateGrid();
            }
        }
    }
}


Looks like this:
3D world map with routes, annotations hidden from the other side of the world by distance.
3D world map with routes, annotations hidden from the other side of the world by distance.
globe_routes.jpg (131.79 KiB) Viewed 18420 times
LightningChart Support Team, PT

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

Re: Using of .shp files in 2D map

Post by ArctionPasi » Sun Apr 13, 2014 3:20 pm

May i know which is the class that is use for labelling the country names in ViewXY.Map, that is something that i want to achieve with Annotation3D, where the label is "fixed"/stuck to the location and will not always show up.
When you set a map in ViewXY.Maps, by setting Maps.Type or by setting Path and FileName, the layers of vector map get updated.
If you were to present cities and their locations are accessible in the Maps.Layers property. Go through all layers, and check the layer Type = City. Get all items and set the preferred cities to the 3D globe. Don't put all, because the chart can't render millions of labels. Location reports the map coordinate. For example, limit by population or country. Different maps provide different info.
Map cities layer
Map cities layer
map_layers.jpg (47.29 KiB) Viewed 18420 times
Use ChartTools.ConvertMapCoordTo3DPointOnSphere() to convert map coordinate to 3D.


For countries there's Land layer.
Map land layer
Map land layer
map_land.jpg (36.28 KiB) Viewed 18420 times
The map coordinate is in Center property.
LightningChart Support Team, PT

hallo888
Posts: 43
Joined: Wed Mar 26, 2014 10:56 am

Re: Using of .shp files in 2D map

Post by hallo888 » Mon Apr 14, 2014 9:49 am

Hi Pasi,

Thanks for taking the trouble to help me update the LC assemblies.

Below is the code which i use the Annotation3D to label the country name on the 3D globe. After executing the getCountry(), the foreach loop that takes around 1min and 34secs to complete. The foreach loop basically initialises an Annotation3D class for each of the 250 countries.

Is this the normal speed? Any other similar labelling/annotation class which i could use? Or is Annotation3D class the only labelling class for View3D?

And also as the foreach is looping, the following line "The thread 'ComposeLineSeriesDrawDataThread' (0X528) has exited with code 0 (0x0)." kept printing on the output window. There were hundreds of them with the same message but different memory locations. Is this the normal or is this the cause for the slow speed?

Code: Select all

private void labelCountry()
{
    List<CountryData> listCountries = GetCountryData();
    foreach(CountryData country in listCountries)
    {
       Annotation3D countrylabel = new Annotation3D(m_chart.View3D, Axis3DBinding.Primary, Axis3DBinding.Primary, Axis3DBinding.Primary)
      countrylabel.Text = country.CountryName;
      MapCoordinate mc = new MapCoordinate(country.centerPoint.Y, country.centerPoint.X);
      PointDouble3D p3d = ChartTools.ConvertMapCoordTo3DPointOnSphere(mc,53);

      countrylabel.TargetAxisValue.X = pd3.X;
      countrylabel.TargetAxisValue.Y = pd3.Y;
      countrylabel.TargetAxisValue.Z = pd3.Z;

      countrylabel.LocationCoordinateSystem = CoordinateSystem.RelativeCoordinatesToTarget;
      countrylabel.LocationAxisValue.X = pd3.X;
      countrylabel.LocationAxisValue.Y = pd3.Y;
      countrylabel.LocationAxisValue.Z = pd3.Z;'

      m_chart.View3D.Annotations.Add(countrylabel);
    }
}
Please advise.

Thank you again for you help.
Last edited by hallo888 on Mon Apr 14, 2014 10:22 am, edited 2 times in total.

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

Re: Using of .shp files in 2D map

Post by ArctionPasi » Mon Apr 14, 2014 9:59 am

If you seen the thread exit messages in output window, that means your chart is being rendered all the time. Prevent it from rendering while adding new annotations by using BeginUpdate...EndUpdate.

chart.BeginUpdate();

//for loop here, annotations creating

chart.EndUpdate();

Finally, run with Ctrl + F5 to see how fast/slow it really executes. Debugger gives a significant performance penalty.
LightningChart Support Team, PT

hallo888
Posts: 43
Joined: Wed Mar 26, 2014 10:56 am

Re: Using of .shp files in 2D map

Post by hallo888 » Mon Apr 14, 2014 10:23 am

Thanks for the prompt reply. It much much faster after following ur suggestion. Thanks!

By the way, I realised that only Map.MapType.WorldLow have population information wheras Map.MapType.WorldHigh got no population information. Is that correct?

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

Re: Using of .shp files in 2D map

Post by ArctionPasi » Mon Apr 14, 2014 10:45 am

Some maps have the population info, some not. The maps have been imported from various sources, with different set of info. WorldMid has also population info.
LightningChart Support Team, PT

Post Reply