<commit_before>/**
 * Appcelerator Titanium Mobile
 * Copyright (c) 2009-2012 by Appcelerator, Inc. All Rights Reserved.
 * Licensed under the terms of the Apache Public License
 * Please see the LICENSE included with this distribution for details.
 */

#include "NativeScrollViewObject.h"
#include "TiEvent.h"
#include "TiEventContainerFactory.h"
#include "TiUIBase.h"
#include <bb/cascades/ScrollView>
#include <bb/cascades/ScrollViewProperties>
#include <bb/cascades/ScrollMode>
#include <bb/cascades/Container>
#include <bb/cascades/Button>
#include <bb/cascades/AbsoluteLayout>
#include <bb/cascades/LayoutUpdateHandler>

NativeScrollViewContentObject::NativeScrollViewContentObject(TiObject* tiObject, NativeScrollViewObject* scrollView)
	: NativeControlObject(tiObject, N_TYPE_VIEW)
{
 	setContainer(bb::cascades::Container::create());
 	scrollView_ = scrollView;
}

void NativeScrollViewContentObject::updateLayout(QRectF rect)
{
    NativeControlObject::updateLayout(rect);
    scrollView_->setContentWidthAndHeight(rect.width(), rect.height());
}
NativeScrollViewObject::NativeScrollViewObject(TiObject* tiObject)
    : NativeControlObject(tiObject, N_TYPE_SCROLL_VIEW)
{
    scrollView_ = NULL;
}

NativeScrollViewObject::~NativeScrollViewObject()
{
}

NativeScrollViewObject* NativeScrollViewObject::createScrollView(TiObject* tiObject)
{
   return new NativeScrollViewObject(tiObject);
}

NATIVE_TYPE NativeScrollViewObject::getObjectType() const
{
    return N_TYPE_SCROLL_VIEW;
}

int NativeScrollViewObject::setLayout(TiObject *obj)
{
	int err = contentViewProxy_->setLayout(obj);
	return err;
}
void NativeScrollViewObject::setContentWidthAndHeight(float width, float height)
{
    contentSize_.setHeight(height);
    contentSize_.setWidth(width);

    if(contentSize_.width() > scrollViewSize_.width() && contentSize_.height() <= scrollViewSize_.height())
    {
    	scrollViewProperties_->setScrollMode(bb::cascades::ScrollMode::Horizontal);
    } else if(contentSize_.height() > scrollViewSize_.height() && contentSize_.width() <= scrollViewSize_.width())
    {
       	scrollViewProperties_->setScrollMode(bb::cascades::ScrollMode::Vertical);
   	} else {
       	scrollViewProperties_->setScrollMode(bb::cascades::ScrollMode::Both);
   	}
}

int NativeScrollViewObject::initialize()
{

	contentViewProxy_ = new NativeScrollViewContentObject(tiObject_, this);
	contentView_ = (bb::cascades::Container*)contentViewProxy_->getNativeHandle();

	scrollView_ = bb::cascades::ScrollView::create();
	nativeContentView_ = bb::cascades::Container::create();

	setControl(scrollView_);

	addChildImpl(contentViewProxy_);

	nativeContentView_->add(contentView_);
    scrollView_->setContent(nativeContentView_);

    scrollViewProperties_ = scrollView_->scrollViewProperties();
	scrollViewProperties_->setScrollMode(bb::cascades::ScrollMode::Both);
	scrollViewProperties_->setOverScrollEffectMode(bb::cascades::OverScrollEffectMode::None);

    ScrollViewEventHandler *eventHandler_ = new ScrollViewEventHandler(this);

    bb::cascades::LayoutUpdateHandler::create(nativeContentView_).onLayoutFrameChanged(eventHandler_, SLOT(onContainerLayoutChange(QRectF)));

    contentSize_ = QSize(0,0);
    scrollViewSize_ = QSize(0,0);
    return NATIVE_ERROR_OK;
}

int NativeScrollViewObject::setContentWidth(TiObject* obj)
{
    return contentViewProxy_->setWidth(obj);
}

int NativeScrollViewObject::setContentHeight(TiObject* obj)
{
    return contentViewProxy_->setHeight(obj);
}

void NativeScrollViewObject::onContentViewSizeChange(QRectF rect)
{
	//contentView_->setBackground(bb::cascades::Color::DarkRed);
}

void NativeScrollViewObject::updateLayout(QRectF rect)
{
    NativeControlObject::updateLayout(rect);
    float h = rect.height();
    float w = rect.width();

    scrollView_->setPreferredHeight(h);
    scrollView_->setPreferredWidth(w);
    scrollViewSize_.setHeight(h);
    scrollViewSize_.setWidth(w);
}

int NativeScrollViewObject::setBackgroundColor(TiObject* obj)
{
	NativeControlObject::setBackgroundColor(obj);
    return contentViewProxy_->setBackgroundColor(obj);
}

int NativeScrollViewObject::addChildNativeObject(NativeObject* obj)
{
	contentViewProxy_->addChildNativeObject(obj);

	return NATIVE_ERROR_OK;
}

void NativeScrollViewObject::setupEvents(TiEventContainerFactory* containerFactory)
{
    NativeControlObject::setupEvents(containerFactory);
    /*
    TiEventContainer* eventClick = containerFactory->createEventContainer();
    eventClick->setDataProperty("type", tetCLICK);
    events_.insert(tetCLICK, EventPairSmartPtr(eventClick, new ButtonEventHandler(eventClick)));
    QObject::connect(button_, SIGNAL(clicked()), events_[tetCLICK]->handler(), SLOT(clicked(void)));
     */
}
<commit_msg>Enable bounciness by default<commit_after>/**
 * Appcelerator Titanium Mobile
 * Copyright (c) 2009-2012 by Appcelerator, Inc. All Rights Reserved.
 * Licensed under the terms of the Apache Public License
 * Please see the LICENSE included with this distribution for details.
 */

#include "NativeScrollViewObject.h"
#include "TiEvent.h"
#include "TiEventContainerFactory.h"
#include "TiUIBase.h"
#include <bb/cascades/ScrollView>
#include <bb/cascades/ScrollViewProperties>
#include <bb/cascades/ScrollMode>
#include <bb/cascades/Container>
#include <bb/cascades/Button>
#include <bb/cascades/AbsoluteLayout>
#include <bb/cascades/LayoutUpdateHandler>

NativeScrollViewContentObject::NativeScrollViewContentObject(TiObject* tiObject, NativeScrollViewObject* scrollView)
	: NativeControlObject(tiObject, N_TYPE_VIEW)
{
 	setContainer(bb::cascades::Container::create());
 	scrollView_ = scrollView;
}

void NativeScrollViewContentObject::updateLayout(QRectF rect)
{
    NativeControlObject::updateLayout(rect);
    scrollView_->setContentWidthAndHeight(rect.width(), rect.height());
}
NativeScrollViewObject::NativeScrollViewObject(TiObject* tiObject)
    : NativeControlObject(tiObject, N_TYPE_SCROLL_VIEW)
{
    scrollView_ = NULL;
}

NativeScrollViewObject::~NativeScrollViewObject()
{
}

NativeScrollViewObject* NativeScrollViewObject::createScrollView(TiObject* tiObject)
{
   return new NativeScrollViewObject(tiObject);
}

NATIVE_TYPE NativeScrollViewObject::getObjectType() const
{
    return N_TYPE_SCROLL_VIEW;
}

int NativeScrollViewObject::setLayout(TiObject *obj)
{
	int err = contentViewProxy_->setLayout(obj);
	return err;
}
void NativeScrollViewObject::setContentWidthAndHeight(float width, float height)
{
    contentSize_.setHeight(height);
    contentSize_.setWidth(width);

    if(contentSize_.width() > scrollViewSize_.width() && contentSize_.height() <= scrollViewSize_.height())
    {
    	scrollViewProperties_->setScrollMode(bb::cascades::ScrollMode::Horizontal);
    } else if(contentSize_.height() > scrollViewSize_.height() && contentSize_.width() <= scrollViewSize_.width())
    {
       	scrollViewProperties_->setScrollMode(bb::cascades::ScrollMode::Vertical);
   	} else {
       	scrollViewProperties_->setScrollMode(bb::cascades::ScrollMode::Both);
   	}
}

int NativeScrollViewObject::initialize()
{

	contentViewProxy_ = new NativeScrollViewContentObject(tiObject_, this);
	contentView_ = (bb::cascades::Container*)contentViewProxy_->getNativeHandle();

	scrollView_ = bb::cascades::ScrollView::create();
	nativeContentView_ = bb::cascades::Container::create();

	setControl(scrollView_);

	addChildImpl(contentViewProxy_);

	nativeContentView_->add(contentView_);
    scrollView_->setContent(nativeContentView_);

    scrollViewProperties_ = scrollView_->scrollViewProperties();

    ScrollViewEventHandler *eventHandler_ = new ScrollViewEventHandler(this);

    bb::cascades::LayoutUpdateHandler::create(nativeContentView_).onLayoutFrameChanged(eventHandler_, SLOT(onContainerLayoutChange(QRectF)));

    contentSize_ = QSize(0,0);
    scrollViewSize_ = QSize(0,0);
    return NATIVE_ERROR_OK;
}
/*
	Not implemented yet
int NariveScrollViewObject::setDisableBounce(TiObject* obj)
{
    bool bounces;
    getBoolean(obj, &bounces);
    if(bounces) {
    	scrollViewProperties_->setOverScrollEffectMode(bb::cascades::OverScrollEffectMode::None);
    }
    return NATIVE_ERROR_OK;
}
*/

int NativeScrollViewObject::setContentWidth(TiObject* obj)
{
    return contentViewProxy_->setWidth(obj);
}

int NativeScrollViewObject::setContentHeight(TiObject* obj)
{
    return contentViewProxy_->setHeight(obj);
}

void NativeScrollViewObject::onContentViewSizeChange(QRectF rect)
{
	//contentView_->setBackground(bb::cascades::Color::DarkRed);
}

void NativeScrollViewObject::updateLayout(QRectF rect)
{
    NativeControlObject::updateLayout(rect);
    float h = rect.height();
    float w = rect.width();

    scrollView_->setPreferredHeight(h);
    scrollView_->setPreferredWidth(w);
    scrollViewSize_.setHeight(h);
    scrollViewSize_.setWidth(w);
}

int NativeScrollViewObject::setBackgroundColor(TiObject* obj)
{
	NativeControlObject::setBackgroundColor(obj);
    return contentViewProxy_->setBackgroundColor(obj);
}

int NativeScrollViewObject::addChildNativeObject(NativeObject* obj)
{
	contentViewProxy_->addChildNativeObject(obj);

	return NATIVE_ERROR_OK;
}

void NativeScrollViewObject::setupEvents(TiEventContainerFactory* containerFactory)
{
    NativeControlObject::setupEvents(containerFactory);
    /*
    TiEventContainer* eventClick = containerFactory->createEventContainer();
    eventClick->setDataProperty("type", tetCLICK);
    events_.insert(tetCLICK, EventPairSmartPtr(eventClick, new ButtonEventHandler(eventClick)));
    QObject::connect(button_, SIGNAL(clicked()), events_[tetCLICK]->handler(), SLOT(clicked(void)));
     */
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2019 The Android Open Source Project
 *
 * 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 "src/trace_processor/ftrace_utils.h"

#include <algorithm>

#include "perfetto/base/logging.h"

namespace perfetto {
namespace trace_processor {
namespace ftrace_utils {

TaskState::TaskState(const char* state_str) {
  bool invalid_char = false;
  bool is_runnable = false;
  for (size_t i = 0; state_str[i] != '\0'; i++) {
    char c = state_str[i];
    if (is_kernel_preempt()) {
      // No other character should be encountered after '+'.
      invalid_char = true;
      break;
    } else if (c == '+') {
      state_ |= kMaxState;
      continue;
    }

    if (is_runnable) {
      // We should not encounter any character apart from '+' if runnable.
      invalid_char = true;
      break;
    }

    if (c == 'R') {
      if (state_ != 0) {
        // We should not encounter R if we already have set other atoms.
        invalid_char = true;
        break;
      } else {
        is_runnable = true;
        continue;
      }
    }

    if (c == 'S')
      state_ |= Atom::kInterruptibleSleep;
    else if (c == 'D')
      state_ |= Atom::kUninterruptibleSleep;
    else if (c == 'T')
      state_ |= Atom::kStopped;
    else if (c == 't')
      state_ |= Atom::kTraced;
    else if (c == 'X')
      state_ |= Atom::kExitDead;
    else if (c == 'Z')
      state_ |= Atom::kExitZombie;
    else if (c == 'x')
      state_ |= Atom::kTaskDead;
    else if (c == 'K')
      state_ |= Atom::kWakeKill;
    else if (c == 'W')
      state_ |= Atom::kWaking;
    else if (c == 'P')
      state_ |= Atom::kParked;
    else if (c == 'N')
      state_ |= Atom::kNoLoad;
    else {
      invalid_char = true;
      break;
    }
  }

  bool no_state = !is_runnable && state_ == 0;
  if (invalid_char || no_state) {
    state_ = 0;
  } else {
    state_ |= kValid;
  }
}

TaskState::TaskStateStr TaskState::ToString() const {
  PERFETTO_CHECK(is_valid());

  char buffer[32];
  size_t pos = 0;

  // This mapping is given by the file
  // https://android.googlesource.com/kernel/msm.git/+/android-msm-wahoo-4.4-pie-qpr1/include/trace/events/sched.h#155
  if (is_runnable()) {
    buffer[pos++] = 'R';
  } else {
    if (state_ & Atom::kInterruptibleSleep)
      buffer[pos++] = 'S';
    if (state_ & Atom::kUninterruptibleSleep)
      buffer[pos++] = 'D';  // D for (D)isk sleep
    if (state_ & Atom::kStopped)
      buffer[pos++] = 'T';
    if (state_ & Atom::kTraced)
      buffer[pos++] = 't';
    if (state_ & Atom::kExitDead)
      buffer[pos++] = 'X';
    if (state_ & Atom::kExitZombie)
      buffer[pos++] = 'Z';
    if (state_ & Atom::kTaskDead)
      buffer[pos++] = 'x';
    if (state_ & Atom::kWakeKill)
      buffer[pos++] = 'K';
    if (state_ & Atom::kWaking)
      buffer[pos++] = 'W';
    if (state_ & Atom::kParked)
      buffer[pos++] = 'P';
    if (state_ & Atom::kNoLoad)
      buffer[pos++] = 'N';
  }

  if (is_kernel_preempt())
    buffer[pos++] = '+';

  // It is very unlikely that we have used more than the size of the string
  // array. Double check that belief on debug builds.
  PERFETTO_DCHECK(pos < std::tuple_size<TaskStateStr>() - 1);

  TaskStateStr output{};
  memcpy(output.data(), buffer, std::min(pos, output.size() - 1));
  return output;
}

}  // namespace ftrace_utils
}  // namespace trace_processor
}  // namespace perfetto
<commit_msg>trace_processor: fix dcheck failure<commit_after>/*
 * Copyright (C) 2019 The Android Open Source Project
 *
 * 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 "src/trace_processor/ftrace_utils.h"

#include <algorithm>

#include "perfetto/base/logging.h"

namespace perfetto {
namespace trace_processor {
namespace ftrace_utils {

TaskState::TaskState(const char* state_str) {
  bool invalid_char = false;
  bool is_runnable = false;
  for (size_t i = 0; state_str[i] != '\0'; i++) {
    char c = state_str[i];
    if (is_kernel_preempt()) {
      // No other character should be encountered after '+'.
      invalid_char = true;
      break;
    } else if (c == '+') {
      state_ |= kMaxState;
      continue;
    }

    if (is_runnable) {
      // We should not encounter any character apart from '+' if runnable.
      invalid_char = true;
      break;
    }

    if (c == 'R') {
      if (state_ != 0) {
        // We should not encounter R if we already have set other atoms.
        invalid_char = true;
        break;
      } else {
        is_runnable = true;
        continue;
      }
    }

    if (c == 'S')
      state_ |= Atom::kInterruptibleSleep;
    else if (c == 'D')
      state_ |= Atom::kUninterruptibleSleep;
    else if (c == 'T')
      state_ |= Atom::kStopped;
    else if (c == 't')
      state_ |= Atom::kTraced;
    else if (c == 'X')
      state_ |= Atom::kExitDead;
    else if (c == 'Z')
      state_ |= Atom::kExitZombie;
    else if (c == 'x')
      state_ |= Atom::kTaskDead;
    else if (c == 'K')
      state_ |= Atom::kWakeKill;
    else if (c == 'W')
      state_ |= Atom::kWaking;
    else if (c == 'P')
      state_ |= Atom::kParked;
    else if (c == 'N')
      state_ |= Atom::kNoLoad;
    else {
      invalid_char = true;
      break;
    }
  }

  bool no_state = !is_runnable && state_ == 0;
  if (invalid_char || no_state) {
    state_ = 0;
  } else {
    state_ |= kValid;
  }
}

TaskState::TaskStateStr TaskState::ToString() const {
  PERFETTO_CHECK(is_valid());

  char buffer[32];
  size_t pos = 0;

  // This mapping is given by the file
  // https://android.googlesource.com/kernel/msm.git/+/android-msm-wahoo-4.4-pie-qpr1/include/trace/events/sched.h#155
  if (is_runnable()) {
    buffer[pos++] = 'R';
  } else {
    if (state_ & Atom::kInterruptibleSleep)
      buffer[pos++] = 'S';
    if (state_ & Atom::kUninterruptibleSleep)
      buffer[pos++] = 'D';  // D for (D)isk sleep
    if (state_ & Atom::kStopped)
      buffer[pos++] = 'T';
    if (state_ & Atom::kTraced)
      buffer[pos++] = 't';
    if (state_ & Atom::kExitDead)
      buffer[pos++] = 'X';
    if (state_ & Atom::kExitZombie)
      buffer[pos++] = 'Z';
    if (state_ & Atom::kTaskDead)
      buffer[pos++] = 'x';
    if (state_ & Atom::kWakeKill)
      buffer[pos++] = 'K';
    if (state_ & Atom::kWaking)
      buffer[pos++] = 'W';
    if (state_ & Atom::kParked)
      buffer[pos++] = 'P';
    if (state_ & Atom::kNoLoad)
      buffer[pos++] = 'N';
  }

  if (is_kernel_preempt())
    buffer[pos++] = '+';

  TaskStateStr output{};
  memcpy(output.data(), buffer, std::min(pos, output.size() - 1));
  return output;
}

}  // namespace ftrace_utils
}  // namespace trace_processor
}  // namespace perfetto
<|endoftext|>


<commit_before><commit_msg>Avoid some code duplication<commit_after><|endoftext|>


<commit_before>#include "mcrt/camera.hh"

#include <glm/gtx/string_cast.hpp>

mcrt::Camera::Camera(const glm::dvec3& viewPlanePosition, const glm::dvec3& lookAtPosition,
                     const glm::dvec3& upwardVector, double aspectRatio, double fieldOfView) {
    // Initial, temporary values.
    viewPlane[0] = { -1, +1, 0 };
    viewPlane[1] = { +1, +1, 0 };
    viewPlane[2] = { +1, -1, 0 };
    viewPlane[3] = { -1, -1, 0 };
    eyePoint = { 0.0, 0.0, 1.0 };

    // Setup our camera setting.
    setAspectRatio(aspectRatio);
    setFieldOfView(fieldOfView);
    moveTo(viewPlanePosition);

    // Does the order matter here or not?
    lookAt(lookAtPosition, upwardVector);
}

void   mcrt::Camera::setAspectRatio(double aspectRatio) {
    double viewPlaneAspectRatio { getAspectRatio() };
    glm::dvec3 viewPlaneCenter { getViewPlanePosition() };
    glm::dvec3 xViewPlaneAxis { viewPlane[1] - viewPlane[0] },
               yViewPlaneAxis { viewPlane[3] - viewPlane[0] };
    double aspectRatioDifference { aspectRatio / viewPlaneAspectRatio };

    xViewPlaneAxis *= aspectRatioDifference;
    yViewPlaneAxis *= 1.0 / aspectRatioDifference;
    glm::dvec3 xHalfAxis { xViewPlaneAxis / 2.0 },
               yHalfAxis { yViewPlaneAxis / 2.0 };

    viewPlane[0] = viewPlaneCenter - xHalfAxis + yHalfAxis;
    viewPlane[1] = viewPlaneCenter + xHalfAxis + yHalfAxis;
    viewPlane[2] = viewPlaneCenter + xHalfAxis - yHalfAxis;
    viewPlane[3] = viewPlaneCenter - xHalfAxis - yHalfAxis;
}

double mcrt::Camera::getAspectRatio() const {
    // Just fetch the length of each axis and find the ratio of these.
    double viewPlaneWidth  { glm::distance(viewPlane[1], viewPlane[0]) },
           viewPlaneHeight { glm::distance(viewPlane[3], viewPlane[0]) };
    return viewPlaneWidth / viewPlaneHeight;
}

double mcrt::Camera::getFieldOfView() const {
    double eyeToPlaneDistance { glm::distance(eyePoint, getViewPlanePosition()) };
    double viewPlaneWidth     { glm::distance(viewPlane[1], viewPlane[0]) };
    return 2*glm::atan((viewPlaneWidth/2)/eyeToPlaneDistance);
}

void   mcrt::Camera::setFieldOfView(double fieldOfView) {
}

glm::dvec3 mcrt::Camera::getPixelCenter(const Image& image, size_t i, size_t j) const {
    // Fetch the plane of the pixel, and just get the pixel's central position.
    SamplingPlane pixelSamplingPlane  { getPixelSamplingPlane(image,  i,  j) };
    // That is basically just half the diagonal from: top-left to bottom-right.
    return (pixelSamplingPlane.corners[2] - pixelSamplingPlane.corners[0])/2.0;
}

mcrt::Camera::SamplingPlane mcrt::Camera::getPixelSamplingPlane(const Image& image, size_t i, size_t j) const {
    // Fetch the axes built from the top-left to top-right (x)
    // and the top-left to bottom-left (y-axis). This is to do
    // mirroring of the coordinate system found in the images.
    glm::dvec3 xViewPlaneAxis { viewPlane[1] - viewPlane[0] },
               yViewPlaneAxis { viewPlane[3] - viewPlane[0] };

    // We find the lengths of the view plane's basis axes.
    double viewPlaneWidth  { glm::length(xViewPlaneAxis) },
           viewPlaneHeight { glm::length(yViewPlaneAxis) };

    xViewPlaneAxis = glm::normalize(xViewPlaneAxis);
    yViewPlaneAxis = glm::normalize(yViewPlaneAxis);

    // Finally, we compute the scaling ratio needed from pixel coordinates to viewplane.
    double widthScaleRatio  { viewPlaneWidth  / static_cast<double>(image.getWidth()) },
           heightScaleRatio { viewPlaneHeight / static_cast<double>(image.getHeight()) };

    SamplingPlane pixelSamplingPlane;
    pixelSamplingPlane.corners[0] = viewPlane[0];
    // Top-left pixel corner is scaled (i,j) units away from view plane tl.
    pixelSamplingPlane.corners[0] += i * widthScaleRatio  * xViewPlaneAxis;
    pixelSamplingPlane.corners[0] += j * heightScaleRatio * yViewPlaneAxis;

    // The rest are simply one pixel length away (or through the diagonal) from top-left pixel corners.
    pixelSamplingPlane.corners[1] =  pixelSamplingPlane.corners[0] + widthScaleRatio  * xViewPlaneAxis;
    pixelSamplingPlane.corners[2] =  pixelSamplingPlane.corners[0] + widthScaleRatio  * xViewPlaneAxis;
    pixelSamplingPlane.corners[2] += heightScaleRatio * yViewPlaneAxis; // top-left ----> bottom-right.
    pixelSamplingPlane.corners[3] =  pixelSamplingPlane.corners[0] + heightScaleRatio * yViewPlaneAxis;
    return pixelSamplingPlane;
}

void mcrt::Camera::moveTo(const glm::dvec3& viewPlanePosition) {
    glm::dvec3 planeCenter  { getViewPlanePosition() };
    glm::dvec3 eyeToCenter { planeCenter - eyePoint };
    glm::dvec3 tl { viewPlane[0] - planeCenter },
               tr { viewPlane[1] - planeCenter },
               br { viewPlane[2] - planeCenter },
               bl { viewPlane[3] - planeCenter };

    // Calculate new positions based on center.
    eyePoint = viewPlanePosition - eyeToCenter;
    viewPlane[0] = viewPlanePosition + tl;
    viewPlane[1] = viewPlanePosition + tr;
    viewPlane[2] = viewPlanePosition + br;
    viewPlane[3] = viewPlanePosition + bl;
}

glm::dvec3 mcrt::Camera::getEyePosition() const {
    // Now this one is quite easy!
    return eyePoint;
}

glm::dvec3 mcrt::Camera::getViewPlanePosition() const {
    glm::dvec3 viewDiagonal { viewPlane[2] - viewPlane[0] };
    // Return the center of the view plane accross diagonal.
    return viewPlane[0] + 0.5*viewDiagonal;
}

void mcrt::Camera::lookAt(const glm::dvec3& lookAtPosition, const glm::dvec3& upwardVector) {
    double eyeToPlaneDistance = glm::distance(eyePoint, getViewPlanePosition());
    glm::dvec3 w = glm::normalize(lookAtPosition - eyePoint);
    glm::dvec3 u = glm::cross(w, upwardVector);
    glm::dvec3 v = glm::cross(u, w);
    glm::dvec3 viewPlaneCenter = eyePoint + w*eyeToPlaneDistance;

    viewPlane[0] = viewPlaneCenter - u + v;
    viewPlane[1] = viewPlaneCenter + u + v;
    viewPlane[2] = viewPlaneCenter + u - v;
    viewPlane[3] = viewPlaneCenter + u + v;
}

std::ostream& mcrt::operator<<(std::ostream& output, const Camera& camera) {
    return output << "eye:          " << glm::to_string(camera.eyePoint) << std::endl
                  << "top-left:     " << glm::to_string(camera.viewPlane[0]) << std::endl
                  << "top-right:    " << glm::to_string(camera.viewPlane[1]) << std::endl
                  << "bottom-right: " << glm::to_string(camera.viewPlane[2]) << std::endl
                  << "bottom-left:  " << glm::to_string(camera.viewPlane[3]) << std::endl
                  << "aspectRatio:  " << camera.getAspectRatio() << std::endl
                  << "fieldOfView:  " << camera.getFieldOfView() <<  std::endl;
}
<commit_msg>Fixed problem with aspect ratio.<commit_after>#include "mcrt/camera.hh"

#include <glm/gtx/string_cast.hpp>

mcrt::Camera::Camera(const glm::dvec3& viewPlanePosition, const glm::dvec3& lookAtPosition,
                     const glm::dvec3& upwardVector, double aspectRatio, double fieldOfView) {
    // Initial, temporary values.
    viewPlane[0] = { -1, +1, 0 };
    viewPlane[1] = { +1, +1, 0 };
    viewPlane[2] = { +1, -1, 0 };
    viewPlane[3] = { -1, -1, 0 };
    eyePoint = { 0.0, 0.0, 1.0 };

    // Setup our camera setting.
    setAspectRatio(aspectRatio);
    setFieldOfView(fieldOfView);
    moveTo(viewPlanePosition);

    // Does the order matter here or not?
    // lookAt(lookAtPosition, upwardVector);
}

void   mcrt::Camera::setAspectRatio(double aspectRatio) {
    double viewPlaneAspectRatio { getAspectRatio() };
    glm::dvec3 viewPlaneCenter { getViewPlanePosition() };
    glm::dvec3 xViewPlaneAxis { viewPlane[1] - viewPlane[0] },
               yViewPlaneAxis { viewPlane[3] - viewPlane[0] };
    double aspectRatioDifference { aspectRatio / viewPlaneAspectRatio };
    aspectRatioDifference = std::sqrt(aspectRatioDifference);

    xViewPlaneAxis *= aspectRatioDifference;
    yViewPlaneAxis *= 1.0 / aspectRatioDifference;
    glm::dvec3 xHalfAxis { xViewPlaneAxis / 2.0 },
               yHalfAxis { yViewPlaneAxis / 2.0 };

    viewPlane[0] = viewPlaneCenter - xHalfAxis - yHalfAxis;
    viewPlane[1] = viewPlaneCenter + xHalfAxis - yHalfAxis;
    viewPlane[2] = viewPlaneCenter + xHalfAxis + yHalfAxis;
    viewPlane[3] = viewPlaneCenter - xHalfAxis + yHalfAxis;
}

double mcrt::Camera::getAspectRatio() const {
    // Just fetch the length of each axis and find the ratio of these.
    double viewPlaneWidth  { glm::distance(viewPlane[1], viewPlane[0]) },
           viewPlaneHeight { glm::distance(viewPlane[3], viewPlane[0]) };
    return viewPlaneWidth / viewPlaneHeight;
}

double mcrt::Camera::getFieldOfView() const {
    double eyeToPlaneDistance { glm::distance(eyePoint, getViewPlanePosition()) };
    double viewPlaneWidth     { glm::distance(viewPlane[1], viewPlane[0]) };
    return 2.0 * glm::atan((viewPlaneWidth / 2.0) / eyeToPlaneDistance);
}

void   mcrt::Camera::setFieldOfView(double fieldOfView) {
}

glm::dvec3 mcrt::Camera::getPixelCenter(const Image& image, size_t i, size_t j) const {
    // Fetch the plane of the pixel, and just get the pixel's central position.
    SamplingPlane pixelSamplingPlane  { getPixelSamplingPlane(image,  i,  j) };
    // That is basically just half the diagonal from: top-left to bottom-right.
    return (pixelSamplingPlane.corners[2] - pixelSamplingPlane.corners[0])/2.0;
}

mcrt::Camera::SamplingPlane mcrt::Camera::getPixelSamplingPlane(const Image& image, size_t i, size_t j) const {
    // Fetch the axes built from the top-left to top-right (x)
    // and the top-left to bottom-left (y-axis). This is to do
    // mirroring of the coordinate system found in the images.
    glm::dvec3 xViewPlaneAxis { viewPlane[1] - viewPlane[0] },
               yViewPlaneAxis { viewPlane[3] - viewPlane[0] };

    // We find the lengths of the view plane's basis axes.
    double viewPlaneWidth  { glm::length(xViewPlaneAxis) },
           viewPlaneHeight { glm::length(yViewPlaneAxis) };

    xViewPlaneAxis = glm::normalize(xViewPlaneAxis);
    yViewPlaneAxis = glm::normalize(yViewPlaneAxis);

    // Finally, we compute the scaling ratio needed from pixel coordinates to viewplane.
    double widthScaleRatio  { viewPlaneWidth  / static_cast<double>(image.getWidth()) },
           heightScaleRatio { viewPlaneHeight / static_cast<double>(image.getHeight()) };

    SamplingPlane pixelSamplingPlane;
    pixelSamplingPlane.corners[0] = viewPlane[0];
    // Top-left pixel corner is scaled (i,j) units away from view plane tl.
    pixelSamplingPlane.corners[0] += i * widthScaleRatio  * xViewPlaneAxis;
    pixelSamplingPlane.corners[0] += j * heightScaleRatio * yViewPlaneAxis;

    // The rest are simply one pixel length away (or through the diagonal) from top-left pixel corners.
    pixelSamplingPlane.corners[1] =  pixelSamplingPlane.corners[0] + widthScaleRatio  * xViewPlaneAxis;
    pixelSamplingPlane.corners[2] =  pixelSamplingPlane.corners[0] + widthScaleRatio  * xViewPlaneAxis;
    pixelSamplingPlane.corners[2] += heightScaleRatio * yViewPlaneAxis; // top-left ----> bottom-right.
    pixelSamplingPlane.corners[3] =  pixelSamplingPlane.corners[0] + heightScaleRatio * yViewPlaneAxis;
    return pixelSamplingPlane;
}

void mcrt::Camera::moveTo(const glm::dvec3& viewPlanePosition) {
    glm::dvec3 planeCenter  { getViewPlanePosition() };
    glm::dvec3 eyeToCenter { planeCenter - eyePoint };
    glm::dvec3 tl { viewPlane[0] - planeCenter },
               tr { viewPlane[1] - planeCenter },
               br { viewPlane[2] - planeCenter },
               bl { viewPlane[3] - planeCenter };

    // Calculate new positions based on center.
    eyePoint = viewPlanePosition - eyeToCenter;
    viewPlane[0] = viewPlanePosition + tl;
    viewPlane[1] = viewPlanePosition + tr;
    viewPlane[2] = viewPlanePosition + br;
    viewPlane[3] = viewPlanePosition + bl;
}

glm::dvec3 mcrt::Camera::getEyePosition() const {
    // Now this one is quite easy!
    return eyePoint;
}

glm::dvec3 mcrt::Camera::getViewPlanePosition() const {
    glm::dvec3 viewDiagonal { viewPlane[2] - viewPlane[0] };
    // Return the center of the view plane accross diagonal.
    return viewPlane[0] + 0.5*viewDiagonal;
}

void mcrt::Camera::lookAt(const glm::dvec3& lookAtPosition, const glm::dvec3& upwardVector) {
    double eyeToPlaneDistance = glm::distance(eyePoint, getViewPlanePosition());
    glm::dvec3 w = glm::normalize(lookAtPosition - eyePoint);
    glm::dvec3 u = glm::cross(w, upwardVector);
    glm::dvec3 v = glm::cross(u, w);
    glm::dvec3 viewPlaneCenter = eyePoint + w*eyeToPlaneDistance;

    viewPlane[0] = viewPlaneCenter - u + v;
    viewPlane[1] = viewPlaneCenter + u + v;
    viewPlane[2] = viewPlaneCenter + u - v;
    viewPlane[3] = viewPlaneCenter + u + v;
}

std::ostream& mcrt::operator<<(std::ostream& output, const Camera& camera) {
    return output << "eye:          " << glm::to_string(camera.eyePoint) << std::endl
                  << "top-left:     " << glm::to_string(camera.viewPlane[0]) << std::endl
                  << "top-right:    " << glm::to_string(camera.viewPlane[1]) << std::endl
                  << "bottom-right: " << glm::to_string(camera.viewPlane[2]) << std::endl
                  << "bottom-left:  " << glm::to_string(camera.viewPlane[3]) << std::endl
                  << "aspectRatio:  " << camera.getAspectRatio() << std::endl
                  << "fieldOfView:  " << camera.getFieldOfView() <<  std::endl;
}
<|endoftext|>


<commit_before><commit_msg>libjrmath lib not correctly linked on Mac<commit_after><|endoftext|>


<commit_before><commit_msg>Add a comment.<commit_after><|endoftext|>


<commit_before>/*
 *  qdespot1.cpp - Part of QUantitative Imaging Tools
 *
 *  Copyright (c) 2015 Tobias Wood.
 *
 *  This Source Code Form is subject to the terms of the Mozilla Public
 *  License, v. 2.0. If a copy of the MPL was not distributed with this
 *  file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 */

#include <time.h>
#include <getopt.h>
#include <iostream>
#include <atomic>
#include <Eigen/Dense>

#include "itkImageFileReader.h"

#include "Filters/ImageToVectorFilter.h"
#include "Filters/ApplyAlgorithmFilter.h"
#include "Model.h"
#include "Sequence.h"
#include "Util.h"

using namespace std;
using namespace Eigen;

//******************************************************************************
// Algorithm Subclasses
//******************************************************************************
class D1Algo : public Algorithm<double> {
protected:
	const shared_ptr<Model> m_model = make_shared<SCD>();
	shared_ptr<SPGRSimple> m_sequence;
	size_t m_iterations = 15;

public:
	void setIterations(size_t n) { m_iterations = n; }
	void setSequence(shared_ptr<SPGRSimple> &s) { m_sequence = s; }
	size_t numInputs() const override { return m_sequence->count(); }
	size_t numConsts() const override { return 1; }
	size_t numOutputs() const override { return 2; }
	size_t dataSize() const override { return m_sequence->size(); }

	virtual VectorXd defaultConsts() {
		// B1
		VectorXd def = VectorXd::Ones(1);
		return def;
	}
};

class D1LLS : public D1Algo {
public:
	virtual void apply(const VectorXd &data, const VectorXd &inputs,
	                   VectorXd &outputs, ArrayXd &resids) const override
	{
		double B1 = inputs[0];
		ArrayXd flip = m_sequence->flip() * B1;
		VectorXd Y = data.array() / flip.sin();
		MatrixXd X(Y.rows(), 2);
		X.col(0) = data.array() / flip.tan();
		X.col(1).setOnes();
		VectorXd b = (X.transpose() * X).partialPivLu().solve(X.transpose() * Y);
		outputs[1] = -m_sequence->TR() / log(b[0]);
		outputs[0] = b[1] / (1. - b[0]);
		ArrayXd theory = One_SPGR(m_sequence->flip(), m_sequence->TR(), outputs[0], outputs[1], B1).array().abs();
		resids = (data.array() - theory);
	}
};

class D1WLLS : public D1Algo {
public:
	virtual void apply(const VectorXd &data, const VectorXd &inputs,
	                   VectorXd &outputs, ArrayXd &resids) const override
	{
		double B1 = inputs[0];
		ArrayXd flip = m_sequence->flip() * B1;
		VectorXd Y = data.array() / flip.sin();
		MatrixXd X(Y.rows(), 2);
		X.col(0) = data.array() / flip.tan();
		X.col(1).setOnes();
		VectorXd b = (X.transpose() * X).partialPivLu().solve(X.transpose() * Y);
		outputs[1] = -m_sequence->TR() / log(b[0]);
		outputs[0] = b[1] / (1. - b[0]);
		for (size_t n = 0; n < m_iterations; n++) {
			MatrixXd W = (flip.sin() / (1. - (exp(-m_sequence->TR()/outputs[1])*flip.cos()))).square();
			b = (X.transpose() * W.asDiagonal() * X).partialPivLu().solve(X.transpose() * W.asDiagonal() * Y);
			outputs[1] = -m_sequence->TR() / log(b[0]);
			outputs[0] = b[1] / (1. - b[0]);
		}
		ArrayXd theory = One_SPGR(m_sequence->flip(), m_sequence->TR(), outputs[0], outputs[1], B1).array().abs();
		resids = (data.array() - theory);
	}
};

// T1 only Functor
class T1Functor : public DenseFunctor<double> {
	protected:
		const shared_ptr<SequenceBase> m_sequence;
		const ArrayXd m_data;
		const double m_B1;
		const shared_ptr<SCD> m_model;

	public:
		T1Functor(const shared_ptr<SequenceBase> cs, const ArrayXd &data, const double B1) :
			DenseFunctor<double>(2, cs->size()),
			m_sequence(cs), m_data(data), m_B1(B1)
		{
			assert(static_cast<size_t>(m_data.rows()) == values());
		}

		int operator()(const Ref<VectorXd> &p, Ref<ArrayXd> diffs) const {
			eigen_assert(diffs.size() == values());
			ArrayXd s = One_SPGR(m_sequence->flip(), m_sequence->TR(), p[0], p[1], m_B1).array().abs();
			diffs = s.abs() - m_data;
			return 0;
		}
};

class D1NLLS : public D1Algo {
public:
	virtual void apply(const VectorXd &data, const VectorXd &inputs,
	                   VectorXd &outputs, ArrayXd &resids) const override
	{
		double B1 = inputs[0];
		T1Functor f(m_sequence, data, B1);
		NumericalDiff<T1Functor> nDiff(f);
		LevenbergMarquardt<NumericalDiff<T1Functor>> lm(nDiff);
		// PD & T1 - Initial guess of 1s
		outputs << data.array().abs().maxCoeff() * 10., 1.;
		lm.setMaxfev(m_iterations * (m_sequence->size() + 1));
		lm.minimize(outputs);
		ArrayXd theory = One_SPGR(m_sequence->flip(), m_sequence->TR(), outputs[0], outputs[1], B1).array().abs();
		resids = data.array() - theory;
	}
};

//******************************************************************************
// Arguments / Usage
//******************************************************************************
const string usage {
"Usage is: despot1 [options] spgr_input \n\
\
Options:\n\
	--help, -h        : Print this message\n\
	--verbose, -v     : Print more information\n\
	--no-prompt, -n   : Suppress input prompts\n\
	--out, -o path    : Add a prefix to the output filenames\n\
	--mask, -m file   : Mask input with specified file\n\
	--B1, -b file     : B1 Map file (ratio)\n\
	--algo, -a l      : LLS algorithm (default)\n\
	           w      : WLLS algorithm\n\
	           n      : NLLS (Levenberg-Marquardt)\n\
	--its, -i N       : Max iterations for WLLS/NLLS (default 15)\n\
	--resids, -r      : Write out per flip-angle residuals\n\
	--threads, -T N   : Use N threads (default=hardware limit)\n"
};

static bool verbose = false, prompt = true, all_residuals = false;
static size_t nIterations = 4;
static string outPrefix;
static struct option long_options[] =
{
	{"help", no_argument, 0, 'h'},
	{"verbose", no_argument, 0, 'v'},
	{"no-prompt", no_argument, 0, 'n'},
	{"out", required_argument, 0, 'o'},
	{"mask", required_argument, 0, 'm'},
	{"B1", required_argument, 0, 'b'},
	{"algo", required_argument, 0, 'a'},
	{"its", required_argument, 0, 'i'},
	{"resids", no_argument, 0, 'r'},
	{"threads", required_argument, 0, 'T'},
	{0, 0, 0, 0}
};
static const char *short_opts = "hvnm:o:b:a:i:rT:";

//******************************************************************************
// Main
//******************************************************************************
int main(int argc, char **argv) {
	try { // To fix uncaught exceptions on Mac
	//cout << version << endl << credit_shared << endl;
	Eigen::initParallel();

	QI::ReadImageF::Pointer mask = ITK_NULLPTR;
	QI::ReadImageF::Pointer B1   = ITK_NULLPTR;

	shared_ptr<D1Algo> algo = make_shared<D1LLS>();
	size_t its = 15;
	int indexptr = 0, c;
	while ((c = getopt_long(argc, argv, short_opts, long_options, &indexptr)) != -1) {
		switch (c) {
			case 'v': verbose = true; break;
			case 'n': prompt = false; break;
			case 'a':
				switch (*optarg) {
					case 'l': algo = make_shared<D1LLS>();  if (verbose) cout << "LLS algorithm selected." << endl; break;
					case 'w': algo = make_shared<D1WLLS>(); if (verbose) cout << "WLLS algorithm selected." << endl; break;
					case 'n': algo = make_shared<D1NLLS>(); if (verbose) cout << "NLLS algorithm selected." << endl; break;
					default:
						cerr << "Unknown algorithm type " << optarg << endl;
						return EXIT_FAILURE;
						break;
				} break;
			case 'm':
				if (verbose) cout << "Opening mask file " << optarg << endl;
				mask = QI::ReadImageF::New();
				mask->SetFileName(optarg);
				break;
			case 'o':
				outPrefix = optarg;
				if (verbose) cout << "Output prefix will be: " << outPrefix << endl;
				break;
			case 'b':
				if (verbose) cout << "Opening B1 file: " << optarg << endl;
				B1 = QI::ReadImageF::New();
				B1->SetFileName(optarg);
				break;
			case 'i': its = (atoi(optarg)); break;
			case 'r': all_residuals = true; break;
			case 'T': itk::MultiThreader::SetGlobalMaximumNumberOfThreads(atoi(optarg)); break;
			case 'h':
			case '?': // getopt will print an error message
				return EXIT_FAILURE;
		}
	}
	if ((argc - optind) != 1) {
		cout << "Incorrect number of arguments." << endl << usage << endl;
		return EXIT_FAILURE;
	}

	string inputFilename = argv[optind++];
	if (verbose) cout << "Opening SPGR file: " << inputFilename << endl;
	auto input = QI::ReadTimeseriesF::New();
	auto convert = QI::TimeseriesToVectorF::New();
	input->SetFileName(inputFilename);
	convert->SetInput(input->GetOutput());

	shared_ptr<SPGRSimple> spgrSequence = make_shared<SPGRSimple>(prompt);
	if (verbose) cout << *spgrSequence;
	algo->setSequence(spgrSequence);
	algo->setIterations(its);
	auto apply = itk::ApplyAlgorithmFilter<QI::VectorImageF, D1Algo>::New();
	apply->SetAlgorithm(algo);
	apply->SetDataInput(0, convert->GetOutput());
	if (mask)
		apply->SetMask(mask->GetOutput());
	if (B1)
		apply->SetConstInput(0, B1->GetOutput());
	if (verbose) cout << "Processing" << endl;
	apply->Update();
	if (verbose) cout << "Writing results." << endl;
	outPrefix = outPrefix + "D1_";

	QI::writeResult(apply->GetOutput(0), outPrefix + "PD.nii");
	QI::writeResult(apply->GetOutput(1), outPrefix + "T1.nii");
	QI::writeResiduals(apply->GetResidOutput(), outPrefix, all_residuals);

	if (verbose) cout << "Finished." << endl;
	} catch (exception &e) {
		cerr << e.what() << endl;
		return EXIT_FAILURE;
	}
	return EXIT_SUCCESS;
}
<commit_msg>Added back thresh/clamp options.<commit_after>/*
 *  qdespot1.cpp - Part of QUantitative Imaging Tools
 *
 *  Copyright (c) 2015 Tobias Wood.
 *
 *  This Source Code Form is subject to the terms of the Mozilla Public
 *  License, v. 2.0. If a copy of the MPL was not distributed with this
 *  file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 */

#include <time.h>
#include <getopt.h>
#include <iostream>
#include <atomic>
#include <Eigen/Dense>

#include "itkImageFileReader.h"

#include "Filters/ImageToVectorFilter.h"
#include "Filters/ApplyAlgorithmFilter.h"
#include "Model.h"
#include "Sequence.h"
#include "Util.h"

using namespace std;
using namespace Eigen;

//******************************************************************************
// Algorithm Subclasses
//******************************************************************************
class D1Algo : public Algorithm<double> {
protected:
	const shared_ptr<Model> m_model = make_shared<SCD>();
	shared_ptr<SPGRSimple> m_sequence;
	size_t m_iterations = 15;
	double m_thresh = -numeric_limits<double>::infinity();
	double m_lo = -numeric_limits<double>::infinity();
	double m_hi = numeric_limits<double>::infinity();

public:
	void setIterations(size_t n) { m_iterations = n; }
	void setSequence(shared_ptr<SPGRSimple> &s) { m_sequence = s; }
	void setThreshold(double t) { m_thresh = t; }
	void setClamp(double lo, double hi) { m_lo = lo; m_hi = hi; }
	size_t numInputs() const override { return m_sequence->count(); }
	size_t numConsts() const override { return 1; }
	size_t numOutputs() const override { return 2; }
	size_t dataSize() const override { return m_sequence->size(); }

	virtual VectorXd defaultConsts() {
		// B1
		VectorXd def = VectorXd::Ones(1);
		return def;
	}
};

class D1LLS : public D1Algo {
public:
	virtual void apply(const VectorXd &data, const VectorXd &inputs,
	                   VectorXd &outputs, ArrayXd &resids) const override
	{
		double B1 = inputs[0];
		ArrayXd flip = m_sequence->flip() * B1;
		VectorXd Y = data.array() / flip.sin();
		MatrixXd X(Y.rows(), 2);
		X.col(0) = data.array() / flip.tan();
		X.col(1).setOnes();
		VectorXd b = (X.transpose() * X).partialPivLu().solve(X.transpose() * Y);
		outputs[1] = -m_sequence->TR() / log(b[0]);
		outputs[0] = b[1] / (1. - b[0]);
		ArrayXd theory = One_SPGR(m_sequence->flip(), m_sequence->TR(), outputs[0], outputs[1], B1).array().abs();
		resids = (data.array() - theory);
		if (outputs[0] < m_thresh)
			outputs.setZero();
		outputs[1] = clamp(outputs[1], m_lo, m_hi);
	}
};

class D1WLLS : public D1Algo {
public:
	virtual void apply(const VectorXd &data, const VectorXd &inputs,
	                   VectorXd &outputs, ArrayXd &resids) const override
	{
		double B1 = inputs[0];
		ArrayXd flip = m_sequence->flip() * B1;
		VectorXd Y = data.array() / flip.sin();
		MatrixXd X(Y.rows(), 2);
		X.col(0) = data.array() / flip.tan();
		X.col(1).setOnes();
		VectorXd b = (X.transpose() * X).partialPivLu().solve(X.transpose() * Y);
		outputs[1] = -m_sequence->TR() / log(b[0]);
		outputs[0] = b[1] / (1. - b[0]);
		for (size_t n = 0; n < m_iterations; n++) {
			MatrixXd W = (flip.sin() / (1. - (exp(-m_sequence->TR()/outputs[1])*flip.cos()))).square();
			b = (X.transpose() * W.asDiagonal() * X).partialPivLu().solve(X.transpose() * W.asDiagonal() * Y);
			outputs[1] = -m_sequence->TR() / log(b[0]);
			outputs[0] = b[1] / (1. - b[0]);
		}
		ArrayXd theory = One_SPGR(m_sequence->flip(), m_sequence->TR(), outputs[0], outputs[1], B1).array().abs();
		resids = (data.array() - theory);
		if (outputs[0] < m_thresh)
			outputs.setZero();
		outputs[1] = clamp(outputs[1], m_lo, m_hi);
	}
};

// T1 only Functor
class T1Functor : public DenseFunctor<double> {
	protected:
		const shared_ptr<SequenceBase> m_sequence;
		const ArrayXd m_data;
		const double m_B1;
		const shared_ptr<SCD> m_model;

	public:
		T1Functor(const shared_ptr<SequenceBase> cs, const ArrayXd &data, const double B1) :
			DenseFunctor<double>(2, cs->size()),
			m_sequence(cs), m_data(data), m_B1(B1)
		{
			assert(static_cast<size_t>(m_data.rows()) == values());
		}

		int operator()(const Ref<VectorXd> &p, Ref<ArrayXd> diffs) const {
			eigen_assert(diffs.size() == values());
			ArrayXd s = One_SPGR(m_sequence->flip(), m_sequence->TR(), p[0], p[1], m_B1).array().abs();
			diffs = s.abs() - m_data;
			return 0;
		}
};

class D1NLLS : public D1Algo {
public:
	virtual void apply(const VectorXd &data, const VectorXd &inputs,
	                   VectorXd &outputs, ArrayXd &resids) const override
	{
		double B1 = inputs[0];
		T1Functor f(m_sequence, data, B1);
		NumericalDiff<T1Functor> nDiff(f);
		LevenbergMarquardt<NumericalDiff<T1Functor>> lm(nDiff);
		// PD & T1 - Initial guess of 1s
		outputs << data.array().abs().maxCoeff() * 10., 1.;
		lm.setMaxfev(m_iterations * (m_sequence->size() + 1));
		lm.minimize(outputs);
		ArrayXd theory = One_SPGR(m_sequence->flip(), m_sequence->TR(), outputs[0], outputs[1], B1).array().abs();
		resids = data.array() - theory;
		if (outputs[0] < m_thresh)
			outputs.setZero();
		outputs[1] = clamp(outputs[1], m_lo, m_hi);
	}
};

//******************************************************************************
// Arguments / Usage
//******************************************************************************
const string usage {
"Usage is: despot1 [options] spgr_input \n\
\
Options:\n\
	--help, -h        : Print this message\n\
	--verbose, -v     : Print more information\n\
	--no-prompt, -n   : Suppress input prompts\n\
	--out, -o path    : Add a prefix to the output filenames\n\
	--mask, -m file   : Mask input with specified file\n\
	--B1, -b file     : B1 Map file (ratio)\n\
	--thresh, -t n    : Threshold maps at PD < n\n\
	--clamp, -c n     : Clamp T1 between 0 and n\n\
	--algo, -a l      : LLS algorithm (default)\n\
	           w      : WLLS algorithm\n\
	           n      : NLLS (Levenberg-Marquardt)\n\
	--its, -i N       : Max iterations for WLLS/NLLS (default 15)\n\
	--resids, -r      : Write out per flip-angle residuals\n\
	--threads, -T N   : Use N threads (default=hardware limit)\n"
};

static bool verbose = false, prompt = true, all_residuals = false;
static size_t nIterations = 4;
static string outPrefix;
static struct option long_options[] =
{
	{"help", no_argument, 0, 'h'},
	{"verbose", no_argument, 0, 'v'},
	{"no-prompt", no_argument, 0, 'n'},
	{"out", required_argument, 0, 'o'},
	{"mask", required_argument, 0, 'm'},
	{"B1", required_argument, 0, 'b'},
	{"thresh", required_argument, 0, 't'},
	{"clamp", required_argument, 0, 'c'},
	{"algo", required_argument, 0, 'a'},
	{"its", required_argument, 0, 'i'},
	{"resids", no_argument, 0, 'r'},
	{"threads", required_argument, 0, 'T'},
	{0, 0, 0, 0}
};
static const char *short_opts = "hvnm:o:b:t:c:a:i:rT:";

//******************************************************************************
// Main
//******************************************************************************
int main(int argc, char **argv) {
	Eigen::initParallel();
	QI::ReadImageF::Pointer mask = ITK_NULLPTR;
	QI::ReadImageF::Pointer B1   = ITK_NULLPTR;

	shared_ptr<D1Algo> algo = make_shared<D1LLS>();
	int indexptr = 0, c;
	while ((c = getopt_long(argc, argv, short_opts, long_options, &indexptr)) != -1) {
		switch (c) {
			case 'v': verbose = true; break;
			case 'n': prompt = false; break;
			case 'a':
				switch (*optarg) {
					case 'l': algo = make_shared<D1LLS>();  if (verbose) cout << "LLS algorithm selected." << endl; break;
					case 'w': algo = make_shared<D1WLLS>(); if (verbose) cout << "WLLS algorithm selected." << endl; break;
					case 'n': algo = make_shared<D1NLLS>(); if (verbose) cout << "NLLS algorithm selected." << endl; break;
					default:
						cerr << "Unknown algorithm type " << optarg << endl;
						return EXIT_FAILURE;
						break;
				} break;
			default: break;
		}
	}
	optind = 1;
	while ((c = getopt_long(argc, argv, short_opts, long_options, &indexptr)) != -1) {
		switch (c) {
			case 'v': case 'n': case 'a': break;
			case 'm':
				if (verbose) cout << "Opening mask file " << optarg << endl;
				mask = QI::ReadImageF::New();
				mask->SetFileName(optarg);
				break;
			case 'o':
				outPrefix = optarg;
				if (verbose) cout << "Output prefix will be: " << outPrefix << endl;
				break;
			case 'b':
				if (verbose) cout << "Opening B1 file: " << optarg << endl;
				B1 = QI::ReadImageF::New();
				B1->SetFileName(optarg);
				break;
			case 't': algo->setThreshold(atof(optarg)); break;
			case 'c': algo->setClamp(0, atof(optarg)); break;
			case 'i': algo->setIterations(atoi(optarg)); break;
			case 'r': all_residuals = true; break;
			case 'T': itk::MultiThreader::SetGlobalMaximumNumberOfThreads(atoi(optarg)); break;
			case 'h':
			case '?': // getopt will print an error message
				return EXIT_FAILURE;
		}
	}
	if ((argc - optind) != 1) {
		cout << "Incorrect number of arguments." << endl << usage << endl;
		return EXIT_FAILURE;
	}

	string inputFilename = argv[optind++];
	if (verbose) cout << "Opening SPGR file: " << inputFilename << endl;
	auto input = QI::ReadTimeseriesF::New();
	auto convert = QI::TimeseriesToVectorF::New();
	input->SetFileName(inputFilename);
	convert->SetInput(input->GetOutput());
	shared_ptr<SPGRSimple> spgrSequence = make_shared<SPGRSimple>(prompt);
	if (verbose) cout << *spgrSequence;
	algo->setSequence(spgrSequence);
	auto apply = itk::ApplyAlgorithmFilter<QI::VectorImageF, D1Algo>::New();
	apply->SetAlgorithm(algo);
	apply->SetDataInput(0, convert->GetOutput());
	if (mask)
		apply->SetMask(mask->GetOutput());
	if (B1)
		apply->SetConstInput(0, B1->GetOutput());
	if (verbose) cout << "Processing" << endl;
	apply->Update();
	if (verbose) cout << "Writing results." << endl;
	outPrefix = outPrefix + "D1_";
	QI::writeResult(apply->GetOutput(0), outPrefix + "PD.nii");
	QI::writeResult(apply->GetOutput(1), outPrefix + "T1.nii");
	QI::writeResiduals(apply->GetResidOutput(), outPrefix, all_residuals);

	if (verbose) cout << "Finished." << endl;
	return EXIT_SUCCESS;
}
<|endoftext|>


<commit_before>/*****************************************************************************
  slopBed.cpp

  (c) 2009 - Aaron Quinlan
  Hall Laboratory
  Department of Biochemistry and Molecular Genetics
  University of Virginia
  aaronquinlan@gmail.com

  Licenced under the GNU General Public License 2.0 license.
******************************************************************************/
#include "lineFileUtilities.h"
#include "slopBed.h"

BedSlop::BedSlop(string &bedFile, string &genomeFile, bool &forceStrand, int &leftSlop, int &rightSlop) {

    _bedFile = bedFile;
    _genomeFile = genomeFile;
    _forceStrand = forceStrand;

    _leftSlop = leftSlop;
    _rightSlop = rightSlop;

    _bed    = new BedFile(bedFile);
    _genome = new GenomeFile(genomeFile);

    SlopBed();
}

BedSlop::~BedSlop(void) {

}

void BedSlop::SlopBed() {

    int lineNum = 0;
    BED bedEntry, nullBed;     // used to store the current BED line from the BED file.
    BedLineStatus bedStatus;

    _bed->Open();
    bedStatus = _bed->GetNextBed(bedEntry, lineNum);
    while (bedStatus != BED_INVALID) {
        if (bedStatus == BED_VALID) {
            AddSlop(bedEntry);
            _bed->reportBedNewLine(bedEntry);
            bedEntry = nullBed;
        }
        bedStatus = _bed->GetNextBed(bedEntry, lineNum);
    }
    _bed->Close();
}

void BedSlop::AddSlop(BED &bed) {

    // special handling if the BED entry is on the negative
    // strand and the user cares about strandedness.
    CHRPOS chromSize = _genome->getChromSize(bed.chrom);

    if ( (_forceStrand) && (bed.strand == "-") ) {
        // inspect the start
        if ( (static_cast<int>(bed.start) - _rightSlop) > 0 ) bed.start -= _rightSlop;
        else bed.start = 0;

        // inspect the start
        if ( (static_cast<int>(bed.end) + _leftSlop) <= static_cast<int>(chromSize)) bed.end += _leftSlop;
        else bed.end = chromSize;
    }
    else {
        // inspect the start
        if ( (static_cast<int>(bed.start) - _leftSlop) > 0) bed.start -= _leftSlop;
        else bed.start = 0;

        // inspect the end
        if ( (static_cast<int>(bed.end) + _rightSlop) <= static_cast<int>(chromSize)) bed.end += _rightSlop;
        else bed.end = chromSize;
    }
}

<commit_msg>Minor formatting in slopBed.cpp.<commit_after>/*****************************************************************************
  slopBed.cpp

  (c) 2009 - Aaron Quinlan
  Hall Laboratory
  Department of Biochemistry and Molecular Genetics
  University of Virginia
  aaronquinlan@gmail.com

  Licenced under the GNU General Public License 2.0 license.
******************************************************************************/
#include "lineFileUtilities.h"
#include "slopBed.h"

BedSlop::BedSlop(string &bedFile, string &genomeFile, bool &forceStrand, int &leftSlop, int &rightSlop) {

    _bedFile     = bedFile;
    _genomeFile  = genomeFile;
    _forceStrand = forceStrand;

    _leftSlop  = leftSlop;
    _rightSlop = rightSlop;

    _bed    = new BedFile(bedFile);
    _genome = new GenomeFile(genomeFile);

    SlopBed();
}

BedSlop::~BedSlop(void) {

}

void BedSlop::SlopBed() {

    int lineNum = 0;
    BED bedEntry, nullBed;     // used to store the current BED line from the BED file.
    BedLineStatus bedStatus;

    _bed->Open();
    bedStatus = _bed->GetNextBed(bedEntry, lineNum);
    while (bedStatus != BED_INVALID) {
        if (bedStatus == BED_VALID) {
            AddSlop(bedEntry);
            _bed->reportBedNewLine(bedEntry);
            bedEntry = nullBed;
        }
        bedStatus = _bed->GetNextBed(bedEntry, lineNum);
    }
    _bed->Close();
}

void BedSlop::AddSlop(BED &bed) {

    // special handling if the BED entry is on the negative
    // strand and the user cares about strandedness.
    CHRPOS chromSize = _genome->getChromSize(bed.chrom);

    if ( (_forceStrand) && (bed.strand == "-") ) {
        // inspect the start
        if ( (static_cast<int>(bed.start) - _rightSlop) > 0 ) bed.start -= _rightSlop;
        else bed.start = 0;

        // inspect the start
        if ( (static_cast<int>(bed.end) + _leftSlop) <= static_cast<int>(chromSize)) bed.end += _leftSlop;
        else bed.end = chromSize;
    }
    else {
        // inspect the start
        if ( (static_cast<int>(bed.start) - _leftSlop) > 0) bed.start -= _leftSlop;
        else bed.start = 0;

        // inspect the end
        if ( (static_cast<int>(bed.end) + _rightSlop) <= static_cast<int>(chromSize)) bed.end += _rightSlop;
        else bed.end = chromSize;
    }
}

<|endoftext|>


<commit_before>#ifndef BUTTON_HPP
#define BUTTON_HPP

#include<string>
#include<SFML/Graphics.hpp>

#define BT_COLOR_DEFAULT 150,150,150
#define BT_COLOR_CLICKED 100,100,100
#define BT_COLOR_TEXT 255,255,255

using namespace std;
using namespace sf;

class Button {
	private:
		string name;
		int x,y,w,h;
		RectangleShape bt;
		Text text;
		RenderWindow *rw;
		int click;

	public:
		Button( string, RenderWindow&, Font&, int, int, int, int);
		void draw();
		bool pressed();
};

#endif<commit_msg>Removed Name Var<commit_after>#ifndef BUTTON_HPP
#define BUTTON_HPP

#include<string>
#include<SFML/Graphics.hpp>

#define BT_COLOR_DEFAULT 150,150,150
#define BT_COLOR_CLICKED 100,100,100
#define BT_COLOR_TEXT 255,255,255

using namespace std;
using namespace sf;

class Button {
	private:
		int x,y,w,h;
		RectangleShape bt;
		Text text;
		RenderWindow *rw;
		int click;

	public:
		Button( string, RenderWindow&, Font&, int, int, int, int);
		void draw();
		bool pressed();
};

#endif<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: dumputils.cxx,v $
 *
 *  $Revision: 1.6 $
 *
 *  last change: $Author: obo $ $Date: 2006-09-17 03:37:08 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_codemaker.hxx"

#include "dumputils.hxx"

#include "codemaker/global.hxx"
#include "codemaker/commoncpp.hxx"

#include "rtl/ustring.hxx"
#include "sal/types.h"

namespace codemaker { namespace cppumaker {

bool dumpNamespaceOpen(
    FileStream & out, rtl::OString const & registryType, bool fullModuleType)
{
    bool output = false;
    if (registryType != "/") {
        bool first = true;
        for (sal_Int32 i = 0; i >= 0;) {
            rtl::OString id(registryType.getToken(0, '/', i));
            if (fullModuleType || i >= 0) {
                if (!first) {
                    out << " ";
                }
                out << "namespace " << id << " {";
                first = false;
                output = true;
            }
        }
    }
    return output;
}

bool dumpNamespaceClose(
    FileStream & out, rtl::OString const & registryType, bool fullModuleType)
{
    bool output = false;
    if (registryType != "/") {
        bool first = true;
        for (sal_Int32 i = 0; i >= 0;) {
            i = registryType.indexOf('/', i);
            if (i >= 0) {
                ++i;
            }
            if (fullModuleType || i >= 0) {
                if (!first) {
                    out << " ";
                }
                out << "}";
                first = false;
                output = true;
            }
        }
    }
    return output;
}

void dumpTypeIdentifier(FileStream & out, rtl::OString const & registryType) {
    out << registryType.copy(registryType.lastIndexOf('/') + 1);
}

} }
<commit_msg>INTEGRATION: CWS changefileheader (1.6.38); FILE MERGED 2008/03/31 07:22:53 rt 1.6.38.1: #i87441# Change license header to LPGL v3.<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: dumputils.cxx,v $
 * $Revision: 1.7 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_codemaker.hxx"

#include "dumputils.hxx"

#include "codemaker/global.hxx"
#include "codemaker/commoncpp.hxx"

#include "rtl/ustring.hxx"
#include "sal/types.h"

namespace codemaker { namespace cppumaker {

bool dumpNamespaceOpen(
    FileStream & out, rtl::OString const & registryType, bool fullModuleType)
{
    bool output = false;
    if (registryType != "/") {
        bool first = true;
        for (sal_Int32 i = 0; i >= 0;) {
            rtl::OString id(registryType.getToken(0, '/', i));
            if (fullModuleType || i >= 0) {
                if (!first) {
                    out << " ";
                }
                out << "namespace " << id << " {";
                first = false;
                output = true;
            }
        }
    }
    return output;
}

bool dumpNamespaceClose(
    FileStream & out, rtl::OString const & registryType, bool fullModuleType)
{
    bool output = false;
    if (registryType != "/") {
        bool first = true;
        for (sal_Int32 i = 0; i >= 0;) {
            i = registryType.indexOf('/', i);
            if (i >= 0) {
                ++i;
            }
            if (fullModuleType || i >= 0) {
                if (!first) {
                    out << " ";
                }
                out << "}";
                first = false;
                output = true;
            }
        }
    }
    return output;
}

void dumpTypeIdentifier(FileStream & out, rtl::OString const & registryType) {
    out << registryType.copy(registryType.lastIndexOf('/') + 1);
}

} }
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2008 James Molloy, Jörg Pfähler, Matthew Iselin
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include "Header.h"
#include <pedigree_config.h>

#include <graphics/Graphics.h>

extern PedigreeGraphics::Framebuffer *g_pFramebuffer;

uint32_t g_BorderColour                    = 0x5096; // {150, 80, 0,0};
uint32_t g_TabBackgroundColour             = 0; // {0, 0, 0,0};
uint32_t g_TabTextColour                   = 0x6496; // {150, 100, 0,0};
uint32_t g_SelectedTabBackgroundColour     = 0x6496; // {150, 100, 0,0};
uint32_t g_SelectedTabTextColour           = 0xFFFFFF; // {255, 255, 255,0};
uint32_t g_TextColour                      = 0xFFFFFF; // {255, 255, 255,0};
uint32_t g_MainBackgroundColour            = 0; // {0, 0, 0,0};
size_t g_FontSize = 16;

Header::Header(size_t nWidth) :
    m_nWidth(nWidth), m_Page(0), m_LastPage(0), m_pFont(0),
    m_pTabs(0), m_NextTabId(0), m_pFramebuffer(0)
{
    m_pFont = new Font(g_FontSize, "/system/fonts/DejaVuSansMono-BoldOblique.ttf", false, nWidth);
    g_FontSize = m_pFont->getHeight();

    int result = pedigree_config_query("select * from 'colour-scheme';");
    if (result == -1)
    {
        log("Unable to query config!");
        return;
    }

    char buf[256];
    if (pedigree_config_was_successful(result) != 0)
    {
        pedigree_config_get_error_message(result, buf, 256);
        log(buf);
        return;
    }

    while (pedigree_config_nextrow(result) == 0)
    {
        memset (buf, 0, 256);
        pedigree_config_getstr_n (result, 0, buf, 256);
        rgb_t rgb;
        rgb.r = pedigree_config_getnum_n (result, 1);
        rgb.g = pedigree_config_getnum_n (result, 2);
        rgb.b = pedigree_config_getnum_n (result, 3);
        rgb.a = 0;

        if (!strcmp(buf, "border"))
        {
            g_BorderColour = PedigreeGraphics::createRgb(rgb.r, rgb.g, rgb.b);
            g_TabBackgroundColour = PedigreeGraphics::createRgb(rgb.r, rgb.g, rgb.b);
        }
        else if (!strcmp(buf, "fill"))
            g_SelectedTabBackgroundColour = PedigreeGraphics::createRgb(rgb.r, rgb.g, rgb.b);
        else if (!strcmp(buf, "selected-text"))
            g_SelectedTabTextColour = PedigreeGraphics::createRgb(rgb.r, rgb.g, rgb.b);
        else if (!strcmp(buf, "text"))
        {
            g_TextColour = PedigreeGraphics::createRgb(rgb.r, rgb.g, rgb.b);
            g_TabTextColour = PedigreeGraphics::createRgb(rgb.r, rgb.g, rgb.b);
        }
        else if (!strcmp(buf, "tui-background"))
            g_MainBackgroundColour = PedigreeGraphics::createRgb(rgb.r, rgb.g, rgb.b);
    }
    pedigree_config_freeresult(result);

}

Header::~Header()
{
    delete m_pFont;
}

size_t Header::getHeight()
{
    return g_FontSize+5;
}

void Header::render(rgb_t *pBuffer, DirtyRectangle &rect)
{
    size_t charWidth = m_pFont->getWidth();

    if(!m_pFramebuffer)
    {
        m_pFramebuffer = g_pFramebuffer->createChild(0, 0, m_nWidth, g_FontSize + 5);
        if(!m_pFramebuffer)
            return;
        else if(!m_pFramebuffer->getRawBuffer())
            return;
    }

    // Set up the dirty rectangle to cover the entire header area.
    rect.point(0, 0);
    rect.point(m_nWidth, g_FontSize+5);

    // Height = font size + 2 px top and bottom + border 1px =
    // font-size + 5px.
    m_pFramebuffer->line(0, g_FontSize + 4, m_nWidth, 1, g_BorderColour, PedigreeGraphics::Bits24_Rgb);

    size_t offset = 0;
    if (m_Page != 0)
    {
        // Render a left-double arrow.
        offset = renderString("<", offset, 2, g_TextColour, g_MainBackgroundColour);
    }

    Tab *pTab = m_pTabs;
    while (pTab)
    {
        if (pTab->page == m_Page)
        {
            // Add 5 pixels.
            offset += 5;

            uint32_t foreColour = g_TextColour;
            if (pTab->flags & TAB_SELECTED)
                foreColour = g_SelectedTabTextColour;
            else if (pTab->flags & TAB_SELECTABLE)
                foreColour = g_TabTextColour;

            uint32_t backColour = g_MainBackgroundColour;
            if (pTab->flags & TAB_SELECTED)
                backColour = g_SelectedTabBackgroundColour;
            else if (pTab->flags & TAB_SELECTABLE)
                backColour = g_TabBackgroundColour;

            // Fill to background colour.
            m_pFramebuffer->rect(offset - 4, 0, strlen(pTab->text) * charWidth + 10, g_FontSize + 4, backColour, PedigreeGraphics::Bits24_Rgb);

            offset = renderString(pTab->text, offset, 2, foreColour, backColour);

            offset += 5;
            // Add a seperator
            m_pFramebuffer->line(offset, 0, 1, g_FontSize + 4, g_BorderColour, PedigreeGraphics::Bits24_Rgb);
        }
        pTab = pTab->next;
    }

    if (m_Page != m_LastPage)
    {
        offset += 5;
        // Render a right-double arrow.
        offset = renderString(">", offset, 2, g_TextColour, g_MainBackgroundColour);
    }
}

size_t Header::renderString(const char *str, size_t x, size_t y, uint32_t f, uint32_t b)
{
    while (*str)
        x += m_pFont->render(m_pFramebuffer, *str++, x, y, f, b);
    return x;
}

void Header::update()
{
    size_t charWidth = m_pFont->getWidth();

    // Here we must run through the list of tabs and assign each a page number.
    size_t offset = 0;
    size_t page = 0;

    // Leave room for a left-arrow.
    offset += charWidth + 5;

    Tab *pTab = m_pTabs;
    while (pTab)
    {
        offset += 5 + strlen(pTab->text)*charWidth + 5;
        if (offset >= m_nWidth - charWidth - 5)
        {
            page ++;
            offset = charWidth + 5;
        }
        pTab->page = page;

        pTab = pTab->next;
    }

    m_LastPage = page;
}

void Header::select(size_t tabId)
{
    Tab *pTab = m_pTabs;
    while(pTab)
    {
        if (pTab->id == tabId)
            pTab->flags |= TAB_SELECTED;
        else
            pTab->flags &= ~TAB_SELECTED;
        pTab = pTab->next;
    }
}

void Header::centreOn(size_t tabId)
{
    Tab *pTab = m_pTabs;
    while(pTab)
    {
        if (pTab->id == tabId)
        {
            m_Page = pTab->page;
            return;
        }
        pTab = pTab->next;
    }
}

size_t Header::addTab(char *string, size_t flags)
{
    Tab *pTab = new Tab;
    pTab->text = string;
    pTab->id = m_NextTabId++;
    pTab->flags = flags;
    pTab->page = 0;
    pTab->next = 0;

    Tab *_pTab = m_pTabs;
    if (!m_pTabs)
    {
        m_pTabs = pTab;
        return pTab->id;
    }

    while(_pTab->next)
        _pTab = _pTab->next;
    _pTab->next = pTab;

    update();

    return pTab->id;
}

<commit_msg>Fix line drawing in the TUI header to use sane co-ordinates for lines.<commit_after>/*
 * Copyright (c) 2008 James Molloy, Jörg Pfähler, Matthew Iselin
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include "Header.h"
#include <pedigree_config.h>

#include <graphics/Graphics.h>

extern PedigreeGraphics::Framebuffer *g_pFramebuffer;

uint32_t g_BorderColour                    = 0x5096; // {150, 80, 0,0};
uint32_t g_TabBackgroundColour             = 0; // {0, 0, 0,0};
uint32_t g_TabTextColour                   = 0x6496; // {150, 100, 0,0};
uint32_t g_SelectedTabBackgroundColour     = 0x6496; // {150, 100, 0,0};
uint32_t g_SelectedTabTextColour           = 0xFFFFFF; // {255, 255, 255,0};
uint32_t g_TextColour                      = 0xFFFFFF; // {255, 255, 255,0};
uint32_t g_MainBackgroundColour            = 0; // {0, 0, 0,0};
size_t g_FontSize = 16;

Header::Header(size_t nWidth) :
    m_nWidth(nWidth), m_Page(0), m_LastPage(0), m_pFont(0),
    m_pTabs(0), m_NextTabId(0), m_pFramebuffer(0)
{
    m_pFont = new Font(g_FontSize, "/system/fonts/DejaVuSansMono-BoldOblique.ttf", false, nWidth);
    g_FontSize = m_pFont->getHeight();

    int result = pedigree_config_query("select * from 'colour-scheme';");
    if (result == -1)
    {
        log("Unable to query config!");
        return;
    }

    char buf[256];
    if (pedigree_config_was_successful(result) != 0)
    {
        pedigree_config_get_error_message(result, buf, 256);
        log(buf);
        return;
    }

    while (pedigree_config_nextrow(result) == 0)
    {
        memset (buf, 0, 256);
        pedigree_config_getstr_n (result, 0, buf, 256);
        rgb_t rgb;
        rgb.r = pedigree_config_getnum_n (result, 1);
        rgb.g = pedigree_config_getnum_n (result, 2);
        rgb.b = pedigree_config_getnum_n (result, 3);
        rgb.a = 0;

        if (!strcmp(buf, "border"))
        {
            g_BorderColour = PedigreeGraphics::createRgb(rgb.r, rgb.g, rgb.b);
            g_TabBackgroundColour = PedigreeGraphics::createRgb(rgb.r, rgb.g, rgb.b);
        }
        else if (!strcmp(buf, "fill"))
            g_SelectedTabBackgroundColour = PedigreeGraphics::createRgb(rgb.r, rgb.g, rgb.b);
        else if (!strcmp(buf, "selected-text"))
            g_SelectedTabTextColour = PedigreeGraphics::createRgb(rgb.r, rgb.g, rgb.b);
        else if (!strcmp(buf, "text"))
        {
            g_TextColour = PedigreeGraphics::createRgb(rgb.r, rgb.g, rgb.b);
            g_TabTextColour = PedigreeGraphics::createRgb(rgb.r, rgb.g, rgb.b);
        }
        else if (!strcmp(buf, "tui-background"))
            g_MainBackgroundColour = PedigreeGraphics::createRgb(rgb.r, rgb.g, rgb.b);
    }
    pedigree_config_freeresult(result);

}

Header::~Header()
{
    delete m_pFont;
}

size_t Header::getHeight()
{
    return g_FontSize+5;
}

void Header::render(rgb_t *pBuffer, DirtyRectangle &rect)
{
    size_t charWidth = m_pFont->getWidth();

    if(!m_pFramebuffer)
    {
        m_pFramebuffer = g_pFramebuffer->createChild(0, 0, m_nWidth, g_FontSize + 5);
        if(!m_pFramebuffer)
            return;
        else if(!m_pFramebuffer->getRawBuffer())
            return;
    }

    // Set up the dirty rectangle to cover the entire header area.
    rect.point(0, 0);
    rect.point(m_nWidth, g_FontSize+5);

    // Height = font size + 2 px top and bottom + border 1px =
    // font-size + 5px.
    m_pFramebuffer->line(0, g_FontSize + 4, m_nWidth, g_FontSize + 4, g_BorderColour, PedigreeGraphics::Bits24_Rgb);

    size_t offset = 0;
    if (m_Page != 0)
    {
        // Render a left-double arrow.
        offset = renderString("<", offset, 2, g_TextColour, g_MainBackgroundColour);
    }

    Tab *pTab = m_pTabs;
    while (pTab)
    {
        if (pTab->page == m_Page)
        {
            // Add 5 pixels.
            offset += 5;

            uint32_t foreColour = g_TextColour;
            if (pTab->flags & TAB_SELECTED)
                foreColour = g_SelectedTabTextColour;
            else if (pTab->flags & TAB_SELECTABLE)
                foreColour = g_TabTextColour;

            uint32_t backColour = g_MainBackgroundColour;
            if (pTab->flags & TAB_SELECTED)
                backColour = g_SelectedTabBackgroundColour;
            else if (pTab->flags & TAB_SELECTABLE)
                backColour = g_TabBackgroundColour;

            // Fill to background colour.
            m_pFramebuffer->rect(offset - 4, 0, strlen(pTab->text) * charWidth + 10, g_FontSize + 4, backColour, PedigreeGraphics::Bits24_Rgb);

            offset = renderString(pTab->text, offset, 2, foreColour, backColour);

            offset += 5;
            // Add a seperator
            m_pFramebuffer->line(offset, 0, offset, g_FontSize + 4, g_BorderColour, PedigreeGraphics::Bits24_Rgb);
        }
        pTab = pTab->next;
    }

    if (m_Page != m_LastPage)
    {
        offset += 5;
        // Render a right-double arrow.
        offset = renderString(">", offset, 2, g_TextColour, g_MainBackgroundColour);
    }
}

size_t Header::renderString(const char *str, size_t x, size_t y, uint32_t f, uint32_t b)
{
    while (*str)
        x += m_pFont->render(m_pFramebuffer, *str++, x, y, f, b);
    return x;
}

void Header::update()
{
    size_t charWidth = m_pFont->getWidth();

    // Here we must run through the list of tabs and assign each a page number.
    size_t offset = 0;
    size_t page = 0;

    // Leave room for a left-arrow.
    offset += charWidth + 5;

    Tab *pTab = m_pTabs;
    while (pTab)
    {
        offset += 5 + strlen(pTab->text)*charWidth + 5;
        if (offset >= m_nWidth - charWidth - 5)
        {
            page ++;
            offset = charWidth + 5;
        }
        pTab->page = page;

        pTab = pTab->next;
    }

    m_LastPage = page;
}

void Header::select(size_t tabId)
{
    Tab *pTab = m_pTabs;
    while(pTab)
    {
        if (pTab->id == tabId)
            pTab->flags |= TAB_SELECTED;
        else
            pTab->flags &= ~TAB_SELECTED;
        pTab = pTab->next;
    }
}

void Header::centreOn(size_t tabId)
{
    Tab *pTab = m_pTabs;
    while(pTab)
    {
        if (pTab->id == tabId)
        {
            m_Page = pTab->page;
            return;
        }
        pTab = pTab->next;
    }
}

size_t Header::addTab(char *string, size_t flags)
{
    Tab *pTab = new Tab;
    pTab->text = string;
    pTab->id = m_NextTabId++;
    pTab->flags = flags;
    pTab->page = 0;
    pTab->next = 0;

    Tab *_pTab = m_pTabs;
    if (!m_pTabs)
    {
        m_pTabs = pTab;
        return pTab->id;
    }

    while(_pTab->next)
        _pTab = _pTab->next;
    _pTab->next = pTab;

    update();

    return pTab->id;
}

<|endoftext|>


<commit_before><commit_msg>Add missing header.<commit_after><|endoftext|>


<commit_before><commit_msg>Update SAMER08F.cpp<commit_after><|endoftext|>


<commit_before>/**
* Copyright 2015 Telefonica Investigación y Desarrollo, S.A.U
*
* This file is part of iotagent project.
*
* iotagent is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published
* by the Free Software Foundation, either version 3 of the License,
* or (at your option) any later version.
*
* iotagent is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with iotagent. If not, see http://www.gnu.org/licenses/.
*
* For those usages not covered by the GNU Affero General Public License
* please contact with iot_support at tid dot es
*/
#include <iostream>

#include <time.h>
#include <algorithm>
#include "store_const.h"
#include "service_mgmt_collection.h"
#include "service_collection.h"
#include "iota_exception.h"
#include "protocol_collection.h"

iota::ServiceMgmtCollection::ServiceMgmtCollection() {
  setBBDD(iota::store::types::MANAGER_SERVICE_TABLE);
};

iota::ServiceMgmtCollection::ServiceMgmtCollection(ServiceMgmtCollection& dc) {
};

iota::ServiceMgmtCollection::~ServiceMgmtCollection() {
};

/*void iota::ServiceMgmtCollection::fillSharKey(mongo::BSONObjBuilder &obj)
{
    // CLAVE DE SHARD  service, name
    if (_m_device._name.empty())
    {
        throw std::runtime_error("ServiceMgmtCollection::fillSharKey name is needed as shardKey");
    }
    obj.append("name", _m_device._name);

    if (_m_device._service.empty())
    {
        throw std::runtime_error("ServiceMgmtCollection::fillSharKey service is needed as shardKey");
    }
    obj.append("service", _m_device._service);

}*/

const std::string & iota::ServiceMgmtCollection::getPostSchema() const{
  return _POST_SCHEMA;
}

const std::string iota::ServiceMgmtCollection::_POST_SCHEMA(
  "{\"$schema\": \"http://json-schema.org/draft-04/schema#\","
  "\"title\": \"Service\","
  "\"description\": \"A service\","
  "\"additionalProperties\":false,"
  "\"type\": \"object\","
  "\"properties\": {"
  "\"services\": {"
  "\"type\":\"array\","
  "\"id\": \"services\","
  "\"items\":{"
  "\"type\":\"object\","
  "\"additionalProperties\":false,"
  "\"id\": \"0\","
  "\"properties\":{"
  "\"protocol\": {"
  "\"type\":\"array\","
  "\"id\": \"protocol\","
  "\"items\":{"
  "\"type\":\"string\""
  "},\"minItems\": 1"
  "},"
  "\"entity_type\": {"
  "\"description\": \"default entity_type, if a device has not got entity_type uses this\","
  "\"type\": \"string\""
  "},"
  "\"apikey\": {"
  "\"description\": \"apikey\","
  "\"type\": \"string\""
  "},"
  "\"token\": {"
  "\"description\": \"token\","
  "\"type\": \"string\""
  "},"
  "\"cbroker\": {"
  "\"description\": \"uri for the context broker\","
  "\"type\": \"string\","
  "\"format\": \"uri\","
  "\"minLength\":1"
  "},"
  "\"outgoing_route\": {"
  "\"description\": \"VPN/GRE tunnel identifier\","
  "\"type\": \"string\""
  "},"
  "\"attributes\": {"
  "\"type\":\"array\","
  "\"id\": \"attributes\","
  "\"items\":{"
  "\"type\":\"object\","
  "\"additionalProperties\":false,"
  "\"id\": \"0\","
  "\"properties\":{"
  "\"object_id\": {"
  "\"description\": \"The unique identifier by service for a device\","
  "\"type\": \"string\""
  "},"
  "\"name\": {"
  "\"description\": \"Name of the entity, if it does not exits use device_id\","
  "\"type\": \"string\""
  "},"
  "\"type\": {"
  "\"description\": \"type of the entity\","
  "\"type\": \"string\""
  "}"
  "}"
  "}"
  "},"
  "\"static_attributes\": {"
  "\"type\":\"array\","
  "\"id\": \"static_attributes\","
  "\"items\":{"
  "\"type\":\"object\","
  "\"additionalProperties\":false,"
  "\"id\": \"0\","
  "\"properties\":{"
  "\"value\": {"
  "\"description\": \"The unique identifier by service for a device\","
  "\"type\": \"string\""
  "},"
  "\"name\": {"
  "\"description\": \"Name of the entity, if it does not exits use device_id\","
  "\"type\": \"string\""
  "},"
  "\"type\": {"
  "\"description\": \"type of the entity\","
  "\"type\": \"string\""
  "}"
  "}"
  "}"
  "}"
  "}"
  ",\"required\": [\"apikey\", \"protocol\", \"cbroker\"]"
  "}"
  "}"
  "}"
  ",\"required\": [\"services\"]"
  "}");

int iota::ServiceMgmtCollection::createTableAndIndex() {

  int res = 200;
  //db.SERVICE_MGMT.ensureIndex({"service":1, service_path:1, iotagent:1, protocol:1},{"unique":1})
  mongo::BSONObj indexUni = BSON(iota::store::types::SERVICE << 1 <<
                                      iota::store::types::SERVICE_PATH << 1
                                   << iota::store::types::IOTAGENT << 1 <<
                                      iota::store::types::PROTOCOL_NAME << 1);

  return createIndex(indexUni, true);
}

std::vector<iota::ServiceType> iota::ServiceMgmtCollection::get_services_by_protocol(
              const std::string &protocol_name,
              int limit, int skip){
  std::vector<iota::ServiceType>  result;

  mongo::BSONObj query;
  mongo::BSONObjBuilder fieldsToReturn;
  fieldsToReturn.append(iota::store::types::SERVICE, 1);
  fieldsToReturn.append(iota::store::types::SERVICE_PATH, 1);

  iota::Collection::find(a_queryOptions, query,
                           limit, skip,
                           BSON(iota::store::types::SERVICE << 1 <<
                           iota::store::types::SERVICE_PATH << 1),
                           fieldsToReturn, 0);

  std::string ser, ser_path;
  mongo::BSONObj elto;
  while(more()){
      //TODO  comprobar que no esta repetido
    elto = next();
    ser = elto.getStringField(iota::store::types::SERVICE);
    ser_path = elto.getStringField(iota::store::types::SERVICE_PATH);
    result.push_back(iota::ServiceType(ser, ser_path));
  }

  return result;
}

std::vector<iota::ServiceType> iota::ServiceMgmtCollection::get_services_group_protocol(
              const std::string &protocol_name,
              int limit, int skip){
  std::vector<iota::ServiceType>  result;

  std::vector<mongo::BSONObj> pipeline;
  // TODO  match y sort
  pipeline.push_back( BSON( "$project" <<
       BSON("service" << 1 << "service_path" << 1 << "protocol" <<1)
       ));
  pipeline.push_back( BSON("$group" <<
       BSON("_id" <<
       BSON("service" << "$service" << "service_path"<< "$service_path") <<
       "protocol" << BSON("$addToSet" << "$protocol" ) ))
  );
  mongo::BSONObj res =iota::Collection::aggregate(pipeline, 0);
  /*std::string ser, ser_path;
  mongo::BSONObj elto;
  while(more()){
      //TODO  comprobar que no esta repetido
    elto = next();
    ser = elto.getStringField(iota::store::types::SERVICE);
    ser_path = elto.getStringField(iota::store::types::SERVICE_PATH);
    result.push_back(iota::ServiceType(ser, ser_path));
  }*/

  return result;
}

std::vector<iota::IotagentType> iota::ServiceMgmtCollection::get_iotagents_by_service(
        const std::string & service, const std::string& service_path,
        const std::string& protocol_id,
        int limit, int skip){
  std::vector<iota::IotagentType>  result;

  mongo::BSONObj query;
  mongo::BSONObjBuilder fieldsToReturn;
  fieldsToReturn.append(iota::store::types::IOTAGENT, 1);

  mongo::BSONObjBuilder bson_query;
  bson_query.append(iota::store::types::SERVICE, service);
  ServiceCollection::addServicePath(service_path, bson_query);
  if (!protocol_id.empty()){
    bson_query.append(iota::store::types::PROTOCOL_NAME, protocol_id);
  }

  mongo::BSONObj res = iota::Collection::distinct("iotagent" , bson_query.obj(), 0);

  int count_eltos=0;
  mongo::BSONObjIterator fields (res.getObjectField ("values"));
  while(fields.more()) {
    result.push_back(fields.next().str ());
    count_eltos++;
  }

  // if there is no limit and count is 0, then throw an exception for no data
  if (count_eltos == 0 && limit ==0 && skip ==0){
    throw iota::IotaException(iota::types::RESPONSE_MESSAGE_MISSING_IOTAGENTS,
                              "[protocol:" + protocol_id+
                              "|service: " + service +
                              "|service_path:" + service_path+"]",
                              iota::types::RESPONSE_CODE_DATA_NOT_FOUND);
  }

  return result;
}

void iota::ServiceMgmtCollection::getElementsFromBSON(mongo::BSONObj &obj,
                                std::vector<mongo::BSONObj> &result){

    std::vector<mongo::BSONElement> be = obj.getField(
                                           iota::store::types::SERVICES).Array();
    std::map<std::string, std::string>protocols;
    iota::ProtocolCollection protocolCol;
    protocolCol.fillProtocols(protocols);
    std::map<std::string,std::string>::iterator it;
    std::string descriptionSTR;

    for (unsigned int i = 0; i<be.size(); i++) {
      mongo::BSONObj obj = be[i].embeddedObject();
      //cogemos el protocolo
      if (obj.hasField(iota::store::types::PROTOCOL_NAME)){
         mongo::BSONElement protocolsObj = obj.getField(iota::store::types::PROTOCOL_NAME);
         std::vector<mongo::BSONElement> proArr = protocolsObj.Array();
         for (unsigned int j = 0; j<proArr.size(); j++) {
            std::string protocol_id = proArr[j].str();
            it=protocols.find(protocol_id);
            if (it == protocols.end()){
                std::string errorSTR = "No exists protocol " + protocol_id;
                PION_LOG_ERROR(m_logger, errorSTR);
                throw iota::IotaException(iota::types::RESPONSE_MESSAGE_BAD_REQUEST,
                           errorSTR, iota::types::RESPONSE_CODE_BAD_REQUEST);
            }else{
              descriptionSTR = it->second;
            }
            mongo::BSONObjBuilder newdata;
            newdata.appendElements(obj.removeField(iota::store::types::PROTOCOL_NAME));
            newdata.append(iota::store::types::PROTOCOL_NAME, protocol_id);
            newdata.append(iota::store::types::PROTOCOL_DESCRIPTION, descriptionSTR);
            mongo::BSONObj ddd  = newdata.obj();
            result.push_back(ddd);
         }
      }
   }
}

void iota::ServiceMgmtCollection::fillServices(const std::string &iotagent,
                                               const std::string &resource,
                                std::map<std::string,mongo::BSONObj> &result){

    mongo::BSONObj query = BSON( iota::store::types::IOTAGENT <<
          iotagent << iota::store::types::PROTOCOL << resource);
    find(query);

    mongo::BSONObj elto;
    std::string key;
    while (more()){
      elto = next();
      std::string key(elto.getStringField(iota::store::types::SERVICE));
      key.append("|");
      key.append(elto.getStringField(iota::store::types::SERVICE_PATH));
      PION_LOG_DEBUG(m_logger, "fillServices: " + key);
      result.insert( std::pair<std::string,mongo::BSONObj>(key,elto) );
    }
}

const std::string & iota::ServiceMgmtCollection::get_resource_name(){
  return iota::store::types::PROTOCOL;
}
<commit_msg>clean key variable<commit_after>/**
* Copyright 2015 Telefonica Investigación y Desarrollo, S.A.U
*
* This file is part of iotagent project.
*
* iotagent is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published
* by the Free Software Foundation, either version 3 of the License,
* or (at your option) any later version.
*
* iotagent is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with iotagent. If not, see http://www.gnu.org/licenses/.
*
* For those usages not covered by the GNU Affero General Public License
* please contact with iot_support at tid dot es
*/
#include <iostream>

#include <time.h>
#include <algorithm>
#include "store_const.h"
#include "service_mgmt_collection.h"
#include "service_collection.h"
#include "iota_exception.h"
#include "protocol_collection.h"

iota::ServiceMgmtCollection::ServiceMgmtCollection() {
  setBBDD(iota::store::types::MANAGER_SERVICE_TABLE);
};

iota::ServiceMgmtCollection::ServiceMgmtCollection(ServiceMgmtCollection& dc) {
};

iota::ServiceMgmtCollection::~ServiceMgmtCollection() {
};

/*void iota::ServiceMgmtCollection::fillSharKey(mongo::BSONObjBuilder &obj)
{
    // CLAVE DE SHARD  service, name
    if (_m_device._name.empty())
    {
        throw std::runtime_error("ServiceMgmtCollection::fillSharKey name is needed as shardKey");
    }
    obj.append("name", _m_device._name);

    if (_m_device._service.empty())
    {
        throw std::runtime_error("ServiceMgmtCollection::fillSharKey service is needed as shardKey");
    }
    obj.append("service", _m_device._service);

}*/

const std::string & iota::ServiceMgmtCollection::getPostSchema() const{
  return _POST_SCHEMA;
}

const std::string iota::ServiceMgmtCollection::_POST_SCHEMA(
  "{\"$schema\": \"http://json-schema.org/draft-04/schema#\","
  "\"title\": \"Service\","
  "\"description\": \"A service\","
  "\"additionalProperties\":false,"
  "\"type\": \"object\","
  "\"properties\": {"
  "\"services\": {"
  "\"type\":\"array\","
  "\"id\": \"services\","
  "\"items\":{"
  "\"type\":\"object\","
  "\"additionalProperties\":false,"
  "\"id\": \"0\","
  "\"properties\":{"
  "\"protocol\": {"
  "\"type\":\"array\","
  "\"id\": \"protocol\","
  "\"items\":{"
  "\"type\":\"string\""
  "},\"minItems\": 1"
  "},"
  "\"entity_type\": {"
  "\"description\": \"default entity_type, if a device has not got entity_type uses this\","
  "\"type\": \"string\""
  "},"
  "\"apikey\": {"
  "\"description\": \"apikey\","
  "\"type\": \"string\""
  "},"
  "\"token\": {"
  "\"description\": \"token\","
  "\"type\": \"string\""
  "},"
  "\"cbroker\": {"
  "\"description\": \"uri for the context broker\","
  "\"type\": \"string\","
  "\"format\": \"uri\","
  "\"minLength\":1"
  "},"
  "\"outgoing_route\": {"
  "\"description\": \"VPN/GRE tunnel identifier\","
  "\"type\": \"string\""
  "},"
  "\"attributes\": {"
  "\"type\":\"array\","
  "\"id\": \"attributes\","
  "\"items\":{"
  "\"type\":\"object\","
  "\"additionalProperties\":false,"
  "\"id\": \"0\","
  "\"properties\":{"
  "\"object_id\": {"
  "\"description\": \"The unique identifier by service for a device\","
  "\"type\": \"string\""
  "},"
  "\"name\": {"
  "\"description\": \"Name of the entity, if it does not exits use device_id\","
  "\"type\": \"string\""
  "},"
  "\"type\": {"
  "\"description\": \"type of the entity\","
  "\"type\": \"string\""
  "}"
  "}"
  "}"
  "},"
  "\"static_attributes\": {"
  "\"type\":\"array\","
  "\"id\": \"static_attributes\","
  "\"items\":{"
  "\"type\":\"object\","
  "\"additionalProperties\":false,"
  "\"id\": \"0\","
  "\"properties\":{"
  "\"value\": {"
  "\"description\": \"The unique identifier by service for a device\","
  "\"type\": \"string\""
  "},"
  "\"name\": {"
  "\"description\": \"Name of the entity, if it does not exits use device_id\","
  "\"type\": \"string\""
  "},"
  "\"type\": {"
  "\"description\": \"type of the entity\","
  "\"type\": \"string\""
  "}"
  "}"
  "}"
  "}"
  "}"
  ",\"required\": [\"apikey\", \"protocol\", \"cbroker\"]"
  "}"
  "}"
  "}"
  ",\"required\": [\"services\"]"
  "}");

int iota::ServiceMgmtCollection::createTableAndIndex() {

  int res = 200;
  //db.SERVICE_MGMT.ensureIndex({"service":1, service_path:1, iotagent:1, protocol:1},{"unique":1})
  mongo::BSONObj indexUni = BSON(iota::store::types::SERVICE << 1 <<
                                      iota::store::types::SERVICE_PATH << 1
                                   << iota::store::types::IOTAGENT << 1 <<
                                      iota::store::types::PROTOCOL_NAME << 1);

  return createIndex(indexUni, true);
}

std::vector<iota::ServiceType> iota::ServiceMgmtCollection::get_services_by_protocol(
              const std::string &protocol_name,
              int limit, int skip){
  std::vector<iota::ServiceType>  result;

  mongo::BSONObj query;
  mongo::BSONObjBuilder fieldsToReturn;
  fieldsToReturn.append(iota::store::types::SERVICE, 1);
  fieldsToReturn.append(iota::store::types::SERVICE_PATH, 1);

  iota::Collection::find(a_queryOptions, query,
                           limit, skip,
                           BSON(iota::store::types::SERVICE << 1 <<
                           iota::store::types::SERVICE_PATH << 1),
                           fieldsToReturn, 0);

  std::string ser, ser_path;
  mongo::BSONObj elto;
  while(more()){
      //TODO  comprobar que no esta repetido
    elto = next();
    ser = elto.getStringField(iota::store::types::SERVICE);
    ser_path = elto.getStringField(iota::store::types::SERVICE_PATH);
    result.push_back(iota::ServiceType(ser, ser_path));
  }

  return result;
}

std::vector<iota::ServiceType> iota::ServiceMgmtCollection::get_services_group_protocol(
              const std::string &protocol_name,
              int limit, int skip){
  std::vector<iota::ServiceType>  result;

  std::vector<mongo::BSONObj> pipeline;
  // TODO  match y sort
  pipeline.push_back( BSON( "$project" <<
       BSON("service" << 1 << "service_path" << 1 << "protocol" <<1)
       ));
  pipeline.push_back( BSON("$group" <<
       BSON("_id" <<
       BSON("service" << "$service" << "service_path"<< "$service_path") <<
       "protocol" << BSON("$addToSet" << "$protocol" ) ))
  );
  mongo::BSONObj res =iota::Collection::aggregate(pipeline, 0);
  /*std::string ser, ser_path;
  mongo::BSONObj elto;
  while(more()){
      //TODO  comprobar que no esta repetido
    elto = next();
    ser = elto.getStringField(iota::store::types::SERVICE);
    ser_path = elto.getStringField(iota::store::types::SERVICE_PATH);
    result.push_back(iota::ServiceType(ser, ser_path));
  }*/

  return result;
}

std::vector<iota::IotagentType> iota::ServiceMgmtCollection::get_iotagents_by_service(
        const std::string & service, const std::string& service_path,
        const std::string& protocol_id,
        int limit, int skip){
  std::vector<iota::IotagentType>  result;

  mongo::BSONObj query;
  mongo::BSONObjBuilder fieldsToReturn;
  fieldsToReturn.append(iota::store::types::IOTAGENT, 1);

  mongo::BSONObjBuilder bson_query;
  bson_query.append(iota::store::types::SERVICE, service);
  ServiceCollection::addServicePath(service_path, bson_query);
  if (!protocol_id.empty()){
    bson_query.append(iota::store::types::PROTOCOL_NAME, protocol_id);
  }

  mongo::BSONObj res = iota::Collection::distinct("iotagent" , bson_query.obj(), 0);

  int count_eltos=0;
  mongo::BSONObjIterator fields (res.getObjectField ("values"));
  while(fields.more()) {
    result.push_back(fields.next().str ());
    count_eltos++;
  }

  // if there is no limit and count is 0, then throw an exception for no data
  if (count_eltos == 0 && limit ==0 && skip ==0){
    throw iota::IotaException(iota::types::RESPONSE_MESSAGE_MISSING_IOTAGENTS,
                              "[protocol:" + protocol_id+
                              "|service: " + service +
                              "|service_path:" + service_path+"]",
                              iota::types::RESPONSE_CODE_DATA_NOT_FOUND);
  }

  return result;
}

void iota::ServiceMgmtCollection::getElementsFromBSON(mongo::BSONObj &obj,
                                std::vector<mongo::BSONObj> &result){

    std::vector<mongo::BSONElement> be = obj.getField(
                                           iota::store::types::SERVICES).Array();
    std::map<std::string, std::string>protocols;
    iota::ProtocolCollection protocolCol;
    protocolCol.fillProtocols(protocols);
    std::map<std::string,std::string>::iterator it;
    std::string descriptionSTR;

    for (unsigned int i = 0; i<be.size(); i++) {
      mongo::BSONObj obj = be[i].embeddedObject();
      //cogemos el protocolo
      if (obj.hasField(iota::store::types::PROTOCOL_NAME)){
         mongo::BSONElement protocolsObj = obj.getField(iota::store::types::PROTOCOL_NAME);
         std::vector<mongo::BSONElement> proArr = protocolsObj.Array();
         for (unsigned int j = 0; j<proArr.size(); j++) {
            std::string protocol_id = proArr[j].str();
            it=protocols.find(protocol_id);
            if (it == protocols.end()){
                std::string errorSTR = "No exists protocol " + protocol_id;
                PION_LOG_ERROR(m_logger, errorSTR);
                throw iota::IotaException(iota::types::RESPONSE_MESSAGE_BAD_REQUEST,
                           errorSTR, iota::types::RESPONSE_CODE_BAD_REQUEST);
            }else{
              descriptionSTR = it->second;
            }
            mongo::BSONObjBuilder newdata;
            newdata.appendElements(obj.removeField(iota::store::types::PROTOCOL_NAME));
            newdata.append(iota::store::types::PROTOCOL_NAME, protocol_id);
            newdata.append(iota::store::types::PROTOCOL_DESCRIPTION, descriptionSTR);
            mongo::BSONObj ddd  = newdata.obj();
            result.push_back(ddd);
         }
      }
   }
}

void iota::ServiceMgmtCollection::fillServices(const std::string &iotagent,
                                               const std::string &resource,
                                std::map<std::string,mongo::BSONObj> &result){

    mongo::BSONObj query = BSON( iota::store::types::IOTAGENT <<
          iotagent << iota::store::types::PROTOCOL << resource);
    find(query);

    mongo::BSONObj elto;
    while (more()){
      elto = next();
      std::string key(elto.getStringField(iota::store::types::SERVICE));
      key.append("|");
      key.append(elto.getStringField(iota::store::types::SERVICE_PATH));
      PION_LOG_DEBUG(m_logger, "fillServices: " + key);
      result.insert( std::pair<std::string,mongo::BSONObj>(key,elto) );
    }
}

const std::string & iota::ServiceMgmtCollection::get_resource_name(){
  return iota::store::types::PROTOCOL;
}
<|endoftext|>