<commit_before>#include "choiceview.h"

#include <QKeyEvent>
#include <QPaintEvent>
#include <QPainter>

Choice::Choice(const QString &title, const QString &id, const QStringList &params)
    : _id(id), _title(title), _params(params) {
}

const QString &Choice::id() const {
  return _id;
}

const QString &Choice::title() const {
  return _title;
}

const QStringList &Choice::params() const {
  return _params;
}

ChoiceView::ChoiceView(QWidget *parent)
    : QWidget(parent),
      _offset(0) {

  setFocusPolicy(Qt::StrongFocus);
  setFont(QFont("Liberation Serif", 20));
}

ChoiceView::~ChoiceView() { }

static const int arrowHeight = 8;

static char _hotkeys[] = { '1', '2', '3', '4', '5', '6', '7', '8', '9', '0' };
void ChoiceView::paintEvent(QPaintEvent *event) {
  QFontMetrics metrics(font());
  QPainter painter(this);

  int y = arrowHeight + 2;
  const int baseline = metrics.leading() + metrics.ascent() + 1;
  const int w = width(), h = height() - (y * 2);
  const int yInc = h / 10;
  const int labelWidth = w - yInc - 10;
  const int hotkeyCenter = w - (yInc / 2);

  // Top arrow
  const int center = w / 2;
  painter.eraseRect(0, 0, w, y);
  if (_offset > 0) {
    painter.drawLine(center, 0, center - arrowHeight, arrowHeight);
    painter.drawLine(center, 0, center + arrowHeight, arrowHeight);
    painter.drawLine(center - arrowHeight, arrowHeight, center + arrowHeight, arrowHeight);
  }

  // Bottom arrow
  painter.eraseRect(0, height() - y, w, y);
  if (_offset + 10 < _choices.size()) {
    painter.drawLine(center, height() - 1, center - arrowHeight, height() - arrowHeight - 1);
    painter.drawLine(center, height() - 1, center + arrowHeight, height() - arrowHeight - 1);
    painter.drawLine(center - arrowHeight, height() - arrowHeight - 1,
        center + arrowHeight, height() - arrowHeight - 1);
  }

  // Choice area
  for (int row = 0; row < NUM_CHOICES; row++) {
    const int item = row + _offset;
    painter.eraseRect(0, y, w, yInc);
    if (item < _choices.size()) {
      const Choice &c = _choices[item];
      painter.drawText(0, y + baseline,
          metrics.elidedText(c.title(), Qt::ElideMiddle, labelWidth));

      painter.save();
      if (row > 0) {
        painter.setPen(QColor(0xAA, 0xAA, 0xAA));
        painter.drawLine(50, y - 10, w - 50, y - 10);
      }

      painter.setPen(QColor(0x55, 0x55, 0x55));
      painter.drawRect(labelWidth + 10, y + metrics.leading(), yInc - 1, metrics.height());
      painter.drawText(hotkeyCenter - (metrics.width(_hotkeys[row]) / 2), y + baseline,
          QString(1, _hotkeys[row]));

      painter.restore();
    }
    y += yInc;
  }
}

void ChoiceView::keyPressEvent(QKeyEvent *event) {
  if (event->key() >= Qt::Key_0 && event->key() <= Qt::Key_9) {
    int chosen = event->key() - Qt::Key_0 + _offset - 1;
    if (chosen < _offset) chosen += 10;
    if (chosen < _choices.size()) {
      choose(chosen);
      return;
    }
  } else if (event->key() == Qt::Key_Escape) {
    goBack();
    return;
  } else if (event->key() == Qt::Key_Down) {
    pageDown();
    return;
  } else if (event->key() == Qt::Key_Up) {
    pageUp();
    return;
  }
  QWidget::keyPressEvent(event);
}

void ChoiceView::choose(int chosen) {
  emit choiceMade(_choices[chosen]);
}

void ChoiceView::goBack() {
  emit back();
}

void ChoiceView::setChoices(const QList<Choice> choices) {
  _choices = choices;
  if (_offset >= _choices.size()) {
    // Integer division floors here.
    _offset = (_choices.size() / 10) * 10;
  }
  emit morePages(_choices.size() / 10);
  refreshLabels();
}

void ChoiceView::pageDown() {
  if (_offset < _choices.size() - 10) {
    _offset += 10;
    refreshLabels();
  }
}

void ChoiceView::pageUp() {
  if (_offset >= 10) {
    _offset -= 10;
    refreshLabels();
  }
}

void ChoiceView::refreshLabels() {
  update();
  emit switchedToPage(_offset / 10);
}

bool operator<(Choice a, Choice b) {
  return a.title().compare(b.title(), Qt::CaseInsensitive) < 0;
}
<commit_msg>Long menu items now fade at the edge.<commit_after>#include "choiceview.h"

#include <QKeyEvent>
#include <QPaintEvent>
#include <QPainter>

Choice::Choice(const QString &title, const QString &id, const QStringList &params)
    : _id(id), _title(title), _params(params) {
}

const QString &Choice::id() const {
  return _id;
}

const QString &Choice::title() const {
  return _title;
}

const QStringList &Choice::params() const {
  return _params;
}

ChoiceView::ChoiceView(QWidget *parent)
    : QWidget(parent),
      _offset(0) {

  setFocusPolicy(Qt::StrongFocus);
  setFont(QFont("Liberation Serif", 20));
}

ChoiceView::~ChoiceView() { }

static const int arrowHeight = 8;

static char _hotkeys[] = { '1', '2', '3', '4', '5', '6', '7', '8', '9', '0' };
void ChoiceView::paintEvent(QPaintEvent *event) {
  QFontMetrics metrics(font());
  QPainter painter(this);

  int y = arrowHeight + 2;
  const int baseline = metrics.leading() + metrics.ascent() + 1;
  const int w = width(), h = height() - (y * 2);
  const int yInc = h / 10;
  const int labelWidth = w - yInc - 10;
  const int hotkeyCenter = w - (yInc / 2);

  // Top arrow
  const int center = w / 2;
  painter.eraseRect(0, 0, w, y);
  if (_offset > 0) {
    painter.drawLine(center, 0, center - arrowHeight, arrowHeight);
    painter.drawLine(center, 0, center + arrowHeight, arrowHeight);
    painter.drawLine(center - arrowHeight, arrowHeight, center + arrowHeight, arrowHeight);
  }

  // Bottom arrow
  painter.eraseRect(0, height() - y, w, y);
  if (_offset + 10 < _choices.size()) {
    painter.drawLine(center, height() - 1, center - arrowHeight, height() - arrowHeight - 1);
    painter.drawLine(center, height() - 1, center + arrowHeight, height() - arrowHeight - 1);
    painter.drawLine(center - arrowHeight, height() - arrowHeight - 1,
        center + arrowHeight, height() - arrowHeight - 1);
  }

  QLinearGradient fade(QPointF(0,0), QPointF(labelWidth, 0));
  fade.setColorAt(0, Qt::black);
  fade.setColorAt(0.95, Qt::black);
  fade.setColorAt(1.0, QColor(0xAA, 0xAA, 0xAA));

  QTextOption noWrap;
  noWrap.setWrapMode(QTextOption::NoWrap);

  // Choice area
  for (int row = 0; row < NUM_CHOICES; row++) {
    const int item = row + _offset;
    painter.eraseRect(0, y, w, yInc);
    if (item < _choices.size()) {
      const Choice &c = _choices[item];
      if (metrics.width(c.title()) > labelWidth) {
        painter.setPen(QPen(QBrush(fade), 1));
      } else {
        painter.setPen(QPen(Qt::black));
      }

      painter.drawText(QRectF(0, y, labelWidth, yInc), c.title(), noWrap);

      painter.save();
      if (row > 0) {
        painter.setPen(QColor(0xAA, 0xAA, 0xAA));
        painter.drawLine(50, y - 10, w - 50, y - 10);
      }

      painter.setPen(QColor(0x55, 0x55, 0x55));
      painter.drawRect(labelWidth + 10, y + metrics.leading(), yInc - 1, metrics.height());
      painter.drawText(hotkeyCenter - (metrics.width(_hotkeys[row]) / 2), y + baseline,
          QString(1, _hotkeys[row]));

      painter.restore();
    }
    y += yInc;
  }
}

void ChoiceView::keyPressEvent(QKeyEvent *event) {
  if (event->key() >= Qt::Key_0 && event->key() <= Qt::Key_9) {
    int chosen = event->key() - Qt::Key_0 + _offset - 1;
    if (chosen < _offset) chosen += 10;
    if (chosen < _choices.size()) {
      choose(chosen);
      return;
    }
  } else if (event->key() == Qt::Key_Escape) {
    goBack();
    return;
  } else if (event->key() == Qt::Key_Down) {
    pageDown();
    return;
  } else if (event->key() == Qt::Key_Up) {
    pageUp();
    return;
  }
  QWidget::keyPressEvent(event);
}

void ChoiceView::choose(int chosen) {
  emit choiceMade(_choices[chosen]);
}

void ChoiceView::goBack() {
  emit back();
}

void ChoiceView::setChoices(const QList<Choice> choices) {
  _choices = choices;
  if (_offset >= _choices.size()) {
    // Integer division floors here.
    _offset = (_choices.size() / 10) * 10;
  }
  emit morePages(_choices.size() / 10);
  refreshLabels();
}

void ChoiceView::pageDown() {
  if (_offset < _choices.size() - 10) {
    _offset += 10;
    refreshLabels();
  }
}

void ChoiceView::pageUp() {
  if (_offset >= 10) {
    _offset -= 10;
    refreshLabels();
  }
}

void ChoiceView::refreshLabels() {
  update();
  emit switchedToPage(_offset / 10);
}

bool operator<(Choice a, Choice b) {
  return a.title().compare(b.title(), Qt::CaseInsensitive) < 0;
}
<|endoftext|>


<commit_before>// -*- c-basic-offset: 2; related-file-name: "aggwrap.h" -*-
/*
 * @(#)$Id$
 *
 * This file is distributed under the terms in the attached INTEL-LICENSE file.
 * If you do not find these files, copies can be found by writing to:
 * Intel Research Berkeley, 2150 Shattuck Avenue, Suite 1300,
 * Berkeley, CA, 94704.  Attention:  Intel License Inquiry.
 *
 */

#include "aggwrap.h"
#include "trace.h"
#include "val_int32.h"

Aggwrap::Aggwrap(str aggfn, int aggfield)
  : Element(strbuf() << "Aggwrap<" << aggfn << "," << aggfield << ">", 2, 2),
    _aggfn(aggfn), _aggfield(aggfield),
    inner_accepting(true),
    ext_in_cb(cbv_null),
    ext_out_cb(cbv_null)
{
  numJoins = 0;
  if (aggfn == "min") {
    log(LoggerI::INFO, 0, str(strbuf() << "min aggregation " << _aggfield));
  } else if (aggfn == "max") {
    log(LoggerI::INFO, 0, str(strbuf() << "max aggregation " << _aggfield));
  } else if (aggfn == "count") {
    log(LoggerI::INFO, 0, str(strbuf() << "count aggregation " << _aggfield));
  } else {
    log(LoggerI::INFO, 0, "HELP: Don't understand agg function '" << aggfn << "'");
  }
}

//
// A new tuple is coming in from outside.
//
int Aggwrap::push(int port, TupleRef t, cbv cb)
{
  log(LoggerI::INFO, 0, str(strbuf() << " Push: " << port << "," << t->toString()));

  // if receive the next one when previous has not finished, then keep in queue?

  // Is this the right port?
  switch (port) {
  case 0:
    ext_in_cb = cb;
    switch(aggState) {
    case 0:  // Waiting
      log(LoggerI::INFO, 0, str(strbuf() << " received a tuple from outside!" << t->toString()));
      assert(inner_accepting);
      agg_init();
      inner_accepting = output(1)->push(t, wrap(this, &Aggwrap::int_push_cb));
      break;
    case 1:
      log(LoggerI::INFO, 0, "FAIL: pushed when processing!");
      // Discard tuple
      break;
    case 2:
      log(LoggerI::INFO, 0, "FAIL: pushed when done pending");
      break;
    default:
      log(LoggerI::INFO, 0, str(strbuf() << "FAIL: weird state " << aggState));
    }
    return 0;
  case 1:
    switch(aggState) {
    case 0:  // Waiting
      log(LoggerI::INFO, 0, "OOPS: unexpected result tuple when in state waiting");
      break;
    case 1:
      agg_accum(t);
      break;
    case 2:
      log(LoggerI::INFO, 0, "FAIL: pushed when done pending");
      break;
    default:
      log(LoggerI::INFO, 0, str(strbuf() << "FAIL: weird state " << aggState));
    }
    return 1;
  default:
    assert(port < 2);
    return  0;
  }

}

//
// Callback from the inner graph when we can push more tuples.
//
void Aggwrap::int_push_cb()
{
  TRC_FN;
  inner_accepting = true;
  log(LoggerI::INFO, 0, str(strbuf() << "Callback from inner graph on successful push" << aggState));
  if (aggState == 0 && ext_in_cb) {
    log(LoggerI::INFO, 0, str(strbuf() << "Invoke ext_in_cb"));
    ext_in_cb();
  }
}

//
// Completion callback
//
void Aggwrap::comp_cb(int jnum)
{
  TRC_FN;
  log(LoggerI::INFO, 0, str(strbuf() << "Join " << jnum << " completed."));
  if (curJoin < jnum) {
    curJoin = jnum;
  }

  if (curJoin >= numJoins - 1) {
    // Presumably, we're now done.
    agg_finalize();
  }
}

//
// Getting hold of a closure for the above
//
cbv Aggwrap::get_comp_cb()
{
  log(LoggerI::INFO, 0, str(strbuf() << "Joins so far: " << numJoins + 1));
  return wrap(this,&Aggwrap::comp_cb,numJoins++);
}

//
// Finally, the aggregation functions
//
void Aggwrap::agg_init() {
  TRC_FN;
  curJoin = -1;
  aggState = 1;
  if ( _aggfn == "count") {
    count = 0;
  } else {
    aggResult = NULL;
  }
}

void Aggwrap::agg_accum(TupleRef t) {
  TRC_FN;
  if ( _aggfn == "count") {
    count++;
    return;
  }

  if ( aggResult == NULL ) {
    aggResult = t;
    log(LoggerI::INFO, 0, str(strbuf() << "After Agg accumulation: " << aggResult->toString()));
    return;
  }

  log(LoggerI::INFO, 0, str(strbuf() << "Before Agg accumulation: " << aggResult->toString()));
  int cr = (*t)[_aggfield]->compareTo((*aggResult)[_aggfield]);
  if ((cr == -1 && _aggfn == "min") || (cr == 1 && _aggfn == "max")) {
    aggResult = t;
  }
  log(LoggerI::INFO, 0, str(strbuf() << "After Agg accumulation: " << aggResult->toString() << cr
			    << " " << (*t)[_aggfield]->toString() << " " << (*aggResult)[_aggfield]->toString()));
}

void Aggwrap::agg_finalize() {
  TRC_FN;
  if (_aggfn == "count") {
    aggResult = Tuple::mk();
    aggResult->append(Val_Int32::mk(count));
    aggResult->freeze();
  }
  if (aggResult) {
    log(LoggerI::INFO, 0, str(strbuf() << " finalize: Pushing tuple" << aggResult->toString()));
    output(0)->push(aggResult, cbv_null);

    if (ext_in_cb) {
      ext_in_cb(); // accept new tuples to be pushed in via outer
    }
  } else {
    log(LoggerI::INFO, 0, "Finalize: Alas, nothing to push");
  }
  aggState = 0;
}
<commit_msg>Aggwrap<commit_after>// -*- c-basic-offset: 2; related-file-name: "aggwrap.h" -*-
/*
 * @(#)$Id$
 *
 * This file is distributed under the terms in the attached INTEL-LICENSE file.
 * If you do not find these files, copies can be found by writing to:
 * Intel Research Berkeley, 2150 Shattuck Avenue, Suite 1300,
 * Berkeley, CA, 94704.  Attention:  Intel License Inquiry.
 *
 */

#include "aggwrap.h"
#include "trace.h"
#include "val_int32.h"

Aggwrap::Aggwrap(str aggfn, int aggfield)
  : Element(strbuf() << "Aggwrap<" << aggfn << "," << aggfield << ">", 2, 2),
    _aggfn(aggfn), _aggfield(aggfield),
    inner_accepting(true),
    ext_in_cb(cbv_null),
    ext_out_cb(cbv_null)
{
  numJoins = 0;
  if (aggfn == "min") {
    log(LoggerI::INFO, 0, str(strbuf() << "min aggregation " << _aggfield));
  } else if (aggfn == "max") {
    log(LoggerI::INFO, 0, str(strbuf() << "max aggregation " << _aggfield));
  } else if (aggfn == "count") {
    log(LoggerI::INFO, 0, str(strbuf() << "count aggregation " << _aggfield));
  } else {
    log(LoggerI::INFO, 0, "HELP: Don't understand agg function '" << aggfn << "'");
  }
}

//
// A new tuple is coming in from outside.
//
int Aggwrap::push(int port, TupleRef t, cbv cb)
{
  log(LoggerI::INFO, 0, str(strbuf() << " Push: " << port << "," << t->toString()));

  // if receive the next one when previous has not finished, then keep in queue?

  // Is this the right port?
  switch (port) {
  case 0:
    ext_in_cb = cb;
    switch(aggState) {
    case 0:  // Waiting
      log(LoggerI::INFO, 0, str(strbuf() << " received a tuple from outside!" << t->toString()));
      assert(inner_accepting);
      agg_init();
      inner_accepting = output(1)->push(t, wrap(this, &Aggwrap::int_push_cb));
      break;
    case 1:
      log(LoggerI::INFO, 0, "FAIL: pushed when processing!");
      // Discard tuple
      break;
    case 2:
      log(LoggerI::INFO, 0, "FAIL: pushed when done pending");
      break;
    default:
      log(LoggerI::INFO, 0, str(strbuf() << "FAIL: weird state " << aggState));
    }
    return 0;
  case 1:
    switch(aggState) {
    case 0:  // Waiting
      log(LoggerI::INFO, 0, "OOPS: unexpected result tuple when in state waiting");
      break;
    case 1:
      agg_accum(t);
      break;
    case 2:
      log(LoggerI::INFO, 0, "FAIL: pushed when done pending");
      break;
    default:
      log(LoggerI::INFO, 0, str(strbuf() << "FAIL: weird state " << aggState));
    }
    return 1;
  default:
    assert(port < 2);
    return  0;
  }

}

//
// Callback from the inner graph when we can push more tuples.
//
void Aggwrap::int_push_cb()
{
  TRC_FN;
  inner_accepting = true;
  log(LoggerI::INFO, 0, str(strbuf() << "Callback from inner graph on successful push" << aggState));
  if (aggState == 0 && ext_in_cb) {
    log(LoggerI::INFO, 0, str(strbuf() << "Invoke ext_in_cb"));
    ext_in_cb();
  }
}

//
// Completion callback
//
void Aggwrap::comp_cb(int jnum)
{
  TRC_FN;
  log(LoggerI::INFO, 0, str(strbuf() << "Join " << jnum << " completed."));
  if (curJoin < jnum) {
    curJoin = jnum;
  }

  if (curJoin >= numJoins - 1) {
    // Presumably, we're now done.
    agg_finalize();
  }
}

//
// Getting hold of a closure for the above
//
cbv Aggwrap::get_comp_cb()
{
  log(LoggerI::INFO, 0, str(strbuf() << "Joins so far: " << numJoins + 1));
  return wrap(this,&Aggwrap::comp_cb,numJoins++);
}

//
// Finally, the aggregation functions
//
void Aggwrap::agg_init() {
  TRC_FN;
  curJoin = -1;
  aggState = 1;
  if ( _aggfn == "count") {
    count = 0;
  } else {
    aggResult = NULL;
  }
}

void Aggwrap::agg_accum(TupleRef t) {
  TRC_FN;
  if ( _aggfn == "count") {
    count++;
    return;
  }

  if ( aggResult == NULL ) {
    aggResult = t;
    log(LoggerI::INFO, 0, str(strbuf() << "After Agg accumulation: " << aggResult->toString()));
    return;
  }

  log(LoggerI::INFO, 0, str(strbuf() << "Before Agg accumulation: " << aggResult->toString()));
  int cr = (*t)[_aggfield]->compareTo((*aggResult)[_aggfield]);
  if ((cr == -1 && _aggfn == "min") || (cr == 1 && _aggfn == "max")) {
    aggResult = t;
  }
  log(LoggerI::INFO, 0, str(strbuf() << "After Agg accumulation: " << aggResult->toString() << cr
			    << " " << (*t)[_aggfield]->toString() << " " << (*aggResult)[_aggfield]->toString()));
}

void Aggwrap::agg_finalize() {
  TRC_FN;
  if (_aggfn == "count") {
    aggResult = Tuple::mk();
    aggResult->append(Val_Int32::mk(count));
    aggResult->freeze();
  }
  if (aggResult) {
    log(LoggerI::INFO, 0, str(strbuf() << " finalize: Pushing tuple" << aggResult->toString()));
    output(0)->push(aggResult, cbv_null);
  } else {
    log(LoggerI::INFO, 0, "Finalize: Alas, nothing to push");
  }
  if (ext_in_cb) {
    ext_in_cb(); // accept new tuples to be pushed in via outer regardless of any outputs
  }
  aggState = 0;
}
<|endoftext|>


<commit_before>#include    <cstdlib>
#include    <cmath>
#include    <fstream>
#include    <sstream>
#include    <iostream>
#include    <iomanip>
#include    <string>
#include    <vector>
#include    <algorithm>
#include    <exception>
#include    <sys/time.h>
#include    "modules/htmTree.h"
#include    "modules/kdTree.h"
#include        "misc.h"
#include        "feat.h"
#include        "structs.h"
#include        "collision.h"
#include        "global.h"
//reduce redistributes, updates  07/02/15 rnc
int main(int argc, char **argv) {
    //// Initializations ---------------------------------------------
    srand48(1234); // Make sure we have reproducability
    check_args(argc);
    Time t, time; // t for global, time for local
    init_time(t);
    Feat F;
    MTL M;

    // Read parameters file //
    F.readInputFile(argv[1]);
    printFile(argv[1]);
    // Read Secretfile
    // Secret contains the identity of each target: QSO-Ly-a, QSO-tracers, LRG, ELG, fake QSO, fake LRG, SS, SF
    Gals Secret;
    init_time_at(time,"# reading Secret file",t);

        Secret=read_Secretfile(F.Secretfile,F);
    printf("# Read %d galaxies from %s \n",Secret.size(),F.Secretfile.c_str());
    print_time(time,"# ... took :");
    std::vector<int> count(10);
    count=count_galaxies(Secret);
    printf(" Number of galaxies by type, QSO-Ly-a, QSO-tracers, LRG, ELG, fake QSO, fake LRG, SS, SF\n");
    for(int i=0;i<8;i++){if(count[i]>0)printf (" type %d number  %d  \n",i, count[i]);}
    //read the three input fits files
    init_time_at(time,"# read target, SS, SF files",t);
    MTL Targ=read_MTLfile(F.Targfile,F,0,0);
    MTL SStars=read_MTLfile(F.SStarsfile,F,1,0);
    MTL SkyF=read_MTLfile(F.SkyFfile,F,0,1);

    if(Targ.size() == 0) {
        std::cerr << "ERROR: No targets found in " << F.Targfile << std::endl;
        myexit(1);
    }

    print_time(time,"# ... took :");
    //combine the three input files
    M=Targ;
    printf(" M size %d \n",M.size());
    M.insert(M.end(),SStars.begin(),SStars.end());
    printf(" M size %d \n",M.size());
    M.insert(M.end(),SkyF.begin(),SkyF.end());
    printf(" M size %d \n",M.size());
    F.Ngal=M.size();
    F.Ntarg=Secret.size();

    //establish priority classes
    init_time_at(time,"# establish priority clasess",t);
    assign_priority_class(M);
    std::vector <int> count_class(M.priority_list.size(),0);
    for(int i;i<M.size();++i){
        if(!M[i].SS&&!M[i].SF){
        count_class[M[i].priority_class]+=1;
        }
    }
    for(int i;i<M.priority_list.size();++i){
        printf("  class %d  priority %d  number %d\n",i,M.priority_list[i],count_class[i]);
    }
    print_time(time,"# ... took :");

    // fiber positioners
    PP pp;
    pp.read_fiber_positions(F);
    F.Nfiber = pp.fp.size()/2;
    F.Npetal = max(pp.spectrom)+1;
    F.Nfbp = (int) (F.Nfiber/F.Npetal);// fibers per petal = 500
    pp.get_neighbors(F);
    pp.compute_fibsofsp(F);
    printf("computed neighbors\n");
    std::cout.flush();
    //P tiles in order specified by surveyFile
    Plates P = read_plate_centers(F);
    F.Nplate=P.size();
    printf("# Read %d plates from %s and %d fibers from %s\n",F.Nplate,F.tileFile.c_str(),F.Nfiber,F.fibFile.c_str());

    // Computes geometries of cb and fh: pieces of positioner - used to determine possible collisions
    F.cb = create_cb(); // cb=central body
    F.fh = create_fh(); // fh=fiber holder

    //// Collect available galaxies <-> tilefibers --------------------
    // HTM Tree of galaxies
    const double MinTreeSize = 0.01;
    init_time_at(time,"# Start building HTM tree",t);

    htmTree<struct target> T(M,MinTreeSize);
    print_time(time,"# ... took :");//T.stats();
    init_time_at(time,"# collect galaxies at ",t);

    // For plates/fibers, collect available galaxies; done in parallel
    collect_galaxies_for_all(M,T,P,pp,F);
    print_time(time,"# ... took :");//T.stats();
    init_time_at(time,"# collect available tile-fibers at",t);
    // For each galaxy, computes available tilefibers  G[i].av_tfs = [(j1,k1),(j2,k2),..]
    collect_available_tilefibers(M,P,F);

    //results_on_inputs("doc/figs/",G,P,F,true);

    //// Assignment |||||||||||||||||||||||||||||||||||||||||||||||||||
    printf(" Nplate %d  Ngal %d   Nfiber %d \n", F.Nplate, F.Ngal, F.Nfiber);
    Assignment A(M,F);

    print_time(t,"# Start assignment at : ");

    // Make a plan ----------------------------------------------------
    // Plans whole survey without sky fibers, standard stars
    // assumes maximum number of observations needed for QSOs, LRGs

    simple_assign(M,P,pp,F,A);

    //check to see if there are tiles with no galaxies
    //need to keep mapping of old tile list to new tile list
    //and inverse map
    A.inv_order=initList(F.Nplate,-1);
    int inv_count=0;
    for (int j=0;j<F.Nplate ;++j){

        bool not_done=true;
        for(int k=0;k<F.Nfiber && not_done;++k){
            if(A.TF[j][k]!=-1){//fiber and therefore plate is used
                A.suborder.push_back(j);//suborder[jused] is jused-th used plate
                not_done=false;
                A.inv_order[j]=inv_count;//inv_order[j] is -1 unless used
                                //and otherwise the position of plate j in list of used plates
                inv_count++;
            }
        }
    }
    F.NUsedplate=A.suborder.size();
    printf(" Plates actually used %d \n",F.NUsedplate);

    if(F.diagnose)diagnostic(M,Secret,F,A);

    print_hist("Unused fibers",5,histogram(A.unused_fbp(pp,F),5),false); // Hist of unused fibs

    // Smooth out distribution of free fibers, and increase the number of assignments

    for (int i=0; i<1; i++) redistribute_tf(M,P,pp,F,A,0);// more iterations will improve performance slightly
    for (int i=0; i<1; i++) {
        improve(M,P,pp,F,A,0);
        redistribute_tf(M,P,pp,F,A,0);
    }
    print_hist("Unused fibers",5,histogram(A.unused_fbp(pp,F),5),false);
    //try assigning SF and SS before real time assignment
    for (int jused=0;jused<F.NUsedplate;++jused){
        int j=A.suborder[jused];
        assign_sf_ss(j,M,P,pp,F,A); // Assign SS and SF for each tile
        assign_unused(j,M,P,pp,F,A);
    }
    if(F.diagnose)diagnostic(M,Secret,F,A);
    init_time_at(time,"# Begin real time assignment",t);

    //Execute plan, updating targets at intervals
    for(int i=0;i<F.pass_intervals.size();i++){
        printf(" i=%d interval %d \n",i,F.pass_intervals[i]);
    }
    std::vector <int> update_intervals=F.pass_intervals;
    update_intervals.push_back(F.NUsedplate);//to end intervals at last plate
    for(int i=0;i<update_intervals.size();++i){
        printf("i %d  update_interval %d\n",i, update_intervals[i]);
    }
    for(int i=0;i<update_intervals.size()-1;++i){//go plate by used plate
        int starter=update_intervals[i];
        printf("-- interval %d\n",i);
        for (int jused=starter; jused<update_intervals[i+1] && jused<A.suborder.size()-1; jused++) {

            if (0<=jused-F.Analysis) {
                update_plan_from_one_obs(jused,Secret,M,P,pp,F,A);
            }
            else printf("\n no update\n");
            // Update corrects all future occurrences of wrong QSOs etc and tries to observe something else

        }
        printf("-- redistribute %d\n",i);
        redistribute_tf(M,P,pp,F,A,starter);
        printf("-- improve %d\n",i);
        improve(M,P,pp,F,A,starter);
        printf("-- improve again %d\n",i);
        redistribute_tf(M,P,pp,F,A,starter);
        printf("-- diagnose %d\n",i);
        if(F.diagnose)diagnostic(M,Secret,F,A);

    }
    // check on SS and SF

    printf("-- Checking SS/SF\n");
    List SS_hist=initList(11,0);
    List SF_hist=initList(41,0);
    for(int jused=0;jused<F.NUsedplate;++jused){
        int j=A.suborder[jused];
        for (int p=0;p<F.Npetal;++p){
            int count_SS=0;
            int count_SF=0;
            for (int k=0;k<F.Nfbp;++k){
                int kk=pp.fibers_of_sp[p][k];
                int g=A.TF[j][kk];
                if(g!=-1 && M[g].SS)count_SS++;
                if(g!=-1 && M[g].SF)count_SF++;
            }
            SS_hist[count_SS]++;
            SF_hist[count_SF]++;
        }
    }
    printf(" SS distribution \n");
    for(int i=0;i<10;i++)printf("%8d",SS_hist[i]);
    printf("\n %8d \n",SS_hist[10]);

    printf(" SF distribution \n");
    for(int i=0;i<10;i++)printf("%8d",SF_hist[i]);
    printf("\n");
    for(int i=10;i<20;i++)printf("%8d",SF_hist[i]);
    printf("\n");
    for(int i=20;i<30;i++)printf("%8d",SF_hist[i]);
    printf("\n");
    for(int i=30;i<40;i++)printf("%8d",SF_hist[i]);
    printf("\n %8d \n",SF_hist[40]);

    // Results -------------------------------------------------------

    //special for clustering group 6/28/16
    //for each tile how many fibers free?  how many to each type of target?
    int free_tot=0;
    for (int jused=0;jused<F.NUsedplate;jused++){
        int free=0;
        int j=A.suborder[jused];
        for (int k=0);k<F.Nfiber;++k){
            if A.TF[j][k]==-1{
                free+=1;
                free_tot+=1;
            }
        }
        printf(" jused  %d   j  %d   free   %d   free total  %d \n",jused,j,free,free_tot)
    }

    if (F.PrintAscii){
        for (int jused=0; jused<F.NUsedplate; jused++){
            int j=A.suborder[jused];
            write_FAtile_ascii(A.suborder[jused],F.outDir,M,P,pp,F,A);
        }
    }

    if (F.PrintFits) {
        for (int jused=0; jused<F.NUsedplate; jused++){
            int j=A.suborder[jused];
            fa_write(A.suborder[jused],F.outDir,M,P,pp,F,A); // Write outpu
        }
    }

	display_results("doc/figs/",Secret,M,P,pp,F,A,F.Nplate,true);
	if (F.Verif) A.verif(P,M,pp,F); // Verification that the assignment is sane

    print_time(t,"# Finished !... in");

    return(0);

}
<commit_msg>get free fibers each plate<commit_after>#include    <cstdlib>
#include    <cmath>
#include    <fstream>
#include    <sstream>
#include    <iostream>
#include    <iomanip>
#include    <string>
#include    <vector>
#include    <algorithm>
#include    <exception>
#include    <sys/time.h>
#include    "modules/htmTree.h"
#include    "modules/kdTree.h"
#include        "misc.h"
#include        "feat.h"
#include        "structs.h"
#include        "collision.h"
#include        "global.h"
//reduce redistributes, updates  07/02/15 rnc
int main(int argc, char **argv) {
    //// Initializations ---------------------------------------------
    srand48(1234); // Make sure we have reproducability
    check_args(argc);
    Time t, time; // t for global, time for local
    init_time(t);
    Feat F;
    MTL M;

    // Read parameters file //
    F.readInputFile(argv[1]);
    printFile(argv[1]);
    // Read Secretfile
    // Secret contains the identity of each target: QSO-Ly-a, QSO-tracers, LRG, ELG, fake QSO, fake LRG, SS, SF
    Gals Secret;
    init_time_at(time,"# reading Secret file",t);

        Secret=read_Secretfile(F.Secretfile,F);
    printf("# Read %d galaxies from %s \n",Secret.size(),F.Secretfile.c_str());
    print_time(time,"# ... took :");
    std::vector<int> count(10);
    count=count_galaxies(Secret);
    printf(" Number of galaxies by type, QSO-Ly-a, QSO-tracers, LRG, ELG, fake QSO, fake LRG, SS, SF\n");
    for(int i=0;i<8;i++){if(count[i]>0)printf (" type %d number  %d  \n",i, count[i]);}
    //read the three input fits files
    init_time_at(time,"# read target, SS, SF files",t);
    MTL Targ=read_MTLfile(F.Targfile,F,0,0);
    MTL SStars=read_MTLfile(F.SStarsfile,F,1,0);
    MTL SkyF=read_MTLfile(F.SkyFfile,F,0,1);

    if(Targ.size() == 0) {
        std::cerr << "ERROR: No targets found in " << F.Targfile << std::endl;
        myexit(1);
    }

    print_time(time,"# ... took :");
    //combine the three input files
    M=Targ;
    printf(" M size %d \n",M.size());
    M.insert(M.end(),SStars.begin(),SStars.end());
    printf(" M size %d \n",M.size());
    M.insert(M.end(),SkyF.begin(),SkyF.end());
    printf(" M size %d \n",M.size());
    F.Ngal=M.size();
    F.Ntarg=Secret.size();

    //establish priority classes
    init_time_at(time,"# establish priority clasess",t);
    assign_priority_class(M);
    std::vector <int> count_class(M.priority_list.size(),0);
    for(int i;i<M.size();++i){
        if(!M[i].SS&&!M[i].SF){
        count_class[M[i].priority_class]+=1;
        }
    }
    for(int i;i<M.priority_list.size();++i){
        printf("  class %d  priority %d  number %d\n",i,M.priority_list[i],count_class[i]);
    }
    print_time(time,"# ... took :");

    // fiber positioners
    PP pp;
    pp.read_fiber_positions(F);
    F.Nfiber = pp.fp.size()/2;
    F.Npetal = max(pp.spectrom)+1;
    F.Nfbp = (int) (F.Nfiber/F.Npetal);// fibers per petal = 500
    pp.get_neighbors(F);
    pp.compute_fibsofsp(F);
    printf("computed neighbors\n");
    std::cout.flush();
    //P tiles in order specified by surveyFile
    Plates P = read_plate_centers(F);
    F.Nplate=P.size();
    printf("# Read %d plates from %s and %d fibers from %s\n",F.Nplate,F.tileFile.c_str(),F.Nfiber,F.fibFile.c_str());

    // Computes geometries of cb and fh: pieces of positioner - used to determine possible collisions
    F.cb = create_cb(); // cb=central body
    F.fh = create_fh(); // fh=fiber holder

    //// Collect available galaxies <-> tilefibers --------------------
    // HTM Tree of galaxies
    const double MinTreeSize = 0.01;
    init_time_at(time,"# Start building HTM tree",t);

    htmTree<struct target> T(M,MinTreeSize);
    print_time(time,"# ... took :");//T.stats();
    init_time_at(time,"# collect galaxies at ",t);

    // For plates/fibers, collect available galaxies; done in parallel
    collect_galaxies_for_all(M,T,P,pp,F);
    print_time(time,"# ... took :");//T.stats();
    init_time_at(time,"# collect available tile-fibers at",t);
    // For each galaxy, computes available tilefibers  G[i].av_tfs = [(j1,k1),(j2,k2),..]
    collect_available_tilefibers(M,P,F);

    //results_on_inputs("doc/figs/",G,P,F,true);

    //// Assignment |||||||||||||||||||||||||||||||||||||||||||||||||||
    printf(" Nplate %d  Ngal %d   Nfiber %d \n", F.Nplate, F.Ngal, F.Nfiber);
    Assignment A(M,F);

    print_time(t,"# Start assignment at : ");

    // Make a plan ----------------------------------------------------
    // Plans whole survey without sky fibers, standard stars
    // assumes maximum number of observations needed for QSOs, LRGs

    simple_assign(M,P,pp,F,A);

    //check to see if there are tiles with no galaxies
    //need to keep mapping of old tile list to new tile list
    //and inverse map
    A.inv_order=initList(F.Nplate,-1);
    int inv_count=0;
    for (int j=0;j<F.Nplate ;++j){

        bool not_done=true;
        for(int k=0;k<F.Nfiber && not_done;++k){
            if(A.TF[j][k]!=-1){//fiber and therefore plate is used
                A.suborder.push_back(j);//suborder[jused] is jused-th used plate
                not_done=false;
                A.inv_order[j]=inv_count;//inv_order[j] is -1 unless used
                                //and otherwise the position of plate j in list of used plates
                inv_count++;
            }
        }
    }
    F.NUsedplate=A.suborder.size();
    printf(" Plates actually used %d \n",F.NUsedplate);

    if(F.diagnose)diagnostic(M,Secret,F,A);

    print_hist("Unused fibers",5,histogram(A.unused_fbp(pp,F),5),false); // Hist of unused fibs

    // Smooth out distribution of free fibers, and increase the number of assignments

    for (int i=0; i<1; i++) redistribute_tf(M,P,pp,F,A,0);// more iterations will improve performance slightly
    for (int i=0; i<1; i++) {
        improve(M,P,pp,F,A,0);
        redistribute_tf(M,P,pp,F,A,0);
    }
    print_hist("Unused fibers",5,histogram(A.unused_fbp(pp,F),5),false);
    //try assigning SF and SS before real time assignment
    for (int jused=0;jused<F.NUsedplate;++jused){
        int j=A.suborder[jused];
        assign_sf_ss(j,M,P,pp,F,A); // Assign SS and SF for each tile
        assign_unused(j,M,P,pp,F,A);
    }
    if(F.diagnose)diagnostic(M,Secret,F,A);
    init_time_at(time,"# Begin real time assignment",t);

    //Execute plan, updating targets at intervals
    for(int i=0;i<F.pass_intervals.size();i++){
        printf(" i=%d interval %d \n",i,F.pass_intervals[i]);
    }
    std::vector <int> update_intervals=F.pass_intervals;
    update_intervals.push_back(F.NUsedplate);//to end intervals at last plate
    for(int i=0;i<update_intervals.size();++i){
        printf("i %d  update_interval %d\n",i, update_intervals[i]);
    }
    for(int i=0;i<update_intervals.size()-1;++i){//go plate by used plate
        int starter=update_intervals[i];
        printf("-- interval %d\n",i);
        for (int jused=starter; jused<update_intervals[i+1] && jused<A.suborder.size()-1; jused++) {

            if (0<=jused-F.Analysis) {
                update_plan_from_one_obs(jused,Secret,M,P,pp,F,A);
            }
            else printf("\n no update\n");
            // Update corrects all future occurrences of wrong QSOs etc and tries to observe something else

        }
        printf("-- redistribute %d\n",i);
        redistribute_tf(M,P,pp,F,A,starter);
        printf("-- improve %d\n",i);
        improve(M,P,pp,F,A,starter);
        printf("-- improve again %d\n",i);
        redistribute_tf(M,P,pp,F,A,starter);
        printf("-- diagnose %d\n",i);
        if(F.diagnose)diagnostic(M,Secret,F,A);

    }
    // check on SS and SF

    printf("-- Checking SS/SF\n");
    List SS_hist=initList(11,0);
    List SF_hist=initList(41,0);
    for(int jused=0;jused<F.NUsedplate;++jused){
        int j=A.suborder[jused];
        for (int p=0;p<F.Npetal;++p){
            int count_SS=0;
            int count_SF=0;
            for (int k=0;k<F.Nfbp;++k){
                int kk=pp.fibers_of_sp[p][k];
                int g=A.TF[j][kk];
                if(g!=-1 && M[g].SS)count_SS++;
                if(g!=-1 && M[g].SF)count_SF++;
            }
            SS_hist[count_SS]++;
            SF_hist[count_SF]++;
        }
    }
    printf(" SS distribution \n");
    for(int i=0;i<10;i++)printf("%8d",SS_hist[i]);
    printf("\n %8d \n",SS_hist[10]);

    printf(" SF distribution \n");
    for(int i=0;i<10;i++)printf("%8d",SF_hist[i]);
    printf("\n");
    for(int i=10;i<20;i++)printf("%8d",SF_hist[i]);
    printf("\n");
    for(int i=20;i<30;i++)printf("%8d",SF_hist[i]);
    printf("\n");
    for(int i=30;i<40;i++)printf("%8d",SF_hist[i]);
    printf("\n %8d \n",SF_hist[40]);

    // Results -------------------------------------------------------

    //special for clustering group 6/28/16
    //for each tile how many fibers free?  how many to each type of target?
    int free_tot=0;
    for (int jused=0;jused<F.NUsedplate;jused++){
        int free=0;
        int j=A.suborder[jused];
        for (int k=0;k<F.Nfiber;++k){
            if A.TF[j][k]==-1{
                free+=1;
                free_tot+=1;
            }
        }
        printf(" jused  %d   j  %d   free   %d   free total  %d \n",jused,j,free,free_tot)
    }

    if (F.PrintAscii){
        for (int jused=0; jused<F.NUsedplate; jused++){
            int j=A.suborder[jused];
            write_FAtile_ascii(A.suborder[jused],F.outDir,M,P,pp,F,A);
        }
    }

    if (F.PrintFits) {
        for (int jused=0; jused<F.NUsedplate; jused++){
            int j=A.suborder[jused];
            fa_write(A.suborder[jused],F.outDir,M,P,pp,F,A); // Write outpu
        }
    }

	display_results("doc/figs/",Secret,M,P,pp,F,A,F.Nplate,true);
	if (F.Verif) A.verif(P,M,pp,F); // Verification that the assignment is sane

    print_time(t,"# Finished !... in");

    return(0);

}
<|endoftext|>


<commit_before>#include <cassert>
#include <iostream>

#include "Workspace/Application/LanguageUtils/streamqstring.h"
#include "Workspace/DataExecution/DataObjects/typedobject.h"
#include "Workspace/DataExecution/InputOutput/inputscalar.h"
#include "Workspace/DataExecution/InputOutput/inputarray.h"
#include "Workspace/DataExecution/InputOutput/output.h"
#include "Workspace/DataExecution/Operations/typedoperationfactory.h"

//OpenCV core for ellipse
#include "opencv2/imgproc.hpp"

#include "qimage.h"

#include "volcanoplugin.h"
#include "ellipticalpile.h"

namespace RF
{
    /**
     * \internal
     */
    class EllipticalPileImpl
    {
        // Allow string translation to work properly
        Q_DECLARE_TR_FUNCTIONS(RF::EllipticalPileImpl)

    public:
        EllipticalPile&  op_;

        // Data objects
        CSIRO::DataExecution::TypedObject< double >        dataCenterX_;
        CSIRO::DataExecution::TypedObject< double >        dataCenterY_;
        CSIRO::DataExecution::TypedObject< double >        dataMajorLen_;
        CSIRO::DataExecution::TypedObject< double >        dataMinorLen_;
        CSIRO::DataExecution::TypedObject< double >        dataAngle_;
        CSIRO::DataExecution::TypedObject< GDALDatasetH >  dataBaseDataSet_;
        CSIRO::DataExecution::TypedObject< GDALDatasetH >  dataOutputEllipse_;
		CSIRO::DataExecution::TypedObject< QString >       dataOutputRasterName_;
		CSIRO::DataExecution::TypedObject< int >           dataRasterBand_;
		CSIRO::DataExecution::TypedObject< double >        dataVolume_;

        // Inputs and outputs
        CSIRO::DataExecution::InputScalar inputCenterX_;
        CSIRO::DataExecution::InputScalar inputCenterY_;
        CSIRO::DataExecution::InputScalar inputMajorLen_;
        CSIRO::DataExecution::InputScalar inputMinorLen_;
        CSIRO::DataExecution::InputScalar inputAngle_;
        CSIRO::DataExecution::InputScalar inputBaseDataSet_;
		CSIRO::DataExecution::InputScalar inputOutputRasterName_;
		CSIRO::DataExecution::Output      outputOutputEllipse_;
		CSIRO::DataExecution::InputScalar inputRasterBand_;
		CSIRO::DataExecution::InputScalar inputVolume_;

        EllipticalPileImpl(EllipticalPile& op);

        bool  execute();
        void  logText(const QString& msg)   { op_.logText(msg); }
    };

    /**
     *
     */
    EllipticalPileImpl::EllipticalPileImpl(EllipticalPile& op) :
        op_(op),
        dataCenterX_(),
        dataCenterY_(),
        dataMajorLen_(),
        dataMinorLen_(),
        dataAngle_(),
        dataBaseDataSet_(),
        dataOutputEllipse_(),
        dataVolume_(),
	    inputCenterX_("Center X", dataCenterX_, op_),
        inputCenterY_("Center Y", dataCenterY_, op_),
        inputMajorLen_("Major axis length", dataMajorLen_, op_),
        inputMinorLen_("Minor axis length", dataMinorLen_, op_),
        inputAngle_("Angle", dataAngle_, op_),
        inputBaseDataSet_("BaseDataSet", dataBaseDataSet_, op_),
        outputOutputEllipse_("Output Ellipse", dataOutputEllipse_, op_),
		inputOutputRasterName_("Output Raster name", dataOutputRasterName_, op_),
		inputRasterBand_("Raster Band", dataRasterBand_, op_),
        inputVolume_("Target volume", dataVolume_, op_)
    {
        // Make sure all of our inputs have data by default. If your operation accepts a
        // large data structure as input, you may wish to remove this call and replace it
        // with constructors for each input in the initialisation list above.
        op_.ensureHasData();

        // Recommend setting a description of the operation and each input / output here:
        // op_.setDescription(tr("My operation does this, that and this other thing."));
        // input_.setDescription(tr("Used for such and such."));
        // output_.setDescription(tr("Results of the blah-di-blah."));
    }

    /**
     *
     */
    bool EllipticalPileImpl::execute()
    {
        double&       centerX       = *dataCenterX_;
        double&       centerY       = *dataCenterY_;
        double&       majorLen      = *dataMajorLen_;
        double&       minorLen      = *dataMinorLen_;
        double&       angle         = *dataAngle_;
        GDALDatasetH& baseDataSet   = *dataBaseDataSet_;
		QString&      outputRasterName = *dataOutputRasterName_;
		GDALDatasetH& outputEllipse = *dataOutputEllipse_;
		int&          rasterBand = *dataRasterBand_;
        double&       volume        = *dataVolume_;

		//Solve for max height of ellipse (h = 3*(2*Vol)/(4*pi*a*b))
		double height = 3 * ((volume*2) / (4 * M_PI*majorLen*minorLen));
		std::cout << QString("Maximum height of ellipse is %1 metres.").arg(height) + "\n";

		//Start with the raster
		GDALRasterBandH hBand;

		if (rasterBand > GDALGetRasterCount(baseDataSet))
		{
			std::cout << QString("ERROR: Not enough raster bands, number of bands is %1, band selected is %2").arg(GDALGetRasterCount(baseDataSet)).arg(rasterBand) + "\n";
		}

		hBand = GDALGetRasterBand(baseDataSet, rasterBand);

		/*
		Coefficients between Pixel Line and Projected (Yp, Xp space)
		Xp = padfTransform[0] + P*padfTransform[1] + L*padfTransform[2];
		Yp = padfTransform[3] + P*padfTransform[4] + L*padfTransform[5];
		*/

		//Get Transform and invert to get pixel/line
		double transform[6], invTransform[6];
		GDALGetGeoTransform(baseDataSet, transform);
		GDALInvGeoTransform(transform, invTransform);

		//Work out the pixel centre, pixel size of data
		cv::Point pixelCentre;
		pixelCentre.x = (int)floor(invTransform[0] + invTransform[1] * centerX + invTransform[2] * centerY);
		pixelCentre.y = (int)floor(invTransform[3] + invTransform[4] * centerX + invTransform[5] * centerY);

		cv::Size axes((int) floor(majorLen/transform[1]),
						(int) floor(minorLen/transform[1]));

		//Nodata stuff
		int srcNoData;
		float srcNoDataValue;
		srcNoDataValue = (float)GDALGetRasterNoDataValue(hBand, &srcNoData);

		//Create elliptical raster array
		float * ellipseRaster;
		ellipseRaster = new float[GDALGetRasterBandXSize(hBand)*GDALGetRasterBandYSize(hBand)];

		//Convert float array to an openCV mat (assuming rows = Y)
		cv::Mat dataToMat(GDALGetRasterBandYSize(hBand), GDALGetRasterBandXSize(hBand), CV_32F, ellipseRaster);

		//Create ellipse
		cv::ellipse(dataToMat,
			pixelCentre,
			axes,
			angle,
			0, 360,
			cv::Scalar(10.0), cv::FILLED);

		double radAngle = M_PI - (angle * DEG2RAD);
		double bigA, bigB, z;
		std::cout << QString("Rotating ellipse by %1 radians.").arg(radAngle) + "\n";

		//Loop through the Mat and set heights
		for (int y = 0; y < dataToMat.rows; y++)
		{
			for (int x = 0; x < dataToMat.cols; x++)
			{
				if (dataToMat.at<float>(y, x) > 0.0)//value within ellipse
				{
					//Work in cell coords
					double xdistance = abs(pixelCentre.x - x);
					double ydistance = abs(pixelCentre.y - y);

					//Calculate values A and B (see http://math.stackexchange.com/questions/426150/what-is-the-general-equation-of-the-ellipse-that-is-not-in-the-origin-and-rotate)
					bigA = pow(((xdistance)*cos(radAngle) + (ydistance)*sin(radAngle)), 2) / pow(axes.width, 2);
					bigB = pow(((xdistance)*sin(radAngle) + (ydistance)*cos(radAngle)), 2) / pow(axes.height, 2);
					z = sqrt(pow(height, 2)*(1 - bigA - bigB));
					dataToMat.at<float>(y, x) = (float)z;

				}
			}
		}

		//Now write to the new gdalDataset

		outputEllipse = GDALCreate(GDALGetDatasetDriver(baseDataSet),
			outputRasterName.toLocal8Bit().constData(),
			GDALGetRasterXSize(baseDataSet), GDALGetRasterYSize(baseDataSet),
			1,
			GDT_Float32, NULL);

		GDALRasterBandH destBand = GDALGetRasterBand(outputEllipse, 1);
		GDALSetGeoTransform(outputEllipse, transform);
		GDALSetProjection(outputEllipse, GDALGetProjectionRef(baseDataSet));
		GDALSetRasterNoDataValue(destBand, srcNoDataValue);

		CPLErr error;
		error = GDALRasterIO(destBand, GF_Write,
			0, 0,
			GDALGetRasterBandXSize(hBand), GDALGetRasterBandYSize(hBand),
			dataToMat.data,
			GDALGetRasterBandXSize(hBand), GDALGetRasterBandYSize(hBand),
			GDT_Float32,
			0, 0);

		if (error != CE_None)
		{
			std::cout << QString("ERROR: GDALRasterIO write operation failed.") + "\n";
		}

        return true;
    }

    /**
     *
     */
    EllipticalPile::EllipticalPile() :
        CSIRO::DataExecution::Operation(
            CSIRO::DataExecution::OperationFactoryTraits< EllipticalPile >::getInstance(),
            tr("Create Elliptical Pile"))
    {
        pImpl_ = new EllipticalPileImpl(*this);
    }

    /**
     *
     */
    EllipticalPile::~EllipticalPile()
    {
        delete pImpl_;
    }

    /**
     *
     */
    bool  EllipticalPile::execute()
    {
        return pImpl_->execute();
    }
}

using namespace RF;
DEFINE_WORKSPACE_OPERATION_FACTORY(EllipticalPile,
                                   RF::VolcanoPlugin::getInstance(),
                                   CSIRO::DataExecution::Operation::tr("Geospatial"))

<commit_msg>Made ellipse in any rotation working<commit_after>#include <cassert>
#include <iostream>

#include "Workspace/Application/LanguageUtils/streamqstring.h"
#include "Workspace/DataExecution/DataObjects/typedobject.h"
#include "Workspace/DataExecution/InputOutput/inputscalar.h"
#include "Workspace/DataExecution/InputOutput/inputarray.h"
#include "Workspace/DataExecution/InputOutput/output.h"
#include "Workspace/DataExecution/Operations/typedoperationfactory.h"

//OpenCV core for ellipse
#include "opencv2/imgproc.hpp"
#include "qimage.h"

#include "volcanoplugin.h"
#include "ellipticalpile.h"

namespace RF
{
    /**
     * \internal
     */
    class EllipticalPileImpl
    {
        // Allow string translation to work properly
        Q_DECLARE_TR_FUNCTIONS(RF::EllipticalPileImpl)

    public:
        EllipticalPile&  op_;

        // Data objects
        CSIRO::DataExecution::TypedObject< double >        dataCenterX_;
        CSIRO::DataExecution::TypedObject< double >        dataCenterY_;
        CSIRO::DataExecution::TypedObject< double >        dataMajorLen_;
        CSIRO::DataExecution::TypedObject< double >        dataMinorLen_;
        CSIRO::DataExecution::TypedObject< double >        dataAngle_;
        CSIRO::DataExecution::TypedObject< GDALDatasetH >  dataBaseDataSet_;
        CSIRO::DataExecution::TypedObject< GDALDatasetH >  dataOutputEllipse_;
		CSIRO::DataExecution::TypedObject< QString >       dataOutputRasterName_;
		CSIRO::DataExecution::TypedObject< int >           dataRasterBand_;
		CSIRO::DataExecution::TypedObject< double >        dataVolume_;

        // Inputs and outputs
        CSIRO::DataExecution::InputScalar inputCenterX_;
        CSIRO::DataExecution::InputScalar inputCenterY_;
        CSIRO::DataExecution::InputScalar inputMajorLen_;
        CSIRO::DataExecution::InputScalar inputMinorLen_;
        CSIRO::DataExecution::InputScalar inputAngle_;
        CSIRO::DataExecution::InputScalar inputBaseDataSet_;
		CSIRO::DataExecution::InputScalar inputOutputRasterName_;
		CSIRO::DataExecution::Output      outputOutputEllipse_;
		CSIRO::DataExecution::InputScalar inputRasterBand_;
		CSIRO::DataExecution::InputScalar inputVolume_;

        EllipticalPileImpl(EllipticalPile& op);

        bool  execute();
        void  logText(const QString& msg)   { op_.logText(msg); }
    };

    /**
     *
     */
    EllipticalPileImpl::EllipticalPileImpl(EllipticalPile& op) :
        op_(op),
        dataCenterX_(),
        dataCenterY_(),
        dataMajorLen_(),
        dataMinorLen_(),
        dataAngle_(),
        dataBaseDataSet_(),
        dataOutputEllipse_(),
        dataVolume_(),
	    inputCenterX_("Center X", dataCenterX_, op_),
        inputCenterY_("Center Y", dataCenterY_, op_),
        inputMajorLen_("Major axis length", dataMajorLen_, op_),
        inputMinorLen_("Minor axis length", dataMinorLen_, op_),
        inputAngle_("Angle", dataAngle_, op_),
        inputBaseDataSet_("BaseDataSet", dataBaseDataSet_, op_),
        outputOutputEllipse_("Output Ellipse", dataOutputEllipse_, op_),
		inputOutputRasterName_("Output Raster name", dataOutputRasterName_, op_),
		inputRasterBand_("Raster Band", dataRasterBand_, op_),
        inputVolume_("Target volume", dataVolume_, op_)
    {
        // Make sure all of our inputs have data by default. If your operation accepts a
        // large data structure as input, you may wish to remove this call and replace it
        // with constructors for each input in the initialisation list above.
        op_.ensureHasData();

        // Recommend setting a description of the operation and each input / output here:
        // op_.setDescription(tr("My operation does this, that and this other thing."));
        // input_.setDescription(tr("Used for such and such."));
        // output_.setDescription(tr("Results of the blah-di-blah."));
    }

    /**
     *
     */
    bool EllipticalPileImpl::execute()
    {
        double&       centerX       = *dataCenterX_;
        double&       centerY       = *dataCenterY_;
        double&       majorLen      = *dataMajorLen_;
        double&       minorLen      = *dataMinorLen_;
        double&       angle         = *dataAngle_;
        GDALDatasetH& baseDataSet   = *dataBaseDataSet_;
		QString&      outputRasterName = *dataOutputRasterName_;
		GDALDatasetH& outputEllipse = *dataOutputEllipse_;
		int&          rasterBand = *dataRasterBand_;
        double&       volume        = *dataVolume_;

		//Solve for max height of ellipse (h = 3*(2*Vol)/(4*pi*a*b))
		double height = 3 * ((volume*2) / (4 * M_PI*majorLen*minorLen));
		std::cout << QString("Maximum height of ellipse is %1 metres.").arg(height) + "\n";

		//Start with the raster
		GDALRasterBandH hBand;

		if (rasterBand > GDALGetRasterCount(baseDataSet))
		{
			std::cout << QString("ERROR: Not enough raster bands, number of bands is %1, band selected is %2").arg(GDALGetRasterCount(baseDataSet)).arg(rasterBand) + "\n";
		}

		hBand = GDALGetRasterBand(baseDataSet, rasterBand);

		/*
		Coefficients between Pixel Line and Projected (Yp, Xp space)
		Xp = padfTransform[0] + P*padfTransform[1] + L*padfTransform[2];
		Yp = padfTransform[3] + P*padfTransform[4] + L*padfTransform[5];
		*/

		//Get Transform and invert to get pixel/line
		double transform[6], invTransform[6];
		GDALGetGeoTransform(baseDataSet, transform);
		GDALInvGeoTransform(transform, invTransform);

		//Work out the pixel centre, pixel size of data
		cv::Point pixelCentre;
		pixelCentre.x = (int)floor(invTransform[0] + invTransform[1] * centerX + invTransform[2] * centerY);
		pixelCentre.y = (int)floor(invTransform[3] + invTransform[4] * centerX + invTransform[5] * centerY);

		cv::Size axes((int) floor(majorLen/transform[1]),
						(int) floor(minorLen/transform[1]));

		//Nodata stuff
		int srcNoData;
		float srcNoDataValue;
		srcNoDataValue = (float)GDALGetRasterNoDataValue(hBand, &srcNoData);

		//Create elliptical raster array
		float * ellipseRaster;
		ellipseRaster = new float[GDALGetRasterBandXSize(hBand)*GDALGetRasterBandYSize(hBand)];

		//Convert float array to an openCV mat (assuming rows = Y)
		cv::Mat dataToMat(GDALGetRasterBandYSize(hBand), GDALGetRasterBandXSize(hBand), CV_32F, ellipseRaster);

		//Create ellipse
		cv::ellipse(dataToMat,
			pixelCentre,
			axes,
			angle,
			0, 360,
			cv::Scalar(10.0), cv::FILLED);

		double radAngle = (angle * DEG2RAD);
		double bigA, bigB, z;
		std::cout << QString("Rotating ellipse by %1 radians.").arg(radAngle) + "\n";

		//Loop through the Mat and set heights
		for (int y = 0; y < dataToMat.rows; y++)
		{
			for (int x = 0; x < dataToMat.cols; x++)
			{
				if (dataToMat.at<float>(y, x) > 0.0)//value within ellipse
				{
					//Work in cell coords
					double xdistance = (pixelCentre.x - x);
					double ydistance = (pixelCentre.y - y);

					//Calculate values A and B (Rotation of coordinates (xcos(t)+ysin(t),(ycos(t)-xsin(t))
					bigA = pow(((xdistance)*cos(radAngle) + (ydistance)*sin(radAngle)), 2) / pow(axes.width, 2);
					bigB = pow(((ydistance)*cos(radAngle) - (xdistance)*sin(radAngle)), 2) / pow(axes.height, 2);
					z = sqrt(pow(height, 2)*(1 - bigA - bigB));
					dataToMat.at<float>(y, x) = (float)z;

				}
			}
		}

		//Now write to the new gdalDataset

		outputEllipse = GDALCreate(GDALGetDatasetDriver(baseDataSet),
			outputRasterName.toLocal8Bit().constData(),
			GDALGetRasterXSize(baseDataSet), GDALGetRasterYSize(baseDataSet),
			1,
			GDT_Float32, NULL);

		GDALRasterBandH destBand = GDALGetRasterBand(outputEllipse, 1);
		GDALSetGeoTransform(outputEllipse, transform);
		GDALSetProjection(outputEllipse, GDALGetProjectionRef(baseDataSet));
		GDALSetRasterNoDataValue(destBand, srcNoDataValue);

		CPLErr error;
		error = GDALRasterIO(destBand, GF_Write,
			0, 0,
			GDALGetRasterBandXSize(hBand), GDALGetRasterBandYSize(hBand),
			dataToMat.data,
			GDALGetRasterBandXSize(hBand), GDALGetRasterBandYSize(hBand),
			GDT_Float32,
			0, 0);

		if (error != CE_None)
		{
			std::cout << QString("ERROR: GDALRasterIO write operation failed.") + "\n";
		}

        return true;
    }

    /**
     *
     */
    EllipticalPile::EllipticalPile() :
        CSIRO::DataExecution::Operation(
            CSIRO::DataExecution::OperationFactoryTraits< EllipticalPile >::getInstance(),
            tr("Create Elliptical Pile"))
    {
        pImpl_ = new EllipticalPileImpl(*this);
    }

    /**
     *
     */
    EllipticalPile::~EllipticalPile()
    {
        delete pImpl_;
    }

    /**
     *
     */
    bool  EllipticalPile::execute()
    {
        return pImpl_->execute();
    }
}

using namespace RF;
DEFINE_WORKSPACE_OPERATION_FACTORY(EllipticalPile,
                                   RF::VolcanoPlugin::getInstance(),
                                   CSIRO::DataExecution::Operation::tr("Geospatial"))

<|endoftext|>


<commit_before>#include <fstream>
#include <iostream>
#include <math.h>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>

using namespace cv;
using namespace std;

const double PI = 3.1415926536;
const int angle2step = 120;

typedef struct angles {
    float a;
    float b;
    float r;
} angles;

typedef struct xyz {
    float x;
    float y;
    float z;
} xyz;

angles cal_angle(xyz coord);
string f_dirsteps(xyz curr, xyz next);
string num2str(int i);
void gen_coord(string file_path);
xyz find_dot(xyz circle, int *cp_img, int width, int height);

int main() {
    gen_coord("../data/img/sketch.jpg");
    return 0;
}

void gen_coord(string file_path) {
    Mat src = imread(file_path, 1);
    ofstream out("out.txt");
    int width = src.cols;
    int height = src.rows;
    int cp_img[height][width];

    for (int h = 0; h < height; h++) {
        uchar *P = src.ptr<uchar>(h);
        for (int w = 0; w < width; w++) {
            cp_img[h][w] = P[w];
        }
    }
    xyz center = {0, 0, 0};
    xyz next_center = {-1, -1, -1};
    int find_tag = 0;
    for (int h = 0; h < height; h++) {
        for (int w = 0; w < width; w++) {
            if (cp_img[h][w] == 255) {
                center = {w, h, 0};
                find_tag = 1;
                break;
            }
        }
        if (find_tag == 1)
            break;
    }

    while (1) {
        next_center = find_dot(center, (int *)cp_img, width, height);
        if (next_center.z == -1)
            break;
        if (next_center.z > 3) {
            xyz temp1 = center;
            temp1.z = 1;
            f_dirsteps(center, temp1);
            next_center.z = 1;
            xyz temp2 = next_center;
            f_dirsteps(temp1, temp2);
            next_center.z = 0;
            f_dirsteps(temp2, next_center);
            center = next_center;
        } else {
            next_center.z = 0;
            f_dirsteps(center, next_center);
            center = next_center;
        }
        cp_img[int(center.y)][int(center.x)] = 0;
    }
    out.close();
}

xyz find_dot(xyz center, int *cp_img, int width, int height) {
    int x = center.x;
    int y = center.y;
    xyz next_dot;
    int map[height][width];
    for (int h = 0; h < height; h++) {
        for (int w = 0; w < width; w++) {
            map[h][w] = *(cp_img + width * h + w);
        }
    }
    int max_cr = max(max(max(x, y), abs(x - width - 1)), abs(y - height - 1));
    for (int cr = 1; cr < max_cr + 1; cr++) {       //分层找点
        for (int dn = -cr + 1; dn < cr + 1; dn++) { //下面的边
            if (y + cr + 1 > height)
                break;
            if (x + dn < 0)
                continue;
            if (x + dn + 1 > width)
                break;
            if (!map[x + dn][y + cr]) {
                next_dot = {x + dn, y + cr, cr};
                map[x + dn][y + cr] = 0;
                return next_dot;
            }
        }

        for (int rt = -cr + 1; rt < cr + 1; rt++) { //右面的边
            if (x + cr + 1 > width)
                break;
            if (y - rt + 1 > height)
                continue;
            if (y - rt < 0)
                break;
            if (!map[x + cr][y - rt]) {
                next_dot = {x + cr, y - rt, cr};
                map[x + cr][y - rt] = 0;
                return next_dot;
            }
        }

        for (int up = -cr + 1; up < cr + 1; up++) { //上面的边
            if (y - cr < 0)
                break;
            if (x - up + 1 > width)
                continue;
            if (x - up < 0)
                break;
            if (!map[x - up][y - cr]) {
                next_dot = {x - up, y - cr, cr};
                map[x - up][y - cr] = 0;
                return next_dot;
            }
        }

        for (int lt = -cr + 1; lt < cr + 1; lt++) { //左面的边
            if (x - cr < 0)
                break;
            if (y + lt < 0)
                continue;
            if (y + lt + 1 > height)
                break;
            if (!map[x - cr][y + lt]) {
                next_dot = {x - cr, y + lt, cr};
                map[x - cr][y + lt] = 0;
                return next_dot;
            }
        }
    }
    next_dot = {-1, -1, -1};
    return next_dot;
}

angles cal_angle(xyz coord) {
    float p = 0.0;
    angles angle;
    p = sqrt(coord.x * coord.x + coord.y * coord.y + coord.z * coord.z);
    if (coord.x <= 0)
        angle.a = asin(-coord.y / sqrt(coord.x * coord.x + coord.y * coord.y)) *
                  180 / PI;
    else
        angle.a = asin(coord.y / sqrt(coord.x * coord.x + coord.y * coord.y)) *
                      180 / PI +
                  180;

    coord.y = coord.y + 80 * sin(angle.a);
    coord.x = coord.x + 80 * cos(angle.a);
    p = sqrt(coord.x * coord.x + coord.y * coord.y + coord.z * coord.z);
    if (coord.x <= 0)
        angle.a = asin(-coord.y / sqrt(coord.x * coord.x + coord.y * coord.y)) *
                  180 / PI;
    else
        angle.a = asin(coord.y / sqrt(coord.x * coord.x + coord.y * coord.y)) *
                      180 / PI +
                  180;

    angle.b = (acos((45 / p) + (p / 500)) + asin(-coord.z / p)) * 180 / PI;
    angle.r =
        (acos((p * p - 22500) / (400 * p)) + acos(-coord.z / p)) * 180 / PI;

    return angle;
}

string f_dirsteps(xyz curr, xyz next) {
    string fpath = "$";
    angles curr_angles = cal_angle(curr);
    angles next_angles = cal_angle(next);
    float angle_a = next_angles.a - curr_angles.a;
    float angle_b = next_angles.b - curr_angles.b;
    float angle_r = next_angles.r - curr_angles.r;
    if (angle_a > 0)
        fpath = fpath + "1" + num2str(round(angle_a * angle2step)) + "#";
    else
        fpath = fpath + "0" + num2str(round(-angle_a * angle2step)) + "#";

    if (angle_b > 0)
        fpath = fpath + "1" + num2str(round(angle_b * angle2step)) + "#";
    else
        fpath = fpath + "0" + num2str(round(-angle_b * angle2step)) + "#";

    if (angle_r > 0)
        fpath = fpath + "1" + num2str(round(angle_r * angle2step)) + "#";
    else
        fpath = fpath + "0" + num2str(round(-angle_r * angle2step)) + "#";

    fpath = fpath + "@";
    return fpath;
}

string num2str(int i) {
    stringstream ss;
    ss << i;
    return ss.str();
}
<commit_msg>a completed program for generate steps and dirrection<commit_after>#include <fstream>
#include <iostream>
#include <math.h>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>

using namespace cv;
using namespace std;

const double PI = 3.1415926535897932384626433832795;
const float angle2step = 6875.4935;
const float std_z = -260;

typedef struct angles {
    float a;
    float b;
    float r;
} angles;

typedef struct xyz {
    float x;
    float y;
    float z;
} xyz;

angles cal_angle(xyz coord);
string f_dirsteps(xyz curr, xyz next);
string num2str(int i);
void gen_coord(string file_path);
xyz find_dot(xyz circle, int *cp_img, int width, int height);
xyz convert_coord(xyz origin_coord, int width, int height);

xyz init_coord = {280, 0, -250};

int main() {
    gen_coord("../data/img/sketch.jpg");
    return 0;
}

void gen_coord(string file_path) {
    Mat src = imread(file_path, 1);
    ofstream out("out.txt");
    int width = src.cols;
    int height = src.rows;
    int cp_img[height][width];

    for (int h = 0; h < height; h++) {
        uchar *P = src.ptr<uchar>(h);
        for (int w = 0; w < width; w++) {
            cp_img[h][w] = P[w];
        }
    }
    xyz center = {0, 0, 0};
    xyz next_center = {-1, -1, -1};
    int find_tag = 0;
    for (int h = 0; h < height; h++) {
        for (int w = 0; w < width; w++) {
            if (cp_img[h][w] == 255) {
                center = {w, h, 1};
                find_tag = 1;
                break;
            }
        }
        if (find_tag == 1)
            break;
    }

    f_dirsteps(init_coord, convert_coord(center, width, height));
    center.z = 0;
    while (1) {
        next_center = find_dot(center, (int *)cp_img, width, height);
        if (next_center.z == -1)
            break;
        if (next_center.z > 3) {
            xyz temp1 = center;
            temp1.z = 1;
            f_dirsteps(convert_coord(center, width, height),
                       convert_coord(temp1, width, height));
            next_center.z = 1;
            xyz temp2 = next_center;
            f_dirsteps(convert_coord(temp1, width, height),
                       convert_coord(temp2, width, height));
            next_center.z = 0;
            f_dirsteps(convert_coord(temp2, width, height),
                       convert_coord(next_center, width, height));
        } else {
            next_center.z = 0;
            f_dirsteps(convert_coord(center, width, height),
                       convert_coord(next_center, width, height));
        }
        cp_img[int(center.y)][int(center.x)] = 0;
        center = next_center;
    }
    next_center = center;
    next_center.z = 1;
    f_dirsteps(convert_coord(center, width, height),
               convert_coord(next_center, width, height));
    f_dirsteps(convert_coord(next_center, width, height), init_coord);
    out.close();
}

xyz find_dot(xyz center, int *cp_img, int width, int height) {
    int x = center.x;
    int y = center.y;
    xyz next_dot;
    int map[height][width];
    for (int h = 0; h < height; h++) {
        for (int w = 0; w < width; w++) {
            map[h][w] = *(cp_img + width * h + w);
        }
    }
    int max_cr = max(max(max(x, y), abs(x - width - 1)), abs(y - height - 1));
    for (int cr = 1; cr < max_cr + 1; cr++) {       //分层找点
        for (int dn = -cr + 1; dn < cr + 1; dn++) { //下面的边
            if (y + cr + 1 > height)
                break;
            if (x + dn < 0)
                continue;
            if (x + dn + 1 > width)
                break;
            if (!map[x + dn][y + cr]) {
                next_dot = {x + dn, y + cr, cr};
                map[x + dn][y + cr] = 0;
                return next_dot;
            }
        }

        for (int rt = -cr + 1; rt < cr + 1; rt++) { //右面的边
            if (x + cr + 1 > width)
                break;
            if (y - rt + 1 > height)
                continue;
            if (y - rt < 0)
                break;
            if (!map[x + cr][y - rt]) {
                next_dot = {x + cr, y - rt, cr};
                map[x + cr][y - rt] = 0;
                return next_dot;
            }
        }

        for (int up = -cr + 1; up < cr + 1; up++) { //上面的边
            if (y - cr < 0)
                break;
            if (x - up + 1 > width)
                continue;
            if (x - up < 0)
                break;
            if (!map[x - up][y - cr]) {
                next_dot = {x - up, y - cr, cr};
                map[x - up][y - cr] = 0;
                return next_dot;
            }
        }

        for (int lt = -cr + 1; lt < cr + 1; lt++) { //左面的边
            if (x - cr < 0)
                break;
            if (y + lt < 0)
                continue;
            if (y + lt + 1 > height)
                break;
            if (!map[x - cr][y + lt]) {
                next_dot = {x - cr, y + lt, cr};
                map[x - cr][y + lt] = 0;
                return next_dot;
            }
        }
    }
    next_dot = {-1, -1, -1};
    return next_dot;
}

angles cal_angle(xyz coord) {
    float p = 0.0;
    angles angle;
    if (coord.x >= 0)
        angle.a = asin(coord.y / sqrt(coord.x * coord.x + coord.y * coord.y));
    else
        angle.a =
            asin(-coord.y / sqrt(coord.x * coord.x + coord.y * coord.y)) - PI;

    coord.y = coord.y - 80 * sin(angle.a);
    coord.x = coord.x - 80 * cos(angle.a);
    p = sqrt(coord.x * coord.x + coord.y * coord.y + coord.z * coord.z);
    angle.b = (acos((45 / p) + (p / 500)) + asin(-coord.z / p));
    angle.r = (acos((p * p - 22500) / (400 * p)) + acos(-coord.z / p));

    return angle;
}

string f_dirsteps(xyz curr, xyz next) {
    string fpath = "$";
    angles curr_angles = cal_angle(curr);
    angles next_angles = cal_angle(next);
    float angle_a = next_angles.a - curr_angles.a;
    float angle_b = next_angles.b - curr_angles.b;
    float angle_r = next_angles.r - curr_angles.r;

    if (angle_a >= 0)
        fpath = fpath + "1" + num2str(round(angle_a * angle2step)) + "#";
    else
        fpath = fpath + "0" + num2str(round(-angle_a * angle2step)) + "#";

    if (angle_b >= 0)
        fpath = fpath + "1" + num2str(round(angle_b * angle2step)) + "#";
    else
        fpath = fpath + "0" + num2str(round(-angle_b * angle2step)) + "#";

    if (angle_r >= 0)
        fpath = fpath + "1" + num2str(round(angle_r * angle2step)) + "#";
    else
        fpath = fpath + "0" + num2str(round(-angle_r * angle2step)) + "#";

    fpath = fpath + "@";
    return fpath;
}

string num2str(int i) {
    stringstream ss;
    ss << i;
    return ss.str();
}

xyz convert_coord(xyz origin_coord, int width, int height) {
    xyz cvt_coord;
    int std_width = 7 * width;
    int std_height = 10 * height;
    float ratio;
    if (width >= height) {
        if (std_width < std_height) {
            ratio = 210.0 / height;
            cvt_coord.x = 330 - int(origin_coord.y * ratio);
            cvt_coord.y = (50 - (300 - int(origin_coord.x * ratio)) / 2) -
                          int(origin_coord.x * ratio);
            cvt_coord.z = std_z - 30 * origin_coord.z;
        } else {
            ratio = 300.0 / width;
            cvt_coord.x = (330 - (210 - int(origin_coord.y * ratio)) / 2) -
                          int(origin_coord.y * ratio);
            cvt_coord.y = 50 - int(origin_coord.x * ratio);
            cvt_coord.z = std_z - 30 * origin_coord.z;
        }
    } else {
        if (std_width < std_height) {
            ratio = 300.0 / height;
            cvt_coord.x = (120 + (210 - int(origin_coord.x * ratio)) / 2) +
                          int(origin_coord.x * ratio);
            cvt_coord.y = 50 - int(origin_coord.y * ratio);
            cvt_coord.z = std_z - 30 * origin_coord.z;
        } else {
            ratio = 210.0 / width;
            cvt_coord.x = 120 + int(origin_coord.x * ratio);
            cvt_coord.y = (50 - (300 - int(origin_coord.y * ratio)) / 2) +
                          int(origin_coord.y * ratio);
            cvt_coord.z = std_z - 30 * origin_coord.z;
        }
    }
    return cvt_coord;
}<|endoftext|>


<commit_before>#include "tcpserver.h"

#include <algorithm>
#include <errno.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
#include <assert.h>
#include <time.h>

#include "address.h"
#include "sockutil.h"
#include "log.h"
#include "acceptor.h"
#include "connection.h"
#include "ioloop.h"
#include "signaler.h"
#include "timer.h"
#include "process.h"
#include "timingwheel.h"

using namespace std;

namespace tnet
{
    const int defaultIdleTimeout = 120;

    void dummyRunCallback(IOLoop*)
    {
    }

    TcpServer::TcpServer()
        : m_loop(0)
    {
        m_process = std::make_shared<Process>();

        m_running = false;

        m_maxIdleTimeout = defaultIdleTimeout;

        m_runCallback = std::bind(&dummyRunCallback, _1);
    }

    TcpServer::~TcpServer()
    {
        if(m_loop)
        {
            delete m_loop;
        }
    }

    int TcpServer::listen(const Address& addr, const ConnEventCallback_t& callback)
    {
        LOG_INFO("listen %s:%d", addr.ipstr().c_str(), addr.port());
        NewConnCallback_t cb = std::bind(&TcpServer::onNewConnection, this, _1, _2, callback);
        AcceptorPtr_t acceptor = std::make_shared<Acceptor>(cb);
        if(acceptor->listen(addr) < 0)
        {
            return -1;
        }

        m_acceptors.push_back(acceptor);
        return 0;
    }

    void TcpServer::run()
    {
        if(m_running)
        {
            return;
        }

        m_loop = new IOLoop();

        m_running = true;

        m_loop->addCallback(std::bind(&TcpServer::onRun, this));

        m_loop->start();
    }

    void TcpServer::onRun()
    {
        LOG_INFO("tcp server on run");

        for_each(m_acceptors.begin(), m_acceptors.end(),
            std::bind(&Acceptor::start, _1, m_loop));

        vector<int> signums{SIGINT, SIGTERM};
        m_signaler = std::make_shared<Signaler>(signums, std::bind(&TcpServer::onSignal, this, _1, _2));

        m_signaler->start(m_loop);

        m_idleWheel = std::make_shared<TimingWheel>(1000, 3600);

        m_idleWheel->start(m_loop);

        m_runCallback(m_loop);
    }

    void TcpServer::start(size_t maxProcess)
    {
        if(maxProcess > 1)
        {
            m_process->wait(maxProcess, std::bind(&TcpServer::run, this));
        }
        else
        {
            run();
        }
    }

    void TcpServer::onStop()
    {
        LOG_INFO("tcp server on stop");
        if(!m_running)
        {
            return;
        }

        m_running = false;

        m_idleWheel->stop();

        m_signaler->stop();

        for_each_all(m_acceptors, std::bind(&Acceptor::stop, _1));

        m_loop->stop();
    }

    void TcpServer::stop()
    {
        LOG_INFO("stop server");
        m_process->stop();

        onStop();
    }

    void TcpServer::onNewConnection(IOLoop* loop, int fd, const ConnEventCallback_t& callback)
    {
        ConnectionPtr_t conn = std::make_shared<Connection>(loop, fd);

        conn->setEventCallback(callback);

        conn->onEstablished();

        //check interval is (maxIdleTimeout * 9 / 10) * 1000
        m_idleWheel->add(std::bind(&TcpServer::onIdleConnCheck, this, _1, WeakConnectionPtr_t(conn)), m_maxIdleTimeout * 900);

        return;
    }

    void TcpServer::onIdleConnCheck(const TimingWheelPtr_t& wheel, const WeakConnectionPtr_t& conn)
    {
        ConnectionPtr_t c = conn.lock();
        if(!c)
        {
            return;
        }

        struct timespec t;
        clock_gettime(CLOCK_MONOTONIC, &t);
        uint64_t now = t.tv_sec;

        if(now - c->lastActiveTime() > (uint64_t)m_maxIdleTimeout)
        {
            LOG_INFO("timeout, force shutdown");
            c->shutDown();
        }
        else
        {
            m_idleWheel->add(std::bind(&TcpServer::onIdleConnCheck, this, _1, WeakConnectionPtr_t(c)), m_maxIdleTimeout * 900);
        }
    }

    void TcpServer::onSignal(const SignalerPtr_t& signaler, int signum)
    {
        switch(signum)
        {
            case SIGINT:
            case SIGTERM:
                {
                    onStop();
                }
                break;
            default:
                LOG_ERROR("invalid signal %d", signum);
                break;
        }
    }
}
<commit_msg>change first idle check time, using random to scatter<commit_after>#include "tcpserver.h"

#include <algorithm>
#include <errno.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
#include <assert.h>
#include <time.h>
#include <stdlib.h>

#include "address.h"
#include "sockutil.h"
#include "log.h"
#include "acceptor.h"
#include "connection.h"
#include "ioloop.h"
#include "signaler.h"
#include "timer.h"
#include "process.h"
#include "timingwheel.h"

using namespace std;

namespace tnet
{
    const int defaultIdleTimeout = 120;

    void dummyRunCallback(IOLoop*)
    {
    }

    TcpServer::TcpServer()
        : m_loop(0)
    {
        m_process = std::make_shared<Process>();

        m_running = false;

        m_maxIdleTimeout = defaultIdleTimeout;

        m_runCallback = std::bind(&dummyRunCallback, _1);
    }

    TcpServer::~TcpServer()
    {
        if(m_loop)
        {
            delete m_loop;
        }
    }

    int TcpServer::listen(const Address& addr, const ConnEventCallback_t& callback)
    {
        LOG_INFO("listen %s:%d", addr.ipstr().c_str(), addr.port());
        NewConnCallback_t cb = std::bind(&TcpServer::onNewConnection, this, _1, _2, callback);
        AcceptorPtr_t acceptor = std::make_shared<Acceptor>(cb);
        if(acceptor->listen(addr) < 0)
        {
            return -1;
        }

        m_acceptors.push_back(acceptor);
        return 0;
    }

    void TcpServer::run()
    {
        if(m_running)
        {
            return;
        }

        m_loop = new IOLoop();

        m_running = true;

        m_loop->addCallback(std::bind(&TcpServer::onRun, this));

        m_loop->start();
    }

    void TcpServer::onRun()
    {
        LOG_INFO("tcp server on run");

        for_each(m_acceptors.begin(), m_acceptors.end(),
            std::bind(&Acceptor::start, _1, m_loop));

        vector<int> signums{SIGINT, SIGTERM};
        m_signaler = std::make_shared<Signaler>(signums, std::bind(&TcpServer::onSignal, this, _1, _2));

        m_signaler->start(m_loop);

        m_idleWheel = std::make_shared<TimingWheel>(1000, 3600);

        m_idleWheel->start(m_loop);

        m_runCallback(m_loop);
    }

    void TcpServer::start(size_t maxProcess)
    {
        if(maxProcess > 1)
        {
            m_process->wait(maxProcess, std::bind(&TcpServer::run, this));
        }
        else
        {
            run();
        }
    }

    void TcpServer::onStop()
    {
        LOG_INFO("tcp server on stop");
        if(!m_running)
        {
            return;
        }

        m_running = false;

        m_idleWheel->stop();

        m_signaler->stop();

        for_each_all(m_acceptors, std::bind(&Acceptor::stop, _1));

        m_loop->stop();
    }

    void TcpServer::stop()
    {
        LOG_INFO("stop server");
        m_process->stop();

        onStop();
    }

    void TcpServer::onNewConnection(IOLoop* loop, int fd, const ConnEventCallback_t& callback)
    {
        ConnectionPtr_t conn = std::make_shared<Connection>(loop, fd);

        conn->setEventCallback(callback);

        conn->onEstablished();

        int afterCheck = m_maxIdleTimeout / 2 + random() % m_maxIdleTimeout;
        m_idleWheel->add(std::bind(&TcpServer::onIdleConnCheck, this, _1, WeakConnectionPtr_t(conn)), afterCheck * 1000);

        return;
    }

    void TcpServer::onIdleConnCheck(const TimingWheelPtr_t& wheel, const WeakConnectionPtr_t& conn)
    {
        ConnectionPtr_t c = conn.lock();
        if(!c)
        {
            return;
        }

        struct timespec t;
        clock_gettime(CLOCK_MONOTONIC, &t);
        uint64_t now = t.tv_sec;

        if(now - c->lastActiveTime() > (uint64_t)m_maxIdleTimeout)
        {
            LOG_INFO("timeout, force shutdown");
            c->shutDown();
        }
        else
        {
            //check interval is (maxIdleTimeout * 9 / 10) * 1000
            m_idleWheel->add(std::bind(&TcpServer::onIdleConnCheck, this, _1, WeakConnectionPtr_t(c)), m_maxIdleTimeout * 900);
        }
    }

    void TcpServer::onSignal(const SignalerPtr_t& signaler, int signum)
    {
        switch(signum)
        {
            case SIGINT:
            case SIGTERM:
                {
                    onStop();
                }
                break;
            default:
                LOG_ERROR("invalid signal %d", signum);
                break;
        }
    }
}
<|endoftext|>


<commit_before>/*
Copyright libCellML Contributors

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

#include "xmldoc.h"

#include "libcellml/component.h"
#include "libcellml/generator.h"
#include "libcellml/model.h"
#include "libcellml/validator.h"

#include <vector>

namespace libcellml{

struct GeneratorVariable
{
};

typedef std::shared_ptr<GeneratorVariable> GeneratorVariablePtr;

struct Generator::GeneratorImpl
{
    bool mWithNames;

    std::vector<GeneratorVariablePtr> mStates;
    std::vector<GeneratorVariablePtr> mVariables;

    void processNode(const XmlNodePtr &node);
};

void Generator::GeneratorImpl::processNode(const XmlNodePtr &node)
{
(void) node;

//TODO
}

Generator::Generator()
    : mPimpl(new GeneratorImpl())
{
}

Generator::~Generator()
{
    delete mPimpl;
}

Generator::Generator(const Generator &rhs)
    : Logger(rhs)
    , mPimpl(new GeneratorImpl())
{
    mPimpl->mStates = rhs.mPimpl->mStates;
    mPimpl->mVariables = rhs.mPimpl->mVariables;
}

Generator::Generator(Generator &&rhs)
    : Logger(std::move(rhs))
    , mPimpl(rhs.mPimpl)
{
    rhs.mPimpl = nullptr;
}

Generator& Generator::operator=(Generator rhs)
{
    Logger::operator =(rhs);
    rhs.swap(*this);
    return *this;
}

void Generator::swap(Generator &rhs)
{
    std::swap(this->mPimpl, rhs.mPimpl);
}

void Generator::processModel(const ModelPtr &model)
{
    // Make sure that the model is valid before processing it
/*TODO: reenable the validation once it is known to work fine...
    libcellml::Validator validator;

    validator.validateModel(model);

    if (validator.errorCount() > 0) {
        // The model is not valid, so retrieve the validation errors and keep a
        // copy of them

        for (size_t i = 0; i < validator.errorCount(); ++i)
            addError(validator.getError(i));

        return;
    }
*/
    // Determine the order in which equations should be executed by processing
    // each of the components in the given model

    for (size_t i = 0; i < model->componentCount(); ++i) {
        // Retrieve the math string associated with the given component and
        // process it, one equation at a time
        // Note: at this stage, we know the model is valid, so no point in
        //       revalidating the math string...

        ComponentPtr component = model->getComponent(i);
        XmlDocPtr xmlDoc = std::make_shared<XmlDoc>();
        std::string math = component->getMath();

        xmlDoc->parse(math);

        XmlNodePtr mathNode = xmlDoc->getRootNode();

        for (XmlNodePtr node = mathNode->getFirstChild();
             node != nullptr; node = node->getNext()) {
            mPimpl->processNode(node);
        }
    }
}

void Generator::setWithNames(bool withNames)
{
    mPimpl->mWithNames = withNames;
}

size_t Generator::stateCount() const
{
    return mPimpl->mStates.size();
}

size_t Generator::rateCount() const
{
    return stateCount();
}

size_t Generator::variableCount() const
{
    return mPimpl->mVariables.size();
}

std::string Generator::initializeVariables() const
{
    return "";
}

std::string Generator::computeConstantEquations() const
{
    return "";
}

std::string Generator::computeRateEquations() const
{
    return "";
}

std::string Generator::computeAlgebraicEquations() const
{
    return "";
}

}
<commit_msg>Some minor cleaning up.<commit_after>/*
Copyright libCellML Contributors

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

#include "xmldoc.h"

#include <vector>

#include "libcellml/component.h"
#include "libcellml/generator.h"
#include "libcellml/model.h"
#include "libcellml/validator.h"

namespace libcellml{

struct GeneratorVariable
{
};

typedef std::shared_ptr<GeneratorVariable> GeneratorVariablePtr;

struct Generator::GeneratorImpl
{
    bool mWithNames;

    std::vector<GeneratorVariablePtr> mStates;
    std::vector<GeneratorVariablePtr> mVariables;

    void processNode(const XmlNodePtr &node);
};

void Generator::GeneratorImpl::processNode(const XmlNodePtr &node)
{
(void) node;

//TODO
}

Generator::Generator()
    : mPimpl(new GeneratorImpl())
{
}

Generator::~Generator()
{
    delete mPimpl;
}

Generator::Generator(const Generator &rhs)
    : Logger(rhs)
    , mPimpl(new GeneratorImpl())
{
    mPimpl->mStates = rhs.mPimpl->mStates;
    mPimpl->mVariables = rhs.mPimpl->mVariables;
}

Generator::Generator(Generator &&rhs)
    : Logger(std::move(rhs))
    , mPimpl(rhs.mPimpl)
{
    rhs.mPimpl = nullptr;
}

Generator& Generator::operator=(Generator rhs)
{
    Logger::operator =(rhs);
    rhs.swap(*this);
    return *this;
}

void Generator::swap(Generator &rhs)
{
    std::swap(this->mPimpl, rhs.mPimpl);
}

void Generator::processModel(const ModelPtr &model)
{
    // Make sure that the model is valid before processing it
/*TODO: reenable the validation once it is known to work fine...
    libcellml::Validator validator;

    validator.validateModel(model);

    if (validator.errorCount() > 0) {
        // The model is not valid, so retrieve the validation errors and keep a
        // copy of them

        for (size_t i = 0; i < validator.errorCount(); ++i)
            addError(validator.getError(i));

        return;
    }
*/
    // Determine the order in which equations should be executed by processing
    // each of the components in the given model

    for (size_t i = 0; i < model->componentCount(); ++i) {
        // Retrieve the math string associated with the given component and
        // process it, one equation at a time
        // Note: at this stage, we know the model is valid, so no point in
        //       revalidating the math string...

        ComponentPtr component = model->getComponent(i);
        XmlDocPtr xmlDoc = std::make_shared<XmlDoc>();
        std::string math = component->getMath();

        xmlDoc->parse(math);

        XmlNodePtr mathNode = xmlDoc->getRootNode();

        for (XmlNodePtr node = mathNode->getFirstChild();
             node != nullptr; node = node->getNext()) {
            mPimpl->processNode(node);
        }
    }
}

void Generator::setWithNames(bool withNames)
{
    mPimpl->mWithNames = withNames;
}

size_t Generator::stateCount() const
{
    return mPimpl->mStates.size();
}

size_t Generator::rateCount() const
{
    return stateCount();
}

size_t Generator::variableCount() const
{
    return mPimpl->mVariables.size();
}

std::string Generator::initializeVariables() const
{
    return "";
}

std::string Generator::computeConstantEquations() const
{
    return "";
}

std::string Generator::computeRateEquations() const
{
    return "";
}

std::string Generator::computeAlgebraicEquations() const
{
    return "";
}

}
<|endoftext|>


<commit_before>#include <asiocurl/easy.hpp>

#include <asiocurl/exception.hpp>
#include <asiocurl/io_service.hpp>
#include <asiocurl/optional.hpp>
#include <boost/asio.hpp>
#include <curl/curl.h>
#include <thread>
#include <catch.hpp>

namespace {

	class fixture {

		protected:

			boost::asio::io_service ios;
			asiocurl::io_service curl;

		private:

			asiocurl::optional<boost::asio::io_service::work> work_;
			std::thread t_;

		public:

			fixture () : curl(ios), work_(asiocurl::in_place,ios) {

				t_=std::thread([&] () noexcept {	ios.run();	});

			}

			~fixture () noexcept {

				work_=asiocurl::nullopt;
				t_.join();

			}

	};

}

SCENARIO_METHOD(fixture,"asiocurl::easy_with_error_buffer captures detailed error messages from libcurl","[asiocurl][easy][easy_with_error_buffer]") {

	GIVEN("An asiocurl::easy_with_error_buffer object which represents a transfer which will fail") {

		asiocurl::easy_with_error_buffer easy;
		const char * str="http://foo.corge";	//	NXDOMAIN
		auto result=curl_easy_setopt(easy,CURLOPT_URL,str);
		if (result!=CURLE_OK) throw asiocurl::easy_error(result);

		WHEN("The transfer is started") {

			auto f=curl.add(easy);

			THEN("It completes") {

				auto s=f.get();

				AND_THEN("The transfer failed") {

					CHECK(s.data.result==CURLE_COULDNT_RESOLVE_HOST);

					AND_THEN("The asio::easy_with_error_buffer contains a detailed error message") {

						CHECK(!easy.empty());

					}

				}

			}

		}

	}

}
<commit_msg>asiocurl::easy_with_error_buffer Tests - CURLOPT_VERBOSE<commit_after>#include <asiocurl/easy.hpp>

#include <asiocurl/exception.hpp>
#include <asiocurl/io_service.hpp>
#include <asiocurl/optional.hpp>
#include <boost/asio.hpp>
#include <curl/curl.h>
#include <thread>
#include <catch.hpp>

namespace {

	class fixture {

		protected:

			boost::asio::io_service ios;
			asiocurl::io_service curl;

		private:

			asiocurl::optional<boost::asio::io_service::work> work_;
			std::thread t_;

		public:

			fixture () : curl(ios), work_(asiocurl::in_place,ios) {

				t_=std::thread([&] () noexcept {	ios.run();	});

			}

			~fixture () noexcept {

				work_=asiocurl::nullopt;
				t_.join();

			}

	};

}

SCENARIO_METHOD(fixture,"asiocurl::easy_with_error_buffer captures detailed error messages from libcurl","[asiocurl][easy][easy_with_error_buffer]") {

	GIVEN("An asiocurl::easy_with_error_buffer object which represents a transfer which will fail") {

		asiocurl::easy_with_error_buffer easy;
		const char * str="http://foo.corge";	//	NXDOMAIN
		auto result=curl_easy_setopt(easy,CURLOPT_URL,str);
		if (result!=CURLE_OK) throw asiocurl::easy_error(result);
		long v=1;
		if ((result=curl_easy_setopt(easy,CURLOPT_VERBOSE,v))!=CURLE_OK) throw asiocurl::easy_error(result);

		WHEN("The transfer is started") {

			auto f=curl.add(easy);

			THEN("It completes") {

				auto s=f.get();

				AND_THEN("The transfer failed") {

					CHECK(s.data.result==CURLE_COULDNT_RESOLVE_HOST);

					AND_THEN("The asio::easy_with_error_buffer contains a detailed error message") {

						CHECK(!easy.empty());

					}

				}

			}

		}

	}

}
<|endoftext|>


<commit_before>#ifndef TOPAZ_GL2_OUTPUT_HPP
#define TOPAZ_GL2_OUTPUT_HPP
#include "core/window.hpp"
#include "gl/api/output.hpp"
#include "gl/component.hpp"

namespace tz::gl
{
	struct ImageOutputInfo
	{
		tz::BasicList<IComponent*> colours;
		IComponent* depth = nullptr;
	};

	class ImageOutput final : public IOutput
	{
	public:
		ImageOutput(ImageOutputInfo info);
		constexpr virtual OutputTarget get_target() const override
		{
			return OutputTarget::OffscreenImage;
		}

		virtual std::unique_ptr<IOutput> unique_clone() const override
		{
			return std::make_unique<ImageOutput>(*this);
		}

		std::size_t colour_attachment_count() const;
		bool has_depth_attachment() const;

		const ImageComponent& get_colour_attachment(std::size_t colour_attachment_idx) const;
		ImageComponent& get_colour_attachment(std::size_t colour_attachment_idx);

		const ImageComponent& get_depth_attachment() const;
		ImageComponent& get_depth_attachment();
	private:
		std::vector<ImageComponent*> colour_attachments;
		ImageComponent* depth_attachment;
	};

	class WindowOutput final : public IOutput
	{
	public:
		WindowOutput(const tz::Window& window);
		constexpr virtual OutputTarget get_target() const override
		{
			return OutputTarget::Window;
		}

		virtual std::unique_ptr<IOutput> unique_clone() const override
		{
			return std::make_unique<WindowOutput>(*this);
		}

		const tz::Window& get_window() const;
	private:
		const tz::Window* wnd;
	};
}

#endif // TOPAZ_GL2_OUTPUT_HPP
<commit_msg>* Fix missing basic_list includfe<commit_after>#ifndef TOPAZ_GL2_OUTPUT_HPP
#define TOPAZ_GL2_OUTPUT_HPP
#include "core/window.hpp"
#include "core/containers/basic_list.hpp"
#include "gl/api/output.hpp"
#include "gl/component.hpp"

namespace tz::gl
{
	struct ImageOutputInfo
	{
		tz::BasicList<IComponent*> colours;
		IComponent* depth = nullptr;
	};

	class ImageOutput final : public IOutput
	{
	public:
		ImageOutput(ImageOutputInfo info);
		constexpr virtual OutputTarget get_target() const override
		{
			return OutputTarget::OffscreenImage;
		}

		virtual std::unique_ptr<IOutput> unique_clone() const override
		{
			return std::make_unique<ImageOutput>(*this);
		}

		std::size_t colour_attachment_count() const;
		bool has_depth_attachment() const;

		const ImageComponent& get_colour_attachment(std::size_t colour_attachment_idx) const;
		ImageComponent& get_colour_attachment(std::size_t colour_attachment_idx);

		const ImageComponent& get_depth_attachment() const;
		ImageComponent& get_depth_attachment();
	private:
		std::vector<ImageComponent*> colour_attachments;
		ImageComponent* depth_attachment;
	};

	class WindowOutput final : public IOutput
	{
	public:
		WindowOutput(const tz::Window& window);
		constexpr virtual OutputTarget get_target() const override
		{
			return OutputTarget::Window;
		}

		virtual std::unique_ptr<IOutput> unique_clone() const override
		{
			return std::make_unique<WindowOutput>(*this);
		}

		const tz::Window& get_window() const;
	private:
		const tz::Window* wnd;
	};
}

#endif // TOPAZ_GL2_OUTPUT_HPP
<|endoftext|>