From 9e464eebd8f44c4714d63c78372368627890af4b Mon Sep 17 00:00:00 2001 From: Edvaldo Szymonek Date: Mon, 17 Aug 2026 21:48:41 -0300 Subject: [PATCH] =?UTF-8?q?corrige=20formata=C3=A7=C3=A3o=20das=20coordena?= =?UTF-8?q?das=20na=20ficha=20tombo=20(#497)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/controllers/splinker-controller.js | 4 +- src/helpers/coordenadas.js | 24 ++++----- test/unit/helpers/coordenadas.test.ts | 68 ++++++++++++++++++++++++++ 3 files changed, 82 insertions(+), 14 deletions(-) create mode 100644 test/unit/helpers/coordenadas.test.ts diff --git a/src/controllers/splinker-controller.js b/src/controllers/splinker-controller.js index 52d8146..da88d58 100644 --- a/src/controllers/splinker-controller.js +++ b/src/controllers/splinker-controller.js @@ -164,10 +164,10 @@ const obterModeloSPlinkerLotes = async (limit, offset, request, response) => { const city = tombo.locais_coletum?.cidade?.nome || '\t'; const locality = tombo.locais_coletum?.descricao || '\t'; const latitude = tombo.latitude - ? converteDecimalParaGrausMinutosSegundos(tombo.latitude, false, true) + ? converteDecimalParaGrausMinutosSegundos(tombo.latitude, true, true) : '\t'; const longitude = tombo.longitude - ? converteDecimalParaGrausMinutosSegundos(tombo.longitude, true, true) + ? converteDecimalParaGrausMinutosSegundos(tombo.longitude, false, true) : '\t'; const elevation = tombo.altitude ? `${tombo.altitude} m` : '\t'; const identificationDate = [ diff --git a/src/helpers/coordenadas.js b/src/helpers/coordenadas.js index 36e86e6..971ee80 100644 --- a/src/helpers/coordenadas.js +++ b/src/helpers/coordenadas.js @@ -6,17 +6,21 @@ const CHAR_SEC = '\u0022'; const CHAR_SEP = '\u0020'; export const converteParaDecimal = coordenada => { - const regex = /^(\d+)\D+(\d+)\D+(\d+(?:[.,]\d+)?)\W+([NSWE])$/; - const matches = coordenada.match(regex); + if (typeof coordenada !== 'string') { + throw new Error('Coordenada inválida'); + } + + const regex = /^(\d+)\D+(\d+)\D+(\d+(?:[.,]\d+)?)\W+([NSWE])$/i; + const matches = coordenada.trim().match(regex); - if (matches.length < 5) { + if (!matches) { throw new Error('Coordenada inválida'); } - const graus = parseInt(matches[1]); - const minutos = parseInt(matches[2]); + const graus = parseInt(matches[1], 10); + const minutos = parseInt(matches[2], 10); const segundos = parseFloat(matches[3].replace(',', '.')); - const hemisferio = matches[4]; + const hemisferio = matches[4].toUpperCase(); const sinal = (['S', 'W'].includes(hemisferio)) ? -1 : 1; @@ -180,13 +184,9 @@ export const converteDecimalParaGrausMinutosSegundos = (gDec, ehLat, formatada) segundos = aux; if (ehLat) { - // Eixo X - if (graus < 0) direcao = 'W'; - else direcao = 'E'; + direcao = graus < 0 ? 'S' : 'N'; } else { - // Eixo Y - if (graus >= 0) direcao = 'N'; - else direcao = 'S'; + direcao = graus < 0 ? 'W' : 'E'; } if (formatada) { diff --git a/test/unit/helpers/coordenadas.test.ts b/test/unit/helpers/coordenadas.test.ts new file mode 100644 index 0000000..6949cab --- /dev/null +++ b/test/unit/helpers/coordenadas.test.ts @@ -0,0 +1,68 @@ +import { + describe, + expect, + test +} from 'vitest' + +import { + converteDecimalParaGrausMinutosSegundos, + converteParaDecimal +} from '@/helpers/coordenadas' + +describe('converteParaDecimal', () => { + test('converts compact DMS latitude 48°56\'15,00"S to decimal degrees', () => { + expect(converteParaDecimal('48°56\'15,00"S')).toBe(-48.9375) + }) + + test('converts compact DMS longitude 48°56\'16,00"W to decimal degrees', () => { + expect(converteParaDecimal('48°56\'16,00"W')).toBeCloseTo( + -(48 + 56 / 60 + 16 / 3600), + 10 + ) + }) + + test('accepts a space before the hemisphere', () => { + expect(converteParaDecimal('48°56\'15,00" S')).toBe(-48.9375) + expect(converteParaDecimal('48°56\'16,00" W')).toBeCloseTo( + -(48 + 56 / 60 + 16 / 3600), + 10 + ) + }) + + test('applies a positive sign for N and E', () => { + expect(converteParaDecimal('48°56\'15,00"N')).toBe(48.9375) + expect(converteParaDecimal('48°56\'16,00"E')).toBeCloseTo( + 48 + 56 / 60 + 16 / 3600, + 10 + ) + }) + + test('throws when the coordinate is not DMS', () => { + expect(() => converteParaDecimal('48.9375')).toThrow('Coordenada inválida') + expect(() => converteParaDecimal('')).toThrow('Coordenada inválida') + }) +}) + +describe('converteDecimalParaGrausMinutosSegundos', () => { + const latitudeHcf46776 = converteParaDecimal('25°18\'27,00"S') + const longitudeHcf46776 = converteParaDecimal('49°0\'49,00"W') + + test('formats HCF 46776 latitude as south, not west', () => { + expect( + converteDecimalParaGrausMinutosSegundos(latitudeHcf46776, true, true) + ).toBe('25°18\'27,00" S') + }) + + test('formats HCF 46776 longitude as west, not south', () => { + expect( + converteDecimalParaGrausMinutosSegundos(longitudeHcf46776, false, true) + ).toBe('49°0\'49,00" W') + }) + + test('uses N/S for latitude and E/W for longitude', () => { + expect(converteDecimalParaGrausMinutosSegundos(25.3075, true, true)).toMatch(/ N$/) + expect(converteDecimalParaGrausMinutosSegundos(-25.3075, true, true)).toMatch(/ S$/) + expect(converteDecimalParaGrausMinutosSegundos(49.013611, false, true)).toMatch(/ E$/) + expect(converteDecimalParaGrausMinutosSegundos(-49.013611, false, true)).toMatch(/ W$/) + }) +})