<commit_before>/***************************************************************************
 *   Copyright (c) 2008 Werner Mayer <wmayer[at]users.sourceforge.net>     *
 *                                                                         *
 *   This file is part of the FreeCAD CAx development system.              *
 *                                                                         *
 *   This library is free software; you can redistribute it and/or         *
 *   modify it under the terms of the GNU Library General Public           *
 *   License as published by the Free Software Foundation; either          *
 *   version 2 of the License, or (at your option) any later version.      *
 *                                                                         *
 *   This library  is distributed in the hope that it will be useful,      *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU Library General Public License for more details.                  *
 *                                                                         *
 *   You should have received a copy of the GNU Library General Public     *
 *   License along with this library; see the file COPYING.LIB. If not,    *
 *   write to the Free Software Foundation, Inc., 59 Temple Place,         *
 *   Suite 330, Boston, MA  02111-1307, USA                                *
 *                                                                         *
 ***************************************************************************/

#include "PreCompiled.h"
#ifndef _PreComp_
# include <gp.hxx>
# include <gp_Lin.hxx>
# include <Geom_Line.hxx>
# include <Geom_TrimmedCurve.hxx>
# include <GC_MakeLine.hxx>
# include <GC_MakeSegment.hxx>
# include <Precision.hxx>
#endif

#include <Base/VectorPy.h>
#include <Base/GeometryPyCXX.h>

#include "OCCError.h"
#include "Geometry.h"
#include "LinePy.h"
#include "LinePy.cpp"

using namespace Part;

extern const char* gce_ErrorStatusText(gce_ErrorType et);

// returns a string which represents the object e.g. when printed in python
std::string LinePy::representation(void) const
{
    std::stringstream str;
    //if(Infinite)
    //   str << "<Line infinite>";
    //else {
        Base::Vector3d start = getGeomLineSegmentPtr()->getStartPoint();
        Base::Vector3d end   = getGeomLineSegmentPtr()->getEndPoint();
        str << "<Line ("
            << start.x << "," <<start.y << "," <<start.z << ") ("
            << end.x   << "," <<end.y   << "," <<end.z   << ") >";
    //}

    return str.str();
}

PyObject *LinePy::PyMake(struct _typeobject *, PyObject *, PyObject *)  // Python wrapper
{
    // create a new instance of LinePy and the Twin object
    return new LinePy(new GeomLineSegment);
}

// constructor method
int LinePy::PyInit(PyObject* args, PyObject* /*kwd*/)
{

    if (PyArg_ParseTuple(args, "")) {
        // default line
        Infinite=false;
        return 0;
    }

    PyErr_Clear();
    PyObject *pLine;
    if (PyArg_ParseTuple(args, "O!", &(LinePy::Type), &pLine)) {
        // Copy line
        LinePy* pcLine = static_cast<LinePy*>(pLine);
        // get Geom_Line of line segment
        Handle_Geom_TrimmedCurve that_curv = Handle_Geom_TrimmedCurve::DownCast
            (pcLine->getGeomLineSegmentPtr()->handle());
        Handle_Geom_Line that_line = Handle_Geom_Line::DownCast
            (that_curv->BasisCurve());
        // get Geom_Line of line segment
        Handle_Geom_TrimmedCurve this_curv = Handle_Geom_TrimmedCurve::DownCast
            (this->getGeomLineSegmentPtr()->handle());
        Handle_Geom_Line this_line = Handle_Geom_Line::DownCast
            (this_curv->BasisCurve());

        Infinite = pcLine->Infinite;

        // Assign the lines
        this_line->SetLin(that_line->Lin());
        this_curv->SetTrim(that_curv->FirstParameter(), that_curv->LastParameter());
        return 0;
    }

    PyErr_Clear();
    PyObject *pV1, *pV2;
    if (PyArg_ParseTuple(args, "O!O!", &(Base::VectorPy::Type), &pV1,
                                       &(Base::VectorPy::Type), &pV2)) {
        Base::Vector3d v1 = static_cast<Base::VectorPy*>(pV1)->value();
        Base::Vector3d v2 = static_cast<Base::VectorPy*>(pV2)->value();
        try {
            // Create line out of two points
            double distance = Base::Distance(v1, v2);
            if (distance < gp::Resolution())
                Standard_Failure::Raise("Both points are equal");
            GC_MakeSegment ms(gp_Pnt(v1.x,v1.y,v1.z),
                              gp_Pnt(v2.x,v2.y,v2.z));
            if (!ms.IsDone()) {
                PyErr_SetString(PartExceptionOCCError, gce_ErrorStatusText(ms.Status()));
                return -1;
            }

            // get Geom_Line of line segment
            Handle_Geom_TrimmedCurve this_curv = Handle_Geom_TrimmedCurve::DownCast
                (this->getGeomLineSegmentPtr()->handle());
            Handle_Geom_Line this_line = Handle_Geom_Line::DownCast
                (this_curv->BasisCurve());
            Handle_Geom_TrimmedCurve that_curv = ms.Value();
            Handle_Geom_Line that_line = Handle_Geom_Line::DownCast(that_curv->BasisCurve());
            this_line->SetLin(that_line->Lin());
            this_curv->SetTrim(that_curv->FirstParameter(), that_curv->LastParameter());

            Infinite = false;
            return 0;
        }
        catch (Standard_Failure) {
            Handle_Standard_Failure e = Standard_Failure::Caught();
            PyErr_SetString(PartExceptionOCCError, e->GetMessageString());
            return -1;
        }
        catch (...) {
            PyErr_SetString(PartExceptionOCCError, "creation of line failed");
            return -1;
        }
    }

    PyErr_SetString(PyExc_TypeError, "Line constructor accepts:\n"
        "-- empty parameter list\n"
        "-- Line\n"
        "-- Point, Point");
    return -1;
}

PyObject* LinePy::setParameterRange(PyObject *args)
{
    double first, last;
    if (!PyArg_ParseTuple(args, "dd", &first, &last))
        return NULL;

    try {
        Handle_Geom_TrimmedCurve this_curve = Handle_Geom_TrimmedCurve::DownCast
            (this->getGeomLineSegmentPtr()->handle());
        this_curve->SetTrim(first, last);
    }
    catch (Standard_Failure) {
        Handle_Standard_Failure e = Standard_Failure::Caught();
        PyErr_SetString(PartExceptionOCCError, e->GetMessageString());
        return NULL;
    }

    Py_Return;
}

Py::Object LinePy::getStartPoint(void) const
{
    Handle_Geom_TrimmedCurve this_curve = Handle_Geom_TrimmedCurve::DownCast
        (this->getGeomLineSegmentPtr()->handle());
    gp_Pnt pnt = this_curve->StartPoint();
    return Py::Vector(Base::Vector3d(pnt.X(), pnt.Y(), pnt.Z()));
}

void LinePy::setStartPoint(Py::Object arg)
{
    gp_Pnt p1, p2;
    Handle_Geom_TrimmedCurve this_curv = Handle_Geom_TrimmedCurve::DownCast
        (this->getGeomLineSegmentPtr()->handle());
    p2 = this_curv->EndPoint();

    PyObject *p = arg.ptr();
    if (PyObject_TypeCheck(p, &(Base::VectorPy::Type))) {
        Base::Vector3d v = static_cast<Base::VectorPy*>(p)->value();
        p1.SetX(v.x);
        p1.SetY(v.y);
        p1.SetZ(v.z);
    }
    else if (PyTuple_Check(p)) {
        Py::Tuple tuple(arg);
        p1.SetX((double)Py::Float(tuple.getItem(0)));
        p1.SetY((double)Py::Float(tuple.getItem(1)));
        p1.SetZ((double)Py::Float(tuple.getItem(2)));
    }
    else {
        std::string error = std::string("type must be 'Vector' or tuple, not ");
        error += p->ob_type->tp_name;
        throw Py::TypeError(error);
    }

    try {
        // Create line out of two points
        if (p1.Distance(p2) < gp::Resolution())
            Standard_Failure::Raise("Both points are equal");
        GC_MakeSegment ms(p1, p2);
        if (!ms.IsDone()) {
            throw Py::Exception(gce_ErrorStatusText(ms.Status()));
        }

        // get Geom_Line of line segment
        Handle_Geom_Line this_line = Handle_Geom_Line::DownCast
            (this_curv->BasisCurve());
        Handle_Geom_TrimmedCurve that_curv = ms.Value();
        Handle_Geom_Line that_line = Handle_Geom_Line::DownCast(that_curv->BasisCurve());
        this_line->SetLin(that_line->Lin());
        this_curv->SetTrim(that_curv->FirstParameter(), that_curv->LastParameter());
    }
    catch (Standard_Failure) {
        Handle_Standard_Failure e = Standard_Failure::Caught();
        throw Py::Exception(e->GetMessageString());
    }
}

Py::Object LinePy::getEndPoint(void) const
{
    Handle_Geom_TrimmedCurve this_curve = Handle_Geom_TrimmedCurve::DownCast
        (this->getGeomLineSegmentPtr()->handle());
    gp_Pnt pnt = this_curve->EndPoint();
    return Py::Vector(Base::Vector3d(pnt.X(), pnt.Y(), pnt.Z()));
}

void LinePy::setEndPoint(Py::Object arg)
{
    gp_Pnt p1, p2;
    Handle_Geom_TrimmedCurve this_curv = Handle_Geom_TrimmedCurve::DownCast
        (this->getGeomLineSegmentPtr()->handle());
    p1 = this_curv->StartPoint();

    PyObject *p = arg.ptr();
    if (PyObject_TypeCheck(p, &(Base::VectorPy::Type))) {
        Base::Vector3d v = static_cast<Base::VectorPy*>(p)->value();
        p2.SetX(v.x);
        p2.SetY(v.y);
        p2.SetZ(v.z);
    }
    else if (PyTuple_Check(p)) {
        Py::Tuple tuple(arg);
        p2.SetX((double)Py::Float(tuple.getItem(0)));
        p2.SetY((double)Py::Float(tuple.getItem(1)));
        p2.SetZ((double)Py::Float(tuple.getItem(2)));
    }
    else {
        std::string error = std::string("type must be 'Vector' or tuple, not ");
        error += p->ob_type->tp_name;
        throw Py::TypeError(error);
    }

    try {
        // Create line out of two points
        if (p1.Distance(p2) < gp::Resolution())
            Standard_Failure::Raise("Both points are equal");
        GC_MakeSegment ms(p1, p2);
        if (!ms.IsDone()) {
            throw Py::Exception(gce_ErrorStatusText(ms.Status()));
        }

        // get Geom_Line of line segment
        Handle_Geom_Line this_line = Handle_Geom_Line::DownCast
            (this_curv->BasisCurve());
        Handle_Geom_TrimmedCurve that_curv = ms.Value();
        Handle_Geom_Line that_line = Handle_Geom_Line::DownCast(that_curv->BasisCurve());
        this_line->SetLin(that_line->Lin());
        this_curv->SetTrim(that_curv->FirstParameter(), that_curv->LastParameter());
    }
    catch (Standard_Failure) {
        Handle_Standard_Failure e = Standard_Failure::Caught();
        throw Py::Exception(e->GetMessageString());
    }
}

Py::Boolean LinePy::getInfinite(void) const
{
    return Py::Boolean(Infinite);
}

void  LinePy::setInfinite(Py::Boolean arg)
{
    Infinite = arg;
}

PyObject *LinePy::getCustomAttributes(const char* /*attr*/) const
{
    return 0;
}

int LinePy::setCustomAttributes(const char* /*attr*/, PyObject* /*obj*/)
{
    return 0;
}
<commit_msg>allow to pass parameter range when creating a line from a line<commit_after>/***************************************************************************
 *   Copyright (c) 2008 Werner Mayer <wmayer[at]users.sourceforge.net>     *
 *                                                                         *
 *   This file is part of the FreeCAD CAx development system.              *
 *                                                                         *
 *   This library is free software; you can redistribute it and/or         *
 *   modify it under the terms of the GNU Library General Public           *
 *   License as published by the Free Software Foundation; either          *
 *   version 2 of the License, or (at your option) any later version.      *
 *                                                                         *
 *   This library  is distributed in the hope that it will be useful,      *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU Library General Public License for more details.                  *
 *                                                                         *
 *   You should have received a copy of the GNU Library General Public     *
 *   License along with this library; see the file COPYING.LIB. If not,    *
 *   write to the Free Software Foundation, Inc., 59 Temple Place,         *
 *   Suite 330, Boston, MA  02111-1307, USA                                *
 *                                                                         *
 ***************************************************************************/

#include "PreCompiled.h"
#ifndef _PreComp_
# include <gp.hxx>
# include <gp_Lin.hxx>
# include <Geom_Line.hxx>
# include <Geom_TrimmedCurve.hxx>
# include <GC_MakeLine.hxx>
# include <GC_MakeSegment.hxx>
# include <Precision.hxx>
#endif

#include <Base/VectorPy.h>
#include <Base/GeometryPyCXX.h>

#include "OCCError.h"
#include "Geometry.h"
#include "LinePy.h"
#include "LinePy.cpp"

using namespace Part;

extern const char* gce_ErrorStatusText(gce_ErrorType et);

// returns a string which represents the object e.g. when printed in python
std::string LinePy::representation(void) const
{
    std::stringstream str;
    //if(Infinite)
    //   str << "<Line infinite>";
    //else {
        Base::Vector3d start = getGeomLineSegmentPtr()->getStartPoint();
        Base::Vector3d end   = getGeomLineSegmentPtr()->getEndPoint();
        str << "<Line ("
            << start.x << "," <<start.y << "," <<start.z << ") ("
            << end.x   << "," <<end.y   << "," <<end.z   << ") >";
    //}

    return str.str();
}

PyObject *LinePy::PyMake(struct _typeobject *, PyObject *, PyObject *)  // Python wrapper
{
    // create a new instance of LinePy and the Twin object
    return new LinePy(new GeomLineSegment);
}

// constructor method
int LinePy::PyInit(PyObject* args, PyObject* /*kwd*/)
{

    if (PyArg_ParseTuple(args, "")) {
        // default line
        Infinite=false;
        return 0;
    }

    PyErr_Clear();
    PyObject *pLine;
    if (PyArg_ParseTuple(args, "O!", &(LinePy::Type), &pLine)) {
        // Copy line
        LinePy* pcLine = static_cast<LinePy*>(pLine);
        // get Geom_Line of line segment
        Handle_Geom_TrimmedCurve that_curv = Handle_Geom_TrimmedCurve::DownCast
            (pcLine->getGeomLineSegmentPtr()->handle());
        Handle_Geom_Line that_line = Handle_Geom_Line::DownCast
            (that_curv->BasisCurve());
        // get Geom_Line of line segment
        Handle_Geom_TrimmedCurve this_curv = Handle_Geom_TrimmedCurve::DownCast
            (this->getGeomLineSegmentPtr()->handle());
        Handle_Geom_Line this_line = Handle_Geom_Line::DownCast
            (this_curv->BasisCurve());

        Infinite = pcLine->Infinite;

        // Assign the lines
        this_line->SetLin(that_line->Lin());
        this_curv->SetTrim(that_curv->FirstParameter(), that_curv->LastParameter());
        return 0;
    }

    PyErr_Clear();
    double first, last;
    if (PyArg_ParseTuple(args, "O!dd", &(LinePy::Type), &pLine, &first, &last)) {
        // Copy line
        LinePy* pcLine = static_cast<LinePy*>(pLine);
        // get Geom_Line of line segment
        Handle_Geom_TrimmedCurve that_curv = Handle_Geom_TrimmedCurve::DownCast
            (pcLine->getGeomLineSegmentPtr()->handle());
        Handle_Geom_Line that_line = Handle_Geom_Line::DownCast
            (that_curv->BasisCurve());
        // get Geom_Line of line segment
        Handle_Geom_TrimmedCurve this_curv = Handle_Geom_TrimmedCurve::DownCast
            (this->getGeomLineSegmentPtr()->handle());
        Handle_Geom_Line this_line = Handle_Geom_Line::DownCast
            (this_curv->BasisCurve());

        Infinite = pcLine->Infinite;

        // Assign the lines
        this_line->SetLin(that_line->Lin());
        this_curv->SetTrim(first, last);
        return 0;
    }

    PyErr_Clear();
    PyObject *pV1, *pV2;
    if (PyArg_ParseTuple(args, "O!O!", &(Base::VectorPy::Type), &pV1,
                                       &(Base::VectorPy::Type), &pV2)) {
        Base::Vector3d v1 = static_cast<Base::VectorPy*>(pV1)->value();
        Base::Vector3d v2 = static_cast<Base::VectorPy*>(pV2)->value();
        try {
            // Create line out of two points
            double distance = Base::Distance(v1, v2);
            if (distance < gp::Resolution())
                Standard_Failure::Raise("Both points are equal");
            GC_MakeSegment ms(gp_Pnt(v1.x,v1.y,v1.z),
                              gp_Pnt(v2.x,v2.y,v2.z));
            if (!ms.IsDone()) {
                PyErr_SetString(PartExceptionOCCError, gce_ErrorStatusText(ms.Status()));
                return -1;
            }

            // get Geom_Line of line segment
            Handle_Geom_TrimmedCurve this_curv = Handle_Geom_TrimmedCurve::DownCast
                (this->getGeomLineSegmentPtr()->handle());
            Handle_Geom_Line this_line = Handle_Geom_Line::DownCast
                (this_curv->BasisCurve());
            Handle_Geom_TrimmedCurve that_curv = ms.Value();
            Handle_Geom_Line that_line = Handle_Geom_Line::DownCast(that_curv->BasisCurve());
            this_line->SetLin(that_line->Lin());
            this_curv->SetTrim(that_curv->FirstParameter(), that_curv->LastParameter());

            Infinite = false;
            return 0;
        }
        catch (Standard_Failure) {
            Handle_Standard_Failure e = Standard_Failure::Caught();
            PyErr_SetString(PartExceptionOCCError, e->GetMessageString());
            return -1;
        }
        catch (...) {
            PyErr_SetString(PartExceptionOCCError, "creation of line failed");
            return -1;
        }
    }

    PyErr_SetString(PyExc_TypeError, "Line constructor accepts:\n"
        "-- empty parameter list\n"
        "-- Line\n"
        "-- Point, Point");
    return -1;
}

PyObject* LinePy::setParameterRange(PyObject *args)
{
    double first, last;
    if (!PyArg_ParseTuple(args, "dd", &first, &last))
        return NULL;

    try {
        Handle_Geom_TrimmedCurve this_curve = Handle_Geom_TrimmedCurve::DownCast
            (this->getGeomLineSegmentPtr()->handle());
        this_curve->SetTrim(first, last);
    }
    catch (Standard_Failure) {
        Handle_Standard_Failure e = Standard_Failure::Caught();
        PyErr_SetString(PartExceptionOCCError, e->GetMessageString());
        return NULL;
    }

    Py_Return;
}

Py::Object LinePy::getStartPoint(void) const
{
    Handle_Geom_TrimmedCurve this_curve = Handle_Geom_TrimmedCurve::DownCast
        (this->getGeomLineSegmentPtr()->handle());
    gp_Pnt pnt = this_curve->StartPoint();
    return Py::Vector(Base::Vector3d(pnt.X(), pnt.Y(), pnt.Z()));
}

void LinePy::setStartPoint(Py::Object arg)
{
    gp_Pnt p1, p2;
    Handle_Geom_TrimmedCurve this_curv = Handle_Geom_TrimmedCurve::DownCast
        (this->getGeomLineSegmentPtr()->handle());
    p2 = this_curv->EndPoint();

    PyObject *p = arg.ptr();
    if (PyObject_TypeCheck(p, &(Base::VectorPy::Type))) {
        Base::Vector3d v = static_cast<Base::VectorPy*>(p)->value();
        p1.SetX(v.x);
        p1.SetY(v.y);
        p1.SetZ(v.z);
    }
    else if (PyTuple_Check(p)) {
        Py::Tuple tuple(arg);
        p1.SetX((double)Py::Float(tuple.getItem(0)));
        p1.SetY((double)Py::Float(tuple.getItem(1)));
        p1.SetZ((double)Py::Float(tuple.getItem(2)));
    }
    else {
        std::string error = std::string("type must be 'Vector' or tuple, not ");
        error += p->ob_type->tp_name;
        throw Py::TypeError(error);
    }

    try {
        // Create line out of two points
        if (p1.Distance(p2) < gp::Resolution())
            Standard_Failure::Raise("Both points are equal");
        GC_MakeSegment ms(p1, p2);
        if (!ms.IsDone()) {
            throw Py::Exception(gce_ErrorStatusText(ms.Status()));
        }

        // get Geom_Line of line segment
        Handle_Geom_Line this_line = Handle_Geom_Line::DownCast
            (this_curv->BasisCurve());
        Handle_Geom_TrimmedCurve that_curv = ms.Value();
        Handle_Geom_Line that_line = Handle_Geom_Line::DownCast(that_curv->BasisCurve());
        this_line->SetLin(that_line->Lin());
        this_curv->SetTrim(that_curv->FirstParameter(), that_curv->LastParameter());
    }
    catch (Standard_Failure) {
        Handle_Standard_Failure e = Standard_Failure::Caught();
        throw Py::Exception(e->GetMessageString());
    }
}

Py::Object LinePy::getEndPoint(void) const
{
    Handle_Geom_TrimmedCurve this_curve = Handle_Geom_TrimmedCurve::DownCast
        (this->getGeomLineSegmentPtr()->handle());
    gp_Pnt pnt = this_curve->EndPoint();
    return Py::Vector(Base::Vector3d(pnt.X(), pnt.Y(), pnt.Z()));
}

void LinePy::setEndPoint(Py::Object arg)
{
    gp_Pnt p1, p2;
    Handle_Geom_TrimmedCurve this_curv = Handle_Geom_TrimmedCurve::DownCast
        (this->getGeomLineSegmentPtr()->handle());
    p1 = this_curv->StartPoint();

    PyObject *p = arg.ptr();
    if (PyObject_TypeCheck(p, &(Base::VectorPy::Type))) {
        Base::Vector3d v = static_cast<Base::VectorPy*>(p)->value();
        p2.SetX(v.x);
        p2.SetY(v.y);
        p2.SetZ(v.z);
    }
    else if (PyTuple_Check(p)) {
        Py::Tuple tuple(arg);
        p2.SetX((double)Py::Float(tuple.getItem(0)));
        p2.SetY((double)Py::Float(tuple.getItem(1)));
        p2.SetZ((double)Py::Float(tuple.getItem(2)));
    }
    else {
        std::string error = std::string("type must be 'Vector' or tuple, not ");
        error += p->ob_type->tp_name;
        throw Py::TypeError(error);
    }

    try {
        // Create line out of two points
        if (p1.Distance(p2) < gp::Resolution())
            Standard_Failure::Raise("Both points are equal");
        GC_MakeSegment ms(p1, p2);
        if (!ms.IsDone()) {
            throw Py::Exception(gce_ErrorStatusText(ms.Status()));
        }

        // get Geom_Line of line segment
        Handle_Geom_Line this_line = Handle_Geom_Line::DownCast
            (this_curv->BasisCurve());
        Handle_Geom_TrimmedCurve that_curv = ms.Value();
        Handle_Geom_Line that_line = Handle_Geom_Line::DownCast(that_curv->BasisCurve());
        this_line->SetLin(that_line->Lin());
        this_curv->SetTrim(that_curv->FirstParameter(), that_curv->LastParameter());
    }
    catch (Standard_Failure) {
        Handle_Standard_Failure e = Standard_Failure::Caught();
        throw Py::Exception(e->GetMessageString());
    }
}

Py::Boolean LinePy::getInfinite(void) const
{
    return Py::Boolean(Infinite);
}

void  LinePy::setInfinite(Py::Boolean arg)
{
    Infinite = arg;
}

PyObject *LinePy::getCustomAttributes(const char* /*attr*/) const
{
    return 0;
}

int LinePy::setCustomAttributes(const char* /*attr*/, PyObject* /*obj*/)
{
    return 0;
}
<|endoftext|>


<commit_before>#ifndef slic3r_LOG_HPP
#define slic3r_LOG_HPP

#include <string>

namespace Slic3r {

class Log {
public:
    static void fatal_error(std::string topic, std::wstring message) {
        std::cerr << topic << " FERR" << ": ";
        std::wcerr << message << std::endl;
    }
    static void error(std::string topic, std::wstring message) {
        std::cerr << topic << "  ERR" << ": ";
        std::wcerr << message << std::endl;
    }

    static void info(std::string topic, std::wstring message) {
        std::clog << topic << " INFO" << ": ";
        std::wclog << message << std::endl;
    }

    static void warn(std::string topic, std::wstring message) {
        std::cerr << topic << " WARN" << ": ";
        std::wcerr << message << std::endl;
    }

};

}

#endif // slic3r_LOG_HPP
<commit_msg>add log function to build strings for vectors<commit_after>#ifndef slic3r_LOG_HPP
#define slic3r_LOG_HPP

#include <string>
#include <vector>
#include <sstream>

namespace Slic3r {

class Log {
public:
    static void fatal_error(std::string topic, std::wstring message) {
        std::cerr << topic << " FERR" << ": ";
        std::wcerr << message << std::endl;
    }
    static void error(std::string topic, std::wstring message) {
        std::cerr << topic << "  ERR" << ": ";
        std::wcerr << message << std::endl;
    }

    static void info(std::string topic, std::wstring message) {
        std::clog << topic << " INFO" << ": ";
        std::wclog << message << std::endl;
    }

    static void warn(std::string topic, std::wstring message) {
        std::cerr << topic << " WARN" << ": ";
        std::wcerr << message << std::endl;
    }

};

/// Utility debug function to transform a std::vector of anything that
/// supports ostream& operator<<() into a std::string.
template <typename T>
std::string
log_string(const std::vector<T>& in)
{
    std::stringstream ss;
    bool first {true};
    ss << "[ ";
    for (auto& c : in) {
        if (!first) {
            ss << ", ";
        }
        ss << c;
        first = false;
    }

    ss << " ]";

    return ss.str();
}

}

#endif // slic3r_LOG_HPP
<|endoftext|>


<commit_before>/*
-----------------------------------------------------------------------------
Copyright (c) 2011 Joachim Dorner

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
-----------------------------------------------------------------------------
*/

#include "Common.h"
#include "Connection.h"
#include "Function.h"

Connection::Connection( v8::Handle<v8::Object> thisHandle) :
  loginParamsSize(0),
  loginParams(nullptr),
  connectionHandle(nullptr)
{
  uv_mutex_init(&this->invocationMutex);
  init( thisHandle);
}

Connection::~Connection()
{
  deferLog(Levels::SILLY, "Connection::~Connection");
  this->CloseConnection();

  uv_mutex_destroy(&this->invocationMutex);

  for (unsigned int i = 0; i < this->loginParamsSize; i++) {
     free(const_cast<SAP_UC*>(loginParams[i].name));
     free(const_cast<SAP_UC*>(loginParams[i].value));
  }
  free(loginParams);

  delete this->cbOpen;
  this->cbOpen = nullptr;
}

NAN_METHOD(Connection::New)
{
  if (!info.IsConstructCall()) {
    Nan::ThrowError("Invalid call format. Please use the 'new' operator.");
    return;
  }

  Connection *self = new Connection( info.This());

  self->log(Levels::SILLY, "Connection object created");

  info.GetReturnValue().Set(info.This());
}

NAN_MODULE_INIT(Connection::Init)
{
  Nan::HandleScope scope;

  v8::Local<v8::FunctionTemplate> ctorTemplate = Nan::New<v8::FunctionTemplate>(New);
  ctorTemplate->InstanceTemplate()->SetInternalFieldCount(1);
  ctorTemplate->SetClassName(Nan::New("Connection").ToLocalChecked());

  Nan::SetPrototypeMethod(ctorTemplate, "GetVersion", Connection::GetVersion);
  Nan::SetPrototypeMethod(ctorTemplate, "Open", Connection::Open);
  Nan::SetPrototypeMethod(ctorTemplate, "Close", Connection::Close);
  Nan::SetPrototypeMethod(ctorTemplate, "Ping", Connection::Ping);
  Nan::SetPrototypeMethod(ctorTemplate, "IsOpen", Connection::IsOpen);
  Nan::SetPrototypeMethod(ctorTemplate, "Lookup", Connection::Lookup);
  Nan::SetPrototypeMethod(ctorTemplate, "SetIniPath", Connection::SetIniPath);

  Nan::Set(target, Nan::New("Connection").ToLocalChecked(), ctorTemplate->GetFunction());
}

/**
 * @return Array
 */
NAN_METHOD(Connection::GetVersion)
{
  unsigned majorVersion, minorVersion, patchLevel;

  RfcGetVersion(&majorVersion, &minorVersion, &patchLevel);
  v8::Local<v8::Array> versionInfo = Nan::New<v8::Array>(3);

  versionInfo->Set(0, Nan::New<v8::Integer>(majorVersion));
  versionInfo->Set(1, Nan::New<v8::Integer>(minorVersion));
  versionInfo->Set(2, Nan::New<v8::Integer>(patchLevel));

  info.GetReturnValue().Set(versionInfo);
}

NAN_METHOD(Connection::Open)
{
  Connection *self = node::ObjectWrap::Unwrap<Connection>(info.This());

  self->log(Levels::VERBOSE, "opening new SAP connection");

  if (info.Length() < 2) {
    Nan::ThrowError("Function expects 2 arguments");
    return;
  }
  if (!info[0]->IsObject()) {
    Nan::ThrowError("Argument 1 must be an object");
    return;
  }
  if (!info[1]->IsFunction()) {
    Nan::ThrowError("Argument 2 must be a function");
    return;
  }

  v8::Local<v8::Object> optionsObj = info[0]->ToObject();
  v8::Local<v8::Array> props = optionsObj->GetPropertyNames();

  self->loginParamsSize = props->Length();
  self->loginParams = static_cast<RFC_CONNECTION_PARAMETER*>(malloc(self->loginParamsSize * sizeof(RFC_CONNECTION_PARAMETER)));
  memset(self->loginParams, 0, self->loginParamsSize * sizeof(RFC_CONNECTION_PARAMETER));
  memset(&self->errorInfo, 0, sizeof(RFC_ERROR_INFO));

  self->log(Levels::DBG, "Connection params", optionsObj);

  for (unsigned int i = 0; i < self->loginParamsSize; i++) {
    v8::Local<v8::Value> name = props->Get(i);
    v8::Local<v8::Value> value = optionsObj->Get(name->ToString());

    self->loginParams[i].name = convertToSAPUC(name);
    self->loginParams[i].value = convertToSAPUC(value);

#ifndef NDEBUG
    std::cout << convertToString(name) << "--> " << convertToString(value) << std::endl;
#endif
  }

  // Store callback
  self->cbOpen = new Nan::Callback(v8::Local<v8::Function>::Cast(info[1]));
  self->Ref();

  uv_work_t* req = new uv_work_t();
  req->data = self;
  uv_queue_work(uv_default_loop(), req, EIO_Open, (uv_after_work_cb)EIO_AfterOpen);
#if !NODE_VERSION_AT_LEAST(0, 7, 9)
    uv_ref(uv_default_loop());
#endif
}

void Connection::EIO_Open(uv_work_t *req)
{
  Connection *self = static_cast<Connection*>(req->data);

  self->connectionHandle = RfcOpenConnection(self->loginParams, self->loginParamsSize, &self->errorInfo);
  DEFER_LOG_API(self, "RfcOpenConnection");
}

void Connection::EIO_AfterOpen(uv_work_t *req)
{
  Nan::HandleScope scope;
  int isValid;
  Connection *self = static_cast<Connection*>(req->data);

  v8::Local<v8::Value> argv[1];
  argv[0] = Nan::Null();

  if (self->connectionHandle == nullptr) {
    self->log(Levels::DBG, "Connection handle is NULL, connection failed");
    argv[0] = RfcError(self->errorInfo);
  } else {
    RfcIsConnectionHandleValid(self->connectionHandle, &isValid, &self->errorInfo);
    LOG_API(self, "RfcIsConnectionHandleValid");
    if (!isValid) {
      self->log(Levels::SILLY, "Connection not valid");
      argv[0] = RfcError(self->errorInfo);
    } else {
      self->log(Levels::SILLY, "Connection still valid");
    }
  }

  Nan::TryCatch try_catch;

  self->log(Levels::SILLY, "EIO_AfterOpen: About to call the callback");
  assert(!self->cbOpen->IsEmpty());
  self->cbOpen->Call(1, argv);
  delete self->cbOpen;
  self->cbOpen = nullptr;
  self->Unref();
  self->log(Levels::SILLY, "EIO_AfterOpen: Finished callback");

  if (try_catch.HasCaught()) {
    self->log(Levels::ERR, "EIO_AfterOpen: Exception thrown in callback. Abort.");
    Nan::FatalException(try_catch);
  }
}

NAN_METHOD(Connection::Close)
{
  Connection *self = node::ObjectWrap::Unwrap<Connection>(info.This());
  self->log(Levels::SILLY, "Connection::Close");
  info.GetReturnValue().Set(self->CloseConnection());
}

v8::Local<v8::Value> Connection::CloseConnection(void)
{
  Nan::EscapableHandleScope scope;
  RFC_RC rc = RFC_OK;

  log(Levels::SILLY, "Connection::CloseConnection");

  if (this->connectionHandle != nullptr) {
    rc = RfcCloseConnection(this->connectionHandle, &errorInfo);
    LOG_API(this, "RfcCloseConnection");
    if (rc != RFC_OK) {
      log(Levels::DBG, "Connection::CloseConnection: Error closing connection");
      return scope.Escape(RfcError(errorInfo));
    }
  }

  return scope.Escape(Nan::True());
}

RFC_CONNECTION_HANDLE Connection::GetConnectionHandle(void)
{
  return this->connectionHandle;
}

void Connection::LockMutex(void)
{
  uv_mutex_lock(&this->invocationMutex);
}

void Connection::UnlockMutex(void)
{
  uv_mutex_unlock(&this->invocationMutex);
}

void Connection::addObjectInfoToLogMeta(v8::Local<v8::Object> meta)
{
  char ptr[ 2 + sizeof(void*)*2 + 1]; // optional "0x" + each byte of pointer represented by 2 digits + terminator
  snprintf( ptr, 2 + sizeof(void*)*2 + 1, "%p", this);
  meta->Set(Nan::New<v8::String>("nativeConnection").ToLocalChecked(),
            Nan::New<v8::String>(ptr).ToLocalChecked());
}

NAN_METHOD(Connection::IsOpen)
{
  Connection *self = node::ObjectWrap::Unwrap<Connection>(info.This());
  RFC_RC rc = RFC_OK;
  int isValid;

  self->log(Levels::SILLY, "Connection::IsOpen");

  rc = RfcIsConnectionHandleValid(self->connectionHandle, &isValid, &self->errorInfo);
  LOG_API(self, "RfcIsConnectionHandleValid");
  if(!isValid) {
    self->log(Levels::SILLY, "Connection::IsOpen: RfcIsConnectionHandleValid returned false");
    info.GetReturnValue().Set(Nan::False());
  } else {
    self->log(Levels::SILLY, "Connection::IsOpen: RfcIsConnectionHandleValid returned true");
    info.GetReturnValue().Set(Nan::True());
  }

}

/**
 *
 * @return true if successful, else: RfcException
 */
NAN_METHOD(Connection::Ping)
{
  Connection *self = node::ObjectWrap::Unwrap<Connection>(info.This());
  RFC_RC rc = RFC_OK;

  self->log(Levels::SILLY, "Connection::IsOpen");

  if (info.Length() > 0) {
    Nan::ThrowError("No arguments expected");
    return;
  }

  rc = RfcPing(self->connectionHandle, &self->errorInfo);
  LOG_API(self, "RfcPing");
  if (rc != RFC_OK) {
    RETURN_RFC_ERROR(self->errorInfo);
  }

  info.GetReturnValue().Set(Nan::True());
}

/**
 *
 * @return Function
 */
NAN_METHOD(Connection::Lookup)
{
  int isValid;

  Connection *self = node::ObjectWrap::Unwrap<Connection>(info.This());

  self->log(Levels::SILLY, "Connection::Lookup");

  if (info.Length() < 1 || info.Length() > 2) {
    Nan::ThrowError("Function expects 1 or 2 arguments");
    return;
  }
  if (!info[0]->IsString()) {
    Nan::ThrowError("Argument 1 must be function module name");
    return;
  }

  if (info.Length() > 1 && !info[1]->IsObject()) {
    Nan::ThrowError("Argument 2 must be an object");
    return;
  }

  RfcIsConnectionHandleValid(self->connectionHandle, &isValid, &self->errorInfo);
  LOG_API(self, "RfcIsConnectionHandleValid");
  if (!isValid) {
    self->log(Levels::SILLY, "Connection::Lookup: RfcIsConnectionHandleValid returned false");
    Nan::ThrowError(RfcError(self->errorInfo));
    return;
  } else {
    self->log(Levels::SILLY, "Connection::Lookup: RfcIsConnectionHandleValid returned true");
  }

  self->log(Levels::SILLY, "Connection::Lookup: About to create function instance");
  v8::Local<v8::Value> f = Function::NewInstance(*self, info);
  if( IsException(f)) {
    self->log(Levels::DBG, "Connection::Lookup: Unable to create function instance");
    Nan::ThrowError(f);
  }
  info.GetReturnValue().Set(f);
}

/**
 *
 * @return true if successful, else: RfcException
 */
NAN_METHOD(Connection::SetIniPath)
{
  Connection *self = node::ObjectWrap::Unwrap<Connection>(info.This());

  self->log(Levels::SILLY, "Connection::SetIniPath");

  if (info.Length() != 1) {
    Nan::ThrowError("Function expects 1 argument");
    return;
  }
  if (!info[0]->IsString()) {
    Nan::ThrowError("Argument 1 must be a path name");
    return;
  }

  v8::Local<v8::Value> iniPath = info[0]->ToString();

  RfcSetIniPath(convertToSAPUC(iniPath), &self->errorInfo);
  LOG_API(self, "RfcSetIniPath");
  if (self->errorInfo.code) {
    self->log(Levels::DBG, "Connection::SetIniPath: RfcSetIniPath failed");
    Nan::ThrowError(RfcError(self->errorInfo));
    return;
  }

  info.GetReturnValue().Set(Nan::True());
}
<commit_msg>RFS-92: Crash in connection destructor<commit_after>/*
-----------------------------------------------------------------------------
Copyright (c) 2011 Joachim Dorner

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
-----------------------------------------------------------------------------
*/

#include "Common.h"
#include "Connection.h"
#include "Function.h"

Connection::Connection( v8::Handle<v8::Object> thisHandle) :
  loginParamsSize(0),
  loginParams(nullptr),
  connectionHandle(nullptr)
{
  uv_mutex_init(&this->invocationMutex);
  init( thisHandle);
}

Connection::~Connection()
{
  deferLog(Levels::SILLY, "Connection::~Connection");

  if (this->connectionHandle != nullptr) {
    RFC_RC rc = RfcCloseConnection(this->connectionHandle, &errorInfo);
    DEFER_LOG_API(this, "RfcCloseConnection");
    if (rc != RFC_OK) {
      deferLog(Levels::DBG, "Connection::CloseConnection: Error closing connection");
    }
  }

  uv_mutex_destroy(&this->invocationMutex);

  for (unsigned int i = 0; i < this->loginParamsSize; i++) {
     free(const_cast<SAP_UC*>(loginParams[i].name));
     free(const_cast<SAP_UC*>(loginParams[i].value));
  }
  free(loginParams);

  delete this->cbOpen;
  this->cbOpen = nullptr;
  deferLog(Levels::SILLY, "Connection::~Connection [end]");
}

NAN_METHOD(Connection::New)
{
  if (!info.IsConstructCall()) {
    Nan::ThrowError("Invalid call format. Please use the 'new' operator.");
    return;
  }

  Connection *self = new Connection( info.This());

  self->log(Levels::SILLY, "Connection object created");

  info.GetReturnValue().Set(info.This());
}

NAN_MODULE_INIT(Connection::Init)
{
  Nan::HandleScope scope;

  v8::Local<v8::FunctionTemplate> ctorTemplate = Nan::New<v8::FunctionTemplate>(New);
  ctorTemplate->InstanceTemplate()->SetInternalFieldCount(1);
  ctorTemplate->SetClassName(Nan::New("Connection").ToLocalChecked());

  Nan::SetPrototypeMethod(ctorTemplate, "GetVersion", Connection::GetVersion);
  Nan::SetPrototypeMethod(ctorTemplate, "Open", Connection::Open);
  Nan::SetPrototypeMethod(ctorTemplate, "Close", Connection::Close);
  Nan::SetPrototypeMethod(ctorTemplate, "Ping", Connection::Ping);
  Nan::SetPrototypeMethod(ctorTemplate, "IsOpen", Connection::IsOpen);
  Nan::SetPrototypeMethod(ctorTemplate, "Lookup", Connection::Lookup);
  Nan::SetPrototypeMethod(ctorTemplate, "SetIniPath", Connection::SetIniPath);

  Nan::Set(target, Nan::New("Connection").ToLocalChecked(), ctorTemplate->GetFunction());
}

/**
 * @return Array
 */
NAN_METHOD(Connection::GetVersion)
{
  unsigned majorVersion, minorVersion, patchLevel;

  RfcGetVersion(&majorVersion, &minorVersion, &patchLevel);
  v8::Local<v8::Array> versionInfo = Nan::New<v8::Array>(3);

  versionInfo->Set(0, Nan::New<v8::Integer>(majorVersion));
  versionInfo->Set(1, Nan::New<v8::Integer>(minorVersion));
  versionInfo->Set(2, Nan::New<v8::Integer>(patchLevel));

  info.GetReturnValue().Set(versionInfo);
}

NAN_METHOD(Connection::Open)
{
  Connection *self = node::ObjectWrap::Unwrap<Connection>(info.This());

  self->log(Levels::VERBOSE, "opening new SAP connection");

  if (info.Length() < 2) {
    Nan::ThrowError("Function expects 2 arguments");
    return;
  }
  if (!info[0]->IsObject()) {
    Nan::ThrowError("Argument 1 must be an object");
    return;
  }
  if (!info[1]->IsFunction()) {
    Nan::ThrowError("Argument 2 must be a function");
    return;
  }

  v8::Local<v8::Object> optionsObj = info[0]->ToObject();
  v8::Local<v8::Array> props = optionsObj->GetPropertyNames();

  self->loginParamsSize = props->Length();
  self->loginParams = static_cast<RFC_CONNECTION_PARAMETER*>(malloc(self->loginParamsSize * sizeof(RFC_CONNECTION_PARAMETER)));
  memset(self->loginParams, 0, self->loginParamsSize * sizeof(RFC_CONNECTION_PARAMETER));
  memset(&self->errorInfo, 0, sizeof(RFC_ERROR_INFO));

  self->log(Levels::DBG, "Connection params", optionsObj);

  for (unsigned int i = 0; i < self->loginParamsSize; i++) {
    v8::Local<v8::Value> name = props->Get(i);
    v8::Local<v8::Value> value = optionsObj->Get(name->ToString());

    self->loginParams[i].name = convertToSAPUC(name);
    self->loginParams[i].value = convertToSAPUC(value);

#ifndef NDEBUG
    std::cout << convertToString(name) << "--> " << convertToString(value) << std::endl;
#endif
  }

  // Store callback
  self->cbOpen = new Nan::Callback(v8::Local<v8::Function>::Cast(info[1]));
  self->Ref();

  uv_work_t* req = new uv_work_t();
  req->data = self;
  uv_queue_work(uv_default_loop(), req, EIO_Open, (uv_after_work_cb)EIO_AfterOpen);
#if !NODE_VERSION_AT_LEAST(0, 7, 9)
    uv_ref(uv_default_loop());
#endif
}

void Connection::EIO_Open(uv_work_t *req)
{
  Connection *self = static_cast<Connection*>(req->data);

  self->connectionHandle = RfcOpenConnection(self->loginParams, self->loginParamsSize, &self->errorInfo);
  DEFER_LOG_API(self, "RfcOpenConnection");
}

void Connection::EIO_AfterOpen(uv_work_t *req)
{
  Nan::HandleScope scope;
  int isValid;
  Connection *self = static_cast<Connection*>(req->data);

  v8::Local<v8::Value> argv[1];
  argv[0] = Nan::Null();

  if (self->connectionHandle == nullptr) {
    self->log(Levels::DBG, "Connection handle is NULL, connection failed");
    argv[0] = RfcError(self->errorInfo);
  } else {
    RfcIsConnectionHandleValid(self->connectionHandle, &isValid, &self->errorInfo);
    LOG_API(self, "RfcIsConnectionHandleValid");
    if (!isValid) {
      self->log(Levels::SILLY, "Connection not valid");
      argv[0] = RfcError(self->errorInfo);
    } else {
      self->log(Levels::SILLY, "Connection still valid");
    }
  }

  Nan::TryCatch try_catch;

  self->log(Levels::SILLY, "EIO_AfterOpen: About to call the callback");
  assert(!self->cbOpen->IsEmpty());
  self->cbOpen->Call(1, argv);
  delete self->cbOpen;
  self->cbOpen = nullptr;
  self->Unref();
  self->log(Levels::SILLY, "EIO_AfterOpen: Finished callback");

  if (try_catch.HasCaught()) {
    self->log(Levels::ERR, "EIO_AfterOpen: Exception thrown in callback. Abort.");
    Nan::FatalException(try_catch);
  }
}

NAN_METHOD(Connection::Close)
{
  Connection *self = node::ObjectWrap::Unwrap<Connection>(info.This());
  self->log(Levels::SILLY, "Connection::Close");
  info.GetReturnValue().Set(self->CloseConnection());
}

v8::Local<v8::Value> Connection::CloseConnection(void)
{
  Nan::EscapableHandleScope scope;
  RFC_RC rc = RFC_OK;

  log(Levels::SILLY, "Connection::CloseConnection");

  if (this->connectionHandle != nullptr) {
    rc = RfcCloseConnection(this->connectionHandle, &errorInfo);
    LOG_API(this, "RfcCloseConnection");
    if (rc != RFC_OK) {
      log(Levels::DBG, "Connection::CloseConnection: Error closing connection");
      return scope.Escape(RfcError(errorInfo));
    }
  }

  return scope.Escape(Nan::True());
}

RFC_CONNECTION_HANDLE Connection::GetConnectionHandle(void)
{
  return this->connectionHandle;
}

void Connection::LockMutex(void)
{
  uv_mutex_lock(&this->invocationMutex);
}

void Connection::UnlockMutex(void)
{
  uv_mutex_unlock(&this->invocationMutex);
}

void Connection::addObjectInfoToLogMeta(v8::Local<v8::Object> meta)
{
  char ptr[ 2 + sizeof(void*)*2 + 1]; // optional "0x" + each byte of pointer represented by 2 digits + terminator
  snprintf( ptr, 2 + sizeof(void*)*2 + 1, "%p", this);
  meta->Set(Nan::New<v8::String>("nativeConnection").ToLocalChecked(),
            Nan::New<v8::String>(ptr).ToLocalChecked());
}

NAN_METHOD(Connection::IsOpen)
{
  Connection *self = node::ObjectWrap::Unwrap<Connection>(info.This());
  RFC_RC rc = RFC_OK;
  int isValid;

  self->log(Levels::SILLY, "Connection::IsOpen");

  rc = RfcIsConnectionHandleValid(self->connectionHandle, &isValid, &self->errorInfo);
  LOG_API(self, "RfcIsConnectionHandleValid");
  if(!isValid) {
    self->log(Levels::SILLY, "Connection::IsOpen: RfcIsConnectionHandleValid returned false");
    info.GetReturnValue().Set(Nan::False());
  } else {
    self->log(Levels::SILLY, "Connection::IsOpen: RfcIsConnectionHandleValid returned true");
    info.GetReturnValue().Set(Nan::True());
  }

}

/**
 *
 * @return true if successful, else: RfcException
 */
NAN_METHOD(Connection::Ping)
{
  Connection *self = node::ObjectWrap::Unwrap<Connection>(info.This());
  RFC_RC rc = RFC_OK;

  self->log(Levels::SILLY, "Connection::IsOpen");

  if (info.Length() > 0) {
    Nan::ThrowError("No arguments expected");
    return;
  }

  rc = RfcPing(self->connectionHandle, &self->errorInfo);
  LOG_API(self, "RfcPing");
  if (rc != RFC_OK) {
    RETURN_RFC_ERROR(self->errorInfo);
  }

  info.GetReturnValue().Set(Nan::True());
}

/**
 *
 * @return Function
 */
NAN_METHOD(Connection::Lookup)
{
  int isValid;

  Connection *self = node::ObjectWrap::Unwrap<Connection>(info.This());

  self->log(Levels::SILLY, "Connection::Lookup");

  if (info.Length() < 1 || info.Length() > 2) {
    Nan::ThrowError("Function expects 1 or 2 arguments");
    return;
  }
  if (!info[0]->IsString()) {
    Nan::ThrowError("Argument 1 must be function module name");
    return;
  }

  if (info.Length() > 1 && !info[1]->IsObject()) {
    Nan::ThrowError("Argument 2 must be an object");
    return;
  }

  RfcIsConnectionHandleValid(self->connectionHandle, &isValid, &self->errorInfo);
  LOG_API(self, "RfcIsConnectionHandleValid");
  if (!isValid) {
    self->log(Levels::SILLY, "Connection::Lookup: RfcIsConnectionHandleValid returned false");
    Nan::ThrowError(RfcError(self->errorInfo));
    return;
  } else {
    self->log(Levels::SILLY, "Connection::Lookup: RfcIsConnectionHandleValid returned true");
  }

  self->log(Levels::SILLY, "Connection::Lookup: About to create function instance");
  v8::Local<v8::Value> f = Function::NewInstance(*self, info);
  if( IsException(f)) {
    self->log(Levels::DBG, "Connection::Lookup: Unable to create function instance");
    Nan::ThrowError(f);
  }
  info.GetReturnValue().Set(f);
}

/**
 *
 * @return true if successful, else: RfcException
 */
NAN_METHOD(Connection::SetIniPath)
{
  Connection *self = node::ObjectWrap::Unwrap<Connection>(info.This());

  self->log(Levels::SILLY, "Connection::SetIniPath");

  if (info.Length() != 1) {
    Nan::ThrowError("Function expects 1 argument");
    return;
  }
  if (!info[0]->IsString()) {
    Nan::ThrowError("Argument 1 must be a path name");
    return;
  }

  v8::Local<v8::Value> iniPath = info[0]->ToString();

  RfcSetIniPath(convertToSAPUC(iniPath), &self->errorInfo);
  LOG_API(self, "RfcSetIniPath");
  if (self->errorInfo.code) {
    self->log(Levels::DBG, "Connection::SetIniPath: RfcSetIniPath failed");
    Nan::ThrowError(RfcError(self->errorInfo));
    return;
  }

  info.GetReturnValue().Set(Nan::True());
}
<|endoftext|>


<commit_before>#include <cassert>
#include <ctime>
#include <iostream>
#include <list>
#include <netinet/in.h>
#include <sstream>
#include <string>
#include <sys/types.h>
#include <sys/socket.h>
#include <typeinfo>
#include <unistd.h>

#include "../../include/domains/racetrack/RacetrackProblem.h"
#include "../../include/domains/racetrack/RTrackDetHeuristic.h"
#include "../../include/domains/DummyState.h"

#include "../include/ppddl/mini-gpt/states.h"
#include "../include/ppddl/mini-gpt/problems.h"
#include "../include/ppddl/mini-gpt/domains.h"
#include "../include/ppddl/mini-gpt/states.h"
#include "../include/ppddl/mini-gpt/exceptions.h"
#include "../../include/ppddl/PPDDLHeuristic.h"
#include "../../include/ppddl/PPDDLProblem.h"

#include "../../include/reduced/PPDDLTaggedReduction.h"
#include "../../include/reduced/ReducedHeuristicWrapper.h"
#include "../../include/reduced/ReducedModel.h"
#include "../../include/reduced/ReducedState.h"
#include "../../include/reduced/ReducedTransition.h"

#include "../../include/solvers/FFReducedModelSolver.h"
#include "../../include/solvers/FFReplanSolver.h"
#include "../../include/solvers/RFFSolver.h"

#include "../../include/util/flags.h"
#include "../../include/util/general.h"

#include "../../include/Problem.h"

#define BUFFER_SIZE 65536

using namespace std;
using namespace mdplib;
using namespace mlppddl;
using namespace mlreduced;
using namespace mlsolvers;

extern int yyparse();
extern FILE* yyin;
string current_file;
int warning_level = 0;

static int verbosity = 0;
static int k = 0;

mlcore::Problem* problem = nullptr;
mlcore::Heuristic* heuristic = nullptr;
ReducedModel* reducedModel = nullptr;
ReducedHeuristicWrapper* reducedHeuristic = nullptr;

string ffExec = "/home/lpineda/Desktop/FF-v2.3/ff";

/*
 * Parses the given PPDDL file, and returns true on success.
 */
static bool read_file( const char* ppddlFileName )
{
    yyin = fopen( ppddlFileName, "r" );
    if( yyin == NULL ) {
        cout << "parser:" << ppddlFileName <<
            ": " << strerror( errno ) << endl;
        return( false );
    }
    else {
        current_file = ppddlFileName;
        bool success;
        try {
            success = (yyparse() == 0);
        }
        catch( Exception exception ) {
            fclose( yyin );
            cout << exception << endl;
            return( false );
        }
        fclose( yyin );
        return( success );
    }
}

/*
 * Initializes the PPDDL problem with the given arguments.
 */
bool initPPDDL(string ppddlArgs)
{
    size_t pos_equals = ppddlArgs.find(":");
    assert(pos_equals != string::npos);
    string file = ppddlArgs.substr(0, pos_equals);
    string prob =
        ppddlArgs.substr(pos_equals + 1, ppddlArgs.size() - pos_equals);

    pair<state_t *,Rational> *initial = nullptr;

    if( !read_file( file.c_str() ) ) {
        cerr << "<main>: ERROR: couldn't read problem file `" << file << endl;
        return false;
    }
    problem_t* internalPPDDLProblem =
        (problem_t *)(problem_t::find(prob.c_str()));
    if( !internalPPDDLProblem ) {
        cerr << "<main>: ERROR: problem `" << prob <<
            "' is not defined in file '" << file << "'" << endl;
        return false;
    }

    problem = new PPDDLProblem(internalPPDDLProblem);
    heuristic = new mlppddl::PPDDLHeuristic(static_cast<PPDDLProblem*>(problem),
                                            mlppddl::FF);
    problem->setHeuristic(heuristic);
}

/*
 * Fills the given map from atom_strings to atom_ids according to the
 * atom_hash of the given problem_t. This map can be used to recover a state
 * from a list of atoms.
 */
void fillStringAtomMap(problem_t* problem,
                       unordered_map<string, ushort_t>& stringAtomMap)
{
    const Domain& dom = problem->domain();
    const PredicateTable& preds = dom.predicates();
    TermTable& terms = problem->terms();
    for (auto const & atom : problem_t::atom_hash()) {
        ostringstream oss;
        atom.first->print(oss, preds, dom.functions(), terms);
        stringAtomMap[oss.str()] = atom.second;
    }
}

/* Returns the state corresponding to the given string. */
mlcore::State* getStatefromString(
    string stateString,
    mlppddl::PPDDLProblem* MLProblem,
    unordered_map<string, ushort_t>& stringAtomMap)
{
    state_t* pState = new state_t();
    for (int i = 0; i < stateString.size(); i++) {
        if (stateString[i] == '(') {
            string atomString = "";
            int j;
            for (j = i; stateString[j] != ')'; j++)
                atomString += stateString[j];
            atomString += stateString[j];
            pState->add(stringAtomMap[atomString]);
            i = j;
        }
    }
    mlppddl::PPDDLState* newState = new mlppddl::PPDDLState(MLProblem);
    newState->setPState(*pState);
    return MLProblem->addState(newState);
}

/**
 * This program creates a reduced model for a given PPDDL file and solves
 * using LAO* and FF.
 *
 * The type of model is a Mk1 reduction (at most one primary outcome),
 * which implies that after k exceptions a deterministic model is used. LAO*
 * will solve this model and use FF on states with k-exceptions so that they
 * can be treated as tip nodes with a fixed cost.
 *
 * The reduction to use is specified by a set of command line arguments:
 *
 *    --det_problem: the path to a PDDL file describing the deterministic
 *        model to be passed to FF after k-exceptions.
 *    --det_descriptor: a configuration file describing the determinization
 *        in a simple format. The user of testReducedFF is responsible for
 *        ensuring consistency between the files det_problem and
 *        det_descriptor. The format of this file will be one action name per
 *        line followed by a number specifying which of the outcomes is primary.
 *    --k: The maximum number of exceptions.
 *
 * Other required command line arguments are:
 *    --problem: the PPDDL domain/problem to solve. The format is
 *        ppddlFilename:problemName
 *    --dir: the directory to use for FF. This directory must contain the file
 *        at "det_problem" as well as a file called "p01.pddl" containing only
 *        the PPDDL problem description (i.e., init and goal, not the domain).
 *        The init state must be described in a single line.
 *        The user of testReducedFF is responsible for ensuring consistency
 *        between p01.pddl and the file passed in the "problem" flag.
 */
int main(int argc, char* args[])
{
    register_flags(argc, args);

    /* *********************** PROBLEM INITIALIZATION ********************** */

    if (flag_is_registered("debug"))
        mdplib_debug = true;

    // Reading flags.
    register_flags(argc, args);

    // The PPDDL problem to solve.
    assert(flag_is_registered_with_value("problem"));;
    string ppddlArgs = flag_value("problem");

    // The PDDL determinization to use.
    assert(flag_is_registered_with_value("det_problem"));
    string detProblem = flag_value("det_problem");

    // The configuration file for this determinization.
    assert(flag_is_registered_with_value("det_descriptor"));
    string detDescriptor = flag_value("det_descriptor");

    //The directory where the determinization is stored.
    assert(flag_is_registered_with_value("dir"));
    string directory = flag_value("dir");

    //The maximum number of exceptions.
    assert(flag_is_registered_with_value("k"));
    int k = stoi(flag_value("k"));

    // The verbosity level.
    if (flag_is_registered_with_value("v"))
        verbosity = stoi(flag_value("v"));

    string algorithm = "reduced";
    if (flag_is_registered("alg")) {
        algorithm = flag_value("alg");
    }

    time_t maxPlanningTime = 60 * 5;
    if (flag_is_registered("max-time"))
        maxPlanningTime = stoi(flag_value("max-time"));
    time_t remainingPlanningTime = maxPlanningTime;

    // If true, FF will be used for the states with exception_counter = k.
    bool useFF = true;
    if (flag_is_registered("no-ff"))
        useFF = false;

    // The number of simulations for the experiments.
    int nsims = 100;
    if (flag_is_registered_with_value("n"))
        nsims = stoi(flag_value("n"));

    initPPDDL(ppddlArgs);

    // Creating the reduced model.
    ReducedTransition* reduction = nullptr;
    if (algorithm == "reduced") {
        reduction = new PPDDLTaggedReduction(problem, detDescriptor);
        reducedModel = new ReducedModel(problem, reduction, k);
        reducedHeuristic = new ReducedHeuristicWrapper(heuristic);
        reducedModel->setHeuristic(reducedHeuristic);
    }

    /* *********************** SERVER INITIALIZATION ********************** */

    // Setting up the server to connect to MDP-SIM.
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0) {
        cerr << "ERROR: couldn't open socket." << endl;
        exit(-1);
    }
    struct sockaddr_in serv_addr;
    bzero((char *) &serv_addr, sizeof(serv_addr));
    int portno = 1234;
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = INADDR_ANY;
    serv_addr.sin_port = htons(portno);
    if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) {
        cerr << "ERROR: couldn't bind the socket." << endl;
        close(sockfd);
        exit(-1);
    }

    // Connect to the MDP-SIM client.
    struct sockaddr_in cli_addr;
    listen(sockfd, 5);
    socklen_t clilen = sizeof(cli_addr);
    int newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
    if (newsockfd < 0) {
        cerr << "ERROR: problems accepting connection." << endl;
        close(sockfd);
        exit(-1);
    }

    /* *********************** SOLVING THE PROBLEM ********************** */
    // Solving reduced model using LAO* + FF.
    time_t totalPlanningTime = 0.0;
    time_t startTime = time(nullptr);
     // using half of the time fot the initial plan (last argument)

    cout << "SOLVING" << endl;
    Solver* solver = nullptr;
    if (algorithm == "reduced") {
        solver = new FFReducedModelSolver(reducedModel,
                                          ffExec,
                                          directory + "/" + detProblem,
                                          directory + "/ff-template.pddl",
                                          k,
                                          1.0e-3,
                                          useFF,
                                          maxPlanningTime / 2);
        solver->solve(reducedModel->initialState());
    } else if (algorithm == "rff") {
        solver = new RFFSolver(static_cast<mlppddl::PPDDLProblem*> (problem),
                               ffExec,
                               directory + "/" + detProblem,
                               directory + "/ff-template.pddl",
                               maxPlanningTime / 2);
        solver->solve(problem->initialState());
    }
    time_t endTime = time(nullptr);
    totalPlanningTime += endTime - startTime;
    remainingPlanningTime -= totalPlanningTime;
    cout << "cost " << reducedModel->initialState()->cost() <<
        " time " << totalPlanningTime << endl;

    /* *********************** SEVER LOOP ********************** */
    // Initializing a map from atom names to atom indices.
    unordered_map<string, ushort_t> stringAtomMap;
    fillStringAtomMap(static_cast<PPDDLProblem*> (problem)->pProblem(),
                      stringAtomMap);
    double cost = 0.0;
    while (true) {
        // Reading communication from the client.
        char buffer[BUFFER_SIZE];
        bzero(buffer, BUFFER_SIZE);
        int n = read(newsockfd, buffer, BUFFER_SIZE - 1);
        if (n < 0) {
            cerr << "ERROR: couldn't read from socket." << endl;
            break;
        }
        cout << "RECEIVED: " << buffer << endl;
        string msg(buffer);
        string atomsString;
        if (msg.substr(0, 6) == "state:") { // Received a state to plan for.
            atomsString = msg.substr(6, msg.size());
        } else if (msg.substr(0, 5) == "stop") { // Stop the program.
            break;
        } else if (msg.substr(0, 9) == "end-round") {
            cost = 0;
            bzero(buffer, BUFFER_SIZE);
            sprintf(buffer, "%s", "round-ended");
            cout << "SENDING: " << buffer << "." << endl;
            n = write(newsockfd, buffer, strlen(buffer));
            if (n < 0) {
                cerr << "ERROR: couldn't write to socket." << endl;
                break;
            }
            continue;
        } else {
            cerr << "ERROR: unknown message. Terminating." << endl;
            break;
        }
        // Getting the state whose action needs to be found.
        mlcore::State* state =
            getStatefromString(atomsString,
                               static_cast<PPDDLProblem*> (problem),
                               stringAtomMap);

        cout << "PLANNING." << endl;
        solver->maxPlanningTime(remainingPlanningTime);
        startTime = time(nullptr);
        mlcore::Action* action = nullptr;
        if (algorithm == "reduced") {
            // For now, always set the exception counter to 0 and re-plan.
            ReducedState* reducedState = static_cast<ReducedState*> (
                reducedModel->addState(
                    new ReducedState(state, 0, reducedModel)));
            action = solver->solve(reducedState);
        } else {
            action = solver->solve(state);
        }
        endTime = time(nullptr);
        remainingPlanningTime -= endTime - startTime;
        cout << "DONE. Remaining time: " << remainingPlanningTime << endl;

        // Sending the action to the client.
        ostringstream oss;
        if (action != nullptr && cost < mdplib::dead_end_cost) {
            oss << action;
            cost += problem->cost(state, action);
        } else {
            cout << "DEAD-END." << endl;
            oss << "(done)";
        }
        bzero(buffer, BUFFER_SIZE);
        sprintf(buffer, "%s", oss.str().c_str());
        cout << buffer << "." << endl;
        n = write(newsockfd, buffer, strlen(buffer));
        if (n < 0) {
            cerr << "ERROR: couldn't write to socket." << endl;
            break;
        }
    }

    // Releasing memory
    if (reducedModel != nullptr) {
        reducedModel->cleanup();
        delete reducedModel;
    }
    delete solver;
    delete problem;
    return 0;
}

<commit_msg>fixed errors in test/reduced/planningServer.cpp<commit_after>#include <cassert>
#include <ctime>
#include <iostream>
#include <list>
#include <netinet/in.h>
#include <sstream>
#include <string>
#include <sys/types.h>
#include <sys/socket.h>
#include <typeinfo>
#include <unistd.h>

#include "../../include/domains/racetrack/RacetrackProblem.h"
#include "../../include/domains/racetrack/RTrackDetHeuristic.h"
#include "../../include/domains/DummyState.h"

#include "../include/ppddl/mini-gpt/states.h"
#include "../include/ppddl/mini-gpt/problems.h"
#include "../include/ppddl/mini-gpt/domains.h"
#include "../include/ppddl/mini-gpt/states.h"
#include "../include/ppddl/mini-gpt/exceptions.h"
#include "../../include/ppddl/PPDDLHeuristic.h"
#include "../../include/ppddl/PPDDLProblem.h"

#include "../../include/reduced/PPDDLTaggedReduction.h"
#include "../../include/reduced/ReducedHeuristicWrapper.h"
#include "../../include/reduced/ReducedModel.h"
#include "../../include/reduced/ReducedState.h"
#include "../../include/reduced/ReducedTransition.h"

#include "../../include/solvers/FFReducedModelSolver.h"
#include "../../include/solvers/FFReplanSolver.h"
#include "../../include/solvers/RFFSolver.h"

#include "../../include/util/flags.h"
#include "../../include/util/general.h"

#include "../../include/Problem.h"

#define BUFFER_SIZE 65536

using namespace std;
using namespace mdplib;
using namespace mlppddl;
using namespace mlreduced;
using namespace mlsolvers;

extern int yyparse();
extern FILE* yyin;
string current_file;
int warning_level = 0;

static int verbosity = 0;
static int k = 0;

mlcore::Problem* problem = nullptr;
mlcore::Heuristic* heuristic = nullptr;
ReducedModel* reducedModel = nullptr;
ReducedHeuristicWrapper* reducedHeuristic = nullptr;

string ffExec = "/home/lpineda/Desktop/FF-v2.3/ff";

/*
 * Parses the given PPDDL file, and returns true on success.
 */
static bool read_file( const char* ppddlFileName )
{
    yyin = fopen( ppddlFileName, "r" );
    if( yyin == NULL ) {
        cerr << "parser:" << ppddlFileName <<
            ": " << strerror( errno ) << endl;
        return( false );
    }
    else {
        current_file = ppddlFileName;
        bool success;
        try {
            success = (yyparse() == 0);
        }
        catch( Exception exception ) {
            fclose( yyin );
            cerr << exception << endl;
            return( false );
        }
        fclose( yyin );
        return( success );
    }
}

/*
 * Initializes the PPDDL problem with the given arguments.
 */
bool initPPDDL(string ppddlArgs)
{
    size_t pos_equals = ppddlArgs.find(":");
    assert(pos_equals != string::npos);
    string file = ppddlArgs.substr(0, pos_equals);
    string prob =
        ppddlArgs.substr(pos_equals + 1, ppddlArgs.size() - pos_equals);

    pair<state_t *,Rational> *initial = nullptr;

    if( !read_file( file.c_str() ) ) {
        cerr << "<main>: ERROR: couldn't read problem file `" << file << endl;
        return false;
    }
    problem_t* internalPPDDLProblem =
        (problem_t *)(problem_t::find(prob.c_str()));
    if( !internalPPDDLProblem ) {
        cerr << "<main>: ERROR: problem `" << prob <<
            "' is not defined in file '" << file << "'" << endl;
        return false;
    }

    problem = new PPDDLProblem(internalPPDDLProblem);
    heuristic = new mlppddl::PPDDLHeuristic(static_cast<PPDDLProblem*>(problem),
                                            mlppddl::FF);
    problem->setHeuristic(heuristic);
}

/*
 * Fills the given map from atom_strings to atom_ids according to the
 * atom_hash of the given problem_t. This map can be used to recover a state
 * from a list of atoms.
 */
void fillStringAtomMap(problem_t* problem,
                       unordered_map<string, ushort_t>& stringAtomMap)
{
    const Domain& dom = problem->domain();
    const PredicateTable& preds = dom.predicates();
    TermTable& terms = problem->terms();
    for (auto const & atom : problem_t::atom_hash()) {
        ostringstream oss;
        atom.first->print(oss, preds, dom.functions(), terms);
        stringAtomMap[oss.str()] = atom.second;
    }
}

/* Returns the state corresponding to the given string. */
mlcore::State* getStatefromString(
    string stateString,
    mlppddl::PPDDLProblem* MLProblem,
    unordered_map<string, ushort_t>& stringAtomMap)
{
    state_t* pState = new state_t();
    for (int i = 0; i < stateString.size(); i++) {
        if (stateString[i] == '(') {
            string atomString = "";
            int j;
            for (j = i; stateString[j] != ')'; j++)
                atomString += stateString[j];
            atomString += stateString[j];
            pState->add(stringAtomMap[atomString]);
            i = j;
        }
    }
    mlppddl::PPDDLState* newState = new mlppddl::PPDDLState(MLProblem);
    newState->setPState(*pState);
    return MLProblem->addState(newState);
}

/**
 * This program creates a reduced model for a given PPDDL file and solves
 * using LAO* and FF.
 *
 * The type of model is a Mk1 reduction (at most one primary outcome),
 * which implies that after k exceptions a deterministic model is used. LAO*
 * will solve this model and use FF on states with k-exceptions so that they
 * can be treated as tip nodes with a fixed cost.
 *
 * The reduction to use is specified by a set of command line arguments:
 *
 *    --det_problem: the path to a PDDL file describing the deterministic
 *        model to be passed to FF after k-exceptions.
 *    --det_descriptor: a configuration file describing the determinization
 *        in a simple format. The user of testReducedFF is responsible for
 *        ensuring consistency between the files det_problem and
 *        det_descriptor. The format of this file will be one action name per
 *        line followed by a number specifying which of the outcomes is primary.
 *    --k: The maximum number of exceptions.
 *
 * Other required command line arguments are:
 *    --problem: the PPDDL domain/problem to solve. The format is
 *        ppddlFilename:problemName
 *    --dir: the directory to use for FF. This directory must contain the file
 *        at "det_problem" as well as a file called "p01.pddl" containing only
 *        the PPDDL problem description (i.e., init and goal, not the domain).
 *        The init state must be described in a single line.
 *        The user of testReducedFF is responsible for ensuring consistency
 *        between p01.pddl and the file passed in the "problem" flag.
 */
int main(int argc, char* args[])
{
    register_flags(argc, args);

    /* *********************** PROBLEM INITIALIZATION ********************** */

    if (flag_is_registered("debug"))
        mdplib_debug = true;

    // Reading flags.
    register_flags(argc, args);

    // The PPDDL problem to solve.
    assert(flag_is_registered_with_value("problem"));;
    string ppddlArgs = flag_value("problem");

    // The PDDL determinization to use.
    assert(flag_is_registered_with_value("det_problem"));
    string detProblem = flag_value("det_problem");

    // The configuration file for this determinization.
    assert(flag_is_registered_with_value("det_descriptor"));
    string detDescriptor = flag_value("det_descriptor");

    //The directory where the determinization is stored.
    assert(flag_is_registered_with_value("dir"));
    string directory = flag_value("dir");

    // The verbosity level.
    if (flag_is_registered_with_value("v"))
        verbosity = stoi(flag_value("v"));

    // The planner to use.
    string planner = "reduced";
    if (flag_is_registered("planner")) {
        planner = flag_value("planner");
    }
    cerr << "..." << planner << "..." << endl;

    //The maximum number of exceptions for the reduced model solver.
    int k = 0;
    if (flag_is_registered_with_value("k"))
        k = stoi(flag_value("k"));

    time_t maxPlanningTime = 60 * 5;
    if (flag_is_registered("max-time"))
        maxPlanningTime = stoi(flag_value("max-time"));
    time_t remainingPlanningTime = maxPlanningTime;

    // If true, FF will be used for the states with exception_counter = k.
    bool useFF = true;
    if (flag_is_registered("no-ff"))
        useFF = false;

    // The number of simulations for the experiments.
    int nsims = 100;
    if (flag_is_registered_with_value("n"))
        nsims = stoi(flag_value("n"));

    initPPDDL(ppddlArgs);

    // Creating the reduced model.
    ReducedTransition* reduction = nullptr;
    if (planner == "reduced") {
        reduction = new PPDDLTaggedReduction(problem, detDescriptor);
        reducedModel = new ReducedModel(problem, reduction, k);
        reducedHeuristic = new ReducedHeuristicWrapper(heuristic);
        reducedModel->setHeuristic(reducedHeuristic);
    }

    /* *********************** SERVER INITIALIZATION ********************** */

    // Setting up the server to connect to MDP-SIM.
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0) {
        cerr << "ERROR: couldn't open socket." << endl;
        exit(-1);
    }
    struct sockaddr_in serv_addr;
    bzero((char *) &serv_addr, sizeof(serv_addr));
    int portno = 1234;
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = INADDR_ANY;
    serv_addr.sin_port = htons(portno);
    if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) {
        cerr << "ERROR: couldn't bind the socket." << endl;
        close(sockfd);
        exit(-1);
    }

    // Connect to the MDP-SIM client.
    struct sockaddr_in cli_addr;
    listen(sockfd, 5);
    socklen_t clilen = sizeof(cli_addr);
    int newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
    if (newsockfd < 0) {
        cerr << "ERROR: problems accepting connection." << endl;
        close(sockfd);
        exit(-1);
    }

    /* *********************** SOLVING THE PROBLEM ********************** */
    // Solving reduced model using LAO* + FF.
    time_t totalPlanningTime = 0.0;
    time_t startTime = time(nullptr);
     // using half of the time fot the initial plan (last argument)

    cerr << "SOLVING" << endl;
    Solver* solver = nullptr;
    if (planner == "reduced") {
        solver = new FFReducedModelSolver(reducedModel,
                                          ffExec,
                                          directory + "/" + detProblem,
                                          directory + "/ff-template.pddl",
                                          k,
                                          1.0e-3,
                                          useFF,
                                          maxPlanningTime / 2);
        solver->solve(reducedModel->initialState());
    } else if (planner == "rff") {
                                                                                dprint1("rff");
        solver = new RFFSolver(static_cast<mlppddl::PPDDLProblem*> (problem),
                               ffExec,
                               directory + "/" + detProblem,
                               directory + "/ff-template.pddl",
                               0.2,
                               100,
                               maxPlanningTime / 2);
        solver->solve(problem->initialState());
                                                                                dprint1("rff-done");
    } else if (planner == "ff-replan") {
        solver = new FFReplanSolver
            (static_cast<mlppddl::PPDDLProblem*> (problem),
             ffExec,
             directory + "/" + detProblem,
             directory + "/ff-template.pddl",
             maxPlanningTime / 2);
        solver->solve(problem->initialState());
    }
    time_t endTime = time(nullptr);
    totalPlanningTime += endTime - startTime;
    remainingPlanningTime -= totalPlanningTime;

    /* *********************** SEVER LOOP ********************** */
    // Initializing a map from atom names to atom indices.
    unordered_map<string, ushort_t> stringAtomMap;
    fillStringAtomMap(static_cast<PPDDLProblem*> (problem)->pProblem(),
                      stringAtomMap);
    double cost = 0.0;
    while (true) {
        // Reading communication from the client.
        char buffer[BUFFER_SIZE];
        bzero(buffer, BUFFER_SIZE);
        int n = read(newsockfd, buffer, BUFFER_SIZE - 1);
        if (n < 0) {
            cerr << "ERROR: couldn't read from socket." << endl;
            break;
        }
        cerr << "RECEIVED: " << buffer << endl;
        string msg(buffer);
        string atomsString;
        if (msg.substr(0, 6) == "state:") { // Received a state to plan for.
            atomsString = msg.substr(6, msg.size());
        } else if (msg.substr(0, 5) == "stop") { // Stop the program.
            break;
        } else if (msg.substr(0, 9) == "end-round") {
            cost = 0;
            bzero(buffer, BUFFER_SIZE);
            sprintf(buffer, "%s", "round-ended");
            cerr << "SENDING: " << buffer << "." << endl;
            n = write(newsockfd, buffer, strlen(buffer));
            if (n < 0) {
                cerr << "ERROR: couldn't write to socket." << endl;
                break;
            }
            continue;
        } else {
            cerr << "ERROR: unknown message. Terminating." << endl;
            break;
        }
        // Getting the state whose action needs to be found.
        mlcore::State* state =
            getStatefromString(atomsString,
                               static_cast<PPDDLProblem*> (problem),
                               stringAtomMap);

        cerr << "PLANNING." << endl;
        solver->maxPlanningTime(remainingPlanningTime);
        startTime = time(nullptr);
        mlcore::Action* action = nullptr;
        if (planner == "reduced") {
            // For now, always set the exception counter to 0 and re-plan.
            ReducedState* reducedState = static_cast<ReducedState*> (
                reducedModel->addState(
                    new ReducedState(state, 0, reducedModel)));
            action = solver->solve(reducedState);
        } else {
            action = solver->solve(state);
        }
        endTime = time(nullptr);
        remainingPlanningTime -= endTime - startTime;
        cerr << "DONE. Remaining time: " << remainingPlanningTime << endl;

        // Sending the action to the client.
        ostringstream oss;
        if (action != nullptr && cost < mdplib::dead_end_cost) {
            oss << action;
            cost += problem->cost(state, action);
        } else {
            cerr << "DEAD-END." << endl;
            oss << "(done)";
        }
        bzero(buffer, BUFFER_SIZE);
        sprintf(buffer, "%s", oss.str().c_str());
        cerr << buffer << "." << endl;
        n = write(newsockfd, buffer, strlen(buffer));
        if (n < 0) {
            cerr << "ERROR: couldn't write to socket." << endl;
            break;
        }
    }

    // Releasing memory
    if (reducedModel != nullptr) {
        reducedModel->cleanup();
        delete reducedModel;
    }
    delete solver;
    delete problem;
    return 0;
}

<|endoftext|>


<commit_before>// Style: http://geosoft.no/development/cppstyle.html

#include <cstdio>
#include <ctime>
#include <iostream>
#include <mutex>
#include <thread>

#include <boost/filesystem.hpp>
#include <fmt/format.h>
#include <GL/glew.h>
#include <GLFW/glfw3.h>

#include <nanogui/nanogui.h>

#include "dijkstra.h"
#include "gl_error.h"
#include "ogl_text.h"
#include "render.h"
#include "solution.h"
#include "utils.h"

using namespace std;
using namespace boost::filesystem;
using namespace nanogui;

//const u32 windowW = 1920 / 2;
//const u32 windowH = 1080 - 200;
const u32 windowW = 700;
const u32 windowH = 700;
const char *FONT_PATH = "./fonts/LiberationMono-Regular.ttf";
const u32 FONT_SIZE = 18;

Costs costs;
Circuit circuit;
Solution solution;
void route();
void runRoute();
thread routeThread;
mutex stopThreadMutex;
OglText* oglTextPtr;
PcbDraw* pcbDrawPtr;
averageSec averageRendering;
std::time_t mtime_prev = 0;
static bool showInputBool = false;

class Application : public nanogui::Screen
{
public:
  Application()
    : nanogui::Screen(Eigen::Vector2i(windowW, windowH), "Stripboard Autorouter",
                      true, false, 8, 8, 24, 8, 4, 3, 3)
  {
    GLuint mTextureId;
    glGenTextures(1, &mTextureId);

    glfwMakeContextCurrent(glfwWindow());

    // Initialize GLEW.
    glewExperimental = GL_TRUE;
    if (glewInit() != GLEW_OK) {
      fprintf(stderr, "Failed to initialize GLEW\n");
      glfwTerminate();
      return;
    }

    glGetError();
    glClearColor(0.3f, 0.3f, 0.3f, 1.0f);
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glDisable(GL_DEPTH_TEST);

    glGenVertexArrays(1, &vertexArrayId);

    glBindVertexArray(vertexArrayId);
    glBindFramebuffer(GL_FRAMEBUFFER, 0);
    glViewport(0, 0, windowW, windowH);

    oglTextPtr = new OglText(windowW, windowH, FONT_PATH, FONT_SIZE);
    pcbDrawPtr = new PcbDraw(windowW, windowH);

    // Main grid window
    auto window = new Window(this, "Router");
    window->setPosition(Vector2i(windowW - 400, windowH - 300));
    GridLayout *layout = new GridLayout(Orientation::Horizontal, 2, Alignment::Middle, 15, 5);
    layout->setColAlignment({Alignment::Maximum, Alignment::Fill});
    layout->setSpacing(0, 10);
    window->setLayout(layout);

//    mProgress = new ProgressBar(window);

    {
      new Label(window, "Wire cost:", "sans-bold");
      auto intBox = new IntBox<int>(window);
      intBox->setEditable(true);
      intBox->setFixedSize(Vector2i(100, 20));
      intBox->setValue(costs.wire);
      intBox->setDefaultValue("0");
      intBox->setFontSize(18);
      intBox->setFormat("[1-9][0-9]*");
      intBox->setSpinnable(true);
      intBox->setMinValue(1);
      intBox->setValueIncrement(1);
      intBox->setCallback([intBox](int value) {
        costs.wire = value;
        runRoute();
      });
    }
    {
      new Label(window, "Strip cost:", "sans-bold");
      auto intBox = new IntBox<int>(window);
      intBox->setEditable(true);
      intBox->setFixedSize(Vector2i(100, 20));
      intBox->setValue(costs.strip);
      intBox->setDefaultValue("0");
      intBox->setFontSize(18);
      intBox->setFormat("[1-9][0-9]*");
      intBox->setSpinnable(true);
      intBox->setMinValue(1);
      intBox->setValueIncrement(1);
      intBox->setCallback([intBox](int value) {
        costs.strip = value;
        runRoute();
      });
    }
    {
      new Label(window, "Via cost:", "sans-bold");
      auto intBox = new IntBox<int>(window);
      intBox->setEditable(true);
      intBox->setFixedSize(Vector2i(100, 20));
      intBox->setValue(costs.via);
      intBox->setDefaultValue("0");
      intBox->setFontSize(18);
      intBox->setFormat("[1-9][0-9]*");
      intBox->setSpinnable(true);
      intBox->setMinValue(1);
      intBox->setValueIncrement(1);
      intBox->setCallback([intBox](int value) {
        costs.via = value;
        runRoute();
      });
    }
    {
      new Label(window, "Show input:", "sans-bold");
      auto cb = new CheckBox(window, "");
      cb->setFontSize(18);
      cb->setChecked(showInputBool);
      cb->setCallback([cb](bool value) {
        showInputBool = value;
      });
    }
    {
      new Label(window, "Zoom:", "sans-bold");

      Widget *panel = new Widget(window);
      panel->setLayout(new BoxLayout(Orientation::Horizontal, Alignment::Middle, 0, 5));

      Slider *slider = new Slider(panel);
      slider->setValue(0.25f);
      slider->setFixedWidth(100);

      TextBox *textBox = new TextBox(panel);
      textBox->setFixedSize(Vector2i(50, 20));
      textBox->setValue("50");
      textBox->setUnits("%");
      slider->setCallback([textBox](float value) {
        textBox->setValue(std::to_string((int) (value * 200)));
        pcbDrawPtr->setZoom(value * 4.0f);
      });
      slider->setFinalCallback([&](float value) {
        pcbDrawPtr->setZoom(value * 4.0f);
      });
      textBox->setFixedSize(Vector2i(60,25));
      textBox->setFontSize(18);
      textBox->setAlignment(TextBox::Alignment::Right);
    }
    performLayout();
  }

  ~Application()
  {
    delete oglTextPtr;
    delete pcbDrawPtr;
  }

  virtual bool keyboardEvent(int key, int scancode, int action, int modifiers)
  {
    if (Screen::keyboardEvent(key, scancode, action, modifiers)) {
      return true;
    }
    if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) {
      setVisible(false);
      return true;
    }
    return false;
  }

  virtual void draw(NVGcontext *ctx)
  {
    // Draw the user interface
    Screen::draw(ctx);
  }

  virtual void drawContents()
  {
    glBindVertexArray(vertexArrayId);
    glBindFramebuffer(GL_FRAMEBUFFER, 0);
    glViewport(0, 0, windowW, windowH);

    std::time_t mtime_cur = boost::filesystem::last_write_time("./circuit.txt");
    if (mtime_cur != mtime_prev) {
      mtime_prev = mtime_cur;
      auto parser = Parser();
      {
        lock_guard<mutex> lockCircuit(circuitMutex);
        parser.parse(circuit);
      }
      runRoute();
    }

    glfwSetTime(0.0);

    pcbDrawPtr->draw(circuit, solution, showInputBool);

    // Needed for timing but can be very bad for performance.
    glFinish();

    averageRendering.addSec(glfwGetTime());
    glfwSetTime(0.0);

    auto avgRenderingSec = averageRendering.calcAverage();

    auto nLine = 0;
    oglTextPtr->print(0, 0, nLine++, fmt::format("Render: {:.1f}ms", avgRenderingSec * 1000));
    for (auto s : circuit.getCircuitInfoVec()) {
      oglTextPtr->print(0, 0, nLine++, s);
    }
  }

private:
  nanogui::ProgressBar *mProgress;
  GLuint vertexArrayId;
};

int main(int argc, char **argv)
{
  try {
    nanogui::init();
    {
      nanogui::ref<Application> app = new Application();
      app->drawAll();
      app->setVisible(true);
      nanogui::mainloop();
    }
    nanogui::shutdown();
  }
  catch (const std::runtime_error &e) {
    std::string error_msg = std::string("Caught a fatal error: ") + std::string(e.what());
#if defined(_WIN32)
	//MessageBoxA(nullptr, error_msg.c_str(), NULL, MB_ICONERROR | MB_OK);
#else
    std::cerr << error_msg << endl;
#endif
    return -1;
  }
  return 0;
}

void runRoute()
{
  try {
    lock_guard<mutex> stopThread(stopThreadMutex);
    routeThread.join();
  }
  catch (const std::system_error &e) {
  }
  routeThread = thread(route);
}

void route()
{
  if (!stopThreadMutex.try_lock()) {
    return;
  }
  else {
    stopThreadMutex.unlock();
  }
  if (!circuit.getErrorBool()) {
    Dijkstra dijkstra;
    dijkstra.route(solution, costs, circuit, stopThreadMutex);
  }
}
<commit_msg>Initial work<commit_after>// Style: http://geosoft.no/development/cppstyle.html

#include <cstdio>
#include <ctime>
#include <iostream>
#include <mutex>
#include <thread>

#include <boost/filesystem.hpp>
#include <fmt/format.h>
#include <GL/glew.h>
#include <GLFW/glfw3.h>

#include <nanogui/nanogui.h>

#include "dijkstra.h"
#include "gl_error.h"
#include "ogl_text.h"
#include "render.h"
#include "solution.h"
#include "utils.h"

using namespace std;
using namespace boost::filesystem;
using namespace nanogui;

//const u32 windowW = 1920 / 2;
//const u32 windowH = 1080 - 200;
const u32 windowW = 700;
const u32 windowH = 700;
const char *FONT_PATH = "./fonts/LiberationMono-Regular.ttf";
const u32 FONT_SIZE = 18;

Costs costs;
Circuit circuit;
Solution solution;
void route();
void runRoute();
thread routeThread;
mutex stopThreadMutex;
OglText* oglTextPtr;
PcbDraw* pcbDrawPtr;
averageSec averageRendering;
std::time_t mtime_prev = 0;
static bool showInputBool = false;

class Application : public nanogui::Screen
{
public:
  Application()
    : nanogui::Screen(Eigen::Vector2i(windowW, windowH), "Stripboard Autorouter",
                      true, false, 8, 8, 24, 8, 4, 3, 3)
  {
    GLuint mTextureId;
    glGenTextures(1, &mTextureId);

    glfwMakeContextCurrent(glfwWindow());

    // Initialize GLEW.
    glewExperimental = GL_TRUE;
    if (glewInit() != GLEW_OK) {
      fprintf(stderr, "Failed to initialize GLEW\n");
      glfwTerminate();
      return;
    }

    glGetError();
    glClearColor(0.3f, 0.3f, 0.3f, 1.0f);
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glDisable(GL_DEPTH_TEST);

    glGenVertexArrays(1, &vertexArrayId);

    glBindVertexArray(vertexArrayId);
    glBindFramebuffer(GL_FRAMEBUFFER, 0);
    glViewport(0, 0, windowW, windowH);

    oglTextPtr = new OglText(windowW, windowH, FONT_PATH, FONT_SIZE);
    pcbDrawPtr = new PcbDraw(windowW, windowH);

    // Main grid window
    auto window = new Window(this, "Router");
    window->setPosition(Vector2i(windowW - 400, windowH - 300));
    GridLayout *layout = new GridLayout(Orientation::Horizontal, 2, Alignment::Middle, 15, 5);
    layout->setColAlignment({Alignment::Maximum, Alignment::Fill});
    layout->setSpacing(0, 10);
    window->setLayout(layout);

//    mProgress = new ProgressBar(window);

    {
      new Label(window, "Wire cost:", "sans-bold");
      auto intBox = new IntBox<int>(window);
      intBox->setEditable(true);
      intBox->setFixedSize(Vector2i(100, 20));
      intBox->setValue(costs.wire);
      intBox->setDefaultValue("0");
      intBox->setFontSize(18);
      intBox->setFormat("[1-9][0-9]*");
      intBox->setSpinnable(true);
      intBox->setMinValue(1);
      intBox->setValueIncrement(1);
      intBox->setCallback([intBox](int value) {
        costs.wire = value;
        runRoute();
      });
    }
    {
      new Label(window, "Strip cost:", "sans-bold");
      auto intBox = new IntBox<int>(window);
      intBox->setEditable(true);
      intBox->setFixedSize(Vector2i(100, 20));
      intBox->setValue(costs.strip);
      intBox->setDefaultValue("0");
      intBox->setFontSize(18);
      intBox->setFormat("[1-9][0-9]*");
      intBox->setSpinnable(true);
      intBox->setMinValue(1);
      intBox->setValueIncrement(1);
      intBox->setCallback([intBox](int value) {
        costs.strip = value;
        runRoute();
      });
    }
    {
      new Label(window, "Via cost:", "sans-bold");
      auto intBox = new IntBox<int>(window);
      intBox->setEditable(true);
      intBox->setFixedSize(Vector2i(100, 20));
      intBox->setValue(costs.via);
      intBox->setDefaultValue("0");
      intBox->setFontSize(18);
      intBox->setFormat("[1-9][0-9]*");
      intBox->setSpinnable(true);
      intBox->setMinValue(1);
      intBox->setValueIncrement(1);
      intBox->setCallback([intBox](int value) {
        costs.via = value;
        runRoute();
      });
    }
    {
      new Label(window, "Show input:", "sans-bold");
      auto cb = new CheckBox(window, "");
      cb->setFontSize(18);
      cb->setChecked(showInputBool);
      cb->setCallback([cb](bool value) {
        showInputBool = value;
      });
    }
    {
      new Label(window, "Zoom:", "sans-bold");

      Widget *panel = new Widget(window);
      panel->setLayout(new BoxLayout(Orientation::Horizontal, Alignment::Middle, 0, 5));

      Slider *slider = new Slider(panel);
      slider->setValue(0.25f);
      slider->setFixedWidth(100);

      TextBox *textBox = new TextBox(panel);
      textBox->setFixedSize(Vector2i(50, 20));
      textBox->setValue("50");
      textBox->setUnits("%");
      slider->setCallback([textBox](float value) {
        textBox->setValue(std::to_string((int) (value * 200)));
        pcbDrawPtr->setZoom(value * 4.0f);
      });
      slider->setFinalCallback([&](float value) {
        pcbDrawPtr->setZoom(value * 4.0f);
      });
      textBox->setFixedSize(Vector2i(60,25));
      textBox->setFontSize(18);
      textBox->setAlignment(TextBox::Alignment::Right);
    }
    performLayout();
  }

  ~Application()
  {
    delete oglTextPtr;
    delete pcbDrawPtr;
  }

  virtual bool keyboardEvent(int key, int scancode, int action, int modifiers)
  {
    if (Screen::keyboardEvent(key, scancode, action, modifiers)) {
      return true;
    }
    if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) {
      setVisible(false);
      return true;
    }
    return false;
  }

  virtual void draw(NVGcontext *ctx)
  {
    // Draw the user interface
    Screen::draw(ctx);
  }

  virtual void drawContents()
  {
    glBindVertexArray(vertexArrayId);
    glBindFramebuffer(GL_FRAMEBUFFER, 0);
    glViewport(0, 0, windowW, windowH);

    std::time_t mtime_cur = boost::filesystem::last_write_time("./circuit.txt");
    if (mtime_cur != mtime_prev) {
      mtime_prev = mtime_cur;
      auto parser = Parser();
      {
        lock_guard<mutex> lockCircuit(circuitMutex);
        parser.parse(circuit);
      }
      runRoute();
    }

    glfwSetTime(0.0);

    {
      lock_guard<mutex> lockSolution(solutionMutex);
      pcbDrawPtr->draw(circuit, solution, showInputBool);
    }

    // Needed for timing but can be very bad for performance.
    glFinish();

    averageRendering.addSec(glfwGetTime());
    glfwSetTime(0.0);

    auto avgRenderingSec = averageRendering.calcAverage();

    auto nLine = 0;
    oglTextPtr->print(0, 0, nLine++, fmt::format("Render: {:.1f}ms", avgRenderingSec * 1000));
    for (auto s : circuit.getCircuitInfoVec()) {
      oglTextPtr->print(0, 0, nLine++, s);
    }
  }

private:
  nanogui::ProgressBar *mProgress;
  GLuint vertexArrayId;
};

int main(int argc, char **argv)
{
  try {
    nanogui::init();
    {
      nanogui::ref<Application> app = new Application();
      app->drawAll();
      app->setVisible(true);
      nanogui::mainloop();
    }
    nanogui::shutdown();
  }
  catch (const std::runtime_error &e) {
    std::string error_msg = std::string("Caught a fatal error: ") + std::string(e.what());
#if defined(_WIN32)
	//MessageBoxA(nullptr, error_msg.c_str(), NULL, MB_ICONERROR | MB_OK);
#else
    std::cerr << error_msg << endl;
#endif
    return -1;
  }
  return 0;
}

void runRoute()
{
  try {
    lock_guard<mutex> stopThread(stopThreadMutex);
    routeThread.join();
  }
  catch (const std::system_error &e) {
  }
  routeThread = thread(route);
}

void route()
{
  if (!stopThreadMutex.try_lock()) {
    return;
  }
  else {
    stopThreadMutex.unlock();
  }
  if (!circuit.getErrorBool()) {
    Dijkstra dijkstra;
    dijkstra.route(solution, costs, circuit, stopThreadMutex);
  }
}
<|endoftext|>


<commit_before>#include "Moves/Pawn_Double_Move.h"

#include "Moves/Move.h"
#include "Pieces/Piece.h"
#include "Game/Board.h"

Pawn_Double_Move::Pawn_Double_Move(Color color) : Pawn_Move(color)
{
    d_rank = d_rank*2;
}

void Pawn_Double_Move::side_effects(Board& board, char file_start, int rank_start) const
{
    board.make_en_passant_targetable(file_start, rank_start + rank_change()/2);
    Pawn_Move::side_effects(board, file_start, rank_start);
}

std::string Pawn_Double_Move::name() const
{
    return "Pawn Double Move";
}
<commit_msg>More succinct code<commit_after>#include "Moves/Pawn_Double_Move.h"

#include "Moves/Move.h"
#include "Pieces/Piece.h"
#include "Game/Board.h"

Pawn_Double_Move::Pawn_Double_Move(Color color) : Pawn_Move(color)
{
    d_rank *= 2;
}

void Pawn_Double_Move::side_effects(Board& board, char file_start, int rank_start) const
{
    board.make_en_passant_targetable(file_start, rank_start + rank_change()/2);
    Pawn_Move::side_effects(board, file_start, rank_start);
}

std::string Pawn_Double_Move::name() const
{
    return "Pawn Double Move";
}
<|endoftext|>