<commit_before>#include "analyzer_good_kf.h"

#include "util.h"
#include "analyzer_util.h"

bool Analyzer_Good_KF::configure(INIReader *config) {
    if (!Analyzer::configure(config)) {
	return false;
    }

    for (std::map<const std::string, kf_variance>::const_iterator it = _variances.begin();
         it != _variances.end();
         ++it) {
        std::string name = (*it).first;

        _variances[name].threshold_warn = config->GetReal(
            "loganalyzer",
            string_format("%s::variance::%s::threshold_warn",
                          shortname_lc().c_str(),
                          name.c_str()),
            0.5f);
        _variances[name].threshold_fail = config->GetReal(
            "loganalyzer",
            string_format("%s::variance::%s::threshold_fail",
                          shortname_lc().c_str(),
                          name.c_str()),
            1.0f);
    }

    return true;
}

void Analyzer_Good_KF::end_of_log(uint32_t packet_count UNUSED)
{
    std::map<const std::string, double> my_variances = variances();

    for (std::map<const std::string, double>::const_iterator it = my_variances.begin();
         it != my_variances.end();
         ++it) {
        // ::fprintf(stderr, "would evaluate (%s)\n", (*it).first.c_str());
        std::string name = (*it).first;
        if (_results[name] != NULL) {
            close_variance_result(name);
        }
    }
    if (_result_flags != NULL) {
        close_result_flags();
    }

    for (std::map<const std::string, double>::const_iterator it = my_variances.begin();
         it != my_variances.end();
         ++it) {
        std::string name = (*it).first;
        if (!variance_T(name)) {
            Analyzer_Result_Summary *summary = new Analyzer_Result_Summary();
            summary->set_status(analyzer_status_warn);
            summary->set_reason(string_format("%s was never updated", name.c_str()));
            summary->add_source(_data_sources.get(
                                    string_format("%s_VARIANCES_%s",
                                                  shortname().c_str(),
                                                  name.c_str())));
            add_result(summary);
        }
    }

    if (!flags_T()) {
        Analyzer_Result_Summary *summary = new Analyzer_Result_Summary();
        summary->set_status(analyzer_status_warn);
        summary->set_reason(string_format("%s flags were never updated",
                                          shortname().c_str()));
        summary->add_source(_data_sources.get(string_format("%s_FLAGS",
                                                            shortname().c_str())));
        add_result(summary);
    }

}

bool Analyzer_Good_KF::flags_bad(uint16_t flags)
{
    for (uint16_t i=1; i<EKF_STATUS_FLAGS_ENUM_END; i<<=1) {
        if (!(flags & i)) {
            return true;
        }
    }
    return false;
}

void Analyzer_Good_KF::close_variance_result(const std::string name)
{
    Analyzer_Good_KF_Result_Variance *result = _results[name];
    kf_variance *variance = result->variance();

    result->set_T_stop(_vehicle->T());
    result->add_evidence(string_format("max-variance=%f", result->max()));
    if (result->max() > variance->threshold_fail) {
        result->set_status(analyzer_status_fail);
        result->set_reason(string_format("%s exceeds fail threshold", name.c_str()));
        result->add_evidence(string_format("threshold=%f", variance->threshold_fail));
        result->increase_severity_score(10);
    } else if (result->max() > variance->threshold_warn) {
        result->set_status(analyzer_status_warn);
        result->set_reason(string_format("%s exceeds warn threshold", name.c_str()));
        result->add_evidence(string_format("threshold=%f", variance->threshold_warn));
        result->increase_severity_score(4);
    } else {
        // should not happen
        ::fprintf(stderr, "Have a result with max less than threshold?!\n");
    }
    if (_vehicle->any_acc_clipping()) {
        result->add_evidence("Vehicle Accelerometers Clipping");
    }
    add_result(result);
    _results[name] = NULL;
}

void Analyzer_Good_KF::evaluate_variance(kf_variance &variance, double value)
{

    Analyzer_Good_KF_Result_Variance *result = _results[variance.name];

    if (result == NULL) {
        if (value > variance.threshold_warn) {
            // we have exceeeded a threshold
            result = new Analyzer_Good_KF_Result_Variance();
            result->add_source(_data_sources.get(string_format("%s_VARIANCES_%s", shortname().c_str(), variance.name)));
            result->set_variance(&variance);
            result->set_T_start(_vehicle->T());
            result->set_max(value);
            _results[variance.name] = result;
        }
    } else {
        // event is underway
        if (value > result->max()) {
            // a new record!
            result->set_max(value);
        } else if (value > variance.threshold_warn) {
            // we continue to exceed variances...
        } else {
            // our variances have come down sufficiently to close this instance
            close_variance_result(variance.name);
        }
    }
}

void Analyzer_Good_KF::evaluate_variances()
{
    std::map<const std::string, double> my_variances = variances();

    for (std::map<const std::string, double>::const_iterator it = my_variances.begin();
         it != my_variances.end();
         ++it) {
        std::string name = (*it).first;
        if (_variances.count(name) == 0) {
            // set a flag and warn?
            fprintf(stderr, "Unknown variance %s\n", name.c_str());
            continue;
        }
        kf_variance &variance = _variances[name];
        evaluate_variance(variance, (*it).second);
    }
}

void Analyzer_Good_KF::close_result_flags()
{
    _result_flags->set_T_stop(_vehicle->T());
    add_result(_result_flags);
    _result_flags = NULL;
}

void Analyzer_Good_KF::open_result_flags(uint16_t flags)
{
    _result_flags = new Analyzer_Good_KF_Result_Flags();
    _result_flags->set_T_start(_vehicle->T());
    _result_flags->set_status(analyzer_status_fail);
    _result_flags->set_flags(flags);
    _result_flags->add_source(_data_sources.get(string_format("%s_FLAGS", shortname().c_str())));
    _result_flags->set_reason(string_format("The %s status report indicates a problem with the EKF", shortname().c_str()));
    _result_flags->set_flags(this->flags());

    _result_flags->add_evidence(string_format("flags=%d", flags));
    // TODO: put the flags and the "bad" descrption into a structure
    _result_flags->increase_severity_score(10);
    if (!(flags & EKF_ATTITUDE)) {
        _result_flags->increase_severity_score(1);
        _result_flags->add_evidence("attitude estimate bad");
    }
    if (!(flags & EKF_VELOCITY_HORIZ)) {
        _result_flags->increase_severity_score(1);
        _result_flags->add_evidence("horizontal velocity estimate bad");
    }
    if (!(flags & EKF_VELOCITY_VERT)) {
        _result_flags->increase_severity_score(1);
        _result_flags->add_evidence("vertical velocity estimate bad");
    }
    if (!(flags & EKF_POS_HORIZ_REL)) {
        _result_flags->increase_severity_score(1);
        _result_flags->add_evidence("horizontal position (relative) estimate bad");
    }
    if (!(flags & EKF_POS_HORIZ_ABS)) {
        _result_flags->increase_severity_score(1);
        _result_flags->add_evidence("horizontal position (absolute) estimate bad");
    }
    if (!(flags & EKF_POS_VERT_ABS)) {
        _result_flags->increase_severity_score(1);
        _result_flags->add_evidence("vertical position (absolute) estimate bad");
    }
    if (!(flags & EKF_POS_VERT_AGL)) {
        _result_flags->increase_severity_score(1);
        _result_flags->add_evidence("vertical position (above ground) estimate bad");
    }
    if (!(flags & EKF_CONST_POS_MODE)) {
        _result_flags->increase_severity_score(1);
        _result_flags->add_evidence("In constant position mode (no abs or rel position)");
    }
    if (!(flags & EKF_PRED_POS_HORIZ_REL)) {
        _result_flags->increase_severity_score(1);
        _result_flags->add_evidence("Predicted horizontal position (relative) bad");
    }
    if (!(flags & EKF_PRED_POS_HORIZ_ABS)) {
        _result_flags->increase_severity_score(1);
        _result_flags->add_evidence("Predicted horizontal position (absolute) bad");
    }

    if (_vehicle->any_acc_clipping()) {
        _result_flags->add_evidence("Vehicle Accelerometers Clipping");
    }
}

// FIXME: should be taking timestamps from ekf_flags_t rather than
// _vehicle->T()
void Analyzer_Good_KF::evaluate_flags()
{
    if (_result_flags == NULL) {
        if (flags_T()) {
            if (flags_bad(flags())) {
                // start a new incident
                open_result_flags(flags());
            }
        }
    } else {
        // ::fprintf(stderr, "flags: %d\n", _vehicle->ekf_flags());
        // incident is under way
        if (_result_flags->flags() != flags()) {
            // close off the old one
            close_result_flags();
            _result_flags = NULL;
            if (flags_bad(flags())) {
                // new flags are also bad!
                open_result_flags(flags());
            }
        }
    }
}

void Analyzer_Good_KF::evaluate()
{
    evaluate_variances();
    evaluate_flags();
}
<commit_msg>analyzer_good_kf: correct checking of constant-position-mode flag<commit_after>#include "analyzer_good_kf.h"

#include "util.h"
#include "analyzer_util.h"

bool Analyzer_Good_KF::configure(INIReader *config) {
    if (!Analyzer::configure(config)) {
	return false;
    }

    for (std::map<const std::string, kf_variance>::const_iterator it = _variances.begin();
         it != _variances.end();
         ++it) {
        std::string name = (*it).first;

        _variances[name].threshold_warn = config->GetReal(
            "loganalyzer",
            string_format("%s::variance::%s::threshold_warn",
                          shortname_lc().c_str(),
                          name.c_str()),
            0.5f);
        _variances[name].threshold_fail = config->GetReal(
            "loganalyzer",
            string_format("%s::variance::%s::threshold_fail",
                          shortname_lc().c_str(),
                          name.c_str()),
            1.0f);
    }

    return true;
}

void Analyzer_Good_KF::end_of_log(uint32_t packet_count UNUSED)
{
    std::map<const std::string, double> my_variances = variances();

    for (std::map<const std::string, double>::const_iterator it = my_variances.begin();
         it != my_variances.end();
         ++it) {
        // ::fprintf(stderr, "would evaluate (%s)\n", (*it).first.c_str());
        std::string name = (*it).first;
        if (_results[name] != NULL) {
            close_variance_result(name);
        }
    }
    if (_result_flags != NULL) {
        close_result_flags();
    }

    for (std::map<const std::string, double>::const_iterator it = my_variances.begin();
         it != my_variances.end();
         ++it) {
        std::string name = (*it).first;
        if (!variance_T(name)) {
            Analyzer_Result_Summary *summary = new Analyzer_Result_Summary();
            summary->set_status(analyzer_status_warn);
            summary->set_reason(string_format("%s was never updated", name.c_str()));
            summary->add_source(_data_sources.get(
                                    string_format("%s_VARIANCES_%s",
                                                  shortname().c_str(),
                                                  name.c_str())));
            add_result(summary);
        }
    }

    if (!flags_T()) {
        Analyzer_Result_Summary *summary = new Analyzer_Result_Summary();
        summary->set_status(analyzer_status_warn);
        summary->set_reason(string_format("%s flags were never updated",
                                          shortname().c_str()));
        summary->add_source(_data_sources.get(string_format("%s_FLAGS",
                                                            shortname().c_str())));
        add_result(summary);
    }

}

bool Analyzer_Good_KF::flags_bad(uint16_t flags)
{
    for (uint16_t i=1; i<EKF_STATUS_FLAGS_ENUM_END; i<<=1) {
        if (!(flags & i)) {
            return true;
        }
    }
    return false;
}

void Analyzer_Good_KF::close_variance_result(const std::string name)
{
    Analyzer_Good_KF_Result_Variance *result = _results[name];
    kf_variance *variance = result->variance();

    result->set_T_stop(_vehicle->T());
    result->add_evidence(string_format("max-variance=%f", result->max()));
    if (result->max() > variance->threshold_fail) {
        result->set_status(analyzer_status_fail);
        result->set_reason(string_format("%s exceeds fail threshold", name.c_str()));
        result->add_evidence(string_format("threshold=%f", variance->threshold_fail));
        result->increase_severity_score(10);
    } else if (result->max() > variance->threshold_warn) {
        result->set_status(analyzer_status_warn);
        result->set_reason(string_format("%s exceeds warn threshold", name.c_str()));
        result->add_evidence(string_format("threshold=%f", variance->threshold_warn));
        result->increase_severity_score(4);
    } else {
        // should not happen
        ::fprintf(stderr, "Have a result with max less than threshold?!\n");
    }
    if (_vehicle->any_acc_clipping()) {
        result->add_evidence("Vehicle Accelerometers Clipping");
    }
    add_result(result);
    _results[name] = NULL;
}

void Analyzer_Good_KF::evaluate_variance(kf_variance &variance, double value)
{

    Analyzer_Good_KF_Result_Variance *result = _results[variance.name];

    if (result == NULL) {
        if (value > variance.threshold_warn) {
            // we have exceeeded a threshold
            result = new Analyzer_Good_KF_Result_Variance();
            result->add_source(_data_sources.get(string_format("%s_VARIANCES_%s", shortname().c_str(), variance.name)));
            result->set_variance(&variance);
            result->set_T_start(_vehicle->T());
            result->set_max(value);
            _results[variance.name] = result;
        }
    } else {
        // event is underway
        if (value > result->max()) {
            // a new record!
            result->set_max(value);
        } else if (value > variance.threshold_warn) {
            // we continue to exceed variances...
        } else {
            // our variances have come down sufficiently to close this instance
            close_variance_result(variance.name);
        }
    }
}

void Analyzer_Good_KF::evaluate_variances()
{
    std::map<const std::string, double> my_variances = variances();

    for (std::map<const std::string, double>::const_iterator it = my_variances.begin();
         it != my_variances.end();
         ++it) {
        std::string name = (*it).first;
        if (_variances.count(name) == 0) {
            // set a flag and warn?
            fprintf(stderr, "Unknown variance %s\n", name.c_str());
            continue;
        }
        kf_variance &variance = _variances[name];
        evaluate_variance(variance, (*it).second);
    }
}

void Analyzer_Good_KF::close_result_flags()
{
    _result_flags->set_T_stop(_vehicle->T());
    add_result(_result_flags);
    _result_flags = NULL;
}

void Analyzer_Good_KF::open_result_flags(uint16_t flags)
{
    _result_flags = new Analyzer_Good_KF_Result_Flags();
    _result_flags->set_T_start(_vehicle->T());
    _result_flags->set_status(analyzer_status_fail);
    _result_flags->set_flags(flags);
    _result_flags->add_source(_data_sources.get(string_format("%s_FLAGS", shortname().c_str())));
    _result_flags->set_reason(string_format("The %s status report indicates a problem with the EKF", shortname().c_str()));
    _result_flags->set_flags(this->flags());

    _result_flags->add_evidence(string_format("flags=%d", flags));
    // TODO: put the flags and the "bad" descrption into a structure
    _result_flags->increase_severity_score(10);
    if (!(flags & EKF_ATTITUDE)) {
        _result_flags->increase_severity_score(1);
        _result_flags->add_evidence("attitude estimate bad");
    }
    if (!(flags & EKF_VELOCITY_HORIZ)) {
        _result_flags->increase_severity_score(1);
        _result_flags->add_evidence("horizontal velocity estimate bad");
    }
    if (!(flags & EKF_VELOCITY_VERT)) {
        _result_flags->increase_severity_score(1);
        _result_flags->add_evidence("vertical velocity estimate bad");
    }
    if (!(flags & EKF_POS_HORIZ_REL)) {
        _result_flags->increase_severity_score(1);
        _result_flags->add_evidence("horizontal position (relative) estimate bad");
    }
    if (!(flags & EKF_POS_HORIZ_ABS)) {
        _result_flags->increase_severity_score(1);
        _result_flags->add_evidence("horizontal position (absolute) estimate bad");
    }
    if (!(flags & EKF_POS_VERT_ABS)) {
        _result_flags->increase_severity_score(1);
        _result_flags->add_evidence("vertical position (absolute) estimate bad");
    }
    if (!(flags & EKF_POS_VERT_AGL)) {
        _result_flags->increase_severity_score(1);
        _result_flags->add_evidence("vertical position (above ground) estimate bad");
    }
    if (flags & EKF_CONST_POS_MODE) {
        _result_flags->increase_severity_score(1);
        _result_flags->add_evidence("In constant position mode (no abs or rel position)");
    }
    if (!(flags & EKF_PRED_POS_HORIZ_REL)) {
        _result_flags->increase_severity_score(1);
        _result_flags->add_evidence("Predicted horizontal position (relative) bad");
    }
    if (!(flags & EKF_PRED_POS_HORIZ_ABS)) {
        _result_flags->increase_severity_score(1);
        _result_flags->add_evidence("Predicted horizontal position (absolute) bad");
    }

    if (_vehicle->any_acc_clipping()) {
        _result_flags->add_evidence("Vehicle Accelerometers Clipping");
    }
}

// FIXME: should be taking timestamps from ekf_flags_t rather than
// _vehicle->T()
void Analyzer_Good_KF::evaluate_flags()
{
    if (_result_flags == NULL) {
        if (flags_T()) {
            if (flags_bad(flags())) {
                // start a new incident
                open_result_flags(flags());
            }
        }
    } else {
        // ::fprintf(stderr, "flags: %d\n", _vehicle->ekf_flags());
        // incident is under way
        if (_result_flags->flags() != flags()) {
            // close off the old one
            close_result_flags();
            _result_flags = NULL;
            if (flags_bad(flags())) {
                // new flags are also bad!
                open_result_flags(flags());
            }
        }
    }
}

void Analyzer_Good_KF::evaluate()
{
    evaluate_variances();
    evaluate_flags();
}
<|endoftext|>


<commit_before>#include "native_handler.h"
#include "include/cef_base.h"
#include "client_handler.h"
#include <iostream>
#include <sys/stat.h>
#include <sys/types.h>
#include <dirent.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <vector>

using namespace std;

NativeHandler::NativeHandler() :
		CefV8Handler() {
	object = CefV8Value::CreateObject(NULL, NULL);

	const char *functionNames[] = { "exists", "alert", "read", "write",
			"absolute", "list", "isFile", "isDirectory", "remove", "asyncList",
			"open", "openDialog", "quit", "writeToPasteboard",
			"readFromPasteboard", "showDevTools", "newWindow", "saveDialog",
			"exit", "watchPath", "unwatchPath", "makeDirectory", "move",
			"moveToTrash" };
	int arrayLength = sizeof(functionNames) / sizeof(const char *);
	for (int i = 0; i < arrayLength; i++) {
		const char *functionName = functionNames[i];
		CefRefPtr<CefV8Value> function = CefV8Value::CreateFunction(
				functionName, this);
		object->SetValue(functionName, function, V8_PROPERTY_ATTRIBUTE_NONE);
	}
}

void NativeHandler::Exists(const CefString& name, CefRefPtr<CefV8Value> object,
		const CefV8ValueList& arguments, CefRefPtr<CefV8Value>& retval,
		CefString& exception) {
	string path = arguments[0]->GetStringValue().ToString();
	struct stat sbuf;
	int result = stat(path.c_str(), &sbuf);
	retval = CefV8Value::CreateBool(result == 0);
}

void NativeHandler::Read(const CefString& name, CefRefPtr<CefV8Value> object,
		const CefV8ValueList& arguments, CefRefPtr<CefV8Value>& retval,
		CefString& exception) {
	string path = arguments[0]->GetStringValue().ToString();
	int fd = open(path.c_str(), O_RDONLY);
	if (fd < 0)
		return;

	char buffer[8192];
	int r;
	string value;
	while ((r = read(fd, buffer, sizeof buffer)) > 0)
		value.append(buffer, 0, r);
	close(fd);
	retval = CefV8Value::CreateString(value);
}

void NativeHandler::Absolute(const CefString& name,
		CefRefPtr<CefV8Value> object, const CefV8ValueList& arguments,
		CefRefPtr<CefV8Value>& retval, CefString& exception) {
	string path = arguments[0]->GetStringValue().ToString();
	if (path[0] == '~') {
		string resolved = getenv("HOME");
		resolved.append(path.substr(1));
		retval = CefV8Value::CreateString(resolved);
	} else
		retval = CefV8Value::CreateString(path);
}

void NativeHandler::List(const CefString& name, CefRefPtr<CefV8Value> object,
		const CefV8ValueList& arguments, CefRefPtr<CefV8Value>& retval,
		CefString& exception) {
	string path = arguments[0]->GetStringValue().ToString();
	DIR *dir;
	if ((dir = opendir(path.c_str())) == NULL)
		return;

	vector < string > paths;
	dirent *entry;

	while ((entry = readdir(dir)) != NULL) {
		if (strcmp(entry->d_name, ".") == 0)
			continue;
		if (strcmp(entry->d_name, "..") == 0)
			continue;
		paths.push_back(entry->d_name);
	}

	closedir(dir);

	retval = CefV8Value::CreateArray();
	for (uint i = 0; i < paths.size(); i++)
		retval->SetValue(i, CefV8Value::CreateString(path + "/" + paths[i]));
}

void NativeHandler::IsFile(const CefString& name, CefRefPtr<CefV8Value> object,
		const CefV8ValueList& arguments, CefRefPtr<CefV8Value>& retval,
		CefString& exception) {
	string path = arguments[0]->GetStringValue().ToString();
	struct stat sbuf;
	int result = stat(path.c_str(), &sbuf);
	retval = CefV8Value::CreateBool(result == 0 && S_ISREG(sbuf.st_mode));
}

void NativeHandler::IsDirectory(const CefString& name,
		CefRefPtr<CefV8Value> object, const CefV8ValueList& arguments,
		CefRefPtr<CefV8Value>& retval, CefString& exception) {
	string path = arguments[0]->GetStringValue().ToString();
	struct stat sbuf;
	int result = stat(path.c_str(), &sbuf);
	retval = CefV8Value::CreateBool(result == 0 && S_ISDIR(sbuf.st_mode));
}

void NativeHandler::OpenDialog(const CefString& name,
		CefRefPtr<CefV8Value> object, const CefV8ValueList& arguments,
		CefRefPtr<CefV8Value>& retval, CefString& exception) {
	GtkWidget *dialog;
	dialog = gtk_file_chooser_dialog_new("Open File", GTK_WINDOW(window),
			GTK_FILE_CHOOSER_ACTION_OPEN, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
			GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, NULL);
	if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
		char *filename;
		filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
		retval = CefV8Value::CreateString(filename);
		g_free(filename);
	} else
		retval = CefV8Value::CreateNull();

	gtk_widget_destroy(dialog);
}

void NativeHandler::Open(const CefString& name,
		CefRefPtr<CefV8Value> object, const CefV8ValueList& arguments,
		CefRefPtr<CefV8Value>& retval, CefString& exception) {
	path = arguments[0]->GetStringValue().ToString();
	CefV8Context::GetCurrentContext()->GetBrowser()->Reload();
}

bool NativeHandler::Execute(const CefString& name, CefRefPtr<CefV8Value> object,
		const CefV8ValueList& arguments, CefRefPtr<CefV8Value>& retval,
		CefString& exception) {

	if (name == "exists")
		Exists(name, object, arguments, retval, exception);
	else if (name == "read")
		Read(name, object, arguments, retval, exception);
	else if (name == "absolute")
		Absolute(name, object, arguments, retval, exception);
	else if (name == "list")
		List(name, object, arguments, retval, exception);
	else if (name == "isFile")
		IsFile(name, object, arguments, retval, exception);
	else if (name == "isDirectory")
		IsDirectory(name, object, arguments, retval, exception);
	else if (name == "showDevTools")
		CefV8Context::GetCurrentContext()->GetBrowser()->ShowDevTools();
	else if (name == "openDialog")
		OpenDialog(name, object, arguments, retval, exception);
	else if(name =="open")
		Open(name, object, arguments, retval, exception);
	else
		cout << "Unhandled -> " + name.ToString() << " : "
				<< arguments[0]->GetStringValue().ToString() << endl;
	return true;
}
<commit_msg>Add support for recursive directory listing<commit_after>#include "native_handler.h"
#include "include/cef_base.h"
#include "client_handler.h"
#include <iostream>
#include <sys/stat.h>
#include <sys/types.h>
#include <dirent.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <vector>

using namespace std;

NativeHandler::NativeHandler() :
		CefV8Handler() {
	object = CefV8Value::CreateObject(NULL, NULL);

	const char *functionNames[] = { "exists", "alert", "read", "write",
			"absolute", "list", "isFile", "isDirectory", "remove", "asyncList",
			"open", "openDialog", "quit", "writeToPasteboard",
			"readFromPasteboard", "showDevTools", "newWindow", "saveDialog",
			"exit", "watchPath", "unwatchPath", "makeDirectory", "move",
			"moveToTrash" };
	int arrayLength = sizeof(functionNames) / sizeof(const char *);
	for (int i = 0; i < arrayLength; i++) {
		const char *functionName = functionNames[i];
		CefRefPtr<CefV8Value> function = CefV8Value::CreateFunction(
				functionName, this);
		object->SetValue(functionName, function, V8_PROPERTY_ATTRIBUTE_NONE);
	}
}

void NativeHandler::Exists(const CefString& name, CefRefPtr<CefV8Value> object,
		const CefV8ValueList& arguments, CefRefPtr<CefV8Value>& retval,
		CefString& exception) {
	string path = arguments[0]->GetStringValue().ToString();
	struct stat sbuf;
	int result = stat(path.c_str(), &sbuf);
	retval = CefV8Value::CreateBool(result == 0);
}

void NativeHandler::Read(const CefString& name, CefRefPtr<CefV8Value> object,
		const CefV8ValueList& arguments, CefRefPtr<CefV8Value>& retval,
		CefString& exception) {
	string path = arguments[0]->GetStringValue().ToString();
	int fd = open(path.c_str(), O_RDONLY);
	if (fd < 0)
		return;

	char buffer[8192];
	int r;
	string value;
	while ((r = read(fd, buffer, sizeof buffer)) > 0)
		value.append(buffer, 0, r);
	close(fd);
	retval = CefV8Value::CreateString(value);
}

void NativeHandler::Absolute(const CefString& name,
		CefRefPtr<CefV8Value> object, const CefV8ValueList& arguments,
		CefRefPtr<CefV8Value>& retval, CefString& exception) {
	string path = arguments[0]->GetStringValue().ToString();
	if (path[0] == '~') {
		string resolved = getenv("HOME");
		resolved.append(path.substr(1));
		retval = CefV8Value::CreateString(resolved);
	} else
		retval = CefV8Value::CreateString(path);
}

void ListDirectory(string path, vector<string>* paths, bool recursive) {
	DIR *dir;
	if ((dir = opendir(path.c_str())) == NULL)
		return;

	dirent *entry;

	while ((entry = readdir(dir)) != NULL) {
		if (strcmp(entry->d_name, ".") == 0)
			continue;
		if (strcmp(entry->d_name, "..") == 0)
			continue;
		string entryPath;
		entryPath = path + "/" + entry->d_name;
		paths->push_back(entryPath);
		if (recursive)
			ListDirectory(entryPath, paths, recursive);
	}

	closedir(dir);
}

void NativeHandler::List(const CefString& name, CefRefPtr<CefV8Value> object,
		const CefV8ValueList& arguments, CefRefPtr<CefV8Value>& retval,
		CefString& exception) {
	string path = arguments[0]->GetStringValue().ToString();
	bool recursive = arguments[1]->GetBoolValue();
	vector < string > *paths = new vector<string>;
	ListDirectory(path, paths, recursive);

	retval = CefV8Value::CreateArray();
	for (uint i = 0; i < paths->size(); i++)
		retval->SetValue(i, CefV8Value::CreateString(paths->at(i)));
	free (paths);
}

void NativeHandler::IsFile(const CefString& name, CefRefPtr<CefV8Value> object,
		const CefV8ValueList& arguments, CefRefPtr<CefV8Value>& retval,
		CefString& exception) {
	string path = arguments[0]->GetStringValue().ToString();
	struct stat sbuf;
	int result = stat(path.c_str(), &sbuf);
	retval = CefV8Value::CreateBool(result == 0 && S_ISREG(sbuf.st_mode));
}

void NativeHandler::IsDirectory(const CefString& name,
		CefRefPtr<CefV8Value> object, const CefV8ValueList& arguments,
		CefRefPtr<CefV8Value>& retval, CefString& exception) {
	string path = arguments[0]->GetStringValue().ToString();
	struct stat sbuf;
	int result = stat(path.c_str(), &sbuf);
	retval = CefV8Value::CreateBool(result == 0 && S_ISDIR(sbuf.st_mode));
}

void NativeHandler::OpenDialog(const CefString& name,
		CefRefPtr<CefV8Value> object, const CefV8ValueList& arguments,
		CefRefPtr<CefV8Value>& retval, CefString& exception) {
	GtkWidget *dialog;
	dialog = gtk_file_chooser_dialog_new("Open File", GTK_WINDOW(window),
			GTK_FILE_CHOOSER_ACTION_OPEN, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
			GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, NULL);
	if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
		char *filename;
		filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
		retval = CefV8Value::CreateString(filename);
		g_free(filename);
	} else
		retval = CefV8Value::CreateNull();

	gtk_widget_destroy(dialog);
}

void NativeHandler::Open(const CefString& name, CefRefPtr<CefV8Value> object,
		const CefV8ValueList& arguments, CefRefPtr<CefV8Value>& retval,
		CefString& exception) {
	path = arguments[0]->GetStringValue().ToString();
	CefV8Context::GetCurrentContext()->GetBrowser()->Reload();
}

bool NativeHandler::Execute(const CefString& name, CefRefPtr<CefV8Value> object,
		const CefV8ValueList& arguments, CefRefPtr<CefV8Value>& retval,
		CefString& exception) {

	if (name == "exists")
		Exists(name, object, arguments, retval, exception);
	else if (name == "read")
		Read(name, object, arguments, retval, exception);
	else if (name == "absolute")
		Absolute(name, object, arguments, retval, exception);
	else if (name == "list")
		List(name, object, arguments, retval, exception);
	else if (name == "isFile")
		IsFile(name, object, arguments, retval, exception);
	else if (name == "isDirectory")
		IsDirectory(name, object, arguments, retval, exception);
	else if (name == "showDevTools")
		CefV8Context::GetCurrentContext()->GetBrowser()->ShowDevTools();
	else if (name == "openDialog")
		OpenDialog(name, object, arguments, retval, exception);
	else if (name == "open")
		Open(name, object, arguments, retval, exception);
	else
		cout << "Unhandled -> " + name.ToString() << " : "
				<< arguments[0]->GetStringValue().ToString() << endl;
	return true;
}
<|endoftext|>


<commit_before>/*********************************************************************************
 *
 * Inviwo - Interactive Visualization Workshop
 *
 * Copyright (c) 2013-2021 Inviwo Foundation
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *********************************************************************************/

#include <modules/fontrendering/processors/textoverlaygl.h>
#include <modules/fontrendering/util/fontutils.h>

#include <inviwo/core/common/inviwoapplication.h>
#include <inviwo/core/datastructures/image/image.h>
#include <modules/opengl/inviwoopengl.h>
#include <modules/opengl/texture/textureutils.h>
#include <modules/opengl/openglutils.h>
#include <modules/opengl/shader/shaderutils.h>
#include <modules/opengl/image/imagegl.h>
#include <inviwo/core/util/assertion.h>
#include <inviwo/core/util/rendercontext.h>
#include <inviwo/core/util/zip.h>
#include <inviwo/core/io/serialization/versionconverter.h>

#include <cctype>
#include <locale>

#include <fmt/format.h>
#include <fmt/args.h>

namespace inviwo {

const std::string TextOverlayProperty::classIdentifier = "org.inviwo.TextOverlayProperty";
std::string TextOverlayProperty::getClassIdentifier() const { return classIdentifier; }

TextOverlayProperty::TextOverlayProperty(std::string_view identifier, std::string_view displayName,
                                         InvalidationLevel invalidationLevel,
                                         PropertySemantics semantics)
    : CompositeProperty(identifier, displayName, invalidationLevel, semantics)
    , text("text", "Text", "Lorem ipsum etc.", InvalidationLevel::InvalidOutput,
           PropertySemantics::TextEditor)
    , position("position", "Position", vec2(0.0f), vec2(0.0f), vec2(1.0f), vec2(0.01f))
    , offset("offset", "Offset (Pixel)", ivec2(0), ivec2(-100), ivec2(100)) {
    addProperties(text, position, offset);
}
TextOverlayProperty::TextOverlayProperty(const TextOverlayProperty& rhs)
    : CompositeProperty(rhs), text{rhs.text}, position{rhs.position}, offset{rhs.offset} {
    addProperties(text, position, offset);
}
TextOverlayProperty* TextOverlayProperty::clone() const { return new TextOverlayProperty(*this); }

const ProcessorInfo TextOverlayGL::processorInfo_{
    "org.inviwo.TextOverlayGL",  // Class identifier
    "Text Overlay",              // Display name
    "Drawing",                   // Category
    CodeState::Stable,           // Code state
    "GL, Font, Text",            // Tags
};
const ProcessorInfo TextOverlayGL::getProcessorInfo() const { return processorInfo_; }

TextOverlayGL::TextOverlayGL()
    : Processor()
    , inport_("inport")
    , outport_("outport")
    , enable_("enable", "Enabled", true)
    , texts_{"texts", "Texts", std::make_unique<TextOverlayProperty>("text0", "Text 0"), 0,
             ListPropertyUIFlag::Add | ListPropertyUIFlag::Remove}
    , color_("color", "Color", vec4(1.0f), vec4(0.0f), vec4(1.0f), vec4(0.01f),
             InvalidationLevel::InvalidOutput, PropertySemantics::Color)
    , font_("font", "Font Settings")
    , args_{"args", "Arguments",
            []() {
                std::vector<std::unique_ptr<Property>> props;
                props.emplace_back(std::make_unique<StringProperty>("arg0", "String Arg 0"));
                props.emplace_back(std::make_unique<IntProperty>("arg0", "Int Arg 0"));
                props.emplace_back(std::make_unique<DoubleProperty>("arg0", "Double Arg 0"));
                return props;
            }(),
            0, ListPropertyUIFlag::Add | ListPropertyUIFlag::Remove}
    , textRenderer_{[]() {
        // ensure the default context is active when creating the TextRenderer
        RenderContext::getPtr()->activateDefaultRenderContext();
        return TextRenderer{};
    }()} {

    addPorts(inport_, outport_);
    addProperties(enable_, font_, texts_, args_);
    font_.addProperties(color_);
    inport_.setOptional(true);

    texts_.constructProperty(0);
    font_.fontFace_.setSelectedIdentifier("arial");
    font_.fontSize_.set(14);

    setAllPropertiesCurrentStateAsDefault();
}

void TextOverlayGL::process() {
    if (!enable_.get()) {
        outport_.setData(inport_.getData());
        return;
    }

    if (font_.fontFace_.isModified()) {
        textRenderer_.setFont(font_.fontFace_.get());
    }

    // check whether a property was modified
    if (textObjects_.size() != texts_.size() || texts_.isModified() || color_.isModified() ||
        font_.isModified() || util::any_of(args_.getProperties(), &Property::isModified)) {
        updateCache();
    }

    // draw cached overlay on top of the input image
    if (inport_.isReady()) {
        utilgl::activateTargetAndCopySource(outport_, inport_, ImageType::ColorDepth);
    } else {
        utilgl::activateAndClearTarget(outport_, ImageType::ColorDepth);
    }

    utilgl::DepthFuncState depthFunc(GL_ALWAYS);
    utilgl::BlendModeState blending(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);

    for (auto&& [item, tex] : util::zip(texts_, textObjects_)) {
        if (auto tp = dynamic_cast<const TextOverlayProperty*>(item)) {
            // use integer position for best results
            vec2 size(tex.bbox.textExtent);
            vec2 shift = 0.5f * size * (font_.anchorPos_.get() + vec2(1.0f, 1.0f));

            ivec2 pos(tp->position.get() * vec2(outport_.getDimensions()));
            pos += tp->offset.get() - ivec2(shift);

            // render texture containing the text onto the current canvas
            textureRenderer_.render(tex.texture, pos + tex.bbox.glyphsOrigin,
                                    outport_.getDimensions());
        }
    }

    utilgl::deactivateCurrentTarget();
}

void TextOverlayGL::updateCache() {
    textRenderer_.setFontSize(font_.fontSize_.get());
    textRenderer_.setLineSpacing(font_.lineSpacing_.get());

    auto store = fmt::dynamic_format_arg_store<fmt::format_context>();
    for (auto item : args_) {
        if (auto sp = dynamic_cast<const StringProperty*>(item)) {
            store.push_back(fmt::arg(sp->getIdentifier().c_str(), sp->get()));
        } else if (auto ip = dynamic_cast<const IntProperty*>(item)) {
            store.push_back(fmt::arg(ip->getIdentifier().c_str(), ip->get()));
        } else if (auto dp = dynamic_cast<const DoubleProperty*>(item)) {
            store.push_back(fmt::arg(dp->getIdentifier().c_str(), dp->get()));
        }
    }

    textObjects_.resize(texts_.size());
    for (auto&& [item, tex] : util::zip(texts_, textObjects_)) {
        if (auto tp = dynamic_cast<const TextOverlayProperty*>(item)) {
            std::string text;
            try {
                text = fmt::vformat(tp->text.get(), store);
            } catch (const fmt::format_error&) {
                LogWarn(
                    fmt::format("Invalid formatting string {}:'{}'\nFormat uses fmt syntax, args "
                                "can be named by index {{0}} or by name {{arg0}}",
                                tp->getPath(), tp->text.get()));
                text = "<Invalid Format!>";
            }
            tex = util::createTextTextureObject(textRenderer_, text, color_.get(), tex.texture);
        }
    }
}

}  // namespace inviwo
<commit_msg>Fontrendering: fmt fix<commit_after>/*********************************************************************************
 *
 * Inviwo - Interactive Visualization Workshop
 *
 * Copyright (c) 2013-2021 Inviwo Foundation
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *********************************************************************************/

#include <modules/fontrendering/processors/textoverlaygl.h>
#include <modules/fontrendering/util/fontutils.h>

#include <inviwo/core/common/inviwoapplication.h>
#include <inviwo/core/datastructures/image/image.h>
#include <modules/opengl/inviwoopengl.h>
#include <modules/opengl/texture/textureutils.h>
#include <modules/opengl/openglutils.h>
#include <modules/opengl/shader/shaderutils.h>
#include <modules/opengl/image/imagegl.h>
#include <inviwo/core/util/assertion.h>
#include <inviwo/core/util/rendercontext.h>
#include <inviwo/core/util/zip.h>
#include <inviwo/core/io/serialization/versionconverter.h>

#include <cctype>
#include <locale>

#include <fmt/format.h>

#if __has_include(<fmt/args.h>) // New in fmt v8
#include <fmt/args.h>
#endif

namespace inviwo {

const std::string TextOverlayProperty::classIdentifier = "org.inviwo.TextOverlayProperty";
std::string TextOverlayProperty::getClassIdentifier() const { return classIdentifier; }

TextOverlayProperty::TextOverlayProperty(std::string_view identifier, std::string_view displayName,
                                         InvalidationLevel invalidationLevel,
                                         PropertySemantics semantics)
    : CompositeProperty(identifier, displayName, invalidationLevel, semantics)
    , text("text", "Text", "Lorem ipsum etc.", InvalidationLevel::InvalidOutput,
           PropertySemantics::TextEditor)
    , position("position", "Position", vec2(0.0f), vec2(0.0f), vec2(1.0f), vec2(0.01f))
    , offset("offset", "Offset (Pixel)", ivec2(0), ivec2(-100), ivec2(100)) {
    addProperties(text, position, offset);
}
TextOverlayProperty::TextOverlayProperty(const TextOverlayProperty& rhs)
    : CompositeProperty(rhs), text{rhs.text}, position{rhs.position}, offset{rhs.offset} {
    addProperties(text, position, offset);
}
TextOverlayProperty* TextOverlayProperty::clone() const { return new TextOverlayProperty(*this); }

const ProcessorInfo TextOverlayGL::processorInfo_{
    "org.inviwo.TextOverlayGL",  // Class identifier
    "Text Overlay",              // Display name
    "Drawing",                   // Category
    CodeState::Stable,           // Code state
    "GL, Font, Text",            // Tags
};
const ProcessorInfo TextOverlayGL::getProcessorInfo() const { return processorInfo_; }

TextOverlayGL::TextOverlayGL()
    : Processor()
    , inport_("inport")
    , outport_("outport")
    , enable_("enable", "Enabled", true)
    , texts_{"texts", "Texts", std::make_unique<TextOverlayProperty>("text0", "Text 0"), 0,
             ListPropertyUIFlag::Add | ListPropertyUIFlag::Remove}
    , color_("color", "Color", vec4(1.0f), vec4(0.0f), vec4(1.0f), vec4(0.01f),
             InvalidationLevel::InvalidOutput, PropertySemantics::Color)
    , font_("font", "Font Settings")
    , args_{"args", "Arguments",
            []() {
                std::vector<std::unique_ptr<Property>> props;
                props.emplace_back(std::make_unique<StringProperty>("arg0", "String Arg 0"));
                props.emplace_back(std::make_unique<IntProperty>("arg0", "Int Arg 0"));
                props.emplace_back(std::make_unique<DoubleProperty>("arg0", "Double Arg 0"));
                return props;
            }(),
            0, ListPropertyUIFlag::Add | ListPropertyUIFlag::Remove}
    , textRenderer_{[]() {
        // ensure the default context is active when creating the TextRenderer
        RenderContext::getPtr()->activateDefaultRenderContext();
        return TextRenderer{};
    }()} {

    addPorts(inport_, outport_);
    addProperties(enable_, font_, texts_, args_);
    font_.addProperties(color_);
    inport_.setOptional(true);

    texts_.constructProperty(0);
    font_.fontFace_.setSelectedIdentifier("arial");
    font_.fontSize_.set(14);

    setAllPropertiesCurrentStateAsDefault();
}

void TextOverlayGL::process() {
    if (!enable_.get()) {
        outport_.setData(inport_.getData());
        return;
    }

    if (font_.fontFace_.isModified()) {
        textRenderer_.setFont(font_.fontFace_.get());
    }

    // check whether a property was modified
    if (textObjects_.size() != texts_.size() || texts_.isModified() || color_.isModified() ||
        font_.isModified() || util::any_of(args_.getProperties(), &Property::isModified)) {
        updateCache();
    }

    // draw cached overlay on top of the input image
    if (inport_.isReady()) {
        utilgl::activateTargetAndCopySource(outport_, inport_, ImageType::ColorDepth);
    } else {
        utilgl::activateAndClearTarget(outport_, ImageType::ColorDepth);
    }

    utilgl::DepthFuncState depthFunc(GL_ALWAYS);
    utilgl::BlendModeState blending(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);

    for (auto&& [item, tex] : util::zip(texts_, textObjects_)) {
        if (auto tp = dynamic_cast<const TextOverlayProperty*>(item)) {
            // use integer position for best results
            vec2 size(tex.bbox.textExtent);
            vec2 shift = 0.5f * size * (font_.anchorPos_.get() + vec2(1.0f, 1.0f));

            ivec2 pos(tp->position.get() * vec2(outport_.getDimensions()));
            pos += tp->offset.get() - ivec2(shift);

            // render texture containing the text onto the current canvas
            textureRenderer_.render(tex.texture, pos + tex.bbox.glyphsOrigin,
                                    outport_.getDimensions());
        }
    }

    utilgl::deactivateCurrentTarget();
}

void TextOverlayGL::updateCache() {
    textRenderer_.setFontSize(font_.fontSize_.get());
    textRenderer_.setLineSpacing(font_.lineSpacing_.get());

    auto store = fmt::dynamic_format_arg_store<fmt::format_context>();
    for (auto item : args_) {
        if (auto sp = dynamic_cast<const StringProperty*>(item)) {
            store.push_back(fmt::arg(sp->getIdentifier().c_str(), sp->get()));
        } else if (auto ip = dynamic_cast<const IntProperty*>(item)) {
            store.push_back(fmt::arg(ip->getIdentifier().c_str(), ip->get()));
        } else if (auto dp = dynamic_cast<const DoubleProperty*>(item)) {
            store.push_back(fmt::arg(dp->getIdentifier().c_str(), dp->get()));
        }
    }

    textObjects_.resize(texts_.size());
    for (auto&& [item, tex] : util::zip(texts_, textObjects_)) {
        if (auto tp = dynamic_cast<const TextOverlayProperty*>(item)) {
            std::string text;
            try {
                text = fmt::vformat(tp->text.get(), store);
            } catch (const fmt::format_error&) {
                LogWarn(
                    fmt::format("Invalid formatting string {}:'{}'\nFormat uses fmt syntax, args "
                                "can be named by index {{0}} or by name {{arg0}}",
                                tp->getPath(), tp->text.get()));
                text = "<Invalid Format!>";
            }
            tex = util::createTextTextureObject(textRenderer_, text, color_.get(), tex.texture);
        }
    }
}

}  // namespace inviwo
<|endoftext|>


<commit_before>#include "solve_mcf.h"

void cacheAlg(std::vector<trEntry> & trace, uint64_t cacheSize) {
    std::unordered_map<std::pair<uint64_t, uint64_t>, trEntry*> cacheState;
    uint64_t currentSize = 0;

    for(size_t i=0; i<trace.size(); i++) {
        trEntry *cur = &trace[i];
        // check in cache
        if(cacheState.count(std::make_pair(cur->id,cur->size)) > 0) {
            // cache hit
            cur->hit = true;
        } else {
            // cache miss
            // admit if hasNext
            if(cur->hasNext && cur->size < cacheSize) {
                cacheState[std::make_pair(cur->id,cur->size)] = cur;
                currentSize += cur->size;
                LOG("admitted",cur->id,cur->size,currentSize);

                // evict if needed
                while(currentSize > cacheSize) {
                    //                    LOG("eviction needed",currentSize,cacheSize,0);

                    int64_t maxDistance = -1, curDistance;
                    trEntry * evictVictim = &trace[0];
                    for(auto & it: cacheState) {
                        trEntry * cand = it.second;
                        //LOG("cache Scan id",cand->id,cand->size,cand->nextSeen);
                        if(cand->nextSeen > i)
                            curDistance = (cand->nextSeen - i) * cand->size;
                        else
                            curDistance = (i - cand->nextSeen) * cand->size;
                        if(curDistance > maxDistance) {
                            maxDistance = curDistance;
                            evictVictim = cand;
                            //LOG("max dist",maxDistance,cand->id,cand->size);
                        }
                    }
                    LOG("vict",maxDistance,evictVictim->id,evictVictim->size);
                    cacheState.erase(std::make_pair(evictVictim->id, evictVictim->size));
                    currentSize -= evictVictim->size;
                }
            }
        }
    }
}

void printRes(std::vector<trEntry> & trace, std::string algName) {
    uint64_t hitc = 0, reqc = 0;
    for(auto & it: trace) {
        reqc++;
        if(it.hit)
            hitc++;
        LOG("tr",it.id,it.nextSeen,it.hit);
    }
    std::cout << algName << " hitc " << hitc << " reqc " << reqc << " ohr " << double(hitc)/reqc << std::endl;
}
<commit_msg>Belady2Size ex. fix<commit_after>#include "solve_mcf.h"

void cacheAlg(std::vector<trEntry> & trace, uint64_t cacheSize) {
    std::unordered_map<std::pair<uint64_t, uint64_t>, trEntry*> cacheState;
    uint64_t currentSize = 0;

    for(size_t i=0; i<trace.size(); i++) {
        trEntry *cur = &trace[i];
        // check in cache
        if(cacheState.count(std::make_pair(cur->id,cur->size)) > 0) {
            // cache hit
            cur->hit = true;
            cacheState[std::make_pair(cur->id,cur->size)] = cur;
        } else {
            // cache miss
            // admit if hasNext
            if(cur->hasNext && cur->size < cacheSize) {
                cacheState[std::make_pair(cur->id,cur->size)] = cur;
                currentSize += cur->size;
                LOG("admitted",cur->id,cur->size,currentSize);

                // evict if needed
                while(currentSize > cacheSize) {
                    //                    LOG("eviction needed",currentSize,cacheSize,0);

                    int64_t maxDistance = -1, curDistance;
                    trEntry * evictVictim = &trace[0];
                    for(auto & it: cacheState) {
                        trEntry * cand = it.second;
                        //LOG("cache Scan id",cand->id,cand->size,cand->nextSeen);
                        if(cand->nextSeen > i)
                            curDistance = (cand->nextSeen - i) * cand->size;
                        else
                            curDistance = (i - cand->nextSeen) * cand->size;
                        if(curDistance > maxDistance) {
                            maxDistance = curDistance;
                            evictVictim = cand;
                            //LOG("max dist",maxDistance,cand->id,cand->size);
                        }
                    }
                    LOG("vict",maxDistance,evictVictim->id,evictVictim->size);
                    cacheState.erase(std::make_pair(evictVictim->id, evictVictim->size));
                    currentSize -= evictVictim->size;
                }
            }
        }
    }
}

void printRes(std::vector<trEntry> & trace, std::string algName) {
    uint64_t hitc = 0, reqc = 0;
    for(auto & it: trace) {
        reqc++;
        if(it.hit)
            hitc++;
        LOG("tr",it.id,it.nextSeen,it.hit);
    }
    std::cout << algName << " hitc " << hitc << " reqc " << reqc << " ohr " << double(hitc)/reqc << std::endl;
}
<|endoftext|>


<commit_before>#include "CueDetector.h"

CueDetector::CueDetector()
{
	cueLine.resize(2);
}

CueDetector::~CueDetector()
{
}

cv::vector<cv::Vec2i> CueDetector::detect(cv::Mat frame)
{
	// Reset cueLines.
	cueLine[0] = cv::Vec2i(0, 0);
	cueLine[1] = cv::Vec2i(0, 0);

	cv::Mat croppedFrame = frame.clone(); // copy so we don't overwrite the user's view with GaussianBlur's blur call.
	croppedFrame = croppedFrame(cv::Rect(CROP_X, CROP_Y, CROP_WIDTH, CROP_HEIGHT)); // Crop the image for the typical location of the cue.
	GaussianBlur(croppedFrame);
	hsiSegment(croppedFrame);
	skeleton(croppedFrame);
	//regHoughLines(croppedFrame, 120);
	probHoughLinesCueSegments(croppedFrame);

	cv::line(frame, cv::Point(cueLine[0][0], cueLine[0][1]), cv::Point(cueLine[1][0], cueLine[1][1]), cv::Scalar(0, 0, 255), 3, CV_AA);

	return cueLine;
}

void CueDetector::probHoughLinesCueSegments(cv::Mat& frame) {
	// Finds segments of a cue interrupted by a hand.
	cv::vector<cv::Vec4i> lines;
	HoughLinesP(frame, lines, 1, CV_PI / 180, HOUGH_THRESHOLD, CUE_SEGMENT_MIN_LENGTH, CUE_SEGMENT_MAX_GAP);

	cv::Mat houghMap(frame.size(), CV_8UC1, cv::Scalar(0));

	for (size_t i = 0; i < lines.size(); i++)
	{
		line(houghMap, cv::Point(lines[i][0], lines[i][1]), cv::Point(lines[i][2], lines[i][3]), cv::Scalar(255), 1, CV_AA);
	}

	mergeCueSegments(houghMap);

	imshow("Cue Segments", houghMap);

	frame = houghMap.clone();
}

void CueDetector::mergeCueSegments(cv::Mat& frame)
{
	//kmeansDemo();

	// combines two cue segments into a single line segment.
	cv::vector<cv::Vec4i> lines;
	cv::Mat ptsmat;
	HoughLinesP(frame, lines , 1, CV_PI / 180, 50, 18, 100);

	if (lines.size() > 0)
	{
		cv::Mat linesMatrix = cv::Mat(lines);
		std::cout << "linesMatrix = " << linesMatrix << std::endl << std::endl;
		std::cout << "linesMatrix_13 = " << linesMatrix.at<int>(1, 3) << std::endl << std::endl;
		//cv::Mat leftLinesMatrix = linesMatrix(cv::Rect(0, 0, 0, 0));
		//std::cout << "leftLinesMatrix = " << linesMatrix << std::endl << std::endl;
		//cv::Mat rightLinesMatrix = linesMatrix(cv::Rect(2, 0, 2, lines.size()));
		//std::cout << "rightLinesMatrix = " << rightLinesMatrix << std::endl << std::endl;

		// Convert vector 'lines' to Mat 'points'.
		cv::Mat points(lines.size()*2, 2, CV_32FC1);
		cv::Mat startPoints(lines.size(), 2, CV_32FC1);
		cv::Mat endPoints(lines.size(), 2, CV_32FC1);
		points = cv::Scalar(0);
		// points(2 * lines.size(), 2, CV_32F);
		for (int i = 0; i < lines.size(); i = i++)
		{
			for (int j = 0; j <= 1; j++)
			{
				std::cout << "startPoint (" << i << ", " << j << ") = " << lines[i][j] << std::endl;
				startPoints.at<float>(i, j) = lines[i][j];

				std::cout << "endPoint (" << i << ", " << j << ") = " << lines[i][j+2] << std::endl;
				endPoints.at<float>(i, j) = lines[i][j+2];
			}
		}

		// Debug

		std::cout << "startPoints = " << startPoints << std::endl;
		std::cout << "endPoints = " << endPoints << std::endl;

		// Vertically concatenate startPoints and endPoints (undocumented, see http://answers.opencv.org/question/1368/concatenating-matrices/)
		cv::vconcat(startPoints, endPoints, points);

		std::cout << "points = " << points << std::endl;

		// Calculate the mean cue endpoints.
		int K = 2;
		cv::Mat labels;
		cv::Mat centers(K, 2, points.type());
		cv::kmeans(points, K, labels, cv::TermCriteria(CV_TERMCRIT_EPS + CV_TERMCRIT_ITER, 10, 1.0), 50, cv::KMEANS_PP_CENTERS, centers);

		for (int i = 0; i < 2*lines.size(); i++)
		{
			int clusterIdx = labels.at<int>(i);
			std::cout << "point " << i << " = " << "class " << clusterIdx << std::endl;

		}

		for (int i = 0; i < 2; i++)
		{
			for (int j = 0; j < 2; j++)
			{
				int cell = centers.at<float>(i, j);
				std::cout << "center (" << i << ", " << j << ") = " << cell << std::endl;
			}

		}
	}

	cv::Mat houghMap(frame.size(), CV_8UC3, cv::Scalar(0));
	cv::Vec4i cueCandidatesSum;
	cueCandidatesSum = cv::Vec4i(0, 0, 0, 0);
	for (size_t i = 0; i < lines.size(); i++)
	{
		line(houghMap, cv::Point(lines[i][0], lines[i][1]), cv::Point(lines[i][2], lines[i][3]), cv::Scalar(255, 255, 255), 1, CV_AA);
		cueCandidatesSum += cv::Vec4i(lines[i][0], lines[i][1], lines[i][2], lines[i][3]);
	}
	float cueCandidatesMean[4];
	for (int i = 0; i < 4; i++)
	{
		cueCandidatesMean[i] = cueCandidatesSum[i] / lines.size();
	}

	// Convert cropped coords to global coords.
	cueLine[0] = cv::Vec2i(cueCandidatesMean[0] + CROP_X, cueCandidatesMean[1] + CROP_Y);
	cueLine[1] = cv::Vec2i(cueCandidatesMean[2] + CROP_X, cueCandidatesMean[3] + CROP_Y);

	imshow("Cue Lines", houghMap);
}

void CueDetector::hsiSegment(cv::Mat& frame)
{
	//Can be used to control with trackbars the values
	int minH = 10;
	int maxH = 40;

	int minS = 1;
	int maxS = 170;

	int minV = 175;
	int maxV = 255;

	cv::Mat hsvFrame;

	cvtColor(frame, hsvFrame, cv::COLOR_BGR2HSV); //Convert the captured frame from BGR to HSV

	cv::Mat hsvMask;

	inRange(hsvFrame, cv::Scalar(minH, minS, minV), cv::Scalar(maxH, maxS, maxV), hsvMask); //Threshold the image

	//Used to make the mask bigger (For our specific situation we want to make sure the mask
	//includes the whole pool table, having it a bit bigger thant he pool table is not an issue.
	dilate(hsvMask, hsvMask, getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(4, 4)));

	cv::Mat maskedFrame;
	frame.copyTo(maskedFrame, hsvMask);
	frame = maskedFrame.clone();

	imshow("HSI Cue", frame);
}

void CueDetector::GaussianBlur(cv::Mat& frame)
{
	//int display_dst(int delay);
	for (int i = 1; i < 7; i = i + 2)
	{
		cv::blur(frame, frame, cv::Size(i, i), cv::Point(-1, -1));
	}
}

void CueDetector::skeleton(cv::Mat& frame)
{
	// http://stackoverflow.com/questions/16665742/a-good-approach-for-detecting-lines-in-an-image
	// http://felix.abecassis.me/2011/09/opencv-morphological-skeleton/

	cvtColor(frame, frame, cv::COLOR_BGR2GRAY); //Convert the captured frame from BGR to greyscale

	cv::threshold(frame, frame, 127, 255, cv::THRESH_BINARY);
	cv::Mat skel(frame.size(), CV_8UC1, cv::Scalar(0));
	cv::Mat temp;
	cv::Mat eroded;

	cv::Mat element = cv::getStructuringElement(cv::MORPH_CROSS, cv::Size(3, 3));

	bool done;
	do
	{
		cv::erode(frame, eroded, element);
		cv::dilate(eroded, temp, element); // temp = open(img)
		cv::subtract(frame, temp, temp);
		cv::bitwise_or(skel, temp, skel);
		eroded.copyTo(frame);

		done = (cv::countNonZero(frame) == 0);
	} while (!done);

	frame = skel.clone();
}

void CueDetector::kmeansDemo()
{
	const int MAX_CLUSTERS = 5;
	cv::Scalar colorTab[] =
	{
		cv::Scalar(0, 0, 255),
		cv::Scalar(0, 255, 0),
		cv::Scalar(255, 100, 100),
		cv::Scalar(255, 0, 255),
		cv::Scalar(0, 255, 255)
	};

	cv::Mat img(500, 500, CV_8UC3);
	cv::RNG rng(12345);

	for (;;)
	{
		int k, clusterCount = rng.uniform(2, MAX_CLUSTERS + 1);
		int i, sampleCount = rng.uniform(1, 1001);
		cv::Mat points(sampleCount, 2, CV_32F), labels;

		clusterCount = MIN(clusterCount, sampleCount);
		cv::Mat centers;

		/* generate random sample from multigaussian distribution */
		for (k = 0; k < clusterCount; k++)
		{
			cv::Point center;
			center.x = rng.uniform(0, img.cols);
			center.y = rng.uniform(0, img.rows);
			cv::Mat pointChunk = points.rowRange(k*sampleCount / clusterCount,
				k == clusterCount - 1 ? sampleCount :
				(k + 1)*sampleCount / clusterCount);
			rng.fill(pointChunk, CV_RAND_NORMAL, cv::Scalar(center.x, center.y), cv::Scalar(img.cols*0.05, img.rows*0.05));
		}

		randShuffle(points, 1, &rng);

		kmeans(points, clusterCount, labels,
			cv::TermCriteria(CV_TERMCRIT_EPS + CV_TERMCRIT_ITER, 10, 1.0),
			3, cv::KMEANS_PP_CENTERS, centers);

		img = cv::Scalar::all(0);

		for (i = 0; i < sampleCount; i++)
		{
			int clusterIdx = labels.at<int>(i);
			cv::Point ipt = points.at<cv::Point2f>(i);
			circle(img, ipt, 2, colorTab[clusterIdx], CV_FILLED, CV_AA);
		}

		imshow("clusters", img);

		char key = (char)cv::waitKey();
		if (key == 27 || key == 'q' || key == 'Q') // 'ESC'
			break;
	}
}<commit_msg>Fully enabled and documented k-means cue clustering  - actually returns class centers as cue endpoints  - commented function  - TODO- remove debug messages     - left in for demonstration to team members using this version, remove for 'production'<commit_after>#include "CueDetector.h"

CueDetector::CueDetector()
{
	cueLine.resize(2);
}

CueDetector::~CueDetector()
{
}

cv::vector<cv::Vec2i> CueDetector::detect(cv::Mat frame)
{
	// Reset cueLines.
	cueLine[0] = cv::Vec2i(0, 0);
	cueLine[1] = cv::Vec2i(0, 0);

	cv::Mat croppedFrame = frame.clone(); // copy so we don't overwrite the user's view with GaussianBlur's blur call.
	croppedFrame = croppedFrame(cv::Rect(CROP_X, CROP_Y, CROP_WIDTH, CROP_HEIGHT)); // Crop the image for the typical location of the cue.
	GaussianBlur(croppedFrame);
	hsiSegment(croppedFrame);
	skeleton(croppedFrame);
	//regHoughLines(croppedFrame, 120);
	probHoughLinesCueSegments(croppedFrame);

	cv::line(frame, cv::Point(cueLine[0][0], cueLine[0][1]), cv::Point(cueLine[1][0], cueLine[1][1]), cv::Scalar(0, 0, 255), 3, CV_AA);

	return cueLine;
}

void CueDetector::probHoughLinesCueSegments(cv::Mat& frame) {
	// Finds segments of a cue interrupted by a hand.
	cv::vector<cv::Vec4i> lines;
	HoughLinesP(frame, lines, 1, CV_PI / 180, HOUGH_THRESHOLD, CUE_SEGMENT_MIN_LENGTH, CUE_SEGMENT_MAX_GAP);

	cv::Mat houghMap(frame.size(), CV_8UC1, cv::Scalar(0));

	for (size_t i = 0; i < lines.size(); i++)
	{
		line(houghMap, cv::Point(lines[i][0], lines[i][1]), cv::Point(lines[i][2], lines[i][3]), cv::Scalar(255), 1, CV_AA);
	}

	mergeCueSegments(houghMap);

	imshow("Cue Segments", houghMap);

	frame = houghMap.clone();
}

void CueDetector::mergeCueSegments(cv::Mat& frame)
{
	// combines two cue segments into a single line segment.
	cv::vector<cv::Vec4i> lines;
	HoughLinesP(frame, lines , 1, CV_PI / 180, 50, 18, 100);

	if (lines.size() > 0)
	{
		// Convert vector 'lines' to Mat 'points'.

		// Declare startPoints and endPoints to hold respective points of detected HoughLines.
		cv::Mat startPoints(lines.size(), 2, CV_32FC1);
		cv::Mat endPoints(lines.size(), 2, CV_32FC1);

		// Declare allPoints to be the vertical concatenation of startPoints and endPoints.
		// Twice the length of lines because HoughLines contain two points.
		cv::Mat allPoints(lines.size()*2, 2, CV_32FC1);
		allPoints = cv::Scalar(0);

		// Convert n-length vector of 4-integer length vector of line boundary points to nx2 Mats.
		for (int i = 0; i < lines.size(); i = i++)
		{
			for (int j = 0; j <= 1; j++)
			{
				// Debug messages
				std::cout << "startPoint (" << i << ", " << j << ") = " << lines[i][j] << std::endl;
				startPoints.at<float>(i, j) = lines[i][j];

				std::cout << "endPoint (" << i << ", " << j << ") = " << lines[i][j+2] << std::endl;
				endPoints.at<float>(i, j) = lines[i][j+2];
			}
		}

		// Vertically concatenate startPoints and endPoints (undocumented, see http://answers.opencv.org/question/1368/concatenating-matrices/)
		cv::vconcat(startPoints, endPoints, allPoints);

		// Debug messages
		std::cout << "startPoints = " << startPoints << std::endl;
		std::cout << "endPoints = " << endPoints << std::endl;
		std::cout << "points = " << allPoints << std::endl;

		// Calculate the mean cue endpoints using K=2-means clustering. See http://www.aishack.in/tutorials/kmeans-clustering-in-opencv/
		int K = 2;
		cv::Mat labels;
		cv::Mat centers(K, 2, allPoints.type());
		cv::kmeans(allPoints, K, labels, cv::TermCriteria(CV_TERMCRIT_EPS + CV_TERMCRIT_ITER, 10, 1.0), 50, cv::KMEANS_PP_CENTERS, centers);

		// Debug messages for point classifications
		for (int i = 0; i < 2*lines.size(); i++)
		{
			int clusterIdx = labels.at<int>(i);
			std::cout << "point " << i << " = " << "class " << clusterIdx << std::endl;

		}

		// Debug messages for class centres
		for (int i = 0; i < 2; i++)
		{
			for (int j = 0; j < 2; j++)
			{
				int cell = centers.at<float>(i, j);
				std::cout << "center (" << i << ", " << j << ") = " << cell << std::endl;
			}
		}

		// Convert cropped coords to global coords.
		cueLine[0] = cv::Vec2i(centers.at<float>(0, 0) + CROP_X, centers.at<float>(0, 1) + CROP_Y);
		cueLine[1] = cv::Vec2i(centers.at<float>(1, 0) + CROP_X, centers.at<float>(1, 1) + CROP_Y);
	}
	else // no lines detected
	{
		// Set cueLines to initial (negligable) values.
		cueLine[0] = cv::Vec2i(0, 0);
		cueLine[1] = cv::Vec2i(0, 0);
	}

	// Debug video display.
	cv::Mat houghMap(frame.size(), CV_8UC3, cv::Scalar(0));
	cv::Vec4i cueCandidatesSum;
	cueCandidatesSum = cv::Vec4i(0, 0, 0, 0);
	for (size_t i = 0; i < lines.size(); i++)
	{
		line(houghMap, cv::Point(lines[i][0], lines[i][1]), cv::Point(lines[i][2], lines[i][3]), cv::Scalar(255, 255, 255), 1, CV_AA);
	}

	float cueCandidatesMean[4];
	for (int i = 0; i < 4; i++)
	{
		cueCandidatesMean[i] = cueCandidatesSum[i] / lines.size();
	}

	imshow("Cue Lines", houghMap);
}

void CueDetector::hsiSegment(cv::Mat& frame)
{
	//Can be used to control with trackbars the values
	int minH = 10;
	int maxH = 40;

	int minS = 1;
	int maxS = 170;

	int minV = 175;
	int maxV = 255;

	cv::Mat hsvFrame;

	cvtColor(frame, hsvFrame, cv::COLOR_BGR2HSV); //Convert the captured frame from BGR to HSV

	cv::Mat hsvMask;

	inRange(hsvFrame, cv::Scalar(minH, minS, minV), cv::Scalar(maxH, maxS, maxV), hsvMask); //Threshold the image

	//Used to make the mask bigger (For our specific situation we want to make sure the mask
	//includes the whole pool table, having it a bit bigger thant he pool table is not an issue.
	dilate(hsvMask, hsvMask, getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(4, 4)));

	cv::Mat maskedFrame;
	frame.copyTo(maskedFrame, hsvMask);
	frame = maskedFrame.clone();

	imshow("HSI Cue", frame);
}

void CueDetector::GaussianBlur(cv::Mat& frame)
{
	//int display_dst(int delay);
	for (int i = 1; i < 7; i = i + 2)
	{
		cv::blur(frame, frame, cv::Size(i, i), cv::Point(-1, -1));
	}
}

void CueDetector::skeleton(cv::Mat& frame)
{
	// http://stackoverflow.com/questions/16665742/a-good-approach-for-detecting-lines-in-an-image
	// http://felix.abecassis.me/2011/09/opencv-morphological-skeleton/

	cvtColor(frame, frame, cv::COLOR_BGR2GRAY); //Convert the captured frame from BGR to greyscale

	cv::threshold(frame, frame, 127, 255, cv::THRESH_BINARY);
	cv::Mat skel(frame.size(), CV_8UC1, cv::Scalar(0));
	cv::Mat temp;
	cv::Mat eroded;

	cv::Mat element = cv::getStructuringElement(cv::MORPH_CROSS, cv::Size(3, 3));

	bool done;
	do
	{
		cv::erode(frame, eroded, element);
		cv::dilate(eroded, temp, element); // temp = open(img)
		cv::subtract(frame, temp, temp);
		cv::bitwise_or(skel, temp, skel);
		eroded.copyTo(frame);

		done = (cv::countNonZero(frame) == 0);
	} while (!done);

	frame = skel.clone();
}

void CueDetector::kmeansDemo()
{
	const int MAX_CLUSTERS = 5;
	cv::Scalar colorTab[] =
	{
		cv::Scalar(0, 0, 255),
		cv::Scalar(0, 255, 0),
		cv::Scalar(255, 100, 100),
		cv::Scalar(255, 0, 255),
		cv::Scalar(0, 255, 255)
	};

	cv::Mat img(500, 500, CV_8UC3);
	cv::RNG rng(12345);

	for (;;)
	{
		int k, clusterCount = rng.uniform(2, MAX_CLUSTERS + 1);
		int i, sampleCount = rng.uniform(1, 1001);
		cv::Mat points(sampleCount, 2, CV_32F), labels;

		clusterCount = MIN(clusterCount, sampleCount);
		cv::Mat centers;

		/* generate random sample from multigaussian distribution */
		for (k = 0; k < clusterCount; k++)
		{
			cv::Point center;
			center.x = rng.uniform(0, img.cols);
			center.y = rng.uniform(0, img.rows);
			cv::Mat pointChunk = points.rowRange(k*sampleCount / clusterCount,
				k == clusterCount - 1 ? sampleCount :
				(k + 1)*sampleCount / clusterCount);
			rng.fill(pointChunk, CV_RAND_NORMAL, cv::Scalar(center.x, center.y), cv::Scalar(img.cols*0.05, img.rows*0.05));
		}

		randShuffle(points, 1, &rng);

		kmeans(points, clusterCount, labels,
			cv::TermCriteria(CV_TERMCRIT_EPS + CV_TERMCRIT_ITER, 10, 1.0),
			3, cv::KMEANS_PP_CENTERS, centers);

		img = cv::Scalar::all(0);

		for (i = 0; i < sampleCount; i++)
		{
			int clusterIdx = labels.at<int>(i);
			cv::Point ipt = points.at<cv::Point2f>(i);
			circle(img, ipt, 2, colorTab[clusterIdx], CV_FILLED, CV_AA);
		}

		imshow("clusters", img);

		char key = (char)cv::waitKey();
		if (key == 27 || key == 'q' || key == 'Q') // 'ESC'
			break;
	}
}<|endoftext|>