Beispiel #1
0
 //Constructor
 public Image(string path, string hash, WordsearchImage[] wordsearchImages, Dictionary<string, string> metaData)
 {
     this.Path = path;
     this.Hash = hash;
     this.WordsearchImages = wordsearchImages;
     this.MetaData = metaData;
 }
        private void btnNextWordsearch_Click(object sender, EventArgs e)
        {
            //If there is a Bitmap to dispose of
            if (currentWordsearchImage != null)
            {
                //Dispose of bitmap(s) derived from WordsearchImage bitmap
                if(picBoxWordsearchImage.Image != currentBitmapWithGrid)
                {
                    picBoxWordsearchImage.Image.Dispose();
                }
                currentBitmapWithGrid.Dispose();
                currentBitmapWithGrid = null;

                currentWordsearchId = null;
                currentWordsearchImage = null;
            }

            //If there is another wordsearch to mark up
            if (toProcess.Count > 0)
            {
                //Get the next wordsearch ID
                currentWordsearchId = toProcess.Dequeue();

                //Get the clearest image of this wordsearch
                currentWordsearchImage = ImageMarkupDatabase.GetClearestWordsearchImage(currentWordsearchId);

                //Get the bitmap of this wordsearch image and draw the grid on it
                currentBitmapWithGrid = currentWordsearchImage.GetBitmapCustomResolution(
                    WORDSEARCH_IMAGE_BITMAP_WIDTH, WORDSEARCH_IMAGE_BITMAP_HEIGHT);
                DrawGrid.GridInPlace(currentBitmapWithGrid, currentWordsearchImage.Rows, currentWordsearchImage.Cols);

                //Highlight 0, 0 (current index) & display the image
                highlightCharacter(0, 0);

                //Update the label showing how many wordsearches are left to be processed
                updateLblToProcess();

                //Update the label showing the wordsearch ID
                lblWordsearchId.Text = defaultLblWordsearchId + currentWordsearchId;

                //Reset all fields
                resetFields();
            }
            else //Otherwise there are no more wordsearches to mark up
            {
                picBoxWordsearchImage.Visible = false;
                lblWordsearchId.Text = defaultLblWordsearchId;
            }
        }
        //Private Methods
        private static void loadDatabase()
        {
            XmlDocument xmlDoc = new XmlDocument();
            xmlDoc.Load(XML_DOC_LOCATION);

            XmlNode rootNode = xmlDoc.SelectSingleNode(XML_ROOT_EL);
            
            //Images
            XmlNode imagesNode = rootNode.SelectSingleNode(XML_IMAGES_EL);
            XmlNodeList imageNodes = imagesNode.SelectNodes(XML_IMAGE_EL);

            images = new Dictionary<string, Image>();
            foreach(XmlNode imageNode in imageNodes)
            {
                string path = imageNode.SelectSingleNode(XML_IMAGE_FILE_PATH_EL).InnerText;
                string hash = imageNode.SelectSingleNode(XML_IMAGE_HASH_EL).InnerText;

                //Wordsearch Images
                XmlNode wordsearchImagesNode = imageNode.SelectSingleNode(XML_WORDSEARCH_IMAGES_EL);
                XmlNodeList wordsearcheImageNodes = wordsearchImagesNode.SelectNodes(XML_WORDSEARCH_IMAGE_EL);
                List<WordsearchImage> wordsearchImages = new List<WordsearchImage>();
                foreach(XmlNode wiNode in wordsearcheImageNodes)
                {
                    //Coordinates
                    string strCoords = wiNode.SelectSingleNode(XML_WORDSEARCH_IMAGE_COORDINATES_EL).InnerText;
                    string[] pairs = strCoords.Trim().Split('.');

                    char[] trimChars = new char[] { '(', ')', ' ' };
                    
                    string[] parts = pairs[0].Split(',');
                    string x = parts[0].Trim(trimChars);
                    string y = parts[1].Trim(trimChars);
                    IntPoint topLeft = new IntPoint(int.Parse(x), int.Parse(y));

                    parts = pairs[1].Split(',');
                    x = parts[0].Trim(trimChars);
                    y = parts[1].Trim(trimChars);
                    IntPoint topRight = new IntPoint(int.Parse(x), int.Parse(y));

                    parts = pairs[2].Split(',');
                    x = parts[0].Trim(trimChars);
                    y = parts[1].Trim(trimChars);
                    IntPoint bottomRight = new IntPoint(int.Parse(x), int.Parse(y));

                    parts = pairs[3].Split(',');
                    x = parts[0].Trim(trimChars);
                    y = parts[1].Trim(trimChars);
                    IntPoint bottomLeft = new IntPoint(int.Parse(x), int.Parse(y));

                    uint rows = uint.Parse(wiNode.SelectSingleNode(XML_WORDSEARCH_IMAGE_ROWS_EL).InnerText);
                    uint cols = uint.Parse(wiNode.SelectSingleNode(XML_WORDSEARCH_IMAGE_COLS_EL).InnerText);

                    //Meta Data
                    XmlNode metaDataNode = wiNode.SelectSingleNode(XML_WORDSEARCH_IMAGE_METADATA_EL);
                    XmlNodeList metaDataNodes = metaDataNode.ChildNodes;
                    Dictionary<string, string> metaData = new Dictionary<string, string>();
                    foreach(XmlNode metaDataEntryNode in metaDataNodes)
                    {
                        metaData.Add(metaDataEntryNode.Name, metaDataEntryNode.InnerText);
                    }

                    //Optional WordsearchID field
                    string wordsearchId = null;
                    try
                    {
                        wordsearchId = wiNode.SelectSingleNode(XML_WORDSEARCH_IMAGE_WORDSEARCH_ID_EL).InnerText;
                    }
                    catch { }

                    //If there was a Wordsearch ID, pass that to the constructor
                    WordsearchImage wordsearchImage;
                    if(wordsearchId != null)
                    {
                        wordsearchImage = new WordsearchImage(topLeft, topRight, bottomRight,
                        bottomLeft, rows, cols, metaData, hash, wordsearchId);
                    }
                    else //Otherwise there is no Wordsearch ID
                    {
                        wordsearchImage = new WordsearchImage(topLeft, topRight, bottomRight, 
                        bottomLeft, rows, cols, metaData, hash);
                    }
                    wordsearchImages.Add(wordsearchImage);
                }

                //Meta Data
                XmlNodeList imageMetaDataNodes = imageNode.SelectSingleNode(XML_IMAGE_METADATA_EL).ChildNodes;
                Dictionary<string, string> imageMetaData = new Dictionary<string, string>();
                foreach(XmlNode metaDataEntryNode in imageMetaDataNodes)
                {
                    imageMetaData.Add(metaDataEntryNode.Name, metaDataEntryNode.InnerText);
                }

                Image image = new Image(path, hash, wordsearchImages.ToArray(), imageMetaData);
                images.Add(hash, image);
            }

            //Wordsearches
            XmlNode wordsearchesNode = rootNode.SelectSingleNode(XML_WORDSEARCHES_EL);
            XmlNodeList wordsearchNodes = wordsearchesNode.SelectNodes(XML_WORDSEARCH_EL);
            wordsearches = new Dictionary<string, Wordsearch>();
            foreach(XmlNode wordsearchNode in wordsearchNodes)
            {
                string wordsearchId = wordsearchNode.SelectSingleNode(XML_WORDSEARCH_ID_EL).InnerText;

                //Chars
                string strChars = wordsearchNode.SelectSingleNode(XML_WORDSEARCH_CHARS_EL).InnerText.Replace("\r", ""); //Strip carriage returns
                string[] strCharsRows = strChars.Split('\n');
                char[,] chars = new char[strCharsRows[0].Length, strCharsRows.Length];
                for(int i = 0; i < strCharsRows.Length; i++)
                {
                    for(int j = 0; j < strCharsRows[i].Length; j++)
                    {
                        chars[j, i] = strCharsRows[i][j];
                    }
                }

                //Words
                XmlNode wordsNode = wordsearchNode.SelectSingleNode(XML_WORDSEARCH_WORDS_EL);
                XmlNodeList wordNodes = wordsNode.SelectNodes(XML_WORDSEARCH_WORD_EL);
                List<string> words = new List<string>();
                foreach(XmlNode wordNode in wordNodes)
                {
                    words.Add(wordNode.InnerText);
                }

                Wordsearch wordsearch = new Wordsearch(wordsearchId, chars, words.ToArray());
                wordsearches.Add(wordsearchId, wordsearch);
            }
        }
        internal static bool IsWordsearch(List<IntPoint> candidate, WordsearchImage wordsearchImage)
        {
            IntPoint[] wordsearchPoints = wordsearchImage.Coordinates;

            //Does the candidate match this wordsearch (allowing for some margin of error so the points needn't be pixel perfect)

            //Margin for error should be an average cell dimension for a wordsearch grid in a circle around each corner of the wordsearch
            double widthTop = Geometry.EuclideanDistance(wordsearchImage.TopLeft, wordsearchImage.TopRight);
            double widthBottom = Geometry.EuclideanDistance(wordsearchImage.BottomLeft, wordsearchImage.BottomRight);
            double avgWidth = (widthTop + widthBottom) / 2;
            double avgCellWidth = avgWidth / wordsearchImage.Cols;

            double heightLeft = Geometry.EuclideanDistance(wordsearchImage.TopLeft, wordsearchImage.BottomLeft);
            double heightRight = Geometry.EuclideanDistance(wordsearchImage.TopRight, wordsearchImage.BottomRight);
            double avgHeight = (heightLeft + heightRight) / 2;
            double avgCellHeight = avgHeight / wordsearchImage.Rows;


            double errorMarginRadius = (avgCellWidth + avgCellHeight) / 2;

            //CandidatePoint => WordsearchPoint
            List<List<int>> matchedPoints = new List<List<int>>(candidate.Count);
            for (int i = 0; i < candidate.Count; i++)
            {
                matchedPoints.Add(new List<int>());
            }

            //For each candidate point, attempt to match each actual wordsearch point, storing the matches
            bool brokeEarly = false;
            for (int i = 0; i < candidate.Count; i++)
            {
                for (int j = 0; j < wordsearchPoints.Length; j++)
                {
                    IntPoint candidatePoint = candidate[i];
                    IntPoint wordsearchPoint = wordsearchPoints[j];

                    double pointDistance = Geometry.EuclideanDistance(candidatePoint, wordsearchPoint);

                    if (pointDistance <= errorMarginRadius)
                    {
                        matchedPoints[i].Add(j);
                    }
                }

                //If there were no wordsearch points that could be matched to this candidate point, fail for this wordsearch
                if (matchedPoints[i].Count == 0)
                {
                    brokeEarly = true;
                    break;
                }
            }

            //If we already know for sure that this isn't a match, continue to the next wordsearch 
            if (brokeEarly)
            {
                return false;
            }

            //Each point matched to another, now to check that there is a way for each point to mapped onto a distinct point in the other set
            List<List<int>> pointMatchCandidates = new List<List<int>>();

            //Initialise the search with the first possible matches
            foreach (int n in matchedPoints[0])
            {
                List<int> li = new List<int>();
                li.Add(n);

                pointMatchCandidates.Add(li);
            }

            for (int i = 1; i < matchedPoints.Count; i++)
            {
                List<List<int>> newCandidates = new List<List<int>>();
                foreach (int wordsearchPoint in matchedPoints[i])
                {
                    for (int j = 0; j < pointMatchCandidates.Count; j++)
                    {
                        //If this branch of the tree doesn't already contain this point, add it as it is a possible next branch to a solution
                        if (!pointMatchCandidates[j].Contains(wordsearchPoint))
                        {
                            List<int> copied = copy(pointMatchCandidates[j]);
                            copied.Add(wordsearchPoint);
                            newCandidates.Add(copied);
                        }
                    }
                }
                //Update the list of candidates
                pointMatchCandidates = newCandidates;
            }

            //If we are left with any solutions, then the candidate matches the wordsearch
            if (pointMatchCandidates.Count > 0)
            {
                return true;
            }
            else
            {
                return false;
            }
        }
Beispiel #5
0
        private void btnAddWordsearchImage_Click(object sender, EventArgs e)
        {
            //Check that we currently have an image on screen
            bool showingBitmap = !currentBitmap.Equals(default(KeyValuePair<Bitmap, string>));

            if(showingBitmap)
            {
                //Fetch all of the data for the Wordsearch Image & Validate it

                //Coordinates
                IntPoint topLeft = new IntPoint(); //Must have defaults to compile
                IntPoint topRight = new IntPoint();
                IntPoint bottomRight = new IntPoint();
                IntPoint bottomLeft = new IntPoint();
                bool validCoords = false;
                try
                {
                    topLeft = getTopLeftCoordinate();
                    topRight = getTopRightCoordinate();
                    bottomRight = getBottomRightCoordinate();
                    bottomLeft = getBottomLeftCoordinate();

                    //Check that the values we have received are in bounds
                    IntPoint[] coords = new IntPoint[4];
                    coords[0] = topLeft; //Winding Order: Clockwise starting in top left
                    coords[1] = topRight;
                    coords[2] = bottomRight;
                    coords[3] = bottomLeft;

                    foreach (IntPoint p in coords)
                    {
                        if (p.X < 0 || p.Y < 0 ||
                            p.X >= currentBitmap.Key.Width || p.Y >= currentBitmap.Key.Height)
                        {
                            throw new Exception("Point outside of Bitmap Bounds");
                        }
                    }

                    validCoords = true;
                }
                catch
                {
                    MessageBox.Show("Error parsing coordinates: please correct them and try again");
                }

                //If the coordinates are valid, get the next lot of data
                if (validCoords)
                {
                    //Num rows & cols
                    uint rows, cols;
                    bool parsedRows = uint.TryParse(txtNumRows.Text, out rows);
                    bool parsedCols = uint.TryParse(txtNumCols.Text, out cols);
                    bool validRowsAndCols = parsedRows && parsedCols && rows != 0 && cols != 0;

                    if (validRowsAndCols)
                    {
                        //Meta Data
                        Dictionary<string, string> metaData = new Dictionary<string, string>();
                        bool validMetaData = true;
                        for (int i = 0; i < dataGridViewWordsearchImageMetaData.Rows.Count; i++)
                        {
                            DataGridViewCell keyCell = dataGridViewWordsearchImageMetaData.Rows[i].Cells[0];
                            //If this cell has a value (i.e. is not the blank cell auto-inserted at the end)
                            if (keyCell.Value != null)
                            {
                                string key = keyCell.Value.ToString().Trim();

                                //Check the key isn't blank
                                if (key != "")
                                {
                                    //Check the key isn't already taken
                                    if (!metaData.ContainsKey(key))
                                    {
                                        DataGridViewCell valueCell = dataGridViewWordsearchImageMetaData.Rows[i].Cells[1];
                                        //Check that this has a value, if not make it empty
                                        string value;
                                        if(valueCell.Value == null)
                                        {
                                            value = "";
                                        }
                                        else
                                        {
                                            value = valueCell.Value.ToString();
                                        }

                                        metaData.Add(key, value);
                                    }
                                    else //Otherwise the key is already taken
                                    {
                                        validMetaData = false;
                                        MessageBox.Show("Invalid Meta Data: You cannot use the same key twice (" + key + ")");
                                        break;
                                    }
                                }
                                else //Otherwise the key is blank
                                {
                                    validMetaData = false;
                                    MessageBox.Show("Invalid Meta Data: You cannot have a blank Key");
                                    break;
                                }
                            }
                        }

                        //If the Meta Data is valid, we have everything necessary to make a WordsearchImage
                        if (validMetaData)
                        {
                            //Make a WordsearchImage
                            string fromImageHash = currentBitmap.Value;

                            WordsearchImage wordsearchImage;

                            //Check for optional field Wordsearch ID
                            string wordsearchId = txtWordsearchId.Text.Trim();
                            if (wordsearchId != "")
                            {
                                wordsearchImage = new WordsearchImage(topLeft, topRight, bottomRight, bottomLeft, rows, cols, metaData, fromImageHash, wordsearchId);
                            }
                            else //Otherwise the optional Wordsearch ID field hasn't been filled in
                            {
                                wordsearchImage = new WordsearchImage(topLeft, topRight, bottomRight, bottomLeft, rows, cols, metaData, fromImageHash);
                            }
                            wordsearchImages.Add(wordsearchImage);

                            //Reset the fields ready for the next WordsearchImage to be entered
                            resetWordsearchImageFields();

                            //If the image being displayed isn't being used elsewhere, dispose of it
                            if(bitmapToShow != picBoxImage.Image)
                            {
                                picBoxImage.Image.Dispose();
                            }

                            //Draw all of the WordsearchImages for this Image onto the original bitmap and display it
                            bitmapToShow = drawWordsearchImagesOnCurrentWordsearch();
                            picBoxImage.Image = bitmapToShow;

                            //If we were showing an enlarged wordsearch image, switch back to the main image
                            if(picBoxWordsearchImageLarge.Visible)
                            {
                                picBoxImage.Visible = true;
                                picBoxWordsearchImageLarge.Visible = false;
                            }
                        }
                    }
                    else
                    {
                        MessageBox.Show("Error parsing number of rows and cols: please correct them and try again");
                    }
                }
            }
            else //Otherwise we aren't showing a bitmap
            {
                MessageBox.Show("No Image currently on screen to add a Word search Image to");
            }
        }