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 ////////////////////////////////////////////////////////////// }
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 }
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(); }
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 "); } }
//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); } }
//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(); } }