refinamento no movimento combinado; carregamento de mapa com .prj quebrado
This commit is contained in:
parent
3891aaf819
commit
e07a842152
|
|
@ -863,6 +863,9 @@ namespace AgroBase
|
||||||
switch (Comando.Dispositivo)
|
switch (Comando.Dispositivo)
|
||||||
{
|
{
|
||||||
case T_Code.Mov:
|
case T_Code.Mov:
|
||||||
|
if (_Controle.TipoMovimento == TipoMovimentoDirecional.RotacionarNoEixo)
|
||||||
|
return;
|
||||||
|
|
||||||
_Controle.PercentualVelocidadeSP = Comando.ValorAplicar;
|
_Controle.PercentualVelocidadeSP = Comando.ValorAplicar;
|
||||||
_Controle.EmFreio = Comando.EstadoAplicar;
|
_Controle.EmFreio = Comando.EstadoAplicar;
|
||||||
op.AtualizarDadosControle(ForcarComando, new List<T_Code>() { Comando.Dispositivo });
|
op.AtualizarDadosControle(ForcarComando, new List<T_Code>() { Comando.Dispositivo });
|
||||||
|
|
|
||||||
|
|
@ -564,11 +564,9 @@ namespace AgroBase.Models.Modules
|
||||||
modulo.MovMotor.EnviarComandoControle(Direcao.Parado);
|
modulo.MovMotor.EnviarComandoControle(Direcao.Parado);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (DirecaoAtual == Direcao.Parado)
|
bool parado() => op?.Sensoriamento?.Movimentacao?.RPMMotorMedio <= 5;
|
||||||
{
|
await FuncoesGlobais.AguardarCondicaoAsync(parado, 2500, 200);
|
||||||
await Task.Delay(1000, cts.Token);
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (op.Controle.TipoMovimento)
|
switch (op.Controle.TipoMovimento)
|
||||||
{
|
{
|
||||||
case TipoMovimentoDirecional.RotacionarNoEixo:
|
case TipoMovimentoDirecional.RotacionarNoEixo:
|
||||||
|
|
@ -580,13 +578,10 @@ namespace AgroBase.Models.Modules
|
||||||
}
|
}
|
||||||
|
|
||||||
DateTime Agora = DateTime.Now;
|
DateTime Agora = DateTime.Now;
|
||||||
bool Sucesso = Modulos.All(x => x.DirMotor.PosicaoTipoMovimentoConcluido(DirecaoAtual));
|
bool atingiuSp() => Modulos.All(x => x.DirMotor.PosicaoTipoMovimentoConcluido(DirecaoAtual));
|
||||||
while (Agora.AddMilliseconds(5000) > DateTime.Now && !Sucesso)
|
await FuncoesGlobais.AguardarCondicaoAsync(atingiuSp, 5000, 200);
|
||||||
{
|
bool Sucesso = atingiuSp();
|
||||||
await Task.Delay(100, cts.Token);
|
|
||||||
Sucesso = Modulos.All(x => x.DirMotor.PosicaoTipoMovimentoConcluido(DirecaoAtual));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Sucesso && DirecaoAtual != Direcao.Parado)
|
if (Sucesso && DirecaoAtual != Direcao.Parado)
|
||||||
{
|
{
|
||||||
op.Controle.PercentualVelocidadeSP = 20;
|
op.Controle.PercentualVelocidadeSP = 20;
|
||||||
|
|
|
||||||
|
|
@ -144,7 +144,22 @@ namespace AgroBase.Services
|
||||||
{
|
{
|
||||||
ValidarArquivosShapefile(caminhoShp);
|
ValidarArquivosShapefile(caminhoShp);
|
||||||
|
|
||||||
Func<double, double, double[]> transformar = CriarTransformacaoParaWgs84(caminhoShp);
|
var featuresShp = Shapefile
|
||||||
|
.ReadAllFeatures(caminhoShp)
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
if (featuresShp.Count == 0)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException(
|
||||||
|
"O Shapefile não possui features válidas."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Func<double, double, double[]> transformar =
|
||||||
|
CriarTransformacaoParaWgs84(
|
||||||
|
caminhoShp,
|
||||||
|
featuresShp
|
||||||
|
);
|
||||||
|
|
||||||
var dados = new MapaFeatureCollectionModel
|
var dados = new MapaFeatureCollectionModel
|
||||||
{
|
{
|
||||||
|
|
@ -154,18 +169,22 @@ namespace AgroBase.Services
|
||||||
|
|
||||||
int indiceRua = 1;
|
int indiceRua = 1;
|
||||||
|
|
||||||
foreach (var featureShp in Shapefile.ReadAllFeatures(caminhoShp))
|
foreach (var featureShp in featuresShp)
|
||||||
{
|
{
|
||||||
if (featureShp?.Geometry == null || featureShp.Geometry.IsEmpty)
|
if (featureShp?.Geometry == null ||
|
||||||
|
featureShp.Geometry.IsEmpty)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
IEnumerable<LineString> linhas = ExtrairLineStrings(featureShp.Geometry);
|
IEnumerable<LineString> linhas =
|
||||||
|
ExtrairLineStrings(featureShp.Geometry);
|
||||||
|
|
||||||
foreach (LineString linha in linhas)
|
foreach (LineString linha in linhas)
|
||||||
{
|
{
|
||||||
if (linha == null || linha.IsEmpty || linha.NumPoints < 2)
|
if (linha == null ||
|
||||||
|
linha.IsEmpty ||
|
||||||
|
linha.NumPoints < 2)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
@ -174,37 +193,49 @@ namespace AgroBase.Services
|
||||||
|
|
||||||
foreach (Coordinate coordenada in linha.Coordinates)
|
foreach (Coordinate coordenada in linha.Coordinates)
|
||||||
{
|
{
|
||||||
double[] lonLat = transformar(coordenada.X, coordenada.Y);
|
double[] lonLat =
|
||||||
|
transformar(
|
||||||
|
coordenada.X,
|
||||||
|
coordenada.Y
|
||||||
|
);
|
||||||
|
|
||||||
double longitude = lonLat[0];
|
double longitude = lonLat[0];
|
||||||
double latitude = lonLat[1];
|
double latitude = lonLat[1];
|
||||||
|
|
||||||
if (double.IsNaN(longitude) ||
|
if (
|
||||||
|
double.IsNaN(longitude) ||
|
||||||
double.IsInfinity(longitude) ||
|
double.IsInfinity(longitude) ||
|
||||||
double.IsNaN(latitude) ||
|
double.IsNaN(latitude) ||
|
||||||
double.IsInfinity(latitude) ||
|
double.IsInfinity(latitude) ||
|
||||||
longitude < -180 ||
|
longitude < -180 ||
|
||||||
longitude > 180 ||
|
longitude > 180 ||
|
||||||
latitude < -90 ||
|
latitude < -90 ||
|
||||||
latitude > 90)
|
latitude > 90
|
||||||
|
)
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException(
|
throw new InvalidOperationException(
|
||||||
"O Shapefile produziu uma coordenada " +
|
"O Shapefile produziu uma coordenada " +
|
||||||
$"inválida: {longitude}, {latitude}."
|
$"inválida após transformação: " +
|
||||||
|
$"{longitude}, {latitude}."
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
coordenadas.Add(new List<double>
|
coordenadas.Add(
|
||||||
{
|
new List<double>
|
||||||
longitude,
|
{
|
||||||
latitude
|
longitude,
|
||||||
});
|
latitude
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (coordenadas.Count < 2)
|
if (coordenadas.Count < 2)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
string id = indiceRua.ToString(CultureInfo.InvariantCulture);
|
string id =
|
||||||
|
indiceRua.ToString(
|
||||||
|
CultureInfo.InvariantCulture
|
||||||
|
);
|
||||||
|
|
||||||
var properties =
|
var properties =
|
||||||
new MapaFeaturePropertiesModel
|
new MapaFeaturePropertiesModel
|
||||||
|
|
@ -314,62 +345,224 @@ namespace AgroBase.Services
|
||||||
". São aceitas somente linhas."
|
". São aceitas somente linhas."
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
private static Func<double, double, double[]> CriarTransformacaoParaWgs84(string caminhoShp)
|
private static Func<double, double, double[]> CriarTransformacaoParaWgs84(string caminhoShp, IEnumerable<IFeature> features)
|
||||||
{
|
{
|
||||||
string caminhoPrj = Path.ChangeExtension(caminhoShp, ".prj");
|
string caminhoPrj =
|
||||||
|
Path.ChangeExtension(caminhoShp, ".prj");
|
||||||
|
|
||||||
|
bool coordenadasParecemGeograficas =
|
||||||
|
CoordenadasParecemLongitudeLatitude(features);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ==========================================================
|
||||||
|
* 1. SHAPEFILE SEM .PRJ
|
||||||
|
* ==========================================================
|
||||||
|
*
|
||||||
|
* Se as próprias coordenadas já estão dentro dos limites
|
||||||
|
* longitude/latitude, aceitamos como coordenadas geográficas.
|
||||||
|
*/
|
||||||
if (!File.Exists(caminhoPrj))
|
if (!File.Exists(caminhoPrj))
|
||||||
{
|
{
|
||||||
|
if (coordenadasParecemGeograficas)
|
||||||
|
{
|
||||||
|
Variaveis.MostrarLog(
|
||||||
|
"[MapasService] Shapefile sem arquivo .prj. " +
|
||||||
|
"As coordenadas já parecem estar em " +
|
||||||
|
"longitude/latitude. Nenhuma reprojeção será aplicada."
|
||||||
|
);
|
||||||
|
|
||||||
|
return (x, y) => new[] { x, y };
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new InvalidOperationException(
|
||||||
|
"O Shapefile não possui arquivo .prj e suas " +
|
||||||
|
"coordenadas não parecem estar em longitude/latitude. " +
|
||||||
|
"Não é possível determinar com segurança o sistema " +
|
||||||
|
"de coordenadas do mapa."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
string wkt =
|
||||||
|
File.ReadAllText(
|
||||||
|
caminhoPrj,
|
||||||
|
Encoding.UTF8
|
||||||
|
);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ==========================================================
|
||||||
|
* 2. .PRJ VAZIO
|
||||||
|
* ==========================================================
|
||||||
|
*/
|
||||||
|
if (string.IsNullOrWhiteSpace(wkt))
|
||||||
|
{
|
||||||
|
if (coordenadasParecemGeograficas)
|
||||||
|
{
|
||||||
|
Variaveis.MostrarLog(
|
||||||
|
"[MapasService] Arquivo .prj vazio. " +
|
||||||
|
"As coordenadas parecem longitude/latitude; " +
|
||||||
|
"o mapa será carregado sem reprojeção."
|
||||||
|
);
|
||||||
|
|
||||||
|
return (x, y) => new[] { x, y };
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new InvalidOperationException(
|
||||||
|
"O arquivo .prj está vazio e as coordenadas " +
|
||||||
|
"do Shapefile não parecem longitude/latitude."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ==========================================================
|
||||||
|
* 3. TENTA INTERPRETAR O .PRJ NORMALMENTE
|
||||||
|
* ==========================================================
|
||||||
|
*/
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var fabricaSistemas =
|
||||||
|
new CoordinateSystemFactory();
|
||||||
|
|
||||||
|
var sistemaOrigem =
|
||||||
|
fabricaSistemas.CreateFromWkt(wkt);
|
||||||
|
|
||||||
|
if (sistemaOrigem == null)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException(
|
||||||
|
"O sistema de coordenadas do .prj não pôde ser criado."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
var sistemaDestino =
|
||||||
|
GeographicCoordinateSystem.WGS84;
|
||||||
|
|
||||||
|
var fabricaTransformacao =
|
||||||
|
new CoordinateTransformationFactory();
|
||||||
|
|
||||||
|
var transformacao =
|
||||||
|
fabricaTransformacao
|
||||||
|
.CreateFromCoordinateSystems(
|
||||||
|
sistemaOrigem,
|
||||||
|
sistemaDestino
|
||||||
|
);
|
||||||
|
|
||||||
|
if (transformacao?.MathTransform == null)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException(
|
||||||
|
"Não foi possível criar a transformação para WGS84."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Sem PRJ, só será permitido se as coordenadas
|
* O PRJ é válido.
|
||||||
* já parecerem longitude/latitude.
|
* Usa a transformação normalmente.
|
||||||
*/
|
*/
|
||||||
return (x, y) =>
|
return (x, y) =>
|
||||||
{
|
{
|
||||||
if (x < -180 || x > 180 || y < -90 || y > 90)
|
double[] resultado =
|
||||||
{
|
transformacao.MathTransform.Transform(
|
||||||
throw new InvalidOperationException(
|
new[] { x, y }
|
||||||
"O Shapefile não possui arquivo .prj e " +
|
|
||||||
"as coordenadas não estão em longitude/latitude."
|
|
||||||
);
|
);
|
||||||
}
|
|
||||||
|
|
||||||
return new[] { x, y };
|
return resultado;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
string wkt = File.ReadAllText(caminhoPrj, Encoding.UTF8);
|
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(wkt))
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException("O arquivo .prj está vazio.");
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var fabricaSistemas = new CoordinateSystemFactory();
|
|
||||||
|
|
||||||
var sistemaOrigem = fabricaSistemas.CreateFromWkt(wkt);
|
|
||||||
|
|
||||||
var sistemaDestino = GeographicCoordinateSystem.WGS84;
|
|
||||||
|
|
||||||
var fabricaTransformacao = new CoordinateTransformationFactory();
|
|
||||||
|
|
||||||
var transformacao = fabricaTransformacao.CreateFromCoordinateSystems(sistemaOrigem, sistemaDestino);
|
|
||||||
|
|
||||||
return (x, y) => transformacao.MathTransform.Transform(
|
|
||||||
new[] { x, y }
|
|
||||||
);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
|
* ======================================================
|
||||||
|
* 4. .PRJ EXISTE, MAS ESTÁ QUEBRADO
|
||||||
|
* ======================================================
|
||||||
|
*
|
||||||
|
* Se as coordenadas já são compatíveis com longitude /
|
||||||
|
* latitude, podemos ignorar o PRJ defeituoso.
|
||||||
|
*
|
||||||
|
* Esse é exatamente o caso do mapa atual.
|
||||||
|
*/
|
||||||
|
if (coordenadasParecemGeograficas)
|
||||||
|
{
|
||||||
|
Variaveis.MostrarLog(
|
||||||
|
"[MapasService] AVISO: o arquivo .prj existe, " +
|
||||||
|
"mas não pôde ser interpretado. " +
|
||||||
|
"Como as coordenadas do Shapefile já parecem estar " +
|
||||||
|
"em longitude/latitude, o mapa será carregado " +
|
||||||
|
"sem reprojeção. Erro do PRJ: " +
|
||||||
|
ex.Message
|
||||||
|
);
|
||||||
|
|
||||||
|
return (x, y) => new[] { x, y };
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Temos um PRJ quebrado e coordenadas aparentemente
|
||||||
|
* projetadas (UTM, por exemplo).
|
||||||
|
*
|
||||||
|
* Aqui NÃO devemos adivinhar.
|
||||||
|
*/
|
||||||
throw new InvalidOperationException(
|
throw new InvalidOperationException(
|
||||||
"Não foi possível interpretar ou reprojetar " +
|
"O arquivo .prj do Shapefile não pôde ser interpretado " +
|
||||||
"o sistema de coordenadas definido no arquivo .prj.",
|
"e as coordenadas do mapa não parecem estar em " +
|
||||||
|
"longitude/latitude. Não é possível determinar com " +
|
||||||
|
"segurança a projeção utilizada.",
|
||||||
ex
|
ex
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
private static bool CoordenadasParecemLongitudeLatitude(IEnumerable<IFeature> features)
|
||||||
|
{
|
||||||
|
if (features == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
int quantidade = 0;
|
||||||
|
|
||||||
|
foreach (IFeature feature in features)
|
||||||
|
{
|
||||||
|
if (feature?.Geometry == null ||
|
||||||
|
feature.Geometry.IsEmpty)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (Coordinate coordenada in feature.Geometry.Coordinates)
|
||||||
|
{
|
||||||
|
if (coordenada == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
double x = coordenada.X;
|
||||||
|
double y = coordenada.Y;
|
||||||
|
|
||||||
|
if (
|
||||||
|
double.IsNaN(x) ||
|
||||||
|
double.IsInfinity(x) ||
|
||||||
|
double.IsNaN(y) ||
|
||||||
|
double.IsInfinity(y)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Limites físicos de longitude e latitude.
|
||||||
|
*/
|
||||||
|
if (
|
||||||
|
x < -180.0 ||
|
||||||
|
x > 180.0 ||
|
||||||
|
y < -90.0 ||
|
||||||
|
y > 90.0
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
quantidade++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Só consideramos válido se realmente encontramos
|
||||||
|
* coordenadas para analisar.
|
||||||
|
*/
|
||||||
|
return quantidade > 0;
|
||||||
|
}
|
||||||
private static void ValidarArquivosShapefile(string caminhoShp)
|
private static void ValidarArquivosShapefile(string caminhoShp)
|
||||||
{
|
{
|
||||||
string caminhoDbf = Path.ChangeExtension(caminhoShp, ".dbf");
|
string caminhoDbf = Path.ChangeExtension(caminhoShp, ".dbf");
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue