CEXT-Dan / PyRx

Python for AutoCAD
42 stars 7 forks source link

Sample for use of GeoData #11

Closed schoeller closed 5 months ago

schoeller commented 5 months ago

Dear all,

thanks for this opensource. I am trying to attach georeference to a drawing as follows:

from pyrx_imp import Rx
# from pyrx_imp import Ge
# from pyrx_imp import Gi
from pyrx_imp import Db
# from pyrx_imp import Ap
# from pyrx_imp import Ed
# from pyrx_imp import Gs
from pyrx_imp import Cv

import requests
import pandas as pd
import geopandas as gpd

print("added command - do_addreferencepoints")

url = "https://overpass-api.de/api/interpreter"
query = """
    [out:json];

    area(id:3600062650)->.dt;
    (
        node["triangulation_point"](area.dt);
        node["survey_point"](area.dt);
        node["man_made"="survey_point"](area.dt);
    );
    out geom;
"""
response = requests.get(url, params={'data': query})
data = response.json()

gdf = gpd.GeoDataFrame(data['elements'])
# print(gdf.head())

def PyRxCmd_do_addreferencepoints():
    try:
        db = Db.HostApplicationServices().workingDatabase()
        model = Db.BlockTableRecord(db.modelSpaceId(), Db.OpenMode.kForWrite)
        geoDataId = Db.Core.getGeoDataObjId(db)
        if geoDataId.isNull():
            return
        geoData = Db.GeoData(geoDataId)        
        geoData.setCoordinateSystem('4326')

        for index, row in gdf.iterrows():
            cpoint = Cv.CvDbPoint()
            cpoint.setDatabaseDefaults()
            cpoint.setNumber(index)
            cpoint.setEasting(row.lat)
            cpoint.setNorthing(row.lon)
            cpoint.setElevation(0)
            cpoint.setName(str(row.tags))
            model.appendAcDbEntity(cpoint)

    except Exception as err:
        print(err)

I presume my use of GeoData inadequate, since I receive the message:

: DO_ADDREFERENCEPOINTS

Exception! (eKeyNotFound) in function getGeoDataObjId ,Line 541, File DbCore.cpp: 

Any hints on how to resolve the situation are very much appreciated.

Best regards

Sebastian

CEXT-Dan commented 5 months ago

I just added a new function Db.Core.hasGeoData(db), but until it's released. try this. I could not get setCoordinateSystem to work, I don't know how to use this method may have to ask bricsys

def getGeoDataId(db : Db.Database) -> Db.ObjectId:
    geoDataId = Db.ObjectId()
    try:
        geoDataId = Db.Core.getGeoDataObjId(db)
    except:
        data = Db.GeoData()
        data.setBlockTableRecordId(db.modelSpaceId())
        geoDataId = data.postToDb()
    return geoDataId

def PyRxCmd_do_addreferencepoints():
    try:
        db = Db.HostApplicationServices().workingDatabase()
        model = Db.BlockTableRecord(db.modelSpaceId(), Db.OpenMode.kForWrite)
        geoDataId = getGeoDataId(db)
        if geoDataId.isNull():
            return
        geoData = Db.GeoData(geoDataId, Db.OpenMode.kForWrite)   
        #geoData.setCoordinateSystem('WGS84')

        for index, row in gdf.iterrows():
            cpoint = Cv.CvDbPoint()
            cpoint.setDatabaseDefaults()
            cpoint.setNumber(index)
            cpoint.setEasting(row.lat)
            cpoint.setNorthing(row.lon)
            cpoint.setElevation(0)
            cpoint.setName(str(row.tags))
            model.appendAcDbEntity(cpoint)

    except Exception as err:
        print(err)
CEXT-Dan commented 5 months ago

The function does work i.e. geoData.setCoordinateSystem('WORLD-MERCATOR')

there's a database of coordinate systems here \AppData\Roaming\Bricsys\BricsCAD\V24x64\en_US\Support\geodatabase.xml

I have no idea how to use it though

CEXT-Dan commented 5 months ago

just to add geoData has transformation functions, I don't know how to use them https://help.autodesk.com/view/OARX/2024/ENU/?guid=OARX-ManagedRefGuide-__OVERLOADED_TransformToLonLatAlt_Autodesk_AutoCAD_DatabaseServices_GeoLocationData

        for index, row in gdf.iterrows():
            cpoint = Cv.CvDbPoint()
            cpoint.setDatabaseDefaults()
            cpoint.setNumber(index)
            cpoint.setEasting(row.lat)
            cpoint.setNorthing(row.lon)
            cpoint.setElevation(0)
            cpoint.setName(str(row.tags))
            tp = geoData.transformToLonLatAlt(Ge.Point3d(row.lat,row.lon,0))#
            cpoint.setPosition(tp)#
            model.appendAcDbEntity(cpoint)
CEXT-Dan commented 5 months ago

I noticed I missed AcDbGeoCoordinateSystem class, I'm wrapping it now

schoeller commented 5 months ago

It seems that WKT definitions and XML definitions may be used for coordinate systems. I have started trying to attach to pycrs in order to refer to EPSG codes (www.epsg.io). Every nations and some companies even have several coordinate systems, so it's a jungle.

import pycrs

crs = pycrs.parse.from_epsg_code(3395)
print(crs.to_ogc_wkt())

outputs

PROJCS["Unknown", GEOGCS["Unknown", DATUM["WGS_1984", SPHEROID["WGS_1984", 6378137.0, 298.257223563]], PRIMEM["Greenwich", 0], UNIT["degree", 0.017453292519943295], AXIS["Lon", EAST], AXIS["Lat", NORTH]], PROJECTION["Mercator"], PARAMETER["Central_Meridian", 0], PARAMETER["false_easting", 0], PARAMETER["false_northing", 0], PARAMETER["scale_factor", 1], UNIT["Meters", 1.0], AXIS["X", EAST], AXIS["Y", NORTH]]

geodatabase.xml reads

<CRS epsg="3395" name="WGS 84 / World Mercator" codeSpace="OGP" x="Easting" y="Northing" prime="0" proj="MercB" Lon="0" Lat1="0" FE="0" FN="0" unitsCode="1" unitsName="Meter" unitsScale="1">
            <Datum epsg="6326" alias="WGS84" id="WORLD-MERCATOR" pjcode="6" />
            <GeoBoundingBox type="WGS84" west="-180" east="180" south="-85" north="85" />
            <informationSource>OGP</informationSource>
            <scope>Very small scale mapping.</scope>
            <remarks>Euro-centric view of world excluding polar areas.</remarks>

They do not coincide. Maybe one may use getWktRepresentation in combination with pycrs to achieve the desired result. So plodding on...