// -*- 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 //template // do I need this? //Vec*> GroupMenu::menulist; unsigned int PixelGroup::ngroups = 0; PixelGroup::~PixelGroup() { // remove this group from lists stored in pixels for(int i=0; ipixelgrouplist[members[i]].Remove(this); } void PixelGroup::append(const Vec &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; ipixelgrouplist[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 &grp) { append(grp.membership()); } void PixelGroup::clear() { // remove this group from lists stored in pixels for(int i=0; ipixelgrouplist[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 &pxls) { remove_base(pxls); if(name != "") { for(int i=0; ipixelgrouplist[pxls[i]].Remove(this); if(current_goof->mesh()) current_goof->mesh()->groups_need_recomputing(); ++current_goof->groups_changed; } } void PixelGroup::remove(const Group &grp) { remove(grp.membership()); } void PixelGroup::trim(const Cell_coordinate &pxl) { Group::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::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 sel(height, width); sel.clear(0); for(int i=0; igroup_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("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("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("intersect", "select intersection of selected pixels with group", interselectgroup); return menu; } Menu *unselectgroupmenu() { static Menu *menu = 0; if(menu) return menu; menu = new GroupMenu("unselect", "unselect the pixels in group", unselectgroup); return menu; } static Menu *groupinfomenu() { static Menu *menu = 0; if(menu) return menu; menu = new GroupMenu("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("delete groups", "delete group", removegroup)); menu->AddSubMenu("add", "add selected pixels to a group", new GroupMenu("add pixels", "add selected pixels to group", addpixels)); menu->AddSubMenu("remove", "remove selected pixels from a group", new GroupMenu("remove pixels", "remove selected pixels from group", removepixels)); menu->AddSubMenu("replace", "replace a group with the selected pixels", new GroupMenu("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; iactive(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 }