I want to import a GPS textfile to Map 2.0 and create object data
automatically. The data file looks like this:
"x, y, z, value1, value2"
Each point is related to 2 values. value1 and 2 are object data.
I'm looking for a way to write a script, AutoLisp code or something
else to create the points and the object data at the same time
automatically. This is a simple GIS feature so it should be possible.
I only found the ADEATTACHDATA command which is interactive.
Any help is greatly appreciated!
Christian Engelmann
University of applied sciences
Zweibrücken, Germany
I found a good non-programming way to do this, and although it seems
cumbersome, it works.
Create a block with two attributes (value1 and Value2)
Write a script to insert a block at each X,Y,Z point, adding two
attributes e.g.,
Attdia 0
INSERT BLOCK X,Y,Z 1 1 0 VALUE1 VALUE2
Create an object data table with the two fields
Use ADEGENLINK to create object data
It works, even though programmers might laugh!
Cheers,
David Walsh
Hello Christian,
This is certainly possible; I'll leave it to the reader to decide if it's
simple.
This sample has no error checking, and requires strict adherence to this
datafile format: real,real,real,field1,field2
I used this sample data for testing:
==================gpsimport.dat============================
1.0,1.0,1.0,1,a
2.0,2.0,2.0,2,b
3.0,3.0,3.0,3,c
4.0,4.0,4.0,4,d
5.0,5.0,5.0,5,e
6.0,6.0,6.0,6,f
7.0,7.0,7.0,7,g
8.0,8.0,8.0,8,h
9.0,9.0,9.0,9,i
======================eof================================
The following code is terse - in particular the parsefile function is hard
to
follow. Sorry. I pulled it from my bag of tricks without commenting or
elaborating its function.
==================gpsimport.lsp============================
;;;
;;; parse file into list using field/record delimiters
;;;
(defun parsefile (fn fd rd / f k r l)
(setq k "" fd (if (listp fd) fd (list fd)) rd (if (listp rd) rd (list
rd)))
(if (setq f (open fn "r"))
(progn
(while (setq c (read-char f))
(setq c (chr c))
(cond
((member c fd) (setq r (cons k r) k ""))
((member c rd) (setq r (reverse (cons k r)) k "" l (cons r l) r
nil))
(t (setq k (strcat k c)))
)
)
(setq r (reverse (cons k r)) l (cons r l) f (close f))
(reverse l)
)
)
)
;;;
;;; importgps main
;;;
(defun importgps (fn odtable / file)
;; define the od table
(ade_oddefinetab
(list
(cons "tablename" odtable)
'("tabledesc" . "Sample table for Christian")
'("columns"
(("colname" . "Value1") ("coldesc" . "Value 1") ("coltype" .
"character") ("defaultval" . "None"))
(("colname" . "Value2") ("coldesc" . "Value 2") ("coltype" .
"character") ("defaultval" . "None"))
)
)
)
;; parse file into list
(foreach record (parsefile fn "," "\n")
;; sanity check
(if (= 5 (length record))
(progn
;; create point
(entmake (list '(0 . "point") (cons 10 (mapcar 'read (reverse (cddr
(reverse record)))))))
(setq en (entlast))
;; add an od record
(ade_odaddrecord en odtable)
(ade_odsetfield en odtable "Value1" 0 (nth 3 record))
(ade_odsetfield en odtable "Value2" 0 (nth 4 record))
)
)
)
)
;;;
;;; demo command
;;;
(defun c:Christian ()
(importgps (getstring "\nFile to import: " t) (getstring "\nObject Data
table name: " t))
(princ)
)
=========================eof====================================
Cheers-
rdh.
The reason I'm doing this is that I need to link the newly created records to
an Access database, and the "generate links" command doesn't recognize the
point; it seems to work only with blocks that have attached object data.
Thanks for any help, Cheers, Bruce
Hello Bruce (or is it Karen?),
First remember that you can use the 'Convert Object Data to ASE' command
(MAPOD2ASE). This will take ANY object data from ANY object and both
write it out to an external database table of your choice and create the
link
to the new records from the object.
Now to modify the import sample I posted, get out your trusty text editor
and
follow along:
>> This sample has no error checking, and requires strict adherence to this
>> datafile format: real,real,real,field1,field2
Add your additional columns to the data file. I take it that means up to
field8.
The parsefile subroutine is fine as is, but we'll need to alter the
importgps function.
>>
>>
>> ;; define the od table
>> (ade_oddefinetab
>> (list
>> (cons "tablename" odtable)
>> '("tabledesc" . "Sample table for Christian")
>> '("columns"
>> (("colname" . "c1") ("coldesc" . "v1") ("coltype" . "character")
("defaultval" . "None"))
>> (("colname" . "c2") ("coldesc" . "v2") ("coltype" . "character")
("defaultval" . "None"))
;;;; add additional column definitions here for the table
>> )
>> )
>> )
>>
You'll need to add an additional column definition to the table definition
above.
Use the same format the prior two columns - just copy the "c2" line and give
the
copies new names like "c3", "c4", etc.. You may also wish to change the
table
description.
>> ;; sanity check
>> (if (= 5 (length record))
This "sanity check" (really the only error checking at all in the program)
should
be altered to test for the total number of fields expected from your data
file columns.
X,Y,Z coordinate plus 8 data fields should be 11.
>> ;; create point
>> (entmake (list '(0 . "point") (cons 10 (mapcar 'read (reverse
(cddr (reverse record)))))))
This is where each point entity was created - to change this into a block
alter the
code like this:
(entmake (list '(0 . "insert") '(2 . "blockname") (list 10 (nth 0
record)(nth 1 record)(nth 2 record))))
where "blockname" is the name of an existing block in the drawing.
>> ;; add an od record
>> (ade_odaddrecord en odtable)
>> (ade_odsetfield en odtable "c1" 0 (nth 3 record))
>> (ade_odsetfield en odtable "c2" 0 (nth 4 record))
;;;; set the additional columns here for the od record
>> )
>> )
>> )
>> )
You'll need to set the additional column values for the object data record
above.
Use the same format as the prior two lines - just copy the "c2" line and
give the
new lines names like "c3", "c4", etc.. You'll also need to bump the nth
statements
to 5, 6, etc.. respectively.
That should do it.
Cheers-
rdh.
Thanks so much for your help - I'd be lost with out it!
Cheers, Bruce
(I chose not to append those other data columns just yet)
;;;==================gpsimport.lsp============================
;;;
;;; parse file into list using field/record delimiters
;;;
(defun parsefile (fn fd rd / f k r l)
(setq k "" fd (if (listp fd) fd (list fd)) rd (if (listp rd) rd (list
rd)))
(if (setq f (open fn "r"))
(progn
(while (setq c (read-char f))
(setq c (chr c))
(cond
((member c fd) (setq r (cons k r) k ""))
((member c rd) (setq r (reverse (cons k r)) k "" l (cons r l) r
nil))
(t (setq k (strcat k c)))
)
)
(setq r (reverse (cons k r)) l (cons r l) f (close f))
(reverse l)
)
)
)
;;;
;;; importgps main
;;;
(defun importgps (fn odtable / file)
;; define the od table
(ade_oddefinetab
(list
(cons "tablename" odtable)
'("tabledesc" . "Sample table for Bruce")
'("columns"
(("colname" . "Value1") ("coldesc" . "Value 1") ("coltype" .
"character") ("defaultval" . "None"))
(("colname" . "Value2") ("coldesc" . "Value 2") ("coltype" .
"character") ("defaultval" . "None"))
)
)
)
;; parse file into list
(foreach record (parsefile fn "," "\n")
;; sanity check
(if (= 5 (length record))
(progn
;; create blk
(entmake (list '(0 . "insert") '(2 . "circle") (list 10 (nth 0 record)
(nth 1 record)(nth 2 record)))
(setq en (entlast))10
;; add an od record
(ade_odaddrecord en odtable)
(ade_odsetfield en odtable "Value1" 0 (nth 3 record))
(ade_odsetfield en odtable "Value2" 0 (nth 4 record))
)
)
)
)
;;;
;;; demo command
;;;
(defun c:gpsimport ()
...
>
Looks like a closing parenthesis somehow got omitted in your version.
Add one more ")" to the entmake line. Also, I see a strange "10" on the
end of following line. Perhaps it's just a typo, but make sure your real
version doesn't have it.
That should do it.
rdh.
Oops,
I see the additional problem in my suggested code. I failed to convert
the point triplets from string into reals needed by entmake. Here's a
working version. Note the added READs in 10 list:
;; create blk
(entmake
(list
'(0 . "insert")
'(2 . "circle")
(list
10
(read (nth 0 record))
(read (nth 1 record))
(read (nth 2 record))
)
)
)
(setq en (entlast))
That will teach me not to test first... sorry for the runaround.
rdh.
;; create block
(entmake (list '(0 .
"insert") '(2 . "circle") (list 10(nth 0 record)
(nth 1 record)(nth 2 record))))
(setq en (entlast))
We're not worrying about increasing the number of records to attach just yet. "circle" is the name of the block created in the drawing in which we are trying to run the routine-correct per the instructions.? When the routine is run it returns the error message "bad entmake list value." Thanks for your patience.
Cheers, Bruce