<commit_before>/*===================================================================

The Medical Imaging Interaction Toolkit (MITK)

Copyright (c) German Cancer Research Center,
Division of Medical and Biological Informatics.
All rights reserved.

This software is distributed WITHOUT ANY WARRANTY; without
even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE.

See LICENSE.txt or http://www.mitk.org for details.

===================================================================*/

#include <mitkImageToUnstructuredGridFilter.h>

#include <vtkSmartPointer.h>
#include <vtkPoints.h>
#include <vtkUnstructuredGrid.h>
#include <vtkPolyVertex.h>

#include <itkImageRegionIterator.h>

#include <mitkImageAccessByItk.h>

mitk::ImageToUnstructuredGridFilter::ImageToUnstructuredGridFilter():
m_NumberOfExtractedPoints(0),
m_Threshold(-0.1)
{
  this->m_UnstructGrid = mitk::UnstructuredGrid::New();
}

mitk::ImageToUnstructuredGridFilter::~ImageToUnstructuredGridFilter(){}

void mitk::ImageToUnstructuredGridFilter::GenerateData()
{
  mitk::UnstructuredGrid::Pointer unstructGrid = this->GetOutput();
  const mitk::Image* image = this->GetInput();

  if(image == nullptr || !image->IsInitialized())
  {
    MITK_ERROR << "Wrong input image set" << std::endl;
    return;
  }

  m_Geometry = image->GetGeometry();

  m_NumberOfExtractedPoints = 0;

  AccessByItk(image, ExtractPoints)
}

void mitk::ImageToUnstructuredGridFilter::SetInput(const mitk::Image* image)
{
  this->ProcessObject::SetNthInput(0, const_cast< mitk::Image* >( image ) );
}

const mitk::Image* mitk::ImageToUnstructuredGridFilter::GetInput(void) const
{
  return this->GetInput();
}

mitk::Image* mitk::ImageToUnstructuredGridFilter::GetInput(void)
{
  if (this->GetNumberOfInputs() < 1)
  {
    MITK_ERROR << "No input set" << std::endl;
    return nullptr;
  }

  return static_cast< mitk::Image* >( this->ProcessObject::GetInput(0) );
}

template<typename TPixel, unsigned int VImageDimension>
void mitk::ImageToUnstructuredGridFilter::
           ExtractPoints(const itk::Image<TPixel, VImageDimension>* image)
{
  typedef itk::Image<TPixel, VImageDimension> InputImageType;
  typename itk::ImageRegionConstIterator<InputImageType> it(image, image->GetRequestedRegion());

  vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New();

  it.GoToBegin();
  while( !it.IsAtEnd() )
  {
    if(it.Get() >= m_Threshold)
    {
      mitk::Point3D imagePoint;
      mitk::Point3D worldPoint;

      imagePoint[0] = it.GetIndex()[0];
      imagePoint[1] = it.GetIndex()[1];
      imagePoint[2] = it.GetIndex()[2];

      m_Geometry->IndexToWorld(imagePoint, worldPoint);

      points->InsertNextPoint(worldPoint[0],worldPoint[1],worldPoint[2]);
      m_NumberOfExtractedPoints++;
    }
    ++it;
  }

  vtkSmartPointer<vtkPolyVertex> verts = vtkSmartPointer<vtkPolyVertex>::New();

  verts->GetPointIds()->SetNumberOfIds(m_NumberOfExtractedPoints);
  for(int i=0; i<m_NumberOfExtractedPoints; i++)
  {
    verts->GetPointIds()->SetId(i,i);
  }

  vtkSmartPointer<vtkUnstructuredGrid> uGrid = vtkSmartPointer<vtkUnstructuredGrid>::New();
  uGrid->Allocate(1);

  uGrid->InsertNextCell(verts->GetCellType(), verts->GetPointIds());
  uGrid->SetPoints(points);

  m_UnstructGrid->SetVtkUnstructuredGrid(uGrid);
}

void mitk::ImageToUnstructuredGridFilter::SetThreshold(double threshold)
{
  this->m_Threshold = threshold;
}

double mitk::ImageToUnstructuredGridFilter::GetThreshold()
{
  return this->m_Threshold;
}

void mitk::ImageToUnstructuredGridFilter::GenerateOutputInformation()
{
  mitk::Image::ConstPointer inputImage = this->GetInput();

  m_UnstructGrid = this->GetOutput();

  itkDebugMacro(<<"GenerateOutputInformation()");

  if(inputImage.IsNull()) return;
}
<commit_msg>Fixed build error on windows<commit_after>/*===================================================================

The Medical Imaging Interaction Toolkit (MITK)

Copyright (c) German Cancer Research Center,
Division of Medical and Biological Informatics.
All rights reserved.

This software is distributed WITHOUT ANY WARRANTY; without
even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE.

See LICENSE.txt or http://www.mitk.org for details.

===================================================================*/

#include <mitkImageToUnstructuredGridFilter.h>

#include <vtkSmartPointer.h>
#include <vtkPoints.h>
#include <vtkUnstructuredGrid.h>
#include <vtkPolyVertex.h>

#include <itkImageRegionIterator.h>

#include <mitkImageAccessByItk.h>

mitk::ImageToUnstructuredGridFilter::ImageToUnstructuredGridFilter():
m_NumberOfExtractedPoints(0),
m_Threshold(-0.1)
{
  this->m_UnstructGrid = mitk::UnstructuredGrid::New();
}

mitk::ImageToUnstructuredGridFilter::~ImageToUnstructuredGridFilter(){}

void mitk::ImageToUnstructuredGridFilter::GenerateData()
{
  mitk::UnstructuredGrid::Pointer unstructGrid = this->GetOutput();
  const mitk::Image* image = this->GetInput();

  if(image == nullptr || !image->IsInitialized())
  {
    MITK_ERROR << "Wrong input image set" << std::endl;
    return;
  }

  m_Geometry = image->GetGeometry();

  m_NumberOfExtractedPoints = 0;

  AccessByItk(image, ExtractPoints)
}

void mitk::ImageToUnstructuredGridFilter::SetInput(const mitk::Image* image)
{
  this->ProcessObject::SetNthInput(0, const_cast< mitk::Image* >( image ) );
}

const mitk::Image* mitk::ImageToUnstructuredGridFilter::GetInput(void) const
{
  if (this->GetNumberOfInputs() < 1)
  {
    MITK_ERROR << "No input set" << std::endl;
    return nullptr;
  }

  return static_cast<const mitk::Image* >(this->ProcessObject::GetInput(0));
}

mitk::Image* mitk::ImageToUnstructuredGridFilter::GetInput(void)
{
  if (this->GetNumberOfInputs() < 1)
  {
    MITK_ERROR << "No input set" << std::endl;
    return nullptr;
  }

  return static_cast< mitk::Image* >( this->ProcessObject::GetInput(0) );
}

template<typename TPixel, unsigned int VImageDimension>
void mitk::ImageToUnstructuredGridFilter::
           ExtractPoints(const itk::Image<TPixel, VImageDimension>* image)
{
  typedef itk::Image<TPixel, VImageDimension> InputImageType;
  typename itk::ImageRegionConstIterator<InputImageType> it(image, image->GetRequestedRegion());

  vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New();

  it.GoToBegin();
  while( !it.IsAtEnd() )
  {
    if(it.Get() >= m_Threshold)
    {
      mitk::Point3D imagePoint;
      mitk::Point3D worldPoint;

      imagePoint[0] = it.GetIndex()[0];
      imagePoint[1] = it.GetIndex()[1];
      imagePoint[2] = it.GetIndex()[2];

      m_Geometry->IndexToWorld(imagePoint, worldPoint);

      points->InsertNextPoint(worldPoint[0],worldPoint[1],worldPoint[2]);
      m_NumberOfExtractedPoints++;
    }
    ++it;
  }

  vtkSmartPointer<vtkPolyVertex> verts = vtkSmartPointer<vtkPolyVertex>::New();

  verts->GetPointIds()->SetNumberOfIds(m_NumberOfExtractedPoints);
  for(int i=0; i<m_NumberOfExtractedPoints; i++)
  {
    verts->GetPointIds()->SetId(i,i);
  }

  vtkSmartPointer<vtkUnstructuredGrid> uGrid = vtkSmartPointer<vtkUnstructuredGrid>::New();
  uGrid->Allocate(1);

  uGrid->InsertNextCell(verts->GetCellType(), verts->GetPointIds());
  uGrid->SetPoints(points);

  m_UnstructGrid->SetVtkUnstructuredGrid(uGrid);
}

void mitk::ImageToUnstructuredGridFilter::SetThreshold(double threshold)
{
  this->m_Threshold = threshold;
}

double mitk::ImageToUnstructuredGridFilter::GetThreshold()
{
  return this->m_Threshold;
}

void mitk::ImageToUnstructuredGridFilter::GenerateOutputInformation()
{
  mitk::Image::ConstPointer inputImage = this->GetInput();

  m_UnstructGrid = this->GetOutput();

  itkDebugMacro(<<"GenerateOutputInformation()");

  if(inputImage.IsNull()) return;
}
<|endoftext|>


<commit_before>/* -------------------------------------------------------------------------- *
 *                  OpenSim:  ConstantDistanceConstraint.cpp                  *
 * -------------------------------------------------------------------------- *
 * The OpenSim API is a toolkit for musculoskeletal modeling and simulation.  *
 * See http://opensim.stanford.edu and the NOTICE file for more information.  *
 * OpenSim is developed at Stanford University and supported by the US        *
 * National Institutes of Health (U54 GM072970, R24 HD065690) and by DARPA    *
 * through the Warrior Web program.                                           *
 *                                                                            *
 * Copyright (c) 2005-2012 Stanford University and the Authors                *
 * Author(s): Matt S. DeMers                                                  *
 *                                                                            *
 * 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.                                             *
 * -------------------------------------------------------------------------- */

//=============================================================================
// INCLUDES
//=============================================================================
#include <iostream>
#include <math.h>
#include <OpenSim/Common/Function.h>
#include <OpenSim/Common/Constant.h>
#include <OpenSim/Simulation/Model/BodySet.h>
#include <OpenSim/Simulation/Model/Model.h>

#include "ConstantDistanceConstraint.h"
#include "SimbodyEngine.h"

//=============================================================================
// STATICS
//=============================================================================
using namespace std;
using namespace SimTK;
using namespace OpenSim;

//=============================================================================
// CONSTRUCTOR(S) AND DESTRUCTOR
//=============================================================================
//_____________________________________________________________________________
/**
 * Destructor.
 */
ConstantDistanceConstraint::~ConstantDistanceConstraint()
{
}

//=============================================================================
// CONSTRUCTION
//=============================================================================
/* Default constructor.
 */
ConstantDistanceConstraint::ConstantDistanceConstraint() :
    Constraint()
{
    setNull();
    constructInfrastructure();
}

/*
 * Convenience Constructor.
*/
ConstantDistanceConstraint::ConstantDistanceConstraint(
    const PhysicalFrame& body1, const SimTK::Vec3& locationBody1,
    const PhysicalFrame& body2, const SimTK::Vec3& locationBody2,
    const double& distance) : Constraint()
{
    setNull();
    constructInfrastructure();

    setBody1ByName(body1.getName());
    setBody2ByName(body2.getName());
    set_location_body_1(locationBody1);

    set_location_body_2(locationBody2);
    set_constant_distance(distance);
}

/* Set the data members of this ConstantDistanceConstraint to their null values.
 */
void ConstantDistanceConstraint::setNull()
{
    setAuthors("Matt S. DeMers");
}

//_____________________________________________________________________________
/**
 * Connect properties to local pointers.
 */
void ConstantDistanceConstraint::constructProperties()
{
    //Default location and orientation (rotation sequence)
    SimTK::Vec3 origin(0.0, 0.0, 0.0);

    constructProperty_location_body_1(origin);
    constructProperty_location_body_2(origin);

    // Constant distance between points
    constructProperty_constant_distance(SimTK::NaN);
}

void ConstantDistanceConstraint::constructConnectors()
{
    constructConnector<PhysicalFrame>("body_1");
    constructConnector<PhysicalFrame>("body_2");
}

void ConstantDistanceConstraint::extendAddToSystem(SimTK::MultibodySystem& system) const
{
    Super::extendAddToSystem(system);

    // Get underlying mobilized bodies
    const PhysicalFrame& f1 = getConnectee<PhysicalFrame>("body_1");
    const PhysicalFrame& f2 = getConnectee<PhysicalFrame>("body_2");

    SimTK::MobilizedBody b1 = f1.getMobilizedBody();
    SimTK::MobilizedBody b2 = f2.getMobilizedBody();

    // Now create a Simbody Constraint::Rod
    SimTK::Constraint::Rod simtkRod(b1, get_location_body_1(),
                                    b2, get_location_body_2(),
                                    get_constant_distance() );

    // Beyond the const Component get the index so we can access the SimTK::Constraint later
    assignConstraintIndex(simtkRod.getConstraintIndex());
}

//=============================================================================
// GET/SET
//=============================================================================
const PhysicalFrame& ConstantDistanceConstraint::getBody1() const
{
    return getConnectee<Body>("body_1");
}

const PhysicalFrame& ConstantDistanceConstraint::getBody2() const
{
    return getConnectee<PhysicalFrame>("body_2");
}

/*
* Following methods set attributes of the constraint */
void ConstantDistanceConstraint::setBody1ByName(const std::string& aBodyName)
{
    updConnector<PhysicalFrame>("body_1").set_connectee_name(aBodyName);
}

void ConstantDistanceConstraint::setBody2ByName(const std::string& aBodyName)
{
    updConnector<PhysicalFrame>("body_2").set_connectee_name(aBodyName);
}

/** Set the location for point on body 1*/
void ConstantDistanceConstraint::setBody1PointLocation(Vec3 location)
{
    set_location_body_1(location);
}

/** Set the location for point on body 2*/
void ConstantDistanceConstraint::setBody2PointLocation(Vec3 location)
{
    set_location_body_2(location);
}

/** Set the constant distance between the two points*/
void ConstantDistanceConstraint::setConstantDistance(double distance)
{
    set_constant_distance(distance);
}

void ConstantDistanceConstraint::updateFromXMLNode(SimTK::Xml::Element& aNode, int versionNumber)
{
    int documentVersion = versionNumber;
    if (documentVersion < XMLDocument::getLatestVersion()){
        if (documentVersion<30500){
            // replace old properties with latest use of Connectors
            SimTK::Xml::element_iterator body1Element = aNode.element_begin("body_1");
            SimTK::Xml::element_iterator body2Element = aNode.element_begin("body_2");
            std::string body1_name(""), body2_name("");
            // If default constructed then elements not serialized since they are default
            // values. Check that we have associated elements, then extract their values.
            if (body1Element != aNode.element_end())
                body1Element->getValueAs<std::string>(body1_name);
            if (body2Element != aNode.element_end())
                body2Element->getValueAs<std::string>(body2_name);
            XMLDocument::addConnector(aNode, "Connector_PhysicalFrame_", "body_1", body1_name);
            XMLDocument::addConnector(aNode, "Connector_PhysicalFrame_", "body_2", body2_name);
        }
    }

    Super::updateFromXMLNode(aNode, versionNumber);
}// Visual support ConstantDistanceConstraint drawing in SimTK visualizer.
void ConstantDistanceConstraint::generateDecorations(
    bool                                        fixed,
    const ModelDisplayHints&                    hints,
    const SimTK::State&                         state,
    SimTK::Array_<SimTK::DecorativeGeometry>&   appendToThis) const
{
    Super::generateDecorations(fixed, hints, state, appendToThis);
    if (fixed) return;
    const Vec3 pink(1, .6, .8);
    const OpenSim::PhysicalFrame& frame1 = getBody1();
    const Vec3& p_B1 = frame1.getGroundTransform(state)*get_location_body_1();
    const OpenSim::PhysicalFrame& frame2 = getBody2();
    const Vec3& p_B2 = frame2.getGroundTransform(state)*get_location_body_2();
    appendToThis.push_back(
        SimTK::DecorativeLine(p_B1, p_B2).setBodyId(0)
        .setColor(pink).setOpacity(1.0).setLineThickness(.05));
}
<commit_msg>Fixed incorrect template argument for ConstantDistanceConstraint getConnectee<>- should be PhysicalFrame instead of Body. Was only causing build failure in debug.<commit_after>/* -------------------------------------------------------------------------- *
 *                  OpenSim:  ConstantDistanceConstraint.cpp                  *
 * -------------------------------------------------------------------------- *
 * The OpenSim API is a toolkit for musculoskeletal modeling and simulation.  *
 * See http://opensim.stanford.edu and the NOTICE file for more information.  *
 * OpenSim is developed at Stanford University and supported by the US        *
 * National Institutes of Health (U54 GM072970, R24 HD065690) and by DARPA    *
 * through the Warrior Web program.                                           *
 *                                                                            *
 * Copyright (c) 2005-2012 Stanford University and the Authors                *
 * Author(s): Matt S. DeMers                                                  *
 *                                                                            *
 * 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.                                             *
 * -------------------------------------------------------------------------- */

//=============================================================================
// INCLUDES
//=============================================================================
#include <iostream>
#include <math.h>
#include <OpenSim/Common/Function.h>
#include <OpenSim/Common/Constant.h>
#include <OpenSim/Simulation/Model/BodySet.h>
#include <OpenSim/Simulation/Model/Model.h>

#include "ConstantDistanceConstraint.h"
#include "SimbodyEngine.h"

//=============================================================================
// STATICS
//=============================================================================
using namespace std;
using namespace SimTK;
using namespace OpenSim;

//=============================================================================
// CONSTRUCTOR(S) AND DESTRUCTOR
//=============================================================================
//_____________________________________________________________________________
/**
 * Destructor.
 */
ConstantDistanceConstraint::~ConstantDistanceConstraint()
{
}

//=============================================================================
// CONSTRUCTION
//=============================================================================
/* Default constructor.
 */
ConstantDistanceConstraint::ConstantDistanceConstraint() :
    Constraint()
{
    setNull();
    constructInfrastructure();
}

/*
 * Convenience Constructor.
*/
ConstantDistanceConstraint::ConstantDistanceConstraint(
    const PhysicalFrame& body1, const SimTK::Vec3& locationBody1,
    const PhysicalFrame& body2, const SimTK::Vec3& locationBody2,
    const double& distance) : Constraint()
{
    setNull();
    constructInfrastructure();

    setBody1ByName(body1.getName());
    setBody2ByName(body2.getName());
    set_location_body_1(locationBody1);

    set_location_body_2(locationBody2);
    set_constant_distance(distance);
}

/* Set the data members of this ConstantDistanceConstraint to their null values.
 */
void ConstantDistanceConstraint::setNull()
{
    setAuthors("Matt S. DeMers");
}

//_____________________________________________________________________________
/**
 * Connect properties to local pointers.
 */
void ConstantDistanceConstraint::constructProperties()
{
    //Default location and orientation (rotation sequence)
    SimTK::Vec3 origin(0.0, 0.0, 0.0);

    constructProperty_location_body_1(origin);
    constructProperty_location_body_2(origin);

    // Constant distance between points
    constructProperty_constant_distance(SimTK::NaN);
}

void ConstantDistanceConstraint::constructConnectors()
{
    constructConnector<PhysicalFrame>("body_1");
    constructConnector<PhysicalFrame>("body_2");
}

void ConstantDistanceConstraint::extendAddToSystem(SimTK::MultibodySystem& system) const
{
    Super::extendAddToSystem(system);

    // Get underlying mobilized bodies
    const PhysicalFrame& f1 = getConnectee<PhysicalFrame>("body_1");
    const PhysicalFrame& f2 = getConnectee<PhysicalFrame>("body_2");

    SimTK::MobilizedBody b1 = f1.getMobilizedBody();
    SimTK::MobilizedBody b2 = f2.getMobilizedBody();

    // Now create a Simbody Constraint::Rod
    SimTK::Constraint::Rod simtkRod(b1, get_location_body_1(),
                                    b2, get_location_body_2(),
                                    get_constant_distance() );

    // Beyond the const Component get the index so we can access the SimTK::Constraint later
    assignConstraintIndex(simtkRod.getConstraintIndex());
}

//=============================================================================
// GET/SET
//=============================================================================
const PhysicalFrame& ConstantDistanceConstraint::getBody1() const
{
    return getConnectee<PhysicalFrame>("body_1");
}

const PhysicalFrame& ConstantDistanceConstraint::getBody2() const
{
    return getConnectee<PhysicalFrame>("body_2");
}

/*
* Following methods set attributes of the constraint */
void ConstantDistanceConstraint::setBody1ByName(const std::string& aBodyName)
{
    updConnector<PhysicalFrame>("body_1").set_connectee_name(aBodyName);
}

void ConstantDistanceConstraint::setBody2ByName(const std::string& aBodyName)
{
    updConnector<PhysicalFrame>("body_2").set_connectee_name(aBodyName);
}

/** Set the location for point on body 1*/
void ConstantDistanceConstraint::setBody1PointLocation(Vec3 location)
{
    set_location_body_1(location);
}

/** Set the location for point on body 2*/
void ConstantDistanceConstraint::setBody2PointLocation(Vec3 location)
{
    set_location_body_2(location);
}

/** Set the constant distance between the two points*/
void ConstantDistanceConstraint::setConstantDistance(double distance)
{
    set_constant_distance(distance);
}

void ConstantDistanceConstraint::updateFromXMLNode(SimTK::Xml::Element& aNode, int versionNumber)
{
    int documentVersion = versionNumber;
    if (documentVersion < XMLDocument::getLatestVersion()){
        if (documentVersion<30500){
            // replace old properties with latest use of Connectors
            SimTK::Xml::element_iterator body1Element = aNode.element_begin("body_1");
            SimTK::Xml::element_iterator body2Element = aNode.element_begin("body_2");
            std::string body1_name(""), body2_name("");
            // If default constructed then elements not serialized since they are default
            // values. Check that we have associated elements, then extract their values.
            if (body1Element != aNode.element_end())
                body1Element->getValueAs<std::string>(body1_name);
            if (body2Element != aNode.element_end())
                body2Element->getValueAs<std::string>(body2_name);
            XMLDocument::addConnector(aNode, "Connector_PhysicalFrame_", "body_1", body1_name);
            XMLDocument::addConnector(aNode, "Connector_PhysicalFrame_", "body_2", body2_name);
        }
    }

    Super::updateFromXMLNode(aNode, versionNumber);
}// Visual support ConstantDistanceConstraint drawing in SimTK visualizer.
void ConstantDistanceConstraint::generateDecorations(
    bool                                        fixed,
    const ModelDisplayHints&                    hints,
    const SimTK::State&                         state,
    SimTK::Array_<SimTK::DecorativeGeometry>&   appendToThis) const
{
    Super::generateDecorations(fixed, hints, state, appendToThis);
    if (fixed) return;
    const Vec3 pink(1, .6, .8);
    const OpenSim::PhysicalFrame& frame1 = getBody1();
    const Vec3& p_B1 = frame1.getGroundTransform(state)*get_location_body_1();
    const OpenSim::PhysicalFrame& frame2 = getBody2();
    const Vec3& p_B2 = frame2.getGroundTransform(state)*get_location_body_2();
    appendToThis.push_back(
        SimTK::DecorativeLine(p_B1, p_B2).setBodyId(0)
        .setColor(pink).setOpacity(1.0).setLineThickness(.05));
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2016 dresden elektronik ingenieurtechnik gmbh.
 * All rights reserved.
 *
 * The software in this package is published under the terms of the BSD
 * style license a copy of which has been included with this distribution in
 * the LICENSE.txt file.
 *
 */
#include "de_web_plugin.h"
#include "de_web_plugin_private.h"

/*! Inits permit join manager.

    The manager will observe and ensure the global permit join state.
 */
void DeRestPluginPrivate::initPermitJoin()
{
    permitJoinFlag = false;
    permitJoinTimer = new QTimer(this);
    permitJoinTimer->setSingleShot(false);
    connect(permitJoinTimer, SIGNAL(timeout()),
            this, SLOT(permitJoinTimerFired()));
    permitJoinTimer->start(1000);
    permitJoinLastSendTime = QTime::currentTime();

    resendPermitJoinTimer = new QTimer(this);
    resendPermitJoinTimer->setSingleShot(true);
    connect(resendPermitJoinTimer, SIGNAL(timeout()),
            this, SLOT(resendPermitJoinTimerFired()));
}

/*! Sets the permit join interval

    \param duration specifies the interval in which joining is enabled
               - 0 disabled
               - 1..254 duration in seconds until joining will be disabled
               - 255 always permit
 * \return
 */
bool DeRestPluginPrivate::setPermitJoinDuration(uint8_t duration)
{
    if (gwPermitJoinDuration != duration)
    {
        gwPermitJoinDuration = duration;
    }

    // force resend
    permitJoinLastSendTime = QTime();
    return true;
}

/*! Handle broadcasting of permit join interval.

    This is done every PERMIT_JOIN_SEND_INTERVAL to ensure
    any node in the network has the same settings.
 */
void DeRestPluginPrivate::permitJoinTimerFired()
{
    Q_Q(DeRestPlugin);
    if (!q->pluginActive())
    {
        return;
    }

    if ((gwPermitJoinDuration > 0) && (gwPermitJoinDuration < 255))
    {
        permitJoinFlag = true;
        gwPermitJoinDuration--;
        updateEtag(gwConfigEtag); // update Etag so that webApp can count down permitJoin duration

        //periodically check if there are deleted lights and undelete them
        if (gwPermitJoinDuration % 10 == 0)
        {
            std::vector<LightNode>::iterator i = nodes.begin();
            std::vector<LightNode>::iterator end = nodes.end();

            for (; i != end; ++i)
            {
                if (i->state() == LightNode::StateDeleted)
                {
                    if (i->isAvailable())
                    {
                        i->setState(LightNode::StateNormal);
                        i->setNeedSaveDatabase(true);
                        queSaveDb(DB_LIGHTS, DB_SHORT_SAVE_DELAY);
                    }
                }
            }
        }
    }

    if (gwPermitJoinDuration == 0 && permitJoinFlag)
    {
        permitJoinFlag = false;
    }

    if (!isInNetwork())
    {
        return;
    }

    if (gwPermitJoinDuration == 0 && otauLastBusyTimeDelta() < (60 * 5))
    {
        // don't pollute channel while OTA is running
        return;
    }

    QTime now = QTime::currentTime();
    int diff = permitJoinLastSendTime.msecsTo(now);

    if (!permitJoinLastSendTime.isValid() || (diff > PERMIT_JOIN_SEND_INTERVAL))
    {
        deCONZ::ApsDataRequest apsReq;
        quint8 tcSignificance = 0x01;

        apsReq.setDstAddressMode(deCONZ::ApsNwkAddress);
        apsReq.dstAddress().setNwk(deCONZ::BroadcastRouters);
        apsReq.setProfileId(ZDP_PROFILE_ID);
        apsReq.setClusterId(ZDP_MGMT_PERMIT_JOINING_REQ_CLID);
        apsReq.setDstEndpoint(ZDO_ENDPOINT);
        apsReq.setSrcEndpoint(ZDO_ENDPOINT);
        apsReq.setTxOptions(0);
        apsReq.setRadius(0);

        QDataStream stream(&apsReq.asdu(), QIODevice::WriteOnly);
        stream.setByteOrder(QDataStream::LittleEndian);

        stream << (uint8_t)now.second(); // seqno
        stream << gwPermitJoinDuration;
        stream << tcSignificance;

        DBG_Assert(apsCtrl != 0);

        if (!apsCtrl)
        {
            return;
        }

        // set for own node
        apsCtrl->setPermitJoin(gwPermitJoinDuration);

        // broadcast
        if (apsCtrl->apsdeDataRequest(apsReq) == deCONZ::Success)
        {
            DBG_Printf(DBG_INFO, "send permit join, duration: %d\n", gwPermitJoinDuration);
            permitJoinLastSendTime = now;
        }
        else
        {
            DBG_Printf(DBG_INFO, "send permit join failed\n");
        }
    }
}

/*! Check if permitJoin is > 60 seconds then resend permitjoin with 60 seconds
 */
void DeRestPluginPrivate::resendPermitJoinTimerFired()
{
    resendPermitJoinTimer->stop();
    if (gwPermitJoinDuration <= 1)
    {
        if (gwPermitJoinResend > 0)
        {

            if (gwPermitJoinResend >= 60)
            {
                setPermitJoinDuration(60);
            }
            else
            {
                setPermitJoinDuration(gwPermitJoinResend);
            }
            gwPermitJoinResend -= 60;
            updateEtag(gwConfigEtag);
            if (gwPermitJoinResend <= 0)
            {
                gwPermitJoinResend = 0;
                return;
            }

        }
        else if (gwPermitJoinResend == 0)
        {
            setPermitJoinDuration(0);
            return;
        }
    }
    else if (gwPermitJoinResend == 0)
    {
        setPermitJoinDuration(0);
        return;
    }
    resendPermitJoinTimer->start(1000);
}
<commit_msg>Check apsCtrl in permitJoinTimerFired()<commit_after>/*
 * Copyright (c) 2016 dresden elektronik ingenieurtechnik gmbh.
 * All rights reserved.
 *
 * The software in this package is published under the terms of the BSD
 * style license a copy of which has been included with this distribution in
 * the LICENSE.txt file.
 *
 */
#include "de_web_plugin.h"
#include "de_web_plugin_private.h"

/*! Inits permit join manager.

    The manager will observe and ensure the global permit join state.
 */
void DeRestPluginPrivate::initPermitJoin()
{
    permitJoinFlag = false;
    permitJoinTimer = new QTimer(this);
    permitJoinTimer->setSingleShot(false);
    connect(permitJoinTimer, SIGNAL(timeout()),
            this, SLOT(permitJoinTimerFired()));
    permitJoinTimer->start(1000);
    permitJoinLastSendTime = QTime::currentTime();

    resendPermitJoinTimer = new QTimer(this);
    resendPermitJoinTimer->setSingleShot(true);
    connect(resendPermitJoinTimer, SIGNAL(timeout()),
            this, SLOT(resendPermitJoinTimerFired()));
}

/*! Sets the permit join interval

    \param duration specifies the interval in which joining is enabled
               - 0 disabled
               - 1..254 duration in seconds until joining will be disabled
               - 255 always permit
 * \return
 */
bool DeRestPluginPrivate::setPermitJoinDuration(uint8_t duration)
{
    if (gwPermitJoinDuration != duration)
    {
        gwPermitJoinDuration = duration;
    }

    // force resend
    permitJoinLastSendTime = QTime();
    return true;
}

/*! Handle broadcasting of permit join interval.

    This is done every PERMIT_JOIN_SEND_INTERVAL to ensure
    any node in the network has the same settings.
 */
void DeRestPluginPrivate::permitJoinTimerFired()
{
    Q_Q(DeRestPlugin);
    if (!q->pluginActive() || !apsCtrl)
    {
        return;
    }

    if ((gwPermitJoinDuration > 0) && (gwPermitJoinDuration < 255))
    {
        permitJoinFlag = true;
        gwPermitJoinDuration--;
        updateEtag(gwConfigEtag); // update Etag so that webApp can count down permitJoin duration

        //periodically check if there are deleted lights and undelete them
        if (gwPermitJoinDuration % 10 == 0)
        {
            std::vector<LightNode>::iterator i = nodes.begin();
            std::vector<LightNode>::iterator end = nodes.end();

            for (; i != end; ++i)
            {
                if (i->state() == LightNode::StateDeleted)
                {
                    if (i->isAvailable())
                    {
                        i->setState(LightNode::StateNormal);
                        i->setNeedSaveDatabase(true);
                        queSaveDb(DB_LIGHTS, DB_SHORT_SAVE_DELAY);
                    }
                }
            }
        }
    }

    if (gwPermitJoinDuration == 0 && permitJoinFlag)
    {
        permitJoinFlag = false;
    }

    if (!isInNetwork())
    {
        return;
    }

    if (gwPermitJoinDuration == 0 && otauLastBusyTimeDelta() < (60 * 5))
    {
        // don't pollute channel while OTA is running
        return;
    }

    QTime now = QTime::currentTime();
    int diff = permitJoinLastSendTime.msecsTo(now);

    if (!permitJoinLastSendTime.isValid() || (diff > PERMIT_JOIN_SEND_INTERVAL))
    {
        deCONZ::ApsDataRequest apsReq;
        quint8 tcSignificance = 0x01;

        apsReq.setDstAddressMode(deCONZ::ApsNwkAddress);
        apsReq.dstAddress().setNwk(deCONZ::BroadcastRouters);
        apsReq.setProfileId(ZDP_PROFILE_ID);
        apsReq.setClusterId(ZDP_MGMT_PERMIT_JOINING_REQ_CLID);
        apsReq.setDstEndpoint(ZDO_ENDPOINT);
        apsReq.setSrcEndpoint(ZDO_ENDPOINT);
        apsReq.setTxOptions(0);
        apsReq.setRadius(0);

        QDataStream stream(&apsReq.asdu(), QIODevice::WriteOnly);
        stream.setByteOrder(QDataStream::LittleEndian);

        stream << (uint8_t)now.second(); // seqno
        stream << gwPermitJoinDuration;
        stream << tcSignificance;

        DBG_Assert(apsCtrl != 0);

        if (!apsCtrl)
        {
            return;
        }

        // set for own node
        apsCtrl->setPermitJoin(gwPermitJoinDuration);

        // broadcast
        if (apsCtrl->apsdeDataRequest(apsReq) == deCONZ::Success)
        {
            DBG_Printf(DBG_INFO, "send permit join, duration: %d\n", gwPermitJoinDuration);
            permitJoinLastSendTime = now;
        }
        else
        {
            DBG_Printf(DBG_INFO, "send permit join failed\n");
        }
    }
}

/*! Check if permitJoin is > 60 seconds then resend permitjoin with 60 seconds
 */
void DeRestPluginPrivate::resendPermitJoinTimerFired()
{
    resendPermitJoinTimer->stop();
    if (gwPermitJoinDuration <= 1)
    {
        if (gwPermitJoinResend > 0)
        {

            if (gwPermitJoinResend >= 60)
            {
                setPermitJoinDuration(60);
            }
            else
            {
                setPermitJoinDuration(gwPermitJoinResend);
            }
            gwPermitJoinResend -= 60;
            updateEtag(gwConfigEtag);
            if (gwPermitJoinResend <= 0)
            {
                gwPermitJoinResend = 0;
                return;
            }

        }
        else if (gwPermitJoinResend == 0)
        {
            setPermitJoinDuration(0);
            return;
        }
    }
    else if (gwPermitJoinResend == 0)
    {
        setPermitJoinDuration(0);
        return;
    }
    resendPermitJoinTimer->start(1000);
}
<|endoftext|>


<commit_before>/*

Copyright (c) 2007, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include <libtorrent/natpmp.hpp>
#include <libtorrent/io.hpp>
#include <boost/bind.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <asio/ip/host_name.hpp>

using boost::bind;
using namespace libtorrent;
using boost::posix_time::microsec_clock;

natpmp::natpmp(io_service& ios, portmap_callback_t const& cb)
	: m_callback(cb)
	, m_currently_mapping(-1)
	, m_retry_count(0)
	, m_socket(ios)
	, m_send_timer(ios)
	, m_refresh_timer(ios)
	, m_disabled(false)
{
	m_mappings[0].protocol = 2; // tcp
	m_mappings[1].protocol = 1; // udp

#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
	m_log.open("natpmp.log", std::ios::in | std::ios::out | std::ios::trunc);
#endif

	udp::resolver r(ios);
	udp::resolver::iterator i = r.resolve(udp::resolver::query(asio::ip::host_name(), "0"));
	for (;i != udp::resolver_iterator(); ++i)
	{
		if (i->endpoint().address().is_v4()) break;
	}

	if (i == udp::resolver_iterator())
	{
#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
		m_log << "local host name did not resolve to an IPv4 address. "
			"disabling NAT-PMP" << std::endl;
#endif
		m_disabled = true;
		return;
	}

	address_v4 local = i->endpoint().address().to_v4();
#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
	m_log << to_simple_string(microsec_clock::universal_time())
		<< " local ip: " << local.to_string() << std::endl;
#endif

	if ((local.to_ulong() & 0xff000000) != 0x0a000000
		&& (local.to_ulong() & 0xfff00000) != 0xac100000
		&& (local.to_ulong() & 0xffff0000) != 0xaca80000)
	{
		// the local address seems to be an external
		// internet address. Assume it is not behind a NAT
#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
		m_log << "not on a NAT. disabling NAT-PMP" << std::endl;
#endif
		m_disabled = true;
		return;
	}

	// assume the router is located on the local
	// network as x.x.x.1
	// TODO: find a better way to figure out the router IP
	m_nat_endpoint = udp::endpoint(
		address_v4((local.to_ulong() & 0xffffff00) | 1), 5351);

#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
	m_log << "assuming router is at: " << m_nat_endpoint.address().to_string() << std::endl;
#endif

	m_socket.open(udp::v4());
	m_socket.bind(udp::endpoint());
}

void natpmp::set_mappings(int tcp, int udp)
{
	if (m_disabled) return;
	update_mapping(0, tcp);
	update_mapping(1, udp);
}

void natpmp::update_mapping(int i, int port)
{
	natpmp::mapping& m = m_mappings[i];
	if (port <= 0) return;
	if (m.local_port != port)
		m.need_update = true;

	m.local_port = port;
	// prefer the same external port as the local port
	if (m.external_port == 0) m.external_port = port;

	if (m_currently_mapping == -1)
	{
		// the socket is not currently in use
		// send out a mapping request
		m_retry_count = 0;
		send_map_request(i);
		m_socket.async_receive_from(asio::buffer(&m_response_buffer, 16)
			, m_remote, bind(&natpmp::on_reply, this, _1, _2));
	}
}

void natpmp::send_map_request(int i) try
{
	using namespace libtorrent::detail;
	using boost::posix_time::milliseconds;

	assert(m_currently_mapping == -1
		|| m_currently_mapping == i);
	m_currently_mapping = i;
	mapping& m = m_mappings[i];
	char buf[12];
	char* out = buf;
	write_uint8(0, out); // NAT-PMP version
	write_uint8(m.protocol, out); // map "protocol"
	write_uint16(0, out); // reserved
	write_uint16(m.local_port, out); // private port
	write_uint16(m.external_port, out); // requested public port
	int ttl = m.external_port == 0 ? 0 : 3600;
	write_uint32(ttl, out); // port mapping lifetime

#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
	m_log << to_simple_string(microsec_clock::universal_time())
		<< " ==> port map request: " << (m.protocol == 1 ? "udp" : "tcp")
		<< " local: " << m.local_port << " external: " << m.external_port
		<< " ttl: " << ttl << std::endl;
#endif

	m_socket.send_to(asio::buffer(buf, 12), m_nat_endpoint);
	// linear back-off instead of exponential
	++m_retry_count;
	m_send_timer.expires_from_now(milliseconds(250 * m_retry_count));
	m_send_timer.async_wait(bind(&natpmp::resend_request, this, i, _1));
}
catch (std::exception& e)
{
	std::string err = e.what();
}

void natpmp::resend_request(int i, asio::error_code const& e)
{
	using boost::posix_time::hours;
	if (e) return;
	if (m_retry_count >= 9)
	{
		m_mappings[i].need_update = false;
		// try again in two hours
		m_mappings[i].expires
			= boost::posix_time::second_clock::universal_time() + hours(2);
		return;
	}
	send_map_request(i);
}

void natpmp::on_reply(asio::error_code const& e
	, std::size_t bytes_transferred)
{
	using namespace libtorrent::detail;
	using boost::posix_time::seconds;
	if (e) return;

	try
	{

		if (m_remote != m_nat_endpoint)
		{
			m_socket.async_receive_from(asio::buffer(&m_response_buffer, 16)
				, m_remote, bind(&natpmp::on_reply, this, _1, _2));
			return;
		}

		m_send_timer.cancel();

		assert(m_currently_mapping >= 0);
		int i = m_currently_mapping;
		mapping& m = m_mappings[i];

		char* in = m_response_buffer;
		int version = read_uint8(in);
		int cmd = read_uint8(in);
		int result = read_uint16(in);
		int time = read_uint32(in);
		int private_port = read_uint16(in);
		int public_port = read_uint16(in);
		int lifetime = read_uint32(in);

#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
		m_log << to_simple_string(microsec_clock::universal_time())
			<< " <== port map response: " << (cmd - 128 == 1 ? "udp" : "tcp")
			<< " local: " << private_port << " external: " << public_port
			<< " ttl: " << lifetime << std::endl;
#endif

#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
		if (version != 0)
		{
			m_log << "*** unexpected version: " << version << std::endl;
		}
#endif

#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
		if (private_port != m.local_port)
		{
			m_log << "*** unexpected local port: " << private_port << std::endl;
		}
#endif

#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
		if (cmd != 128 + m.protocol)
		{
			m_log << "*** unexpected protocol: " << (cmd - 128) << std::endl;
		}
#endif

		if (public_port == 0 || lifetime == 0)
		{
			// this means the mapping was
			// successfully closed
			m.local_port = 0;
		}
		else
		{
			m.expires = boost::posix_time::second_clock::universal_time()
				+ seconds(int(lifetime * 0.7f));
			m.external_port = public_port;
		}

		if (result != 0)
		{
#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
			m_log << "*** ERROR: " << result << std::endl;
#endif
			std::stringstream errmsg;
			errmsg << "NAT router reports error (" << result << ") ";
			switch (result)
			{
				case 1: errmsg << "Unsupported protocol version"; break;
				case 2: errmsg << "Not authorized to create port map (enable NAT-PMP on your router)"; break;
				case 3: errmsg << "Network failure"; break;
				case 4: errmsg << "Out of resources"; break;
				case 5: errmsg << "Unsupported opcpde"; break;
			}
			throw std::runtime_error(errmsg.str());
		}

		int tcp_port = 0;
		int udp_port = 0;
		if (m.protocol == 1) udp_port = m.external_port;
		else tcp_port = public_port;
		m_callback(tcp_port, udp_port, "");
	}
	catch (std::exception& e)
	{
		using boost::posix_time::hours;
		// try again in two hours
		m_mappings[m_currently_mapping].expires
			= boost::posix_time::second_clock::universal_time() + hours(2);
		m_callback(0, 0, e.what());
	}
	int i = m_currently_mapping;
	m_currently_mapping = -1;
	m_mappings[i].need_update = false;
	update_expiration_timer();
	try_next_mapping(i);
}

void natpmp::update_expiration_timer()
{
	using boost::posix_time::seconds;
	boost::posix_time::ptime now = boost::posix_time::second_clock::universal_time();
	boost::posix_time::ptime min_expire = now + seconds(3600);
	int min_index = -1;
	for (int i = 0; i < 2; ++i)
		if (m_mappings[i].expires < min_expire
			&& m_mappings[i].local_port != 0)
		{
			min_expire = m_mappings[i].expires;
			min_index = i;
		}

	if (min_index >= 0)
	{
		m_refresh_timer.expires_from_now(min_expire - now);
		m_refresh_timer.async_wait(bind(&natpmp::mapping_expired, this, _1, min_index));
	}
}

void natpmp::mapping_expired(asio::error_code const& e, int i)
{
	if (e) return;
#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
	m_log << "*** mapping " << i << " expired, updating" << std::endl;
#endif
	refresh_mapping(i);
}

void natpmp::refresh_mapping(int i)
{
	m_mappings[i].need_update = true;
	if (m_currently_mapping == -1)
	{
		// the socket is not currently in use
		// send out a mapping request
		m_retry_count = 0;
		send_map_request(i);
		m_socket.async_receive_from(asio::buffer(&m_response_buffer, 16)
			, m_remote, bind(&natpmp::on_reply, this, _1, _2));
	}
}

void natpmp::try_next_mapping(int i)
{
	++i;
	if (i >= 2) i = 0;
	if (m_mappings[i].need_update)
		refresh_mapping(i);
}

void natpmp::close()
{
	if (m_disabled) return;
	for (int i = 0; i < 2; ++i)
	{
		if (m_mappings[i].local_port == 0)
			continue;
		m_mappings[i].external_port = 0;
		refresh_mapping(i);
	}
}

<commit_msg>fixes incorrect local IP address check<commit_after>/*

Copyright (c) 2007, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include <libtorrent/natpmp.hpp>
#include <libtorrent/io.hpp>
#include <boost/bind.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <asio/ip/host_name.hpp>

using boost::bind;
using namespace libtorrent;
using boost::posix_time::microsec_clock;

natpmp::natpmp(io_service& ios, portmap_callback_t const& cb)
	: m_callback(cb)
	, m_currently_mapping(-1)
	, m_retry_count(0)
	, m_socket(ios)
	, m_send_timer(ios)
	, m_refresh_timer(ios)
	, m_disabled(false)
{
	m_mappings[0].protocol = 2; // tcp
	m_mappings[1].protocol = 1; // udp

#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
	m_log.open("natpmp.log", std::ios::in | std::ios::out | std::ios::trunc);
#endif

	udp::resolver r(ios);
	udp::resolver::iterator i = r.resolve(udp::resolver::query(asio::ip::host_name(), "0"));
	for (;i != udp::resolver_iterator(); ++i)
	{
		if (i->endpoint().address().is_v4()) break;
	}

	if (i == udp::resolver_iterator())
	{
#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
		m_log << "local host name did not resolve to an IPv4 address. "
			"disabling NAT-PMP" << std::endl;
#endif
		m_disabled = true;
		return;
	}

	address_v4 local = i->endpoint().address().to_v4();
#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
	m_log << to_simple_string(microsec_clock::universal_time())
		<< " local ip: " << local.to_string() << std::endl;
#endif

	if ((local.to_ulong() & 0xff000000) != 0x0a000000
		&& (local.to_ulong() & 0xfff00000) != 0xac100000
		&& (local.to_ulong() & 0xffff0000) != 0xc0a80000)
	{
		// the local address seems to be an external
		// internet address. Assume it is not behind a NAT
#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
		m_log << "not on a NAT. disabling NAT-PMP" << std::endl;
#endif
		m_disabled = true;
		return;
	}

	// assume the router is located on the local
	// network as x.x.x.1
	// TODO: find a better way to figure out the router IP
	m_nat_endpoint = udp::endpoint(
		address_v4((local.to_ulong() & 0xffffff00) | 1), 5351);

#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
	m_log << "assuming router is at: " << m_nat_endpoint.address().to_string() << std::endl;
#endif

	m_socket.open(udp::v4());
	m_socket.bind(udp::endpoint());
}

void natpmp::set_mappings(int tcp, int udp)
{
	if (m_disabled) return;
	update_mapping(0, tcp);
	update_mapping(1, udp);
}

void natpmp::update_mapping(int i, int port)
{
	natpmp::mapping& m = m_mappings[i];
	if (port <= 0) return;
	if (m.local_port != port)
		m.need_update = true;

	m.local_port = port;
	// prefer the same external port as the local port
	if (m.external_port == 0) m.external_port = port;

	if (m_currently_mapping == -1)
	{
		// the socket is not currently in use
		// send out a mapping request
		m_retry_count = 0;
		send_map_request(i);
		m_socket.async_receive_from(asio::buffer(&m_response_buffer, 16)
			, m_remote, bind(&natpmp::on_reply, this, _1, _2));
	}
}

void natpmp::send_map_request(int i) try
{
	using namespace libtorrent::detail;
	using boost::posix_time::milliseconds;

	assert(m_currently_mapping == -1
		|| m_currently_mapping == i);
	m_currently_mapping = i;
	mapping& m = m_mappings[i];
	char buf[12];
	char* out = buf;
	write_uint8(0, out); // NAT-PMP version
	write_uint8(m.protocol, out); // map "protocol"
	write_uint16(0, out); // reserved
	write_uint16(m.local_port, out); // private port
	write_uint16(m.external_port, out); // requested public port
	int ttl = m.external_port == 0 ? 0 : 3600;
	write_uint32(ttl, out); // port mapping lifetime

#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
	m_log << to_simple_string(microsec_clock::universal_time())
		<< " ==> port map request: " << (m.protocol == 1 ? "udp" : "tcp")
		<< " local: " << m.local_port << " external: " << m.external_port
		<< " ttl: " << ttl << std::endl;
#endif

	m_socket.send_to(asio::buffer(buf, 12), m_nat_endpoint);
	// linear back-off instead of exponential
	++m_retry_count;
	m_send_timer.expires_from_now(milliseconds(250 * m_retry_count));
	m_send_timer.async_wait(bind(&natpmp::resend_request, this, i, _1));
}
catch (std::exception& e)
{
	std::string err = e.what();
}

void natpmp::resend_request(int i, asio::error_code const& e)
{
	using boost::posix_time::hours;
	if (e) return;
	if (m_retry_count >= 9)
	{
		m_mappings[i].need_update = false;
		// try again in two hours
		m_mappings[i].expires
			= boost::posix_time::second_clock::universal_time() + hours(2);
		return;
	}
	send_map_request(i);
}

void natpmp::on_reply(asio::error_code const& e
	, std::size_t bytes_transferred)
{
	using namespace libtorrent::detail;
	using boost::posix_time::seconds;
	if (e) return;

	try
	{

		if (m_remote != m_nat_endpoint)
		{
			m_socket.async_receive_from(asio::buffer(&m_response_buffer, 16)
				, m_remote, bind(&natpmp::on_reply, this, _1, _2));
			return;
		}

		m_send_timer.cancel();

		assert(m_currently_mapping >= 0);
		int i = m_currently_mapping;
		mapping& m = m_mappings[i];

		char* in = m_response_buffer;
		int version = read_uint8(in);
		int cmd = read_uint8(in);
		int result = read_uint16(in);
		int time = read_uint32(in);
		int private_port = read_uint16(in);
		int public_port = read_uint16(in);
		int lifetime = read_uint32(in);

#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
		m_log << to_simple_string(microsec_clock::universal_time())
			<< " <== port map response: " << (cmd - 128 == 1 ? "udp" : "tcp")
			<< " local: " << private_port << " external: " << public_port
			<< " ttl: " << lifetime << std::endl;
#endif

#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
		if (version != 0)
		{
			m_log << "*** unexpected version: " << version << std::endl;
		}
#endif

#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
		if (private_port != m.local_port)
		{
			m_log << "*** unexpected local port: " << private_port << std::endl;
		}
#endif

#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
		if (cmd != 128 + m.protocol)
		{
			m_log << "*** unexpected protocol: " << (cmd - 128) << std::endl;
		}
#endif

		if (public_port == 0 || lifetime == 0)
		{
			// this means the mapping was
			// successfully closed
			m.local_port = 0;
		}
		else
		{
			m.expires = boost::posix_time::second_clock::universal_time()
				+ seconds(int(lifetime * 0.7f));
			m.external_port = public_port;
		}

		if (result != 0)
		{
#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
			m_log << "*** ERROR: " << result << std::endl;
#endif
			std::stringstream errmsg;
			errmsg << "NAT router reports error (" << result << ") ";
			switch (result)
			{
				case 1: errmsg << "Unsupported protocol version"; break;
				case 2: errmsg << "Not authorized to create port map (enable NAT-PMP on your router)"; break;
				case 3: errmsg << "Network failure"; break;
				case 4: errmsg << "Out of resources"; break;
				case 5: errmsg << "Unsupported opcpde"; break;
			}
			throw std::runtime_error(errmsg.str());
		}

		int tcp_port = 0;
		int udp_port = 0;
		if (m.protocol == 1) udp_port = m.external_port;
		else tcp_port = public_port;
		m_callback(tcp_port, udp_port, "");
	}
	catch (std::exception& e)
	{
		using boost::posix_time::hours;
		// try again in two hours
		m_mappings[m_currently_mapping].expires
			= boost::posix_time::second_clock::universal_time() + hours(2);
		m_callback(0, 0, e.what());
	}
	int i = m_currently_mapping;
	m_currently_mapping = -1;
	m_mappings[i].need_update = false;
	update_expiration_timer();
	try_next_mapping(i);
}

void natpmp::update_expiration_timer()
{
	using boost::posix_time::seconds;
	boost::posix_time::ptime now = boost::posix_time::second_clock::universal_time();
	boost::posix_time::ptime min_expire = now + seconds(3600);
	int min_index = -1;
	for (int i = 0; i < 2; ++i)
		if (m_mappings[i].expires < min_expire
			&& m_mappings[i].local_port != 0)
		{
			min_expire = m_mappings[i].expires;
			min_index = i;
		}

	if (min_index >= 0)
	{
		m_refresh_timer.expires_from_now(min_expire - now);
		m_refresh_timer.async_wait(bind(&natpmp::mapping_expired, this, _1, min_index));
	}
}

void natpmp::mapping_expired(asio::error_code const& e, int i)
{
	if (e) return;
#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
	m_log << "*** mapping " << i << " expired, updating" << std::endl;
#endif
	refresh_mapping(i);
}

void natpmp::refresh_mapping(int i)
{
	m_mappings[i].need_update = true;
	if (m_currently_mapping == -1)
	{
		// the socket is not currently in use
		// send out a mapping request
		m_retry_count = 0;
		send_map_request(i);
		m_socket.async_receive_from(asio::buffer(&m_response_buffer, 16)
			, m_remote, bind(&natpmp::on_reply, this, _1, _2));
	}
}

void natpmp::try_next_mapping(int i)
{
	++i;
	if (i >= 2) i = 0;
	if (m_mappings[i].need_update)
		refresh_mapping(i);
}

void natpmp::close()
{
	if (m_disabled) return;
	for (int i = 0; i < 2; ++i)
	{
		if (m_mappings[i].local_port == 0)
			continue;
		m_mappings[i].external_port = 0;
		refresh_mapping(i);
	}
}

<|endoftext|>


<commit_before>// -*- Mode:C++ -*-

/**************************************************************************************************/
/*                                                                                */
/* Copyright (C) 2013-2015 University of Hull                                                     */
/*                                                                                */
/**************************************************************************************************/
/*                                                                                */
/*  module     :  scene/loader/mtl.cpp                                                            */
/*  project    :                                                                                */
/*  description:                                                                                */
/*                                                                                */
/**************************************************************************************************/

// include i/f header

#include "loader/mtl.hpp"

// includes, system

// altough dealing w/ lowering the noise level for boost::spirit headers, the pragmas need to be
// here
#if defined(_MSC_VER) && (_MSC_VER < 1800)
// warning C4100: 'x' : unreferenced formal parameter
#  pragma warning(disable:4100)
// warning C4127: conditional expression is constant
#  pragma warning(disable:4127)
#endif

#include <boost/algorithm/string.hpp>                // boost::trim
#include <boost/config/warning_disable.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_object.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/tokenizer.hpp>                       // boost::char_separator<>, boost::tokenizer<>
#include <cmath>                                     // std::pow
#include <fstream>                                   // std::[i|o]fstream
#include <istream>                                   // std::istream
#include <ostream>                                   // std::ostream

// includes, project

// #include <>

#define UKACHULLDCS_USE_TRACE
// #undef UKACHULLDCS_USE_TRACE
#include <support/trace.hpp>
#include <support/type_info.hpp>

#if defined(UKACHULLDCS_USE_TRACE)
#  include <boost/fusion/include/io.hpp>
#  include <glm/gtx/io.hpp>
#endif

BOOST_FUSION_ADAPT_STRUCT(glm::vec3,
                          (glm::vec3::value_type, x)
                          (glm::vec3::value_type, y)
                          (glm::vec3::value_type, z)
                          );

// internal unnamed namespace

namespace {

  // types, internal (class, enum, struct, union, typedef)

  namespace qi    = boost::spirit::qi;
  namespace ascii = boost::spirit::ascii;

  template <typename IT>
  struct rgb_parser : qi::grammar<IT, glm::vec3(), ascii::space_type> {

    rgb_parser()
      : rgb_parser::base_type(start)
    {
      TRACE_NEVER("scene::file::mtl::<unnamed>::rgb_parser::rgb_parser");

      using qi::debug;
      using qi::float_;

      start %=
        float_ >>  // x
        float_ >>  // y
        float_     // z
        ;

      // debug(start);
    }

    qi::rule<IT, glm::vec3(), ascii::space_type> start;

  };

  template <typename IT>
  struct xyz_parser : qi::grammar<IT, glm::vec3(), ascii::space_type> {

    xyz_parser()
      : xyz_parser::base_type(start)
    {
      TRACE_NEVER("scene::file::mtl::<unnamed>::xyz_parser::xyz_parser");

      using qi::debug;
      using qi::float_;
      using qi::lit;

      start %=
        lit("xyz") >>  // "xyz"
        float_     >>  // x
        float_     >>  // y
        float_         // z
        ;

      // debug(start);
    }

    qi::rule<IT, glm::vec3(), ascii::space_type> start;

  };

  template <typename IT>
  struct float_parser : qi::grammar<IT, float(), ascii::space_type> {

    float_parser()
      : float_parser::base_type(start)
    {
      TRACE_NEVER("scene::file::mtl::<unnamed>::float_parser::float_parser");

      using qi::debug;
      using qi::float_;

      start %=
        float_
        ;

      // debug(start);
    }

    qi::rule<IT, float(), ascii::space_type> start;

  };

  // variables, internal

  // functions, internal

  template <typename P, typename O>
  bool
  parse(std::string const& exp, O& o)
  {
    TRACE_NEVER("scene::file::mtl::<unamed>::parse<" +
                support::demangle(typeid(P)) + "," + support::demangle(typeid(O)) + ">");

    auto       first (exp.begin());
    auto       last  (exp.end());
    bool const result(phrase_parse(first, last, P(), ascii::space, o));

#if 0 // defined(UKACHULLDCS_USE_TRACE)
    if (result && first == last) {
      std::cout << support::trace::prefix() << "scene::file::mtl::parse<"
                << support::demangle(typeid(P)) << ',' << support::demangle(typeid(O)) << ">: "
                << boost::fusion::tuple_open('[')
                << boost::fusion::tuple_close(']')
                << boost::fusion::tuple_delimiter(", ")
                << "in:'" << exp << "', out:" << o
                << std::endl;
    } else {
      std::cout << support::trace::prefix() << "scene::file::mtl::parse<"
                << support::demangle(typeid(P)) << ',' << support::demangle(typeid(O)) << ">: "
                << "failed to parse '" << exp << "'" << std::endl;
    }
#endif

    return (result && first == last);
  }

  /*
   * see [http://www.wikipedia.org/wiki/SRGB]
   */
  glm::vec3
  xyz_to_rgb(glm::vec3 const& xyz)
  {
    static float const     a( 0.055);
    static float const     b(12.920);
    static glm::mat3 const c(+3.2406, -1.5372, -0.4986,
                             -0.9689, +1.8758, +0.0415,
                             +0.0557, -0.2040, +1.0570);

    glm::vec3 result(c * (xyz / glm::vec3(100.0)));

    result.r = (result.r > 0.0031308) ? ((1.0 + a) * std::pow(result.r, 1/2.4)) : (b * result.r);
    result.g = (result.g > 0.0031308) ? ((1.0 + a) * std::pow(result.g, 1/2.4)) : (b * result.g);
    result.b = (result.b > 0.0031308) ? ((1.0 + a) * std::pow(result.b, 1/2.4)) : (b * result.b);

    return result;
  }

} // namespace {

namespace scene {

  namespace file {

    namespace mtl {

      // variables, exported

      // functions, exported

      list_type
      load(std::istream& is)
      {
        TRACE("scene::file::mtl::load(std::istream)");

        list_type result;

        result.push_back(new scene::object::material);

        std::string line;

        while (std::getline(is, line)) {
          if (line.empty() || ('#' == line[0]) || ('!' == line[0]) || ('$' == line[0])) {
            continue;
          }

          static boost::char_separator<char> const token_separator_space(" ");

          typedef boost::tokenizer<boost::char_separator<char>> tokenizer;

          tokenizer tokens(line, token_separator_space);

          // bump -options args filename

          if      ("d" == *tokens.begin()) { // d [-halo] f
            std::string const exp(line.begin() + (*tokens.begin()).length(), line.end());
            float             d;

            if (parse<float_parser<std::string::const_iterator>>(exp, d)) {
              (*result.rbegin())->alpha = d;
            }
          }

          else if ("illum" == *tokens.begin()) { // illum #
            // nothing to do (yet)
          }

          else if ("Ka" == *tokens.begin()) { // Ka [r g b] | [spectral file.refl f] | [xyz x y z]
            std::string const exp(line.begin() + (*tokens.begin()).length(), line.end());
            glm::vec3         c;

            if        (parse<rgb_parser<std::string::const_iterator>>(exp, c)) {
              (*result.rbegin())->ambient = c;
            } else if (parse<xyz_parser<std::string::const_iterator>>(exp, c)) {
              (*result.rbegin())->ambient = xyz_to_rgb(c);
            }
          }

          else if ("Ke" == *tokens.begin()) { // Ke [r g b] | [spectral file.refl f] | [xyz x y z]
            std::string const exp(line.begin() + (*tokens.begin()).length(), line.end());
            glm::vec3         c;

            if (parse<rgb_parser<std::string::const_iterator>>(exp, c)) {
              (*result.rbegin())->emission = c;
            }  else if (parse<xyz_parser<std::string::const_iterator>>(exp, c)) {
              (*result.rbegin())->emission = xyz_to_rgb(c);
            }
          }

          else if ("Kd" == *tokens.begin()) { // Kd [r g b] | [spectral file.refl f] | [xyz x y z]
            std::string const exp(line.begin() + (*tokens.begin()).length(), line.end());
            glm::vec3         c;

            if (parse<rgb_parser<std::string::const_iterator>>(exp, c)) {
              (*result.rbegin())->diffuse = c;
            } else if (parse<xyz_parser<std::string::const_iterator>>(exp, c)) {
              (*result.rbegin())->diffuse = xyz_to_rgb(c);
            }
          }

          else if ("Ks" == *tokens.begin()) { // Ks [r g b] | [spectral file.refl f] | [xyz x y z]
            std::string const exp(line.begin() + (*tokens.begin()).length(), line.end());
            glm::vec3         c;

            if (parse<rgb_parser<std::string::const_iterator>>(exp, c)) {
              (*result.rbegin())->specular = c;
            } else if (parse<xyz_parser<std::string::const_iterator>>(exp, c)) {
              (*result.rbegin())->specular = xyz_to_rgb(c);
            }
          }

          // else if ("map_d" == *tokens.begin()) { // map_d -options args filename
          // }

          // else if ("map_Ka" == *tokens.begin()) { // map_Ka -options args filenam
          // }

          // else if ("map_Ke" == *tokens.begin()) { // map_Ka -options args filenam
          // }

          // else if ("map_Kd" == *tokens.begin()) { // map_Kd -options args filename
          // }

          // else if ("map_Ks" == *tokens.begin()) { // map_Ks -options args filename
          // }

          // else if ("map_Ns" == *tokens.begin()) { // map_Ns -options args filename
          // }

          else if ("Ni" == *tokens.begin()) { // Ni f
            std::string const exp(line.begin() + (*tokens.begin()).length(), line.end());
            float             r;

            if (parse<float_parser<std::string::const_iterator>>(exp, r)) {
              (*result.rbegin())->refraction = r;
            }
          }

          else if ("Ns" == *tokens.begin()) { // Ns exp
            std::string const exp(line.begin() + (*tokens.begin()).length(), line.end());
            float             s;

            if (parse<float_parser<std::string::const_iterator>>(exp, s)) {
              (*result.rbegin())->shininess = s;
            }
          }

          else if ("newmtl" == *tokens.begin()) { // newmtl <string>
            result.push_back(new scene::object::material);
          }

          //else if ("refl" == *tokens.begin()) { //refl -type <type> -options -args filename
          //}

          else if ("Tf" == *tokens.begin()) { // Tf [r g b] | [spectral file.refl f] | [xyz x y z]
            std::string const exp(line.begin() + (*tokens.begin()).length(), line.end());
            glm::vec3         c;

            if (parse<rgb_parser<std::string::const_iterator>>(exp, c)) {
              (*result.rbegin())->transmission = c;
            } else if (parse<xyz_parser<std::string::const_iterator>>(exp, c)) {
              (*result.rbegin())->transmission = xyz_to_rgb(c);
            }
          }

          else if ("Tr" == *tokens.begin()) { // Tr x (== 1 - alpha)
            std::string const exp(line.begin() + (*tokens.begin()).length(), line.end());
            float             t;

            if (parse<float_parser<std::string::const_iterator>>(exp, t)) {
              (*result.rbegin())->alpha = (1.0f - t);
            }
          }

          else if ("TWOSIDE" == *tokens.begin()) { // TWOSIDE (non-standard)
            (*result.rbegin())->front = true;
            (*result.rbegin())->back  = true;
          }

#if 0 // defined(UKACHULLDCS_USE_TRACE)
          else {
            std::cout << support::trace::prefix() << "scene::file::mtl::load(std::istream): "
                      << "unhandled token '" << *tokens.begin() << "'; skipping "
                      << "whole line '" << line << "'" << std::endl;
          }
#endif
        }

        return result;
      }

      list_type
      load(std::string const& a)
      {
        TRACE("scene::file::mtl::load(std::string) [" + a + "]");

        list_type     result;
        std::ifstream ifs(a, std::ios::in|std::ios::binary);

        if (ifs.is_open()) {
          result = load(ifs);
        }

        return result;
      }

      bool
      save(std::ostream&, list_type const&)
      {
        TRACE("scene::file::mtl::save(std::ostream)");

        return false;
      }

      bool
      save(std::string const& a, list_type const& b)
      {
        TRACE("scene::file::mtl::save(std::string) [" + a + "]");

        bool          result(false);
        std::ofstream ofs(a, std::ios::out|std::ios::binary|std::ios::trunc);

        if (ofs.is_open()) {
          result = save(ofs, b);
        }

        return result;
      }

    } // namespace mtl {

  } // namespace file {

} // namespace scene {
<commit_msg>cleanup + adding material name<commit_after>// -*- Mode:C++ -*-

/**************************************************************************************************/
/*                                                                                */
/* Copyright (C) 2013-2015 University of Hull                                                     */
/*                                                                                */
/**************************************************************************************************/
/*                                                                                */
/*  module     :  scene/loader/mtl.cpp                                                            */
/*  project    :                                                                                */
/*  description:                                                                                */
/*                                                                                */
/**************************************************************************************************/

// include i/f header

#include "loader/mtl.hpp"

// includes, system

// altough dealing w/ lowering the noise level for boost::spirit headers, the pragmas need to be
// here
#if defined(_MSC_VER) && (_MSC_VER < 1800)
// warning C4100: 'x' : unreferenced formal parameter
#  pragma warning(disable:4100)
// warning C4127: conditional expression is constant
#  pragma warning(disable:4127)
#endif

#include <boost/algorithm/string.hpp>                // boost::trim
#include <boost/config/warning_disable.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_object.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/tokenizer.hpp>                       // boost::char_separator<>, boost::tokenizer<>
#include <cmath>                                     // std::pow
#include <fstream>                                   // std::[i|o]fstream
#include <istream>                                   // std::istream
#include <ostream>                                   // std::ostream

// includes, project

// #include <>

#define UKACHULLDCS_USE_TRACE
#undef UKACHULLDCS_USE_TRACE
#include <support/trace.hpp>
#include <support/type_info.hpp>

#if defined(UKACHULLDCS_USE_TRACE)
#  include <boost/fusion/include/io.hpp>
#  include <glm/gtx/io.hpp>
#endif

BOOST_FUSION_ADAPT_STRUCT(glm::vec3,
                          (glm::vec3::value_type, x)
                          (glm::vec3::value_type, y)
                          (glm::vec3::value_type, z)
                          );

// internal unnamed namespace

namespace {

  // types, internal (class, enum, struct, union, typedef)

  namespace qi    = boost::spirit::qi;
  namespace ascii = boost::spirit::ascii;

  template <typename IT>
  struct rgb_parser : qi::grammar<IT, glm::vec3(), ascii::space_type> {

    rgb_parser()
      : rgb_parser::base_type(start)
    {
      TRACE_NEVER("scene::file::mtl::<unnamed>::rgb_parser::rgb_parser");

      using qi::debug;
      using qi::float_;

      start %=
        float_ >>  // x
        float_ >>  // y
        float_     // z
        ;

      // debug(start);
    }

    qi::rule<IT, glm::vec3(), ascii::space_type> start;

  };

  template <typename IT>
  struct xyz_parser : qi::grammar<IT, glm::vec3(), ascii::space_type> {

    xyz_parser()
      : xyz_parser::base_type(start)
    {
      TRACE_NEVER("scene::file::mtl::<unnamed>::xyz_parser::xyz_parser");

      using qi::debug;
      using qi::float_;
      using qi::lit;

      start %=
        lit("xyz") >>  // "xyz"
        float_     >>  // x
        float_     >>  // y
        float_         // z
        ;

      // debug(start);
    }

    qi::rule<IT, glm::vec3(), ascii::space_type> start;

  };

  template <typename IT>
  struct float_parser : qi::grammar<IT, float(), ascii::space_type> {

    float_parser()
      : float_parser::base_type(start)
    {
      TRACE_NEVER("scene::file::mtl::<unnamed>::float_parser::float_parser");

      using qi::debug;
      using qi::float_;

      start %=
        float_
        ;

      // debug(start);
    }

    qi::rule<IT, float(), ascii::space_type> start;

  };

  // variables, internal

  // functions, internal

  template <typename P, typename O>
  bool
  parse(std::string const& exp, O& o)
  {
    TRACE_NEVER("scene::file::mtl::<unamed>::parse<" +
                support::demangle(typeid(P)) + "," + support::demangle(typeid(O)) + ">");

    auto       first (exp.begin());
    auto       last  (exp.end());
    bool const result(phrase_parse(first, last, P(), ascii::space, o));

#if 0 // defined(UKACHULLDCS_USE_TRACE)
    if (result && first == last) {
      std::cout << support::trace::prefix() << "scene::file::mtl::parse<"
                << support::demangle(typeid(P)) << ',' << support::demangle(typeid(O)) << ">: "
                << boost::fusion::tuple_open('[')
                << boost::fusion::tuple_close(']')
                << boost::fusion::tuple_delimiter(", ")
                << "in:'" << exp << "', out:" << o
                << std::endl;
    } else {
      std::cout << support::trace::prefix() << "scene::file::mtl::parse<"
                << support::demangle(typeid(P)) << ',' << support::demangle(typeid(O)) << ">: "
                << "failed to parse '" << exp << "'" << std::endl;
    }
#endif

    return (result && first == last);
  }

  /*
   * see [http://www.wikipedia.org/wiki/SRGB]
   */
  glm::vec3
  xyz_to_rgb(glm::vec3 const& xyz)
  {
    static float const     a( 0.055);
    static float const     b(12.920);
    static glm::mat3 const c(+3.2406, -1.5372, -0.4986,
                             -0.9689, +1.8758, +0.0415,
                             +0.0557, -0.2040, +1.0570);

    glm::vec3 result(c * (xyz / glm::vec3(100.0)));

    result.r = (result.r > 0.0031308) ? ((1.0 + a) * std::pow(result.r, 1/2.4)) : (b * result.r);
    result.g = (result.g > 0.0031308) ? ((1.0 + a) * std::pow(result.g, 1/2.4)) : (b * result.g);
    result.b = (result.b > 0.0031308) ? ((1.0 + a) * std::pow(result.b, 1/2.4)) : (b * result.b);

    return result;
  }

} // namespace {

namespace scene {

  namespace file {

    namespace mtl {

      // variables, exported

      // functions, exported

      list_type
      load(std::istream& is)
      {
        TRACE("scene::file::mtl::load(std::istream)");

        list_type result;

        {
          result.push_back(new scene::object::material);

          (*result.rbegin())->name = "default material";
        }

        std::string line;

        while (std::getline(is, line)) {
          if (line.empty() || ('#' == line[0]) || ('!' == line[0]) || ('$' == line[0])) {
            continue;
          }

          static boost::char_separator<char> const token_separator_space(" ");

          using tokenizer = boost::tokenizer<boost::char_separator<char>>;

          tokenizer tokens(line, token_separator_space);

          // bump -options args filename

          if      ("d" == *tokens.begin()) { // d [-halo] f
            std::string const exp(line.begin() + (*tokens.begin()).length(), line.end());
            float             d;

            if (parse<float_parser<std::string::const_iterator>>(exp, d)) {
              (*result.rbegin())->alpha = d;
            }
          }

          else if ("illum" == *tokens.begin()) { // illum #
            // nothing to do (yet)
          }

          else if ("Ka" == *tokens.begin()) { // Ka [r g b] | [spectral file.refl f] | [xyz x y z]
            std::string const exp(line.begin() + (*tokens.begin()).length(), line.end());
            glm::vec3         c;

            if        (parse<rgb_parser<std::string::const_iterator>>(exp, c)) {
              (*result.rbegin())->ambient = c;
            } else if (parse<xyz_parser<std::string::const_iterator>>(exp, c)) {
              (*result.rbegin())->ambient = xyz_to_rgb(c);
            }
          }

          else if ("Ke" == *tokens.begin()) { // Ke [r g b] | [spectral file.refl f] | [xyz x y z]
            std::string const exp(line.begin() + (*tokens.begin()).length(), line.end());
            glm::vec3         c;

            if (parse<rgb_parser<std::string::const_iterator>>(exp, c)) {
              (*result.rbegin())->emission = c;
            }  else if (parse<xyz_parser<std::string::const_iterator>>(exp, c)) {
              (*result.rbegin())->emission = xyz_to_rgb(c);
            }
          }

          else if ("Kd" == *tokens.begin()) { // Kd [r g b] | [spectral file.refl f] | [xyz x y z]
            std::string const exp(line.begin() + (*tokens.begin()).length(), line.end());
            glm::vec3         c;

            if (parse<rgb_parser<std::string::const_iterator>>(exp, c)) {
              (*result.rbegin())->diffuse = c;
            } else if (parse<xyz_parser<std::string::const_iterator>>(exp, c)) {
              (*result.rbegin())->diffuse = xyz_to_rgb(c);
            }
          }

          else if ("Ks" == *tokens.begin()) { // Ks [r g b] | [spectral file.refl f] | [xyz x y z]
            std::string const exp(line.begin() + (*tokens.begin()).length(), line.end());
            glm::vec3         c;

            if (parse<rgb_parser<std::string::const_iterator>>(exp, c)) {
              (*result.rbegin())->specular = c;
            } else if (parse<xyz_parser<std::string::const_iterator>>(exp, c)) {
              (*result.rbegin())->specular = xyz_to_rgb(c);
            }
          }

          // else if ("map_d" == *tokens.begin()) { // map_d -options args filename
          // }

          // else if ("map_Ka" == *tokens.begin()) { // map_Ka -options args filenam
          // }

          // else if ("map_Ke" == *tokens.begin()) { // map_Ka -options args filenam
          // }

          // else if ("map_Kd" == *tokens.begin()) { // map_Kd -options args filename
          // }

          // else if ("map_Ks" == *tokens.begin()) { // map_Ks -options args filename
          // }

          // else if ("map_Ns" == *tokens.begin()) { // map_Ns -options args filename
          // }

          else if ("Ni" == *tokens.begin()) { // Ni f
            std::string const exp(line.begin() + (*tokens.begin()).length(), line.end());
            float             r;

            if (parse<float_parser<std::string::const_iterator>>(exp, r)) {
              (*result.rbegin())->refraction = r;
            }
          }

          else if ("Ns" == *tokens.begin()) { // Ns exp
            std::string const exp(line.begin() + (*tokens.begin()).length(), line.end());
            float             s;

            if (parse<float_parser<std::string::const_iterator>>(exp, s)) {
              (*result.rbegin())->shininess = s;
            }
          }

          else if ("newmtl" == *tokens.begin()) { // newmtl <string>
            result.push_back(new scene::object::material);

            (*result.rbegin())->name = std::string(line.begin() + (*tokens.begin()).length() + 1,
                                                   line.end());
          }

          //else if ("refl" == *tokens.begin()) { //refl -type <type> -options -args filename
          //}

          else if ("Tf" == *tokens.begin()) { // Tf [r g b] | [spectral file.refl f] | [xyz x y z]
            std::string const exp(line.begin() + (*tokens.begin()).length(), line.end());
            glm::vec3         c;

            if (parse<rgb_parser<std::string::const_iterator>>(exp, c)) {
              (*result.rbegin())->transmission = c;
            } else if (parse<xyz_parser<std::string::const_iterator>>(exp, c)) {
              (*result.rbegin())->transmission = xyz_to_rgb(c);
            }
          }

          else if ("Tr" == *tokens.begin()) { // Tr x (== 1 - alpha)
            std::string const exp(line.begin() + (*tokens.begin()).length(), line.end());
            float             t;

            if (parse<float_parser<std::string::const_iterator>>(exp, t)) {
              (*result.rbegin())->alpha = (1.0f - t);
            }
          }

          else if ("TWOSIDE" == *tokens.begin()) { // TWOSIDE (non-standard)
            (*result.rbegin())->front = true;
            (*result.rbegin())->back  = true;
          }

#if 0 // defined(UKACHULLDCS_USE_TRACE)
          else {
            std::cout << support::trace::prefix() << "scene::file::mtl::load(std::istream): "
                      << "unhandled token '" << *tokens.begin() << "'; skipping "
                      << "whole line '" << line << "'" << std::endl;
          }
#endif
        }

        return result;
      }

      list_type
      load(std::string const& a)
      {
        TRACE("scene::file::mtl::load(std::string) [" + a + "]");

        list_type     result;
        std::ifstream ifs(a, std::ios::in|std::ios::binary);

        if (ifs.is_open()) {
          result = load(ifs);
        }

        return result;
      }

      bool
      save(std::ostream&, list_type const&)
      {
        TRACE("scene::file::mtl::save(std::ostream)");

        return false;
      }

      bool
      save(std::string const& a, list_type const& b)
      {
        TRACE("scene::file::mtl::save(std::string) [" + a + "]");

        bool          result(false);
        std::ofstream ofs(a, std::ios::out|std::ios::binary|std::ios::trunc);

        if (ofs.is_open()) {
          result = save(ofs, b);
        }

        return result;
      }

    } // namespace mtl {

  } // namespace file {

} // namespace scene {
<|endoftext|>


<commit_before>#define _LOG_PROB_ neg_binomial_log
#include <stan/prob/distributions/univariate/discrete/neg_binomial.hpp>
#include <stan/prob/distributions/univariate/discrete/binomial.hpp>

using std::vector;
using std::numeric_limits;
using stan::agrad::var;

class AgradDistributionsNegBinomial : public AgradDistributionTest {
public:
  void valid_values(vector<vector<double> >& parameters,
                    vector<double>& log_prob) {
    vector<double> param(3);

    param[0] = 10;           // n
    param[1] = 2.0;          // alpha
    param[2] = 1.5;          // beta
    parameters.push_back(param);
    log_prob.push_back(-7.786663); // expected log_prob

    param[0] = 100;          // n
    param[1] = 3.0;          // alpha
    param[2] = 3.5;          // beta
    parameters.push_back(param);
    log_prob.push_back(-142.6147); // expected log_prob

    param[0] = 13;
    param[1] = 1e11; // alpha > 1e10, causes redux to Poisson
    param[2] = 1e10; // equiv to Poisson(1e11/1e10) = Poisson(10)
    parameters.push_back(param);
    log_prob.push_back(-2.618558); // log poisson(13|10)
  }

  void invalid_values(vector<size_t>& index,
                      vector<double>& value) {
    // n
    index.push_back(0U);
    value.push_back(-1);

    // alpha
    index.push_back(1U);
    value.push_back(0);

    // beta
    index.push_back(2U);
    value.push_back(0);
  }

  template <class T_n, class T_shape, class T_inv_scale,
            typename T3, typename T4, typename T5,
            typename T6, typename T7, typename T8,
            typename T9>
  typename stan::return_type<T_shape,T_inv_scale>::type
  log_prob(const T_n& n, const T_shape& alpha, const T_inv_scale& beta,
	   const T3&, const T4&, const T5&,
	   const T6&, const T7&, const T8&,
	   const T9&) {
    return stan::prob::neg_binomial_log(n, alpha, beta);
  }

  template <bool propto,
	    class T_n, class T_shape, class T_inv_scale,
            typename T3, typename T4, typename T5,
            typename T6, typename T7, typename T8,
            typename T9>
  typename stan::return_type<T_shape,T_inv_scale>::type
  log_prob(const T_n& n, const T_shape& alpha, const T_inv_scale& beta,
	   const T3&, const T4&, const T5&,
	   const T6&, const T7&, const T8&,
	   const T9&) {
    return stan::prob::neg_binomial_log<propto>(n, alpha, beta);
  }

  template <bool propto,
	    class T_n, class T_shape, class T_inv_scale,
            typename T3, typename T4, typename T5,
            typename T6, typename T7, typename T8,
            typename T9,
	    class Policy>
  typename stan::return_type<T_shape,T_inv_scale>::type
  log_prob(const T_n& n, const T_shape& alpha, const T_inv_scale& beta,
	   const T3&, const T4&, const T5&,
	   const T6&, const T7&, const T8&,
	   const T9&) {
    return stan::prob::neg_binomial_log<propto>(n, alpha, beta, Policy());
  }

  template <class T_n, class T_shape, class T_inv_scale,
            typename T3, typename T4, typename T5,
            typename T6, typename T7, typename T8,
            typename T9>
  var log_prob_function(const T_n& n, const T_shape& alpha, const T_inv_scale& beta,
			const T3&, const T4&, const T5&,
			const T6&, const T7&, const T8&,
			const T9&) {
    using std::log;
    using stan::math::binomial_coefficient_log;
    using stan::math::log1m;
    using stan::math::multiply_log;
    using stan::prob::include_summand;

    var logp(0);
    // Special case where negative binomial reduces to Poisson
    if (alpha > 1e10) {
      if (include_summand<true>::value)
        logp -= lgamma(n + 1.0);
      if (include_summand<true,T_shape>::value ||
          include_summand<true,T_inv_scale>::value) {
        typename stan::return_type<T_shape, T_inv_scale>::type lambda;
        lambda = alpha / beta;
        logp += multiply_log(n, lambda) - lambda;
      }
      return logp;
    }
    // More typical cases
    if (include_summand<true,T_shape>::value)
      if (n != 0)
        logp += binomial_coefficient_log<typename stan::scalar_type<T_shape>::type>
          (n + alpha - 1.0, n);
    if (include_summand<true,T_shape,T_inv_scale>::value)
      logp += -n * log1p(beta)
        + alpha * log(beta / (1 + beta));
    return logp;
  }
};

const double p = 0.57;
const double beta = p / (1.0 - p);

TEST(ProbDistributionsNegBinomialCDF,Values) {
    EXPECT_FLOAT_EQ(0.042817421, stan::prob::neg_binomial_cdf(30, 24, beta));

    // Consistency with implemented Binomial
    EXPECT_FLOAT_EQ(stan::prob::binomial_cdf(24, 54, p), stan::prob::neg_binomial_cdf(30, 24, beta));
}
<commit_msg>fixed neg_binomial test<commit_after>// Arguments: Ints, Doubles, Doubles
#include <stan/prob/distributions/univariate/discrete/neg_binomial.hpp>
#include <stan/prob/distributions/univariate/discrete/binomial.hpp>

using std::vector;
using std::numeric_limits;
using stan::agrad::var;

class AgradDistributionsNegBinomial : public AgradDistributionTest {
public:
  void valid_values(vector<vector<double> >& parameters,
                    vector<double>& log_prob) {
    vector<double> param(3);

    param[0] = 10;           // n
    param[1] = 2.0;          // alpha
    param[2] = 1.5;          // beta
    parameters.push_back(param);
    log_prob.push_back(-7.786663); // expected log_prob

    param[0] = 100;          // n
    param[1] = 3.0;          // alpha
    param[2] = 3.5;          // beta
    parameters.push_back(param);
    log_prob.push_back(-142.6147); // expected log_prob

    param[0] = 13;
    param[1] = 1e11; // alpha > 1e10, causes redux to Poisson
    param[2] = 1e10; // equiv to Poisson(1e11/1e10) = Poisson(10)
    parameters.push_back(param);
    log_prob.push_back(-2.618558); // log poisson(13|10)
  }

  void invalid_values(vector<size_t>& index,
                      vector<double>& value) {
    // n
    index.push_back(0U);
    value.push_back(-1);

    // alpha
    index.push_back(1U);
    value.push_back(0);

    // beta
    index.push_back(2U);
    value.push_back(0);
  }

  template <class T_n, class T_shape, class T_inv_scale,
            typename T3, typename T4, typename T5,
            typename T6, typename T7, typename T8,
            typename T9>
  typename stan::return_type<T_shape,T_inv_scale>::type
  log_prob(const T_n& n, const T_shape& alpha, const T_inv_scale& beta,
	   const T3&, const T4&, const T5&,
	   const T6&, const T7&, const T8&,
	   const T9&) {
    return stan::prob::neg_binomial_log(n, alpha, beta);
  }

  template <bool propto,
	    class T_n, class T_shape, class T_inv_scale,
            typename T3, typename T4, typename T5,
            typename T6, typename T7, typename T8,
            typename T9>
  typename stan::return_type<T_shape,T_inv_scale>::type
  log_prob(const T_n& n, const T_shape& alpha, const T_inv_scale& beta,
	   const T3&, const T4&, const T5&,
	   const T6&, const T7&, const T8&,
	   const T9&) {
    return stan::prob::neg_binomial_log<propto>(n, alpha, beta);
  }

  template <bool propto,
	    class T_n, class T_shape, class T_inv_scale,
            typename T3, typename T4, typename T5,
            typename T6, typename T7, typename T8,
            typename T9,
	    class Policy>
  typename stan::return_type<T_shape,T_inv_scale>::type
  log_prob(const T_n& n, const T_shape& alpha, const T_inv_scale& beta,
	   const T3&, const T4&, const T5&,
	   const T6&, const T7&, const T8&,
	   const T9&) {
    return stan::prob::neg_binomial_log<propto>(n, alpha, beta, Policy());
  }

  template <class T_n, class T_shape, class T_inv_scale,
            typename T3, typename T4, typename T5,
            typename T6, typename T7, typename T8,
            typename T9>
  var log_prob_function(const T_n& n, const T_shape& alpha, const T_inv_scale& beta,
			const T3&, const T4&, const T5&,
			const T6&, const T7&, const T8&,
			const T9&) {
    using std::log;
    using stan::math::binomial_coefficient_log;
    using stan::math::log1m;
    using stan::math::multiply_log;
    using stan::prob::include_summand;

    var logp(0);
    // Special case where negative binomial reduces to Poisson
    if (alpha > 1e10) {
      if (include_summand<true>::value)
        logp -= lgamma(n + 1.0);
      if (include_summand<true,T_shape>::value ||
          include_summand<true,T_inv_scale>::value) {
        typename stan::return_type<T_shape, T_inv_scale>::type lambda;
        lambda = alpha / beta;
        logp += multiply_log(n, lambda) - lambda;
      }
      return logp;
    }
    // More typical cases
    if (include_summand<true,T_shape>::value)
      if (n != 0)
        logp += binomial_coefficient_log<typename stan::scalar_type<T_shape>::type>
          (n + alpha - 1.0, n);
    if (include_summand<true,T_shape,T_inv_scale>::value)
      logp += -n * log1p(beta)
        + alpha * log(beta / (1 + beta));
    return logp;
  }
};

const double p = 0.57;
const double beta = p / (1.0 - p);

TEST(ProbDistributionsNegBinomialCDF,Values) {
    EXPECT_FLOAT_EQ(0.042817421, stan::prob::neg_binomial_cdf(30, 24, beta));

    // Consistency with implemented Binomial
    EXPECT_FLOAT_EQ(stan::prob::binomial_cdf(24, 54, p), stan::prob::neg_binomial_cdf(30, 24, beta));
}
<|endoftext|>


<commit_before>/*
 * File:   histogramnew.cc
 * Author: ruehle
 *
 * Created on March 11, 2009, 4:29 PM
 */

#include "histogramnew.h"

HistogramNew::HistogramNew()
{
    _min=_max=_step=0;
    _weight = 1.;
    _periodic=false;
}

void HistogramNew::Initialize(double min, double max, int nbins)
{
    _min = min; _max = max;
    _step = (_max - _min)/nbins;
    _weight = 1.;
    _data.resize(nbins);
    _nbins = nbins;

    int i;
    for(double v=_min, i=0; i<nbins; v+=_step,++i)
        _data.x(i)=v;

    _data.y()=ub::zero_vector<double>(_nbins);
    _data.flags()=ub::scalar_vector<char>(_nbins, 'i');
}

void HistogramNew::Process(double &v)
{
    int i = (int) ((v - _min) / _step);

    if (i < 0 || i >= _nbins) {
        if(!_periodic) return;
        if(i<0) i = _nbins - ((-i) % _nbins);
        else i = i % _nbins;
    }
    _data.y(i) += _weight;
}

void HistogramNew::Normalize()
{
    double area = 0;

    area=ub::norm_1(_data.x()) * _step;

    _weight /= area;
    double scale = 1./area;

    _data.y() *= scale;
}

void HistogramNew::Clear()
{
    _weight = 1.;
    _data.y() = ub::zero_vector<double>(_nbins);
}<commit_msg>interval now centered around bins<commit_after>/*
 * File:   histogramnew.cc
 * Author: ruehle
 *
 * Created on March 11, 2009, 4:29 PM
 */

#include "histogramnew.h"

HistogramNew::HistogramNew()
{
    _min=_max=_step=0;
    _weight = 1.;
    _periodic=false;
}

void HistogramNew::Initialize(double min, double max, int nbins)
{
    _min = min; _max = max;
    _step = (_max - _min)/nbins;
    _weight = 1.;
    _data.resize(nbins);
    _nbins = nbins;

    int i;
    for(double v=_min, i=0; i<nbins; v+=_step,++i)
        _data.x(i)=v;

    _data.y()=ub::zero_vector<double>(_nbins);
    _data.flags()=ub::scalar_vector<char>(_nbins, 'i');
}

void HistogramNew::Process(double &v)
{
    int i = (int) ((v - _min) / _step + 0.5);

    if (i < 0 || i >= _nbins) {
        if(!_periodic) return;
        if(i<0) i = _nbins - ((-i) % _nbins);
        else i = i % _nbins;
    }
    _data.y(i) += _weight;
}

void HistogramNew::Normalize()
{
    double area = 0;

    area=ub::norm_1(_data.x()) * _step;

    _weight /= area;
    double scale = 1./area;

    _data.y() *= scale;
}

void HistogramNew::Clear()
{
    _weight = 1.;
    _data.y() = ub::zero_vector<double>(_nbins);
}<|endoftext|>