<commit_before>/***************************************************************************
 *   Copyright (c) 2016 Wandererfan <wandererfan@gmail.com>                *
 *                                                                         *
 *   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                                *
 *                                                                         *
 ***************************************************************************/
/*                                                                         *
 * Some material based on Boost sample code                                */
// Distributed under the Boost Software License, Version 1.0. (See
// http://www.boost.org/LICENSE_1_0.txt)
//**************************************************************************

#include "PreCompiled.h"
#ifndef _PreComp_
#include <BRepBuilderAPI_MakeWire.hxx>
#include <BRepBndLib.hxx>
#include <Bnd_Box.hxx>
#include <ShapeFix_ShapeTolerance.hxx>
#include <ShapeExtend_WireData.hxx>
#include <ShapeFix_Wire.hxx>
#include <TopExp.hxx>
#include <TopExp_Explorer.hxx>
#include <BRepBuilderAPI_MakeFace.hxx>
#include <GProp_GProps.hxx>
#include <BRepGProp.hxx>

#endif

#include <Base/Console.h>

#include "DrawUtil.h"
#include "EdgeWalker.h"

using namespace TechDraw;
using namespace boost;

//*******************************************************
//* edgeVisior methods
//*******************************************************
template <typename Edge>
void edgeVisitor::next_edge(Edge e)
{
    graph_traits<graph>::vertex_descriptor s = source(e,m_g);
    graph_traits<graph>::vertex_descriptor t = target(e,m_g);
    WalkerEdge we;
    we.v1 = s;
    we.v2 = t;
    we.idx = get(edge_index,m_g,e);
    wireEdges.push_back(we);
}

void edgeVisitor::begin_face()
{
    wireEdges.clear();
}

void edgeVisitor::end_face()
{
    graphWires.push_back(wireEdges);
}

TechDraw::ewWireList edgeVisitor::getResult(void)
{
    return graphWires;
}

void edgeVisitor::setGraph(TechDraw::graph& g)
{
    m_g = g;
}

//*******************************************************
//* EdgeWalker
//*******************************************************

EdgeWalker::EdgeWalker()
{
}

EdgeWalker::~EdgeWalker()
{
}

bool EdgeWalker::loadEdges(std::vector<TechDraw::WalkerEdge> edges)
{
    for (auto e: edges) {
        add_edge(e.v1,e.v2,m_g);
    }
    return true;
}

bool EdgeWalker::loadEdges(std::vector<TopoDS_Edge> edges)
{
    std::vector<TopoDS_Vertex> verts = makeUniqueVList(edges);
    setSize(verts.size());
    std::vector<WalkerEdge>  we  = makeWalkerEdges(edges, verts);
    saveInEdges = edges;

    return loadEdges(we);
}
bool EdgeWalker::setSize(int size)
{
    m_g.clear();
    for (int i = 0; i < size; i++) {
        boost::adjacency_list<>::vertex_descriptor vd = boost::add_vertex(m_g);
    }
    return true;
}

bool EdgeWalker::perform()
{
    // Initialize the interior edge index
    //property<edge_index_t, int>
    property_map<TechDraw::graph, edge_index_t>::type e_index = get(edge_index, m_g);
    graph_traits<TechDraw::graph>::edges_size_type edge_count = 0;
    graph_traits<TechDraw::graph>::edge_iterator ei, ei_end;
    for(boost::tie(ei, ei_end) = edges(m_g); ei != ei_end; ++ei)
      put(e_index, *ei, edge_count++);

    // Test for planarity - we know it is planar, we just want to
    // compute the planar embedding as a side-effect
    typedef std::vector< graph_traits<TechDraw::graph>::edge_descriptor > vec_t;
    std::vector<vec_t> embedding(num_vertices(m_g));
    boyer_myrvold_planarity_test(boyer_myrvold_params::graph = m_g,
                                 boyer_myrvold_params::embedding = &embedding[0]);

    m_eV.setGraph(m_g);
    planar_face_traversal(m_g, &embedding[0], m_eV);

    return true;
}

ewWireList EdgeWalker::getResult()
{
    ewWireList result = m_eV.getResult();
    // result is a list of many wires each of which is a list of many WE
    return result;
}

std::vector<TopoDS_Wire> EdgeWalker::getResultWires()
{
    ewWireList result = m_eV.getResult();

    std::vector<ewWire>::iterator iWire = result.wires.begin();     // a WE within [WE]
    std::vector<TopoDS_Wire> fw;
    for (;iWire != result.wires.end(); iWire++) {
        std::vector<WalkerEdge>::iterator iEdge = (*iWire).wedges.begin();
        std::vector<TopoDS_Edge> topoEdges;
        for (;iEdge != (*iWire).wedges.end(); iEdge++) {
            TopoDS_Edge e = saveInEdges.at((*iEdge).idx);
            topoEdges.push_back(e);
        }
    TopoDS_Wire w = makeCleanWire(topoEdges);             //make 1 clean wire from its edges
    fw.push_back(w);
    }
    return fw;
}

std::vector<TopoDS_Wire> EdgeWalker::getResultNoDups()
{
    ewWireList result = m_eV.getResult();
    result = result.removeDuplicates();

    std::vector<ewWire>::iterator iWire = result.wires.begin();
    std::vector<TopoDS_Wire> fw;
    for (;iWire != result.wires.end(); iWire++) {
        std::vector<WalkerEdge>::iterator iEdge = (*iWire).wedges.begin();
        std::vector<TopoDS_Edge> topoEdges;
        for (;iEdge != (*iWire).wedges.end(); iEdge++) {
            TopoDS_Edge e = saveInEdges.at((*iEdge).idx);
            topoEdges.push_back(e);
        }
    TopoDS_Wire w = makeCleanWire(topoEdges);             //make 1 clean wire from its edges
    fw.push_back(w);
    }
    return fw;
}

//! make a clean wire with sorted, oriented, connected, etc edges
TopoDS_Wire EdgeWalker::makeCleanWire(std::vector<TopoDS_Edge> edges, double tol)
{
    TopoDS_Wire result;
    BRepBuilderAPI_MakeWire mkWire;
    ShapeFix_ShapeTolerance sTol;
    Handle(ShapeExtend_WireData) wireData = new ShapeExtend_WireData();

    for (auto e:edges) {
        wireData->Add(e);
    }

    Handle(ShapeFix_Wire) fixer = new ShapeFix_Wire;
    fixer->Load(wireData);
    fixer->Perform();
    fixer->FixReorder();
    fixer->SetMaxTolerance(tol);
    fixer->ClosedWireMode() = Standard_True;
    fixer->FixConnected(Precision::Confusion());
    fixer->FixClosed(Precision::Confusion());

    for (int i = 1; i <= wireData->NbEdges(); i ++) {
        TopoDS_Edge edge = fixer->WireData()->Edge(i);
        sTol.SetTolerance(edge, tol, TopAbs_VERTEX);
        mkWire.Add(edge);
    }

    result = mkWire.Wire();
    return result;
}

std::vector<TopoDS_Vertex> EdgeWalker:: makeUniqueVList(std::vector<TopoDS_Edge> edges)
{
    std::vector<TopoDS_Vertex> uniqueVert;
    for(auto& e:edges) {
        TopoDS_Vertex v1 = TopExp::FirstVertex(e);
        TopoDS_Vertex v2 = TopExp::LastVertex(e);
        bool addv1 = true;
        bool addv2 = true;
        for (auto v:uniqueVert) {
            if (DrawUtil::isSamePoint(v,v1))
                addv1 = false;
            if (DrawUtil::isSamePoint(v,v2))
                addv2 = false;
        }
        if (addv1)
            uniqueVert.push_back(v1);
        if (addv2)
            uniqueVert.push_back(v2);
    }
    return uniqueVert;
}

//!make WalkerEdges (unique Vertex index pairs) from edge list
std::vector<WalkerEdge> EdgeWalker::makeWalkerEdges(std::vector<TopoDS_Edge> edges,
                                                      std::vector<TopoDS_Vertex> verts)
{
    std::vector<WalkerEdge> walkerEdges;
    for (auto e:edges) {
        TopoDS_Vertex ev1 = TopExp::FirstVertex(e);
        TopoDS_Vertex ev2 = TopExp::LastVertex(e);
        int v1dx = findUniqueVert(ev1, verts);
        int v2dx = findUniqueVert(ev2, verts);
        WalkerEdge we;
        we.v1 = v1dx;
        we.v2 = v2dx;
        walkerEdges.push_back(we);
    }
    return walkerEdges;
}

int EdgeWalker::findUniqueVert(TopoDS_Vertex vx, std::vector<TopoDS_Vertex> &uniqueVert)
{
    int idx = 0;
    int result = 0;
    for(auto& v:uniqueVert) {                    //we're always going to find vx, right?
        if (DrawUtil::isSamePoint(v,vx)) {
            result = idx;
            break;
        }
        idx++;
    }                                           //if idx >= uniqueVert.size() TARFU
    return result;
}

/*static*/ bool WalkerEdge::weCompare(WalkerEdge i, WalkerEdge j)
{
    return (i.idx < j.idx);
}

bool ewWire::isEqual(ewWire w2)
{
    bool result = true;
    if (wedges.size() != w2.wedges.size()) {
        result = false;
    } else {
        std::sort(wedges.begin(),wedges.end(),WalkerEdge::weCompare);
        std::sort(w2.wedges.begin(),w2.wedges.end(),WalkerEdge::weCompare);
        for (unsigned int i = 0; i < w2.wedges.size(); i ++) {
            if (wedges.at(i).idx != w2.wedges.at(i).idx) {
                result = false;
                break;
            }
        }
    }
    return result;
}

void ewWire::push_back(WalkerEdge w)
{
    wedges.push_back(w);
}

//check wirelist for wires that use the same set of edges, but maybe in a different order.
ewWireList ewWireList::removeDuplicates()
{
    ewWireList result;
    result.push_back(*(wires.begin()));                //save the first ewWire
    std::vector<ewWire>::iterator iWire = (wires.begin()) + 1;    //starting with second
    for (; iWire != wires.end(); iWire++) {
        bool addToResult = true;
        for (auto& w:result.wires) {
            if ((*iWire).isEqual(w))  {             //already in result?
                addToResult = false;
                break;
            }
        }
        if (addToResult) {
            result.push_back((*iWire));
        }
    }
    return result;
}

void ewWireList::push_back(ewWire w)
{
    wires.push_back(w);
}

std::vector<TopoDS_Wire> EdgeWalker::sortStrip(std::vector<TopoDS_Wire> fw, bool includeBiggest)
{
    std::vector<TopoDS_Wire> sortedWires = sortWiresBySize(fw,false);           //biggest 1st
    if (!sortedWires.size()) {
        Base::Console().Log("INFO - DVP::extractFaces - no sorted Wires!\n");
        return sortedWires;                                     // might happen in the middle of changes?
    }

    //find the largest wire (OuterWire of graph) using bbox
    Bnd_Box bigBox;
    if (sortedWires.size() && !sortedWires.front().IsNull()) {
        BRepBndLib::Add(sortedWires.front(), bigBox);
        bigBox.SetGap(0.0);
    }
    std::vector<std::size_t> toBeChecked;
    std::vector<TopoDS_Wire>::iterator it = sortedWires.begin() + 1;
    for (; it != sortedWires.end(); it++) {
        if (!(*it).IsNull()) {
            Bnd_Box littleBox;
            BRepBndLib::Add((*it), littleBox);
            littleBox.SetGap(0.0);
            if (bigBox.SquareExtent() > littleBox.SquareExtent()) {
                break;
            } else {
                auto position = std::distance( sortedWires.begin(), it );    //get an index from iterator
                toBeChecked.push_back(position);
            }
        }
    }

    //unfortuneately, faces can have same bbox, but not be same size.  need to weed out biggest
    if (toBeChecked.size() == 0) {
        //nobody had as big a bbox as first element of sortedWires
        if (!includeBiggest) {
            sortedWires.erase(sortedWires.begin());
        }
    } else if (toBeChecked.size() > 0) {
        BRepBuilderAPI_MakeFace mkFace(sortedWires.front());
        const TopoDS_Face& face = mkFace.Face();
        GProp_GProps props;
        BRepGProp::SurfaceProperties(face, props);
        double bigArea = props.Mass();
        unsigned int bigIndex = 0;
        for (unsigned int idx = 0; idx < toBeChecked.size(); idx++) {
            int iCheck = toBeChecked.at(idx);
            BRepBuilderAPI_MakeFace mkFace2(sortedWires.at(iCheck));
            const TopoDS_Face& face2 = mkFace2.Face();
            BRepGProp::SurfaceProperties(face2, props);
            double area = props.Mass();
            if (area > bigArea) {
                bigArea = area;
                bigIndex = iCheck;
            }
        }
        if (bigIndex == 0) {                    //first wire is the biggest
            if (!includeBiggest) {
                sortedWires.erase(sortedWires.begin());
            }
        } else {                                  //first wire is not the biggest
            TopoDS_Wire bigWire = *(sortedWires.begin() + bigIndex);
            sortedWires.erase(sortedWires.begin() + bigIndex);
            if (includeBiggest) {
                sortedWires.insert(sortedWires.begin(),bigWire);               //doesn't happen often
            }
        }

    }
    return sortedWires;
}

//sort wires in order of bbox diagonal.
std::vector<TopoDS_Wire> EdgeWalker::sortWiresBySize(std::vector<TopoDS_Wire>& w, bool ascend)
{
    std::vector<TopoDS_Wire> wires = w;
    std::sort(wires.begin(), wires.end(), EdgeWalker::wireCompare);
    if (ascend) {
        std::reverse(wires.begin(),wires.end());
    }
    return wires;
}

//! return true if w1 bbox is bigger than w2 bbox
//NOTE: this won't necessarily sort the OuterWire correctly (ex smaller wire, same bbox)
/*static*/bool EdgeWalker::wireCompare(const TopoDS_Wire& w1, const TopoDS_Wire& w2)
{
    Bnd_Box box1, box2;
    if (!w1.IsNull()) {
        BRepBndLib::Add(w1, box1);
        box1.SetGap(0.0);
    }

    if (!w2.IsNull()) {
        BRepBndLib::Add(w2, box2);
        box2.SetGap(0.0);
    }

    return box1.SquareExtent() > box2.SquareExtent();
}
<commit_msg>Handle case where no faces found in View.<commit_after>/***************************************************************************
 *   Copyright (c) 2016 Wandererfan <wandererfan@gmail.com>                *
 *                                                                         *
 *   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                                *
 *                                                                         *
 ***************************************************************************/
/*                                                                         *
 * Some material based on Boost sample code                                */
// Distributed under the Boost Software License, Version 1.0. (See
// http://www.boost.org/LICENSE_1_0.txt)
//**************************************************************************

#include "PreCompiled.h"
#ifndef _PreComp_
#include <BRepBuilderAPI_MakeWire.hxx>
#include <BRepBndLib.hxx>
#include <Bnd_Box.hxx>
#include <ShapeFix_ShapeTolerance.hxx>
#include <ShapeExtend_WireData.hxx>
#include <ShapeFix_Wire.hxx>
#include <TopExp.hxx>
#include <TopExp_Explorer.hxx>
#include <BRepBuilderAPI_MakeFace.hxx>
#include <GProp_GProps.hxx>
#include <BRepGProp.hxx>

#endif

#include <Base/Console.h>

#include "DrawUtil.h"
#include "EdgeWalker.h"

using namespace TechDraw;
using namespace boost;

//*******************************************************
//* edgeVisior methods
//*******************************************************
template <typename Edge>
void edgeVisitor::next_edge(Edge e)
{
    graph_traits<graph>::vertex_descriptor s = source(e,m_g);
    graph_traits<graph>::vertex_descriptor t = target(e,m_g);
    WalkerEdge we;
    we.v1 = s;
    we.v2 = t;
    we.idx = get(edge_index,m_g,e);
    wireEdges.push_back(we);
}

void edgeVisitor::begin_face()
{
    wireEdges.clear();
}

void edgeVisitor::end_face()
{
    graphWires.push_back(wireEdges);
}

TechDraw::ewWireList edgeVisitor::getResult(void)
{
    return graphWires;
}

void edgeVisitor::setGraph(TechDraw::graph& g)
{
    m_g = g;
}

//*******************************************************
//* EdgeWalker
//*******************************************************

EdgeWalker::EdgeWalker()
{
}

EdgeWalker::~EdgeWalker()
{
}

bool EdgeWalker::loadEdges(std::vector<TechDraw::WalkerEdge> edges)
{
    for (auto e: edges) {
        add_edge(e.v1,e.v2,m_g);
    }
    return true;
}

bool EdgeWalker::loadEdges(std::vector<TopoDS_Edge> edges)
{
    std::vector<TopoDS_Vertex> verts = makeUniqueVList(edges);
    setSize(verts.size());
    std::vector<WalkerEdge>  we  = makeWalkerEdges(edges, verts);
    saveInEdges = edges;

    return loadEdges(we);
}
bool EdgeWalker::setSize(int size)
{
    m_g.clear();
    for (int i = 0; i < size; i++) {
        boost::adjacency_list<>::vertex_descriptor vd = boost::add_vertex(m_g);
    }
    return true;
}

bool EdgeWalker::perform()
{
    // Initialize the interior edge index
    //property<edge_index_t, int>
    property_map<TechDraw::graph, edge_index_t>::type e_index = get(edge_index, m_g);
    graph_traits<TechDraw::graph>::edges_size_type edge_count = 0;
    graph_traits<TechDraw::graph>::edge_iterator ei, ei_end;
    for(boost::tie(ei, ei_end) = edges(m_g); ei != ei_end; ++ei)
      put(e_index, *ei, edge_count++);

    // Test for planarity - we know it is planar, we just want to
    // compute the planar embedding as a side-effect
    typedef std::vector< graph_traits<TechDraw::graph>::edge_descriptor > vec_t;
    std::vector<vec_t> embedding(num_vertices(m_g));
    boyer_myrvold_planarity_test(boyer_myrvold_params::graph = m_g,
                                 boyer_myrvold_params::embedding = &embedding[0]);

    m_eV.setGraph(m_g);
    planar_face_traversal(m_g, &embedding[0], m_eV);

    return true;
}

ewWireList EdgeWalker::getResult()
{
    ewWireList result = m_eV.getResult();
    // result is a list of many wires each of which is a list of many WE
    return result;
}

std::vector<TopoDS_Wire> EdgeWalker::getResultWires()
{
    std::vector<TopoDS_Wire> fw;
    ewWireList result = m_eV.getResult();
    if (result.wires.empty()) {
        return fw;
    }

    std::vector<ewWire>::iterator iWire = result.wires.begin();     // a WE within [WE]
    for (;iWire != result.wires.end(); iWire++) {
        std::vector<WalkerEdge>::iterator iEdge = (*iWire).wedges.begin();
        std::vector<TopoDS_Edge> topoEdges;
        for (;iEdge != (*iWire).wedges.end(); iEdge++) {
            TopoDS_Edge e = saveInEdges.at((*iEdge).idx);
            topoEdges.push_back(e);
        }
    TopoDS_Wire w = makeCleanWire(topoEdges);             //make 1 clean wire from its edges
    fw.push_back(w);
    }
    return fw;
}

std::vector<TopoDS_Wire> EdgeWalker::getResultNoDups()
{
    std::vector<TopoDS_Wire> fw;
    ewWireList result = m_eV.getResult();
    if (result.wires.empty()) {
        return fw;
    }
    result = result.removeDuplicates();

    std::vector<ewWire>::iterator iWire = result.wires.begin();
    for (;iWire != result.wires.end(); iWire++) {
        std::vector<WalkerEdge>::iterator iEdge = (*iWire).wedges.begin();
        std::vector<TopoDS_Edge> topoEdges;
        for (;iEdge != (*iWire).wedges.end(); iEdge++) {
            TopoDS_Edge e = saveInEdges.at((*iEdge).idx);
            topoEdges.push_back(e);
        }
    TopoDS_Wire w = makeCleanWire(topoEdges);             //make 1 clean wire from its edges
    fw.push_back(w);
    }
    return fw;
}

//! make a clean wire with sorted, oriented, connected, etc edges
TopoDS_Wire EdgeWalker::makeCleanWire(std::vector<TopoDS_Edge> edges, double tol)
{
    TopoDS_Wire result;
    BRepBuilderAPI_MakeWire mkWire;
    ShapeFix_ShapeTolerance sTol;
    Handle(ShapeExtend_WireData) wireData = new ShapeExtend_WireData();

    for (auto e:edges) {
        wireData->Add(e);
    }

    Handle(ShapeFix_Wire) fixer = new ShapeFix_Wire;
    fixer->Load(wireData);
    fixer->Perform();
    fixer->FixReorder();
    fixer->SetMaxTolerance(tol);
    fixer->ClosedWireMode() = Standard_True;
    fixer->FixConnected(Precision::Confusion());
    fixer->FixClosed(Precision::Confusion());

    for (int i = 1; i <= wireData->NbEdges(); i ++) {
        TopoDS_Edge edge = fixer->WireData()->Edge(i);
        sTol.SetTolerance(edge, tol, TopAbs_VERTEX);
        mkWire.Add(edge);
    }

    result = mkWire.Wire();
    return result;
}

std::vector<TopoDS_Vertex> EdgeWalker:: makeUniqueVList(std::vector<TopoDS_Edge> edges)
{
    std::vector<TopoDS_Vertex> uniqueVert;
    for(auto& e:edges) {
        TopoDS_Vertex v1 = TopExp::FirstVertex(e);
        TopoDS_Vertex v2 = TopExp::LastVertex(e);
        bool addv1 = true;
        bool addv2 = true;
        for (auto v:uniqueVert) {
            if (DrawUtil::isSamePoint(v,v1))
                addv1 = false;
            if (DrawUtil::isSamePoint(v,v2))
                addv2 = false;
        }
        if (addv1)
            uniqueVert.push_back(v1);
        if (addv2)
            uniqueVert.push_back(v2);
    }
    return uniqueVert;
}

//!make WalkerEdges (unique Vertex index pairs) from edge list
std::vector<WalkerEdge> EdgeWalker::makeWalkerEdges(std::vector<TopoDS_Edge> edges,
                                                      std::vector<TopoDS_Vertex> verts)
{
    std::vector<WalkerEdge> walkerEdges;
    for (auto e:edges) {
        TopoDS_Vertex ev1 = TopExp::FirstVertex(e);
        TopoDS_Vertex ev2 = TopExp::LastVertex(e);
        int v1dx = findUniqueVert(ev1, verts);
        int v2dx = findUniqueVert(ev2, verts);
        WalkerEdge we;
        we.v1 = v1dx;
        we.v2 = v2dx;
        walkerEdges.push_back(we);
    }
    return walkerEdges;
}

int EdgeWalker::findUniqueVert(TopoDS_Vertex vx, std::vector<TopoDS_Vertex> &uniqueVert)
{
    int idx = 0;
    int result = 0;
    for(auto& v:uniqueVert) {                    //we're always going to find vx, right?
        if (DrawUtil::isSamePoint(v,vx)) {
            result = idx;
            break;
        }
        idx++;
    }                                           //if idx >= uniqueVert.size() TARFU
    return result;
}

/*static*/ bool WalkerEdge::weCompare(WalkerEdge i, WalkerEdge j)
{
    return (i.idx < j.idx);
}

bool ewWire::isEqual(ewWire w2)
{
    bool result = true;
    if (wedges.size() != w2.wedges.size()) {
        result = false;
    } else {
        std::sort(wedges.begin(),wedges.end(),WalkerEdge::weCompare);
        std::sort(w2.wedges.begin(),w2.wedges.end(),WalkerEdge::weCompare);
        for (unsigned int i = 0; i < w2.wedges.size(); i ++) {
            if (wedges.at(i).idx != w2.wedges.at(i).idx) {
                result = false;
                break;
            }
        }
    }
    return result;
}

void ewWire::push_back(WalkerEdge w)
{
    wedges.push_back(w);
}

//check wirelist for wires that use the same set of edges, but maybe in a different order.
ewWireList ewWireList::removeDuplicates()
{
    ewWireList result;
    if (wires.empty()) {
        return result;
    }
    result.push_back(*(wires.begin()));                //save the first ewWire
    std::vector<ewWire>::iterator iWire = (wires.begin()) + 1;    //starting with second
    for (; iWire != wires.end(); iWire++) {
        bool addToResult = true;
        for (auto& w:result.wires) {
            if ((*iWire).isEqual(w))  {             //already in result?
                addToResult = false;
                break;
            }
        }
        if (addToResult) {
            result.push_back((*iWire));
        }
    }
    return result;
}

void ewWireList::push_back(ewWire w)
{
    wires.push_back(w);
}

std::vector<TopoDS_Wire> EdgeWalker::sortStrip(std::vector<TopoDS_Wire> fw, bool includeBiggest)
{
    std::vector<TopoDS_Wire> sortedWires = sortWiresBySize(fw,false);           //biggest 1st
    if (!sortedWires.size()) {
        Base::Console().Log("INFO - DVP::extractFaces - no sorted Wires!\n");
        return sortedWires;                                     // might happen in the middle of changes?
    }

    //find the largest wire (OuterWire of graph) using bbox
    Bnd_Box bigBox;
    if (sortedWires.size() && !sortedWires.front().IsNull()) {
        BRepBndLib::Add(sortedWires.front(), bigBox);
        bigBox.SetGap(0.0);
    }
    std::vector<std::size_t> toBeChecked;
    std::vector<TopoDS_Wire>::iterator it = sortedWires.begin() + 1;
    for (; it != sortedWires.end(); it++) {
        if (!(*it).IsNull()) {
            Bnd_Box littleBox;
            BRepBndLib::Add((*it), littleBox);
            littleBox.SetGap(0.0);
            if (bigBox.SquareExtent() > littleBox.SquareExtent()) {
                break;
            } else {
                auto position = std::distance( sortedWires.begin(), it );    //get an index from iterator
                toBeChecked.push_back(position);
            }
        }
    }

    //unfortuneately, faces can have same bbox, but not be same size.  need to weed out biggest
    if (toBeChecked.size() == 0) {
        //nobody had as big a bbox as first element of sortedWires
        if (!includeBiggest) {
            sortedWires.erase(sortedWires.begin());
        }
    } else if (toBeChecked.size() > 0) {
        BRepBuilderAPI_MakeFace mkFace(sortedWires.front());
        const TopoDS_Face& face = mkFace.Face();
        GProp_GProps props;
        BRepGProp::SurfaceProperties(face, props);
        double bigArea = props.Mass();
        unsigned int bigIndex = 0;
        for (unsigned int idx = 0; idx < toBeChecked.size(); idx++) {
            int iCheck = toBeChecked.at(idx);
            BRepBuilderAPI_MakeFace mkFace2(sortedWires.at(iCheck));
            const TopoDS_Face& face2 = mkFace2.Face();
            BRepGProp::SurfaceProperties(face2, props);
            double area = props.Mass();
            if (area > bigArea) {
                bigArea = area;
                bigIndex = iCheck;
            }
        }
        if (bigIndex == 0) {                    //first wire is the biggest
            if (!includeBiggest) {
                sortedWires.erase(sortedWires.begin());
            }
        } else {                                  //first wire is not the biggest
            TopoDS_Wire bigWire = *(sortedWires.begin() + bigIndex);
            sortedWires.erase(sortedWires.begin() + bigIndex);
            if (includeBiggest) {
                sortedWires.insert(sortedWires.begin(),bigWire);               //doesn't happen often
            }
        }

    }
    return sortedWires;
}

//sort wires in order of bbox diagonal.
std::vector<TopoDS_Wire> EdgeWalker::sortWiresBySize(std::vector<TopoDS_Wire>& w, bool ascend)
{
    std::vector<TopoDS_Wire> wires = w;
    std::sort(wires.begin(), wires.end(), EdgeWalker::wireCompare);
    if (ascend) {
        std::reverse(wires.begin(),wires.end());
    }
    return wires;
}

//! return true if w1 bbox is bigger than w2 bbox
//NOTE: this won't necessarily sort the OuterWire correctly (ex smaller wire, same bbox)
/*static*/bool EdgeWalker::wireCompare(const TopoDS_Wire& w1, const TopoDS_Wire& w2)
{
    Bnd_Box box1, box2;
    if (!w1.IsNull()) {
        BRepBndLib::Add(w1, box1);
        box1.SetGap(0.0);
    }

    if (!w2.IsNull()) {
        BRepBndLib::Add(w2, box2);
        box2.SetGap(0.0);
    }

    return box1.SquareExtent() > box2.SquareExtent();
}
<|endoftext|>


<commit_before>/*===========================================================================*\
 *                                                                           *
 *                               OpenMesh                                    *
 *      Copyright (C) 2001-2011 by Computer Graphics Group, RWTH Aachen      *
 *                           www.openmesh.org                                *
 *                                                                           *
 *---------------------------------------------------------------------------*
 *  This file is part of OpenMesh.                                           *
 *                                                                           *
 *  OpenMesh is free software: you can redistribute it and/or modify         *
 *  it under the terms of the GNU Lesser General Public License as           *
 *  published by the Free Software Foundation, either version 3 of           *
 *  the License, or (at your option) any later version with the              *
 *  following exceptions:                                                    *
 *                                                                           *
 *  If other files instantiate templates or use macros                       *
 *  or inline functions from this file, or you compile this file and         *
 *  link it with other files to produce an executable, this file does        *
 *  not by itself cause the resulting executable to be covered by the        *
 *  GNU Lesser General Public License. This exception does not however       *
 *  invalidate any other reasons why the executable file might be            *
 *  covered by the GNU Lesser General Public License.                        *
 *                                                                           *
 *  OpenMesh is distributed in the hope that it will be useful,              *
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of           *
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            *
 *  GNU Lesser General Public License for more details.                      *
 *                                                                           *
 *  You should have received a copy of the GNU LesserGeneral Public          *
 *  License along with OpenMesh.  If not,                                    *
 *  see <http://www.gnu.org/licenses/>.                                      *
 *                                                                           *
\*===========================================================================*/

/*===========================================================================*\
 *                                                                           *
 *   $Revision$                                                         *
 *   $Date$                   *
 *                                                                           *
\*===========================================================================*/

//=============================================================================
//
//  CLASS PolyMeshT - IMPLEMENTATION
//
//=============================================================================

#define OPENMESH_POLYMESH_C

//== INCLUDES =================================================================

#include <OpenMesh/Core/Mesh/PolyMeshT.hh>
#include <OpenMesh/Core/Geometry/LoopSchemeMaskT.hh>
#include <OpenMesh/Core/Utils/vector_cast.hh>
#include <OpenMesh/Core/System/omstream.hh>
#include <vector>

//== NAMESPACES ===============================================================

namespace OpenMesh {

//== IMPLEMENTATION ==========================================================

template <class Kernel>
uint PolyMeshT<Kernel>::find_feature_edges(Scalar _angle_tresh)
{
  assert(Kernel::has_edge_status());//this function needs edge status property
  uint n_feature_edges = 0;
  for (EdgeIter e_it = Kernel::edges_begin(); e_it != Kernel::edges_end(); ++e_it)
  {
    if (fabs(calc_dihedral_angle(e_it)) > _angle_tresh)
    {//note: could be optimized by comparing cos(dih_angle) vs. cos(_angle_tresh)
      status(e_it).set_feature(true);
      n_feature_edges++;
    }
    else
    {
      status(e_it).set_feature(false);
    }
  }
  return n_feature_edges;
}

//-----------------------------------------------------------------------------

template <class Kernel>
typename PolyMeshT<Kernel>::Normal
PolyMeshT<Kernel>::
calc_face_normal(FaceHandle _fh) const
{
  assert(this->halfedge_handle(_fh).is_valid());
  ConstFaceVertexIter fv_it(this->cfv_iter(_fh));

  Point p0 = this->point(fv_it);
  Point p0i = p0; //save point of vertex 0
  ++fv_it;
  Point p1 = this->point(fv_it);
  Point p1i = p1; //save point of vertex 1
  ++fv_it;
  Point p2;

  //calculate area-weighted average normal of polygon's ears
  Normal n(0,0,0);
  for(; fv_it; ++fv_it)
  {
    p2 = this->point(fv_it);
    n += vector_cast<Normal>(calc_face_normal(p0, p1, p2));
    p0 = p1;
    p1 = p2;
  }

  //two additional steps since we started at vertex 2, not 0
  n += vector_cast<Normal>(calc_face_normal(p0i, p0, p1));
  n += vector_cast<Normal>(calc_face_normal(p1i, p0i, p1));

  typename Normal::value_type norm = n.length();

  // The expression ((n *= (1.0/norm)),n) is used because the OpenSG
  // vector class does not return self after component-wise
  // self-multiplication with a scalar!!!
  return (norm != typename Normal::value_type(0)) ? ((n *= (typename Normal::value_type(1)/norm)),n) : Normal(0,0,0);
}

//-----------------------------------------------------------------------------

template <class Kernel>
typename PolyMeshT<Kernel>::Normal
PolyMeshT<Kernel>::
calc_face_normal(const Point& _p0,
     const Point& _p1,
     const Point& _p2) const
{
#if 1
  // The OpenSG <Vector>::operator -= () does not support the type Point
  // as rhs. Therefore use vector_cast at this point!!!
  // Note! OpenSG distinguishes between Normal and Point!!!
  Normal p1p0(vector_cast<Normal>(_p0));  p1p0 -= vector_cast<Normal>(_p1);
  Normal p1p2(vector_cast<Normal>(_p2));  p1p2 -= vector_cast<Normal>(_p1);

  Normal n    = cross(p1p2, p1p0);
  typename Normal::value_type norm = n.length();

  // The expression ((n *= (1.0/norm)),n) is used because the OpenSG
  // vector class does not return self after component-wise
  // self-multiplication with a scalar!!!
  return (norm != typename Normal::value_type(0)) ? ((n *= (typename Normal::value_type(1)/norm)),n) : Normal(0,0,0);
#else
  Point p1p0 = _p0;  p1p0 -= _p1;
  Point p1p2 = _p2;  p1p2 -= _p1;

  Normal n = vector_cast<Normal>(cross(p1p2, p1p0));
  typename Normal::value_type norm = n.length();

  return (norm != 0.0) ? n *= (1.0/norm) : Normal(0,0,0);
#endif
}

//-----------------------------------------------------------------------------

template <class Kernel>
void
PolyMeshT<Kernel>::
calc_face_centroid(FaceHandle _fh, Point& _pt) const
{
  _pt.vectorize(0);
  uint valence = 0;
  for (ConstFaceVertexIter cfv_it = this->cfv_iter(_fh); cfv_it; ++cfv_it, ++valence)
  {
    _pt += this->point(cfv_it);
  }
  _pt /= valence;
}
//-----------------------------------------------------------------------------

template <class Kernel>
void
PolyMeshT<Kernel>::
update_normals()
{
  // Face normals are required to compute the vertex and the halfedge normals
  if (Kernel::has_face_normals() ) {
    update_face_normals();

    if (Kernel::has_vertex_normals() ) update_vertex_normals();
    if (Kernel::has_halfedge_normals()) update_halfedge_normals();
  }
}

//-----------------------------------------------------------------------------

template <class Kernel>
void
PolyMeshT<Kernel>::
update_face_normals()
{
  FaceIter f_it(Kernel::faces_begin()), f_end(Kernel::faces_end());

  for (; f_it != f_end; ++f_it)
    this->set_normal(f_it.handle(), calc_face_normal(f_it.handle()));
}

//-----------------------------------------------------------------------------

template <class Kernel>
void
PolyMeshT<Kernel>::
update_halfedge_normals(const double _feature_angle)
{
  HalfedgeIter h_it(Kernel::halfedges_begin()), h_end(Kernel::halfedges_end());

  for (; h_it != h_end; ++h_it)
    this->set_normal(h_it.handle(), calc_halfedge_normal(h_it.handle(), _feature_angle));
}

//-----------------------------------------------------------------------------

template <class Kernel>
typename PolyMeshT<Kernel>::Normal
PolyMeshT<Kernel>::
calc_halfedge_normal(HalfedgeHandle _heh, const double _feature_angle) const
{
  if(Kernel::is_boundary(_heh))
    return Normal(0,0,0);
  else
  {
    std::vector<FaceHandle> fhs; fhs.reserve(10);

    HalfedgeHandle heh = _heh;

    // collect CW face-handles
    do
    {
      fhs.push_back(Kernel::face_handle(heh));

      heh = Kernel::next_halfedge_handle(heh);
      heh = Kernel::opposite_halfedge_handle(heh);
    }
    while(heh != _heh && !Kernel::is_boundary(heh) && !is_estimated_feature_edge(heh, _feature_angle));

    // collect CCW face-handles
    if(heh != _heh && !is_estimated_feature_edge(_heh, _feature_angle))
    {
      heh = Kernel::opposite_halfedge_handle(_heh);

      if ( !Kernel::is_boundary(heh) ) {
        do
        {

          fhs.push_back(Kernel::face_handle(heh));

          heh = Kernel::prev_halfedge_handle(heh);
          heh = Kernel::opposite_halfedge_handle(heh);
        }
        while(!Kernel::is_boundary(heh) && !is_estimated_feature_edge(heh, _feature_angle));
      }
    }

    Normal n(0,0,0);
    for(unsigned int i=0; i<fhs.size(); ++i)
      n += Kernel::normal(fhs[i]);

    return n.normalize();
  }
}

//-----------------------------------------------------------------------------

template <class Kernel>
bool
PolyMeshT<Kernel>::
is_estimated_feature_edge(HalfedgeHandle _heh, const double _feature_angle) const
{
  EdgeHandle eh = Kernel::edge_handle(_heh);

  if(Kernel::has_edge_status())
  {
    if(Kernel::status(eh).feature())
      return true;
  }

  if(Kernel::is_boundary(eh))
    return false;

  // compute angle between faces
  FaceHandle fh0 = Kernel::face_handle(_heh);
  FaceHandle fh1 = Kernel::face_handle(Kernel::opposite_halfedge_handle(_heh));

  Normal fn0 = Kernel::normal(fh0);
  Normal fn1 = Kernel::normal(fh1);

  // dihedral angle above angle threshold
  return ( dot(fn0,fn1) < cos(_feature_angle) );
}

//-----------------------------------------------------------------------------

template <class Kernel>
typename PolyMeshT<Kernel>::Normal
PolyMeshT<Kernel>::
calc_vertex_normal(VertexHandle _vh) const
{
  Normal n;
  calc_vertex_normal_fast(_vh,n);

  Scalar norm = n.length();
  if (norm != 0.0) n *= (1.0/norm);

  return n;
}

//-----------------------------------------------------------------------------
template <class Kernel>
void PolyMeshT<Kernel>::
calc_vertex_normal_fast(VertexHandle _vh, Normal& _n) const
{
  _n.vectorize(0.0);
  for (ConstVertexFaceIter vf_it=this->cvf_iter(_vh); vf_it; ++vf_it)
    _n += this->normal(vf_it.handle());
}

//-----------------------------------------------------------------------------
template <class Kernel>
void PolyMeshT<Kernel>::
calc_vertex_normal_correct(VertexHandle _vh, Normal& _n) const
{
  _n.vectorize(0.0);
  ConstVertexIHalfedgeIter cvih_it = cvih_iter(_vh);
  if (!cvih_it)
  {//don't crash on isolated vertices
    return;
  }
  Normal in_he_vec;
  calc_edge_vector(cvih_it, in_he_vec);
  for ( ; cvih_it; ++cvih_it)
  {//calculates the sector normal defined by cvih_it and adds it to _n
    if (is_boundary(cvih_it))
    {
      continue;
    }
    HalfedgeHandle out_heh(next_halfedge_handle(cvih_it));
    Normal out_he_vec;
    calc_edge_vector(out_heh, out_he_vec);
    _n += cross(in_he_vec, out_he_vec);//sector area is taken into account
    in_he_vec = out_he_vec;
    in_he_vec *= -1;//change the orientation
  }
}

//-----------------------------------------------------------------------------
template <class Kernel>
void PolyMeshT<Kernel>::
calc_vertex_normal_loop(VertexHandle _vh, Normal& _n) const
{
  static const LoopSchemeMaskDouble& loop_scheme_mask__ =
                  LoopSchemeMaskDoubleSingleton::Instance();

  Normal t_v(0.0,0.0,0.0), t_w(0.0,0.0,0.0);
  unsigned int vh_val = valence(_vh);
  unsigned int i = 0;
  for (ConstVertexOHalfedgeIter cvoh_it = cvoh_iter(_vh); cvoh_it; ++cvoh_it, ++i)
  {
    VertexHandle r1_v(to_vertex_handle(cvoh_it));
    t_v += (typename Point::value_type)(loop_scheme_mask__.tang0_weight(vh_val, i))*this->point(r1_v);
    t_w += (typename Point::value_type)(loop_scheme_mask__.tang1_weight(vh_val, i))*this->point(r1_v);
  }
  _n = cross(t_w, t_v);//hack: should be cross(t_v, t_w), but then the normals are reversed?
}

//-----------------------------------------------------------------------------

template <class Kernel>
void
PolyMeshT<Kernel>::
update_vertex_normals()
{
  VertexIter  v_it(Kernel::vertices_begin()), v_end(Kernel::vertices_end());

  for (; v_it!=v_end; ++v_it)
    this->set_normal(v_it.handle(), calc_vertex_normal(v_it.handle()));
}

//=============================================================================
} // namespace OpenMesh
//=============================================================================
<commit_msg>Fixed build warning due to types<commit_after>/*===========================================================================*\
 *                                                                           *
 *                               OpenMesh                                    *
 *      Copyright (C) 2001-2011 by Computer Graphics Group, RWTH Aachen      *
 *                           www.openmesh.org                                *
 *                                                                           *
 *---------------------------------------------------------------------------*
 *  This file is part of OpenMesh.                                           *
 *                                                                           *
 *  OpenMesh is free software: you can redistribute it and/or modify         *
 *  it under the terms of the GNU Lesser General Public License as           *
 *  published by the Free Software Foundation, either version 3 of           *
 *  the License, or (at your option) any later version with the              *
 *  following exceptions:                                                    *
 *                                                                           *
 *  If other files instantiate templates or use macros                       *
 *  or inline functions from this file, or you compile this file and         *
 *  link it with other files to produce an executable, this file does        *
 *  not by itself cause the resulting executable to be covered by the        *
 *  GNU Lesser General Public License. This exception does not however       *
 *  invalidate any other reasons why the executable file might be            *
 *  covered by the GNU Lesser General Public License.                        *
 *                                                                           *
 *  OpenMesh is distributed in the hope that it will be useful,              *
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of           *
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            *
 *  GNU Lesser General Public License for more details.                      *
 *                                                                           *
 *  You should have received a copy of the GNU LesserGeneral Public          *
 *  License along with OpenMesh.  If not,                                    *
 *  see <http://www.gnu.org/licenses/>.                                      *
 *                                                                           *
\*===========================================================================*/

/*===========================================================================*\
 *                                                                           *
 *   $Revision$                                                         *
 *   $Date$                   *
 *                                                                           *
\*===========================================================================*/

//=============================================================================
//
//  CLASS PolyMeshT - IMPLEMENTATION
//
//=============================================================================

#define OPENMESH_POLYMESH_C

//== INCLUDES =================================================================

#include <OpenMesh/Core/Mesh/PolyMeshT.hh>
#include <OpenMesh/Core/Geometry/LoopSchemeMaskT.hh>
#include <OpenMesh/Core/Utils/vector_cast.hh>
#include <OpenMesh/Core/System/omstream.hh>
#include <vector>

//== NAMESPACES ===============================================================

namespace OpenMesh {

//== IMPLEMENTATION ==========================================================

template <class Kernel>
uint PolyMeshT<Kernel>::find_feature_edges(Scalar _angle_tresh)
{
  assert(Kernel::has_edge_status());//this function needs edge status property
  uint n_feature_edges = 0;
  for (EdgeIter e_it = Kernel::edges_begin(); e_it != Kernel::edges_end(); ++e_it)
  {
    if (fabs(calc_dihedral_angle(e_it)) > _angle_tresh)
    {//note: could be optimized by comparing cos(dih_angle) vs. cos(_angle_tresh)
      status(e_it).set_feature(true);
      n_feature_edges++;
    }
    else
    {
      status(e_it).set_feature(false);
    }
  }
  return n_feature_edges;
}

//-----------------------------------------------------------------------------

template <class Kernel>
typename PolyMeshT<Kernel>::Normal
PolyMeshT<Kernel>::
calc_face_normal(FaceHandle _fh) const
{
  assert(this->halfedge_handle(_fh).is_valid());
  ConstFaceVertexIter fv_it(this->cfv_iter(_fh));

  Point p0 = this->point(fv_it);
  Point p0i = p0; //save point of vertex 0
  ++fv_it;
  Point p1 = this->point(fv_it);
  Point p1i = p1; //save point of vertex 1
  ++fv_it;
  Point p2;

  //calculate area-weighted average normal of polygon's ears
  Normal n(0,0,0);
  for(; fv_it; ++fv_it)
  {
    p2 = this->point(fv_it);
    n += vector_cast<Normal>(calc_face_normal(p0, p1, p2));
    p0 = p1;
    p1 = p2;
  }

  //two additional steps since we started at vertex 2, not 0
  n += vector_cast<Normal>(calc_face_normal(p0i, p0, p1));
  n += vector_cast<Normal>(calc_face_normal(p1i, p0i, p1));

  typename Normal::value_type norm = n.length();

  // The expression ((n *= (1.0/norm)),n) is used because the OpenSG
  // vector class does not return self after component-wise
  // self-multiplication with a scalar!!!
  return (norm != typename Normal::value_type(0)) ? ((n *= (typename Normal::value_type(1)/norm)),n) : Normal(0,0,0);
}

//-----------------------------------------------------------------------------

template <class Kernel>
typename PolyMeshT<Kernel>::Normal
PolyMeshT<Kernel>::
calc_face_normal(const Point& _p0,
     const Point& _p1,
     const Point& _p2) const
{
#if 1
  // The OpenSG <Vector>::operator -= () does not support the type Point
  // as rhs. Therefore use vector_cast at this point!!!
  // Note! OpenSG distinguishes between Normal and Point!!!
  Normal p1p0(vector_cast<Normal>(_p0));  p1p0 -= vector_cast<Normal>(_p1);
  Normal p1p2(vector_cast<Normal>(_p2));  p1p2 -= vector_cast<Normal>(_p1);

  Normal n    = cross(p1p2, p1p0);
  typename Normal::value_type norm = n.length();

  // The expression ((n *= (1.0/norm)),n) is used because the OpenSG
  // vector class does not return self after component-wise
  // self-multiplication with a scalar!!!
  return (norm != typename Normal::value_type(0)) ? ((n *= (typename Normal::value_type(1)/norm)),n) : Normal(0,0,0);
#else
  Point p1p0 = _p0;  p1p0 -= _p1;
  Point p1p2 = _p2;  p1p2 -= _p1;

  Normal n = vector_cast<Normal>(cross(p1p2, p1p0));
  typename Normal::value_type norm = n.length();

  return (norm != 0.0) ? n *= (1.0/norm) : Normal(0,0,0);
#endif
}

//-----------------------------------------------------------------------------

template <class Kernel>
void
PolyMeshT<Kernel>::
calc_face_centroid(FaceHandle _fh, Point& _pt) const
{
  _pt.vectorize(0);
  Scalar valence = 0.0;
  for (ConstFaceVertexIter cfv_it = this->cfv_iter(_fh); cfv_it; ++cfv_it, valence += 1.0)
  {
    _pt += this->point(cfv_it);
  }
  _pt /= valence;
}
//-----------------------------------------------------------------------------

template <class Kernel>
void
PolyMeshT<Kernel>::
update_normals()
{
  // Face normals are required to compute the vertex and the halfedge normals
  if (Kernel::has_face_normals() ) {
    update_face_normals();

    if (Kernel::has_vertex_normals() ) update_vertex_normals();
    if (Kernel::has_halfedge_normals()) update_halfedge_normals();
  }
}

//-----------------------------------------------------------------------------

template <class Kernel>
void
PolyMeshT<Kernel>::
update_face_normals()
{
  FaceIter f_it(Kernel::faces_begin()), f_end(Kernel::faces_end());

  for (; f_it != f_end; ++f_it)
    this->set_normal(f_it.handle(), calc_face_normal(f_it.handle()));
}

//-----------------------------------------------------------------------------

template <class Kernel>
void
PolyMeshT<Kernel>::
update_halfedge_normals(const double _feature_angle)
{
  HalfedgeIter h_it(Kernel::halfedges_begin()), h_end(Kernel::halfedges_end());

  for (; h_it != h_end; ++h_it)
    this->set_normal(h_it.handle(), calc_halfedge_normal(h_it.handle(), _feature_angle));
}

//-----------------------------------------------------------------------------

template <class Kernel>
typename PolyMeshT<Kernel>::Normal
PolyMeshT<Kernel>::
calc_halfedge_normal(HalfedgeHandle _heh, const double _feature_angle) const
{
  if(Kernel::is_boundary(_heh))
    return Normal(0,0,0);
  else
  {
    std::vector<FaceHandle> fhs; fhs.reserve(10);

    HalfedgeHandle heh = _heh;

    // collect CW face-handles
    do
    {
      fhs.push_back(Kernel::face_handle(heh));

      heh = Kernel::next_halfedge_handle(heh);
      heh = Kernel::opposite_halfedge_handle(heh);
    }
    while(heh != _heh && !Kernel::is_boundary(heh) && !is_estimated_feature_edge(heh, _feature_angle));

    // collect CCW face-handles
    if(heh != _heh && !is_estimated_feature_edge(_heh, _feature_angle))
    {
      heh = Kernel::opposite_halfedge_handle(_heh);

      if ( !Kernel::is_boundary(heh) ) {
        do
        {

          fhs.push_back(Kernel::face_handle(heh));

          heh = Kernel::prev_halfedge_handle(heh);
          heh = Kernel::opposite_halfedge_handle(heh);
        }
        while(!Kernel::is_boundary(heh) && !is_estimated_feature_edge(heh, _feature_angle));
      }
    }

    Normal n(0,0,0);
    for(unsigned int i=0; i<fhs.size(); ++i)
      n += Kernel::normal(fhs[i]);

    return n.normalize();
  }
}

//-----------------------------------------------------------------------------

template <class Kernel>
bool
PolyMeshT<Kernel>::
is_estimated_feature_edge(HalfedgeHandle _heh, const double _feature_angle) const
{
  EdgeHandle eh = Kernel::edge_handle(_heh);

  if(Kernel::has_edge_status())
  {
    if(Kernel::status(eh).feature())
      return true;
  }

  if(Kernel::is_boundary(eh))
    return false;

  // compute angle between faces
  FaceHandle fh0 = Kernel::face_handle(_heh);
  FaceHandle fh1 = Kernel::face_handle(Kernel::opposite_halfedge_handle(_heh));

  Normal fn0 = Kernel::normal(fh0);
  Normal fn1 = Kernel::normal(fh1);

  // dihedral angle above angle threshold
  return ( dot(fn0,fn1) < cos(_feature_angle) );
}

//-----------------------------------------------------------------------------

template <class Kernel>
typename PolyMeshT<Kernel>::Normal
PolyMeshT<Kernel>::
calc_vertex_normal(VertexHandle _vh) const
{
  Normal n;
  calc_vertex_normal_fast(_vh,n);

  Scalar norm = n.length();
  if (norm != 0.0) n *= (1.0/norm);

  return n;
}

//-----------------------------------------------------------------------------
template <class Kernel>
void PolyMeshT<Kernel>::
calc_vertex_normal_fast(VertexHandle _vh, Normal& _n) const
{
  _n.vectorize(0.0);
  for (ConstVertexFaceIter vf_it=this->cvf_iter(_vh); vf_it; ++vf_it)
    _n += this->normal(vf_it.handle());
}

//-----------------------------------------------------------------------------
template <class Kernel>
void PolyMeshT<Kernel>::
calc_vertex_normal_correct(VertexHandle _vh, Normal& _n) const
{
  _n.vectorize(0.0);
  ConstVertexIHalfedgeIter cvih_it = cvih_iter(_vh);
  if (!cvih_it)
  {//don't crash on isolated vertices
    return;
  }
  Normal in_he_vec;
  calc_edge_vector(cvih_it, in_he_vec);
  for ( ; cvih_it; ++cvih_it)
  {//calculates the sector normal defined by cvih_it and adds it to _n
    if (is_boundary(cvih_it))
    {
      continue;
    }
    HalfedgeHandle out_heh(next_halfedge_handle(cvih_it));
    Normal out_he_vec;
    calc_edge_vector(out_heh, out_he_vec);
    _n += cross(in_he_vec, out_he_vec);//sector area is taken into account
    in_he_vec = out_he_vec;
    in_he_vec *= -1;//change the orientation
  }
}

//-----------------------------------------------------------------------------
template <class Kernel>
void PolyMeshT<Kernel>::
calc_vertex_normal_loop(VertexHandle _vh, Normal& _n) const
{
  static const LoopSchemeMaskDouble& loop_scheme_mask__ =
                  LoopSchemeMaskDoubleSingleton::Instance();

  Normal t_v(0.0,0.0,0.0), t_w(0.0,0.0,0.0);
  unsigned int vh_val = valence(_vh);
  unsigned int i = 0;
  for (ConstVertexOHalfedgeIter cvoh_it = cvoh_iter(_vh); cvoh_it; ++cvoh_it, ++i)
  {
    VertexHandle r1_v(to_vertex_handle(cvoh_it));
    t_v += (typename Point::value_type)(loop_scheme_mask__.tang0_weight(vh_val, i))*this->point(r1_v);
    t_w += (typename Point::value_type)(loop_scheme_mask__.tang1_weight(vh_val, i))*this->point(r1_v);
  }
  _n = cross(t_w, t_v);//hack: should be cross(t_v, t_w), but then the normals are reversed?
}

//-----------------------------------------------------------------------------

template <class Kernel>
void
PolyMeshT<Kernel>::
update_vertex_normals()
{
  VertexIter  v_it(Kernel::vertices_begin()), v_end(Kernel::vertices_end());

  for (; v_it!=v_end; ++v_it)
    this->set_normal(v_it.handle(), calc_vertex_normal(v_it.handle()));
}

//=============================================================================
} // namespace OpenMesh
//=============================================================================
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2007, Michael Feathers, James Grenning and Bas Vodde
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the <organization> nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE EARLIER MENTIONED AUTHORS ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <stdlib.h>
#include "CppUTest/TestHarness.h"
#undef malloc
#undef free
#undef calloc
#undef realloc
#undef strdup
#undef strndup

#ifdef CPPUTEST_HAVE_GETTIMEOFDAY
#include <sys/time.h>
#endif

#include <time.h>
#include <stdio.h>
#include <stdarg.h>
#include <setjmp.h>
#include <string.h>
#include <math.h>
#include <ctype.h>
#include <unistd.h>
#include <signal.h>
#ifndef __MINGW32__
#include <sys/wait.h>
#include <errno.h>
#endif
#include <pthread.h>

#include "CppUTest/PlatformSpecificFunctions.h"

static jmp_buf test_exit_jmp_buf[10];
static int jmp_buf_index = 0;

#ifndef CPPUTEST_HAVE_FORK

static void GccPlatformSpecificRunTestInASeperateProcess(UtestShell* shell, TestPlugin*, TestResult* result)
{
    result->addFailure(TestFailure(shell, "-p doesn't work on this platform, as it is lacking fork.\b"));
}

static int PlatformSpecificForkImplementation(void)
{
    return 0;
}

static int PlatformSpecificWaitPidImplementation(int, int*, int)
{
    return 0;
}

#else

static void SetTestFailureByStatusCode(UtestShell* shell, TestResult* result, int status)
{
    if (WIFEXITED(status) && WEXITSTATUS(status) != 0) {
        result->addFailure(TestFailure(shell, "Failed in separate process"));
    } else if (WIFSIGNALED(status)) {
        SimpleString message("Failed in separate process - killed by signal ");
        message += StringFrom(WTERMSIG(status));
        result->addFailure(TestFailure(shell, message));
    } else if (WIFSTOPPED(status)) {
        result->addFailure(TestFailure(shell, "Stopped in separate process - continuing"));
    }
}

static void GccPlatformSpecificRunTestInASeperateProcess(UtestShell* shell, TestPlugin* plugin, TestResult* result)
{
    const pid_t syscallError = -1;
    pid_t cpid;
    pid_t w;
    int status = 0;

    cpid = PlatformSpecificFork();

    if (cpid == syscallError) {
        result->addFailure(TestFailure(shell, "Call to fork() failed"));
        return;
    }

    if (cpid == 0) {            /* Code executed by child */
        const size_t initialFailureCount = result->getFailureCount(); // LCOV_EXCL_LINE
        shell->runOneTestInCurrentProcess(plugin, *result);        // LCOV_EXCL_LINE
        _exit(initialFailureCount < result->getFailureCount());    // LCOV_EXCL_LINE
    } else {                    /* Code executed by parent */
        size_t amountOfRetries = 0;
        do {
            w = PlatformSpecificWaitPid(cpid, &status, WUNTRACED);
            if (w == syscallError) {
                // OS X debugger causes EINTR
                if (EINTR == errno) {
                  if (amountOfRetries > 30) {
                    result->addFailure(TestFailure(shell, "Call to waitpid() failed with EINTR. Tried 30 times and giving up! Sometimes happens in debugger"));
                    return;
                  }
                  amountOfRetries++;
                }
                else {
                    result->addFailure(TestFailure(shell, "Call to waitpid() failed"));
                    return;
                }
            } else {
                SetTestFailureByStatusCode(shell, result, status);
                if (WIFSTOPPED(status)) kill(w, SIGCONT);
            }
        } while ((w == syscallError) || (!WIFEXITED(status) && !WIFSIGNALED(status)));
    }
}

static pid_t PlatformSpecificForkImplementation(void)
{
    return fork();
}

static pid_t PlatformSpecificWaitPidImplementation(int pid, int* status, int options)
{
    return waitpid(pid, status, options);
}

#endif

TestOutput::WorkingEnvironment PlatformSpecificGetWorkingEnvironment()
{
    return TestOutput::eclipse;
}

void (*PlatformSpecificRunTestInASeperateProcess)(UtestShell* shell, TestPlugin* plugin, TestResult* result) =
        GccPlatformSpecificRunTestInASeperateProcess;
int (*PlatformSpecificFork)(void) = PlatformSpecificForkImplementation;
int (*PlatformSpecificWaitPid)(int, int*, int) = PlatformSpecificWaitPidImplementation;

extern "C" {

static int PlatformSpecificSetJmpImplementation(void (*function) (void* data), void* data)
{
    if (0 == setjmp(test_exit_jmp_buf[jmp_buf_index])) {
        jmp_buf_index++;
        function(data);
        jmp_buf_index--;
        return 1;
    }
    return 0;
}

/*
 * MacOSX clang 3.0 doesn't seem to recognize longjmp and thus complains about __no_return_.
 * The later clang compilers complain when it isn't there. So only way is to check the clang compiler here :(
 */
#if !((__clang_major__ == 3) && (__clang_minor__ == 0))
__no_return__
#endif
static void PlatformSpecificLongJmpImplementation()
{
    jmp_buf_index--;
    longjmp(test_exit_jmp_buf[jmp_buf_index], 1);
}

static void PlatformSpecificRestoreJumpBufferImplementation()
{
    jmp_buf_index--;
}

void (*PlatformSpecificLongJmp)() = PlatformSpecificLongJmpImplementation;
int (*PlatformSpecificSetJmp)(void (*)(void*), void*) = PlatformSpecificSetJmpImplementation;
void (*PlatformSpecificRestoreJumpBuffer)() = PlatformSpecificRestoreJumpBufferImplementation;

///////////// Time in millis

static long TimeInMillisImplementation()
{
#ifdef CPPUTEST_HAVE_GETTIMEOFDAY
    struct timeval tv;
    struct timezone tz;
    gettimeofday(&tv, &tz);
    return (tv.tv_sec * 1000) + (long)((double)tv.tv_usec * 0.001);
#else
    return 0;
#endif
}

static const char* TimeStringImplementation()
{
    time_t tm = time(NULLPTR);
    static char dateTime[80];
    struct tm *tmp = localtime(&tm);
    strftime(dateTime, 80, "%Y-%m-%dT%H:%M:%S", tmp);
    return dateTime;
}

long (*GetPlatformSpecificTimeInMillis)() = TimeInMillisImplementation;
const char* (*GetPlatformSpecificTimeString)() = TimeStringImplementation;

/* Wish we could add an attribute to the format for discovering mis-use... but the __attribute__(format) seems to not work on va_list */
#ifdef __clang__
#pragma clang diagnostic ignored "-Wformat-nonliteral"
#endif

#ifdef __clang__
#pragma clang diagnostic ignored "-Wused-but-marked-unused"
#endif
int (*PlatformSpecificVSNprintf)(char *str, size_t size, const char* format, va_list va_args_list) = vsnprintf;

static PlatformSpecificFile PlatformSpecificFOpenImplementation(const char* filename, const char* flag)
{
   return fopen(filename, flag);
}

static void PlatformSpecificFPutsImplementation(const char* str, PlatformSpecificFile file)
{
   fputs(str, (FILE*)file);
}

static void PlatformSpecificFCloseImplementation(PlatformSpecificFile file)
{
   fclose((FILE*)file);
}

static void PlatformSpecificFlushImplementation()
{
  fflush(stdout);
}

PlatformSpecificFile (*PlatformSpecificFOpen)(const char*, const char*) = PlatformSpecificFOpenImplementation;
void (*PlatformSpecificFPuts)(const char*, PlatformSpecificFile) = PlatformSpecificFPutsImplementation;
void (*PlatformSpecificFClose)(PlatformSpecificFile) = PlatformSpecificFCloseImplementation;

int (*PlatformSpecificPutchar)(int) = putchar;
void (*PlatformSpecificFlush)() = PlatformSpecificFlushImplementation;

void* (*PlatformSpecificMalloc)(size_t size) = malloc;
void* (*PlatformSpecificRealloc)(void*, size_t) = realloc;
void (*PlatformSpecificFree)(void* memory) = free;
void* (*PlatformSpecificMemCpy)(void*, const void*, size_t) = memcpy;
void* (*PlatformSpecificMemset)(void*, int, size_t) = memset;

/* GCC 4.9.x introduces -Wfloat-conversion, which causes a warning / error
 * in GCC's own (macro) implementation of isnan() and isinf().
 */
#if defined(__GNUC__) && (__GNUC__ >= 5 || (__GNUC__ == 4 && __GNUC_MINOR__ > 8))
#pragma GCC diagnostic ignored "-Wfloat-conversion"
#endif

static int IsNanImplementation(double d)
{
    return isnan(d);
}

static int IsInfImplementation(double d)
{
    return isinf(d);
}

double (*PlatformSpecificFabs)(double) = fabs;
void (*PlatformSpecificSrand)(unsigned int) = srand;
int (*PlatformSpecificRand)(void) = rand;
int (*PlatformSpecificIsNan)(double) = IsNanImplementation;
int (*PlatformSpecificIsInf)(double) = IsInfImplementation;
int (*PlatformSpecificAtExit)(void(*func)(void)) = atexit;  /// this was undefined before

static PlatformSpecificMutex PThreadMutexCreate(void)
{
    pthread_mutex_t *mutex = new pthread_mutex_t;

    pthread_mutex_init(mutex, NULLPTR);

    return (PlatformSpecificMutex)mutex;
}

static void PThreadMutexLock(PlatformSpecificMutex mtx)
{
    pthread_mutex_lock((pthread_mutex_t *)mtx);
}

static void PThreadMutexUnlock(PlatformSpecificMutex mtx)
{
    pthread_mutex_unlock((pthread_mutex_t *)mtx);
}

static void PThreadMutexDestroy(PlatformSpecificMutex mtx)
{
    pthread_mutex_t *mutex = (pthread_mutex_t *)mtx;
    pthread_mutex_destroy(mutex);
    delete mutex;
}

PlatformSpecificMutex (*PlatformSpecificMutexCreate)(void) = PThreadMutexCreate;
void (*PlatformSpecificMutexLock)(PlatformSpecificMutex) = PThreadMutexLock;
void (*PlatformSpecificMutexUnlock)(PlatformSpecificMutex) = PThreadMutexUnlock;
void (*PlatformSpecificMutexDestroy)(PlatformSpecificMutex) = PThreadMutexDestroy;

}
<commit_msg>Added #ifdef before include<commit_after>/*
 * Copyright (c) 2007, Michael Feathers, James Grenning and Bas Vodde
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the <organization> nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE EARLIER MENTIONED AUTHORS ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <stdlib.h>
#include "CppUTest/TestHarness.h"
#undef malloc
#undef free
#undef calloc
#undef realloc
#undef strdup
#undef strndup

#ifdef CPPUTEST_HAVE_GETTIMEOFDAY
#include <sys/time.h>
#endif
#ifdef CPPUTEST_HAVE_FORK
#include <unistd.h>
#endif

#include <time.h>
#include <stdio.h>
#include <stdarg.h>
#include <setjmp.h>
#include <string.h>
#include <math.h>
#include <ctype.h>
#include <signal.h>
#ifndef __MINGW32__
#include <sys/wait.h>
#include <errno.h>
#endif
#include <pthread.h>

#include "CppUTest/PlatformSpecificFunctions.h"

static jmp_buf test_exit_jmp_buf[10];
static int jmp_buf_index = 0;

#ifndef CPPUTEST_HAVE_FORK

static void GccPlatformSpecificRunTestInASeperateProcess(UtestShell* shell, TestPlugin*, TestResult* result)
{
    result->addFailure(TestFailure(shell, "-p doesn't work on this platform, as it is lacking fork.\b"));
}

static int PlatformSpecificForkImplementation(void)
{
    return 0;
}

static int PlatformSpecificWaitPidImplementation(int, int*, int)
{
    return 0;
}

#else

static void SetTestFailureByStatusCode(UtestShell* shell, TestResult* result, int status)
{
    if (WIFEXITED(status) && WEXITSTATUS(status) != 0) {
        result->addFailure(TestFailure(shell, "Failed in separate process"));
    } else if (WIFSIGNALED(status)) {
        SimpleString message("Failed in separate process - killed by signal ");
        message += StringFrom(WTERMSIG(status));
        result->addFailure(TestFailure(shell, message));
    } else if (WIFSTOPPED(status)) {
        result->addFailure(TestFailure(shell, "Stopped in separate process - continuing"));
    }
}

static void GccPlatformSpecificRunTestInASeperateProcess(UtestShell* shell, TestPlugin* plugin, TestResult* result)
{
    const pid_t syscallError = -1;
    pid_t cpid;
    pid_t w;
    int status = 0;

    cpid = PlatformSpecificFork();

    if (cpid == syscallError) {
        result->addFailure(TestFailure(shell, "Call to fork() failed"));
        return;
    }

    if (cpid == 0) {            /* Code executed by child */
        const size_t initialFailureCount = result->getFailureCount(); // LCOV_EXCL_LINE
        shell->runOneTestInCurrentProcess(plugin, *result);        // LCOV_EXCL_LINE
        _exit(initialFailureCount < result->getFailureCount());    // LCOV_EXCL_LINE
    } else {                    /* Code executed by parent */
        size_t amountOfRetries = 0;
        do {
            w = PlatformSpecificWaitPid(cpid, &status, WUNTRACED);
            if (w == syscallError) {
                // OS X debugger causes EINTR
                if (EINTR == errno) {
                  if (amountOfRetries > 30) {
                    result->addFailure(TestFailure(shell, "Call to waitpid() failed with EINTR. Tried 30 times and giving up! Sometimes happens in debugger"));
                    return;
                  }
                  amountOfRetries++;
                }
                else {
                    result->addFailure(TestFailure(shell, "Call to waitpid() failed"));
                    return;
                }
            } else {
                SetTestFailureByStatusCode(shell, result, status);
                if (WIFSTOPPED(status)) kill(w, SIGCONT);
            }
        } while ((w == syscallError) || (!WIFEXITED(status) && !WIFSIGNALED(status)));
    }
}

static pid_t PlatformSpecificForkImplementation(void)
{
    return fork();
}

static pid_t PlatformSpecificWaitPidImplementation(int pid, int* status, int options)
{
    return waitpid(pid, status, options);
}

#endif

TestOutput::WorkingEnvironment PlatformSpecificGetWorkingEnvironment()
{
    return TestOutput::eclipse;
}

void (*PlatformSpecificRunTestInASeperateProcess)(UtestShell* shell, TestPlugin* plugin, TestResult* result) =
        GccPlatformSpecificRunTestInASeperateProcess;
int (*PlatformSpecificFork)(void) = PlatformSpecificForkImplementation;
int (*PlatformSpecificWaitPid)(int, int*, int) = PlatformSpecificWaitPidImplementation;

extern "C" {

static int PlatformSpecificSetJmpImplementation(void (*function) (void* data), void* data)
{
    if (0 == setjmp(test_exit_jmp_buf[jmp_buf_index])) {
        jmp_buf_index++;
        function(data);
        jmp_buf_index--;
        return 1;
    }
    return 0;
}

/*
 * MacOSX clang 3.0 doesn't seem to recognize longjmp and thus complains about __no_return_.
 * The later clang compilers complain when it isn't there. So only way is to check the clang compiler here :(
 */
#if !((__clang_major__ == 3) && (__clang_minor__ == 0))
__no_return__
#endif
static void PlatformSpecificLongJmpImplementation()
{
    jmp_buf_index--;
    longjmp(test_exit_jmp_buf[jmp_buf_index], 1);
}

static void PlatformSpecificRestoreJumpBufferImplementation()
{
    jmp_buf_index--;
}

void (*PlatformSpecificLongJmp)() = PlatformSpecificLongJmpImplementation;
int (*PlatformSpecificSetJmp)(void (*)(void*), void*) = PlatformSpecificSetJmpImplementation;
void (*PlatformSpecificRestoreJumpBuffer)() = PlatformSpecificRestoreJumpBufferImplementation;

///////////// Time in millis

static long TimeInMillisImplementation()
{
#ifdef CPPUTEST_HAVE_GETTIMEOFDAY
    struct timeval tv;
    struct timezone tz;
    gettimeofday(&tv, &tz);
    return (tv.tv_sec * 1000) + (long)((double)tv.tv_usec * 0.001);
#else
    return 0;
#endif
}

static const char* TimeStringImplementation()
{
    time_t tm = time(NULLPTR);
    static char dateTime[80];
    struct tm *tmp = localtime(&tm);
    strftime(dateTime, 80, "%Y-%m-%dT%H:%M:%S", tmp);
    return dateTime;
}

long (*GetPlatformSpecificTimeInMillis)() = TimeInMillisImplementation;
const char* (*GetPlatformSpecificTimeString)() = TimeStringImplementation;

/* Wish we could add an attribute to the format for discovering mis-use... but the __attribute__(format) seems to not work on va_list */
#ifdef __clang__
#pragma clang diagnostic ignored "-Wformat-nonliteral"
#endif

#ifdef __clang__
#pragma clang diagnostic ignored "-Wused-but-marked-unused"
#endif
int (*PlatformSpecificVSNprintf)(char *str, size_t size, const char* format, va_list va_args_list) = vsnprintf;

static PlatformSpecificFile PlatformSpecificFOpenImplementation(const char* filename, const char* flag)
{
   return fopen(filename, flag);
}

static void PlatformSpecificFPutsImplementation(const char* str, PlatformSpecificFile file)
{
   fputs(str, (FILE*)file);
}

static void PlatformSpecificFCloseImplementation(PlatformSpecificFile file)
{
   fclose((FILE*)file);
}

static void PlatformSpecificFlushImplementation()
{
  fflush(stdout);
}

PlatformSpecificFile (*PlatformSpecificFOpen)(const char*, const char*) = PlatformSpecificFOpenImplementation;
void (*PlatformSpecificFPuts)(const char*, PlatformSpecificFile) = PlatformSpecificFPutsImplementation;
void (*PlatformSpecificFClose)(PlatformSpecificFile) = PlatformSpecificFCloseImplementation;

int (*PlatformSpecificPutchar)(int) = putchar;
void (*PlatformSpecificFlush)() = PlatformSpecificFlushImplementation;

void* (*PlatformSpecificMalloc)(size_t size) = malloc;
void* (*PlatformSpecificRealloc)(void*, size_t) = realloc;
void (*PlatformSpecificFree)(void* memory) = free;
void* (*PlatformSpecificMemCpy)(void*, const void*, size_t) = memcpy;
void* (*PlatformSpecificMemset)(void*, int, size_t) = memset;

/* GCC 4.9.x introduces -Wfloat-conversion, which causes a warning / error
 * in GCC's own (macro) implementation of isnan() and isinf().
 */
#if defined(__GNUC__) && (__GNUC__ >= 5 || (__GNUC__ == 4 && __GNUC_MINOR__ > 8))
#pragma GCC diagnostic ignored "-Wfloat-conversion"
#endif

static int IsNanImplementation(double d)
{
    return isnan(d);
}

static int IsInfImplementation(double d)
{
    return isinf(d);
}

double (*PlatformSpecificFabs)(double) = fabs;
void (*PlatformSpecificSrand)(unsigned int) = srand;
int (*PlatformSpecificRand)(void) = rand;
int (*PlatformSpecificIsNan)(double) = IsNanImplementation;
int (*PlatformSpecificIsInf)(double) = IsInfImplementation;
int (*PlatformSpecificAtExit)(void(*func)(void)) = atexit;  /// this was undefined before

static PlatformSpecificMutex PThreadMutexCreate(void)
{
    pthread_mutex_t *mutex = new pthread_mutex_t;

    pthread_mutex_init(mutex, NULLPTR);

    return (PlatformSpecificMutex)mutex;
}

static void PThreadMutexLock(PlatformSpecificMutex mtx)
{
    pthread_mutex_lock((pthread_mutex_t *)mtx);
}

static void PThreadMutexUnlock(PlatformSpecificMutex mtx)
{
    pthread_mutex_unlock((pthread_mutex_t *)mtx);
}

static void PThreadMutexDestroy(PlatformSpecificMutex mtx)
{
    pthread_mutex_t *mutex = (pthread_mutex_t *)mtx;
    pthread_mutex_destroy(mutex);
    delete mutex;
}

PlatformSpecificMutex (*PlatformSpecificMutexCreate)(void) = PThreadMutexCreate;
void (*PlatformSpecificMutexLock)(PlatformSpecificMutex) = PThreadMutexLock;
void (*PlatformSpecificMutexUnlock)(PlatformSpecificMutex) = PThreadMutexUnlock;
void (*PlatformSpecificMutexDestroy)(PlatformSpecificMutex) = PThreadMutexDestroy;

}
<|endoftext|>


<commit_before><commit_msg>`InputMaster`: make 1 parameter constructor `explicit`.<commit_after><|endoftext|>


<commit_before>#include <coffee/core/platform_data.h>
#include <coffee/core/plat/plat_environment.h>

#include <coffee/core/plat/plat_primary_identify.h>
#include <coffee/core/coffee_mem_macros.h>

#if defined(COFFEE_ANDROID)
#include <coffee/android/android_main.h>
#endif

namespace Coffee{

#if defined(COFFEE_LINUX)
namespace Environment{
namespace Linux{
extern CString get_kern_name();
extern CString get_kern_arch();
extern PlatformData::DeviceType get_device_variant();
}
}
#endif

PlatformData::DeviceType PlatformData::DeviceVariant()
{
#if defined(COFFEE_ANDROID) \
    || defined(COFFEE_APPLE_MOBILE) \
    || defined(COFFEE_MAEMO)

    /* TODO: Add difference between tablet and phone */

    return DevicePhone;
#elif defined(COFFEE_LINUX)
    return DeviceUnknown;
#elif defined(COFFEE_RASPBERRY)
    return DeviceIOT;
#elif
    return DevicePhone;
#elif defined(COFFEE_EMSCRIPTEN)
    return DeviceIOT;
#else
    return DeviceUnknown;
#endif
}

PlatformData::Platform PlatformData::PlatformVariant()
{
#if defined(COFFEE_ANDROID)
    return PlatformAndroid;

#elif defined(COFFEE_RASPBERRYPI)
    return PlatformLinuxRaspberry;
#elif defined(COFFEE_MAEMO)
    return PlatformLinuxMaemo;
#elif defined(COFFEE_LINUX)
    return PlatformLinux;

#elif defined(COFFEE_EMSCRIPTEN)
    return PlatformEmscripten;

#elif defined(COFFEE_MINGW64)
    return PlatformMinGW;
#elif defined(COFFEE_WINDOWS_UWP)
    return PlatformUWP;
#elif defined(COFFEE_WINDOWS)
    return PlatformWindows;

#elif defined(COFFEE_APPLE_MOBILE)
    return PlatformMacIOS;
#elif defined(COFFEE_APPLE)
    return PlatformMac;

#elif defined(COFFEE_UNIXPLAT)
    return PlatformUnix;
#endif
}

scalar PlatformData::DeviceDPI()
{
    /* TODO: Add DPI fetch for Android and iOS */
    /* Also, add DPI fetching for OS X and Linux */
    /* DPI in Windows is a lie */
#if defined(COFFEE_ANDROID)

    AndroidForeignCommand fcmd;
    fcmd.type = Android_QueryDeviceDPI;

    CoffeeForeignSignalHandleNA(CoffeeForeign_RequestPlatformData,
                                &fcmd, nullptr, nullptr);

    /* A very careful ballpark set of constants
     *  based on how it looks on a 320 DPI screen
     *  and a 420 DPI screen */
    return (scalar(fcmd.data.scalarI64) / 160.f);
#else
    return 1.f;
#endif
}

CString PlatformData::SystemDisplayString()
{
    const constexpr cstring _fmt = "%s %s %u-bit (%s ";
    CString sys_ver = SysInfo::GetSystemVersion();
    CString sys_name = C_SYSTEM_STRING;
    CString curr_arch = COFFEE_ARCH;
#if defined(COFFEE_LINUX)
    sys_name = Environment::Linux::get_kern_name();
    curr_arch = Environment::Linux::get_kern_arch();
#endif
    int len = snprintf(nullptr,0,_fmt,
                       sys_name.c_str(),
                       sys_ver.c_str(),
                       C_SYSTEM_BITNESS,
                       curr_arch.c_str());
    CString base;
    base.resize(len);
    snprintf(&base[0],base.size(),_fmt,
            sys_name.c_str(),
            sys_ver.c_str(),
            C_SYSTEM_BITNESS,
            curr_arch.c_str());
    base.resize(base.find('\0'));
    /* What the fuck. Where does the rest of the string go? */
    base.append(")");
    return base;
}

bool PlatformData::IsMobile()
{
#if defined(COFFEE_ANDROID) || defined(COFFEE_IOS)
    return true;
#else
    return false;
#endif
}

bool PlatformData::UseVirtualFS()
{
#if defined(COFFEE_ANDROID) || defined(COFFEE_WINDOWS)
    return true;
#else
    return false;
#endif
}

bool PlatformData::IsDebug()
{
#ifndef NDEBUG
    return true;
#else
    return false;
#endif
}

}
<commit_msg> - Fix tiny oopsie<commit_after>#include <coffee/core/platform_data.h>
#include <coffee/core/plat/plat_environment.h>

#include <coffee/core/plat/plat_primary_identify.h>
#include <coffee/core/coffee_mem_macros.h>

#if defined(COFFEE_ANDROID)
#include <coffee/android/android_main.h>
#endif

namespace Coffee{

#if defined(COFFEE_LINUX)
namespace Environment{
namespace Linux{
extern CString get_kern_name();
extern CString get_kern_arch();
extern PlatformData::DeviceType get_device_variant();
}
}
#endif

PlatformData::DeviceType PlatformData::DeviceVariant()
{
#if defined(COFFEE_ANDROID) \
    || defined(COFFEE_APPLE_MOBILE) \
    || defined(COFFEE_MAEMO)

    /* TODO: Add difference between tablet and phone */

    return DevicePhone;
#elif defined(COFFEE_LINUX)
    return DeviceUnknown;
#elif defined(COFFEE_RASPBERRY)
    return DeviceIOT;
#elif defined(COFFEE_EMSCRIPTEN)
    return DeviceIOT;
#else
    return DeviceUnknown;
#endif
}

PlatformData::Platform PlatformData::PlatformVariant()
{
#if defined(COFFEE_ANDROID)
    return PlatformAndroid;

#elif defined(COFFEE_RASPBERRYPI)
    return PlatformLinuxRaspberry;
#elif defined(COFFEE_MAEMO)
    return PlatformLinuxMaemo;
#elif defined(COFFEE_LINUX)
    return PlatformLinux;

#elif defined(COFFEE_EMSCRIPTEN)
    return PlatformEmscripten;

#elif defined(COFFEE_MINGW64)
    return PlatformMinGW;
#elif defined(COFFEE_WINDOWS_UWP)
    return PlatformUWP;
#elif defined(COFFEE_WINDOWS)
    return PlatformWindows;

#elif defined(COFFEE_APPLE_MOBILE)
    return PlatformMacIOS;
#elif defined(COFFEE_APPLE)
    return PlatformMac;

#elif defined(COFFEE_UNIXPLAT)
    return PlatformUnix;
#endif
}

scalar PlatformData::DeviceDPI()
{
    /* TODO: Add DPI fetch for Android and iOS */
    /* Also, add DPI fetching for OS X and Linux */
    /* DPI in Windows is a lie */
#if defined(COFFEE_ANDROID)

    AndroidForeignCommand fcmd;
    fcmd.type = Android_QueryDeviceDPI;

    CoffeeForeignSignalHandleNA(CoffeeForeign_RequestPlatformData,
                                &fcmd, nullptr, nullptr);

    /* A very careful ballpark set of constants
     *  based on how it looks on a 320 DPI screen
     *  and a 420 DPI screen */
    return (scalar(fcmd.data.scalarI64) / 160.f);
#else
    return 1.f;
#endif
}

CString PlatformData::SystemDisplayString()
{
    const constexpr cstring _fmt = "%s %s %u-bit (%s ";
    CString sys_ver = SysInfo::GetSystemVersion();
    CString sys_name = C_SYSTEM_STRING;
    CString curr_arch = COFFEE_ARCH;
#if defined(COFFEE_LINUX)
    sys_name = Environment::Linux::get_kern_name();
    curr_arch = Environment::Linux::get_kern_arch();
#endif
    int len = snprintf(nullptr,0,_fmt,
                       sys_name.c_str(),
                       sys_ver.c_str(),
                       C_SYSTEM_BITNESS,
                       curr_arch.c_str());
    CString base;
    base.resize(len);
    snprintf(&base[0],base.size(),_fmt,
            sys_name.c_str(),
            sys_ver.c_str(),
            C_SYSTEM_BITNESS,
            curr_arch.c_str());
    base.resize(base.find('\0'));
    /* What the fuck. Where does the rest of the string go? */
    base.append(")");
    return base;
}

bool PlatformData::IsMobile()
{
#if defined(COFFEE_ANDROID) || defined(COFFEE_IOS)
    return true;
#else
    return false;
#endif
}

bool PlatformData::UseVirtualFS()
{
#if defined(COFFEE_ANDROID) || defined(COFFEE_WINDOWS)
    return true;
#else
    return false;
#endif
}

bool PlatformData::IsDebug()
{
#ifndef NDEBUG
    return true;
#else
    return false;
#endif
}

}
<|endoftext|>


<commit_before><commit_msg>Fixing bug on deletion<commit_after><|endoftext|>


<commit_before><commit_msg>Better variable name<commit_after><|endoftext|>


<commit_before>//===----------------------------------------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

// test <stdio.h>

#include <stdio.h>
#include <type_traits>

#ifndef BUFSIZ
#error BUFSIZ not defined
#endif

#ifndef EOF
#error EOF not defined
#endif

#ifndef FILENAME_MAX
#error FILENAME_MAX not defined
#endif

#ifndef FOPEN_MAX
#error FOPEN_MAX not defined
#endif

#ifndef L_tmpnam
#error L_tmpnam not defined
#endif

#ifndef NULL
#error NULL not defined
#endif

#ifndef SEEK_CUR
#error SEEK_CUR not defined
#endif

#ifndef SEEK_END
#error SEEK_END not defined
#endif

#ifndef SEEK_SET
#error SEEK_SET not defined
#endif

#ifndef TMP_MAX
#error TMP_MAX not defined
#endif

#ifndef _IOFBF
#error _IOFBF not defined
#endif

#ifndef _IOLBF
#error _IOLBF not defined
#endif

#ifndef _IONBF
#error _IONBF not defined
#endif

#ifndef stderr
#error stderr not defined
#endif

#ifndef stdin
#error stdin not defined
#endif

#ifndef stdout
#error stdout not defined
#endif

#include <cstdarg>

#pragma clang diagnostic ignored "-Wformat-zero-length"

int main()
{
    FILE* fp = 0;
    fpos_t fpos = {0};
    size_t s = 0;
    char* cp = 0;
    va_list va;
    static_assert((std::is_same<decltype(remove("")), int>::value), "");
    static_assert((std::is_same<decltype(rename("","")), int>::value), "");
    static_assert((std::is_same<decltype(tmpfile()), FILE*>::value), "");
    static_assert((std::is_same<decltype(tmpnam(cp)), char*>::value), "");
    static_assert((std::is_same<decltype(fclose(fp)), int>::value), "");
    static_assert((std::is_same<decltype(fflush(fp)), int>::value), "");
    static_assert((std::is_same<decltype(fopen("", "")), FILE*>::value), "");
    static_assert((std::is_same<decltype(freopen("", "", fp)), FILE*>::value), "");
    static_assert((std::is_same<decltype(setbuf(fp,cp)), void>::value), "");
    static_assert((std::is_same<decltype(vfprintf(fp,"",va)), int>::value), "");
    static_assert((std::is_same<decltype(fprintf(fp," ")), int>::value), "");
    static_assert((std::is_same<decltype(fscanf(fp,"")), int>::value), "");
    static_assert((std::is_same<decltype(printf("\n")), int>::value), "");
    static_assert((std::is_same<decltype(scanf("\n")), int>::value), "");
    static_assert((std::is_same<decltype(snprintf(cp,0,"p")), int>::value), "");
    static_assert((std::is_same<decltype(sprintf(cp," ")), int>::value), "");
    static_assert((std::is_same<decltype(sscanf("","")), int>::value), "");
    static_assert((std::is_same<decltype(vfprintf(fp,"",va)), int>::value), "");
    static_assert((std::is_same<decltype(vfscanf(fp,"",va)), int>::value), "");
    static_assert((std::is_same<decltype(vprintf(" ",va)), int>::value), "");
    static_assert((std::is_same<decltype(vscanf("",va)), int>::value), "");
    static_assert((std::is_same<decltype(vsnprintf(cp,0," ",va)), int>::value), "");
    static_assert((std::is_same<decltype(vsprintf(cp," ",va)), int>::value), "");
    static_assert((std::is_same<decltype(vsscanf("","",va)), int>::value), "");
    static_assert((std::is_same<decltype(fgetc(fp)), int>::value), "");
    static_assert((std::is_same<decltype(fgets(cp,0,fp)), char*>::value), "");
    static_assert((std::is_same<decltype(fputc(0,fp)), int>::value), "");
    static_assert((std::is_same<decltype(fputs("",fp)), int>::value), "");
    static_assert((std::is_same<decltype(getc(fp)), int>::value), "");
    static_assert((std::is_same<decltype(getchar()), int>::value), "");
    static_assert((std::is_same<decltype(gets(cp)), char*>::value), "");
    static_assert((std::is_same<decltype(putc(0,fp)), int>::value), "");
    static_assert((std::is_same<decltype(putchar(0)), int>::value), "");
    static_assert((std::is_same<decltype(puts("")), int>::value), "");
    static_assert((std::is_same<decltype(ungetc(0,fp)), int>::value), "");
    static_assert((std::is_same<decltype(fread((void*)0,0,0,fp)), size_t>::value), "");
    static_assert((std::is_same<decltype(fwrite((const void*)0,0,0,fp)), size_t>::value), "");
    static_assert((std::is_same<decltype(fgetpos(fp, &fpos)), int>::value), "");
    static_assert((std::is_same<decltype(fseek(fp, 0,0)), int>::value), "");
    static_assert((std::is_same<decltype(fsetpos(fp, &fpos)), int>::value), "");
    static_assert((std::is_same<decltype(ftell(fp)), long>::value), "");
    static_assert((std::is_same<decltype(rewind(fp)), void>::value), "");
    static_assert((std::is_same<decltype(clearerr(fp)), void>::value), "");
    static_assert((std::is_same<decltype(feof(fp)), int>::value), "");
    static_assert((std::is_same<decltype(ferror(fp)), int>::value), "");
    static_assert((std::is_same<decltype(perror("")), void>::value), "");
}
<commit_msg>fix stdio.h test to reflect removal of ::gets in c++14<commit_after>//===----------------------------------------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

// test <stdio.h>

#include <stdio.h>
#include <type_traits>

#ifndef BUFSIZ
#error BUFSIZ not defined
#endif

#ifndef EOF
#error EOF not defined
#endif

#ifndef FILENAME_MAX
#error FILENAME_MAX not defined
#endif

#ifndef FOPEN_MAX
#error FOPEN_MAX not defined
#endif

#ifndef L_tmpnam
#error L_tmpnam not defined
#endif

#ifndef NULL
#error NULL not defined
#endif

#ifndef SEEK_CUR
#error SEEK_CUR not defined
#endif

#ifndef SEEK_END
#error SEEK_END not defined
#endif

#ifndef SEEK_SET
#error SEEK_SET not defined
#endif

#ifndef TMP_MAX
#error TMP_MAX not defined
#endif

#ifndef _IOFBF
#error _IOFBF not defined
#endif

#ifndef _IOLBF
#error _IOLBF not defined
#endif

#ifndef _IONBF
#error _IONBF not defined
#endif

#ifndef stderr
#error stderr not defined
#endif

#ifndef stdin
#error stdin not defined
#endif

#ifndef stdout
#error stdout not defined
#endif

#include <cstdarg>

#pragma clang diagnostic ignored "-Wformat-zero-length"

int main()
{
    FILE* fp = 0;
    fpos_t fpos = {0};
    size_t s = 0;
    char* cp = 0;
    va_list va;
    static_assert((std::is_same<decltype(remove("")), int>::value), "");
    static_assert((std::is_same<decltype(rename("","")), int>::value), "");
    static_assert((std::is_same<decltype(tmpfile()), FILE*>::value), "");
    static_assert((std::is_same<decltype(tmpnam(cp)), char*>::value), "");
    static_assert((std::is_same<decltype(fclose(fp)), int>::value), "");
    static_assert((std::is_same<decltype(fflush(fp)), int>::value), "");
    static_assert((std::is_same<decltype(fopen("", "")), FILE*>::value), "");
    static_assert((std::is_same<decltype(freopen("", "", fp)), FILE*>::value), "");
    static_assert((std::is_same<decltype(setbuf(fp,cp)), void>::value), "");
    static_assert((std::is_same<decltype(vfprintf(fp,"",va)), int>::value), "");
    static_assert((std::is_same<decltype(fprintf(fp," ")), int>::value), "");
    static_assert((std::is_same<decltype(fscanf(fp,"")), int>::value), "");
    static_assert((std::is_same<decltype(printf("\n")), int>::value), "");
    static_assert((std::is_same<decltype(scanf("\n")), int>::value), "");
    static_assert((std::is_same<decltype(snprintf(cp,0,"p")), int>::value), "");
    static_assert((std::is_same<decltype(sprintf(cp," ")), int>::value), "");
    static_assert((std::is_same<decltype(sscanf("","")), int>::value), "");
    static_assert((std::is_same<decltype(vfprintf(fp,"",va)), int>::value), "");
    static_assert((std::is_same<decltype(vfscanf(fp,"",va)), int>::value), "");
    static_assert((std::is_same<decltype(vprintf(" ",va)), int>::value), "");
    static_assert((std::is_same<decltype(vscanf("",va)), int>::value), "");
    static_assert((std::is_same<decltype(vsnprintf(cp,0," ",va)), int>::value), "");
    static_assert((std::is_same<decltype(vsprintf(cp," ",va)), int>::value), "");
    static_assert((std::is_same<decltype(vsscanf("","",va)), int>::value), "");
    static_assert((std::is_same<decltype(fgetc(fp)), int>::value), "");
    static_assert((std::is_same<decltype(fgets(cp,0,fp)), char*>::value), "");
    static_assert((std::is_same<decltype(fputc(0,fp)), int>::value), "");
    static_assert((std::is_same<decltype(fputs("",fp)), int>::value), "");
    static_assert((std::is_same<decltype(getc(fp)), int>::value), "");
    static_assert((std::is_same<decltype(getchar()), int>::value), "");
#if _LIBCPP_STD_VER < 14
    static_assert((std::is_same<decltype(gets(cp)), char*>::value), "");
#endif
    static_assert((std::is_same<decltype(putc(0,fp)), int>::value), "");
    static_assert((std::is_same<decltype(putchar(0)), int>::value), "");
    static_assert((std::is_same<decltype(puts("")), int>::value), "");
    static_assert((std::is_same<decltype(ungetc(0,fp)), int>::value), "");
    static_assert((std::is_same<decltype(fread((void*)0,0,0,fp)), size_t>::value), "");
    static_assert((std::is_same<decltype(fwrite((const void*)0,0,0,fp)), size_t>::value), "");
    static_assert((std::is_same<decltype(fgetpos(fp, &fpos)), int>::value), "");
    static_assert((std::is_same<decltype(fseek(fp, 0,0)), int>::value), "");
    static_assert((std::is_same<decltype(fsetpos(fp, &fpos)), int>::value), "");
    static_assert((std::is_same<decltype(ftell(fp)), long>::value), "");
    static_assert((std::is_same<decltype(rewind(fp)), void>::value), "");
    static_assert((std::is_same<decltype(clearerr(fp)), void>::value), "");
    static_assert((std::is_same<decltype(feof(fp)), int>::value), "");
    static_assert((std::is_same<decltype(ferror(fp)), int>::value), "");
    static_assert((std::is_same<decltype(perror("")), void>::value), "");
}
<|endoftext|>