Определение максимального размера пикселя символов в ограниченной области - PullRequest
0 голосов
/ 06 марта 2020

Я пытаюсь реализовать функцию, которая показывает максимально возможное количество пикселей, которое умещается в области.

Пример 1 : представьте светодиодный дисплей размером: 100x20 пикселей. Строка, которую нужно показать: volutpa commodo diam

После того, как я все сделал вручную, я смог определить, что максимально возможный размер пикселя символов без разделения / разделения слов: 8x8 пикселей Каждый символ должен иметь одинаковый размер пикселя.

Приведенная выше строка будет успешно отображаться на светодиодном дисплее, если размер символа составляет 8x8 пикселей. Ожидаемый результат: 8

Пример 2 : представьте светодиодный дисплей размером: 100x20 пикселей. Требуемая строка: dia volutpa diam

Приведенная выше строка будет успешно отображаться на светодиодном дисплее, если размер символа составляет 9x9 пикселей. Ожидаемый результат: 9

Пример 3 : представьте светодиодный дисплей размером: 55x25 пикселей. Строка, которая должна быть показана: dio tuo diam

Строка выше будет успешно отображена на светодиодном дисплее, если размер символа составляет 8x8 пикселей. Ожидаемый результат: 8

Пример 4 : представьте светодиодный дисплей размером: 20x6 пикселей. Строка, которая должна быть показана: tuo volutpa

Строка выше будет успешно отображена на светодиодном дисплее, если размер пикселя символа составляет 2x2 px. Ожидаемый результат: 2

Примечание. Каждый символ в строке (включая пробел) должен иметь одинаковый размер пикселя (например, 6x6 пикселей), чтобы заполнить всю область (светодиодный дисплей) и слова в строке нельзя разбивать / делить.

В этом примере 1 вы можете увидеть «сделанное вручную» изображение того, чего я пытаюсь достичь. Весь макет представляет размер области (100x20 пикселей), в то время как черные квадраты представляют максимально возможный размер символа (8x8 пикселей). Если я использую (9x9 px или больше) для размера символа, текст не поместится, и если я использую (7x7 px или меньше), будет слишком много пустого пространства.

В этом пример 2 вы можете увидеть "сделанное вручную" изображение того, чего я пытаюсь достичь. Весь макет представляет размер области (100x20 пикселей), в то время как черные квадраты представляют максимально возможный размер символа (9x9 пикселей). Если я использую (10x10 px или больше) для размера символа, текст не поместится, и если я использую (8x8 px или меньше), будет слишком много пустого пространства. Мы должны игнорировать пробел в конце слова, если строка подходит к концу.

Ожидается :

Строка 1: dio_volutpa

Строка 2: диаметр

Фактический :

Строка 1: dio_volutpa_

Строка 2: диаметр

В этом пример 3 вы можете увидеть "сделанное вручную" изображение того, чего я пытаюсь достичь. Весь макет представляет размер области (55x25 пикселей), в то время как черные квадраты представляют максимально возможный размер символа (8x8 пикселей). Если я использую (9x9 px или больше) для размера символа, текст не поместится, и если я использую (7x7 px или меньше), будет слишком много пустого пространства. Красные прямоугольники показывают, что для следующего слова нет места, поэтому ему нужно go для новой строки ИЛИ уменьшить размер в пикселях, если ниже строки нет пробела.

Что будет лучший способ реализовать это в C#?

static void Main(string[] args)
    {
        String sentence = "volutpa commodo diam";
        int width = 100; // 100 px
        int height = 20; // 20 px
        int pixelSize = height / 2; // Starting pixel size (10)
        int maxLines = height / pixelSize; // Max. available lines in the area
        int currentLine = 1; // Starting line

        string[] words = sentence.Split(' '); // Splitting words from the sentence. words[1] = volutpa, words[2] = commodo, words[3] = diam

        // Length of the words
        for (int i = 0; i < words.Length; i++)
        {
            Console.WriteLine("Word " + i + " length: " + words[i].Length * pixelSize);
        }

        Console.ReadLine();
    }

Я сделал это сейчас, но не могу понять, как продолжить. Буду признателен за некоторые советы и идеи.

1 Ответ

0 голосов
/ 06 марта 2020

Вот мое окончательное решение на основе вашего обновленного вопроса. пожалуйста, прочитайте комментарии внутри кода.

ОБНОВЛЕНИЕ внутри fixtoFitMatrix() пробел метода будет учитываться только между 2 словами.

ОБНОВЛЕНИЕ 2 прочитайте комментарий 1, комментарий 2 и комментарий 3 внутри кода.

namespace ConsoleApplication29
{
    class Program
    {
        private static void Main(string[] args)
        {

            Check("volutpa commodo diam", 100, 20);
            Check("dio volutpa diam", 100, 20);
            Check("dio tuo diam", 55, 25);
            Check("tuo volutpa", 20, 6);
            Check("volutpa", 23, 2);
            Check("diam tu diam op comodo", 10, 20);
            Check("volutpas di diam e commodo", 65, 65);
            Check("diamo volutpasoni onedo commodoso", 10, 40);
            Console.ReadLine();
        }

        private static void Check(string txt,int w,int h)
        {
            String sentence = txt;
            int width = w;
            int height = h;

            string[] words = sentence.Split(' '); 

            int maxLines;
            int pixelSize = GetPixelSize(words, height, width,out maxLines);

            Console.WriteLine(sentence);
            // length of the words
            for (int i = 0; i < words.Length; i++)
            {               
                Console.WriteLine("Word " + i + " length: " + words[i].Length * pixelSize );
            }

            Console.WriteLine("pixel size will be " + pixelSize + " lines: " + maxLines );
            Console.WriteLine("--------------------------------------------");
        }

        private static int GetPixelSize(string[] words, int height, int width,out int maxlines)
        {
            int lines = 1;
            int basepx = GetBasePixelSize(words, height, width,1,ref lines);

            // fix if not each line is fitted to width or the height of the matrix
            int finalpx = fixtoFitMatrix(basepx,words,width,height,lines);
            maxlines = lines;
            return finalpx;
        }

        private static int fixtoFitMatrix(int basepx, string[] words,int width,int height,int lines)
        {
            List<LedLine> ldlines = new List<LedLine>();
            int currentline = 0;
            // set text for each line
            LedLine l = new LedLine() { LineNumber = currentline, LineText = words[0]};
            ldlines.Add(l);
            for (int i = 1;i< words.Length;i++)
            {
                var currentstring = words[i];

                if (ldlines[currentline].Len * basepx + basepx + currentstring.Length * basepx <= width)
                {
                    // add to current line
                    ldlines[currentline].LineText = ldlines[currentline].LineText + currentstring;
                }
                else
                {
                    // it is a new line
                    currentline++;
                    LedLine newl = new LedLine() { LineNumber = currentline, LineText = currentstring };
                    ldlines.Add(newl);
                }
            }
            // px size is also a function of the width
            // for example:
            // on surface of 100X20 volutpa commodo diam will be 8px and dio volutpa diam will be 9px
            // that happens because commodo diam is the length of 12 and 12*9=108 and the width is only 100 so we will need to fix
            //fix will be chcked if the number of lines requeired is not the same in ldlines.count that means that we will need to "shrink" px by 1 every recursive call
            if (ldlines.Count > lines)
            {
                return fixtoFitMatrix(basepx - 1, words, width,height, lines);
            }
            // comment 1: we need to check the height also
            else if (lines * basepx > height)
            {
                return fixtoFitMatrix(basepx - 1, words, width, height, lines);
            }
            return basepx;
        }

        private static int GetBasePixelSize(string[] words, int height,int width,int linesneeded,ref int finalnumberoflines,int specialH = 0)
        {
            int h = (int)Math.Ceiling(((double)height / (double)linesneeded));
            if (specialH > 0)
                h = specialH;

            var lines = linesneeded;
            var accumulate = 0;

            for (int i = 0;i< words.Length;i++)
            {
                accumulate += words[i].Length * h;
                // add space if it is not the last word
                if (i < words.Length - 1)
                {
                    accumulate += h;
                }

                // more line needed - call recursivaly until we get the number of lines needed
                if (accumulate / lines > width)
                {
                    return GetBasePixelSize(words, height, width, linesneeded+1,ref finalnumberoflines,specialH);
                }
            }
            finalnumberoflines = lines;


            // comment 2 - special case - if there is a single word that is larger than all px (int h) we will decrease h, for example on matrix of 10*20 the word 'comodo'
            // can be displayed only when h=1 because if its 2 then 2* 6 = 12
            // we will strat all over again with the new size
            if (words.Any(x => x.Length * h > width))
            {
                string specialword = words.Where(x => x.Length * h > width).FirstOrDefault();
                // decrease h by the equation X = height/word.length, if the result is under 1 its not possible to do that
                h = (int)Math.Floor((double)width/ (double)specialword.Length);
                // comment 3 - if h = 0 exit the method and return 0 - it is not possible with the given conditions 
                // (for example matrix of 10X40 with the sentence 'diamo volutpasoni onedo commodoso' is not possible)
                if (h == 0)
                    return 0;

                finalnumberoflines = 1;
                return GetBasePixelSize(words, height, width, 1, ref finalnumberoflines,h);
            }

            return h;
        }
    }

    public class LedLine
    {
        public int LineNumber { get; set; }
        public string LineText { get; set; }
        public int Len
        {
            get
            {
                return LineText.Length;
            }
        }
    }
}

ВЫХОД:

volutpa commodo diam Длина слова 0: 56 Длина слова 1: 56 Длина слова 2: 32 размер пикселя составит 8 строк: 2 -------------------------------------------- дио волутпа диам Длина слова 0: 27 Длина слова 1: 63 Длина слова 2: 36 размер пикселя будет 9 строк: 2 -------------------------------------------- дио туо диам Длина слова 0: 24 Длина слова 1: 24 Длина слова 2: 32 размер пикселя будет 8 строк: 3 -------------------------------------------- Tuo Volutpa Длина слова 0: 6 Длина слова 1: 14 размер пикселя будет 2 строки: 2 -------------------------------------------- volutpa Длина слова 0: 14 размер пикселя будет 2 строки: 1 -------------------------------------------- диам ту диам оп комодо Длина слова 0: 4 Длина слова 1: 2 Длина слова 2: 4 Длина слова 3: 2 Длина слова 4: 6 размер пикселя будет 1 строки: 3 -------------------------------------------- Volutpas Di Diam E Commodo Длина слова 0: 64 Длина слова 1: 16 Длина слова 2: 32 Длина слова 3: 8 Длина слова 4: 56 размер пикселя составит 8 строк: 4 -------------------------------------------- Diamo Volutpasoni Onedo Commodoso Длина слова 0: 0 Длина слова 1: 0 Длина слова 2: 0 Длина слова 3: 0 размер пикселя будет 0 строк: 7 --------------------------------------------

...