Adding CvDbPoints to DWG

Adding CvDbPoints to DWG

Do I need to create a AcDbGeoData then transform the positions?
What’s the difference between setPosition and setEasting, setNorthing?

I assume that the position is the dwg coordinate and Easting, Northing are just labels?

Or should I just go back to drawing cabinets LOL!

import traceback
from pyrx_imp import Rx
from pyrx_imp import Ge
from pyrx_imp import Gi
from pyrx_imp import Gs
from pyrx_imp import Db
from pyrx_imp import Ap
from pyrx_imp import Ed
from pyrx_imp import Cv
import math

import requests
import pandas as pd
import geopandas as gpd

print("added command - AddTin")
print("added command - addreferencepoints")

# debug
def PyRxCmd_pydebug() -> None:
import PyRxDebug
PyRxDebug.startListener()

def getGeoDataId(db: Db.Database) -> Db.ObjectId:
if not Db.Core.hasGeoData(db):
data = Db.GeoData()
data.setBlockTableRecordId(db.modelSpaceId())
return data.postToDb()
return Db.Core.getGeoDataObjId(db)

def makeGeoDataFrame() -> gpd.GeoDataFrame:
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()
return gpd.GeoDataFrame(data["elements"])

def PyRxCmd_AddTin():
try:
db = Db.curDb()
geoDataId = getGeoDataId(db)
if geoDataId.isNull():
return
geoData = Db.GeoData(geoDataId, Db.OpenMode.kForWrite)
geoData.setCoordinateSystem("WORLD-MERCATOR")
gdf = makeGeoDataFrame()

elev = 0.0 # how?
pnts = []
for index, row in gdf.iterrows():
pnts.append(geoData.transformFromLonLatAlt(Ge.Point3d(row.lat, row.lon, elev)))
#pnts.append(geoData.transformToLonLatAlt(Ge.Point3d(row.lat, row.lon, elev)))

extents = Db.Extents()
extents.addPoints(pnts)
surf = Cv.CvDbTinSurface()
surf.setDatabaseDefaults(db)
surf.initialize(extents.minPoint(), extents.maxPoint(), len(pnts))
surf.addPoints(pnts)
db.addToModelspace(surf)

except Exception as err:
traceback.print_exception(err)


def PyRxCmd_addreferencepoints():
try:
gdf = gdf = makeGeoDataFrame()
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("WORLD-MERCATOR")

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))

#transform?
tp = geoData.transformFromLonLatAlt(Ge.Point3d(row.lat,row.lon,0))
#tp = geoData.transformToLonLatAlt(Ge.Point3d(row.lat,row.lon,0))
cpoint.setPosition(tp)

model.appendAcDbEntity(cpoint)

except Exception as err:
traceback.print_exception(err)
no transformation:


with transformation:



Comments

  • DFLY
    edited March 13
    I'm not sure what you want to do.
    If you just want to import points from a CSV file here is a code in LISP that should do the job.
    (defun c:importcsv () (alert "FOR THIS TO WORK YOU NEED TO HAVE THE CSV FILE IN THE SAME LOCATION AS YOUR DRAWING") (MakePointMarker) (getcsv) ) (defun interpretcsv () ; This sets the columns you want to import from the csf (setq eastcolumn (getint "\n SELECT THE COLUMN NUMBER FOR EASTINGS")) (setq northcolumn (getint "\n SELECT THE COLUMN NUMBER FOR NORTHINGS")) ) ;CREATE A POINT MARKER BLOCK. JUST A CROSS WITH A CIRCLE (defun MakePointMarker () (if (not (tblsearch "block" "pointmarker") ) (progn (setvar "insunits" 6) ; setts the drawing units to metres. All sruveys are in metres. (command "line" "0.0,-1.0" "0.0, 1.0" "") (setq line1 (entlast)) (command "line" "-1.0,0.0" "1.0,0.0" "") (setq line2 (entlast)) (command "circle" "0.0,0.0" "0.5") (setq circle1 (entlast)) (command "block" "PointMarker" "0.0,0.0" line1 line2 circle1 "" ) ;(alert "BLOCK CREATED") ) ) ) ;Get get the current drawing directory and allow operator to choose the name of the csv file to import (defun getcsv ( / dirc filen ff) (setq dirc (getvar "dwgprefix")) ;"current directory" (setq filen (getstring "\ENTER FILE NAME")) ; Allows operator to enter the name of the csv file to load (setq files (strcat dirc filen ".csv")) ; adds .csv to file name (print "FILE NAME") (print files) (interpretcsv);Calls the function to allow operator to specify columns that contain eastings and northings (LM:readcsv files) ) ;; Read CSV - Lee Mac ;; Parses a CSV file into a matrix list of cell values. ;; csv - [str] filename of CSV file to read (defun LM:readcsv ( csv / des lst sep str ) (if (setq des (open csv "r")) (progn (setq sep (cond ((vl-registry-read "HKEY_CURRENT_USER\\Control Panel\\International" "sList")) (","))) (while (setq str (read-line des)) (setq lst (cons (LM:csv->lst str sep 0) lst)) ) (close des) ) ) (reverse lst) (setq coordlist lst) (placepoints coordlist) ) ;; CSV -> List - Lee Mac ;; Parses a line from a CSV file into a list of cell values. ;; str - [str] string read from CSV file ;; sep - [str] CSV separator token ;; pos - [int] initial position index (always zero) (defun LM:csv->lst ( str sep pos / s ) (cond ( (not (setq pos (vl-string-search sep str pos))) (if (wcmatch str "\"*\"") (list (LM:csv-replacequotes (substr str 2 (- (strlen str) 2)))) (list str) ) ) ( (or (wcmatch (setq s (substr str 1 pos)) "\"*[~\"]") (and (wcmatch s "~*[~\"]*") (= 1 (logand 1 pos))) ) (LM:csv->lst str sep (+ pos 2)) ) ( (wcmatch s "\"*\"") (cons (LM:csv-replacequotes (substr str 2 (- pos 2))) (LM:csv->lst (substr str (+ pos 2)) sep 0) ) ) ( (cons s (LM:csv->lst (substr str (+ pos 2)) sep 0))) ) ) (defun LM:csv-replacequotes ( str / pos ) (setq pos 0) (while (setq pos (vl-string-search "\"\"" str pos)) (setq str (vl-string-subst "\"" "\"\"" str pos) pos (1+ pos) ) ) str );; Read CSV - Lee Mac ;; Parses a CSV file into a matrix list of cell values. ;; csv - [str] filename of CSV file to read (defun placepoints(coordlist) (foreach pointset coordlist (print "pointset" ) (print pointset) (setq easting (nth (1- eastcolumn ) pointset)) ;selects the atom that corresponds to the csv column (1- is used bucaus nth 0 is first atom) (setq northing (nth (1- northcolumn) pointset));selects the atom that corresponds to the csv column (1- is used bucaus nth 0 is first atom) (if (and (vl-string->list easting) (vl-string->list northing) ) (progn (setq coordinate (strcat easting "," northing )) ;turns eastings and northings into one string variable to be put into command. (command "insert" "PointMarker" coordinate "1.0" "1.0" "0.0" ) ;^C is equal to the escape key, avoids bugs by pressin escape at the end of this command ) ) ) ;(foreach pointset coordlist (print pointset)) )

    Sorry about the jumbled format. Don't know why that happened.
  • Another is use "CIVIL SITE DESIGN" has way more than import points, Survey, surfaces, Road, Sewer, Drainage design etc and works inside Bricscad.
  • DFLY said:

    I'm not sure what you want to do.

    I just finished wrapping most all of the BRX Civil space in Python.
    Now it’s possible to insert geometry from a variety of sources, Spatialite, Shapely, GeoPandas, Web API’s, etc.

    So mostly I’m just writing tests, making sure things work. I have no intention of doing actual civil work, all though I do find it fascinating.

    - A civil point has two inputs. Position as X Y Z, and East, North, Elev. My question is… what’s the difference and how does setting one affect the other, or are they the same?

    - Also, I assume the Civil guys need to have a transformation class of some sorts. Example, where an X, Y, Z of a block reference can be exported and have its coordinates transformed from drawing units to lat, lon , elev. AcDbGeoData has a transform, I was just wandering how to use it

    There’s also GDAL, but it currently won’t load into BricsCAD due to library conflict. But I assume geospatial data could/should be transformed as well

    Basically, I’m just goofing off


  • @Its_Alive
    elev = 0.0 # how?

    this could be a sample of fetching elevations for single points online with accuracy +-15m. For some regions in the world exist higher accuracy datasets (BKG, Swisstopo).
    import requests
    import json
    
    def get_elevation(x):
       url = 'https://api.opentopodata.org/v1/aster30m?'
       # url = 'https://api.open-elevation.com/api/v1/lookup?'
       params = {'locations': f"{x[0]},{x[1]}"}
       result = requests.get(url, params)
       return result.json()['results'][0]['elevation']
    
    print(get_elevation([56.0,123.0]))
    P.S.: I really appreciate your PyRx project marrying Python and BCAD. I hope it'll be taken up by others. Looking at the magnitude of possibilites it is a way forward to me as an end user. Unfortunately I'll never get around to the LISP syntax (evolution level too low).
  • Terry Dotson
    edited March 13
    Its_Alive said:

    A civil point has two inputs. Position as X Y Z, and East, North, Elev. My question is… what’s the difference and how does setting one affect the other, or are they the same?

    Yes, they are the same: X = Easting Y = Northing Z = Elevation

    It was likely primarily added for compatibility and to conform with a train of thought if the coder had a mapping background. Later on a GridNorthing and GridEasting may come along providing some thought.
    Its_Alive said:

    There’s also GDAL, but it currently won’t load into BricsCAD due to library conflict.

    You will find GDAL302.dll already exists in BricsCADs top folder. I've heard of similar problems of those attempting to use GDAL inside 'ProductA'.
  • Awesome, Thanks for the info!

    GDAL-3.8.4 is the python binding I have installed currently; it runs fine on all platforms but BricsCAD
    I'm not compiling it, its just the latest from https://pypi.org/project/GDAL/

    3.0 is from 2019, maybe bricsys can at least upgrade : )
  • @Its_Alive I confirm that the code sample is working with 1.2.003.20240314. The alternative sample crashes
  • Re lat long etc its a bit of can of worms as the earth is not round, just close. In say CIV3D you enter a zone value MGA 55 etc I am not a surveyor so the formula when reading in point values does translations.

    So CIV3D has the option read Lat/long which can make life easier, played with read and place mobile phone photos on a real world map so could see where they were taken.

    There is a bit of Lat.long to XYZ around but you must know your zone values. Get it wrong and working in US may give a point here in AUS. Like wise can take local XYZ and do a translation, scaling and rotation to true world co-ordinates. Our guys did that every day.