// -*- C++ -*-
// $RCSfile: pixelgroups.C,v $
// $Revision: 1.12 $
// $Author: langer $
// $Date: 2000/11/01 16:41:51 $
/* This software was produced by NIST, an agency of the U.S. government,
* and by statute is not subject to copyright in the United States.
* Recipients of this software assume all responsibilities associated
* with its operation, modification and maintenance. However, to
* facilitate maintenance we ask that before distributing modifed
* versions of this software, you first contact the authors at
* oof_manager@ctcms.nist.gov.
*/
#include "adaptmesh.h"
#include "cell_coordinate.h"
#include "goof.h"
#include "meshcoord.h"
#include "pixelgroups.h"
#include "ppm2oof.h"
#include <math.h>
//template <class TYPE> // do I need this?
//Vec<GroupMenu<Cell_coordinate>*> GroupMenu<Cell_coordinate>::menulist;
unsigned int PixelGroup::ngroups = 0;
PixelGroup::~PixelGroup() {
// remove this group from lists stored in pixels
for(int i=0; i<members.capacity(); i++)
current_goof->pixelgrouplist[members[i]].Remove(this);
}
void PixelGroup::append(const Vec<Cell_coordinate> &list) {
append_base(list);
// add this group to the list of groups in each pixel, making sure
// that the list remains sorted.
if(name != "") {
for(int i=0; i<list.capacity(); i++)
current_goof->pixelgrouplist[list[i]].Insert(this, compare);
if(current_goof->mesh())
current_goof->mesh()->groups_need_recomputing();
++current_goof->groups_changed;
}
}
void PixelGroup::append(const Cell_coordinate &pxl) {
append_base(pxl);
// add this group to the list of groups in the given pixel, making
// sure that the list remains sorted.
if(name != "") {
current_goof->pixelgrouplist[pxl].Insert(this, compare);
if(current_goof->mesh())
current_goof->mesh()->groups_need_recomputing();
++current_goof->groups_changed;
}
}
void PixelGroup::append(const Group<Cell_coordinate> &grp) {
append(grp.membership());
}
void PixelGroup::clear() {
// remove this group from lists stored in pixels
for(int i=0; i<members.capacity(); i++)
current_goof->pixelgrouplist[members[i]].Remove(this);
clear_base();
if(name != "") {
if(current_goof->mesh())
current_goof->mesh()->groups_need_recomputing();
++current_goof->groups_changed;
}
}
void PixelGroup::remove(const Cell_coordinate &pxl) {
remove_base(pxl);
if(name != "") {
current_goof->pixelgrouplist[pxl].Remove(this);
if(current_goof->mesh())
current_goof->mesh()->groups_need_recomputing();
++current_goof->groups_changed;
}
}
void PixelGroup::remove(const Vec<Cell_coordinate> &pxls) {
remove_base(pxls);
if(name != "") {
for(int i=0; i<pxls.capacity(); i++)
current_goof->pixelgrouplist[pxls[i]].Remove(this);
if(current_goof->mesh())
current_goof->mesh()->groups_need_recomputing();
++current_goof->groups_changed;
}
}
void PixelGroup::remove(const Group<Cell_coordinate> &grp) {
remove(grp.membership());
}
void PixelGroup::trim(const Cell_coordinate &pxl) {
Group<Cell_coordinate>::trim(pxl);
if(name != "") {
current_goof->pixelgrouplist[pxl].Remove(this);
if(current_goof->mesh())
current_goof->mesh()->groups_need_recomputing();
++current_goof->groups_changed;
}
}
void PixelGroup::replace(const Cell_coordinate &oldpxl,
const Cell_coordinate &newpxl)
{
Group<Cell_coordinate>::replace(oldpxl, newpxl);
if(name != "") {
current_goof->pixelgrouplist[oldpxl].Remove(this);
current_goof->pixelgrouplist[newpxl].Insert(this, compare);
if(current_goof->mesh())
current_goof->mesh()->groups_need_recomputing();
++current_goof->groups_changed;
}
}
//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//
static const Cell_coordinate xhat(1, 0);
static const Cell_coordinate yhat(0, 1);
double PixelGroup::perimeter() const {
int nperim = 0;
int width = current_goof->query_width();
int height = current_goof->query_height();
Array<bool> sel(height, width);
sel.clear(0);
for(int i=0; i<size(); i++)
sel[(*this)[i]] = 1;
for(int i=0; i<size(); i++) {
Cell_coordinate here = (*this)[i];
if((here.x == 0 || !sel[here-xhat]) ||
(here.x == width-1 || !sel[here+xhat]) ||
(here.y == 0 || !sel[here-yhat]) ||
(here.y == height-1 || !sel[here+yhat]))
nperim++;
}
return nperim/(sqrt(double(size()))*M_PI);
}
//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//
// function used to keep groups sorted in Goof::pixelgrouplists
int PixelGroup::compare(PixelGroup* const &a, PixelGroup* const &b)
{
if(a->group_id < b->group_id) return -1;
if(a->group_id > b->group_id) return 1;
return 0;
}
//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//
class NewPixelGroupCmd : public CommandM {
private:
CharString name;
public:
NewPixelGroupCmd() : CommandM("new", "create a new group"),
name("groupname")
{
AddArgument(this, "name", name);
}
virtual CommandFn func() {
if(goofinit()) {
char *c;
int modified = 0;
while(c = (char*) strchr(name, ' ')) { // cast required by Sun
*c = '_';
modified = 1;
}
if(modified)
garcon()->msout << ms_info
<< "Group name changed to \"" << name << "\""
<< endl << ms_normal;
if(name == "")
garcon()->msout << ms_error << "Can't create a group with no name!"
<< endl << ms_normal;
else
current_goof->add_group(name);
}
}
virtual CommandM *clone() const {
NewPixelGroupCmd *ngc = new NewPixelGroupCmd;
ngc->name = name;
return ngc;
}
};
static PixelGroup *getgroup() {
if(!current_goof) return 0;
CharString whichgroup = garcon()->get_command();
return current_goof->get_group(whichgroup);
}
// functions operating on groups
static CommandFn addpixels() {
PixelGroup *g = getgroup();
if(g) {
current_goof->selected().weed();
g->append(current_goof->selected());
g->weed();
garcon()->msout << ms_info << "Group " << g->query_name()
<< " now contains " << g->size() << " pixels"
<< endl << ms_normal;
}
}
static CommandFn removepixels() {
PixelGroup *g = getgroup();
if(g) {
current_goof->selected().weed();
g->remove(current_goof->selected());
garcon()->msout << ms_info << "Group " << g->query_name()
<< " now contains " << g->size() << " pixels"
<< endl << ms_normal;
}
}
static CommandFn replacepixels() {
PixelGroup *g = getgroup();
if(g) {
g->clear();
current_goof->selected().weed();
g->append(current_goof->selected());
garcon()->msout << ms_info << "Group " << g->query_name()
<< " now contains " << g->size() << " pixels"
<< endl << ms_normal;
}
}
static CommandFn removegroup() {
PixelGroup *g = getgroup();
if(g)
current_goof->remove_group(g->query_name());
}
static CommandFn selectgroup() {
PixelGroup *g = getgroup();
if(g) {
current_goof->init_selection(0);
current_goof->select(*g);
current_goof->redraw();
}
}
static CommandFn selectgroup_too() {
PixelGroup *g = getgroup();
if(g) {
current_goof->init_selection(1);
current_goof->select(*g);
current_goof->redraw();
}
}
static CommandFn interselectgroup() {
// select the intersection of the current selection and a group
PixelGroup *g = getgroup();
if(g) {
// don't call init_selection, because it's done in Goof::select_intersection
current_goof->select_intersection(*g);
current_goof->redraw();
}
}
static CommandFn unselectgroup() {
// select the intersection of the complement of the current
// selection and a group
PixelGroup *g = getgroup();
if(g) {
// don't call init_selection, because it's done in Goof::select_intersection
current_goof->select_intersection(*g, 1);
current_goof->redraw();
}
}
static CommandFn select_all_groups() {
if(current_goof) {
current_goof->init_selection(0);
current_goof->select_all_groups();
current_goof->redraw();
}
}
static CommandFn select_all_groups_too() {
if(current_goof) {
current_goof->init_selection(1);
current_goof->select_all_groups();
current_goof->redraw();
}
}
static CommandFn infogroup() {
PixelGroup *g = getgroup();
if(g) {
g->weed();
double total = current_goof->query_width()*current_goof->query_height();
garcon()->msout << "Group " << g->query_name() << " contains "
<< g->size() << " pixels ("
<< g->size()/total*100 << "% of the image)" << endl;
}
}
// ---------------------------------------------------- //
Menu *groupselectmenu() {
static Menu *menu = 0;
if(menu) return menu;
menu = new GroupMenu<Cell_coordinate>("select group",
"select all pixels in group",
selectgroup);
menu->AddCommand("all_groups", "select all groups", select_all_groups);
return menu;
}
Menu *groupselectmenu_too() {
static Menu *menu = 0;
if(menu) return menu;
menu = new GroupMenu<Cell_coordinate>("also select group",
"also select all pixels in group",
selectgroup_too);
menu->AddCommand("all_groups", "select all groups", select_all_groups_too);
return menu;
}
Menu *groupinterselectmenu() {
static Menu *menu = 0;
if(menu) return menu;
menu = new GroupMenu<Cell_coordinate>("intersect",
"select intersection of selected pixels with group",
interselectgroup);
return menu;
}
Menu *unselectgroupmenu() {
static Menu *menu = 0;
if(menu) return menu;
menu = new GroupMenu<Cell_coordinate>("unselect",
"unselect the pixels in group",
unselectgroup);
return menu;
}
static Menu *groupinfomenu() {
static Menu *menu = 0;
if(menu) return menu;
menu = new GroupMenu<Cell_coordinate>("group information",
"print information about group",
infogroup);
return menu;
}
Menu *groupmenu() {
static Menu *menu = 0;
if(menu) return menu;
menu = new Menu("group");
menu->AddCommand(new NewPixelGroupCmd);
menu->AddSubMenu("delete", "delete a group",
new GroupMenu<Cell_coordinate>("delete groups", "delete group", removegroup));
menu->AddSubMenu("add", "add selected pixels to a group",
new GroupMenu<Cell_coordinate>("add pixels",
"add selected pixels to group", addpixels));
menu->AddSubMenu("remove", "remove selected pixels from a group",
new GroupMenu<Cell_coordinate>("remove pixels",
"remove selected pixels from group",
removepixels));
menu->AddSubMenu("replace", "replace a group with the selected pixels",
new GroupMenu<Cell_coordinate>("add pixels",
"use selected pixels to replace group",
replacepixels));
// This duplicates stuff in the "select" menu, and it doesn't have
// to be here as well, does it?
// menu->AddSubMenu("select",
// "select pixels in a group, unselecting all other pixels",
// groupselectmenu());
// menu->AddSubMenu("also_select",
// "select pixels in a group, keeping already selected pixels",
// groupselectmenu_too());
// menu->AddSubMenu("intersect_group",
// "select the intersection of a group with the previously selected pixels",
// groupinterselectmenu());
// menu->AddSubMenu("unselect_group", "unselect the pixels in a group",
// unselectgroupmenu());
menu->AddSubMenu("info", "print information about a group", groupinfomenu());
return menu;
}
//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//
void PixelGroup::calcEigenValues(double &eig1, double &eig2) const{
//calculates the Eigenvalues for a selection
double sumX=0, sumY=0 , sumXsquared=0, sumYsquared=0, sumXtimesY=0;
int i, count=0;;
//for every selected pixel that is in the burn
for(i=0; i<size(); i++){
Cell_coordinate here=(*this)[i];
if(current_goof->active(here)){
sumX+=here.x;
sumY+=here.y;
sumXsquared+=here.x*here.x;
sumYsquared+=here.y*here.y;
sumXtimesY+=here.x*here.y;
count++;
}
}
//get average coordinates
double meanX=sumX/(double)count;
double meanY=sumY/(double)count;
//calculate matrix values
double deltaXsquared=sumXsquared-meanX*meanX*count;
double deltaYsquared=sumYsquared-meanY*meanY*count;
double deltaXdeltaY=sumXtimesY-meanX*meanY*count;
//solve the matrix equation using the quadratic formula
//to get the two Eigen values
double a=1;
double b=-(deltaXsquared+deltaYsquared); //matrix -(a+d)
double c=deltaXsquared*deltaYsquared-deltaXdeltaY*deltaXdeltaY; //matrix ad-bc
double q=0;
if(b<0)
q=-.5*(b-sqrt(b*b-4*a*c));
else
q=-.5*(b+sqrt(b*b-4*a*c));
if(count!=0){
eig1=q/a;
eig2=c/q;
}
else{
garcon()->msout << ms_error << "No selected pixels" << endl << ms_normal;
}
}
//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//=\\=//
double PixelGroup::aspectRatio() const{
//returns the aspect ratio of a selection
double eig1=0, eig2=1;
calcEigenValues(eig1, eig2);
return sqrt(eig1/eig2); //0 is returned if no pixels are selected
}
syntax highlighted by Code2HTML, v. 0.9.1