# # $Id: hammer.py,v 1.25 2001/10/29 07:52:53 mrnolta Exp $ # # Copyright (C) 2000-2001 : # # Walter Brisken # Mike Nolta # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public # License along with this program; if not, write to the # Free Software Foundation, Inc., 59 Temple Place - Suite 330, # Boston, MA 02111-1307, USA. # # # Hammer-Aitoff coordinates are an equal area projection of the # sphere into the plane. The spherical coordinates l and b are # used where l runs from -pi to pi and b from -pi/2 to pi/2. # The equator is b=0, and b = +/-pi/2 are the north/south poles. # import math from biggles import \ _series, _PlotComposite, _PlotGeometry, _PlotContainer, Geodesic, Curve from geometry import * import _biggles class _HammerAitoffGeometry: def __init__( self, dest, l0=0., b0=0, rot=0. ): self.src_bbox = BoundingBox( (-1.,-.5), (1.,.5) ) self.dest_bbox = dest self.aff = RectilinearMap( self.src_bbox, dest ) self.l0 = l0 self.b0 = b0 self.rot = rot def __call__( self, l_, b_ ): xh, yh = _biggles.hammer_call( \ l_, b_, self.l0, self.b0, self.rot ) return self.aff( xh, yh ) def call_vec( self, l_, b_ ): xh, yh = _biggles.hammer_call_vec( \ l_, b_, self.l0, self.b0, self.rot ) return self.aff.call_vec( xh, yh ) def geodesic( self, l_, b_, div=2 ): l, b = _biggles.hammer_geodesic_fill( l_, b_, div ) segs = [] i0 = 0 for i in range(1,len(l)): if _biggles.hammer_connect( \ l[i-1], b[i-1], l[i], b[i], \ self.l0, self.b0, self.rot ): segs.append( (l[i0:i],b[i0:i]) ) i0 = i segs.append( (l[i0:],b[i0:]) ) return segs class _HammerAitoffContext: def __init__( self, device, dev, l0=0., b0=0., rot=0. ): self.draw = device self.dev_bbox = dev self.geom = _HammerAitoffGeometry( dev, l0, b0, rot ) self.plot_geom = _PlotGeometry( BoundingBox((0,0),(1,1)), dev ) def do_clip( self ): pass class HammerAitoffPlot( _PlotContainer ): _attr_deprecated = { "num_l_ribs" : "ribs_l", "num_b_ribs" : "ribs_b", } def __init__( self, l0=0., b0=0, rot=0., **kw ): apply( _PlotContainer.__init__, (self,) ) apply( self.conf_setattr, ("HammerAitoffPlot",), kw ) self.content = _PlotComposite() self.l0 = l0 self.b0 = b0 self.rot = rot _attr_deprecated = { "num_l_ribs" : "ribs_l", "num_b_ribs" : "ribs_b", } def __setattr__( self, name, value ): self.__dict__[ self._attr_deprecated.get(name,name) ] = value def __iadd__( self, other ): self.add( other ) def add( self, *args ): apply( self.content.add, args ) def _draw_background( self, context ): pc = _PlotComposite() nl = self.ribs_l b = _series( -90/2, 90/2, 2*math.pi/180. ) for l0 in _series( -nl, nl, math.pi/nl ): c = apply( Curve, ([l0]*len(b), b), self.ribs_style ) pc.add( c ) nb = self.ribs_b l = _series( -180/2, 180/2, 2*math.pi/180. ) for b0 in _series( -nb, nb, 0.5*math.pi/(nb+1) ): c = apply( Curve, (l, [b0]*len(l)), self.ribs_style ) pc.add( c ) pc.render( context ) def exterior( self, device, interior ): bb = interior.copy() context = _HammerAitoffContext( device, interior, self.l0, self.b0, self.rot ) bb.union( self.content.bbox(context) ) return bb def compose_interior( self, device, interior ): _PlotContainer.compose_interior( self, device, interior ) context = _HammerAitoffContext( device, interior, self.l0, self.b0, self.rot ) self._draw_background( context ) self.content.render( context )