# -*- coding: iso-8859-7 -*-
import sys
import p_ggen
from thanimpdxf import ThanImportDxf
def _prt(s):
"This function consumes a string that should be printed, but prints nothing."
pass
class ThanDrIgnore:
"A class which ignores the elements read by ThanImportDxf."
def __init__(self, prt=p_ggen.prg):
if prt == None: self.prt = _prt # No message will be printed
else: self.prt = prt
def dxfVport (self, name, x1, y1, x2, y2): pass
def dxfXymm (self, x1, y1, x2, y2): pass
def dxfLayer (self, name, atts): pass
def dxfLtype (self, name, desc, elems): pass
def dxfPolyline(self, xx, yy, zz, lay, handle, col): pass
def dxfLine (self, xx, yy, zz, lay, handle, col): pass
def dxfCircle (self, xx, yy, zz, lay, handle, col, r):pass
def dxfPoint (self, xx, yy, zz, lay, handle, col): pass
def dxfArc (self, xx, yy, zz, lay, handle, col, r, theta1, theta2): pass
def dxfText (self, xx, yy, zz, lay, handle, col, text, h, theta): pass
def dxfBlockAtt(self, xx, yy, zz, lay, handle, col, blname, blatts): pass
def dxfThanImage(self, xx, yy, zz, lay, handle, col, filnam, size, ale, theta): pass
def dxf3dface (self, xx, yy, zz, lay, handle, col): pass
class ThanDrLayer(ThanDrIgnore):
"A class which saves layers and ignores anything else."
def __init__(self, *args, **kw):
"Initialize layer container."
ThanDrIgnore.__init__(self, *args, **kw)
self.layer = {}
def dxfLayer (self, name, atts):
"Collect the layers."
self.layer[name] = atts
class ThanDrWarn:
"""A class which warns about unknown object/layer pairs.
I think that this is the safest class to derive from. If new functionality is
added to the library, this class will be updated. So the derived classes will
dynamically inherit and they will produce warnings about things not implemented,
or not accessed, or ignored.
"""
def __init__(self, laykno=None, prt=p_ggen.prg):
"Set known and unknown layers."
self._objunk = {}
self._functy = {}
self._laykno = {}
self._layunk = {}
self._allLayKno = False
if laykno == "*":
self._allLayKno = True
elif laykno != None:
for lay in laykno: self._laykno[lay] = 0
if prt == None: self.prt = _prt # No message will be printed
else: self.prt = prt
def warnObj(self, lay, obj):
"Warn once if an unknown object/layer pair is found."
if self._allLayKno or lay in self._laykno:
m = self._objunk.get((obj, lay), 0) + 1
self._objunk[obj, lay] = m
if m > 1: return
self.prt("Dxf import Warning: (duplicate) objects of type '%s'" % obj)
self.prt(" are ignored in layer %s." % lay)
else:
m = self._layunk.get(lay, 0) + 1
self._layunk[lay] = m
if m > 1: return
self.prt("Dxf import Warning: layer %s will be ignored." % lay)
def warnFuncty(self, functyname):
"Warn once for every unimplemented type of functionality."
n = self._functy.get(functyname, 0) + 1
self._functy[functyname] = n
if n > 1: return
self.prt("Dxf import Warning: %s will be ignored." % functyname)
def dxfVport (self, name, x1, y1, x2, y2): self.warnFuncty("Viewport definition")
def dxfXymm (self, x1, y1, x2, y2): self.warnFuncty("Extents definition")
def dxfLayer (self, name, atts): self.warnFuncty("Layer definition")
def dxfLtype (self, name, desc, elems): self.warnFuncty("Line type definition")
POLYLINE = "polyline"
LINE = "line"
CIRCLE = "circle"
POINT = "point"
ARC = "arc"
TEXT = "text"
BLOCK = "block"
IMAGE = "image"
FACE3D = "3dface"
def dxfPolyline (self, xx, yy, zz, lay, handle, col): self.warnObj(lay, self.POLYLINE)
def dxfLine (self, xx, yy, zz, lay, handle, col): self.warnObj(lay, self.LINE)
def dxfCircle (self, xx, yy, zz, lay, handle, col, r): self.warnObj(lay, self.CIRCLE)
def dxfPoint (self, xx, yy, zz, lay, handle, col): self.warnObj(lay, self.POINT)
def dxfArc (self, xx, yy, zz, lay, handle, col, r, theta1,
theta2): self.warnObj(lay, self.ARC)
def dxfText (self, xx, yy, zz, lay, handle, col, text, h, theta): self.warnObj(lay, self.TEXT)
def dxfBlockAtt (self, xx, yy, zz, lay, handle, col, blname, blatts): self.warnObj(lay, self.BLOCK)
def dxfThanImage(self, xx, yy, zz, lay, handle, col, filnam, size,
scale, theta): self.warnObj(lay, self.IMAGE)
def dxf3dface (self, xx, yy, zz, lay, handle, col): self.warnObj(lay, self.FACE3D)
class ThanDrLine(ThanDrWarn):
"A class which gets only lines/polylines; it is an example of ThanDrWarn usage."
def dxfPolyline (self, xx, yy, zz, lay, handle, col):
"Get polyline if it is in known layers."
if self._allLayKno or lay in self._laykno:
self.processLine(xx, yy, zz, lay, handle, col)
else:
self.warnObj(lay, self.POLYLINE)
def dxfLine (self, xx, yy, zz, lay, handle, col):
"Get line if it is in known layers."
if self._allLayKno or lay in self._laykno:
self.processLine(xx, yy, zz, lay, handle, col)
else:
self.warnObj(lay, self.LINE)
def processLine(self, xx, yy, zz, lay, handle, col):
"What to do with the line/polyline; overwrite it."
self.prt("Line x1=%.3f y1=%.3f z1=%.3f ... in layer=%s" % (xx[0], yy[0], zz[0], lay))
class ThanDrSave:
"A class which stores the elements read by ThanImportDxf."
def __init__(self, prt=p_ggen.prg):
"Creates an instance of the class."
if prt == None: self.prt = _prt # No message will be printed
else: self.prt = prt
self.thanVports = [ ]
self.thanLayers = [ ]
self.thanLtypes = [ ]
self.thanXymm = None
self.thanPolylines = [ ]
self.thanLines = [ ]
self.thanCircles = [ ]
self.thanPoints = [ ]
self.thanArcs = [ ]
self.thanTexts = [ ]
self.thanBlocks = []
self.thanImages = []
self.than3dfaces = []
def dxfVport(self, name, x1, y1, x2, y2):
"Saves a View Port."
self.thanVports.append((name, x1, y1, x2, y2))
def dxfXymm(self, x1, y1, x2, y2):
"Saves xmin,ymin,xmax,ymax of the dxf drawing."
self.thanXymm = x1, y1, x2, y2
def dxfLayer(self, name, atts):
"Saves a layer."
self.thanLayers.append((name, atts))
def dxfLtype(self, name, desc, elems):
"Saves a line type."
self.thanLtypes.append((name, desc, elems))
def dxfPolyline(self, xx, yy, zz, lay, handle, col):
"Saves a polyline."
self.thanPolylines.append((xx, yy, zz, lay, col))
def dxfLine(self, xx, yy, zz, lay, handle, col):
"Saves a line."
self.thanLines.append((xx, yy, zz, lay, col))
def dxfCircle(self, xx, yy, zz, lay, handle, col, r):
"Saves a View Port."
self.thanCircles.append((xx, yy, zz, lay, col, r))
def dxfPoint(self, xx, yy, zz, lay, handle, col):
"Saves a point."
self.thanPoints.append((xx, yy, lay, col))
def dxfArc(self, xx, yy, zz, lay, handle, col, r, theta1, theta2):
"Saves a point."
self.thanArcs.append((xx, yy, lay, col, r, theta1, theta2))
def dxfText(self, xx, yy, zz, lay, handle, col, text, h, theta):
"Saves a text."
self.thanTexts.append((xx, yy, lay, col, text, h, theta))
def dxfBlockAtt(self, xx, yy, zz, lay, handle, col, blname, blatts):
"Saves a block insertion."
self.thanBlocks.append((xx, yy, zz, lay, col, handle, col, blname, blatts))
def dxfThanImage(self, xx, yy, zz, lay, handle, col, filnam, size, scale, theta):
"Saves an ThanImage."
self.thanImages.append((xx, yy, zz, lay, col, handle, filnam, size, scale, theta))
def dxf3dface (self, xx, yy, zz, lay, handle, col):
"Saves a 3dface."
self.than3dfaces.append((xx, yy, zz, lay, handle, col))
def statistics(self):
"Saves a text."
self.prt("Contents of dxf file:")
n = ""
if self.thanXymm == None: n = "NOT"
self.prt("Max, min of x,y : %s defined in dxf file" % n)
self.prt("Number of view ports: %d" % len(self.thanVports))
self.prt("Number of layers : %d" % len(self.thanLayers))
self.prt("Number of line types: %d" % len(self.thanLtypes))
self.prt("Number of polylines : %d" % len(self.thanPolylines))
self.prt("Number of lines : %d" % len(self.thanLines))
self.prt("Number of texts : %d" % len(self.thanTexts))
self.prt("Number of points : %d" % len(self.thanPoints))
self.prt("Number of circles : %d" % len(self.thanCircles))
self.prt("Number of arcs : %d" % len(self.thanArcs))
self.prt("Number of blocks ins: %d" % len(self.thanBlocks))
self.prt("Number of thanImages: %d" % len(self.thanImages))
self.prt("Number of 3dfaces : %d" % len(self.than3dfaces))
class ThanDrConpas(ThanDrWarn):
"A class which gets control/pass points from a .dxf file."
def __init__(self, filnam="<undefined>", ctype="noname", layer="fotost", prt=p_ggen.prg):
"""Sets the type of points and the layers to serach.
If type == "noname" then x, y, z coordinates of all points plus an
arbitrary name are returned.
If type == "pixel" then x, y, z coordinates of all points are returned.
Furthermore, the program looks for texts and finds the closest text to
a point, and considers it as the point's name. As a precaution, this
point must also be the closest point to the text found, or else there
is ambiguity and the program returns an error. The texts must not
contain the character '/'.
If type == "EGSA87" then x, y coordinates of all points are returned.
Furthermore, the program looks for texts and finds the closest text to
a point, and considers it as the point's name. As a precaution, this
point must also be the closest point to the text found, or else there
is ambiguity and the program returns an error. The texts must
contain the character '/' and after this the z coordinate of the point
for example "Point1/123.457". This z is returned.
if layer == "*" all the layers are searched. Else only the layer with name
the content of the variable layer is searched.
"""
self.layer = layer.lower()
ThanDrWarn.__init__(self, self.layer, prt=prt)
self.cxypix = [] # pixel coordinates of control points
self.cname = [] # names of control points
self.filnam = filnam # Name of the dxf file
self.ctype = ctype # Coordinate system type: pixel, EGSA87, or noname
def dxfPoint(self, xx, yy, zz, lay, handle, col):
"Selects the polylines only in certain layers."
if self.layer == "*" or self.layer == lay.lower():
self.cxypix.append([None, xx, yy, zz])
else:
self.warnObj(lay, self.POINT)
def dxfText(self, xx, yy, zz, lay, handle, col, t, h, theta):
"Selects the circle of layer plaisio; its center is the origin point."
if self.layer == "*" or self.layer == lay.lower():
self.cname.append((t, xx, yy))
else:
self.warnObj(lay, self.TEXT)
def findHeight(self):
"Tests and finds the height for the EGSA87 coordinates, or put zero height for pixel coordinates."
if self.ctype == "nonamez":
for j,(t,xt,yt) in enumerate(self.cname):
try:
ht = float(t)
except ValueError, IndexError:
self.prt("Error in file %s: Illegal height '%s':" % (self.filnam, t))
self.prt("The height must be a numeic value.")
self.prt("For example: '128.89' or '12.989'")
raise ThanImportError
self.cname[j] = "noname", xt, yt, ht
elif self.ctype != "pixel":
for j,(t,xt,yt) in enumerate(self.cname):
try:
t1, t2 = t.split("/")
ht = float(t2)
except ValueError, IndexError:
self.prt("Error in file %s: Illegal point name '%s':" % (self.filnam, t))
self.prt("The point should be of the form:")
self.prt(" <name> / <height>")
self.prt("For example: 'P1 / 128.89' or '1/12.989'")
raise ThanImportError
self.cname[j] = t1.strip(), xt, yt, ht
else:
for j,(t,xt,yt) in enumerate(self.cname):
try:
t1, t2 = t.split("/")
ht = float(t2)
except ValueError, IndexError:
pass
else:
self.prt("Warning in file %s: It seems that you defined height to point '%s':" % (self.filnam, t))
self.prt(" The point should NOT be of the form:")
self.prt(" <name> / <height>")
self.prt(" Please remove the height from the point.")
self.cname[j] = t.strip(), xt, yt, 0.0
def corNameHeight(self):
"Correlates names with points; the name of a point is the closest text to it."
for i,(aa,x,y,h) in enumerate(self.cxypix):
if len(self.cname) < 1:
self.prt("Error in file %s: Point with %s coordinates %.1f %.1f:" % (self.filnam, self.ctype, x,y))
self.prt("The name and/or the height of this point was not defined.")
self.prt("(The number of point names and/or heights is less than the number of points!)")
raise ThanImportError
ds = [((x-xt)**2+(y-yt)**2, j) for j,(t,xt,yt,ht) in enumerate(self.cname)]
d, j = min(ds); t,xt,yt,ht = self.cname[j]
ds = [((x1-xt)**2+(y1-yt)**2, i1) for i1,(aa1,x1,y1,h1) in enumerate(self.cxypix) if aa1 == None]
d, i1 = min(ds)
if i1 != i:
self.prt("Error in file %s: Point with %s coordinates %.1f %.1f:" % (self.filnam, self.ctype, x,y))
self.prt("The name and/or height of this point was probably not defined.")
self.prt("The nearest name and/or height to this point is: '%s' but it was found to refer to" % t)
self.prt("point with pixel coordinates %.1f %.1f" % (x1,y1))
raise ThanImportError
self.cxypix[i][0] = t
if self.ctype != "pixel": self.cxypix[i][3] = ht
del self.cname[j]
if len(self.cname) > 0:
self.prt("Warning in file %s: The number of points is less than the number of point names" % self.filnam)
self.prt("and/or heights. The following point names and/or heights do not refer to any point:")
if self.ctype == "nonamez":
for t,xt,yt,ht in self.cname: self.prt(str(ht))
else:
for t,xt,yt,ht in self.cname: self.prt(t)
def addName(self):
"Adds suitable name to simple points."
i = 1
for c in self.cxypix:
c[0] = str(i)
i += 1
def thanDxfGetConpas(fdxf, ctype, layer="fotost", prt=p_ggen.prg):
"Reads the coordinates of the control points from dxf file."
dr = ThanDrConpas(fdxf.name, ctype, layer, prt)
t = ThanImportDxf(fdxf, dr)
t.thanImport()
if ctype == "noname":
dr.addName()
elif ctype == "nonamez":
dr.findHeight()
dr.corNameHeight()
dr.addName()
else:
dr.findHeight()
dr.corNameHeight()
return dr.cxypix
def testThanDxfGetConpas():
"Test dxf import of named points."
f = open("trap.dxf", "r")
cxypix = thanDxfGetConpas(f, "pixel")
for a,x,y,h in cxypix:
print "%10s%15.3f%15.3f%15.3f" % (a,x,y,h)
f = open("trap.dxe", "r")
cxypix = thanDxfGetConpas(f, "EGSA87")
for a,x,y,h in cxypix:
print "%10s%15.3f%15.3f%15.3f" % (a,x,y,h)
def testThanDrSave():
"Test dxf import."
from p_gimdxf import ThanImportDxf,ThanImportError
f = file("116.dxf", "r")
dr = ThanDrSave()
t = ThanImportDxf(f, dr)
t.thanImport()
f.close()
dr.statistics()
def testThanDrLayer():
"Test dxf import."
from p_gimdxf import ThanImportDxf,ThanDrLayer,thanDxfColCode2Rgb
fr = file("shm.dxf", "r")
dr = ThanDrLayer() # Instantiate the object that collects the layers
t = ThanImportDxf(fr, dr) # Instantiate the object which reads the dxf file
t.thanImport() # Read and parse the dxf file
fr.close()
del t
fw = file("shm.csv", "w")
form = "%s\t" * 9 + "\n"
fw.write(form % ("Name", "Autocad Color", "RGB color", "line type", "frozen",
"off", "locked", "lineweight", "noplot"))
for name in dr.layer:
atts = dr.layer[name]
fw.write(form % (name, atts["color"], thanDxfColCode2Rgb[atts["color"]],
atts["linetype"], atts["frozen"], atts["off"], atts["locked"],
atts["lineweight"], atts["noplot"]))
fw.close()
def testThanDrWarn():
"Test dxf import."
from p_gimdxf import ThanImportDxf,ThanImportError
f = file("116.dxf", "r")
dr = ThanDrWarn()
t = ThanImportDxf(f, dr)
t.thanImport()
f.close()
def testThanDrConpas():
"Test dxf import."
from p_gimdxf import ThanImportDxf,ThanImportError
f = file("trap1.dxe", "r")
xy = thanDxfGetConpas(f, ctype="EGSA87", layer="fotost")
for xy1 in xy: print xy1
f.close()
if __name__ == "__main__": testThanDrLayer()
|