Bug 3101

Summary: В эскизе КОМПАСа некорректно располагается размерный текст
Product: [Поддержка проектов] КОМПАС 3D Reporter: Виталий Булгаков <bulgakov>
Component: ТестированиеAssignee: Константин Кондратюк <kondratyuk>
Status: CLOSED FIXED QA Contact: Денис Баранов <baraka>
Severity: critical    
Priority: P2 CC: kondratyuk, lav, mais, mibori, mx
Version: v10   
Target Milestone: ---   
Hardware: PC   
OS: All   
Whiteboard:
Заявки RT: Связано с:
Дата напоминания:
Bug Depends on:    
Bug Blocks: 753, 1733, 2608, 3106, 4039    
Attachments: скриншот
скриншот
архив с тестом
Скриншот теста в windows и в wine
тест (Etersoft edition)
тест (Etersoft edition)
Отображение после исправлений
Скриншот с развернутой плоскостью эскиза
Разворот подсветки текста условного обозначения
тест SetWorldTransform

Description Виталий Булгаков 2008-11-24 13:58:09 MSK
В эскизе КОМПАСа некорректно располагается размерный текст
Во вложении скриншоты:
dimwin - как должен располагаться размерный текст
dimlin - как он располагается при работе под wine
Comment 1 Виталий Булгаков 2008-11-24 13:59:00 MSK
Created attachment 916 [details]
скриншот
Comment 2 Виталий Булгаков 2008-11-24 14:02:37 MSK
Created attachment 917 [details]
скриншот
Comment 3 Виталий Булгаков 2008-12-22 18:26:30 MSK
вероятно, неправильно работает WorldTransform. Добавил тест. Текст в тесте вращается курсорными клавишами (влево-вправо).
Comment 4 Виталий Булгаков 2008-12-22 18:27:24 MSK
Created attachment 982 [details]
архив с тестом
Comment 5 Константин Кондратюк 2008-12-23 02:15:35 MSK
Да, SetWorldTransform действительно работает странно. Такое ощущение, что в зависимости от угла поворота меняется что угодно - фон текста, ширина и размер символов, положение строки, наличие её на экране и даже буквы в тексте! :)

Не понимаю пока, как такое может быть, но это явно не нарушение восприятия :)
Comment 6 Константин Кондратюк 2008-12-23 02:51:17 MSK
Created attachment 983 [details]
Скриншот теста в windows и в wine

Всё-таки перестал игнорировать GM_ADVANCED в вайновской функции - и сразу появилась стабильность (неправильных) результатов.
Вот скриншоты повёрнутого на один угол текста в Windows и в Wine - Очень похоже на нашу 2999 багу (по углу расхождения).
Comment 7 Константин Кондратюк 2008-12-23 03:01:43 MSK
Created attachment 984 [details]
тест (Etersoft edition)

Тест хоть и кривоват, но простой до невозможности. Не придумывая ничего нового используем формулы поворота из начального теста, взяв за основу программы наш WinAPISkel.
Comment 8 Константин Кондратюк 2008-12-23 03:27:54 MSK
Ещё, из обычных наблюдений по тесту: угол наклона строки зависит от _модуля_ угла поворота, то есть строка при -40 и при 40 повёрнута и отрисована одинаково.
Отличия - в стартовой точке, откуда рисуется строка.
Comment 9 Константин Кондратюк 2008-12-23 12:55:39 MSK
Created attachment 985 [details]
тест (Etersoft edition)

Test with makefile and recources
Comment 10 Константин Кондратюк 2008-12-23 15:32:05 MSK
Отрисовка прямоугольника тоже неправильна, но это связано с тем, что функция рисования прямоугольника не умеет поворачивать его в соответствии с матрицей преобразования.
Текст, выводимый TextOut'ом поворачивается, но не правильно. Считаем матрицы...
Comment 11 Anton Rudnev 2008-12-23 15:41:34 MSK
проверил умножение матриц в CombineTransform
оно в точности соответствует опеределению 

       C = A x B

A = ||aij||, i = 1..m, j = 1..n
B = ||bij||, i = 1..n, j = 1..p
C = ||cij||, i = 1..m, j = 1..p

cij = sum(k = 1..n) (aik * bkj)

с учетом, что 

(a13, a23, b13, b23) = 0
(a33, b33) = 1
Comment 12 Anton Rudnev 2008-12-23 17:12:11 MSK
в функции BOOL DC_InvertXform
производится вычисление преобразования, обратного тому, что передается в SetWorldTransform

я не нашел формулу обратного преобразования

в функции преобразование ведется по такому алгориму:

для преобразования A обратное к нему будет являться A' , где A = ||aij||, A'=||a'ij||, при (a13, a23, a'13, a'23) = 0 и (a33, a'33) = 1

det A = a11 * a22 - a12 * a21

a'11 = a22 / det A;      a'12 = - a12 / det A
a'12 = - a21 / det A;    a'22 = a11 / det A

a'31 = - a31 * a11 - a32 * a21 
a'32 = - a31 * a12 - a32 * a22

можно считать, что верно, т.к. это соответствует, тому что я прочитал в книжке по линейной алгебре (если бы мы имели зависимость реальных координат (x, y) от преобразованных (x', y') через матрицу их преобразования A):

x = x' * a22 / det A - y' * a12 / det A - (a13 * a12 - a23 * a22) / det A
y = - x' * a21 / det A + y' * a11 / det A - (a11 * a22 - a21 * a13) / det A

верность показывают коэффициэнты при 1/det A

пока нужно отложить разбор SetWorldTransform, и копать TextOut.
Comment 13 Vitaly Lipatov 2008-12-24 04:53:48 MSK
При отключении в X11DRV_XRender_ExtTextOut
возможности невыполнения условия
            if(!lpDx)
то есть делаем
if (!lpDx)
получаем корректное отображение, но с неверным (как будто по модулю) углом наклона.
Comment 14 Anton Rudnev 2008-12-24 16:50:59 MSK
> в X11DRV_XRender_ExtTextOut

заметил, что при каждом повороте на один TextOut  (тот самый, который отрисовывает надпись под наклоном), X11DRV_XRender_ExtTextOut вызывается дважды:

theta = 0.00 ->
X11DRV_XRender_ExtTextOut(..., x=0, y=0, flags=2, lprect{left=150, top=150, right=237, bottom=168}, {(null)}, lpDx=0)
X11DRV_XRender_ExtTextOut(..., x=150, y=165, flags=4112, lprect{left=4210809, top=12, right=1219208, bottom=12}, {L"7H[W5RWDWLRQ"}, lpDx=0)
theta = -15.00 ->
X11DRV_XRender_ExtTextOut(..., x=0, y=0, flags=2, lprect{left=150, top=150, right=231, bottom=167}, {(null)}, lpDx=0)
X11DRV_XRender_ExtTextOut(..., x=150, y=164, flags=4112, lprect{left=4210809, top=12, right=1224376, bottom=12}, {L"7H[W5RWDWLRQ"}, lpDx=0)
theta = -30.00 ->
X11DRV_XRender_ExtTextOut(..., x=0, y=0, flags=2, lprect{left=150, top=150, right=210, bottom=163}, {(null)}, lpDx=0)
X11DRV_XRender_ExtTextOut(..., x=150, y=160, flags=4112, lprect{left=4210809, top=12, right=1231952, bottom=12}, {L"7H[W5RWDWLRQ"}, lpDx=0)
...

вывод строчки theta = ... -> в консоль и предворяет каждую отрисовку TextOut'ом
надо посмотреть какой в этом смысл





Comment 15 Anton Rudnev 2008-12-24 20:05:53 MSK
Обнаружил, что если трейсить WineEngGetGlyphOutline
то, например, при +15 градусах происходит некоторый пересчет (вызов WineEngGetGlyphOutline) инициируемый функцией X11DRV_XRender_ExtTextOut

затем, при -15 градусах такого пересчета не происходит.

Если упасть в момент этого пересчета, то получаем следующий бэктрейс:
Backtrace:

=>0 0x7ebb5f49 WineEngGetGlyphOutline+0x192(incoming_font=0x129b60, glyph=55, format=255, lpgm=0x66f220, buflen=0, buf=(nil), lpmat=(nil)) [/srv/mibori/Projects/wine/dlls/gdi32/freetype.c:4417] in gdi32 (0x0066f148)
  1 0x7eba5a45 GetGlyphOutlineW+0xf1(hdc=0x1e4, uChar=55, fuFormat=255, lpgm=0x66f220, cbBuffer=0, lpBuffer=(nil), lpmat2=(nil)) [/srv/mibori/Projects/wine/dlls/gdi32/font.c:2398] in gdi32 (0x0066f198)
  2 0x7e80af3f UploadGlyph+0x12f(physDev=0x127790, glyph=55, format=AA_Grey) [/srv/mibori/Projects/wine/dlls/winex11.drv/xrender.c:627] in winex11 (0x0066f3e8)
  3 0x7e80cc91 X11DRV_XRender_ExtTextOut+0x746(physDev=0x127790, x=150, y=164, flags=4112, lprect=0x66f9a8, wstr=0x12aef8, count=12, lpDx=(nil)) [/srv/mibori/Projects/wine/dlls/winex11.drv/xrender.c:1266] in winex11 (0x0066f6f8)
  4 0x7e7ec2e8 X11DRV_ExtTextOut+0x80(physDev=0x127790, x=150, y=164, flags=4112, lprect=0x66f9a8, wstr=0x12aef8, count=12, lpDx=(nil)) [/home/mibori/Projects/wine/dlls/winex11.drv/text.c:55] in winex11 (0x0066f7e8)
  5 0x7eba445d ExtTextOutW+0x1757(hdc=0x1e4, x=150, y=164, flags=4112, lprect=(nil), str=0x12aeb8, count=12, lpDx=(nil)) [/srv/mibori/Projects/wine/dlls/gdi32/font.c:1994] in gdi32 (0x0066fa88)
  6 0x7eba2cac ExtTextOutA+0x1c7(hdc=0x1e4, x=0, y=0, flags=0, lprect=(nil), str="TextRotation", count=12, lpDx=(nil)) [/srv/mibori/Projects/wine/dlls/gdi32/font.c:1609] in gdi32 (0x0066fae8)
  7 0x7eba510e TextOutA+0x51(hdc=0x1e4, x=0, y=0, str="TextRotation", count=12) [/srv/mibori/Projects/wine/dlls/gdi32/font.c:2125] in gdi32 (0x0066fb18)
  8 0x004017f9 in main (+0x17f9) (0x0066fc38)
  9 0x0040151f in main (+0x151f) (0x0066fc68)
  10 0x7e9392be WINPROC_wrapper+0x1a() in user32 (0x0066fc98)
  11 0x7e939962 call_window_proc+0xca(hwnd=0x10028, msg=15, wp=0, lp=0, result=0x66fd78, arg=0x4014a4) [/home/mibori/Projects/wine/dlls/user32/winproc.c:461] in user32 (0x0066fce8)
  12 0x7e93ff56 WINPROC_call_window+0x1db(hwnd=0x10028, msg=15, wParam=0, lParam=0, result=0x66fd78, unicode=0, mapping=WMCHAR_MAP_DISPATCHMESSAGE) [/home/mibori/Projects/wine/dlls/user32/winproc.c:2215] in user32 (0x0066fd38)
  13 0x7e8fa362 DispatchMessageA+0x103(msg=0x66fdd0) [/home/mibori/Projects/wine/dlls/user32/message.c:3062] in user32 (0x0066fd88)
  14 0x00401482 in main (+0x1482) (0x0066fe38)
  15 0x004019b4 in main (+0x19b4) (0x0066feb8)
  16 0x0040122f in main (+0x122f) (0x0066fee8)
  17 0x00401275 in main (+0x1275) (0x0066fef8)
  18 0x7b880891 start_process+0xe4(arg=(nil)) [/home/mibori/Projects/wine/dlls/kernel32/process.c:912] in kernel32 (0x0066ffe8)
  19 0xb7eb1cc7 wine_switch_to_stack+0x17() in libwine.so.1 (0x00000000)


Получается, что при несохраненном в кеш значении, происходит вложенные вызовы X11DRV_XRender_ExtTextOut{UploadGlyph{GetGlyphOutlineW{WineEngGetGlyphOutline(падение при +15 градусах)}}}

а при сохраненном (по мнению функции X11DRV_XRender_ExtTextOut), таких вызовов не происходят.

Чтобы понять в каком месте искать условие при котором не происходит такой последовательности вызовов, нужно потрейсить UploadGlyph и GetGlyphOutlineW на предмет запуска их в случае повторного пересчета.
Comment 16 Anton Rudnev 2008-12-24 20:36:25 MSK
> Чтобы понять в каком месте искать условие
> при котором не происходит такой
> последовательности вызовов, нужно
> потрейсить UploadGlyph и GetGlyphOutlineW на предмет
> запуска их в случае повторного пересчета.

По дебаглогам у меня получается, что при повторном пересчете (когда X11DRV_XRender_ExtTextOut считает, что совершенно новый угол это старый, хранящийся в кеше) не происходит вызова UploadGlyph непосредственно из X11DRV_XRender_ExtTextOut.

Получается, что UploadGlyph не вызывается, когда она должна быть вызвана.

Т. е. теперь необходимо найти вызов UploadGlyph в теле X11DRV_XRender_ExtTextOut и посмотреть при каких условиях он работает, а при каких нет.
Comment 17 Vitaly Lipatov 2008-12-25 12:51:17 MSK
Ошибка происходила из-за кэширования в функции UploadGlyph
(при сравнении formatEntry->realized[wstr[idx]] == FALSE).
Временно исправлено, далее нужно улучшить сравнение при выборке из кэша.

commit 8702aa58bad421bbcfbc5c76d46d63a7e7992c50
Author: Vitaly Lipatov <lav@etersoft.ru>
Date:   Thu Dec 25 12:49:59 2008 +0300

    disable glyph cache for non 1C application (see eterbug #3101)
Comment 18 Vitaly Lipatov 2008-12-25 15:07:54 MSK
Итак, проблема в повороте зелёного текста состояла в неверном преобразовании матрицы worldtransform (был неверный знак поворота). Поворачивался он через SetWorldTransform.

Исправление в сборке eter39
Comment 19 Vitaly Lipatov 2008-12-25 15:12:16 MSK
Created attachment 989 [details]
Отображение после исправлений

Чем ближе мы приближаем надпись, тем более совпадают буквы. Очевидно, у чёрной буквы неверно вычисляется ширина.
Поскольку после наших исправлений отрисовка чёрной буквы не изменилась, делаем вывод, что она выводится без использования SetWorldTransofrm, в отличие от зелёной.
Comment 20 Константин Кондратюк 2008-12-25 15:27:55 MSK
Надписи, поворачивающиеся с использованием SetWorldTransform, отображаются корректно.
Comment 21 Vitaly Lipatov 2008-12-25 15:31:09 MSK
Проблема была в противоположном градусе поворота при использовании SetWorldTransorm. Исправили.

commit fa26aeee5c6d8a40b881d5a778e3670f04f407cb
Author: Konstantin Kondratyuk <kondratyuk@etersoft.ru>
Date:   Thu Dec 25 13:23:08 2008 +0300

    gdi32: correct order of transformation matrix elements

diff --git a/dlls/gdi32/freetype.c b/dlls/gdi32/freetype.c
index 5a48c33..a0c3eb1 100644
--- a/dlls/gdi32/freetype.c
+++ b/dlls/gdi32/freetype.c
@@ -4468,8 +4468,8 @@ DWORD WineEngGetGlyphOutline(GdiFont *incoming_font, UINT glyph, UINT format,
     {
         FT_Matrix worldMat;
         worldMat.xx = FT_FixedFromFloat(font->font_desc.matrix.eM11);
-        worldMat.xy = FT_FixedFromFloat(font->font_desc.matrix.eM21);
-        worldMat.yx = FT_FixedFromFloat(font->font_desc.matrix.eM12);
+        worldMat.xy = FT_FixedFromFloat(font->font_desc.matrix.eM12);
+        worldMat.yx = FT_FixedFromFloat(font->font_desc.matrix.eM21);
         worldMat.yy = FT_FixedFromFloat(font->font_desc.matrix.eM22);
Comment 22 Виталий Булгаков 2008-12-25 18:06:28 MSK
Исправлено не до конца. Сервис - Параметры - Система  - Редактор моделей - Размеры и обозначения - выключить Оптимизировать отображение - Ок. При повороте плоскости эскиза (например, зажав среднюю кнопку мыши) размерный текст трансформируется неправильно. Его плоскость как бы пересекает плоскость эскиза. См. прилагаемый скриншот.
Comment 23 Виталий Булгаков 2008-12-25 18:07:18 MSK
Created attachment 990 [details]
Скриншот с развернутой плоскостью эскиза
Comment 24 Vitaly Lipatov 2008-12-25 22:31:43 MSK
Для определения причин неправильной трансформации как бы в 3D режиме нужно видеть код, или тест от АСКОНа, показывающий проблему.
Comment 25 Vitaly Lipatov 2008-12-25 22:33:01 MSK
Как выяснилось, чёрный текст и зелёный выводятся принципиально разными способами, это видно даже по форме букв (чёрный, через GL, имеет незакруглённые углы, видно что он построен другими сплайнами).
Comment 26 Виталий Булгаков 2008-12-26 11:51:43 MSK
Created attachment 996 [details]
Разворот подсветки текста условного обозначения
Comment 27 Виталий Булгаков 2008-12-26 11:54:30 MSK
ROTATE по SetWorldTransform выполняется корректно. Есть ли уверенность ,что корректно выполняются остальные возможные преобразования (SCALE, SHEAR и т.д.)?
Comment 28 Константин Кондратюк 2008-12-26 13:56:27 MSK
Проверил Scaling, Shear и Reflection - работает корректно, идентично Windows.
Comment 29 Виталий Булгаков 2008-12-26 15:49:20 MSK
Запросил у программистов уточненный тест. Как будет готов приложу сюда.
Comment 30 Константин Кондратюк 2009-01-15 12:05:20 MSK
Пока считаем приостановленной...
Comment 31 Виталий Булгаков 2009-02-10 15:40:13 MSK
Created attachment 1057 [details]
тест SetWorldTransform

тест
Comment 32 Виталий Булгаков 2009-02-10 15:47:03 MSK
добавлен тест SetWorldTransform. После запуска курсорными клавишами влево-вправо вызывается трансформация текстов. В правой колонке трансформация выполняется наоборот (верхняя меняется с нижней) по отношению к тому, как это происходит под windows.
Comment 33 Константин Кондратюк 2009-04-15 13:14:29 MSD
Воспроизводится моим тестом из репозитория wine-etersoft-devel: gdi/setworldtransform/textshear.*

Опытным путём установлено, что разницу в выполнении дают преобразования, выполняемые в функции WineEngGetGlyphOutline (блок помечен комментарием "World transform")


Поведение становится идентичным Windows, если в матрицу преобразования внести такие изменения:
--- a/dlls/gdi32/freetype.c
+++ b/dlls/gdi32/freetype.c
@@ -4517,8 +4517,8 @@ DWORD WineEngGetGlyphOutline(GdiFont *incoming_font, UINT glyph, UINT format,
     {
         FT_Matrix worldMat;
         worldMat.xx = FT_FixedFromFloat(font->font_desc.matrix.eM11);
-        worldMat.xy = FT_FixedFromFloat(font->font_desc.matrix.eM12);
-        worldMat.yx = FT_FixedFromFloat(font->font_desc.matrix.eM21);
+        worldMat.xy = FT_FixedFromFloat(-font->font_desc.matrix.eM21);
+        worldMat.yx = FT_FixedFromFloat(-font->font_desc.matrix.eM12);
         worldMat.yy = FT_FixedFromFloat(font->font_desc.matrix.eM22);
         pFT_Matrix_Multiply(&worldMat, &transMat);
         pFT_Matrix_Multiply(&worldMat, &transMatUnrotated);

Проверил Rotation и Scaling/Reflection - с ними всё в порядке, да и не может ничего в них сломаться, потому что изменённая пара коэффициентов участвует только в shear-преобразовании
Comment 34 Константин Кондратюк 2009-04-15 13:46:29 MSD
Путаница с горизонтальным и вертикальным преобразованиями вносится моим же декабрьским патчем. Видимо, Тимошков изменил где-то код так, что его первоначальные строки стали более актуальны, а мой патч - неправильным.
Свой патч откатил.

Теперь есть проблема с направлением преобразования. Для идентичности Windows поменял знаки коэввициентов M12 и M21. Патч в рассылке.
Comment 35 Константин Кондратюк 2009-04-15 15:26:17 MSD
На приложенном к баге тесте поведение соответствует поведению теста в Windows.
Comment 36 Константин Кондратюк 2009-06-29 12:33:45 MSD
(In reply to comment #17)
> Ошибка происходила из-за кэширования в
> функции UploadGlyph
> (при сравнении formatEntry->realized[wstr[idx]] == FALSE).
> Временно исправлено, далее нужно улучшить
> сравнение при выборке из кэша.
> 
> commit 8702aa58bad421bbcfbc5c76d46d63a7e7992c50
> Author: Vitaly Lipatov <lav@etersoft.ru>
> Date:   Thu Dec 25 12:49:59 2008 +0300
> 
>     disable glyph cache for non 1C application (see eterbug #3101)
> 

Откачен, так как ломает работу Консультанта (#4039)
Кажется, неправильное поведение кэша уже исправлено Тимошковым.
Comment 37 Денис Баранов 2009-07-29 20:59:16 MSD
Принято
WINE@Etersoft CAD eter2.1/eter2
Тест одинаково себя ведет на Windows и Linux