public FlightPathLineGeometry(  int _pathNumber,   linearFeatureCoverageSummary _LFSum)
        {
            ////////////////////////////////////////////////////////////////////////////////
            //path: a set of smoothed trajectory points defined from the mission planned
            //compute those variables that are constant across the path
            ////////////////////////////////////////////////////////////////////////////////

            LFSum = _LFSum;
            pathNumber = _pathNumber;

            UTM2Geodetic utm = new UTM2Geodetic();

            //set up the polygon (point list) math procedures
            polyMath = new polygonMath(LFSum.paths[pathNumber].pathUTM);

            //get the semi-infinite line extending beyond the path at the start and end
            int count = LFSum.paths[pathNumber].pathGeoDeg.Count;

            unitAwayFromEndUTM = new PointD();
            unitAwayFromStartUTM = new PointD();
            //semi-infinite line use for drawing a line extending beyond the path end
            unitAwayFromEndUTM   = LFSum.paths[pathNumber].pathUTM[count - 1] - LFSum.paths[pathNumber].pathUTM[count - 2];
            unitAwayFromStartUTM = LFSum.paths[pathNumber].pathUTM[0]         - LFSum.paths[pathNumber].pathUTM[1];
            double delSMag = Math.Sqrt(unitAwayFromStartUTM.X * unitAwayFromStartUTM.X + unitAwayFromStartUTM.Y * unitAwayFromStartUTM.Y);
            unitAwayFromStartUTM = unitAwayFromStartUTM / delSMag;
            double delEMag = Math.Sqrt(unitAwayFromEndUTM.X * unitAwayFromEndUTM.X + unitAwayFromEndUTM.Y * unitAwayFromEndUTM.Y);
            unitAwayFromEndUTM = unitAwayFromEndUTM / delEMag;

            //semi-infinite line ate start and end in UTM coordinates
            PointD semiInfiniteFLstartUTM = LFSum.paths[pathNumber].pathUTM[0] + 10000.0 * unitAwayFromStartUTM;
            PointD semiInfiniteFLendUTM = LFSum.paths[pathNumber].pathUTM[count - 1] + 10000.0 * unitAwayFromEndUTM;

            //convert to geodetic
            semiInfiniteFLstartGeo = new PointD();
            semiInfiniteFLendGeo   = new PointD();
            utm.UTMtoLL(semiInfiniteFLstartUTM, LFSum.UTMZone, ref semiInfiniteFLstartGeo);
            utm.UTMtoLL(semiInfiniteFLendUTM, LFSum.UTMZone, ref semiInfiniteFLendGeo);

            //compute the path length
            pathlengthMeters = 0.0;
            for (int i = 1; i < LFSum.paths[pathNumber].pathUTM.Count; i++)
            {
                double delX = LFSum.paths[pathNumber].pathUTM[i].X - LFSum.paths[pathNumber].pathUTM[i - 1].X;
                double delY = LFSum.paths[pathNumber].pathUTM[i].Y - LFSum.paths[pathNumber].pathUTM[i - 1].Y;
                double magDel = Math.Sqrt(delX * delX + delY * delY);
                pathlengthMeters += magDel;
            }

            //number of expected photocenters
            numPhotoCenters = (int)(pathlengthMeters / LFSum.photocenterSpacing + 1.0);
        }
        public List<endPoints> UpdateFlightLinesPerPriorFlownMissions(int missionNumber)
        {
            /////////////////////////////////////////////////////////////////////////////////////////////
            //use the MissionUpdateFlightlines structure (fromn the constructor) to update the flight lines
            //the new flight lines replace the old flight lines
            //the initial prior flightline analysis provided a structure
            //that contained only data from the flown missions.
            //This procedure creates a replica of the mission plan flight lines,
            //for a specific mission, that are adjusted to remove the prior flown lines (and segments)
            /////////////////////////////////////////////////////////////////////////////////////////////

            UTM2Geodetic utm = new UTM2Geodetic();  //needs to be in a utility procedure available to all in the solution

            //test to see if pre-flown mission dataset contain this mission
            int preFlownMissionIndex = 0;  //mission index from the flightline analysis
            bool thisMissionWasPreflown = false;
            foreach (MissionUpdateFlightlines msnUpdate in projUpdate.msnUpdate)
            {
                if (missionNumber == msnUpdate.missionNumber) { thisMissionWasPreflown = true; break; }
                preFlownMissionIndex++;
            }

            ////////////////////////////////////////////////////////////////////////////////////////////
            //this is the updates flight line dataset that replicates the data in the original plan
            List<endPoints> FLUpdateList = new List<endPoints>();  //return value
            ////////////////////////////////////////////////////////////////////////////////////////////

            //if this mission was not reflown -- just copy the old data to the replica
            if (!thisMissionWasPreflown)
            {
                for (int iFL = 0; iFL < projSum.msnSum[missionNumber].numberOfFlightlines; iFL++)
                    FLUpdateList.Add(projSum.msnSum[missionNumber].FlightLinesCurrentPlan[iFL]);
                return FLUpdateList;
            }

            //if here, the mission was reflown -- generate the replica.
            //NOTE: all flightlines were likely not preflown -- just a part of them.

            //this is an index into the preflown-analysis structure indicating the reflown line
            int nextFlownFL = 0;

            //cycle through ALL flight lines for this mission
            for (int iFL = 0; iFL < projSum.msnSum[missionNumber].numberOfFlightlines; iFL++)
            {
                bool thisFlightLineWasPreflown = false;
                //the "if" below skips the checks on the remaining lines if we are beyond the nuber of reflown lines
                if (nextFlownFL >= projUpdate.msnUpdate[preFlownMissionIndex].flightLineUpdate.Count) thisFlightLineWasPreflown = false;
                //this is the test to see if we have reflown this line = iFL
                else if (iFL == projUpdate.msnUpdate[preFlownMissionIndex].flightLineUpdate[nextFlownFL].FLNumber) thisFlightLineWasPreflown = true;

                if (!thisFlightLineWasPreflown)  //if not reflown -- just copy the old data
                {
                    FLUpdateList.Add(projSum.msnSum[missionNumber].FlightLinesCurrentPlan[iFL]);
                }
                else  //create a new flightline dataset
                {
                    // NOTE:  we convert the initial geodetic ends to UTM for the now endpoint computations
                    //        this is to maintain precision

                    //found a pre-flown flightline
                    PointD FLendGeo = projSum.msnSum[missionNumber].FlightLinesCurrentPlan[iFL].end;
                    PointD FLstartGeo = projSum.msnSum[missionNumber].FlightLinesCurrentPlan[iFL].start;
                    PointD FLendUTM = new PointD(0.0, 0.0);
                    PointD FLstartUTM = new PointD(0.0, 0.0);

                    //convert the original planned flight line ends to UTM -- could pass these in from the original plan
                    //NOTTE:  maintain the same utm zone fro the mission planning -- else big trouble!!!
                    utm.LLtoUTM(FLstartGeo.Y * utm.Deg2Rad, FLstartGeo.X * utm.Deg2Rad, ref FLstartUTM.Y, ref FLstartUTM.X, ref projSum.UTMZone, true);
                    utm.LLtoUTM(FLendGeo.Y   * utm.Deg2Rad, FLendGeo.X   * utm.Deg2Rad, ref FLendUTM.Y,   ref FLendUTM.X,   ref projSum.UTMZone, true);

                    //below are the start and end photocenters as determined from the prior-flown mission analysis
                    //NOTE: the start is geodetically fixed -- e.g., at the south end for a NS flightline
                    int startPhotoCenter = projUpdate.msnUpdate[preFlownMissionIndex].flightLineUpdate[nextFlownFL].early;
                    int endPhotoCenter   = projUpdate.msnUpdate[preFlownMissionIndex].flightLineUpdate[nextFlownFL].late;

                    PointD newStartUTM = new PointD(0.0, 0.0);
                    PointD newEndUTM = new PointD(0.0, 0.0);

                    // just a comparison of the computed and input flightline lengths ... it checks: JEK 1/26/2012
                    double FLMag1 = projSum.msnSum[missionNumber].FlightLinesCurrentPlan[iFL].FLLengthMeters;
                    //double FLMag2 = Math.Sqrt((FLendUTM.X - FLstartUTM.X) * (FLendUTM.X - FLstartUTM.X) + (FLendUTM.Y - FLstartUTM.Y) * (FLendUTM.Y - FLstartUTM.Y));

                    //proportionally space the new photocenters along the origional flightine -- in UTM space
                    newStartUTM = FLstartUTM + (startPhotoCenter * projSum.downrangeTriggerSpacing / FLMag1) * (FLendUTM - FLstartUTM);
                    newEndUTM = FLstartUTM + (endPhotoCenter * projSum.downrangeTriggerSpacing / FLMag1) * (FLendUTM - FLstartUTM);

                    PointD newStartGeo = new PointD(0.0, 0.0);
                    PointD newEndGeo = new PointD(0.0, 0.0);

                    //now convert them back to geodetic
                    utm.UTMtoLL(newStartUTM.Y, newStartUTM.X, projSum.UTMZone, ref newStartGeo.Y, ref newStartGeo.X);
                    utm.UTMtoLL(newEndUTM.Y, newEndUTM.X, projSum.UTMZone, ref newEndGeo.Y, ref newEndGeo.X);

                    endPoints epts = new endPoints();  //temporary structure

                    //fill the temporary structure
                    //this used the 2D geometry and will work for NS or EW flight lines
                    epts.FLLengthMeters = (endPhotoCenter - startPhotoCenter) * projSum.downrangeTriggerSpacing;
                    epts.end = newEndGeo;
                    epts.start = newStartGeo;
                    //this is the global project flight line number -- not a local number used for this mission
                    epts.FlightLineNumber = projSum.msnSum[missionNumber].FlightLinesCurrentPlan[iFL].FlightLineNumber;

                    //below is important to allow flight line updates that include partial flown lines.
                    //all photocenters are given a unique name in the original flight plan
                    //we must keep this original name for the photocenters
                    //the names are based on the distance from the geodetic fixed otiginal start location
                    // so we have to keep the offset for the updated flight lines from the original plan
                    epts.photoCenterOffset = startPhotoCenter;

                    //fill the replical flight line structure
                    FLUpdateList.Add(epts);

                    //increment the index into the preflown flightline analysis structure
                    nextFlownFL++;

                }   //end of filling the new flightline record
            }       //end of filling the individual flight lines (iFL)

            return FLUpdateList;  //filled replica of the original flightplan fllightlines for this mission
        }
        public linearFeatureCoverageSummary readLinearFeatureCoverageData(XmlReader tr, String ProjectName)
        {
            ///////////////////////////////////////////////////////////////////////
            //read in the input kml describing the line feature coverage
            ///////////////////////////////////////////////////////////////////////

            //input kml linear feature -- dont need this
            //project map bounds
            //path information (trigger spacing, origin, UTM zone)
            //table of information -- need some of this
            //takeoff airport -- dont need this
            //along-path map bounds -- need this
            //path specific data -- dont need this
            //smoothed trajectory -- need this
            //center projection -- dont need
            //image endpoints  -- dont need

            bool completedreadingProjectMapBounds       = false;
            bool completedReadingPathInformation        = false;
            bool completedReadingSmoothedPathPoints     = false;

            linearFeatureCoverageSummary LFSummary = new linearFeatureCoverageSummary();
            LFSummary.gridOrigin = new PointD();

            //get the project map bounds
            //how do I exit this loop ???
            //TODO:  test to see if the kml file projectName is the same as the kml fileName
            while (tr.Read() && !completedreadingProjectMapBounds)
            {
                if (tr.EOF) break;
                if (tr.IsStartElement() && tr.Name == "GroundOverlay")
                {
                    while (tr.Read() && !completedreadingProjectMapBounds)
                    {
                        if (tr.IsStartElement() && tr.Name == "name")
                        {
                            tr.Read();
                            //we are looking for the name "project Map" where we will get the map bounds
                            if (tr.Value == "Project Map")
                            {
                                int numBounds = 0;
                                while (tr.Read() && !completedreadingProjectMapBounds)
                                {
                                    if (tr.IsStartElement() && tr.Name == "north")
                                    {
                                        tr.Read();
                                        LFSummary.ProjectImage.northDeg = Convert.ToDouble(tr.Value);

                                        numBounds++;
                                    }
                                    if (tr.IsStartElement() && tr.Name == "south")
                                    {
                                        tr.Read();
                                        LFSummary.ProjectImage.southDeg = Convert.ToDouble(tr.Value);
                                        numBounds++;
                                    }
                                    if (tr.IsStartElement() && tr.Name == "east")
                                    {
                                        tr.Read();
                                        LFSummary.ProjectImage.eastDeg = Convert.ToDouble(tr.Value);
                                        numBounds++;
                                    }
                                    if (tr.IsStartElement() && tr.Name == "west")
                                    {
                                        tr.Read();
                                        LFSummary.ProjectImage.westDeg = Convert.ToDouble(tr.Value);
                                        numBounds++;
                                    }
                                    if (numBounds == 4) completedreadingProjectMapBounds = true;
                                }
                            }
                        }
                    }
                }
            }// end of:   get the project map bounds
            if (tr.EOF)
            {
                MessageBox.Show("Bad map bounds format for the input kml file -- exiting");
                Environment.Exit(-1);
            }

            int numPathInfo = 0;
            while (tr.Read() && !completedReadingPathInformation)
            {
                if (tr.EOF) break;
                if (tr.IsStartElement() && tr.Name == "downRangePhotoSpacingMeters")
                {
                    tr.Read();
                    LFSummary.photocenterSpacing = Convert.ToDouble(tr.Value);
                    numPathInfo++;
                }

                if (tr.IsStartElement() && tr.Name == "numberOfPaths")
                {
                    tr.Read();
                    LFSummary.numberParallelPaths = Convert.ToInt32(tr.Value);
                    numPathInfo++;
                }

                if (tr.IsStartElement() && tr.Name == "UTMZone")
                {
                    tr.Read();
                    LFSummary.UTMZone = tr.Value;
                    numPathInfo++;
                }

                if (tr.IsStartElement() && tr.Name == "gridOriginUTMNorthing")
                {
                    tr.Read();
                    LFSummary.gridOrigin.Y = Convert.ToDouble(tr.Value);
                    numPathInfo++;
                }

                if (tr.IsStartElement() && tr.Name == "gridOriginUTMEasting")
                {
                    tr.Read();
                    LFSummary.gridOrigin.X = Convert.ToDouble(tr.Value);
                    numPathInfo++;
                }

                if (tr.IsStartElement() && tr.Name == "proNavGain")
                {
                    tr.Read();
                    LFSummary.proNavGain = Convert.ToDouble(tr.Value);
                    numPathInfo++;
                }
                if (tr.IsStartElement() && tr.Name == "rabbitAheadDistance")
                {
                    tr.Read();
                    LFSummary.plannedRabbitDistanceAhead = Convert.ToDouble(tr.Value);
                    numPathInfo++;
                }
                if (tr.IsStartElement() && tr.Name == "flightAltAGLft")
                {
                    tr.Read();
                    LFSummary.flightAltAGLft = Convert.ToDouble(tr.Value);
                    numPathInfo++;
                }

                if (numPathInfo == 8)completedReadingPathInformation = true;

            }  // end of:   get the path info
            if (tr.EOF)
            {
                MessageBox.Show("Bad path info format for the input kml file -- exiting");
                Environment.Exit(-1);
            }

            //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
            //read in the bounds of the mission images ProjectName_Background\background_YY.jpg
            //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

            LFSummary.paths = new List<pathDescription>();

            int numPathsProcessedForBounds = 0;
            while (tr.Read() && numPathsProcessedForBounds < LFSummary.numberParallelPaths)
            {
                if (tr.EOF) break;
                //read til we get the top of the next set of image bounds for a path
                if (tr.IsStartElement() && tr.Name == "numBGImagesThisPath")
                {
                    tr.Read();
                    int numImagesThisPath = Convert.ToInt32(tr.Value);
                    int pathImageBoundsRead = 0;
                    pathDescription path = new pathDescription();
                    path.imageBounds = new List<ImageBounds>();

                    //read off a complete set of bounds for a path
                    while (tr.Read() && pathImageBoundsRead < numImagesThisPath)  //loop over all image bounds in the folder
                    {
                        //read a complete set of image bounds
                        ImageBounds ib = new ImageBounds(); // fill an image bounds structure
                        int numBounds = 0;
                        while (tr.Read() && numBounds < 4)
                        {
                            if (tr.IsStartElement() && tr.Name == "north")
                            {
                                tr.Read();
                                ib.northDeg = Convert.ToDouble(tr.Value);
                                numBounds++;
                            }

                            if (tr.IsStartElement() && tr.Name == "east")
                            {
                                tr.Read();
                                ib.eastDeg = Convert.ToDouble(tr.Value);
                                numBounds++;
                            }

                            if (tr.IsStartElement() && tr.Name == "south")
                            {
                                tr.Read();
                                ib.southDeg = Convert.ToDouble(tr.Value);
                                numBounds++;
                            }

                            if (tr.IsStartElement() && tr.Name == "west")
                            {
                                tr.Read();
                                ib.westDeg = Convert.ToDouble(tr.Value);
                                numBounds++;
                            }
                        }
                        path.imageBounds.Add(ib);

                        pathImageBoundsRead++;
                    }
                    LFSummary.paths.Add(path);
                    numPathsProcessedForBounds++;
               }
            }  //end of reading in the map bounds along the paths

            if (tr.EOF)
            {
                MessageBox.Show("Bad path info format for the input kml file -- exiting");
                Environment.Exit(-1);
            }

            //read in the smoothed trajectory for each path
            UTM2Geodetic utm = new UTM2Geodetic();

            //we are ready to read off the coordinates of the smoothed trajectory
            int numPathsProcessed = 0;
            while (tr.Read() && !completedReadingSmoothedPathPoints)
            {
                if (tr.EOF) break;
                if (tr.IsStartElement() && tr.Name == "name")
                {
                    tr.Read();
                    //we will encounter this statement "numberParallelPaths"  times
                    if (tr.Value == "Smoothed Linear Feature Trajectory")
                    {

                        pathDescription path = LFSummary.paths[numPathsProcessed];
                        path.pathGeoDeg = new List<PointD>();
                        path.pathUTM = new List<PointD>();
                        path.commandedAltAlongPath = new List<double>();
                        bool thisPathComplete = false;
                        while (tr.Read() && !thisPathComplete)
                        {
                            //locate the coordinate tag for this path
                            if (tr.IsStartElement() && tr.Name == "coordinates")
                            {
                                tr.Read(); //read the complete coordinate dataset
                                char[] delimiterChars = { ',', ' ', '\t', '\n', '\r' };   //these delimiters were determined by looking at a file ...
                                //create a character string with all characters separated by a delimeter
                                string[] coordinateValues = tr.Value.ToString().Split(delimiterChars);

                                //the "value" is the text between the <coordinates> and </coordinates>
                                //below we read the complete string value and split it into separate substrings -- ugly but it works
                                //the substrings contain the individual coordinate values with some ""s and the heigts are "0".

                                //get the quantitative lat/long values from the text array ... there are a number of ""s in the text file ...
                                //each Google point has three values : longitude, Latitude, height -- we assume the height is zero here
                                int k = 0; int i = 0;
                                while (i < coordinateValues.Count())
                                {
                                    if (coordinateValues[i] != "")
                                    {
                                        double lat = Convert.ToDouble(coordinateValues[i + 1]);
                                        double lon = Convert.ToDouble(coordinateValues[i]);
                                        double alt = Convert.ToDouble(coordinateValues[i + 2]);

                                        path.pathGeoDeg.Add(new PointD(lon, lat) );
                                        path.commandedAltAlongPath.Add(alt);

                                        //convert the geodetic to UTM
                                        double UTMNorthing = 0.0, UTMEasting = 0.0;
                                        utm.LLtoUTM(lat * utm.Deg2Rad, lon * utm.Deg2Rad, ref UTMNorthing, ref UTMEasting, ref LFSummary.UTMZone, true);
                                        path.pathUTM.Add(new PointD(UTMEasting, UTMNorthing));

                                        k++;  //index of the storage array

                                        //increment the split array by 3 because the points are lat,lon,height
                                        i += 3;  //increment by 3 to get the next coordinate
                                    }
                                    else i++;  //here we skip the ""s in the text array
                                }
                                thisPathComplete = true;
                                numPathsProcessed++;
                            }

                        }  //end of while numPathsProcessed < LFSummary.numberParallelPaths

                        if (numPathsProcessed == LFSummary.numberParallelPaths)
                                   completedReadingSmoothedPathPoints = true;
                    }
                }
            }
            if (tr.EOF)
            {
                MessageBox.Show("Bad smoothed trajectory format for the input kml file -- exiting");
                Environment.Exit(-1);
            }

            return LFSummary;

            //////////////////////////////////////////////////////////////
            // the Project Summary for Waldo_FCS is Complete
            //////////////////////////////////////////////////////////////
        }
Example #4
0
        private void Mission_Load(object sender, EventArgs e)
        {
            ////////////////////////////////////////
            this.DoubleBuffered = true;
            ////////////////////////////////////////

            this.Top = 0;
            this.Left = 0;

            //this is the grey bar that is across the bottom
            Color gray = Color.Gray;
            //should make this a transparent grey --- but it flickers when 255 set to 200
            //panelMessage.BackColor = Color.FromArgb(0, gray.R, gray.G, gray.B);
            //panelMessage.Top = this.Height - panelMessage.Height;
            //panelMessage.Left = 0;
            //panelMessage.Width = this.Width;

            btnBack.FlatAppearance.BorderSize = 0;
            btnBack.FlatStyle = FlatStyle.Flat;
            btnBack.BackColor = Color.Black;
            btnBack.ForeColor = Color.White;
            btnBack.Height = this.Height / 10;
            btnBack.Top = this.Height - btnBack.Height;
            btnBack.Left = 0;

            //this control is used to start the real-time activity.
            //It should not re-appear after the real-time has been initiated
            btnOK.FlatAppearance.BorderSize = 0;
            btnOK.FlatStyle = FlatStyle.Flat;
            btnOK.BackColor = Color.Black;
            btnOK.ForeColor = Color.White;
            btnOK.Height = this.Height/10;
            btnOK.Top = this.Height - btnOK.Height; ;
            btnOK.Left = this.Width - btnOK.Width;

            //place top edge of panel1 along top edge of panelMessage
            panel1.Height = this.Height / 10;
            panel1.Top = this.Height - panel1.Height;
            panel1.Left = this.Width-panel1.Width; //panel1 at left of panelmessage
            panel1.BackColor = Color.Black;
            panel1.Visible = false;

            //labelVEL.Left = 0;
            //labelXTR.Left = 0;

            panelLeftText.Top = 0;
            panelLeftText.Left = 0;
            panelLeftText.Height = steeringBarHeightPix;
            panelRightText.Width = panelLeftText.Width;
            panelRightText.Height = steeringBarHeightPix;
            panelLeftText.Visible = false;
            panelRightText.Visible = false;

            panelRightText.Top = 0;
            panelRightText.Left = this.Width - panelRightText.Width;

            //fixes font scaling issues on other computers
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;

            this.lblMissionNumber.Text = "Mission Number: " + missionNumber.ToString();
            this.lblMissionNumber.Left = this.Width / 2 - lblMissionNumber.Width / 2;

            if (coverageType == COVERAGE_TYPE.polygon)
            {
                this.lblFlightAlt.Text = "MSL (ft):  " + ps.msnSum[missionNumber].flightAltMSLft.ToString("F0");
                this.lblFlightLines.Text = "Flightlines: " + ps.msnSum[missionNumber].numberOfFlightlines.ToString();
            }
            this.lblFlightAlt.Left = this.Width / 4;
            this.lblFlightLines.Left = this.Width/2 + this.Width / 12;

            labelElapsedTime.Visible = false;
            labelElapsedTime.BackColor = Color.Transparent;
            labelElapsedTime.Top = this.Height - this.Height / 20 - labelElapsedTime.Height/2;

            labelSatsLocked.Visible = false;
            labelSatsLocked.BackColor = Color.Transparent;
            labelSatsLocked.Top = this.Height - this.Height / 20 - labelSatsLocked.Height;
            labelNumImages.Visible = false;
            labelNumImages.BackColor = Color.Transparent;
            labelNumImages.Top = this.Height - this.Height / 20 ;

            utm = new UTM2Geodetic();  //utm to geodetic conversion class

            if (coverageType == COVERAGE_TYPE.polygon)
            {
                setupPolygonMission();

                if (platformWithinMissionMap())  UseZImapForPolygonMission = true;
                else UseZImapForPolygonMission = false;

                preparePolygonMissionDisplayfixedBackground();  //static map portion of the display
                prepPolygonBitmapForPaint();  //dynamic map portion of the display
            }
            else if (coverageType == COVERAGE_TYPE.linearFeature)
            {
                //always start the mission using the planned start at path number zero
                pathNumber = 0;
                setupLinearFeatureMission(pathNumber);
            }

            //there is no fixed background map for the linear feature mission
            //this is a moving map display so it is completly refreshed every display cycle.

            //Refresh();  //call Paint to draw the initial mission form

            btnOK.Enabled = true;
            btnOK.Visible = true;

            elapsedTime.Start();  //start the elapsed mission timer for the message bar display
        }
Example #5
0
        private void setupLinearFeatureMission(int pathNumber)
        {
            //////////////////////////////////////
            //called from btn_OK_clicked
            //initializes the simuation
            //////////////////////////////////////

            //simulation trajectory start point in pixel coordinates
            Point startPlatformPoint = new Point(FlightLineStartPix.X, FlightLineStartPix.Y);

            this.lblFlightAlt.Visible = false;
            this.lblFlightLines.Visible = false;
            this.lblMissionNumber.Visible = false;

            btnOK.Visible = true;  //dont need this anymore --- reset to visible if we return to a selected mission

            btnBack.Text = "EXIT"; // this is a better name because we exit the realtime mission and return to the mission selection Form
            //note we can exit a mission in the middle of a line and renter the mission at the exited point.

            //get all flightline geometry that is invariant for traveling along this path
            FPGeometry = new FlightPathLineGeometry(pathNumber, LFSum);

            utm = new UTM2Geodetic();

            //initialize the position when in sim mode
            if (simulatedMission)
            {
                ////////////////////////////////////////////////////////////////////////////////
                //set the position along the semi-infinite line at the start of the first path
                ////////////////////////////////////////////////////////////////////////////////

                PointD startUTM = new PointD();
                //simulation is initiated 5000m from the start and headed towards the start
                startUTM.X = LFSum.paths[pathNumber].pathUTM[0].X + 2000.0 * FPGeometry.unitAwayFromStartUTM.X + 100.0 * FPGeometry.unitAwayFromStartUTM.Y;
                startUTM.Y = LFSum.paths[pathNumber].pathUTM[0].Y + 2000.0 * FPGeometry.unitAwayFromStartUTM.Y - 100.0 * FPGeometry.unitAwayFromStartUTM.X;

                PointD startGeo = new PointD();
                utm.UTMtoLL(startUTM, LFSum.UTMZone, ref startGeo);

                platFormPosVel.UTMPos.X = startUTM.X;
                platFormPosVel.UTMPos.Y = startUTM.Y;
                platFormPosVel.GeodeticPos.X = startGeo.X;
                platFormPosVel.GeodeticPos.Y = startGeo.Y;
                //set the altitude at the initial commanded altitude (input in ft)
                platFormPosVel.altitude = LFSum.paths[0].commandedAltAlongPath[0] * 0.3048;

                //////////////////////////////////////////////////////////
                speed = 51.4;   // 100 knots
                //////////////////////////////////////////////////////////

                platFormPosVel.velD = 0.0;
                //negative sigh cause velocity towards the start of the path
                platFormPosVel.velE = -speed * FPGeometry.unitAwayFromStartUTM.X;
                platFormPosVel.velN = -speed * FPGeometry.unitAwayFromStartUTM.Y;

            }

            FPGeometry.getPlatformToFLGeometry(platFormPosVel);

            //pre-load the crumbtrail array prior to the start point
            //for (int i = 0; i < numberCrumbTrailPoints; i++) crumbTrail[i] = startPlatformPoint;

            //merged maps combine two along-path maps so the moving map shows all the subtended terrain
            //set up the first mergedMap
            mergedMapBounds = new ImageBounds(); //initialize this using first 2 images

            currentAlongPathMap = 0;
            triggerCountAlongpath = 0;

            mergedMap = new Bitmap(mergedMapMultiplier * mapWidth, mergedMapMultiplier * mapHeight);

            //triggerPointsOnMergedMap saves the camera trigger points along the merged map
            //used to present the crumb trail
            LFSum.paths[pathNumber].triggerPoints = new List<PointD>();
            //tempTriggerPoints = new List<PointD>();
            triggerPointsOnMergedMap = new List<Point>();

            ImageBounds displayImageBounds = generateDisplayMapBounds(pathNumber);
            //generate the first merged map for this path
            generateNewMergedMap(pathNumber, currentAlongPathMap, displayImageBounds);

            //this is hardwired in btn_OK
            deltaT = 0.25;

            //no crumbtrail used for the linear path
            numberCrumbTrailPoints = 5;

            bm3 = new Bitmap(mapWidth, mapHeight, System.Drawing.Imaging.PixelFormat.Format24bppRgb);

            prepLinearFeatureBitmapForPaint();
        }
Example #6
0
        public NavInterfaceMBed(LogFile _logFile, SettingsManager Settings)
        {
            logFile = _logFile;  //file where we write the mbed navigation data and status message

            //Thread reader/writer lock to prevent clobbering the posvel variable while it is being accessed
            posvelLock = new ReaderWriterLockSlim();
            comStatusMessageLock = new ReaderWriterLockSlim();

            triggerTimeReceievdFromMbed = false;  //set to true when we receive a 1PPS status message
            //reset to false in the calling program when the status message is processed

            //used to store the CRC results fpr the GPS messages received at the PC
            GPS_PC_CRC = new GPSMessageCRC_atPC();
            trigger = new Trigger();

            computeCRC = new NovatelCRC();  //class to compute the Novatel CRC value (see their manual)

            comStats = new CommStats();     //accumulated comm stats
            commStatusMessage = new CommStatusMessage(); //per sec comm status message

            navIFMutex_ = new Mutex();  //not sure we need this

            ////////////////////////////////////////////////////////////////////////////////////////////
            //wait here in a loop unitl we have attached the USB cable to access the mbed device
            ////////////////////////////////////////////////////////////////////////////////////////////
            initializeMbedSerialPort();
            if (!serialInit_)
            {
                logFile.WriteLine("mbed serial port not found");
                throw new Exception("no serial port found");
            }

            /////////////////////////////////////////////////////////////////////////////////////
            //At this stage we have found the mbed port and have successfully opened the port
            /////////////////////////////////////////////////////////////////////////////////////

            logFile.WriteLine("Successfully opened the mbed device");

            utm = new UTM2Geodetic();
            posvelAt1PPS = new PosVel();

            timeFrom1PPS = new Stopwatch();

            //set up the communications interface thread
            Thread mbedCommunication = new Thread(mbedCommunicationWorker);
            mbedCommunication.IsBackground = false;

            //start the communication and begin retrieving mbed messages
            mbedCommunication.Start();
            logFile.WriteLine("Completed starting the mbed communication thread");

            if (mbedCommunication.IsAlive)
            {
                logFile.WriteLine("mbedCommunication thread is operating ");
            }
            else
            {
                logFile.WriteLine("mbed communication htread os not operating ");
                MessageBox.Show("mbed comminication thread did not start ");
            }
        }
Example #7
0
        //constructor for MissionSelection Form for polygon mission
        public MissionSelection(ProjectSummary _ps, String _FlightPlanFolder, LogFile _logFile,
            NavInterfaceMBed navIF_In, SDKHandler cameraIn, bool hardwareAttached_, SettingsManager _settings, String _MissionDateString)
        {
            InitializeComponent();

            posVel_ = new PosVel();

            //set the flight plans folder and the Project Summary structure from the prior Project Selection
            FlightPlanFolder = _FlightPlanFolder;
            ps = _ps;
            navIF_ = navIF_In;
            camera = cameraIn;
            hardwareAttached = hardwareAttached_;
            settings = _settings;
            MissionDateString = _MissionDateString;
            logFile = _logFile;

            projectName = ps.ProjectName;

            //there is a separate constructor for the linearFeature coverage type
            coverageType = COVERAGE_TYPE.polygon;

            //getPosVelTimer = new Stopwatch();
            utm = new UTM2Geodetic();

            /////////////////////////////////////////////////////////////////////////////////////
            //set up the project polygon and the individual Mission polygons in pixel units
            /////////////////////////////////////////////////////////////////////////////////////

            //set of points in Pixels that we use to draw the project polygon onto the project map
            //creats space for an array of Point structures tha will hold the project polygon
            projectPolyPointsPix = new Point[ps.ProjectPolygon.Count];

            //lat/lon image bounds from the mission plan
            ib = ps.ProjectImage;  //placeholder for the project image bounds NOTE:  this is also used elsewhere

            //multiplier used for pix-to-geodetic conversion for the project map -- scales lat/lon to pixels
            // TODO:  ugly --- cant we do this exactly???
            //lon2PixMultiplier = mapScaleFactor * mapWidth / (ib.eastDeg - ib.westDeg);
            //lat2PixMultiplier = -mapScaleFactor * mapHeight / (ib.northDeg - ib.southDeg);  //"-" cause vertical map direction is positive towards the south
            lon2PixMultiplier =  mapWidth  / (ib.eastDeg - ib.westDeg);
            lat2PixMultiplier = -mapHeight / (ib.northDeg - ib.southDeg);  //"-" cause vertical map direction is positive towards the south

            //create the project polygon in pixel units -- once
            for (int i = 0; i < ps.ProjectPolygon.Count; i++)
                projectPolyPointsPix[i] = GeoToPix(ps.ProjectPolygon[i]);  //just uses a linear scaling

            //create the mission polygons (one per mission) in pixel units
            //used to form the clickable region on the project map
            missionPolysInPix = new List<Point[]>();
            for (int i = 0; i < ps.msnSum.Count; i++)
            {
                Point [] pts = new Point[ps.msnSum[i].missionGeodeticPolygon.Count];
                for (int j = 0; j < ps.msnSum[i].missionGeodeticPolygon.Count; j++)
                    pts[j] = GeoToPix(ps.msnSum[i].missionGeodeticPolygon[j]);
                missionPolysInPix.Add(pts);
            }
        }
Example #8
0
        //constructor for MissionSelection Form Linear Feature mission
        public MissionSelection(linearFeatureCoverageSummary _LFSum, String _FlightPlanFolder, LogFile _logFile,
            NavInterfaceMBed navIF_In, SDKHandler cameraIn, bool hardwareAttached_, SettingsManager _settings, String _MissionDateString)
        {
            InitializeComponent();

            posVel_ = new PosVel();

            //set the flight plans folder and the Project Summary structure from the prior Project Selection
            FlightPlanFolder = _FlightPlanFolder;
            LFSum = _LFSum;
            navIF_ = navIF_In;
            camera = cameraIn;
            hardwareAttached = hardwareAttached_;
            settings = _settings;
            MissionDateString = _MissionDateString;
            logFile = _logFile;

            projectName = LFSum.ProjectName;

            //this is a specific constructor for the linear feature coverage type
            coverageType = COVERAGE_TYPE.linearFeature;

            getPosVelTimer = new Stopwatch();
            utm = new UTM2Geodetic();

            //lat/lon image bounds from the mission plan
            ib = LFSum.ProjectImage;  //placeholder for the project image bounds NOTE:  this is also used elsewhere

            //multiplier used for pix-to-geodetic conversion for the project map -- scales lat/lon to pixels
            // TODO:  ugly --- cant we do this exactly???
            //lon2PixMultiplier = mapScaleFactor * mapWidth / (ib.eastDeg - ib.westDeg);
            //lat2PixMultiplier = -mapScaleFactor * mapHeight / (ib.northDeg - ib.southDeg);  //"-" cause vertical map direction is positive towards the south
            lon2PixMultiplier =  mapWidth / (ib.eastDeg   - ib.westDeg);
            lat2PixMultiplier = -mapHeight / (ib.northDeg - ib.southDeg);  //"-" cause vertical map direction is positive towards the south
        }
        public CurrentFlightLineGeometry( int missionNumber, int flightLineNumber, ProjectSummary _ps, bool[] _priorFlownFLs)
        {
            ////////////////////////////////////////////////////////////////////
            //do all the stuff that does not vary with the aircraft location
            ////////////////////////////////////////////////////////////////////

            ps = _ps;
            priorFlownFLs = _priorFlownFLs;

            UTM2Geodetic utm = new UTM2Geodetic();
            Rad2Deg = 180.0 / Math.Acos(-1.0);
            Deg2Rad = Math.Acos(-1.0) / 180.0;

            FLendUTM        = new PointD(0.0, 0.0);
            FLstartUTM      = new PointD(0.0, 0.0);
            FLP1endUTM      = new PointD(0.0, 0.0);
            FLP1startUTM    = new PointD(0.0, 0.0);

            //set up the parameters of the flight line independent of the aircraft Platform
            FLendGeo = ps.msnSum[missionNumber].FlightLinesCurrentPlan[flightLineNumber].end;
            FLstartGeo = ps.msnSum[missionNumber].FlightLinesCurrentPlan[flightLineNumber].start;

            //utm flight line endpoints
            utm.LLtoUTM(FLstartGeo.Y * Deg2Rad, FLstartGeo.X * Deg2Rad, ref FLstartUTM.Y, ref FLstartUTM.X, ref ps.UTMZone, true);
            utm.LLtoUTM(FLendGeo.Y   * Deg2Rad, FLendGeo.X   * Deg2Rad, ref FLendUTM.Y,   ref FLendUTM.X,   ref ps.UTMZone, true);

            // the number 10 means that the semi-infinite line extensions are 10 times longer than the flightline ....
            PointD del = 10 * (FLendGeo - FLstartGeo);  //semi-infinite line use for drawing a line extending beyond the FL ends
            semiInfiniteFLstartGeo = FLstartGeo - del;
            semiInfiniteFLendGeo   = FLendGeo   + del;

            FLlengthSq = (FLendUTM.X - FLstartUTM.X) * (FLendUTM.X - FLstartUTM.X) + (FLendUTM.Y - FLstartUTM.Y) * (FLendUTM.Y - FLstartUTM.Y);

            FLlengthMeters = Math.Sqrt(FLlengthSq);
            start2EndFlightLineUnit = new PointD((FLendUTM.X - FLstartUTM.X) / FLlengthMeters, (FLendUTM.Y - FLstartUTM.Y) / FLlengthMeters);

            //next flight line data -- what happens on the last flightlne ??
            if (flightLineNumber < (ps.msnSum[missionNumber].numberOfFlightlines-1) )
            {
                //this is redundant with code where the currentFlightLine is switched
                //  nextFlightlineNumber should be kept as a part of flightline geometry
                nextFlightlineNumber = flightLineNumber + 1;
                while (priorFlownFLs[nextFlightlineNumber])
                {
                    if (nextFlightlineNumber >= priorFlownFLs.Count() - 1) break;
                    nextFlightlineNumber++;
                }

                PointD FLP1endGeo = ps.msnSum[missionNumber].FlightLinesCurrentPlan[nextFlightlineNumber].end;
                PointD FLP1startGeo = ps.msnSum[missionNumber].FlightLinesCurrentPlan[nextFlightlineNumber].start;
                utm.LLtoUTM(FLP1startGeo.Y * Deg2Rad, FLP1startGeo.X * Deg2Rad, ref FLP1startUTM.Y, ref FLP1startUTM.X, ref ps.UTMZone, true);
                utm.LLtoUTM(FLP1endGeo.Y   * Deg2Rad, FLP1endGeo.X   * Deg2Rad, ref FLP1endUTM.Y,   ref FLP1endUTM.X,   ref ps.UTMZone, true);

                //works for all flightline aspects -- assumes the flightlines are parallel
                //project start-to-start (RS) and end-to-end (RE) vectors onto current flightline start-to-end unit vector
                double delSX = FLP1startUTM.X - FLstartUTM.X;
                double delSY = FLP1startUTM.Y - FLstartUTM.Y;
                double RS = start2EndFlightLineUnit.X * delSX + start2EndFlightLineUnit.Y * delSY;
                double delEX = FLP1endUTM.X - FLendUTM.X;
                double delEY = FLP1endUTM.Y - FLendUTM.Y;
                double RE = start2EndFlightLineUnit.X * delEX + start2EndFlightLineUnit.Y * delEY;
                if (RS < 0.0) ExtensionBeforeStart = -RS;
                if (RE > 0.0) ExtensionBeyondEnd   =  RE;

                //below works for only NS missions
                //if (FLP1endUTM.Y > FLendUTM.Y) ExtensionBeyondEnd = FLP1endUTM.Y - FLendUTM.Y;
                //if (FLP1startUTM.Y < FLstartUTM.Y) ExtensionBeforeStart = FLstartUTM.Y - FLP1startUTM.Y;
            }

               //the "+1" ensures a photocenter at the start of the flight line and at the end of the flight line.
            //The start/ends of the line have been placed on a grid with fixed downrange spacing for the complete project
            numPhotoCenters = Convert.ToInt32( FLlengthMeters / ps.downrangeTriggerSpacing) + 1;

            //used to record the successful completion of a photocenter
            //set to true after we have recorded the image on the storage media
            successfulImagesCollected = new bool[numPhotoCenters+10];
            //store the photocenter locations in pixel coordinates
            TriggerPoints = new Point[numPhotoCenters + 10];
            for (int i = 0; i < numPhotoCenters + 10; i++)
            {
                successfulImagesCollected[i] = false;
                TriggerPoints[i] = new Point();
            }
        }