В эскизе КОМПАСа некорректно располагается размерный текст Во вложении скриншоты: dimwin - как должен располагаться размерный текст dimlin - как он располагается при работе под wine
Created attachment 916 [details] скриншот
Created attachment 917 [details] скриншот
вероятно, неправильно работает WorldTransform. Добавил тест. Текст в тесте вращается курсорными клавишами (влево-вправо).
Created attachment 982 [details] архив с тестом
Да, SetWorldTransform действительно работает странно. Такое ощущение, что в зависимости от угла поворота меняется что угодно - фон текста, ширина и размер символов, положение строки, наличие её на экране и даже буквы в тексте! :) Не понимаю пока, как такое может быть, но это явно не нарушение восприятия :)
Created attachment 983 [details] Скриншот теста в windows и в wine Всё-таки перестал игнорировать GM_ADVANCED в вайновской функции - и сразу появилась стабильность (неправильных) результатов. Вот скриншоты повёрнутого на один угол текста в Windows и в Wine - Очень похоже на нашу 2999 багу (по углу расхождения).
Created attachment 984 [details] тест (Etersoft edition) Тест хоть и кривоват, но простой до невозможности. Не придумывая ничего нового используем формулы поворота из начального теста, взяв за основу программы наш WinAPISkel.
Ещё, из обычных наблюдений по тесту: угол наклона строки зависит от _модуля_ угла поворота, то есть строка при -40 и при 40 повёрнута и отрисована одинаково. Отличия - в стартовой точке, откуда рисуется строка.
Created attachment 985 [details] тест (Etersoft edition) Test with makefile and recources
Отрисовка прямоугольника тоже неправильна, но это связано с тем, что функция рисования прямоугольника не умеет поворачивать его в соответствии с матрицей преобразования. Текст, выводимый TextOut'ом поворачивается, но не правильно. Считаем матрицы...
проверил умножение матриц в 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
в функции 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.
При отключении в X11DRV_XRender_ExtTextOut возможности невыполнения условия if(!lpDx) то есть делаем if (!lpDx) получаем корректное отображение, но с неверным (как будто по модулю) углом наклона.
> в 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'ом надо посмотреть какой в этом смысл
Обнаружил, что если трейсить 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 на предмет запуска их в случае повторного пересчета.
> Чтобы понять в каком месте искать условие > при котором не происходит такой > последовательности вызовов, нужно > потрейсить UploadGlyph и GetGlyphOutlineW на предмет > запуска их в случае повторного пересчета. По дебаглогам у меня получается, что при повторном пересчете (когда X11DRV_XRender_ExtTextOut считает, что совершенно новый угол это старый, хранящийся в кеше) не происходит вызова UploadGlyph непосредственно из X11DRV_XRender_ExtTextOut. Получается, что UploadGlyph не вызывается, когда она должна быть вызвана. Т. е. теперь необходимо найти вызов UploadGlyph в теле X11DRV_XRender_ExtTextOut и посмотреть при каких условиях он работает, а при каких нет.
Ошибка происходила из-за кэширования в функции 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)
Итак, проблема в повороте зелёного текста состояла в неверном преобразовании матрицы worldtransform (был неверный знак поворота). Поворачивался он через SetWorldTransform. Исправление в сборке eter39
Created attachment 989 [details] Отображение после исправлений Чем ближе мы приближаем надпись, тем более совпадают буквы. Очевидно, у чёрной буквы неверно вычисляется ширина. Поскольку после наших исправлений отрисовка чёрной буквы не изменилась, делаем вывод, что она выводится без использования SetWorldTransofrm, в отличие от зелёной.
Надписи, поворачивающиеся с использованием SetWorldTransform, отображаются корректно.
Проблема была в противоположном градусе поворота при использовании 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);
Исправлено не до конца. Сервис - Параметры - Система - Редактор моделей - Размеры и обозначения - выключить Оптимизировать отображение - Ок. При повороте плоскости эскиза (например, зажав среднюю кнопку мыши) размерный текст трансформируется неправильно. Его плоскость как бы пересекает плоскость эскиза. См. прилагаемый скриншот.
Created attachment 990 [details] Скриншот с развернутой плоскостью эскиза
Для определения причин неправильной трансформации как бы в 3D режиме нужно видеть код, или тест от АСКОНа, показывающий проблему.
Как выяснилось, чёрный текст и зелёный выводятся принципиально разными способами, это видно даже по форме букв (чёрный, через GL, имеет незакруглённые углы, видно что он построен другими сплайнами).
Created attachment 996 [details] Разворот подсветки текста условного обозначения
ROTATE по SetWorldTransform выполняется корректно. Есть ли уверенность ,что корректно выполняются остальные возможные преобразования (SCALE, SHEAR и т.д.)?
Проверил Scaling, Shear и Reflection - работает корректно, идентично Windows.
Запросил у программистов уточненный тест. Как будет готов приложу сюда.
Пока считаем приостановленной...
Created attachment 1057 [details] тест SetWorldTransform тест
добавлен тест SetWorldTransform. После запуска курсорными клавишами влево-вправо вызывается трансформация текстов. В правой колонке трансформация выполняется наоборот (верхняя меняется с нижней) по отношению к тому, как это происходит под windows.
Воспроизводится моим тестом из репозитория 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-преобразовании
Путаница с горизонтальным и вертикальным преобразованиями вносится моим же декабрьским патчем. Видимо, Тимошков изменил где-то код так, что его первоначальные строки стали более актуальны, а мой патч - неправильным. Свой патч откатил. Теперь есть проблема с направлением преобразования. Для идентичности Windows поменял знаки коэввициентов M12 и M21. Патч в рассылке.
На приложенном к баге тесте поведение соответствует поведению теста в Windows.
(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) Кажется, неправильное поведение кэша уже исправлено Тимошковым.
Принято WINE@Etersoft CAD eter2.1/eter2 Тест одинаково себя ведет на Windows и Linux