Exemple #1
0
        public Match(
            DatabaseFin unknownFin,
            DarwinDatabase db,
            UpdateDisplayOutlinesDelegate updateOutlines,
            List <MatchFactor> matchFactors,
            bool createDefaultFactors = false)
            : this(unknownFin, db, updateOutlines)
        {
            if (!createDefaultFactors)
            {
                MatchFactors = matchFactors;
            }
            else if (Database.CatalogScheme != null)
            {
                switch (db.CatalogScheme.FeatureSetType)
                {
                case FeatureSetType.DorsalFin:
                    SetMatchOptions(RegistrationMethodType.TrimOptimalTip, true);
                    break;

                case FeatureSetType.Bear:
                    MatchFactors = MatchFactorPresets.CreateBearMatchFactors(db);
                    break;
                }
            }

            CheckUnknownForRequiredFeatures();

            // Force rediscovery (for debugging/testing, can uncomment
            //UnknownFin.FinOutline.RediscoverFeaturePoints(Database.CatalogScheme.FeatureSetType);
        }
Exemple #2
0
 public Match(
     DatabaseFin unknownFin,
     DarwinDatabase db,
     UpdateDisplayOutlinesDelegate updateOutlines,
     RegistrationMethodType registrationMethod,
     bool useFullFinError)
     : this(unknownFin, db, updateOutlines)
 {
     SetMatchOptions(registrationMethod, useFullFinError);
 }
Exemple #3
0
        private static Vector <double> CalculateRatios(
            DatabaseFin individual,
            List <FeaturePointType> benchmarkFeatures,
            List <FeaturePointType> landmarkFeatures,
            List <IEnumerable <FeaturePointType> > ratioPermutations,
            bool useRemappedOutline = false)
        {
            var coordinates = new Dictionary <FeaturePointType, PointF>();

            foreach (var featurePoint in landmarkFeatures)
            {
                if (useRemappedOutline)
                {
                    coordinates[featurePoint] = individual.FinOutline.GetRemappedFeaturePointCoords(featurePoint);
                }
                else
                {
                    coordinates[featurePoint] = individual.FinOutline.GetFeaturePointCoords(featurePoint);
                }
            }

            var benchmarkDistance = MathHelper.GetDistance(
                coordinates[benchmarkFeatures[0]].X,
                coordinates[benchmarkFeatures[0]].Y,
                coordinates[benchmarkFeatures[1]].X,
                coordinates[benchmarkFeatures[1]].Y);

            Vector <double> ratios = CreateVector.Dense <double>(ratioPermutations.Count - 1);

            int i = 0;

            foreach (var permutation in ratioPermutations)
            {
                var permutationList = permutation.ToList();

                if ((permutationList[0] == benchmarkFeatures[0] && permutationList[1] == benchmarkFeatures[1]) ||
                    (permutationList[0] == benchmarkFeatures[1] && permutationList[1] == benchmarkFeatures[0]))
                {
                    // This is our benchmark
                    continue;
                }

                var currentDistance = MathHelper.GetDistance(
                    coordinates[permutationList[0]].X,
                    coordinates[permutationList[0]].Y,
                    coordinates[permutationList[1]].X,
                    coordinates[permutationList[1]].Y);

                ratios[i] = currentDistance / benchmarkDistance;

                i += 1;
            }

            return(ratios);
        }
        private void ViewOutlineInformationButton_Click(object sender, RoutedEventArgs e)
        {
            if (_vm.SelectedResult != null)
            {
                var selectedDBFin = _vm.FullyLoadFinByID(_vm.SelectedResult.DatabaseID);

                selectedDBFin.FinOutline.ChainPoints = _vm.SelectedResult.dbContour;

                DatabaseFin copyUnknown = new DatabaseFin(_vm.DatabaseFin);
                copyUnknown.FinOutline.ChainPoints = _vm.SelectedResult.unknownContour;

                var outlineWindowVM = new OutlineWindowViewModel(_vm.Database, selectedDBFin, copyUnknown, _vm.SelectedResult);

                var outlineWindow = new OutlineWindow(outlineWindowVM);

                outlineWindow.Show();
            }
        }
        private void ViewUnknownImageButton_Click(object sender, RoutedEventArgs e)
        {
            if (_vm.SelectedResult != null)
            {
                var fin = new DatabaseFin(_vm.DatabaseFin);

                fin.FinOutline.ChainPoints = null;

                if (_vm.UnknownShowOriginalImage)
                {
                    fin.FinImage = fin.OriginalFinImage;
                }

                var         vm          = new TraceWindowViewModel(fin, _vm.Database, "Viewing Unknown", null, true);
                TraceWindow traceWindow = new TraceWindow(vm);
                traceWindow.Show();
            }
        }
Exemple #6
0
        private bool FilterListView(object item)
        {
            if (string.IsNullOrEmpty(FilterTextBox.Text))
            {
                return(true);
            }

            DatabaseFin filterItem = item as DatabaseFin;

            if (filterItem == null)
            {
                return(true);
            }

            if (string.IsNullOrEmpty(filterItem.IDCode))
            {
                return(false);
            }

            return(filterItem.IDCode.IndexOf(FilterTextBox.Text, StringComparison.OrdinalIgnoreCase) > 0);
        }
Exemple #7
0
        public static MatchError ComputeMouthDentError(
            DatabaseFin unknownFin,
            DatabaseFin databaseFin,
            MatchOptions options)
        {
            if (unknownFin == null)
            {
                throw new ArgumentNullException(nameof(unknownFin));
            }

            if (databaseFin == null)
            {
                throw new ArgumentNullException(nameof(databaseFin));
            }

            var maxError = new MatchError {
                Error = 1
            };

            if (databaseFin.FinOutline?.FeatureSet?.Features.ContainsKey(Features.FeatureType.HasMouthDent) != true ||
                unknownFin.FinOutline?.FeatureSet?.Features.ContainsKey(Features.FeatureType.BrowCurvature) != true)
            {
                return(maxError);
            }

            var unknownHasMouthDent  = unknownFin.FinOutline?.FeatureSet?.Features[Features.FeatureType.HasMouthDent].Value;
            var databaseHasMouthDent = databaseFin.FinOutline?.FeatureSet?.Features[Features.FeatureType.HasMouthDent].Value;

            if (unknownHasMouthDent == null || databaseHasMouthDent == null)
            {
                return(maxError);
            }

            return(new MatchError
            {
                Error = Math.Abs(unknownHasMouthDent.Value - databaseHasMouthDent.Value)
            });
        }
Exemple #8
0
        public Match(
            DatabaseFin unknownFin,
            DarwinDatabase db,
            UpdateDisplayOutlinesDelegate updateOutlines)
        {
            if (unknownFin == null)
            {
                throw new ArgumentNullException(nameof(unknownFin));
            }

            if (db == null)
            {
                throw new ArgumentNullException(nameof(db));
            }

            UnknownFin      = new DatabaseFin(unknownFin);
            Database        = db;
            _updateOutlines = updateOutlines;

            CurrentFinIndex = 0;

            MatchResults = new MatchResults(unknownFin.IDCode, unknownFin?.FinFilename, db?.Filename);
        }
Exemple #9
0
        public static MatchError ComputeEigenValueWeightedCosineDistance(
            RatioComparison ratioComparison,
            DatabaseFin unknownFin,
            DatabaseFin databaseFin,
            MatchOptions options)
        {
            if (ratioComparison == null)
            {
                throw new ArgumentNullException(nameof(ratioComparison));
            }

            if (unknownFin == null)
            {
                throw new ArgumentNullException(nameof(unknownFin));
            }

            if (databaseFin == null)
            {
                throw new ArgumentNullException(nameof(databaseFin));
            }

            bool useRemappedOutline = false;

            var featureSetMatchOptions = options as FeatureSetMatchOptions;

            if (featureSetMatchOptions != null)
            {
                useRemappedOutline = featureSetMatchOptions.UseRemappedOutline;
            }

            // TODO: Some of this is the same for each comparison, so we're doing extra work here.  Might want to refactor some of this.
            Vector <double> unknownRatiosUncorrected = CalculateRatios(unknownFin,
                                                                       ratioComparison.BenchmarkFeatures,
                                                                       ratioComparison.LandmarkFeatures,
                                                                       ratioComparison.RatioPermutations,
                                                                       useRemappedOutline);

            var unknownRatios = unknownRatiosUncorrected - ratioComparison.AverageRatios;

            var unknownRHatMatrix = unknownRatios.ToRowMatrix() * ratioComparison.ProjectionMatrix;

            ratioComparison.UnknownRHat = CreateVector.Dense <double>(unknownRHatMatrix.ColumnCount);
            for (int i = 0; i < unknownRHatMatrix.ColumnCount; i++)
            {
                ratioComparison.UnknownRHat[i] = unknownRHatMatrix[0, i];
            }

            var databaseRHat = ratioComparison.IndividualRatios
                               .Where(ir => ir.DatabaseFin == databaseFin)
                               .Select(ir => ir.RHat)
                               .First();
            var databaseRawRatios = ratioComparison.IndividualRatios
                                    .Where(ir => ir.DatabaseFin == databaseFin)
                                    .Select(ir => ir.RawRatios)
                                    .First();

            double numerator    = 0;
            double probeValue   = 0;
            double galleryValue = 0;

            for (int i = 0; i < ratioComparison.UnknownRHat.Count; i++)
            {
                numerator += (databaseRHat[i] * ratioComparison.UnknownRHat[i]) / Math.Pow(ratioComparison.EigenValues[i], 2);

                probeValue   += Math.Pow(ratioComparison.UnknownRHat[i] / ratioComparison.EigenValues[i], 2);
                galleryValue += Math.Pow(databaseRHat[i] / ratioComparison.EigenValues[i], 2);
            }

            numerator *= -1;

            double denominator = Math.Sqrt(probeValue * galleryValue);

            double ewcDistance = numerator / denominator;

            Trace.WriteLine("Unknown: " + unknownFin.IDCode + " DB: " + databaseFin.IDCode + " EWC Distance: " + ewcDistance);

            // Raw EWC is between -1 and 1.  -1 is the best match, 1 is the worst
            return(new MatchError
            {
                Error = ewcDistance + 1, // Adding 1 so this should always be positive with 0 as the "best" match,
                RHat = ratioComparison.UnknownRHat,
                RawRatios = unknownRatiosUncorrected,
                DBRawRatios = databaseRawRatios,
                DBRHat = databaseRHat
            });
        }
Exemple #10
0
        public static MatchError ComputeMahalanobisDistance(
            RatioComparison ratioComparison,
            DatabaseFin unknownFin,
            DatabaseFin databaseFin,
            MatchOptions options)
        {
            if (ratioComparison == null)
            {
                throw new ArgumentNullException(nameof(ratioComparison));
            }

            if (unknownFin == null)
            {
                throw new ArgumentNullException(nameof(unknownFin));
            }

            if (databaseFin == null)
            {
                throw new ArgumentNullException(nameof(databaseFin));
            }

            bool useRemappedOutline = false;

            var featureSetMatchOptions = options as FeatureSetMatchOptions;

            if (featureSetMatchOptions != null)
            {
                useRemappedOutline = featureSetMatchOptions.UseRemappedOutline;
            }

            // TODO: Some of this is the same for each comparison, so we're doing extra work here.  Might want to refactor some of this.
            Vector <double> unknownRatiosUncorrected = CalculateRatios(unknownFin,
                                                                       ratioComparison.BenchmarkFeatures,
                                                                       ratioComparison.LandmarkFeatures,
                                                                       ratioComparison.RatioPermutations,
                                                                       useRemappedOutline);

            var unknownRatios = unknownRatiosUncorrected - ratioComparison.AverageRatios;

            var unknownRHatMatrix = unknownRatios.ToRowMatrix() * ratioComparison.ProjectionMatrix;

            ratioComparison.UnknownRHat = CreateVector.Dense <double>(unknownRHatMatrix.ColumnCount);
            for (int i = 0; i < unknownRHatMatrix.ColumnCount; i++)
            {
                ratioComparison.UnknownRHat[i] = unknownRHatMatrix[0, i];
            }

            var databaseRHat = ratioComparison.IndividualRatios
                               .Where(ir => ir.DatabaseFin == databaseFin)
                               .Select(ir => ir.RHat)
                               .First();
            var databaseRawRatios = ratioComparison.IndividualRatios
                                    .Where(ir => ir.DatabaseFin == databaseFin)
                                    .Select(ir => ir.RawRatios)
                                    .First();

            double mahalanobisDistanceSum = 0;

            for (int i = 0; i < ratioComparison.UnknownRHat.Count; i++)
            {
                mahalanobisDistanceSum += Math.Abs(ratioComparison.UnknownRHat[i] - databaseRHat[i]) / ratioComparison.EigenValues[i];
            }

            Trace.WriteLine("Unknown: " + unknownFin.IDCode + " DB: " + databaseFin.IDCode + " Mahalanobis Distance: " + mahalanobisDistanceSum);

            return(new MatchError
            {
                Error = mahalanobisDistanceSum,
                RHat = ratioComparison.UnknownRHat,
                RawRatios = unknownRatiosUncorrected,
                DBRawRatios = databaseRawRatios,
                DBRHat = databaseRHat
            });
        }
Exemple #11
0
        //*******************************************************************
        //
        // float Match::matchSingleFin(int registrationMethod, int regSegmentsUsed,
        //                             bool categoryToMatch[], bool useFullFinError,
        //                             bool useAbsoluteOffsets)
        //
        //    Attempts to match unknown fin to a single database fin.  The
        //    current fin is mDatabase->getItem(mCurrentFin). The match_method
        //    parameter determines which of several outline mapping and
        //    error between match techniques is used.
        //
        //    now modified to match ONLY those database fins with category designation
        //    indicated in categoryToMatch array
        //
        //    ***055ER
        //    the new useFullFinError parameter indicates whether or not to use the
        //    entire outlines in the final calculation of the error measure.  When false,
        //    only the portion of the outlines between the adjusted leadingeEdgeBegin and
        //    trailingEdgeEnd points is used. When true, the fin mapping is done using
        //    various subsets of the outlines (and errors derived from same), but the
        //    final error (measure of mismatch) uses all outline points from each fin.
        //    This parameter does not affect the original and the trim by 1/10th percent
        //    matching techniques, which always use the entire outline in error calculations
        //
        //    ***1.3
        //    New parameter useAbsoluteOffsets, wen true, causes function to step through
        //    the database absolute offset list so that fins are matched in the actual
        //    order that they are stored in the database.  This is used ONLY when MATCH
        //    QUEUES are being processed, and it keeps the fin numbers correct even if the
        //    database is later modified.
        //
        public float MatchSingleIndividual(List <Category> categoriesToMatch)
        {
            if (MatchFactors == null || MatchFactors.Count < 1)
            {
                throw new Exception("Match factors haven't been set yet!");
            }

            var stopWatch = System.Diagnostics.Stopwatch.StartNew();

            int matchIndex = 0;

            lock (locker)
            {
                // If we have any factors missing updateOutlines, but we know what
                // the delegate should be, fill them in
                if (CurrentFinIndex == 0 && _updateOutlines != null && MatchFactors.Any(mf => mf.MatchFactorType == MatchFactorType.Outline && mf.UpdateOutlines == null))
                {
                    foreach (var matchFactor in MatchFactors.Where(mf => mf.MatchFactorType == MatchFactorType.Outline && mf.UpdateOutlines == null))
                    {
                        matchFactor.UpdateOutlines = _updateOutlines;
                    }
                }

                // TODO?
                //if (CurrentFinIndex >= Database.AllFins.Count)
                //    return 100.0f;

                matchIndex       = CurrentFinIndex;
                CurrentFinIndex += 1;
            }

            DatabaseFin thisDBFin = Database.AllFins[matchIndex];

            bool tryMatch = categoriesToMatch.Exists(c => c.Name.ToLower() == thisDBFin.DamageCategory.ToLower());

            if (tryMatch)
            {
                // TODO: This isn't done quite right yet
                MatchError matchErrorResult = new MatchError();
                double     errorBetweenFins = 0.0;

                List <MatchFactorError> rawError = new List <MatchFactorError>();

                int factorIndex = 0;
                try
                {
                    foreach (var factor in MatchFactors)
                    {
                        var factorResult = factor.FindErrorBetweenIndividuals(UnknownFin, thisDBFin);

                        if (factor.MatchFactorType == MatchFactorType.Outline)
                        {
                            Vector <double> saveRawRatios = null;
                            if (matchErrorResult.RawRatios != null)
                            {
                                saveRawRatios = matchErrorResult.RawRatios;
                            }

                            Vector <double> saveRHat = null;
                            if (matchErrorResult.RHat != null)
                            {
                                saveRHat = matchErrorResult.RHat;
                            }

                            Vector <double> saveDBRHat = null;
                            if (matchErrorResult.DBRHat != null)
                            {
                                saveDBRHat = matchErrorResult.DBRHat;
                            }

                            Vector <double> saveDBRawRatios = null;
                            if (matchErrorResult.DBRawRatios != null)
                            {
                                saveDBRawRatios = matchErrorResult.DBRawRatios;
                            }

                            matchErrorResult = factorResult;

                            if (factorResult.Contour1 != null)
                            {
                                UnknownFin.FinOutline.RemappedChainPoints = factorResult.Contour1;
                            }

                            if (saveRawRatios != null)
                            {
                                matchErrorResult.RawRatios = saveRawRatios;
                            }
                            if (saveRHat != null)
                            {
                                matchErrorResult.RHat = saveRHat;
                            }
                            if (saveDBRawRatios != null)
                            {
                                matchErrorResult.DBRawRatios = saveDBRawRatios;
                            }
                            if (saveDBRHat != null)
                            {
                                matchErrorResult.DBRHat = saveDBRHat;
                            }
                        }
                        else
                        {
                            matchErrorResult.RawRatios   = factorResult.RawRatios;
                            matchErrorResult.RHat        = factorResult.RHat;
                            matchErrorResult.DBRawRatios = factorResult.DBRawRatios;
                            matchErrorResult.DBRHat      = factorResult.DBRHat;
                        }

                        // We're going to rescale this later -- should probably remove this
                        // errorBetweenFins += factor.Weight * result.Error;
                        var matchFactorError = new MatchFactorError
                        {
                            FactorIndex = factorIndex,
                            Error       = factorResult.Error,
                            Weight      = factor.Weight
                        };

                        rawError.Add(matchFactorError);

                        lock (locker)
                        {
                            RawErrorTracking.Add(matchFactorError);
                        }

                        factorIndex += 1;
                    }
                }
                catch (Exception ex)
                {
                    Trace.WriteLine(ex);
                }

                // Now, store the result
                Result r = new Result(
                    matchErrorResult.Contour1, //***005CM
                    matchErrorResult.Contour2, //***005CM
                    thisDBFin.ID,
                    // TODO - This image filename stuff is a little ugly.
                    (string.IsNullOrEmpty(thisDBFin.OriginalImageFilename)) ? thisDBFin.ImageFilename : thisDBFin.OriginalImageFilename,
                    thisDBFin.ThumbnailFilenameUri,
                    matchIndex,
                    rawError,
                    errorBetweenFins,
                    thisDBFin.IDCode,
                    thisDBFin.Name,
                    thisDBFin.DamageCategory,
                    thisDBFin.DateOfSighting,
                    thisDBFin.LocationCode);

                if (matchErrorResult.RHat != null)
                {
                    r.RHat = matchErrorResult.RHat;
                }

                if (matchErrorResult.RawRatios != null)
                {
                    r.RawRatios = matchErrorResult.RawRatios;
                }

                if (matchErrorResult.DBRHat != null)
                {
                    r.DBRHat = matchErrorResult.DBRHat;
                }

                if (matchErrorResult.DBRawRatios != null)
                {
                    r.DBRawRatios = matchErrorResult.DBRawRatios;
                }

                //***1.1 - set indices of beginning, tip and end points used in mapping
                r.SetMappingControlPoints(
                    matchErrorResult.Contour1ControlPoint1, matchErrorResult.Contour1ControlPoint2, matchErrorResult.Contour1ControlPoint3,  // beginning, tip & end of unknown fin
                    matchErrorResult.Contour2ControlPoint1, matchErrorResult.Contour2ControlPoint2, matchErrorResult.Contour2ControlPoint3); // beginning, tip & end of database fin

                stopWatch.Stop();

                lock (locker)
                {
                    MatchResults.AddResult(r);
                    MatchResults.TimeTaken += stopWatch.ElapsedMilliseconds;
                }
            }

            lock (locker)
            {
                int numberDone = MatchResults.Count;

                if (numberDone >= Database.AllFins.Count)
                {
                    if (RawErrorTracking != null && RawErrorTracking.Count > 0)
                    {
                        // Now that we're through matching, let's rescale the errors
                        Dictionary <int, float> scaleFactors = new Dictionary <int, float>();

                        foreach (var idx in RawErrorTracking.Select(r => r.FactorIndex).Distinct())
                        {
                            double minError = RawErrorTracking.Where(r => r.FactorIndex == idx).Min(r => r.Error);
                            double maxError = RawErrorTracking.Where(r => r.FactorIndex == idx).Max(r => r.Error);

                            // Force minError to 0 if it's not <= already
                            if (minError > 0)
                            {
                                minError = 0;
                            }

                            scaleFactors[idx] = (float)(1 / (maxError - minError));
                        }

                        foreach (var result in MatchResults.Results)
                        {
                            if (result.RawError != null && result.RawError.Count > 0)
                            {
                                double scaledError = 0.0;

                                foreach (var raw in result.RawError)
                                {
                                    scaledError += scaleFactors[raw.FactorIndex] * raw.Error * raw.Weight;
                                }

                                result.Error      = scaledError;
                                result.Confidence = 1.0f - scaledError;

                                // For rounding issues so we prevent seeing "-0" in the UI
                                if (result.Confidence < 0)
                                {
                                    result.Confidence = 0;
                                }
                            }
                        }
                    }

                    return(1.0f);
                }

                return((float)numberDone / Database.AllFins.Count);
            }
        }
Exemple #12
0
        //  1.1 - the following functions used in MatchQueue context

        public static MatchResults Load(string fileName, out DarwinDatabase db, out DatabaseFin databaseFin)
        {
            MatchResults result = new MatchResults();

            db          = null;
            databaseFin = null;

            if (string.IsNullOrEmpty(fileName))
            {
                throw new ArgumentNullException(nameof(fileName));
            }

            if (!File.Exists(fileName))
            {
                throw new ArgumentOutOfRangeException(nameof(fileName));
            }

            var lines = File.ReadAllLines(fileName);

            if (lines.Length < 6 || !lines[0].StartsWith("Results for ID:"))
            {
                return(result);
            }

            result._finID = lines[0].Substring(lines[0].LastIndexOf(":") + 1).Trim();

            result.TracedFinFile = lines[1].Substring(lines[1].IndexOf(":") + 1).Trim();
            result.DatabaseFile  = lines[2].Substring(lines[2].IndexOf(":") + 1).Trim();

            db = CatalogSupport.OpenDatabase(result.DatabaseFile, Options.CurrentUserOptions.DefaultCatalogScheme, false);

            //***2.2 - if we can, determine if database path has just changed drive letter
            // or some part of path that is a prefix to the SurveyArea.  If the database
            // is in the same SurveyArea and has the same database name, then we can
            // proceed with the building of the MatchResults
            //int p = mDatabaseFile.find("surveyAreas");
            //string rqdAreaAndDB = mDatabaseFile.substr(p);  // survey area and database name
            //string rqdPreamble = mDatabaseFile.substr(0, p);    // strip it to get preamble

            //string currentDBFile = db->getFilename();
            //p = currentDBFile.find("surveyAreas");
            //string currentAreaAndDB = currentDBFile.substr(p); // survey area and catalog name
            //string currentPreamble = currentDBFile.substr(0, p); // strip it to get preamble

            //if (db.Filename.ToLower() != DatabaseFile.ToLower())
            //{
            //    //cout << mDatabaseFile << endl;
            //    //cout << rqdPreamble << "   " << rqdAreaAndDB << endl;
            //    //cout << currentDBFile << endl;
            //    //cout << currentPreamble << "   " << currentAreaAndDB << endl;

            //    if (currentAreaAndDB == rqdAreaAndDB)
            //    {
            //        string msg = "The Survey Area and Catalog for the match results appear corrrect,\n";
            //        msg += "but the path to DARWIN's home folder seems to have changed.\n";
            //        msg += "Is it OK to open the indicated catalog in the current location\n";
            //        msg += "as shown below?\n\n";
            //        msg += (currentPreamble + rqdAreaAndDB);

            //        Trace.WriteLine(msg);
            //        //ErrorDialog *err = new ErrorDialog(msg);
            //        //err->show();

            //        //***2.2 - path possibly has to be fixed to FIN file as well
            //        if ((currentDBFile != mDatabaseFile) && (currentAreaAndDB == rqdAreaAndDB))
            //        {
            //            //add preamble of current DARWINHOME to FINs relative location
            //            p = mTracedFinFile.find("surveyAreas");
            //            string currentFinAreaPlus = mTracedFinFile.substr(p);
            //            mTracedFinFile = currentPreamble + currentFinAreaPlus;
            //            cout << mTracedFinFile << endl;
            //        }
            //    }
            //    else
            //    {
            //        string msg = "The WRONG database is currently loaded for viewing these results ...\n\n";
            //        msg += "LOADED DB:\n    " + db->getFilename() + "\n\n";
            //        msg += "REQUIRED DB:\n    " + mDatabaseFile + "\n\n";
            //        msg += "Please load the required database from the main window\n";
            //        msg += "and then reload the desired results file.";

            //        //ErrorDialog *err = new ErrorDialog(msg);
            //        //err->show();
            //        //***2.22 - replacing own ErrorDialog with GtkMessageDialogs
            //        GtkWidget* errd = gtk_message_dialog_new(NULL,
            //                                GTK_DIALOG_DESTROY_WITH_PARENT,
            //                                GTK_MESSAGE_ERROR,
            //                                GTK_BUTTONS_CLOSE,
            //                                msg.c_str());
            //        gtk_dialog_run(GTK_DIALOG(errd));
            //        gtk_widget_destroy(errd);
            //        return NULL;
            //    }
            //}

            DatabaseFin unkFin = CatalogSupport.OpenFinz(result.TracedFinFile);

            // get match info on each matched database fin
            // After skipping some of the headers
            for (int i = 6; i < lines.Length; i++)
            {
                string line = lines[i];

                int pos = line.IndexOf("\t");
                //string rank = line.Substring(0, pos);
                line = line.Substring(pos + 1);

                pos = line.IndexOf("\t");
                string error = line.Substring(0, pos);
                line = line.Substring(pos + 1);

                pos = line.IndexOf("\t");
                string dbFinID = line.Substring(0, pos);
                line = line.Substring(pos + 1);

                //cout << "dbFinID[" << dbFinID << "]"; //*** 2.2 - show for now

                string numStr;
                int
                    dbFinPosition,
                    uBegin, uTip, uEnd,
                    dbBegin, dbTip, dbEnd;

                pos           = line.IndexOf("\t");
                numStr        = line.Substring(0, pos);
                line          = line.Substring(pos + 1);
                dbFinPosition = int.Parse(numStr);
                //cout << "[" << dbFinPosition << "]" << endl; //*** 2.2 - show for now

                pos    = line.IndexOf("\t");
                numStr = line.Substring(0, pos);
                uBegin = int.Parse(numStr);
                line   = line.Substring(pos + 1);
                //cout << "[" << uBegin << "]";

                pos    = line.IndexOf("\t");
                numStr = line.Substring(0, pos);
                uTip   = int.Parse(numStr);
                line   = line.Substring(pos + 1);
                //cout << "[" << uTip << "]";

                pos    = line.IndexOf("\t");
                numStr = line.Substring(0, pos);
                uEnd   = int.Parse(numStr);
                line   = line.Substring(pos + 1);
                //cout << "[" << uEnd << "]";

                pos     = line.IndexOf("\t");
                numStr  = line.Substring(0, pos);
                dbBegin = int.Parse(numStr);
                line    = line.Substring(pos + 1);
                //cout << "[" << dbBegin << "]";

                pos    = line.IndexOf("\t");
                numStr = line.Substring(0, pos);
                dbTip  = int.Parse(numStr);
                line   = line.Substring(pos + 1);
                //cout << "[" << dbTip << "]";

                pos    = line.IndexOf("\t");
                numStr = line.Substring(0, pos);
                dbEnd  = int.Parse(numStr);
                line   = line.Substring(pos + 1);
                //cout << "[" << dbEnd << "]";

                //string damage = line;
                //cout << "[" << damage << "]" << endl;

                // The position is written starting at 1, but our index is 0 based
                DatabaseFin thisDBFin = db.AllFins[dbFinPosition - 1];

                // TODO: Should this throw an exception instead?
                if (thisDBFin.IDCode != dbFinID)
                {
                    Trace.WriteLine("Disaster " + thisDBFin.IDCode + " " + dbFinID);
                }

                FloatContour mappedUnknownContour = unkFin.FinOutline.ChainPoints.MapContour(
                    unkFin.FinOutline.ChainPoints[uTip],
                    unkFin.FinOutline.ChainPoints[uBegin],
                    unkFin.FinOutline.ChainPoints[uEnd],
                    thisDBFin.FinOutline.ChainPoints[dbTip],
                    thisDBFin.FinOutline.ChainPoints[dbBegin],
                    thisDBFin.FinOutline.ChainPoints[dbEnd]);

                Result r = new Result(
                    mappedUnknownContour,                 //***1.3 - Mem Leak - constructor make copy now
                    thisDBFin.FinOutline.ChainPoints,     //***1.3 - Mem Leak - constructor make copy now
                    thisDBFin.ID,
                    // TODO - This image filename stuff is a little ugly.
                    (string.IsNullOrEmpty(thisDBFin.OriginalImageFilename)) ? thisDBFin.ImageFilename : thisDBFin.OriginalImageFilename,
                    thisDBFin.ThumbnailFilenameUri,
                    dbFinPosition - 1,     // position of fin in database
                    double.Parse(error),
                    thisDBFin.IDCode,
                    thisDBFin.Name,
                    thisDBFin.DamageCategory,
                    thisDBFin.DateOfSighting,
                    thisDBFin.LocationCode);

                r.SetMappingControlPoints(
                    uBegin, uTip, uEnd,      // beginning, tip & end of unknown fin
                    dbBegin, dbTip, dbEnd);  // beginning, tip & end of database fin

                result.Results.Add(r);
            }

            databaseFin = unkFin;
            result.SetRankings();
            return(result);
        }