Най-добрият начин за изчисляване на индекса на знак в низ, даден от отместването на пиксела

Свързан въпрос: Получаване на индекс на низ въз основа на отместване на пиксел

Знам, че това е близо до този въпрос, но това не е въпросът как да го направите директно, а въпросът как да го фалшифицирате най-добре.


Внедрявам свое собствено текстово поле за Windows Forms (защото RichTextBox е гадно) и се опитвам да намеря най-добрия начин да изчисля над кой знак е мишката, като се имат предвид низове, които са начертани на екрана. Проблемът е, че знаците могат да бъдат с променлива ширина.

Измислих две възможности:

  1. Направете Graphics.MeasureCharacterRange всеки път, когато мишката се движи по начин на двоично търсене на реда, над който е мишката (както е предложено във въпроса, свързан в горната част)

  2. Съхранявайте списък с отместването на всеки знак от всеки ред.

(1) Ще има лошо представяне и

(2) ще бъде неефективно за паметта плюс ще направи въвеждането на символ O(n) операция (защото трябва да коригирате отместването на всеки знак след него) плюс невъзможно да се направи точно защото Graphics.MeasureCharacterRange е' t прецизен (връща една стойност за един символ, друга стойност за друг знак и напълно различна стойност [която не е равна на двете предишни стойности, събрани заедно] за двете заедно в един низ. Например W ще бъде широк 16 пиксела и f ще бъде широк 5 пиксела, но Wf е широк 20 пиксела. Тези числа са от действителен тест.).

Така че търся по-добра стратегия за това, за предпочитане такава, която изисква минимално пространство и O(1) изчислителна сложност (въпреки че с удоволствие ще заменя малко ефективност на паметта за ефективност на скоростта).


person Seth Carnegie    schedule 09.09.2011    source източник
comment
трябва ли да запазите текста в текстовото поле или можете да използвате алтернативен контейнер, като div?   -  person Kris Ivanov    schedule 09.09.2011
comment
@Kris какво е div? Използвам winforms, а не HTML. Извинете ме, ако има такова нещо в winforms, никога не съм го чувал.   -  person Seth Carnegie    schedule 09.09.2011
comment
Дори не звучи като HTML въпрос, дали е WinForms въпроси?   -  person Erik Philips    schedule 09.09.2011
comment
Зла преждевременна оптимизация. Мишката се движи от човек.   -  person Hans Passant    schedule 09.09.2011
comment
добре, ти редактирахте въпроса, за да имате маркера winform и допълнителния текст за Windows Forms (защото RichTextBox е гаден), може би следващия път ще добавите това в първоначалния въпрос и моля, не звучи така, сякаш съм прочел погрешно въпроса   -  person Kris Ivanov    schedule 09.09.2011
comment
@Kris, да, редактирах го, за да стане по-ясно. Но не знаех, че неща като Graphics.MeasureCharacterRange съществуват в HTML. Или че можете да използвате C# в HTML. И грешното прочитане на въпроса не е нещо ужасно, правя го през цялото време. съжалявам Няма нужда да гласувате против въпроса.   -  person Seth Carnegie    schedule 09.09.2011
comment
@Hans Не искам да решавам това и да създавам куп неща върху него и по-късно да трябва да го променя, защото е бавно, а след това да променям и всичко, изградено върху него. Това е проблемът, който имам с аргумента за преждевременна оптимизация.   -  person Seth Carnegie    schedule 09.09.2011
comment
Лошото в това е да се полагат усилия, без да се знае дали е необходимо. Измерете.   -  person Hans Passant    schedule 09.09.2011
comment
@Hans Разбирам какво имаш предвид, но може да е огромна загуба на време за нещо, което вероятно ще бъде бавно, е достатъчно, за да потърся друг начин.   -  person Seth Carnegie    schedule 09.09.2011


Отговори (1)


Не мисля, че трябва да правите O(1). O(1) предполага, че всеки допълнителен знак има ефект върху ВСИЧКИ предишни знаци, което не би било. В най-добрия случай бих видял O(1) за всяка дума, което трябва да е лудо бързо. Звучи сякаш това, от което се нуждаете, е начин за съхранение; 1 местоположението на всяка дума, 2 всяка уникална дума и 3 ширината на всяка буква в думата. Това значително ще намали съхранението и ще увеличи скоростта на търсене. Може би нещо като:

IEnumerable<TextLocation> TextLocations = ...;

internal class TextLocation
{
    public RectF BoundingBox { get; set; }  //this is relative to the textbox
    public TextWord TextWord { get; set; }
}

internal class TextWord
{
    public string Text { get; set; }
    public IEnumerable<LetterInfo> Letters { get; set; }
}

internal class LetterInfo
{
    public char Letter { get; set; }
    public float left { get; set; }  //these would be relative to the bounding box
    public float right { get; set; } //not to the textbox
}

Тогава може да успеете да направите нещо подобно

var tl = TextLocations.FirstOrDefault(x => x.BoundingBox.Left < Mouse.X 
                                           && x.BoundingBox.Right > Mouse.X
                                           && x.BoundingBox.Top < Mouse.Y
                                           && x.BoundingBox.Bottom > Mouse.Y)

if (tl != null)
{
    //tl.TextWord.Text is the Word ("The", "Lazy", "Dog"...)

    var letter = tl.TextWord.Letters
                   .FirstOrDefault(x => Mouse.x - tl.BoundingBox.left > x.left
                                        Mouse.x - tl.BoundingBox.left < x.right);

    if (letter != null)
    {
        // you get the idea
    }                              
}
person Erik Philips    schedule 09.09.2011
comment
Това така или иначе ще бъде O(n), защото трябва да преизчислите позицията на всяка дума след знака, който въвеждате на този ред. И не мога да съхранявам думи като разделени с интервали поради осветяването на синтаксиса. Благодаря все пак. - person Seth Carnegie; 09.09.2011
comment
Написах алгоритъм за печат за определяне на страници преди печат с помощта на Graphics.MeasureString и смятам, че проблемът беше да се уверя, че използваната графика има DPI, равен или по-голям от действителния сравним. Когато използвах монитор, използвах 300 DPI, а при печат използвах 1800 DPI, но само на MeasureString, не за реален печат. - person Erik Philips; 09.09.2011
comment
И така, това, което казвате, е, че всеки тип знак в текстово поле засяга ширината на ВСЕКИ един знак преди това? Знам, че не работи по този начин, не и за всеки шрифт. Единственото изключение би било, ако използвате странно подравняване (център) или пълно оправдаване (което не се поддържа автоматично). - person Erik Philips; 09.09.2011
comment
Не преди, а след това и то на същата линия. И не ширината, а отместването. Това приема за даденост, че моето текстово поле не прави пренасяне на редове, в който случай това ще засегне всеки знак след въведения, не само на същия ред, но и на всички редове след този, който е получил новия знак. - person Seth Carnegie; 09.09.2011
comment
Но чрез преизчисляване на думата, която е редактирана, вие знаете отместването, което да се приложи към всички думи на този ред. Нищо не трябва да се преизчислява, само TextLocation.BoundingBox.Left и `TextLocation.BoundingBox.Right' трябва да се актуализират с новото отместване. - person Erik Philips; 09.09.2011
comment
имам предвид, че трябва да преминете през всяка дума след тази, която сте въвели, и да добавите това отместване към тях. Това означава, че е O(n). Освен това, както казах, не мога да разделя текста на думи. - person Seth Carnegie; 09.09.2011