Exemple #1
0
    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()
Exemple #2
0
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
Exemple #3
0
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()
Exemple #4
0
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
Exemple #6
0
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
Exemple #7
0
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)
Exemple #8
0
 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
Exemple #9
0
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
Exemple #10
0
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
Exemple #11
0
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)
Exemple #12
0
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
Exemple #14
0
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
Exemple #15
0
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'"
                )
Exemple #16
0
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()
Exemple #17
0
def test_artskode(firedb: FireDb, koordinat: Koordinat):
    koordinat.artskode = Artskode.TRANSFORMERET
    firedb.session.commit()
Exemple #18
0
    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,
            ))
Exemple #19
0
    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)
Exemple #20
0
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