View Issue Details
| ID | Project | Category | View Status | Date Submitted | Last Update |
|---|---|---|---|---|---|
| 0003781 | SAS.Планета | Баг / Bug | public | 01-09-2021 19:44 | 06-09-2021 09:48 |
| Reporter | VadimK | Assigned To | zed | ||
| Priority | normal | Severity | minor | Reproducibility | always |
| Status | resolved | Resolution | fixed | ||
| Platform | Windows | OS | 7 | OS Version | Home Basic |
| Product Version | 201212 | ||||
| Target Version | 211230 | Fixed in Version | 211230 | ||
| Summary | 0003781: При выборе проекции "Geographic Lat/Lon" вылазит "Invalid Floatig Point Operation" | ||||
| Description | При выборе проекции "Geographic Lat/Lon" и дальнейшей работой с картой вылазит ошибка"Invalid Floatig Point Operation". Происходит это при малом масштабе, когда весь мир на экране (например самый-самый первый запуск программы), либо когда ползаешь по карте в верхних широтах 85+ Ошибка не пропадает, выскакивает постоянно, пока двигаешь мышью. В момент появления диалогового окошка мышка "прилипает" к полю карты и уползти обратно в "нижние" широты получается с трудом. Если закрыть программу в этот момент, то при следующем запуске она "теряет" карту (серое поле), которая выбрана. В меню Вид-Проекция остаётся только один вариант - "Оригинальная (из ZMP)". Вывести из ступора программу можно, удалив ini-файлы. | ||||
| Steps To Reproduce | Прилагаю архив с файлами (настройки), созданными программой. Этот набор файлов относится к состоянию ступора, в который программа впадает. Распаковать и закинуть в ночную сборку. | ||||
| Tags | No tags attached. | ||||
| Attached Files | 3781.diff (7,283 bytes)
diff --git a/Src/CoordConvert/u_ProjectionTypeBase.pas b/Src/CoordConvert/u_ProjectionTypeBase.pas
index 5d527a72c..6c5c34f70 100644
--- a/Src/CoordConvert/u_ProjectionTypeBase.pas
+++ b/Src/CoordConvert/u_ProjectionTypeBase.pas
@@ -47,7 +47,8 @@ type
protected
function Relative2LonLatInternal(const APoint: TDoublePoint): TDoublePoint; virtual; abstract;
function LonLat2RelativeInternal(const APoint: TDoublePoint): TDoublePoint; virtual; abstract;
- private
+ protected
+ { IProjectionType }
function GetHash: THashValue;
function GetDatum: IDatum;
function GetProjectionEPSG: Integer;
@@ -64,8 +65,8 @@ type
procedure ValidateRelativePos(var APoint: TDoublePoint);
procedure ValidateRelativeRect(var ARect: TDoubleRect);
- procedure ValidateLonLatPos(var APoint: TDoublePoint);
- procedure ValidateLonLatRect(var ARect: TDoubleRect);
+ procedure ValidateLonLatPos(var APoint: TDoublePoint); virtual;
+ procedure ValidateLonLatRect(var ARect: TDoubleRect); virtual;
function CheckRelativePos(const APoint: TDoublePoint): boolean;
function CheckRelativeRect(const ARect: TDoubleRect): boolean;
diff --git a/Src/CoordConvert/u_ProjectionTypeGELonLat.pas b/Src/CoordConvert/u_ProjectionTypeGELonLat.pas
index 9f3f373ba..e3136726d 100644
--- a/Src/CoordConvert/u_ProjectionTypeGELonLat.pas
+++ b/Src/CoordConvert/u_ProjectionTypeGELonLat.pas
@@ -24,9 +24,7 @@ unit u_ProjectionTypeGELonLat;
interface
uses
- t_Hash,
t_GeoTypes,
- i_Datum,
u_ProjectionTypeBase;
type
@@ -34,44 +32,60 @@ type
protected
function Relative2LonLatInternal(const APoint: TDoublePoint): TDoublePoint; override;
function LonLat2RelativeInternal(const APoint: TDoublePoint): TDoublePoint; override;
- public
- constructor Create(
- const AHash: THashValue;
- const ADatum: IDatum;
- const AProjEPSG: integer
- );
+ protected
+ procedure ValidateLonLatPos(var APoint: TDoublePoint); override;
+ procedure ValidateLonLatRect(var ARect: TDoubleRect); override;
end;
implementation
-uses
- Math;
+const
+ CMaxLatitude = 85.0511287798066;
{ TProjectionTypeGELonLat }
-constructor TProjectionTypeGELonLat.Create(
- const AHash: THashValue;
- const ADatum: IDatum;
- const AProjEPSG: integer
-);
-begin
- inherited Create(AHash, ADatum, AProjEPSG);
-end;
-
function TProjectionTypeGELonLat.LonLat2RelativeInternal(
const APoint: TDoublePoint
): TDoublePoint;
begin
- Result.x := (0.5 + APoint.x / 360);
- Result.y := (0.5 - APoint.y / 360);
+ Result.X := (0.5 + APoint.X / 360);
+ Result.Y := (0.5 - APoint.Y / 360);
end;
function TProjectionTypeGELonLat.Relative2LonLatInternal(
const APoint: TDoublePoint
): TDoublePoint;
begin
- Result.X := (APoint.x - 0.5) * 360;
- Result.y := -(APoint.y - 0.5) * 360;
+ Result.X := (APoint.X - 0.5) * 360;
+ Result.Y := -(APoint.Y - 0.5) * 360;
+end;
+
+procedure _ValidateLonLatPos(var APoint: TDoublePoint); inline;
+begin
+ if APoint.X < -180 then begin
+ APoint.X := -180;
+ end else
+ if APoint.X > 180 then begin
+ APoint.X := 180;
+ end;
+
+ if APoint.Y < -CMaxLatitude then begin
+ APoint.Y := -CMaxLatitude;
+ end else
+ if APoint.Y > CMaxLatitude then begin
+ APoint.Y := CMaxLatitude;
+ end;
+end;
+
+procedure TProjectionTypeGELonLat.ValidateLonLatPos(var APoint: TDoublePoint);
+begin
+ _ValidateLonLatPos(APoint);
+end;
+
+procedure TProjectionTypeGELonLat.ValidateLonLatRect(var ARect: TDoubleRect);
+begin
+ _ValidateLonLatPos(ARect.TopLeft);
+ _ValidateLonLatPos(ARect.BottomRight);
end;
end.
diff --git a/Src/MapLayers/WindowLayers/ScaleLine/u_WindowLayerScaleLineHorizontal.pas b/Src/MapLayers/WindowLayers/ScaleLine/u_WindowLayerScaleLineHorizontal.pas
index 3ba43ded4..50b9d5749 100644
--- a/Src/MapLayers/WindowLayers/ScaleLine/u_WindowLayerScaleLineHorizontal.pas
+++ b/Src/MapLayers/WindowLayers/ScaleLine/u_WindowLayerScaleLineHorizontal.pas
@@ -104,6 +104,18 @@ begin
VValidLegendWidth := (Config.Width div 4) * 4;
num := GetMetersPerLine(AVisualCoordConverter, VValidLegendWidth);
+ if num <= 0 then begin
+ DrawScaleLegend(
+ VColor,
+ VOutLineColor,
+ VColor,
+ VValidLegendWidth,
+ ' ',
+ ' ',
+ Layer.Bitmap
+ );
+ Exit;
+ end;
if Config.NumbersFormat = slnfNice then begin
ModifyLenAndWidth(Num, VValidLegendWidth);
@@ -244,7 +256,9 @@ begin
VFinishPixel := DoublePoint(VStartPixel.X + 1, VStartPixel.Y);
VProjection.ValidatePixelPosFloat(VFinishPixel, True);
VStartLonLat := VProjection.PixelPosFloat2LonLat(VStartPixel);
+ VProjection.ProjectionType.ValidateLonLatPos(VStartLonLat);
VFinishLonLat := VProjection.PixelPosFloat2LonLat(VFinishPixel);
+ VProjection.ProjectionType.ValidateLonLatPos(VFinishLonLat);
Result := VProjection.ProjectionType.Datum.CalcDist(VStartLonLat, VFinishLonLat) * ALineWidth;
end;
diff --git a/Src/MapLayers/WindowLayers/ScaleLine/u_WindowLayerScaleLineVertical.pas b/Src/MapLayers/WindowLayers/ScaleLine/u_WindowLayerScaleLineVertical.pas
index a2fbe0551..9167a8763 100644
--- a/Src/MapLayers/WindowLayers/ScaleLine/u_WindowLayerScaleLineVertical.pas
+++ b/Src/MapLayers/WindowLayers/ScaleLine/u_WindowLayerScaleLineVertical.pas
@@ -249,10 +249,12 @@ begin
VCenterPixelXY := AVisualCoordConverter.GetCenterMapPixelFloat;
VProjection.ValidatePixelPosFloatStrict(VCenterPixelXY, False);
VStartLonLat := VProjection.PixelPosFloat2LonLat(VCenterPixelXY);
+ VProjection.ProjectionType.ValidateLonLatPos(VStartLonLat);
VFinishPixelXY := DoublePoint(VCenterPixelXY.X, VCenterPixelXY.Y - ALineHeight / 2);
if VProjection.CheckPixelPosFloatStrict(VFinishPixelXY) then begin
VFinishLonLat := VProjection.PixelPosFloat2LonLat(VFinishPixelXY);
+ VProjection.ProjectionType.ValidateLonLatPos(VFinishLonLat);
AHalfLen := VProjection.ProjectionType.Datum.CalcDist(VStartLonLat, VFinishLonLat);
end else begin
AHalfLen := -1;
@@ -261,6 +263,7 @@ begin
VFinishPixelXY := DoublePoint(VCenterPixelXY.X, VCenterPixelXY.Y - ALineHeight);
if VProjection.CheckPixelPosFloatStrict(VFinishPixelXY) then begin
VFinishLonLat := VProjection.PixelPosFloat2LonLat(VFinishPixelXY);
+ VProjection.ProjectionType.ValidateLonLatPos(VFinishLonLat);
AFullLen := VProjection.ProjectionType.Datum.CalcDist(VStartLonLat, VFinishLonLat);
end else begin
AFullLen := -1;
diff --git a/Src/MapLayers/WindowLayers/StatusBar/u_WindowLayerStatusBar.pas b/Src/MapLayers/WindowLayers/StatusBar/u_WindowLayerStatusBar.pas
index ec9862f7c..0062bf674 100644
--- a/Src/MapLayers/WindowLayers/StatusBar/u_WindowLayerStatusBar.pas
+++ b/Src/MapLayers/WindowLayers/StatusBar/u_WindowLayerStatusBar.pas
@@ -489,6 +489,7 @@ begin
VMapPoint := VVisualCoordConverter.LocalPixel2MapPixelFloat(VMousePos);
VProjection.ValidatePixelPosFloatStrict(VMapPoint, True);
VLonLat := VProjection.PixelPosFloat2LonLat(VMapPoint);
+ VProjection.ProjectionType.ValidateLonLatPos(VLonLat);
I := Low(TStatusBarItemID);
AItems[I].Visible := FConfig.ViewZoomInfo;
| ||||
| related to | 0003065 | confirmed | Создать IProjectionConverter |
|
|
Да, есть такая проблема. Эта проекция отличается тем, что карта в ней не квадратная (как для Меркатора на сфере или эллипсоиде), а прямоугольная. Возможно, достаточно вот тут подправить расчёты для Y, чтобы значения не выходили за +-85 градусов, но не уверен, что это не поломает что-нибудь в другом месте... |
|
|
>Возможно, достаточно вот тут подправить расчёты для Y, чтобы значения не выходили за +-85 градусов, но не уверен, что это не поломает что-нибудь в другом месте... Нет. Там надо разбираться почему именно вылазит ошибка. У всех типов проекций покрытие чуток отличается, так что там есть механизм подгоняющий координты к допустимым при переходах от одной проекциии к другой. Нужно понять почему он не сработал и в чем конкретно. Просто этот тип проекции сильно отличается вот на нем и вылезло, но может вылезти на любой паре разных типов и даже на разных проекциях одного типа с разными параметрами. PS: Скорее всего где-то забыил вызвать Validate для координат или прямоугольника при переходе между проекциями. PPS: Собственно IProjectionConverter и планироваля для унификации таких операций, но увы там непочатый край работы. Общая идея: по двум IProjection получаем объект, который умеет правильно конвертировать все используемые в САС примитивы туда и обратно правильно со всеми проверками (ну или вообще ничего не делая, если это одинаковые проекции) |
|
|
Ошибка возникает из-за того, что допустимыми координатами для Lat в географической проекции в SAS считаются фантастические 180..-180. Все валидации вызываются и проходят без ошибок, но потом вызывается IDatum.CalcDist (при перерисовке Масштабной шкалы), который, естественно, падает с такими входными данными. Попробовал пофиксить конвертацию Relative2LonLat и обратно, чтобы он ограничил Lat диапазоном 90..-90 - ошибка уходит, но тайлы начинают проецироваться неверно. Т.е. страдает уже отображение тайлов. Сейчас думаю попробовать поиграться с ограничением относительных координат. Дело в том, что сейчас считается, что для всех проекций относительные координаты валидны в диапазоне 0..1. Может, если сделать кастомную валидацию для географической проекции с допустимыми значениями для Y в диапазоне 0..0.5 (что в итоге ограничит и Lat допустимыми значениями), получится ошибку исправить. |
|
|
Вроде получилось исправить. Тестовая сборка: https://disk.yandex.ru/d/cAaF1nBPVee_EQ vdemidov Патч приложил в аттаче. Так пойдёт? |
|
|
> Патч приложил в аттаче. Так пойдёт? Ну как минимум константа CMaxLatitude = 85.0511287798066; фигня. Если уже ограничиваться то 90. А в других типах проекций будут свои ограничения. А еще изменение форматирования вместе с изменением логики это капец. Невозможно найти где логика менялась. |
| Date Modified | Username | Field | Change |
|---|---|---|---|
| 01-09-2021 19:44 | VadimK | New Issue | |
| 01-09-2021 19:44 | VadimK | File Added: BUG_STATE_SAS.Planet.Nightly.210824.10169.zip | |
| 01-09-2021 19:44 | VadimK | File Added: Geographic_Lat-Lon.png | |
| 01-09-2021 19:45 | VadimK | File Added: InvalidFloatigPointOperation.png | |
| 04-09-2021 09:47 | zed | Note Added: 0020186 | |
| 04-09-2021 09:47 | zed | Status | new => confirmed |
| 04-09-2021 09:47 | zed | Product Version | .Nightly => 201212 |
| 04-09-2021 09:47 | zed | Target Version | => 50xxxx |
| 04-09-2021 21:19 | vdemidov | Note Added: 0020188 | |
| 04-09-2021 21:20 | vdemidov | Note Edited: 0020188 | |
| 04-09-2021 21:25 | vdemidov | Relationship added | related to 0003065 |
| 04-09-2021 21:28 | vdemidov | Note Edited: 0020188 | |
| 05-09-2021 07:56 | zed | Note Added: 0020189 | |
| 05-09-2021 09:08 | zed | Note Added: 0020190 | |
| 05-09-2021 09:08 | zed | File Added: 3781.diff | |
| 06-09-2021 08:21 | vdemidov | Note Added: 0020191 | |
| 06-09-2021 09:47 | zed | Status | confirmed => resolved |
| 06-09-2021 09:47 | zed | Fixed in Version | => 211230 |
| 06-09-2021 09:47 | zed | Resolution | open => fixed |
| 06-09-2021 09:47 | zed | Assigned To | => zed |
| 06-09-2021 09:48 | zed | Target Version | 50xxxx => 211230 |
| 06-09-2021 09:48 | zed | Summary | при выборе проекции "Geographic Lat/Lon" вылазит "Invalid Floatig Point Operation" => При выборе проекции "Geographic Lat/Lon" вылазит "Invalid Floatig Point Operation" |
| 08-08-2025 13:22 | zed | Category | Баг => Баг / Bug |