Using GitHub with CLI

github

A simple program using gtkmm is now available at GitHub.

% cd gtkmm
% git init
% git add .
% git commit -m "Initial commit."
% git push --set-upstream git@github.com:jh1ood/gtkmm.git master

The Feynman Lectures on Physics

640px-The_Feynman_Lectures_on_Physics

I did not know that this million seller book is now freely available on the web site feynmanlectures.caltech.edu.

I suppose I first read the book some twenty years ago, long after I last attended such lectures as a student. The book is based on his lectures given to undergraduate students at Caltech. All freshmen and sophomores were required to take the course regardless of their majors.

The style of the book is far from those of traditional textbooks. One may find difficulties in understanding because there are too few equations.

For us amateur radio operators, why not start reading from Chapter 21-4 The fields of an oscillating dipole (Volulme II).

radiation

We start from Maxwell’s equations as usual:

maxwell

Note that “1” and “2” are the short forms of “(x1, y1, z1)” and “(x2, y2, z2)”, respectively.

Let p be the dipole moment, and with some assumptions and with some tedious calculations, we get:

results

I suppose you can follow the discussions in the text with no great difficulties, especially if you enjoy fiddling with vector calculus. However, the important part is how you interpret the obtained equations, always evaluating if the model and the assumptions used are applicable to the situation being considered.

What a wonder that such a simple model described as Maxwell’s equations is applicable to so many problems!

IPv4: Deprecated, use IPv6 instead.

World_IPv6_launch_banner_bg_512

It was almost three years ago when I put the above graphics onto my site to show that it is accessible via IPv6. At that time I was using a virtual private server (VPS), and my hosting provide was not offering native IPv6 connectivity so I had to use one of the various tunneling mechanisms that existed. The situation was the same at my premises with my ISP, so native IPv6 was somthing to come in the future…

Now the time goes by, and a few days ago I noticed that I am visiting some of the sites via IPv6.

iijv6

Really? Let’s see..

% wget ipv6.google.com
--2015-03-08 09:20:55--  http://ipv6.google.com/
Resolving ipv6.google.com (ipv6.google.com)... 2404:6800:4004:814::200e
Connecting to ipv6.google.com (ipv6.google.com)|2404:6800:4004:814::200e|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: unspecified 
Saving to: ‘index.html’
    [ <=> ] 19,746      --.-K/s   in 0.01s   
2015-03-08 09:20:55 (1.58 MB/s) - ‘index.html’ saved [19746]

A technique called dual stack is employed with my ISP. Try http://ipv6-test.com/ to see what happens in your environment. (The results depends on both your PC and your ISP.)

ipv6test

Google says that the percentage of users that access Google over IPv6 is around 5% now.

googleipv6

Still not really comfortable (2)

This is better.

I did not notice the difference between the two; sigc::ptr_fun() generates a slot for a standalone function or static method. sigc::mem_fun() generates a slot for a member method of a particular instance.

So it’s another RTFM as it always happens to me.

/* MyWindow.cpp */

#include "MyWindow.h"
#include "MyArea.h"
#include <gtkmm.h>

MyWindow::MyWindow() : m_box(Gtk::ORIENTATION_VERTICAL), m_buttons(Gtk::ORIENTATION_HORIZONTAL),
		m_button1("_reset", true), m_button2("_shrink", true), m_button3("_left", true),
		m_button4("righ_t", true), m_button5("_up"    , true), m_button6("_down", true) {
	set_title("Test test...");
	set_default_size(300, 329);
	set_border_width(10);
	add(m_box);
	m_box.pack_start(m_buttons, false, true);
	m_buttons.pack_start(m_button1, true, true);
	m_buttons.pack_start(m_button2, true, true);
	m_buttons.pack_start(m_button3, true, true);
	m_buttons.pack_start(m_button4, true, true);
	m_buttons.pack_start(m_button5, true, true);
	m_buttons.pack_start(m_button6, true, true);
	m_button1.signal_clicked().connect(sigc::mem_fun(m_area, &MyArea::area_reset ));
	m_button2.signal_clicked().connect(sigc::mem_fun(m_area, &MyArea::area_shrink));
	m_button3.signal_clicked().connect(sigc::mem_fun(m_area, &MyArea::area_left  ));
	m_button4.signal_clicked().connect(sigc::mem_fun(m_area, &MyArea::area_right ));
	m_button5.signal_clicked().connect(sigc::mem_fun(m_area, &MyArea::area_up    ));
	m_button6.signal_clicked().connect(sigc::mem_fun(m_area, &MyArea::area_down  ));
	m_box.pack_start(m_area);
	show_all_children();
}

MyWindow::~MyWindow() {
}

Still not really comfortable

notcomfortable

It works, but I am not satisfied.

/* main.cpp */
#include "MyWindow.h"
#include <gtkmm/application.h>

int main(int argc, char** argv)
{
   Glib::RefPtr<Gtk::Application> app = Gtk::Application::create(argc, argv, "org.gtkmm.example");
   MyWindow win;
   return app->run(win);
}
/* MyWindow.h */

#ifndef MYWINDOW_H_
#define MYWINDOW_H_

#include "MyArea.h"
#include <gtkmm/window.h>
#include <gtkmm/box.h>
#include <gtkmm/button.h>

class MyWindow : public Gtk::Window {
public:
	MyWindow();
	virtual ~MyWindow();
protected:
	void on_button1_clicked();
	void on_button2_clicked();
	void on_button3_clicked();
	void on_button4_clicked();
	void on_button5_clicked();
	void on_button6_clicked();
private:
	Gtk::Box    m_box;
	Gtk::Box    m_buttons;
	Gtk::Button m_button1;
	Gtk::Button m_button2;
	Gtk::Button m_button3;
	Gtk::Button m_button4;
	Gtk::Button m_button5;
	Gtk::Button m_button6;
	MyArea      m_area;
};

#endif /* MYWINDOW_H_ */
/* MyWindow.cpp */

#include "MyWindow.h"
#include "MyArea.h"

MyWindow::MyWindow() : m_box(Gtk::ORIENTATION_VERTICAL), m_buttons(Gtk::ORIENTATION_HORIZONTAL),
		m_button1("reset"), m_button2("shrink"), m_button3("left"), m_button4("right"), m_button5("up"), m_button6("down") {
	set_title("Not comfortable...");
	set_default_size(300, 329);
	add(m_box);
	m_box.pack_start(m_buttons, false, true);
	m_buttons.pack_start(m_button1, true, true);
	m_buttons.pack_start(m_button2, true, true);
	m_buttons.pack_start(m_button3, true, true);
	m_buttons.pack_start(m_button4, true, true);
	m_buttons.pack_start(m_button5, true, true);
	m_buttons.pack_start(m_button6, true, true);
	m_button1.signal_clicked().connect(sigc::mem_fun(*this, &MyWindow::on_button1_clicked));
	m_button1.signal_clicked().connect(sigc::mem_fun(*this, &MyWindow::on_button1_clicked));
	m_button1.signal_clicked().connect(sigc::mem_fun(*this, &MyWindow::on_button1_clicked));
	m_button2.signal_clicked().connect(sigc::mem_fun(*this, &MyWindow::on_button2_clicked));
	m_button3.signal_clicked().connect(sigc::mem_fun(*this, &MyWindow::on_button3_clicked));
	m_button4.signal_clicked().connect(sigc::mem_fun(*this, &MyWindow::on_button4_clicked));
	m_button5.signal_clicked().connect(sigc::mem_fun(*this, &MyWindow::on_button5_clicked));
	m_button6.signal_clicked().connect(sigc::mem_fun(*this, &MyWindow::on_button6_clicked));
	m_box.pack_start(m_area);
	show_all_children();
}

MyWindow::~MyWindow() {
}

void MyWindow::on_button1_clicked() {
	m_area.area_reset();
}

void MyWindow::on_button2_clicked() {
	m_area.area_shrink();
}

void MyWindow::on_button3_clicked() {
	m_area.area_left();
}

void MyWindow::on_button4_clicked() {
	m_area.area_right();
}

void MyWindow::on_button5_clicked() {
	m_area.area_up();
}

void MyWindow::on_button6_clicked() {
	m_area.area_down();
}
/* MyArea.h */

#ifndef MYAREA_H_
#define MYAREA_H_

#include <gtkmm/drawingarea.h>

class MyArea : public Gtk::DrawingArea
{
public:
  MyArea();
  virtual ~MyArea();
  void area_reset();
  void area_shrink();
  void area_left();
  void area_right();
  void area_up();
  void area_down();
protected:
  virtual bool on_draw(const Cairo::RefPtr<Cairo::Context>& cr);
  virtual bool on_button_press_event  ( GdkEventButton* event );
  virtual bool on_button_release_event( GdkEventButton* event );
private:
  double x_min;
  double x_max;
  double y_min;
  double y_max;
  double x_press;
  double y_press;
  double x_release;
  double y_release;
};

#endif /* MYAREA_H_ */
/* MyArea.cpp */

#include "MyArea.h"
#include <complex>
#include <iostream>
using namespace std;

MyArea::MyArea() : x_min {-1.5}, x_max { 0.5}, y_min {-1.0}, y_max { 1.0},
				   x_press {0.0}, y_press {0.0}, x_release {0.0}, y_release {0.0}
{
	add_events( Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK );
}

MyArea::~MyArea() {
}

void MyArea::area_reset() {
	x_min = -1.5;
	x_max =  0.5;
	y_min = -1.0;
	y_max =  1.0;
	get_window()->invalidate(true);
}

void MyArea::area_shrink() {
	double xc = (x_min + x_max) / 2.0;
	double yc = (y_min + y_max) / 2.0;
	double xs = (x_max - xc) / 0.67;
	double ys = (y_max - yc) / 0.67;
	x_min = xc - xs;
	x_max = xc + xs;
	y_min = yc - ys;
	y_max = yc + ys;
	get_window()->invalidate(true);
}

void MyArea::area_left() {
	double xc = (x_min + x_max) / 2.0;
	double xs = (x_max - xc) * 0.67;
	x_min += xs;
	x_max += xs;
	get_window()->invalidate(true);
}

void MyArea::area_right() {
	double xc = (x_min + x_max) / 2.0;
	double xs = (x_max - xc) * 0.67;
	x_min -= xs;
	x_max -= xs;
	get_window()->invalidate(true);
}

void MyArea::area_up() {
	double yc = (y_min + y_max) / 2.0;
	double ys = (y_max - yc) * 0.67;
	y_min += ys;
	y_max += ys;
	get_window()->invalidate(true);
}

void MyArea::area_down() {
	double yc = (y_min + y_max) / 2.0;
	double ys = (y_max - yc) * 0.67;
	y_min -= ys;
	y_max -= ys;
	get_window()->invalidate(true);
}

bool MyArea::on_button_press_event( GdkEventButton* event )
{
    std::cout << "pressed:  " << event->x << " : " << event->y << std::endl;
    x_press = event->x;
    y_press = event->y;
    return true;
}

bool MyArea::on_button_release_event( GdkEventButton* event )
{
    std::cout << "released: " << event->x << " : " << event->y << std::endl;
    x_release = event->x;
    y_release = event->y;
	get_window()->invalidate(true);
    return true;
}

bool MyArea::on_draw(const Cairo::RefPtr<Cairo::Context>& cr)
{
  Gtk::Allocation allocation = get_allocation();
  const int width  = allocation.get_width();
  const int height = allocation.get_height();
  if(x_press != x_release && y_press != y_release) {
	  double x_min_new = x_min + (x_max - x_min) * ( x_press   / (double) width );
	  double x_max_new = x_min + (x_max - x_min) * ( x_release / (double) width );
	  x_min = x_min_new;
	  x_max = x_max_new;
	  double y_min_new = y_min + (y_max - y_min) * ( y_press   / (double) height );
	  double y_max_new = y_min + (y_max - y_min) * ( y_release / (double) height );
	  y_min = y_min_new;
	  y_max = y_max_new;
	  x_press = y_press = x_release = y_release = 0.0;
  }
  cout << "MyArea: width = " << width << ", height = " << height
       << ", (" << x_min << ", " << y_min << ") ----> (" << x_max << ", " << y_max << ") \n";

  cr->set_line_width(1.0);

  double large = 100.0;
  int    kmax  =  50;

  for(int i=0;i<width;i++) {
	  for(int j=0;j<height;j++) {
		  double x=x_min+(x_max-x_min)*(double)i/(double)width;
		  double y=y_min+(y_max-y_min)*(double)j/(double)height;
		  complex<double> z=0.0;
		  complex<double> w=complex<double>(x,y);
		  int count=0;
		  for(int k=0;k<kmax;k++) {
			  z=z*z+w;
			  if(abs(z)>large) {
				  count = k;
				  break;
			  }
		  }
		  if(count) {
			  cr->set_source_rgba(0.9,(count%10)/10.0,0.3,1.0);
		  } else {
			  cr->set_source_rgba(0.0,0.2,0.7,1.0);
		  }
		  cr->rectangle((double)i, (double)j, 1.0, 1.0);
		  cr->stroke();
	  }
  }
  return true;
}

CW: Deprecated, use a digital mode instead.

deprecated

/* deprecated.cpp */
#include <gtkmm.h>

int main(int argc, char** argv)
{
	Gtk::Main kit(argc, argv);
	Gtk::Window win;
	kit.run(win);
	return 0;
}

The above program works fine, but unfortunately Gtk::Main is a deprecated class.

mainkit

http://en.wikipedia.org/wiki/Deprecation

  • the term is also used for a feature, design, or practice that is permitted but no longer recommended
  • Among the most common reasons for deprecation are:
    • The feature has been replaced by a more powerful alternative feature.
    • The feature contains a design flaw—frequently a security flaw—and so should be avoided, but existing code depends upon it.
    • The feature is considered extraneous, and will be removed in the future in order to simplify the system as a whole.

Isn’t that very interesting if we just replace some of the words with those that are used in ham radio.

Static Data Members

One way to avoid global variables such as appeared in my previous article is to use static data members.

class MyArea : public Gtk::DrawingArea
{
public:
  MyArea();
  virtual ~MyArea();
protected:
  virtual bool on_draw(const Cairo::RefPtr<Cairo::Context>& cr);
  virtual bool on_button_press_event  ( GdkEventButton* event );
  virtual bool on_button_release_event( GdkEventButton* event );
public:
  static double x_min;
  static double x_max;
  static double y_min;
  static double y_max;
private:
  double x_press;
  double y_press;
  double x_release;
  double y_release;
};
double MyArea::x_min {-1.5};
double MyArea::x_max { 0.5};
double MyArea::y_min {-1.0};
double MyArea::y_max { 1.0};

MyArea::MyArea() : x_press {0.0}, y_press {0.0}, x_release {0.0}, y_release {0.0}
{
	add_events( Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK );
}
void MyButton::on_button1_clicked() {
	double xc = (MyArea::x_min + MyArea::x_max) / 2.0;
	double yc = (MyArea::y_min + MyArea::y_max) / 2.0;
	double xs = (MyArea::x_max - xc) * 0.67;
	double ys = (MyArea::y_max - yc) * 0.67;
	MyArea::x_min = xc - xs;
	MyArea::x_max = xc + xs;
	MyArea::y_min = yc - ys;
	MyArea::y_max = yc + ys;
	get_window()->invalidate(true);
}

I do not know if this is any improvement.

Mouse Events

mouse1

Now you can zoom in to the area you have specified with your mouse.

MyArea: width = 400, height = 400, (-1.5, -1) ----> (0.5, 1) 
pressed:  46.2161 : 126.588
released: 87.2161 : 162.588
MyArea: width = 400, height = 400, (-1.26892, -0.367061) ----> (-1.06392, -0.187061) 

The size of the drawing area is 400 by 400 pixels, and the upper left corner is initially mapped to (xmin=-1.5, ymin=-1), while the lower right corner to (xmax=0.5, ymax=1).

By detectiong the points where the mouse is pressed and released, a new drawing area is defined considering the two points as a diagonal.

bool MyArea::on_draw(const Cairo::RefPtr<Cairo::Context>& cr)
{
  Gtk::Allocation allocation = get_allocation();
  const int width  = allocation.get_width();
  const int height = allocation.get_height();
  if(x_press != x_release && y_press != y_release) {
	  double x_min_new = x_min + (x_max - x_min) * ( x_press   / (double) width );
	  double x_max_new = x_min + (x_max - x_min) * ( x_release / (double) width );
	  x_min = x_min_new;
	  x_max = x_max_new;
	  double y_min_new = y_min + (y_max - y_min) * ( y_press   / (double) height );
	  double y_max_new = y_min + (y_max - y_min) * ( y_release / (double) height );
	  y_min = y_min_new;
	  y_max = y_max_new;
	  x_press = y_press = x_release = y_release = 0.0;
  }
  cout << "MyArea: width = " << width << ", height = " << height
       << ", (" << x_min << ", " << y_min << ") ----> (" << x_max << ", " << y_max << ") \n";
  /*** etc. ***/
}
MyWindow::MyWindow() : m_box(Gtk::ORIENTATION_VERTICAL) {
	add_events( Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK );
  /*** etc. ***/
}

bool MyWindow::on_button_press_event( GdkEventButton* event )
{
    std::cout << "pressed:  " << event->x << " : " << event->y << std::endl;
    x_press = event->x;
    y_press = event->y;
    return true;
}

bool MyWindow::on_button_release_event( GdkEventButton* event )
{
    std::cout << "released: " << event->x << " : " << event->y << std::endl;
    x_release = event->x;
    y_release = event->y;
	get_window()->invalidate(true);
    return true;
}
class MyWindow : public Gtk::Window {
public:
	virtual bool on_button_press_event  ( GdkEventButton* event );
	virtual bool on_button_release_event( GdkEventButton* event );
/*** etc. ***/
};