banner



How To Draw A Compass

  • Download Compass_Sources_and_Build.zip - 114.6 KB

Introduction

This lawmaking shows how to draw a compass and how to use it with a NMEA uniform GPS device.

Background

For me this was just a prelude for some other projection, testing out how to access GPS data from a NMEA device and information technology was fun to draw a Compass.

Using the code

You lot tin easily modify the code to support your custom adruino electronic compass if you similar. The compass class is independently from the data source reusable. Just call the static DrawCompass method to depict the compass.

pictureBox1.Image = Compass.DrawCompass(degree, pitch,          lxxx, tilt,          80, pictureBox1.Size);

Points of Interest

I found quite abrasive that NMEA devices seem not to ship an identifier, and so when opening Com ports to scan for one you really have to expect for the next data to arrive, parse it and if it is NMEA data accept it, and the close all other Com Ports, or y'all force the user configure the used Com Port to make it less userfriendly ;-).  Important is to abort all open up threads on Exiting the App, for else it won't get out due to the blocked threads. To have them Blocked at opening/closing all ports was necessary equally it seems that the SerialPort Object seems not threadsafe in that it looses it's eventhandlers otherwise or the object disposes itself despite nevertheless having references, when opened from within another thread, a thread.Join seems to alleviate the event but creating some few blocked threads for each airtight port that notwithstanding have to be aborted at the end of the application. I presume this approach could be used for other types of serial devices equally well. Delight send me a note if you find a better solution to this trouble.

          void          DisconnectGPS()     {          if          (serialPort1 !=          null)         {          try          {          if          (serialPort1.IsOpen)                     serialPort1.Close();                 serialPort1.Dispose();             }          catch          { }                      }          if          (_Serial_Ports !=          null)         {          for          (int          i = _Serial_Ports.Length -          i; i >=          0; i--)             {                 System.IO.Ports.SerialPort p = _Serial_Ports[i];          if          (p !=          nil)                 {          try          {          if          (p.IsOpen)                             p.Close();                         p.Dispose();                     }          take hold of          { }                                      }              }         }          foreach          (Thread t          in          _Gps_Threads)         {             t.Abort();         }     }          void          ConnectGPS()     {         String[] portnames = Arrangement.IO.Ports.SerialPort.GetPortNames();         _Serial_Ports =          new          System.IO.Ports.SerialPort[portnames.Length];         _Gps_Threads =          new          Thread[portnames.Length];          for          (int          i =          0; i < portnames.Length; i++)         {             System.IO.Ports.SerialPort ssp =          new          Organisation.IO.Ports.SerialPort(portnames[i]);          try          {          object          data0 = (object)new          object[] { ssp, i };                 System.Threading.Thread t1 =          new          Thread(delegate(object          data)                 {                     System.IO.Ports.SerialPort sspt1 = (System.IO.Ports.SerialPort)((object[])data)[0];          int          it1 = (int)((object[])information)[one];                     _Serial_Ports[it1] = sspt1;          endeavour          {                         sspt1.DataReceived += serialPort1_DataReceived;                         sspt1.Open();                     }          grab          { }                     System.Threading.Thread.Sleep(3000);          endeavour          {          foreach          (System.IO.Ports.SerialPort sspt2          in          _Serial_Ports.Where(r => !r.PortName.Equals(serialPort1.PortName)))                         {          if          (sspt2.IsOpen)                                 sspt2.Close();                             sspt2.Dispose();                         }                     }          grab          { }                      Arrangement.Threading.Thread.CurrentThread.Bring together();                  });                 _Gps_Threads[i] = t1;                 t1.Start(data0);                              }          catch          { }          }      }        

To identify a NMEA compatible device you merely read out what's coming from the port. Does it lucifer your expected NMEA sentences, then you got it and fix your serialPort1=p. The beneath code works for Magellan Explorist devices. Not certain if GPRMC sentence is provided with all NMEA device. You can easily alter information technology to match it your device. NMEA Sentence Specs that worked for me, I  constitute hither: http://aprs.gids.nl/nmea/

It'south pretty easy to piece of work out I'd say. Consider that the NMEA device may loose the satelite connectedness and you may get blanks from the device in those lines.

          void          serialPort1_DataReceived(object          sender, System.IO.Ports.SerialDataReceivedEventArgs e) {          try          {   System.IO.Ports.SerialPort p = ((Organisation.IO.Ports.SerialPort)sender);          cord          data = p.ReadExisting();   cord[] strArr = data.Split('          $');          for          (int          i =          0; i < strArr.Length; i++)   {          string          strTemp = strArr[i];    string[] nmea = strTemp.Split('          ,');          if          (nmea[0] ==          "          GPRMC")     {     serialPort1 = p;          if          (!String.IsNullOrEmpty(nmea[eight]) )     {      degree = Convert.ToDouble(nmea[8]);      pitch =          0;      tilt =          0;      pictureBox1.Image = Compass.DrawCompass(degree, pitch,          80, tilt,          80, pictureBox1.Size);     }    }   } }          catch          {} }

To draw the Compass itself is pretty straight frontwards. Simply using a little bit of geometry and DrawLine, DrawElipse, DrawString... run into beneath what y'all can do with these simple commands. Nearly amazing well-nigh it is that it runs in only a few milliseconds (on ii year quondam my notebook its only 5ms per DrawCompass).

To draw the compass onto an existing Bitmap simply modify the method to not use "result" merely to utilize the passed on Bitmap and utilize the size of the existing bitmap or whichever size yous want he compass to exist and to modify it'due south location on the bitmap is easy enough by modifying the xcenterpoint and ycenterpoint.

Pitch and Tilt is not used when with a GPS device, equally you lot become your heading from the device's location and movement, but if you utilise a magnetic compass (i.due east. adruino device) you may want to show the pitch or tilt when calibrating, then I added the pitch and tilt so you lot tin can roll information technology, just similar on your smart telephone and see how it deviates from a 0 caste pitch / tilt roll.

          public          class          Compass   {          public          static          Bitmap DrawCompass(double          caste,          double          pitch,          double          maxpitch,          double          tilt,          double          maxtilt, Size s)       {          double          maxRadius = due south.Width > s.Elevation ? s.Height /          2          : south.Width /          ii;          double          sizeMultiplier = maxRadius /          200;          double          relativepitch = pitch / maxpitch;          double          relativetilt = tilt / maxtilt;                Bitmap result=null;               SolidBrush drawBrushWhite =          new          SolidBrush(Colour.FromArgb(255,          244,          255));               SolidBrush drawBrushRed =          new          SolidBrush(Color.FromArgb(240,          255,          0,          0));               SolidBrush drawBrushOrange =          new          SolidBrush(Color.FromArgb(240,          255,          150,          0));               SolidBrush drawBrushBlue =          new          SolidBrush(Color.FromArgb(100,          0,          250,          255));               SolidBrush drawBrushWhiteGrey =          new          SolidBrush(Color.FromArgb(20,          255,          255,          255));          double          outerradius = (((maxRadius - sizeMultiplier *          60) / maxRadius) * maxRadius);          double          innerradius = (((maxRadius - sizeMultiplier *          90) / maxRadius) * maxRadius);          double          degreeRadius = outerradius +          37          * sizeMultiplier;          double          dirRadius = innerradius -          30          * sizeMultiplier;          double          TriRadius = outerradius +          xx          * sizeMultiplier;          double          PitchTiltRadius = innerradius *          0.55;          if          (s.Width * s.Summit >          0)               {                   event=new          Bitmap(s.Width, s.Top);          using          (Font font2 =          new          Font("          Arial", (bladder)(16          * sizeMultiplier)))               {          using          (Font font1 =          new          Font("          Arial", (float)(14          * sizeMultiplier)))                   {          using          (Pen penblue =          new          Pen(Color.FromArgb(100,          0,          250,          255), ((int)(sizeMultiplier) <          4          ?          4          : (int)(sizeMultiplier))))                       {          using          (Pen penorange =          new          Pen(Color.FromArgb(255,          150,          0), ((int)(sizeMultiplier) <          one          ?          1          : (int)(sizeMultiplier))))                           {          using          (Pen penred =          new          Pen(Color.FromArgb(255,          0,          0), ((int)(sizeMultiplier) <          1          ?          1          : (int)(sizeMultiplier))))                               {          using          (Pen pen1 =          new          Pen(Color.FromArgb(255,          255,          255), (int)(sizeMultiplier *          4)))                                   {          using          (Pen pen2 =          new          Pen(Color.FromArgb(255,          255,          255), ((int)(sizeMultiplier) <          ane          ?          ane          : (int)(sizeMultiplier))))                                       {          using          (Pen pen3 =          new          Pen(Color.FromArgb(0,          255,          255,          255), ((int)(sizeMultiplier) <          1          ?          1          : (int)(sizeMultiplier))))                                           {          using          (Graphics grand = Graphics.FromImage(upshot))                                               {                                                              double          sourcewidth = s.Width;          double          sourceheight = south.Height;          int          xcenterpoint = (int)(s.Width /          two);          int          ycenterpoint = (int)((s.Acme /          two));                                                    Bespeak pA1 =          new          Point(xcenterpoint, ycenterpoint - (int)(sizeMultiplier *          45));                                                   Betoken pB1 =          new          Signal(xcenterpoint - (int)(sizeMultiplier *          seven), ycenterpoint - (int)(sizeMultiplier *          45));                                                   Point pC1 =          new          Indicate(xcenterpoint, ycenterpoint - (int)(sizeMultiplier *          90));                                                   Betoken pB2 =          new          Point(xcenterpoint + (int)(sizeMultiplier *          7), ycenterpoint - (int)(sizeMultiplier *          45));                                                    Betoken[] a2 =          new          Bespeak[] { pA1, pB1, pC1 };                                                   Signal[] a3 =          new          Point[] { pA1, pB2, pC1 };                                                    m.DrawPolygon(penred, a2);                                                   yard.FillPolygon(drawBrushRed, a2);                                                   g.DrawPolygon(penred, a3);                                                   g.FillPolygon(drawBrushWhite, a3);                                                    double[] Cos =          new          double[360];                                                   double[] Sin =          new          double[360];                                                                                                       1000.DrawLine(pen2,          new          Betoken(((int)(xcenterpoint - (PitchTiltRadius - sizeMultiplier *          50))), ycenterpoint),          new          Point(((int)(xcenterpoint + (PitchTiltRadius - sizeMultiplier *          50))), ycenterpoint));                                                   g.DrawLine(pen2,          new          Signal(xcenterpoint, (int)(ycenterpoint - (PitchTiltRadius - sizeMultiplier *          l))),          new          Signal(xcenterpoint, ((int)(ycenterpoint + (PitchTiltRadius - sizeMultiplier *          50)))));                                                                                                       Point PitchTiltCenter =          new          Betoken((int)(xcenterpoint + PitchTiltRadius * relativetilt), (int)(ycenterpoint - PitchTiltRadius * relativepitch));          int          rad = (int)(sizeMultiplier *          8);          int          rad2 = (int)(sizeMultiplier *          25);                                                    Rectangle r =          new          Rectangle((int)(PitchTiltCenter.Ten - rad2), (int)(PitchTiltCenter.Y - rad2), (int)(rad2 *          2), (int)(rad2 *          2));                                                   g.DrawEllipse(pen3, r);                                                   yard.FillEllipse(drawBrushWhiteGrey, r);                                                   g.DrawLine(penorange, PitchTiltCenter.X - rad, PitchTiltCenter.Y, PitchTiltCenter.10 + rad, PitchTiltCenter.Y);                                                   thousand.DrawLine(penorange, PitchTiltCenter.X, PitchTiltCenter.Y - rad, PitchTiltCenter.X, PitchTiltCenter.Y + rad);                                                              for          (int          d =          0; d <          360; d++)                                                   {                                                                 double          angleInRadians = ((((double)d) + 270d) - degree) /          180F          * Math.PI;                                                       Cos[d] = Math.Cos(angleInRadians);                                                       Sin[d] = Math.Sin(angleInRadians);                                                   }          for          (int          d =          0; d <          360; d++)                                                   {                                                         Bespeak p1 =          new          Point((int)(outerradius * Cos[d]) + xcenterpoint, (int)(outerradius * Sin[d]) + ycenterpoint);                                                       Signal p2 =          new          Betoken((int)(innerradius * Cos[d]) + xcenterpoint, (int)(innerradius * Sin[d]) + ycenterpoint);                                                                  if          (d %          30          ==          0)                                                       {                                                           m.DrawLine(penblue, p1, p2);                                                            Point p3 =          new          Point((int)(degreeRadius * Cos[d]) + xcenterpoint, (int)(degreeRadius * Sin[d]) + ycenterpoint);                                                           SizeF s1 = chiliad.MeasureString(d.ToString(), font1);                                                           p3.X = p3.Ten - (int)(s1.Width /          2);                                                           p3.Y = p3.Y - (int)(s1.Height /          2);                                                            m.DrawString(d.ToString(), font1, drawBrushWhite, p3);                                                           Point pA =          new          Point((int)(TriRadius * Cos[d]) + xcenterpoint, (int)(TriRadius * Sin[d]) + ycenterpoint);          int          width = (int)(sizeMultiplier *          3);          int          dp = d + width >          359          ? d + width -          360          : d + width;          int          dm = d - width <          0          ? d - width +          360          : d - width;                                                            Betoken pb =          new          Betoken((int)((TriRadius - (15          * sizeMultiplier)) * Cos[dm]) + xcenterpoint, (int)((TriRadius - (15          * sizeMultiplier)) * Sin[dm]) + ycenterpoint);                                                           Point pC =          new          Indicate((int)((TriRadius - (15          * sizeMultiplier)) * Cos[dp]) + xcenterpoint, (int)((TriRadius - (fifteen          * sizeMultiplier)) * Sin[dp]) + ycenterpoint);                                                            Pen p = penblue;                                                           Brush b = drawBrushBlue;          if          (d ==          0)                                                           {                                                               p = penred;                                                               b = drawBrushRed;                                                           }                                                           Point[] a =          new          Indicate[] { pA, atomic number 82, pC };                                                            g.DrawPolygon(p, a);                                                           g.FillPolygon(b, a);                                                       }          else          if          (d %          ii          ==          0)                                                           g.DrawLine(pen2, p1, p2);                                                                  if          (d %          90          ==          0)                                                       {          string          dir = (d ==          0          ?          "          N"          : (d ==          ninety          ?          "          E"          : (d ==          180          ?          "          S"          :          "          W")));                                                           Point p4 =          new          Point((int)(dirRadius * Cos[d]) + xcenterpoint, (int)(dirRadius * Sin[d]) + ycenterpoint);                                                           SizeF s2 = thousand.MeasureString(dir, font1);                                                           p4.X = p4.Ten - (int)(s2.Width /          two);                                                           p4.Y = p4.Y - (int)(s2.Height /          2);                                                            g.DrawString(dir, font1, d ==          0          ? drawBrushRed : drawBrushBlue, p4);                                                                                                                                                                                                                                                                                                    }                                                    }                                                                                                                 String          deg = Math.Circular(degree,          2).ToString("          0.00") +          "          °";                                                   SizeF s3 = g.MeasureString(deg, font1);                                                    g.DrawString(deg, font2, drawBrushOrange,          new          Point(xcenterpoint - (int)(s3.Width /          2), ycenterpoint - (int)(sizeMultiplier *          xl)));                                                }                                           }                                       }                                   }                               }                           }                       }                   }               }           }          return          result;       }   }        
The Truth nearly Northward

I intentionally called it a "simple Compass" not to open up the can of worms regarding all the other topics of navigation. Only now that the can has been opened we may equally well mention and bespeak out is that GPS devices determine ane's heading ordinarily by computing the vector between the GPS Ready points. Correct me if I am wrong, that significant that a GPS compass will work only as long as yous are moving, unless information technology has a secondary magnetic sensor, or other means of determining the heading (i.e. cell tower triangulation, wireless network information, etc.) built in too. Magnetic due north nevertheless would demand to be corrected to calculate True N for navigational purposes considering magnetic declination and magnetic departure. (come across http://en.wikipedia.org/wiki/Magnetic_deviation)

Electronic compasses furthermore crave recalibration to compensate for the environmental deviations.

GPS compass Pros: True north

GPS compass Cons: No heading when stationary, Accuracy depending satellite data receptions and its interpretation

Magnetic Compass Pros: Headings when stationary, based on Earth's magnetic fields

Magnetic Compass Cons: Inaccuracies deviating from True North due to magnetic declination and deviation

i.eastward. my analogue magnetic scuba diving compasses deviate towards my torch (it having magnetic switches), and my European Scuba diving compass is off by roughly 5 degrees here in Australia.

Clearly I am non an expert at this matter, but information technology'south mentioned now. The Compass.DrawCompass feature volition piece of work accurately and correclty in either way. Whether your information input is accurate for your purposes remains within your control choosing your about suitable Compass - data source and adjusting the data against your individually applicable declination/deviation before drawing the Compass.

History

2014-05-26 Added a point of interest as suggested past SteveHolle regarding the "truth" most northward and device specific caveats on that.

Source: https://www.codeproject.com/Articles/788611/A-simple-Compass

Posted by: drummondtals1968.blogspot.com

0 Response to "How To Draw A Compass"

Post a Comment

Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel