connect('expose_event' , array($this, 'expose_event')); $this->connect('configure_event' , array($this, 'configure_event')); $this->connect('realize' , array($this, 'realize')); $this->set_events(Gdk::EXPOSURE_MASK); $this->_gc = null; $this->_realized = false; } function realize(){ $this->_realized = true; } function realized(){ return $this->_realized; } function configure_event($widget, $event) { return true; } function expose_event($widget, $event) { $this->redraw(); return false; } function set_color($color){ $col = $this->colormap()->alloc_color($color); if($col === false) return $this->foreground('black'); return $this->gc()->set_foreground($col); } function set_background_color($color){ $col = $this->colormap()->alloc_color($color); if($col === false) return $this->background('white'); return $this->gc()->set_background($col); } function colormap(){ return $this->gc()->get_colormap(); } function drawable(){ if(!$this->realized()){ trigger_error("Widget not realized ; can't get drawable"); return null; } return $this->window; } function gc(){ if(!$this->realized()){ trigger_error("Widget not realized ; can't get GC"); return null; } if($this->_gc == null) $this->_gc = new GdkGc($this->drawable()); return $this->_gc; } function width(){ return $this->allocation->width; } function height(){ return $this->allocation->height; } function w(){ return $this->width(); } function h(){ return $this->height(); } protected function draw_point($x, $y){ $this->drawable()->draw_point($this->gc(),$x, $y); } protected function draw_rectangle($filled, $x, $y, $w, $h){ $this->drawable()->draw_rectangle($this->gc(), $filled, $x, $y, $w, $h); } public function draw_line($x1, $y1, $x2, $y2){ $this->drawable()->draw_line($this->gc(), $x1, $y1, $x2, $y2); } public function draw_text($text, $x, $y, $color, $font=null){ $this->set_color($color); if($font == null) $font = $this->style->get_font(); @$this->drawable()->draw_string($font, $this->gc(), $x, $y, $text); } protected function queue_tainted(){ # $this->queue_draw(); } protected function clear($color = 'white'){ $this->set_color($color); $this->draw_rectangle($filled=true, 0,0, $this->w(), $this->h()); } protected function set_clip_rectangle($x, $y, $w, $h){ $rec = new GdkRectangle($x, $y, $w, $h); $this->gc()->set_clip_rectangle($rec); } } class BufferedGraph extends DirectGraph{ protected $_pixmap; function __construct(){ parent::__construct(); $this->_pixmap = null; } function realize(){ parent::realize(); $this->redraw(); } function configure_event($widget, $event) { $w = $this->width(); $h = $this->height(); # allocated a new pixmap with according to requested size ($this->allocation) $this->_pixmap = new GdkPixmap($this->window, $w, $h, -1); # clear pixmap (white color) $this->_pixmap->draw_rectangle($this->style->white_gc, true, 0, 0, $w, $h); $this->redraw(); return true; } function expose_event($widget, $event) { $this->window->draw_drawable($this->style->fg_gc[$this->state], $this->drawable(), $event->area->x, $event->area->y, $event->area->x, $event->area->y, $event->area->width, $event->area->height); return false; } function drawable(){ if(!$this->realized()){ trigger_error("Widget not realized ; can't get pixmap"); return null; } return $this->_pixmap; } protected function queue_tainted(){ $this->queue_draw(); } } class Plotter extends DirectGraph{ # class Plotter extends BufferedGraph{ protected $dots; protected $border; protected $left_margin; function __construct($dots = null){ parent::__construct(); $this->dots = $dots; $this->border=15; $this->left_margin=0; } protected function redraw(){ if(!$this->realized()) return false; if($this->dots != null){ $this->plot($this->dots, 'red'); # redraw full area (acts on queue stack for expose events) $this->queue_tainted(); } } public function plot(&$dots, $color){ if(count($dots) == 0) return false; if(!$this->realized()) return false; $this->set_color($color); $w = $this->w() - 2* + $this->border - $this->left_margin; $h = $this->h() - 2* + $this->border; $count = count($dots); static $has_scaled = false; static $y_span; if(!$has_scaled){ $min = min(array_values($dots)); $max = max(array_values($dots)); $y_span = 1.2 * ($max - $min); # for auto-scale $has_scaled = true; } $last = array(); foreach($dots as $key=>$value){ $x = intval($key * $w / $count) + $this->border + $this->left_margin; # auto-scale X $y = intval($value * $h / $y_span); # auto-scale Y # center Y value and translate $y = intval($h/2 - $y + $this->border ); if(count($last)>0) $this->draw_line($x, $y, $last[0], $last[1]); $last[0] = $x; $last[1] = $y; } return true; } } class TurtleGraph extends DirectGraph{ private $x; private $y; public function __construct(){ parent::__construct(); $this->x = 0; $this->y = 0; } public function gotoXY($x, $y){ $this->x = $x; $this->y = $y; } public function lineRel($dx, $dy){ $this->draw_line($this->x, $this->y, $this->x + $dx, $this->y + $dy); $this->x += $dx; $this->y += $dy; } } class HilbertCurve extends TurtleGraph{ protected $dist; public function __construct(){ parent::__construct(); } protected function redraw(){ $colors = array( 'yellow', 'green', 'lightblue', 'grey', 'OrangeRed', 'pink', 'purple'); $level=5; $this->dist = 512; # $this->gotoXY ( $this->dist/2, $this->dist/2 ); # $this->HilbertA(3); # return; for ($i=$level;$i>0;$i--){ $this->dist /= 2; $this->set_color($colors[$level-$i]); $this->gotoXY ( $this->dist/2, $this->dist/2 ); $this->HilbertA($level); // start recursion } } protected function HilbertA($level) { if ($level > 0) { $this->HilbertB($level-1); $this->lineRel(0, $this->dist); $this->HilbertA($level-1); $this->lineRel($this->dist,0); $this->HilbertA($level-1); $this->lineRel(0,-$this->dist); $this->HilbertC($level-1); } } protected function HilbertB($level) { if ($level > 0) { $this->HilbertA($level-1); $this->lineRel($this->dist,0); $this->HilbertB($level-1); $this->lineRel(0,$this->dist); $this->HilbertB($level-1); $this->lineRel(-$this->dist,0); $this->HilbertD($level-1); } } protected function HilbertC($level) { if ($level > 0) { $this->HilbertD($level-1); $this->lineRel(-$this->dist,0); $this->HilbertC($level-1); $this->lineRel(0,-$this->dist); $this->HilbertC($level-1); $this->lineRel($this->dist,0); $this->HilbertA($level-1); } } protected function HilbertD($level) { if ($level > 0) { $this->HilbertC($level-1); $this->lineRel(0,-$this->dist); $this->HilbertD($level-1); $this->lineRel(-$this->dist,0); $this->HilbertD($level-1); $this->lineRel(0,$this->dist); $this->HilbertB($level-1); } } } $curve = new HilbertCurve(); $curve->set_size_request(512, 512); $window = new GtkWindow(); $window->connect_simple('destroy', array('gtk', 'main_quit')); $window->set_title('Hilbert curve'); $window->set_position(Gtk::WIN_POS_CENTER); $window->set_border_width(8); $window->add($curve); $window->show_all(); Gtk::main(); ?>