def fejlmeld_koordinat(self, sagsevent: Sagsevent, koordinat: Koordinat): """ Fejlmeld en allerede eksisterende koordinat. Hvis koordinaten er den eneste af sin slags på det tilknyttede punkt fejlmeldes og afregistreres den. Hvis koordinaten indgår i en tidsserie sker en af to ting: 1. Hvis koordinaten forekommer midt i en tidsserie fejlmeldes den uden videre. 2. Hvis koordinaten er den seneste i tidsserien fejlmeldes den, den foregående koordinat fejlmeldes og en ny koordinat indsættes med den foregåendes værdier. Denne fremgangsmåde sikrer at der er en aktuel og gyldig koordinat, samt at den samme koordinat ikke fremtræder to gange i en tidsserie. """ punkt = koordinat.punkt srid = koordinat.srid ny_koordinat = None if len(punkt.koordinater) == 1: self._luk_fikspunkregisterobjekt(koordinat, sagsevent, commit=False) # Er koordinaten den sidste i tidsserien? if koordinat.registreringtil is None: # Find seneste ikke-fejlmeldte koordinat så den # bruges som den seneste gyldige koordinat for forrige_koordinat in reversed(punkt.koordinater[0:-1]): if forrige_koordinat.srid != srid: continue if not forrige_koordinat.fejlmeldt: break if not forrige_koordinat.fejlmeldt: ny_koordinat = Koordinat( punktid=forrige_koordinat.punktid, sridid=forrige_koordinat.sridid, x=forrige_koordinat.x, y=forrige_koordinat.y, z=forrige_koordinat.z, t=forrige_koordinat.t, sx=forrige_koordinat.sx, sy=forrige_koordinat.sy, sz=forrige_koordinat.sz, transformeret=forrige_koordinat.transformeret, artskode=forrige_koordinat.artskode, _registreringfra=func.sysdate(), ) sagsevent.koordinater = [ny_koordinat] self.session.add(sagsevent) koordinat.fejlmeldt = True if ny_koordinat: koordinat._registreringtil = ny_koordinat._registreringfra self.session.add(koordinat) self.session.commit()
def test_afregistrering_af_koordinat( firedb: FireDb, sag: Sag, srid: Srid, punkt: Punkt ): """ Database triggeren BID#KOORDINAT sætter registreringtil og sagseventtilid ved indsættelse af ny koordinat. Tjek at triggeren virker. """ se1 = Sagsevent( id=str(uuid.uuid4()), sag=sag, eventtype=EventType.KOORDINAT_BEREGNET ) se1.koordinater = [ Koordinat( srid=srid, punkt=punkt, t=dt.datetime(2020, 5, 13, 8, 0), x=0, y=0, z=0, sx=0, sy=0, sz=0, ) ] firedb.session.add(se1) firedb.session.commit() se2 = Sagsevent( id=str(uuid.uuid4()), sag=sag, eventtype=EventType.KOORDINAT_BEREGNET ) se2.koordinater = [ Koordinat( srid=srid, punkt=punkt, t=dt.datetime(2020, 5, 13, 9, 45), x=1, y=1, z=1, sx=1, sy=1, sz=1, ) ] firedb.session.add(se2) firedb.session.commit() p = firedb.hent_punkt(punkt.id) assert len(p.koordinater) == 2 assert p.koordinater[0].srid.sridid == srid.sridid assert p.koordinater[1].srid.sridid == srid.sridid assert p.koordinater[0].registreringtil == p.koordinater[1].registreringfra assert p.koordinater[0].sagseventtilid == p.koordinater[1].sagseventfraid
def test_indlæsning_af_lukket_koordinat(firedb: FireDb, koordinat: Koordinat): """ Test trigger koordinat_bi_trg. Direkte indlæsning af en lukket koordinat er ikke tilladt, tjek at databasen brokker sig over det. """ koordinat._registreringtil = dt.datetime(2020, 9, 22, 13, 37) koordinat._registreringfra = dt.datetime(2020, 9, 22, 13, 37) firedb.session.add(koordinat) with pytest.raises(DatabaseError): firedb.session.commit() firedb.session.rollback()
def test_fejlmeld_koordinat_midt_i_tidsserie(firedb: FireDb, sag: Sag, punkt: Punkt, srid: Srid): koordinater = [] for i in range(3): se = Sagsevent(id=str(uuid.uuid4()), sag=sag, eventtype=EventType.KOORDINAT_BEREGNET) koordinat = Koordinat( srid=srid, punkt=punkt, _registreringfra=dt.datetime(2020, 9, 22, 8, i), t=dt.datetime(2020, 5, 9, 22, i), x=i, y=i, z=i, sx=0, sy=0, sz=0, ) koordinater.append(koordinat) se.koordinater = [koordinat] firedb.session.add(se) firedb.session.commit() firedb.fejlmeld_koordinat( Sagsevent(sag=sag, eventtype=EventType.KOORDINAT_NEDLAGT), koordinater[1]) assert koordinater[1].fejlmeldt is True assert koordinater[1].registreringtil is not None
def convert_heights(): """Skab UTM koordinater for grønlandske højdefikspunkter. Der tilføjes kun UTM koordinater hvis ikke fikspunktet i forvejen har tilknyttet en UTM koordinater. Da der for mange højdefikspunkter ikke findes en plankoordinat benyttes dens lokationskoordinat. """ UTM24 = firedb.hent_srid("EPSG:3184") region_gl = firedb.hent_punktinformationtype("REGION:GL") punkt_kandidater = ( firedb.session.query(Punkt).join(PunktInformation).filter( PunktInformation.infotypeid == region_gl.infotypeid).all()) oracle_killer = Transformer.from_crs("EPSG:4326", "EPSG:3184") nye_koordinater = [] with click.progressbar( punkt_kandidater, label=f"Transforming WGS84 coordinates", length=len(punkt_kandidater), ) as punkter: for punkt in punkter: needs_transformation = True for koordinat in punkt.koordinater: if koordinat.sridid == UTM24.sridid: needs_transformation = False # punktet har en UTM koordinat, videre break if not needs_transformation: continue try: (lon, lat) = punkt.geometriobjekter[0].geometri._geom['coordinates'] except IndexError: continue # Der findes ikke en lokationskoordinat, videre utm = oracle_killer.transform(lat, lon) utm_koordinat = Koordinat( srid=UTM24, sx=999, sy=999, # Vi bruger punktets oprettelsesdato for ikke at få koordinaten # til at se nyere og bedre ud end den er t=punkt.registreringfra, transformeret="true", x=utm[0], y=utm[1], punkt=punkt, artskode=Artskode.TRANSFORMERET, ) nye_koordinater.append(utm_koordinat) return nye_koordinater
def test_afregistrering_koordinat(firedb: FireDb, sag: Sag, punkt: Punkt, srid: Srid): """ Test trigger koordinat_au_trg - Automatisk afrestrering af tidligere koordinat. """ k1 = Koordinat( punkt=punkt, srid=srid, x=0, y=0, z=0, sx=0, sy=0, sz=0, t=dt.datetime(2020, 9, 22, 13, 37), ) se = Sagsevent(sag=sag, eventtype=EventType.KOORDINAT_BEREGNET) se.koordinater = [k1] firedb.session.add(se) k2 = Koordinat( punkt=punkt, srid=srid, x=0.1, y=0, z=0, sx=0, sy=0, sz=0, t=dt.datetime(2020, 9, 22, 13, 40), ) se = Sagsevent(sag=sag, eventtype=EventType.KOORDINAT_BEREGNET) se.koordinater = [k2] firedb.session.add(se) firedb.session.commit() assert k1.registreringtil == k2.registreringfra assert k1.sagseventtilid == k2.sagseventfraid assert k2.registreringtil is None assert k2.sagseventtilid is None
def test_timestamps(firedb: FireDb, koordinat: Koordinat): """ Test at TIMESTAMPs kan opløse mikrosekunder. """ timestamp = dt.datetime(2020, 9, 22, 13, 37, 12, 345) koordinat.t = timestamp firedb.session.add(koordinat) firedb.session.commit() firedb.session.refresh(koordinat) assert koordinat.t == dt.datetime(2020, 9, 22, 13, 37, 12, 345)
def fabrik(): sagsevent.eventtype = EventType.KOORDINAT_BEREGNET k0 = Koordinat( sagsevent=sagsevent, punkt=punkt, srid=srid, x=0, y=0, z=0, sx=0, sy=0, sz=0, ) firedb.session.add(k0) return k0
def koordinat(firedb, sagsevent, punkt, srid): sagsevent.eventtype = EventType.KOORDINAT_BEREGNET k0 = Koordinat( sagsevent=sagsevent, punkt=punkt, transformeret="false", srid=srid, x=0, y=0, z=0, sx=0, sy=0, sz=0, ) firedb.session.add(k0) return k0
def test_fejlmeld_koordinat_enlig_koordinat(firedb: FireDb, sag: Sag, sagsevent: Sagsevent, koordinat: Koordinat): sagsevent.eventtype = EventType.KOORDINAT_BEREGNET sagsevent.sagsid = sag.id koordinat.sagsevent = sagsevent firedb.session.add(sag) firedb.session.add(sagsevent) firedb.session.add(koordinat) firedb.session.commit() firedb.fejlmeld_koordinat( Sagsevent(eventtype=EventType.KOORDINAT_BEREGNET, sag=sag), koordinat) assert koordinat.fejlmeldt is True assert koordinat.registreringtil is not None
def test_luk_punkt( firedb: FireDb, punkt: Punkt, sagsevent: Sagsevent, observationer: List[Observation], koordinat: Koordinat, punktinformationtype: PunktInformationType, ): # byg et punkt der har tilknyttet geometri, koordinat, # punktinfo og observationer geometri = GeometriObjekt(punkt=punkt, geometri=Point([10, 55]), sagsevent=sagsevent) firedb.session.add(geometri) observationer[0].opstillingspunkt = punkt observationer[1].sigtepunkt = punkt koordinat.punkt = punkt punkt.punktinformationer = [ PunktInformation(infotype=punktinformationtype, sagsevent=sagsevent) ] firedb.session.commit() firedb.luk_punkt(punkt, sagsevent) assert punkt.registreringtil is not None assert punkt.sagsevent.eventtype == EventType.PUNKT_NEDLAGT assert punkt.sagseventtilid == sagsevent.id assert geometri.registreringtil is not None assert geometri.sagsevent.eventtype == EventType.PUNKT_NEDLAGT for koordinat in punkt.koordinater: assert koordinat.registreringtil is not None assert koordinat.sagsevent.eventtype == EventType.PUNKT_NEDLAGT assert koordinat.sagseventtilid == sagsevent.id for punktinfo in punkt.punktinformationer: assert punktinfo.registreringtil is not None assert punktinfo.sagsevent.eventtype == EventType.PUNKT_NEDLAGT assert punktinfo.sagseventtilid == sagsevent.id for observation in chain(punkt.observationer_fra, punkt.observationer_til): assert observation.registreringtil is not None assert observation.sagsevent.eventtype == EventType.PUNKT_NEDLAGT assert observation.sagseventtilid == sagsevent.id with pytest.raises(TypeError): firedb.luk_punkt(999)
def test_indset_beregning( firedb: FireDb, sag: Sag, sagsevent: Sagsevent, punkt: Punkt, srid: Srid, observationstype: ObservationsType, ): o0 = Observation( sagsevent=sagsevent, observationstidspunkt=func.current_timestamp(), observationstype=observationstype, opstillingspunkt=punkt, ) firedb.indset_sagsevent( Sagsevent( sag=sag, sagseventinfos=[ SagseventInfo(beskrivelse="Testindsættelse af observation") ], eventtype=EventType.OBSERVATION_INDSAT, observationer=[o0], )) beregning = Beregning() beregning.observationer.append(o0) koordinat = Koordinat(srid=srid, punkt=punkt, x=0, y=0, z=0, sx=0, sy=0, sz=0) beregning.koordinater.append(koordinat) firedb.indset_sagsevent( Sagsevent( sag=sag, eventtype=EventType.KOORDINAT_BEREGNET, sagseventinfos=[SagseventInfo(beskrivelse="Testberegning")], beregninger=[beregning], koordinater=beregning.koordinater, )) assert koordinat.objektid is not None
def convert_coordinates(epsg_code): from_srid = firedb.hent_srid(epsg_code) try: # tilføjet i Migration/MakeSRIDType.sql, men inkluderet her for en sikkerheds skyld to_srid = firedb.hent_srid("EPSG:3184") except: new_srid = Srid( beskrivelse="Projicerede koordinater 2D: UTM Zone 24, GR96", x="Easting [m]", y="Northing [m]", name="EPSG:3184", ) firedb.indset_srid(new_srid) finally: to_srid = firedb.hent_srid("EPSG:3184") koordinater = (firedb.session.query(Koordinat).filter( and_(Koordinat.sridid == from_srid.sridid, Koordinat._registreringtil == None)).all()) nye_koordinater = [] oracle_killer = Transformer.from_crs(epsg_code, "EPSG:3184") with click.progressbar( koordinater, label=f"Transforming {epsg_code} coordinates", length=len(koordinater), ) as koord: for koordinat in koord: utm = oracle_killer.transform(koordinat.y, koordinat.x) utm_koordinat = Koordinat( srid=to_srid, sx=koordinat.sx, sy=koordinat.sy, # vi beholder samme tidspunkt for ikke at få det til at se # ud som om koordinaten er nyere, og dermed bedre t=koordinat.t, transformeret="true", x=utm[0], y=utm[1], punkt=koordinat.punkt, artskode=Artskode.TRANSFORMERET, ) nye_koordinater.append(utm_koordinat) return nye_koordinater
def test_fejlmeld_koordinat_midt_i_tidsserie_flere_srider( firedb: FireDb, sag: Sag, punkt: Punkt, srid: Srid): """ Test fejlmeldingslogik i tilfælde af at punktet har koordinater tilhørende flere SRID'er """ srid = [firedb.hent_srid("EPSG:5799"), srid] koordinater = [] for i in range(4): se = Sagsevent(id=str(uuid.uuid4()), sag=sag, eventtype=EventType.KOORDINAT_BEREGNET) koordinat = Koordinat( srid=srid[i % 2], punkt=punkt, _registreringfra=dt.datetime(2020, 9, 22, 8, i), t=dt.datetime(2020, 5, 9, 22, i), x=i, y=i, z=i, sx=0, sy=0, sz=0, ) koordinater.append(koordinat) se.koordinater = [koordinat] firedb.session.add(se) firedb.session.commit() firedb.fejlmeld_koordinat( Sagsevent(sag=sag, eventtype=EventType.KOORDINAT_NEDLAGT), koordinater[3]) assert koordinater[3].fejlmeldt is True assert koordinater[3].registreringtil is not None assert punkt.koordinater[4].registreringtil is None assert punkt.koordinater[4].fejlmeldt is False assert punkt.koordinater[1].x == punkt.koordinater[4].x
def ilæg_nye_koter(projektnavn: str, sagsbehandler: str, **kwargs) -> None: """Registrer nyberegnede koter i databasen""" sag = find_sag(projektnavn) sagsgang = find_sagsgang(projektnavn) sag = find_sag(projektnavn) sagsgang = find_sagsgang(projektnavn) fire.cli.print(f"Sags/projekt-navn: {projektnavn} ({sag.id})") fire.cli.print(f"Sagsbehandler: {sagsbehandler}") punktoversigt = find_faneblad(projektnavn, "Endelig beregning", ARKDEF_PUNKTOVERSIGT) ny_punktoversigt = punktoversigt[0:0] DVR90 = fire.cli.firedb.hent_srid("EPSG:5799") registreringstidspunkt = func.current_timestamp() tid = gyldighedstidspunkt(projektnavn) # Generer sagsevent sagsevent = Sagsevent(sag=sag, id=uuid(), eventtype=EventType.KOORDINAT_BEREGNET) til_registrering = [] opdaterede_punkter = [] for punktdata in punktoversigt.to_dict(orient="records"): # Blanklinje, tilbageholdt, eller allerede registreret? if (pd.isna(punktdata["Ny kote"]) or punktdata["uuid"] != "" or punktdata["Udelad publikation"] == "x"): ny_punktoversigt = ny_punktoversigt.append(punktdata, ignore_index=True) continue punkt = fire.cli.firedb.hent_punkt(punktdata["Punkt"]) opdaterede_punkter.append(punkt) punktdata["uuid"] = sagsevent.id kote = Koordinat( srid=DVR90, punkt=punkt, t=tid, z=punktdata["Ny kote"], sz=punktdata["Ny σ"], ) til_registrering.append(kote) ny_punktoversigt = ny_punktoversigt.append(punktdata, ignore_index=True) if 0 == len(til_registrering): fire.cli.print("Ingen koter at registrere!", fg="yellow", bold=True) return # Vi vil ikke have alt for lange sagseventtekster (bl.a. fordi Oracle ikke # kan lide lange tekststrenge), så vi indsætter udeladelsesprikker hvis vi # opdaterer mere end 10 punkter ad gangen n = len(opdaterede_punkter) punktnavne = [p.ident for p in opdaterede_punkter] if n > 10: punktnavne[9] = "..." punktnavne[10] = punktnavne[-1] punktnavne = punktnavne[0:10] sagseventtekst = f"Opdatering af DVR90 kote til {', '.join(punktnavne)}" with open(f"{projektnavn}-resultat-endelig.html") as html: clob = "".join(html.readlines()) sagseventinfo = SagseventInfo( beskrivelse=sagseventtekst, htmler=[SagseventInfoHtml(html=clob)], ) sagsevent.sagseventinfos.append(sagseventinfo) sagsevent.koordinater = til_registrering fire.cli.firedb.indset_sagsevent(sagsevent, commit=False) # Generer dokumentation til fanebladet "Sagsgang" # Variablen "registreringstidspunkt" har værdien "CURRENT_TIMESTAMP" # som udvirker mikrosekundmagi når den bliver skrevet til databasen, # men ikke er meget informativ for en menneskelig læser her i regne- # arkenes prosaiske verden. Derfor benytter vi pd.Timestamp.now(), # som ikke har mikrosekundmagi over sig, men som kan læses og giver # mening, selv om den ikke bliver eksakt sammenfaldende med det # tidsstempel hændelsen får i databasen. Det lever vi med. sagsgangslinje = { "Dato": pd.Timestamp.now(), "Hvem": sagsbehandler, "Hændelse": "Koteberegning", "Tekst": sagseventtekst, "uuid": sagsevent.id, } sagsgang = sagsgang.append(sagsgangslinje, ignore_index=True) fire.cli.print(sagseventtekst, fg="yellow", bold=True) fire.cli.print(f"Ialt {n} koter") try: fire.cli.firedb.session.flush() except Exception as ex: # rul tilbage hvis databasen smider en exception fire.cli.firedb.session.rollback() fire.cli.print( f"Der opstod en fejl - koter for '{projektnavn}' IKKE indlæst!") fire.cli.print(f"Mulig årsag: {ex}") else: spørgsmål = click.style("Du indsætter nu ", fg="white", bg="red") spørgsmål += click.style(f"{len(til_registrering)} kote(r) ", fg="white", bg="red", bold=True) spørgsmål += click.style(f"i ", fg="white", bg="red") spørgsmål += click.style(f"{fire.cli.firedb.db}", fg="white", bg="red", bold=True) spørgsmål += click.style("-databasen - er du sikker?", fg="white", bg="red") if bekræft(spørgsmål): fire.cli.firedb.session.commit() # Skriv resultater til resultatregneark resultater = {"Sagsgang": sagsgang, "Resultat": ny_punktoversigt} if skriv_ark(projektnavn, resultater): fire.cli.print( f"Koter registreret. Resultater skrevet til '{projektnavn}.xlsx'" )
def ilæg_revision( projektnavn: str, sagsbehandler: str, **kwargs, ) -> None: """Læg reviderede punktdata i databasen""" sag = find_sag(projektnavn) sagsgang = find_sagsgang(projektnavn) fire.cli.print(f"Sags/projekt-navn: {projektnavn} ({sag.id})") fire.cli.print(f"Sagsbehandler: {sagsbehandler}") fire.cli.print("") revision = find_faneblad(f"{projektnavn}-revision", "Revision", ARKDEF_REVISION) # Tildel navne til endnu ikke oprettede punkter oprettelse = revision.query("Attribut == 'OPRET'") for i, _ in oprettelse.iterrows(): revision.loc[i, "Punkt"] = f"NYTPUNKT{i}" # Udfyld udeladte identer punkter = list(revision["Punkt"]) udfyldningsværdi = "" for i in range(len(punkter)): if punkter[i].strip() != "": udfyldningsværdi = punkter[i].strip() continue punkter[i] = udfyldningsværdi revision["Punkt"] = punkter # Find alle punkter, der skal nyoprettes nye_punkter = [] oprettelse = revision.query("Attribut == 'OPRET'") for row in oprettelse.to_dict("records"): if row["id"] == -1: continue punkt = opret_punkt(row["Ny værdi"]) fire.cli.print(f"Opretter nyt punkt {punkt.ident}: {row['Ny værdi']}") nye_punkter.append(punkt) # indsæt nyt punkt ID i Punkt kolonnen, for at kunne trække # dem ud med hent_punkt() senere erstat = lambda x: punkt.id if x == row["Punkt"] else x revision["Punkt"] = revision.Punkt.apply(erstat) revision = revision.query("Attribut != 'OPRET'") # Find alle lokationskoordinater, der skal korrigeres nye_lokationer = [] lokation = revision.query("Attribut == 'LOKATION'") lokation = lokation.query("`Ny værdi` != ''") for row in lokation.to_dict("records"): punkt = fire.cli.firedb.hent_punkt(row["Punkt"]) # gem her inden ny geometri tilknyttes punktet (λ1, φ1) = punkt.geometri.koordinater go = læs_lokation(row["Ny værdi"]) go.punkt = punkt nye_lokationer.append(go) (λ2, φ2) = go.koordinater g = Geod(ellps="GRS80") _, _, dist = g.inv(λ1, φ1, λ2, φ2) if dist >= 25: fire.cli.print( f" ADVARSEL: Ny lokationskoordinat afviger {dist:.0f} m fra den gamle", fg="yellow", bold=True, ) if len(nye_punkter) > 0 or len(nye_lokationer) > 0: sagsevent = Sagsevent( id=uuid(), sagsid=sag.id, sagseventinfos=[ SagseventInfo(beskrivelse="Oprettelse af nye punkter") ], eventtype=EventType.PUNKT_OPRETTET, punkter=nye_punkter, geometriobjekter=nye_lokationer, ) fire.cli.firedb.indset_sagsevent(sagsevent, commit=False) sagsgang = opdater_sagsgang(sagsgang, sagsevent, sagsbehandler) flush() revision = revision.query("Attribut != 'LOKATION'") # Find alle koordinater, der skal oprettes # Først skal vi bruge alle gyldige koordinatsystemnavne srider = fire.cli.firedb.hent_srider() sridnavne = [srid.name.upper() for srid in srider] # Så itererer vi over hele rammen og ignorerer ikke-koordinaterne nye_koordinater = [] opdaterede_punkter = [] for r in revision.to_dict("records"): sridnavn = r["Attribut"].upper() if sridnavn not in sridnavne: continue try: koord = [float(k.replace(",", ".")) for k in r["Ny værdi"].split()] except ValueError as ex: fire.cli.print( f"Ukorrekt koordinatformat:\n{' '.join(r['Ny værdi'])}\n{ex}" ) fire.cli.print( "Skal være på formen: 'x y z t sx sy sz', hvor ubrugte værdier sættes til 'nan'" ) sys.exit(1) # Oversæt NaN til None koord = [None if isnan(k) else k for k in koord] # Tæt-på-kopi af kode fra "niv/ilæg_nye_koter.py". Her bør mediteres og overvejes # hvordan denne opgave kan parametriseres på en rimeligt generel måde, så den kan # udstilles i et "højniveau-API" srid = fire.cli.firedb.hent_srid(sridnavn) punkt = fire.cli.firedb.hent_punkt(r["Punkt"]) opdaterede_punkter.append(r["Punkt"]) # Det er ikke helt så nemt som i C at oversætte decimal-år til datetime år = trunc(koord[3]) rest = koord[3] - år startdato = datetime(år, 1, 1) årlængde = datetime(år + 1, 1, 1) - startdato tid = startdato + rest * årlængde koordinat = Koordinat( srid=srid, punkt=punkt, x=koord[0], y=koord[1], z=koord[2], t=tid, sx=koord[4], sy=koord[5], sz=koord[6], ) nye_koordinater.append(koordinat) # I Grønland er vi nødt til at duplikere geografiske koordinater til UTM24, # da Oracles indbyggede UTM-rutine er for ringe til at vi kan generere # udstillingskoordinater on-the-fly. if sridnavn in ("EPSG:4909", "EPSG:4747"): srid_utm24 = fire.cli.firedb.hent_srid("EPSG:3184") utm24 = Proj("proj=utm zone=24 ellps=GRS80", preserve_units=False) x, y = utm24(koord[0], koord[1]) koordinat = Koordinat( srid=srid_utm24, punkt=punkt, x=x, y=y, z=None, t=tid, sx=koord[4], sy=koord[5], sz=None, ) nye_koordinater.append(koordinat) n = len(opdaterede_punkter) if n > 0: punktnavne = sorted(list(set(opdaterede_punkter))) if len(punktnavne) > 10: punktnavne[9] = "..." punktnavne[10] = punktnavne[-1] punktnavne = punktnavne[0:10] koordinatoprettelsestekst = ( f"Opdatering af {n} koordinater til {', '.join(punktnavne)}") sagsevent = Sagsevent( id=uuid(), sagsid=sag.id, sagseventinfos=[ SagseventInfo(beskrivelse=koordinatoprettelsestekst) ], eventtype=EventType.KOORDINAT_BEREGNET, koordinater=nye_koordinater, ) fire.cli.firedb.indset_sagsevent(sagsevent, commit=False) sagsgang = opdater_sagsgang(sagsgang, sagsevent, sagsbehandler) flush() # Så tager vi fat på punktinformationerne til_opret = [] til_ret = [] til_sluk = [] punkter_med_oprettelse = set() punkter_med_rettelse = set() punkter_med_slukning = set() # Først, tilknyt regionspunktinfo til nyoprettede punkter for p in nye_punkter: til_opret.append(opret_region_punktinfo(p)) # Find identer for alle punkter, der indgår i revisionen identer = tuple(sorted(set(revision["Punkt"]) - set(["nan", ""]))) fire.cli.print("") fire.cli.print(f"Behandler {len(identer)} punkter") # Så itererer vi over alle punkter for ident in identer: fire.cli.print(ident, fg="yellow", bold=True) # Hent punkt og alle relevante punktinformationer i databasen. # Her er det lidt sværere end for koordinaternes vedkommende: # Ved opdatering af eksisterende punkter vil vi gerne checke # infonøglerne, så vi er nødt til at hente det faktiske punkt, # med tilørende infonøgler, fra databasen try: punkt = fire.cli.firedb.hent_punkt(ident) infonøgler = { info.objektid: i for i, info in enumerate(punkt.punktinformationer) } except NoResultFound as ex: fire.cli.print( f"FEJL: Kan ikke finde punkt {ident}!", fg="yellow", bg="red", bold=True, ) fire.cli.print(f"Mulig årsag: {ex}") sys.exit(1) # Hent alle revisionselementer for punktet fra revisionsarket rev = revision.query(f"Punkt == '{ident}'") for r in rev.to_dict("records"): if r["Attribut"] in sridnavne: continue if r["id"] == 999999: continue if r["id"] == -1: continue pitnavn = r["Attribut"] if pitnavn == "": continue if r["Sluk"] and r["Ny værdi"]: fire.cli.print( f" * FEJL: 'Sluk' og 'Ny værdi' begge udfyldt: {r['Ny værdi']}", fg="red", bold=False, ) continue if r["Tekstværdi"] != "" and r["Tekstværdi"] == r["Ny værdi"]: fire.cli.print( f" ADVARSEL: Tekst i 'Ny værdi' identisk med udgangspunkt for {pitnavn}.", fg="yellow", bold=True, ) continue if pitnavn is None: fire.cli.print( " * Ignorerer uanført punktinformationstype", fg="red", bold=False, ) continue pit = fire.cli.firedb.hent_punktinformationtype(pitnavn) if pit is None: fire.cli.print( f" * Ignorerer ukendt punktinformationstype '{pitnavn}'", fg="red", bold=True, ) continue # Nyt punktinfo-element? if pd.isna(r["id"]): # ATTR:muligt_datumstabil+slukket == ikke eksisterende i DB # Indsat af fire niv udtræk-revision if pitnavn == "ATTR:muligt_datumstabil" and r["Sluk"]: continue fire.cli.print( f" Opretter nyt punktinfo-element: {pitnavn}") if pit.anvendelse == PunktInformationTypeAnvendelse.FLAG: if r["Ny værdi"]: fire.cli.print( f" BEMÆRK: {pitnavn} er et flag. Ny værdi '{r['Ny værdi']}' ignoreres", fg="yellow", bold=True, ) pi = PunktInformation(infotype=pit, punkt=punkt) elif pit.anvendelse == PunktInformationTypeAnvendelse.TEKST: # Ingen definitiv test her: Tom tekst kan være gyldig. # Men vi sørger for at den ikke er None tekst = r["Ny værdi"] if tekst is None or tekst == "": fire.cli.print( f" ADVARSEL: Tom tekst anført for {pitnavn}.", fg="yellow", bold=True, ) tekst = "" pi = PunktInformation(infotype=pit, punkt=punkt, tekst=tekst) else: try: # Både punktum og komma er accepterede decimalseparatorer tal = float(r["Ny værdi"].replace(",", ".")) except ValueError as ex: fire.cli.print( f" FEJL: {pitnavn} forventer numerisk værdi [{ex}].", fg="yellow", bold=True, ) tal = 0 pi = PunktInformation(infotype=pit, punkt=punkt, tal=tal) til_opret.append(pi) punkter_med_oprettelse.add(ident) continue # Ingen ændringer? - så afslutter vi og går til næste element. if r["Sluk"] == r["Ny værdi"] == "": continue # Herfra håndterer vi kun punktinformationer med indførte ændringer # Nu kan vi bruge objektid som heltal (ovenfor havde vi brug for NaN-egenskaben) oid = int(r["id"]) if r["Sluk"] == "x": try: pi = punkt.punktinformationer[infonøgler[oid]] except KeyError: fire.cli.print( f" * Ukendt id - ignorerer element '{oid}'", fg="red", bold=True, ) continue fire.cli.print(f" Slukker: {pitnavn}") # pi._registreringtil = func.current_timestamp() til_sluk.append(pi) punkter_med_slukning.add(punkt.ident) continue fire.cli.print(f" Retter punktinfo-element: {pitnavn}") if pit.anvendelse == PunktInformationTypeAnvendelse.FLAG: pi = PunktInformation(infotype=pit, punkt=punkt) elif pit.anvendelse == PunktInformationTypeAnvendelse.TEKST: # Fjern overflødigt whitespace og duplerede punktummer tekst = r["Ny værdi"] tekst = re.sub(r"[ \t]+", " ", tekst.strip()) tekst = re.sub(r"[.]+", ".", tekst) pi = PunktInformation(infotype=pit, punkt=punkt, tekst=tekst) else: try: tal = float(r["Ny værdi"]) except ValueError as ex: fire.cli.print( f" FEJL: {pitnavn} forventer numerisk værdi [{ex}].", fg="yellow", bold=True, ) tal = 0 pi = PunktInformation(infotype=pit, punkt=punkt, tal=tal) til_ret.append(pi) punkter_med_rettelse.add(punkt.ident) continue fikspunktstyper = [FikspunktsType.GI for _ in nye_punkter] landsnumre = fire.cli.firedb.tilknyt_landsnumre(nye_punkter, fikspunktstyper) til_opret.extend(landsnumre) for p in nye_punkter: punkter_med_oprettelse.add(p.ident) if len(til_opret) > 0 or len(til_ret) > 0: sagsevent = Sagsevent( id=uuid(), sagsid=sag.id, sagseventinfos=[ SagseventInfo(beskrivelse="Opdatering af punktinformationer") ], eventtype=EventType.PUNKTINFO_TILFOEJET, punktinformationer=[*til_opret, *til_ret], ) fire.cli.firedb.indset_sagsevent(sagsevent, commit=False) sagsgang = opdater_sagsgang(sagsgang, sagsevent, sagsbehandler) flush() if len(til_sluk) > 0: sagsevent = Sagsevent( id=uuid(), sagsid=sag.id, sagseventinfos=[ SagseventInfo(beskrivelse="Lukning af punktinformationer") ], eventtype=EventType.PUNKTINFO_FJERNET, punktinformationer_slettede=til_sluk, ) fire.cli.firedb.indset_sagsevent(sagsevent, commit=False) sagsgang = opdater_sagsgang(sagsgang, sagsevent, sagsbehandler) flush() opret_tekst = f"- oprette {len(til_opret)} attributter fordelt på {len(punkter_med_oprettelse)} punkter" sluk_tekst = f"- slukke for {len(til_sluk)} attributter fordelt på {len(punkter_med_slukning)} punkter" ret_tekst = f"- rette {len(til_ret)} attributter fordelt på {len(punkter_med_rettelse)} punkter" lok_tekst = f"- rette {len(nye_lokationer)} lokationskoordinater" fire.cli.print("") fire.cli.print("-" * 50) fire.cli.print("Punkter færdigbehandlet, klar til at") fire.cli.print(opret_tekst) fire.cli.print(sluk_tekst) fire.cli.print(ret_tekst) fire.cli.print(lok_tekst) spørgsmål = click.style( f"Er du sikker på du vil indsætte ovenstående i {fire.cli.firedb.db}-databasen", fg="white", bg="red", ) if bekræft(spørgsmål): fire.cli.firedb.session.commit() skriv_ark(projektnavn, {"Sagsgang": sagsgang}) else: fire.cli.firedb.session.rollback()
def test_artskode(firedb: FireDb, koordinat: Koordinat): koordinat.artskode = Artskode.TRANSFORMERET firedb.session.commit()
def read(self, sags_id): sag = self.fireDb.hent_sag(sags_id) namespace = "{http://www.gnu.org/software/gama/gama-local-adjustment}" tree = ET.parse(self.input_stream) root = tree.getroot() beregning = Beregning() srid = self.fireDb.hent_srid("EPSG:5799") adjusted_element = root.find(namespace + "coordinates").find(namespace + "adjusted") cov_mat_values = ( root.find(namespace + "coordinates").find(namespace + "cov-mat").findall(namespace + "flt")) original_index_indicies = ( root.find(namespace + "coordinates").find(namespace + "original-index").findall(namespace + "ind")) for idx, point in enumerate(adjusted_element.iter(namespace + "point")): # Read values from the point z = point.find(namespace + "z").text point_id = point.find(namespace + "id").text # Read the correct entry in cov_mat_values cov_mat_index = int(original_index_indicies[idx].text) - 1 cov_mat_element = cov_mat_values[cov_mat_index] # Read value as float cov_mat_value = float(cov_mat_element.text) # .. and tale sqrt to find std_dev std_dev = math.sqrt(cov_mat_value) koordinat = Koordinat() koordinat.srid = srid koordinat.z = z koordinat.sz = std_dev koordinat.punkt = self.fireDb.hent_punkt(point_id) beregning.koordinater.append(koordinat) observation_id_list = [] observations_element = root.find(namespace + "observations") for idx, diff in enumerate( observations_element.iter(namespace + "height-diff")): observationId = diff.get("extern") observation_id_list.append(observationId) observation_list = self.fireDb.hent_observationer(observation_id_list) beregning.observationer.extend(observation_list) self.fireDb.indset_sagsevent( Sagsevent( sag=sag, eventtype=EventType.KOORDINAT_BEREGNET, sagseventinfos=[ SagseventInfo(beskrivelse="Beregning indlæst via GNU Gama") ], beregninger=[beregning], koordinater=beregning.koordinater, ))
def read(self, sags_id): sag = self.fireDb.hent_sag(sags_id) namespace = "{http://www.gnu.org/software/gama/gama-local-adjustment}" tree = ET.parse(self.input_stream) root = tree.getroot() # In the description description_element = root.find(namespace + "description") description = description_element.text # .. find all obervation ids # observation_ids_start = description.find("{observation_ids}") + len("{observation_ids} :") # bservation_ids_end = description.find("{/observation_ids}") # observation_ids = description[observation_ids_start:observation_ids_end] # observation_id_list= ast.literal_eval(observation_ids) # ... and fetch those observations beregning = Beregning() srid = self.fireDb.hent_srid("EPSG:5799") adjusted_element = root.find(namespace + "coordinates").find(namespace + "adjusted") cov_mat_values = ( root.find(namespace + "coordinates").find(namespace + "cov-mat").findall(namespace + "flt")) original_index_indicies = ( root.find(namespace + "coordinates").find(namespace + "original-index").findall(namespace + "ind")) for idx, point in enumerate(adjusted_element.iter(namespace + "point")): # Read values from the point z = point.find(namespace + "z").text point_id = point.find(namespace + "id").text # Read the correct entry in cov_mat_values cov_mat_index = int(original_index_indicies[idx].text) - 1 cov_mat_element = cov_mat_values[cov_mat_index] # Read value as float cov_mat_value = float(cov_mat_element.text) # .. and tale sqrt to find std_dev std_dev = math.sqrt(cov_mat_value) koordinat = Koordinat() koordinat.srid = srid koordinat.z = z koordinat.sz = std_dev koordinat.transformeret = "false" koordinat.punkt = self.fireDb.hent_punkt(point_id) beregning.koordinater.append(koordinat) observation_id_list = [] observations_element = root.find(namespace + "observations") for idx, diff in enumerate( observations_element.iter(namespace + "height-diff")): observationId = diff.get("extern") observation_id_list.append(observationId) observation_list = self.fireDb.hent_observationer(observation_id_list) beregning.observationer.extend(observation_list) self.fireDb.indset_beregning(Sagsevent(sag=sag), beregning)
def test_indset_beregning_invalidates_existing_koordinat( firedb: FireDb, sag: Sag, punkt: Punkt, srid: Srid, observation: Observation): firedb.indset_sagsevent( Sagsevent( sag=sag, sagseventinfos=[ SagseventInfo(beskrivelse="Testindsættelse af observation") ], eventtype=EventType.OBSERVATION_INDSAT, observationer=[observation], )) beregning = Beregning() beregning.observationer.append(observation) koordinat = Koordinat(srid=srid, punkt=punkt, x=0, y=0, z=0, sx=0, sy=0, sz=0) beregning.koordinater.append(koordinat) firedb.indset_sagsevent( Sagsevent( sag=sag, eventtype=EventType.KOORDINAT_BEREGNET, sagseventinfos=[SagseventInfo(beskrivelse="Testberegning")], beregninger=[beregning], koordinater=beregning.koordinater, )) # new beregning of the same observation with a new koordinat beregning2 = Beregning() beregning2.observationer.append(observation) koordinat2 = Koordinat( srid=srid, punkt=punkt, x=1, y=0, z=0, sx=0, sy=0, sz=0, ) beregning2.koordinater.append(koordinat2) firedb.indset_sagsevent( Sagsevent( sag=sag, eventtype=EventType.KOORDINAT_BEREGNET, sagseventinfos=[SagseventInfo(beskrivelse="Testberegning")], beregninger=[beregning2], koordinater=beregning2.koordinater, )) assert len(punkt.koordinater) == 2 assert len([k for k in punkt.koordinater if k.registreringtil is None]) == 1 assert koordinat2.srid is not None