Changeset 501

Show
Ignore:
Timestamp:
02/26/08 21:33:54 (9 months ago)
Author:
asc
Message:

plots, dots, lines and hulls

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/py/wscompose/markers.py

    r476 r501  
    442442    # ########################################################## 
    443443     
    444     def mk_perspective_shadow (self) : 
     444    def mk_perspective_shadow (self, img, corners) : 
    445445 
    446446        # 
     
    455455        # im.transform(size, PERSPECTIVE, data) 
    456456        # 
    457          
    458         pass 
    459      
     457 
     458        """ 
     459             
     460        Returns a new surface containing the image reshaped to fit inside the quadrilateral defined by the given vertices (top-left, top-right, bottom-right, bottom-left). 
     461         
     462        For the sake of my sanity, we're assuming that the left and right sides, post-transform, will be straight vertical lines. If you intend them to be otherwise, I shall punch you in the cock. Also assumed is that the smaller end doesn't extend above or below the longer end (though I'm not sure that it doing so would actually be a problem). 
     463        """ 
     464         
     465        tl, tr, br, bl = corners 
     466        sourceSize = img.size 
     467        newSize = (max(tr[0], br[0]), max(bl[1], br[1])) 
     468         
     469        a = float(sourceSize[0] * (br[1] - tr[1])) / \ 
     470            (newSize[0] * (bl[1] - tl[1])) 
     471        b = 0 
     472        c = 0 
     473        d = float(sourceSize[1] * (tl[1] - tr[1])) / \ 
     474            (newSize[0] * (bl[1] - tl[1])) 
     475        e = float(sourceSize[1]) / \ 
     476            (bl[1] - tl[1]) 
     477        f = float(-(sourceSize[1] * tl[1])) / \ 
     478            (bl[1] - tl[1]) 
     479        g = float(tl[1] - tr[1] + br[1] - bl[1]) / \ 
     480            (newSize[0] * (bl[1] - tl[1])) 
     481        h = 0 
     482        vals = [a, b, c, d, e, f, g, h] 
     483         
     484        return img.transform (newSize, Image.PERSPECTIVE, vals, Image.BILINEAR) 
     485            
     486 
    460487    # ########################################################## 
    461488 
     
    566593     
    567594    pw = pinwin(w, h, 15) 
    568     im = pw.draw() 
    569          
    570     im.save("/home/asc/Desktop/mrk.png") 
     595    im = pw.mk_pinwin() 
     596    im = pw.mk_perspective_shadow(im, ((10,100), (10,10), (500,500), (500,200))) 
     597    # im.save("/home/asc/Desktop/mrk.png") 
    571598    im.show() 
  • trunk/py/wscompose/pinwin.py

    r478 r501  
    99 
    1010import wscompose 
     11import convexhull 
    1112 
    1213import wscompose.plotting 
     
    3637 
    3738        # 
     39 
     40        if self.ctx.has_key('polylines') : 
     41            img = self.draw_polylines(img) 
     42 
     43        # 
     44 
     45        if self.ctx.has_key('hulls') : 
     46            img = self.draw_convex_hulls(img) 
     47             
     48        # 
    3849         
    3950        if self.ctx.has_key('dots') : 
     
    95106    # ########################################################## 
    96107 
    97     # only works for method='bbox' ... WTF? 
    98  
     108    def draw_polylines (self, img) : 
     109 
     110        for poly in self.ctx['polylines'] : 
     111            img = self.draw_polyline(img, poly) 
     112 
     113        return img 
     114 
     115    # ########################################################## 
     116     
     117    def draw_polyline (self, img, poly) : 
     118         
     119        dr = ImageDraw.Draw(img) 
     120        cnt = len(poly) 
     121        i = 0 
     122 
     123        grey = (42, 42, 42) 
     124         
     125        while i < cnt :  
     126 
     127            j = i + 1 
     128 
     129            if j == cnt : 
     130                break 
     131 
     132            cur = self.latlon_to_point(poly[i]['latitude'], poly[i]['longitude']) 
     133            next = self.latlon_to_point(poly[j]['latitude'], poly[j]['longitude'])             
     134 
     135            dr.line((cur.x, cur.y, next.x, next.y), fill=grey, width=4) 
     136            i += 1 
     137 
     138        # 
     139                 
     140        return img 
     141             
     142    # ########################################################## 
     143 
     144    def draw_convex_hulls(self, img) : 
     145 
     146        dr = ImageDraw.Draw(img) 
     147 
     148        for type in self.ctx['hulls'] : 
     149 
     150            points = [] 
     151             
     152            for coord in self.ctx[type] :  
     153 
     154                pt = self.latlon_to_point(coord['latitude'], coord['longitude'])     
     155                points.append((pt.x, pt.y)) 
     156 
     157            hull = convexhull.convexHull(points) 
     158 
     159            # 
     160            # no way to assign width to polygon outlines in PIL... 
     161            # 
     162             
     163            pink = (255, 0, 132) 
     164            cnt = len(hull) 
     165            i = 0 
     166 
     167            while i < cnt :  
     168 
     169                (x1, y1) = hull[i] 
     170                 
     171                j = i + 1 
     172 
     173                if j == cnt : 
     174                    (x2, y2) = hull[0] 
     175                else : 
     176                    (x2, y2) = hull[j] 
     177 
     178                dr.line((x1, y1, x2, y2), fill=pink, width=6) 
     179                i += 1 
     180             
     181        return img 
     182     
     183    # ########################################################## 
     184     
    99185    # To do : move this code in to methods that can be run 
    100186    # easily from unit tests and/or CLI tools... 
     
    390476                self.error(141, e) 
    391477                return False 
     478 
     479        # 
     480        # polylines 
     481        # 
     482 
     483        if params.has_key('polyline') : 
     484 
     485            try : 
     486                valid['polylines'] = validator.polylines(params['polyline']) 
     487            except Exception, e : 
     488                self.error(142, e) 
     489                return False 
     490 
     491        # 
     492        # 
     493        # 
     494 
     495        if params.has_key('convex') : 
     496 
     497            try : 
     498                valid['hulls'] = validator.convex(params['convex']) 
     499            except Exception, e : 
     500                self.error(143, e) 
     501                return False 
     502             
     503        # 
     504        # Happy happy 
     505        # 
    392506         
    393507        return valid 
     
    410524        wscompose.handler.help_parameters(self) 
    411525 
     526        self.help_option('dot', 'Draw a pinwin-style dot (but not the marker) at a given point. You may pass multiple dot arguments, each of which should contain the following comma separated values :', False) 
     527        self.help_option('label', 'A unique string to identify the dot by', True, 1) 
     528        self.help_option('point', 'A comma-separated string containing the latitude and longitude indicating the point where the dot should be placed', True, 1) 
     529        self.help_option('radius', 'The radius, in pixels, of the dot - the default is 18', False, 1)     
     530 
    412531        self.help_option('marker', 'Draw a pinwin-style marker at a given point. You may pass multiple marker arguments, each of which should contain the following comma separated values :', False) 
    413532        self.help_option('label', 'A unique string to identify the marker by', True, 1) 
     
    415534        self.help_option('dimensions', 'A comma-separated string containing the height and width of the marker canvas - the default is 75 x 75', False, 1)    
    416535 
    417         self.help_option('dot', 'Draw a pinwin-style dot (but not the marker) at a given point. You may pass multiple dot arguments, each of which should contain the following comma separated values :', False) 
    418         self.help_option('label', 'A unique string to identify the dot by', True, 1) 
    419         self.help_option('point', 'A comma-separated string containing the latitude and longitude indicating the point where the dot should be placed', True, 1) 
    420         self.help_option('radius', 'The radius, in pixels, of the dot - the default is 18', False, 1)     
    421  
    422         self.help_option('plot', 'Plot -- but do not render -- the x and y coordinates for a given point. Coordinate data will be returned HTTP header(s) named \'X-wscompose-plot-\' followed by the label you choose when passing latitude and longitude information. You may pass multiple plot arguments, each of which should contain the following comma separated values :', False) 
    423         self.help_option('label', 'A unique string to identify the plotting by', True, 1) 
    424         self.help_option('point', 'A comma-separated string containing the latitude and longitude indicating the point to be plotted', True, 1) 
    425  
     536        self.help_option('polyline', 'Draw a polyline on the map. Polylines are passed as multiple coordinates (comma-separated latitude and longitude pairs) each separated by a single space. You may pass multiple \'polyline\' arguments. This option is currently experimental and arguments may change.', False) 
     537 
     538        self.help_option('convex', 'Draw a polyline representing the convex hull of a collection of points passed in the \'marker\', \'dot\' or \'plot\' arguments (see above). Valid options are, not surprisingly : \'marker\', \'dot\' or \'plot\'; you may pass multiple \'convex\' arguments. This option is currently experimental and arguments may change.', False) 
     539         
    426540        self.help_option('fill', 'A helper argument which if present will cause each marker specified to be filled with the contents of map for the marker\'s coordinates at zoom level 15. The value should be a valid ModestMaps map tile provider.', False) 
    427541         
  • trunk/py/wscompose/validate.py

    r482 r501  
    2121            'num' : re.compile(r"^\d+$"), 
    2222            'provider' : re.compile(r"^([A-Z_]+)$"), 
    23             'label' : re.compile(r"^(?:[a-z0-9-_]+)$") 
     23            'label' : re.compile(r"^(?:[a-z0-9-_]+)$"), 
     24            'hull' : re.compile(r"^(marker|dot|plot)$")    
    2425            } 
    2526 
     
    312313             
    313314    # ########################################################## 
     315 
     316    def polylines (self, lines) : 
     317 
     318        valid = [] 
     319         
     320        for poly in lines : 
     321 
     322            points = [] 
     323             
     324            for pt in poly.split(" ") : 
     325             
     326                coord = pt.split(",") 
     327 
     328                if len(coord) != 2 : 
     329                    raise Exception, "Polyline coordinate missing data" 
     330                 
     331                (lat, lon) = map(string.strip, coord)  
     332                 
     333                lat = self.latlon(lat) 
     334                lon = self.latlon(lon) 
     335 
     336                points.append({'latitude':lat, 'longitude':lon}) 
     337 
     338            valid.append(points) 
     339             
     340        return valid 
     341     
     342    # ##########################################################     
     343 
     344    def convex (self, hulls) : 
     345         
     346        valid = [] 
     347 
     348        for label in hulls : 
     349 
     350            if not self.regexp('hull', label)  : 
     351                raise Exception, "Unknown marker type for convex hulls" 
     352 
     353            valid.append(label) 
     354 
     355        return valid 
     356     
     357    # ########################################################## 
    314358     
    315359    def __num (self, input) : 
  • trunk/py/wscompose/__init__.py

    r480 r501  
    241241        self.send_header("X-wscompose-Map-Zoom", self.ctx['zoom']) 
    242242 
    243         if self.ctx.has_key('plot') : 
    244             for data in self.ctx['plot'] : 
     243        if self.ctx.has_key('plots') : 
     244            for data in self.ctx['plots'] : 
    245245 
    246246                pt = self.latlon_to_point(data['latitude'], data['longitude']) 
     
    380380                    return False 
    381381 
     382            # you can blame migurski for this 
     383             
     384            if params.has_key('zoom') : 
     385                self.error(125, "'zoom' is not a valid argument when method is 'extent'") 
     386                return False 
     387                 
    382388        elif params['method'][0] == 'bbox' : 
    383389 
     
    406412                except Exception, e : 
    407413                    self.error(124, e) 
     414                    return False 
     415 
     416            # you can blame migurski for this 
     417             
     418            for p in ('height', 'width') : 
     419                if params.has_key(p) : 
     420                    self.error(125, "'%s' is not a valid argument when method is 'bbox'" % p) 
    408421                    return False 
    409422                 
     
    448461 
    449462            try : 
    450                 valid['plot'] = validator.plots(params['plot']) 
     463                valid['plots'] = validator.plots(params['plot']) 
    451464            except Exception, e : 
    452465                self.error(141, e) 
     
    540553        X-wscompose-plot-roy: 667,285""") 
    541554 
    542         self.help_para("Most headers are self-explanatory. Markers, dots and plotting coordinates are a little more complicated.") 
    543  
    544         self.help_para("The string after 'X-wscompose-plot-' is the label assigned to the marker when the API call was made. The value is a comma separated list containing the x and y coordinates for (label's) corresponding latitude and longitude.") 
     555        self.help_para("Most headers are self-explanatory. Plotted coordinates are a little more complicated.") 
     556 
     557        self.help_para("The string after 'X-wscompose-plot' is the label assigned to the marker when the API call was made. The value is a comma separated list containing the x and y coordinates for (label's) corresponding latitude and longitude.") 
    545558         
    546559    # ##########################################################