plotter/hpgl_parser.py

changeset 32
59da528bc470
parent 20
de60b63b2275
child 34
022e881b758e
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plotter/hpgl_parser.py	Fri Jan 25 21:00:34 2008 +0100
@@ -0,0 +1,451 @@
+# -*- coding: utf-8 -*-
+
+import re
+import numpy
+
+vsplitter = re.compile('[ ,]')
+vextractor = re.compile('(?P<value>[^;\n\r\aA-DF-Za-df-z]*?)(?P<terminator>[;\n\r\a]+)', re.S+re.M) 
+
+class HPGLParser(object):
+    def __init__(self, data=None):
+        self.str_terminator = chr(0x03)
+        self.IN()
+        if data:
+            self.parse(data)
+
+    def parse(self, data):
+        self.data = data
+        self.idx = 0
+        self.IN()        
+        while self.idx<len(data):
+            while data[self.idx] in [';','\n','\r', '\a', ' ']:
+                self.idx += 1
+            if data[self.idx] == chr(0x03):
+                self.ESC()
+            else:
+                cmd = data[self.idx: self.idx+2]
+                self.idx += 2
+                getattr(self, cmd)()
+            while self.idx<len(data) and data[self.idx] in [';','\n','\r', '\a', ' ']:
+                self.idx += 1
+
+    def user_to_abs(self, pos):
+        """
+        converts a position (x, y) given in user units to absolute
+        units
+        """
+        return pos #TODO
+        
+    def extract_value(self, raw=False):
+        m = vextractor.match(self.data[self.idx:])
+        if m:
+            val = m.group("value")
+            self.idx = self.idx + len(val) + len(m.group("terminator"))
+            val = vsplitter.split(val)
+            if not raw:
+                val = [eval(x) for x in val if x.strip()]
+            return val
+        return []
+
+    def extract_string(self):
+        idx2 = self.data.find(self.str_terminator, self.idx)
+        val = self.data[self.idx: idx2]
+        self.idx = idx2+1
+        return val
+
+    def polyline(self, values):
+        if (len(values)%2) == 1:
+            # this is a syntax error in the HPGL data
+            values = values[:-1]
+        values = numpy.array(values).reshape(-1, 2)
+        # TODO use scaling            
+        # do plots 
+        values = numpy.r_[[self.pos], values] #add self.pos as 1st value
+        if self.plot_mode == 'relative':
+            values = values.cumsum(axis=0)
+        if self.symbol_mode:
+            self.plot_symbols(values[1:])
+        if self.pen_state == "down":
+            self.plot_lines(values)
+        self.pos = values[-1]
+
+    def plot_string(self, s):
+        pass
+    
+    def get_window_for_paper(self):
+        return 0,100,0,100
+    def get_scaling_points_for_paper(self):
+        return 0,100,0,100
+        
+    # effective plot methods; to be defined in subclasses (backends)
+    def plot_symbols(self, points):
+        pass
+    def plot_lines(self, points):
+        pass
+        
+    # HPGL-related methods
+    def ESC(self):
+        #print "ESC"
+        self.idx += 1
+
+    def OE(self):
+        """ Output Error """
+        pass
+        
+    def EC(self):
+        """? what's this """
+        values = self.extract_value()
+
+    def OO(self):
+        """idem"""
+        pass
+
+    def OP(self):
+        """idem"""
+        pass
+
+    def VS(self):
+        """idem"""
+        pass
+        
+        
+    def DF(self):
+        """ Default """
+        self.pen = 0
+        self.pen_width = 1 # 1/300 inch
+        self.pos = 0,0
+        self.char_set = "std"
+        self.plot_mode = 'absolute'
+        self.char_direction = 1,0
+        self.line_type = 0 # 'solid'
+        self.pattern_len = 4 #percentage
+        self.window = self.get_window_for_paper()
+        self.char_size = 0.75, 1.5 #percentages
+        self.symbol_mode = False
+        self.tick_len = 0.5, 0.5 # %
+        self.std_char_set = 0
+        self.alt_char_set = 0
+        self.selected_char_set = 0
+        self.char_slant = 0 # degrees
+        self.scale = None
+        self.str_terminator = chr(0x03)
+        self.chord_ang = 5 #degrees
+        self.fill_type = 'bidirectionnal', 1
+        self.fill_distance = 1 # %
+        self.fill_slant = 0 # degrees
+        self.pen_thickness = 0.3 # mm
+
+    def IN(self):
+        """ Initialize """
+        self.DF()
+        self.pen_state = "up"
+        self.rotation = 0 #degrees
+        self.scaling_points = self.get_scaling_points_for_paper()
+
+    def IP(self):
+        """ Input Scale Point"""
+        values = self.extract_value()
+        if len(values) == 0:
+            self.scaling_points = self.get_scaling_points_for_paper()
+        elif len(values) == 2:
+            p1x, p1y, p2x, p2y = self.scaling_points
+            dx, dy = p2x-p1x, p2y-p1y
+            x, y = values
+            self.scaling = (x, y, x+dx, y+dy)
+        elif len(values) == 4:
+            self.values = tuple(values)
+            
+    def SC(self):
+        """ Scale """
+        values = self.extract_value()
+        if len(values) == 4:
+            self.scale = tuple(values)
+        else:
+            self.scale = None
+
+    def IW(self):
+        values = self.extract_value()
+        if len(values) == 0:
+            self.window = self.get_window_for_paper()
+        elif len(value) == 4:            
+            self.window = tuple(values)
+
+    def RO(self):
+        values = self.extract_value()
+        if len(values) == 0:
+            self.rotation = 0
+        elif len(values) == 1:
+            self.rotation = values[0]
+
+    def PG(self):
+        pass
+
+    def PU(self):
+        """ Pen Up"""
+        self.pen_state = "up"        
+        values = self.extract_value()
+        self.polyline(values)
+
+    def PD(self):
+        """ Pen Down """
+        self.pen_state = "down"        
+        values = self.extract_value()
+        self.polyline(values)
+
+    def PA(self):
+        """ Plot Absolute """
+        self.plot_mode = "absolute"        
+        values = self.extract_value()
+        self.polyline(values)
+
+    def PR(self):
+        """ Plot Relative """
+        self.plot_mode = "relative"        
+        values = self.extract_value()
+        self.polyline(values)
+
+    def AA(self):
+        """ Arc Absolute """
+        values = self.extract_value()
+        if len(values) in [3, 4]:
+            x, y, qc = values[:3]
+            if len(values)==4:
+                qd = values[-1]
+            else:
+                qd = self.chord_ang
+            # TODO : plot arc
+            print "plotting an arc"
+    def AR(self):
+        """ Arc Relative """
+        values = self.extract_value()
+        # TODO
+
+    def CI(self):
+        """ Circle Plot"""
+        values = self.extract_value()
+        # TODO
+
+    def EA(self):
+        """Edge Rectangle Absolute"""
+        values = self.extract_value()
+        # TODO
+
+    def ER(self):
+        """Edge Rectangle Relative"""
+        values = self.extract_value()
+        # TODO
+
+    def EW(self):
+        """ Edge Wedge """
+        values = self.extract_value()
+        # TODO
+
+    def RA(self):
+        """ Fill Rectangle Absolute """
+        values = self.extract_value()
+        # TODO
+
+    def RR(self):
+        """ Fill Rectangle Relative """
+        values = self.extract_value()
+        # TODO
+
+    def WG(self):
+        """ Fill Wedge """
+        values = self.extract_value()
+        # TODO
+
+    def FT(self):
+        """ Fill Type """
+        values = self.extract_value()
+        # TODO
+
+    def LT(self):
+        """ Line Type """
+        values = self.extract_value()
+
+        if len(values)==0:
+            self.line_type = 0 #'solid'
+        else:
+            self.line_type = values[0]
+            if len(values)>1:
+                self.pattern_len = values[1]
+
+    def PW(self):
+        """ Pen Width """
+        values = self.extract_value()
+        if len(values) == 1:
+            self.pen_thickness = values[0]
+
+    def SM(self):
+        """ Symbol Mode """
+        values = self.extract_value()
+        if len(values) == 0:
+            self.symbol_mode = False
+        elif len(values) == 1:
+            self.symbol_mode = values[0]
+
+    def SP(self):
+        """ Select Pen """
+        values = self.extract_value()
+        if len(values) == 1:
+            self.pen = values[0]
+
+    def TL(self):
+        """ Tick Len """
+        values = self.extract_value()
+        # TODO
+
+    def XT(self):
+        """ X-axis Tick """
+        # TODO
+        print "X ticks"
+
+    def YT(self):
+        """ X-axis Tick """
+        # TODO
+        print "Y ticks"
+
+    def PT(self):
+        """ Pen Thickness Select """
+        values = self.extract_value()
+        if len(values) == 0:
+            self.pen_thickness = 0.3
+        elif len(values) == 1:
+            self.pen_thickness = values[0]
+
+    def CS(self):
+        """ Standard Character Set """
+        values = self.extract_value()
+        if len(values) == 0:
+            self.std_char_set = 0
+        elif len(values) == 1:
+            self.std_char_set = values[0]
+
+    def CA(self):
+        """ Alternate Character Set """
+        values = self.extract_value()
+        if len(values) == 0:
+            self.alt_char_set = 0
+        elif len(values) == 1:
+            self.alt_char_set = values[0]
+        
+    def SS(self):
+        """ Select Standard Character Set """
+        self.char_set = "std"
+
+    def SA(self):
+        """ Select Alternate Character Set """
+        self.char_set = "alt"
+
+    def DT(self):
+        """ Define Label Terminator """
+        values = self.extract_value(raw=True)
+        if len(values) == 0:
+            self.str_terminator = chr(0x03)
+        elif len(values) == 1:
+            self.str_terminator = values[0]
+
+    def LB(self):
+        """ Character Plot """
+        values = self.extract_string()
+        self.plot_string(values)
+        x, y = self.pos
+        values = values.split('\n')
+        if self.char_size == "absolute":
+            x += len(values[-1]) * self.char_width *1016/2.54
+            y += (len(values)-1) * self.char_height *1016/2.54
+        else:
+            x0, x1, y0, y1 = self.scale
+            dx = x1-x0
+            dy = y1-y0
+            x += len(values[-1]) * self.char_width / 100.0 * dx
+            y += (len(values)-1) * self.char_height / 100.0 * dy
+            
+        #print "LB pos[%s] %s -> %s"%(repr(values), self.pos, (x,y))
+        self.pos = [x, y]
+
+    def get_char_size(self):
+        if self.char_size == "absolute":
+            x = self.char_width *1016/2.54
+            y = self.char_height *1016/2.54
+        else:
+            x0, x1, y0, y1 = self.scale
+            dx = x1-x0
+            dy = y1-y0
+            x = self.char_width / 100.0 * dx
+            y = self.char_height / 100.0 * dy
+        return x, y
+    
+    def DI(self):
+        """ Absolute Direction """
+        values = self.extract_value()
+        if len(values) == 0:
+            self.char_direction = 1.0, 0.0
+        elif len(values) == 2:
+            self.char_direction = values
+
+    def DR(self):
+        """ Relative Direction """
+        values = self.extract_value()
+        if len(values) == 0:
+            self.char_direction = 1.0, 0.0
+        elif len(values) == 2:
+            # TODO : compute as percentages
+            self.char_direction = values
+
+    def CP(self):
+        """ Character Plot """
+        values = self.extract_value()
+        # TODO
+        if len(values) == 0:
+            values = 0, 1
+        x, y = self.pos
+        if self.char_size == "absolute":
+            x += values[0] * self.char_width *1016/2.54
+            y += values[1] * self.char_height *1016/2.54
+        else:
+            x0, x1, y0, y1 = self.scale
+            dx = x1-x0
+            dy = y1-y0
+            x += values[0] * self.char_width / 100.0 * dx
+            y += values[1] * self.char_height / 100.0 * dy
+        #print "CB pos[%s] %s -> %s"%(repr(values), self.pos, (x,y))
+        self.pos = [x, y]
+
+    def SI(self):
+        """ Set Absolute Character Size """
+        values = self.extract_value()
+        self.char_size = "absolute"
+        if len(values) == 0:
+            self.char_width = 0.1879 # cm
+            self.char_height = 0.2690 # cm
+        elif len(values) == 2:
+            self.char_width, self.char_height = values
+
+    def SR(self):
+        """ Set Relative Character Size """
+        values = self.extract_value()
+        self.char_size = "relative"
+        if len(values) == 0:
+            self.char_width = 0.75 # percentage
+            self.char_height = 1.5 # id
+        elif len(values) == 2:
+            self.char_width, self.char_height = values
+        
+    def SL(self):
+        """ Character Slant """        
+        values = self.extract_value()
+        # TODO
+
+    def UC(self):
+        """ User Defined Character """
+        values = self.extract_value()
+        # TODO
+        
+if __name__ == '__main__':
+    import sys
+    data = open(sys.argv[1]).read()
+    
+    p = HPGLParser(data)
+    

mercurial