<commit_before>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2012 Artem Pavlenko
 *
 * This library 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 2.1 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

#ifndef MAPNIK_TRANSFORM_PROCESSOR_HPP
#define MAPNIK_TRANSFORM_PROCESSOR_HPP

// mapnik
#include <mapnik/config.hpp>
#include <mapnik/debug.hpp>
#include <mapnik/feature.hpp>
#include <mapnik/value.hpp>
#include <mapnik/transform_expression.hpp>
#include <mapnik/expression_evaluator.hpp>

// boost
#include <boost/foreach.hpp>

// agg
#include <agg_trans_affine.h>

namespace mapnik {

template <typename Container> struct expression_attributes;

template <typename T>
struct transform_processor
{
    typedef T feature_type;
    typedef agg::trans_affine transform_type;

    template <typename Container>
    struct attribute_collector : boost::static_visitor<void>
    {
        expression_attributes<Container> collect_;

        attribute_collector(Container& names)
            : collect_(names) {}

        void operator() (identity_node const& node) const
        {
            boost::ignore_unused_variable_warning(node);
        }

        void operator() (matrix_node const& node) const
        {
            boost::apply_visitor(collect_, node.a_);
            boost::apply_visitor(collect_, node.b_);
            boost::apply_visitor(collect_, node.c_);
            boost::apply_visitor(collect_, node.d_);
            boost::apply_visitor(collect_, node.e_);
            boost::apply_visitor(collect_, node.f_);
        }

        void operator() (translate_node const& node) const
        {
            boost::apply_visitor(collect_, node.tx_);
            boost::apply_visitor(collect_, node.ty_);
        }

        void operator() (scale_node const& node) const
        {
            boost::apply_visitor(collect_, node.sx_);
            boost::apply_visitor(collect_, node.sy_);
        }

        void operator() (rotate_node const& node) const
        {
            boost::apply_visitor(collect_, node.angle_);
            boost::apply_visitor(collect_, node.cx_);
            boost::apply_visitor(collect_, node.cy_);
        }

        void operator() (skewX_node const& node) const
        {
            boost::apply_visitor(collect_, node.angle_);
        }

        void operator() (skewY_node const& node) const
        {
            boost::apply_visitor(collect_, node.angle_);
        }
    };

    struct node_evaluator : boost::static_visitor<void>
    {
        node_evaluator(transform_type& tr, feature_type const& feat)
            : transform_(tr), feature_(feat) {}

        void operator() (identity_node const& node)
        {
            boost::ignore_unused_variable_warning(node);
        }

        void operator() (matrix_node const& node)
        {
            double a = eval(node.a_);
            double b = eval(node.b_);
            double c = eval(node.c_);
            double d = eval(node.d_);
            double e = eval(node.e_);
            double f = eval(node.f_);
            transform_.multiply(agg::trans_affine(a, b, c, d, e, f));
        }

        void operator() (translate_node const& node)
        {
            double tx = eval(node.tx_);
            double ty = eval(node.ty_, 0.0);
            transform_.translate(tx, ty);
        }

        void operator() (scale_node const& node)
        {
            double sx = eval(node.sx_);
            double sy = eval(node.sy_, sx);
            transform_.scale(sx, sy);
        }

        void operator() (rotate_node const& node)
        {
            double angle = deg2rad(eval(node.angle_));
            double cx = eval(node.cx_, 0.0);
            double cy = eval(node.cy_, 0.0);
            transform_.translate(-cx, -cy);
            transform_.rotate(angle);
            transform_.translate(cx, cy);
        }

        void operator() (skewX_node const& node)
        {
            double angle = deg2rad(eval(node.angle_));
            transform_.multiply(agg::trans_affine_skewing(angle, 0.0));
        }

        void operator() (skewY_node const& node)
        {
            double angle = deg2rad(eval(node.angle_));
            transform_.multiply(agg::trans_affine_skewing(0.0, angle));
        }

    private:

        static double deg2rad(double d)
        {
            return d * M_PI / 180.0;
        }

        double eval(expr_node const& x) const
        {
            mapnik::evaluate<feature_type, value_type> e(feature_);
            return boost::apply_visitor(e, x).to_double();
        }

        double eval(expr_node const& x, double def) const
        {
            return is_null(x) ? def : eval(x);
        }

        transform_type& transform_;
        feature_type const& feature_;
    };

    template <typename Container>
    static void collect_attributes(Container& names,
                                   transform_list const& list)
    {
        attribute_collector<Container> collect(names);

        BOOST_FOREACH (transform_node const& node, list)
        {
            boost::apply_visitor(collect, *node);
        }
    }

    static void evaluate(transform_type& tr, feature_type const& feat,
                         transform_list const& list)
    {
        node_evaluator eval(tr, feat);

        #ifdef MAPNIK_LOG
        MAPNIK_LOG_DEBUG(transform) << "transform: begin with " << to_string(matrix_node(tr));
        #endif

        BOOST_REVERSE_FOREACH (transform_node const& node, list)
        {
            boost::apply_visitor(eval, *node);
            #ifdef MAPNIK_LOG
            MAPNIK_LOG_DEBUG(transform) << "transform: apply " << to_string(*node);
            MAPNIK_LOG_DEBUG(transform) << "transform: result " << to_string(matrix_node(tr));
            #endif
        }

        #ifdef MAPNIK_LOG
        MAPNIK_LOG_DEBUG(transform) << "transform: end";
        #endif
    }

    static std::string to_string(transform_node const& node)
    {
        return to_expression_string(node);
    }

    static std::string to_string(transform_list const& list)
    {
        return to_expression_string(list);
    }
};

typedef mapnik::transform_processor<Feature> transform_processor_type;

} // namespace mapnik

#endif // MAPNIK_TRANSFORM_PROCESSOR_HPP
<commit_msg>only include debug.hpp if needed<commit_after>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2012 Artem Pavlenko
 *
 * This library 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 2.1 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

#ifndef MAPNIK_TRANSFORM_PROCESSOR_HPP
#define MAPNIK_TRANSFORM_PROCESSOR_HPP

// mapnik
#include <mapnik/config.hpp>
#ifdef MAPNIK_LOG
#include <mapnik/debug.hpp>
#endif
#include <mapnik/feature.hpp>
#include <mapnik/value.hpp>
#include <mapnik/transform_expression.hpp>
#include <mapnik/expression_evaluator.hpp>

// boost
#include <boost/foreach.hpp>

// agg
#include <agg_trans_affine.h>

namespace mapnik {

template <typename Container> struct expression_attributes;

template <typename T>
struct transform_processor
{
    typedef T feature_type;
    typedef agg::trans_affine transform_type;

    template <typename Container>
    struct attribute_collector : boost::static_visitor<void>
    {
        expression_attributes<Container> collect_;

        attribute_collector(Container& names)
            : collect_(names) {}

        void operator() (identity_node const& node) const
        {
            boost::ignore_unused_variable_warning(node);
        }

        void operator() (matrix_node const& node) const
        {
            boost::apply_visitor(collect_, node.a_);
            boost::apply_visitor(collect_, node.b_);
            boost::apply_visitor(collect_, node.c_);
            boost::apply_visitor(collect_, node.d_);
            boost::apply_visitor(collect_, node.e_);
            boost::apply_visitor(collect_, node.f_);
        }

        void operator() (translate_node const& node) const
        {
            boost::apply_visitor(collect_, node.tx_);
            boost::apply_visitor(collect_, node.ty_);
        }

        void operator() (scale_node const& node) const
        {
            boost::apply_visitor(collect_, node.sx_);
            boost::apply_visitor(collect_, node.sy_);
        }

        void operator() (rotate_node const& node) const
        {
            boost::apply_visitor(collect_, node.angle_);
            boost::apply_visitor(collect_, node.cx_);
            boost::apply_visitor(collect_, node.cy_);
        }

        void operator() (skewX_node const& node) const
        {
            boost::apply_visitor(collect_, node.angle_);
        }

        void operator() (skewY_node const& node) const
        {
            boost::apply_visitor(collect_, node.angle_);
        }
    };

    struct node_evaluator : boost::static_visitor<void>
    {
        node_evaluator(transform_type& tr, feature_type const& feat)
            : transform_(tr), feature_(feat) {}

        void operator() (identity_node const& node)
        {
            boost::ignore_unused_variable_warning(node);
        }

        void operator() (matrix_node const& node)
        {
            double a = eval(node.a_);
            double b = eval(node.b_);
            double c = eval(node.c_);
            double d = eval(node.d_);
            double e = eval(node.e_);
            double f = eval(node.f_);
            transform_.multiply(agg::trans_affine(a, b, c, d, e, f));
        }

        void operator() (translate_node const& node)
        {
            double tx = eval(node.tx_);
            double ty = eval(node.ty_, 0.0);
            transform_.translate(tx, ty);
        }

        void operator() (scale_node const& node)
        {
            double sx = eval(node.sx_);
            double sy = eval(node.sy_, sx);
            transform_.scale(sx, sy);
        }

        void operator() (rotate_node const& node)
        {
            double angle = deg2rad(eval(node.angle_));
            double cx = eval(node.cx_, 0.0);
            double cy = eval(node.cy_, 0.0);
            transform_.translate(-cx, -cy);
            transform_.rotate(angle);
            transform_.translate(cx, cy);
        }

        void operator() (skewX_node const& node)
        {
            double angle = deg2rad(eval(node.angle_));
            transform_.multiply(agg::trans_affine_skewing(angle, 0.0));
        }

        void operator() (skewY_node const& node)
        {
            double angle = deg2rad(eval(node.angle_));
            transform_.multiply(agg::trans_affine_skewing(0.0, angle));
        }

    private:

        static double deg2rad(double d)
        {
            return d * M_PI / 180.0;
        }

        double eval(expr_node const& x) const
        {
            mapnik::evaluate<feature_type, value_type> e(feature_);
            return boost::apply_visitor(e, x).to_double();
        }

        double eval(expr_node const& x, double def) const
        {
            return is_null(x) ? def : eval(x);
        }

        transform_type& transform_;
        feature_type const& feature_;
    };

    template <typename Container>
    static void collect_attributes(Container& names,
                                   transform_list const& list)
    {
        attribute_collector<Container> collect(names);

        BOOST_FOREACH (transform_node const& node, list)
        {
            boost::apply_visitor(collect, *node);
        }
    }

    static void evaluate(transform_type& tr, feature_type const& feat,
                         transform_list const& list)
    {
        node_evaluator eval(tr, feat);

        #ifdef MAPNIK_LOG
        MAPNIK_LOG_DEBUG(transform) << "transform: begin with " << to_string(matrix_node(tr));
        #endif

        BOOST_REVERSE_FOREACH (transform_node const& node, list)
        {
            boost::apply_visitor(eval, *node);
            #ifdef MAPNIK_LOG
            MAPNIK_LOG_DEBUG(transform) << "transform: apply " << to_string(*node);
            MAPNIK_LOG_DEBUG(transform) << "transform: result " << to_string(matrix_node(tr));
            #endif
        }

        #ifdef MAPNIK_LOG
        MAPNIK_LOG_DEBUG(transform) << "transform: end";
        #endif
    }

    static std::string to_string(transform_node const& node)
    {
        return to_expression_string(node);
    }

    static std::string to_string(transform_list const& list)
    {
        return to_expression_string(list);
    }
};

typedef mapnik::transform_processor<feature_impl> transform_processor_type;

} // namespace mapnik

#endif // MAPNIK_TRANSFORM_PROCESSOR_HPP
<|endoftext|>


<commit_before>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2015 Artem Pavlenko
 *
 * This library 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 2.1 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

#ifndef MAPNIK_TRANSFORM_PROCESSOR_HPP
#define MAPNIK_TRANSFORM_PROCESSOR_HPP

// mapnik
#include <mapnik/config.hpp>
#include <mapnik/value.hpp>
#include <mapnik/transform_expression.hpp>
#include <mapnik/expression_evaluator.hpp>
#include <mapnik/util/variant.hpp>
// agg
#include <agg_trans_affine.h>

namespace mapnik {

class feature_impl;

template <typename Container> struct expression_attributes;

template <typename T, typename T1>
struct transform_processor
{
    using feature_type = T;
    using variable_type = T1;
    using transform_type = agg::trans_affine;

    template <typename Container>
    struct attribute_collector
    {
        expression_attributes<Container> collect_;

        attribute_collector(Container& names)
            : collect_(names) {}

        void operator() (identity_node const&) const
        {
        }

        void operator() (matrix_node const& node) const
        {
            util::apply_visitor(collect_, node.a_);
            util::apply_visitor(collect_, node.b_);
            util::apply_visitor(collect_, node.c_);
            util::apply_visitor(collect_, node.d_);
            util::apply_visitor(collect_, node.e_);
            util::apply_visitor(collect_, node.f_);
        }

        void operator() (translate_node const& node) const
        {
            util::apply_visitor(collect_, node.tx_);
            util::apply_visitor(collect_, node.ty_);
        }

        void operator() (scale_node const& node) const
        {
            util::apply_visitor(collect_, node.sx_);
            util::apply_visitor(collect_, node.sy_);
        }

        void operator() (rotate_node const& node) const
        {
            util::apply_visitor(collect_, node.angle_);
            util::apply_visitor(collect_, node.cx_);
            util::apply_visitor(collect_, node.cy_);
        }

        void operator() (skewX_node const& node) const
        {
            util::apply_visitor(collect_, node.angle_);
        }

        void operator() (skewY_node const& node) const
        {
            util::apply_visitor(collect_, node.angle_);
        }
    };

    struct node_evaluator
    {
        node_evaluator(transform_type& tr,
                       feature_type const& feat,
                       variable_type const& v,
                       double scale_factor)
            : transform_(tr),
              feature_(feat),
              vars_(v),
              scale_factor_(scale_factor) {}

        void operator() (identity_node const&)
        {
        }

        void operator() (matrix_node const& node)
        {
            double a = eval(node.a_); // scale x;
            double b = eval(node.b_);
            double c = eval(node.c_);
            double d = eval(node.d_); // scale y;
            double e = eval(node.e_) * scale_factor_; // translate x
            double f = eval(node.f_) * scale_factor_; // translate y
            transform_.multiply(agg::trans_affine(a, b, c, d, e, f));
        }

        void operator() (translate_node const& node)
        {
            double tx = eval(node.tx_) * scale_factor_;
            double ty = eval(node.ty_, 0.0) * scale_factor_;
            transform_.translate(tx, ty);
        }

        void operator() (scale_node const& node)
        {
            double sx = eval(node.sx_);
            double sy = eval(node.sy_, sx);
            transform_.scale(sx, sy);
        }

        void operator() (rotate_node const& node)
        {
            double angle = deg2rad(eval(node.angle_));
            double cx = eval(node.cx_, 0.0);
            double cy = eval(node.cy_, 0.0);
            transform_.translate(-cx, -cy);
            transform_.rotate(angle);
            transform_.translate(cx, cy);
        }

        void operator() (skewX_node const& node)
        {
            double angle = deg2rad(eval(node.angle_));
            transform_.multiply(agg::trans_affine_skewing(angle, 0.0));
        }

        void operator() (skewY_node const& node)
        {
            double angle = deg2rad(eval(node.angle_));
            transform_.multiply(agg::trans_affine_skewing(0.0, angle));
        }

    private:

        static double deg2rad(double d)
        {
            return d * M_PI / 180.0;
        }

        double eval(expr_node const& x) const
        {
            mapnik::evaluate<feature_type, value_type, variable_type> e(feature_,vars_);
            return util::apply_visitor(e, x).to_double();
        }

        double eval(expr_node const& x, double def) const
        {
            return detail::is_null_node(x) ? def : eval(x);
        }

        transform_type& transform_;
        feature_type const& feature_;
        variable_type const& vars_;
        double scale_factor_;
    };

    template <typename Container>
    static void collect_attributes(Container& names,
                                   transform_list const& list)
    {
        attribute_collector<Container> collect(names);

        for (transform_node const& node : list)
        {
            util::apply_visitor(collect, *node);
        }
    }

    static void evaluate(transform_type& tr,
                         feature_type const& feat,
                         variable_type const& vars,
                         transform_list const& list,
                         double scale_factor)
    {
        node_evaluator eval(tr, feat, vars, scale_factor);

        transform_list::const_reverse_iterator rit;
        for (rit = list.rbegin(); rit!= list.rend(); ++rit)
        {
            util::apply_visitor(eval, *(*rit));
        }
    }

    static std::string to_string(transform_node const& node)
    {
        return to_expression_string(node);
    }

    static std::string to_string(transform_list const& list)
    {
        return to_expression_string(list);
    }
};

using transform_processor_type = mapnik::transform_processor<feature_impl,attributes>;

} // namespace mapnik

#endif // MAPNIK_TRANSFORM_PROCESSOR_HPP
<commit_msg>skewX/skewY - add input validation ref https://github.com/mapbox/mapbox-studio/issues/1409<commit_after>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2015 Artem Pavlenko
 *
 * This library 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 2.1 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

#ifndef MAPNIK_TRANSFORM_PROCESSOR_HPP
#define MAPNIK_TRANSFORM_PROCESSOR_HPP

// mapnik
#include <mapnik/config.hpp>
#include <mapnik/value.hpp>
#include <mapnik/transform_expression.hpp>
#include <mapnik/expression_evaluator.hpp>
#include <mapnik/util/variant.hpp>
// agg
#include <agg_trans_affine.h>
// boost
#include <boost/algorithm/clamp.hpp>
// stl
#include <cmath>

namespace mapnik {

class feature_impl;

template <typename Container> struct expression_attributes;

template <typename T, typename T1>
struct transform_processor
{
    using feature_type = T;
    using variable_type = T1;
    using transform_type = agg::trans_affine;

    template <typename Container>
    struct attribute_collector
    {
        expression_attributes<Container> collect_;

        attribute_collector(Container& names)
            : collect_(names) {}

        void operator() (identity_node const&) const
        {
        }

        void operator() (matrix_node const& node) const
        {
            util::apply_visitor(collect_, node.a_);
            util::apply_visitor(collect_, node.b_);
            util::apply_visitor(collect_, node.c_);
            util::apply_visitor(collect_, node.d_);
            util::apply_visitor(collect_, node.e_);
            util::apply_visitor(collect_, node.f_);
        }

        void operator() (translate_node const& node) const
        {
            util::apply_visitor(collect_, node.tx_);
            util::apply_visitor(collect_, node.ty_);
        }

        void operator() (scale_node const& node) const
        {
            util::apply_visitor(collect_, node.sx_);
            util::apply_visitor(collect_, node.sy_);
        }

        void operator() (rotate_node const& node) const
        {
            util::apply_visitor(collect_, node.angle_);
            util::apply_visitor(collect_, node.cx_);
            util::apply_visitor(collect_, node.cy_);
        }

        void operator() (skewX_node const& node) const
        {
            util::apply_visitor(collect_, node.angle_);
        }

        void operator() (skewY_node const& node) const
        {
            util::apply_visitor(collect_, node.angle_);
        }
    };

    struct node_evaluator
    {
        node_evaluator(transform_type& tr,
                       feature_type const& feat,
                       variable_type const& v,
                       double scale_factor)
            : transform_(tr),
              feature_(feat),
              vars_(v),
              scale_factor_(scale_factor) {}

        void operator() (identity_node const&)
        {
        }

        void operator() (matrix_node const& node)
        {
            double a = eval(node.a_); // scale x;
            double b = eval(node.b_);
            double c = eval(node.c_);
            double d = eval(node.d_); // scale y;
            double e = eval(node.e_) * scale_factor_; // translate x
            double f = eval(node.f_) * scale_factor_; // translate y
            transform_.multiply(agg::trans_affine(a, b, c, d, e, f));
        }

        void operator() (translate_node const& node)
        {
            double tx = eval(node.tx_) * scale_factor_;
            double ty = eval(node.ty_, 0.0) * scale_factor_;
            transform_.translate(tx, ty);
        }

        void operator() (scale_node const& node)
        {
            double sx = eval(node.sx_);
            double sy = eval(node.sy_, sx);
            transform_.scale(sx, sy);
        }

        void operator() (rotate_node const& node)
        {
            double angle = deg2rad(eval(node.angle_));
            double cx = eval(node.cx_, 0.0);
            double cy = eval(node.cy_, 0.0);
            transform_.translate(-cx, -cy);
            transform_.rotate(angle);
            transform_.translate(cx, cy);
        }

        void operator() (skewX_node const& node)
        {
            auto degrees = std::fmod(eval(node.angle_),90.0);
            auto angle = deg2rad(boost::algorithm::clamp(degrees, -89.0, 89.0));
            transform_.multiply(agg::trans_affine_skewing(angle, 0.0));
        }

        void operator() (skewY_node const& node)
        {
            auto degrees = std::fmod(eval(node.angle_),90.0);
            auto angle = deg2rad(boost::algorithm::clamp(degrees, -89.0, 89.0));
            transform_.multiply(agg::trans_affine_skewing(0.0, angle));
        }

    private:

        static double deg2rad(double d)
        {
            return d * M_PI / 180.0;
        }

        double eval(expr_node const& x) const
        {
            mapnik::evaluate<feature_type, value_type, variable_type> e(feature_,vars_);
            return util::apply_visitor(e, x).to_double();
        }

        double eval(expr_node const& x, double def) const
        {
            return detail::is_null_node(x) ? def : eval(x);
        }

        transform_type& transform_;
        feature_type const& feature_;
        variable_type const& vars_;
        double scale_factor_;
    };

    template <typename Container>
    static void collect_attributes(Container& names,
                                   transform_list const& list)
    {
        attribute_collector<Container> collect(names);

        for (transform_node const& node : list)
        {
            util::apply_visitor(collect, *node);
        }
    }

    static void evaluate(transform_type& tr,
                         feature_type const& feat,
                         variable_type const& vars,
                         transform_list const& list,
                         double scale_factor)
    {
        node_evaluator eval(tr, feat, vars, scale_factor);

        transform_list::const_reverse_iterator rit;
        for (rit = list.rbegin(); rit!= list.rend(); ++rit)
        {
            util::apply_visitor(eval, *(*rit));
        }
    }

    static std::string to_string(transform_node const& node)
    {
        return to_expression_string(node);
    }

    static std::string to_string(transform_list const& list)
    {
        return to_expression_string(list);
    }
};

using transform_processor_type = mapnik::transform_processor<feature_impl,attributes>;

} // namespace mapnik

#endif // MAPNIK_TRANSFORM_PROCESSOR_HPP
<|endoftext|>


<commit_before>// call.cpp
// Copyright (c) 2014 - 2017, zhiayang@gmail.com
// Licensed under the Apache License Version 2.0.

#include "pts.h"
#include "ast.h"
#include "errors.h"
#include "typecheck.h"

#include "polymorph.h"
#include "resolver.h"

#include "ir/type.h"

#include <set>

namespace sst {
namespace resolver
{
	TCResult resolveFunctionCallFromCandidates(TypecheckState* fs, const std::vector<Defn*>& cands, std::vector<FnCallArgument>* args,
		const PolyArgMapping_t& gmaps, bool allowImplicitSelf)
	{
		auto cds = util::map(cands, [&args](auto c) -> std::pair<Defn*, std::vector<FnCallArgument>> { return { c, *args }; });
		auto [ ret, new_args ] = resolver::internal::resolveFunctionCallFromCandidates(fs, fs->loc(), cds, gmaps, allowImplicitSelf, nullptr);

		*args = new_args;
		return ret;
	}

	TCResult resolveFunctionCall(TypecheckState* fs, const std::string& name, std::vector<FnCallArgument>* arguments, const PolyArgMapping_t& gmaps,
		bool travUp, fir::Type* return_infer)
	{
		StateTree* tree = fs->stree;

		//* the purpose of this 'didVar' flag (because I was fucking confused reading this)
		//* is so we only consider the innermost (ie. most local) variable, because variables don't participate in overloading.
		//! ACHTUNG !
		// TODO: do we even need this didVar nonsense? variables don't overload yes, but we can't even define more than one
		// TODO: variable in a scope with the same name. if we find something with a matching name we quit immediately, so there
		// TODO: shouldn't be a point in having 'didVar'!!
		// TODO: - zhiayang, 28/10/18

		//? I can't find any information about this behaviour in languages other than C++, because we need to have a certain set of
		//? features for it to manifest -- 1. user-defined, explicit namespaces; 2. function overloading.

		//* how it works in C++, and for now also in Flax, is that once we match *any* names in the current scope, we stop searching upwards
		//* -- even if it means we will throw an error because of mismatched arguments or whatever.
		// bool didVar = false;

		bool didGeneric = false;

		auto errs = SimpleError::make(Location(), "");
		std::vector<std::tuple<Defn*, std::vector<FnCallArgument>, poly::Solution_t>> fns;
		while(tree)
		{
			// unify the handling of generic and non-generic stuff.
			// if we provided mappings, don't bother searching normal functions.
			if(gmaps.empty())
			{
				auto defs = tree->getDefinitionsWithName(name);
				for(auto d : defs)
					fns.push_back({ d, *arguments, poly::Solution_t() });
			}

			if(auto gdefs = tree->getUnresolvedGenericDefnsWithName(name); gdefs.size() > 0)
			{
				didGeneric = true;
				auto argcopy = *arguments;

				auto pots = poly::findPolymorphReferences(fs, name, gdefs, gmaps, /* return_infer: */ return_infer,
					/* type_infer: */ 0, /* isFnCall: */ true, &argcopy);

				for(const auto& pot : pots)
				{
					if(!pot.first.isDefn())
					{
						iceAssert(pot.first.isError());
						errs->append(pot.first.error());
					}
					else
					{
						auto def = pot.first.defn();
						if(def->type->containsPlaceholders())
							error("wtf??? '%s'", def->type);

						// make sure we didn't already find this in the non-generic search
						//? (can happen when we recursively call a generic function!)
						if(auto it = std::find_if(fns.begin(), fns.end(), [def](const auto& tup) -> bool {
							return std::get<0>(tup) == def;
						}); it != fns.end())
						{
							continue;
						}

						auto sln = pot.second;
						// ! ACHTUNG !
						// insert a hefty penalty for using a polymorphic function!
						// this doesn't disallow polymorphic functions from participating in
						// overloading, but this makes our resolver prefer non-generic functions.
						sln.distance += 10;

						fns.push_back({ def, argcopy, sln });
					}
				}
			}

			if(travUp && fns.empty())
				tree = tree->parent;

			else
				break;
		}

		if(fns.empty())
		{
			if(!didGeneric)
			{
				errs = SimpleError::make(fs->loc(), "no such function named '%s'", name);
			}

			return TCResult(errs);
		}

		std::vector<std::pair<sst::Defn*, std::vector<FnCallArgument>>> cands;
		for(const auto& [ def, args, soln ] : fns)
		{
			auto ts = args; // copy it.

			if(dcast(FunctionDecl, def) || dcast(TypeDefn, def))
			{
				cands.push_back({ def, ts });
			}
			else if(dcast(VarDefn, def) && def->type->isFunctionType() /* && !didVar */)
			{
				cands.push_back({ def, ts });
				// didVar = true;
			}
			else
			{
				return TCResult(
					SimpleError::make(fs->loc(), "'%s' cannot be called as a function; it was defined with type '%s' in the current scope",
						name, def->type)->append(SimpleError::make(def->loc, "Previously defined here:"))
				);
			}
		}

		auto [ res, new_args ] = resolver::internal::resolveFunctionCallFromCandidates(fs, fs->loc(), cands, gmaps, travUp, return_infer);
		if(res.isDefn())
		{
			*arguments = new_args;

			return res;
		}
		else
		{
			return TCResult(errs->append(res.error()));
		}
	}

	TCResult resolveConstructorCall(TypecheckState* fs, TypeDefn* typedf, const std::vector<FnCallArgument>& arguments, const PolyArgMapping_t& pams)
	{
		//! ACHTUNG: DO NOT REARRANGE !
		//* NOTE: ClassDefn inherits from StructDefn *

		if(auto cls = dcast(ClassDefn, typedf))
		{
			// class initialisers must be called with named arguments only.
			for(const auto& arg : arguments)
			{
				if(arg.name.empty())
				{
					return TCResult(SimpleError::make(arg.loc, "arguments to class initialisers (for class '%s' here) must be named", cls->id.name));
				}
			}

			auto copy = arguments;

			//! SELF HANDLING (INSERTION) (CONSTRUCTOR)
			copy.push_back(FnCallArgument::make(cls->loc, "self", cls->type->getMutablePointerTo()));
			auto copy1 = copy;

			auto cand = resolveFunctionCallFromCandidates(fs, util::map(cls->initialisers, [](auto e) -> auto {
				return dcast(sst::Defn, e);
			}), &copy, pams, true);

			// TODO: support re-eval of constructor args!
			// TODO: support re-eval of constructor args!
			// TODO: support re-eval of constructor args!

			if(copy1 != copy)
				error(fs->loc(), "args changed for constructor call -- fixme!!!");

			if(cand.isError())
			{
				cand.error()->prepend(SimpleError::make(fs->loc(), "failed to find matching initialiser for class '%s':", cls->id.name));
				return TCResult(cand.error());
			}

			return TCResult(cand);
		}
		else if(auto str = dcast(StructDefn, typedf))
		{
			std::vector<std::string> fieldNames;

			for(auto f : str->fields)
				fieldNames.push_back(f->id.name);

			auto [ seen, err ] = resolver::verifyStructConstructorArguments(fs->loc(), str->id.name, fieldNames, arguments);

			if(err != nullptr)
			{
				return TCResult(err);
			}
			else
			{
				std::vector<FnParam> target = util::filterMap(str->fields, [&seen](sst::StructFieldDefn* f) -> bool {
					return seen.find(f->id.name) != seen.end();
				}, [](sst::StructFieldDefn* f) -> FnParam {
					return FnParam(f->loc, f->id.name, f->type);
				});

				ErrorMsg* _err = 0;
				auto args = resolver::misc::canonicaliseCallArguments(fs->loc(), target, arguments, &_err);
				if(_err != 0) return TCResult(_err);

				auto [ soln, err ] = poly::solveTypeList(util::map(target, [](const FnParam& f) -> fir::LocatedType {
					return fir::LocatedType(f.type, f.loc);
				}), args, poly::Solution_t(), /* isFnCall: */ true);

				// in actual fact we just return the thing here. sigh.
				if(err != nullptr)  return TCResult(err);
				else                return TCResult(str);
			}
		}
		else if(auto uvd = dcast(sst::UnionVariantDefn, typedf))
		{
			// TODO: support re-eval of constructor args!
			// TODO: support re-eval of constructor args!
			// TODO: support re-eval of constructor args!

			auto copy = arguments;

			auto ret = resolver::resolveAndInstantiatePolymorphicUnion(fs, uvd, &copy, /* type_infer: */ nullptr, /* isFnCall: */ true);

			if(copy != arguments)
				error(fs->loc(), "args changed for constructor call -- fixme!!!");

			return ret;
		}
		else
		{
			return TCResult(
				SimpleError::make(fs->loc(), "unsupported constructor call on type '%s'", typedf->id.name)
			    ->append(SimpleError::make(typedf->loc, "type was defined here:"))
			);
		}
	}
	}

	fir::Type* TypecheckState::checkIsBuiltinConstructorCall(const std::string& name, const std::vector<FnCallArgument>& arguments)
	{
		if(auto type = fir::Type::fromBuiltin(name))
		{
			for(const auto& a : arguments)
			{
				if(!a.name.empty())
					error(a.loc, "builtin type initialisers do not accept named arguments");
			}

			// all builtin types can be zero-initialised.
			if(arguments.empty())
			{
				return type;
			}
			else if(arguments.size() == 1)
			{
				if(int d = getCastDistance(arguments[0].value->type, type); d >= 0 || (type->isStringType() && arguments[0].value->type->isCharSliceType()))
				{
					return type;
				}
				else
				{
					error(arguments[0].loc, "type mismatch in initialiser call to builtin type '%s', found type '%s' instead", type,
						arguments[0].value->type);
				}
			}
			else
			{
				if(type->isStringType())
				{
					// either from a slice, or from a ptr + len
					if(arguments.size() == 1)
					{
						if(!arguments[0].value->type->isCharSliceType())
						{
							error(arguments[0].loc, "single argument to string initialiser must be a slice of char, aka '%s', found '%s' instead",
								fir::Type::getCharSlice(false), arguments[0].value->type);
						}

						return type;
					}
					else if(arguments.size() == 2)
					{
						if(auto t1 = arguments[0].value->type; (t1 != fir::Type::getInt8Ptr() && t1 != fir::Type::getMutInt8Ptr()))
						{
							error(arguments[0].loc, "first argument to two-arg string initialiser (data pointer) must be '%s' or '%s', found '%s' instead",
								fir::Type::getInt8Ptr(), fir::Type::getMutInt8Ptr(), t1);
						}
						else if(auto t2 = arguments[1].value->type; fir::getCastDistance(t2, fir::Type::getInt64()) < 0)
						{
							error(arguments[0].loc, "second argument to two-arg string initialiser (length) must be '%s', found '%s' instead",
								(fir::Type*) fir::Type::getInt64(), t2);
						}
						else
						{
							return type;
						}
					}
					else
					{
						error(arguments[2].loc, "string initialiser only takes 1 (from slice) or 2 (from pointer+length) arguments, found '%ld' instead",
							arguments.size());
					}
				}
				else
				{
					error(arguments[1].loc, "builtin type '%s' cannot be initialised with more than 1 value", type);
				}
			}
		}

		return 0;
	}
}

<commit_msg>fuck this thing<commit_after>// call.cpp
// Copyright (c) 2014 - 2017, zhiayang@gmail.com
// Licensed under the Apache License Version 2.0.

#include "pts.h"
#include "ast.h"
#include "errors.h"
#include "typecheck.h"

#include "polymorph.h"
#include "resolver.h"

#include "ir/type.h"

#include <set>

namespace sst {
namespace resolver
{
	TCResult resolveFunctionCallFromCandidates(TypecheckState* fs, const std::vector<Defn*>& cands, std::vector<FnCallArgument>* args,
		const PolyArgMapping_t& gmaps, bool allowImplicitSelf)
	{
		auto cds = util::map(cands, [&args](auto c) -> std::pair<Defn*, std::vector<FnCallArgument>> { return { c, *args }; });
		auto [ ret, new_args ] = resolver::internal::resolveFunctionCallFromCandidates(fs, fs->loc(), cds, gmaps, allowImplicitSelf, nullptr);

		*args = new_args;
		return ret;
	}

	TCResult resolveFunctionCall(TypecheckState* fs, const std::string& name, std::vector<FnCallArgument>* arguments, const PolyArgMapping_t& gmaps,
		bool travUp, fir::Type* return_infer)
	{
		StateTree* tree = fs->stree;

		//* the purpose of this 'didVar' flag (because I was fucking confused reading this)
		//* is so we only consider the innermost (ie. most local) variable, because variables don't participate in overloading.
		//! ACHTUNG !
		// TODO: do we even need this didVar nonsense? variables don't overload yes, but we can't even define more than one
		// TODO: variable in a scope with the same name. if we find something with a matching name we quit immediately, so there
		// TODO: shouldn't be a point in having 'didVar'!!
		// TODO: - zhiayang, 28/10/18

		//? I can't find any information about this behaviour in languages other than C++, because we need to have a certain set of
		//? features for it to manifest -- 1. user-defined, explicit namespaces; 2. function overloading.

		//* how it works in C++, and for now also in Flax, is that once we match *any* names in the current scope, we stop searching upwards
		//* -- even if it means we will throw an error because of mismatched arguments or whatever.
		// bool didVar = false;

		bool didGeneric = false;

		auto errs = SimpleError::make(Location(), "");
		std::vector<std::tuple<Defn*, std::vector<FnCallArgument>, poly::Solution_t>> fns;
		while(tree)
		{
			// unify the handling of generic and non-generic stuff.
			// if we provided mappings, don't bother searching normal functions.
			if(gmaps.empty())
			{
				auto defs = tree->getDefinitionsWithName(name);
				for(auto d : defs)
					fns.push_back({ d, *arguments, poly::Solution_t() });
			}

			if(auto gdefs = tree->getUnresolvedGenericDefnsWithName(name); gdefs.size() > 0)
			{
				didGeneric = true;
				auto argcopy = *arguments;

				auto pots = poly::findPolymorphReferences(fs, name, gdefs, gmaps, /* return_infer: */ return_infer,
					/* type_infer: */ 0, /* isFnCall: */ true, &argcopy);

				for(const auto& pot : pots)
				{
					if(!pot.first.isDefn())
					{
						iceAssert(pot.first.isError());
						errs->append(pot.first.error());
					}
					else
					{
						auto def = pot.first.defn();
						if(def->type->containsPlaceholders())
							error("wtf??? '%s'", def->type);

						// make sure we didn't already find this in the non-generic search
						//? (can happen when we recursively call a generic function!)
						if(auto it = std::find_if(fns.begin(), fns.end(), [def](const auto& tup) -> bool {
							return std::get<0>(tup) == def;
						}); it != fns.end())
						{
							continue;
						}

						auto sln = pot.second;
						// ! ACHTUNG !
						// insert a hefty penalty for using a polymorphic function!
						// this doesn't disallow polymorphic functions from participating in
						// overloading, but this makes our resolver prefer non-generic functions.
						sln.distance += 10;

						fns.push_back({ def, argcopy, sln });
					}
				}
			}

			if(travUp && fns.empty())
				tree = tree->parent;

			else
				break;
		}

		if(fns.empty())
		{
			if(!didGeneric)
			{
				errs = SimpleError::make(fs->loc(), "no such function named '%s'", name);
			}

			return TCResult(errs);
		}

		std::vector<std::pair<sst::Defn*, std::vector<FnCallArgument>>> cands;
		for(const auto& [ def, args, soln ] : fns)
		{
			auto ts = args; // copy it.

			if(dcast(FunctionDecl, def) || dcast(TypeDefn, def))
			{
				cands.push_back({ def, ts });
			}
			else if(dcast(VarDefn, def) && def->type->isFunctionType() /* && !didVar */)
			{
				cands.push_back({ def, ts });
				// didVar = true;
			}
			else
			{
				return TCResult(
					SimpleError::make(fs->loc(), "'%s' cannot be called as a function; it was defined with type '%s' in the current scope",
						name, def->type)->append(SimpleError::make(def->loc, "Previously defined here:"))
				);
			}
		}

		auto [ res, new_args ] = resolver::internal::resolveFunctionCallFromCandidates(fs, fs->loc(), cands, gmaps, travUp, return_infer);
		if(res.isDefn())
		{
			*arguments = new_args;

			return res;
		}
		else
		{
			return TCResult(errs->append(res.error()));
		}
	}

	TCResult resolveConstructorCall(TypecheckState* fs, TypeDefn* typedf, const std::vector<FnCallArgument>& arguments, const PolyArgMapping_t& pams)
	{
		//! ACHTUNG: DO NOT REARRANGE !
		//* NOTE: ClassDefn inherits from StructDefn *

		if(auto cls = dcast(ClassDefn, typedf))
		{
			// class initialisers must be called with named arguments only.
			for(const auto& arg : arguments)
			{
				if(arg.name.empty())
				{
					return TCResult(SimpleError::make(arg.loc, "arguments to class initialisers (for class '%s' here) must be named", cls->id.name));
				}
			}

			auto copy = arguments;

			//! SELF HANDLING (INSERTION) (CONSTRUCTOR)
			copy.push_back(FnCallArgument::make(cls->loc, "self", cls->type->getMutablePointerTo()));
			auto copy1 = copy;

			auto cand = resolveFunctionCallFromCandidates(fs, util::map(cls->initialisers, [](auto e) -> auto {
				return dcast(sst::Defn, e);
			}), &copy, pams, true);

			// TODO: support re-eval of constructor args!
			// TODO: support re-eval of constructor args!
			// TODO: support re-eval of constructor args!

			if(copy1 != copy)
				error(fs->loc(), "args changed for constructor call -- fixme!!!");

			if(cand.isError())
			{
				cand.error()->prepend(SimpleError::make(fs->loc(), "failed to find matching initialiser for class '%s':", cls->id.name));
				return TCResult(cand.error());
			}

			return TCResult(cand);
		}
		else if(auto str = dcast(StructDefn, typedf))
		{
			std::vector<std::string> fieldNames;

			for(auto f : str->fields)
				fieldNames.push_back(f->id.name);

			auto [ seen, err ] = resolver::verifyStructConstructorArguments(fs->loc(), str->id.name, fieldNames, arguments);

			if(err != nullptr)
			{
				return TCResult(err);
			}
			else
			{
				auto seencopy = seen;
				std::vector<FnParam> target = util::filterMap(str->fields, [&seencopy](sst::StructFieldDefn* f) -> bool {
					return seencopy.find(f->id.name) != seencopy.end();
				}, [](sst::StructFieldDefn* f) -> FnParam {
					return FnParam(f->loc, f->id.name, f->type);
				});

				ErrorMsg* _err = 0;
				auto args = resolver::misc::canonicaliseCallArguments(fs->loc(), target, arguments, &_err);
				if(_err != 0) return TCResult(_err);

				auto [ soln, err ] = poly::solveTypeList(util::map(target, [](const FnParam& f) -> fir::LocatedType {
					return fir::LocatedType(f.type, f.loc);
				}), args, poly::Solution_t(), /* isFnCall: */ true);

				// in actual fact we just return the thing here. sigh.
				if(err != nullptr)  return TCResult(err);
				else                return TCResult(str);
			}
		}
		else if(auto uvd = dcast(sst::UnionVariantDefn, typedf))
		{
			// TODO: support re-eval of constructor args!
			// TODO: support re-eval of constructor args!
			// TODO: support re-eval of constructor args!

			auto copy = arguments;

			auto ret = resolver::resolveAndInstantiatePolymorphicUnion(fs, uvd, &copy, /* type_infer: */ nullptr, /* isFnCall: */ true);

			if(copy != arguments)
				error(fs->loc(), "args changed for constructor call -- fixme!!!");

			return ret;
		}
		else
		{
			return TCResult(
				SimpleError::make(fs->loc(), "unsupported constructor call on type '%s'", typedf->id.name)
			    ->append(SimpleError::make(typedf->loc, "type was defined here:"))
			);
		}
	}
	}

	fir::Type* TypecheckState::checkIsBuiltinConstructorCall(const std::string& name, const std::vector<FnCallArgument>& arguments)
	{
		if(auto type = fir::Type::fromBuiltin(name))
		{
			for(const auto& a : arguments)
			{
				if(!a.name.empty())
					error(a.loc, "builtin type initialisers do not accept named arguments");
			}

			// all builtin types can be zero-initialised.
			if(arguments.empty())
			{
				return type;
			}
			else if(arguments.size() == 1)
			{
				if(int d = getCastDistance(arguments[0].value->type, type); d >= 0 || (type->isStringType() && arguments[0].value->type->isCharSliceType()))
				{
					return type;
				}
				else
				{
					error(arguments[0].loc, "type mismatch in initialiser call to builtin type '%s', found type '%s' instead", type,
						arguments[0].value->type);
				}
			}
			else
			{
				if(type->isStringType())
				{
					// either from a slice, or from a ptr + len
					if(arguments.size() == 1)
					{
						if(!arguments[0].value->type->isCharSliceType())
						{
							error(arguments[0].loc, "single argument to string initialiser must be a slice of char, aka '%s', found '%s' instead",
								fir::Type::getCharSlice(false), arguments[0].value->type);
						}

						return type;
					}
					else if(arguments.size() == 2)
					{
						if(auto t1 = arguments[0].value->type; (t1 != fir::Type::getInt8Ptr() && t1 != fir::Type::getMutInt8Ptr()))
						{
							error(arguments[0].loc, "first argument to two-arg string initialiser (data pointer) must be '%s' or '%s', found '%s' instead",
								fir::Type::getInt8Ptr(), fir::Type::getMutInt8Ptr(), t1);
						}
						else if(auto t2 = arguments[1].value->type; fir::getCastDistance(t2, fir::Type::getInt64()) < 0)
						{
							error(arguments[0].loc, "second argument to two-arg string initialiser (length) must be '%s', found '%s' instead",
								(fir::Type*) fir::Type::getInt64(), t2);
						}
						else
						{
							return type;
						}
					}
					else
					{
						error(arguments[2].loc, "string initialiser only takes 1 (from slice) or 2 (from pointer+length) arguments, found '%ld' instead",
							arguments.size());
					}
				}
				else
				{
					error(arguments[1].loc, "builtin type '%s' cannot be initialised with more than 1 value", type);
				}
			}
		}

		return 0;
	}
}

<|endoftext|>


<commit_before>// Copyright 2014 eric schkufza
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "src/tunit/tunit.h"

#include <sstream>
#include <vector>

#include "src/ext/cpputil/include/io/column.h"
#include "src/ext/cpputil/include/io/filterstream.h"
#include "src/ext/cpputil/include/io/indent.h"

using namespace cpputil;
using namespace std;
using namespace x64asm;

namespace stoke {

istream& operator>>(istream& is, TUnit& t) {
  string s;

  getline(is, s);
  is >> s >> t.name;
  getline(is, s);
  getline(is, s);
  getline(is, s);

  vector<string> lines;
  for (size_t i = 0; getline(is, s); ++i) {
    lines.push_back(s);
  }
  lines.pop_back();
  is.clear(ios::eofbit);

  stringstream ss;
  for (const auto& l : lines) {
    ss << l << endl;
  }
  ss >> t.code;

  if (ss.fail()) {
    is.setstate(ios::failbit);
  }

	return is;
}

ostream& operator<<(ostream& os, const TUnit& t) {
	os << "  .text" << endl;
	os << "  .globl " << t.name << endl;
	os << "  .type " << t.name << ", @function" << endl;
	os << t.name << ":" << endl;

	ofilterstream<Column> col(os);
	col.filter().padding(2);

	for (size_t i = 0, ie = t.code.size(); i < ie; ++i) {
		if (!t.code[i].is_label_defn()) {
			col << "  ";
		}
		col << t.code[i];
	 	if (i+1 != ie) {
			col	<< endl;
		}
	}
	col.filter().next();

	size_t line = 0;
	for (size_t i = 0, ie = t.code.size(); i < ie; ++i) {
		if (!t.code[i].is_label_defn()) {
			col << "# " << dec << line++;
		}
		if (i+1 != ie) {
			col << endl;
		}
	}
	col.filter().done();

	os << endl;
	os << ".size " << t.name << ", .-" << t.name << endl;

	return os;
}

} // namespace stoke
<commit_msg>Fix for #122.<commit_after>// Copyright 2014 eric schkufza
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "src/tunit/tunit.h"

#include <sstream>
#include <vector>

#include "src/ext/cpputil/include/io/column.h"
#include "src/ext/cpputil/include/io/filterstream.h"
#include "src/ext/cpputil/include/io/indent.h"

using namespace cpputil;
using namespace std;
using namespace x64asm;

namespace stoke {

istream& operator>>(istream& is, TUnit& t) {
  string s;

  getline(is, s);
  is >> s >> t.name;
  getline(is, s);
  getline(is, s);
  getline(is, s);

  vector<string> lines;
  for (size_t i = 0; getline(is, s); ++i) {
    lines.push_back(s);
  }
  is.clear(ios::eofbit);

  stringstream ss;
  for (const auto& l : lines) {
    if(!l.empty()) {
      ss << l << endl;
    } else {
      break;
    }
  }
  ss >> t.code;

  if (ss.fail()) {
    is.setstate(ios::failbit);
  }

	return is;
}

ostream& operator<<(ostream& os, const TUnit& t) {
	os << "  .text" << endl;
	os << "  .globl " << t.name << endl;
	os << "  .type " << t.name << ", @function" << endl;
	os << t.name << ":" << endl;

	ofilterstream<Column> col(os);
	col.filter().padding(2);

	for (size_t i = 0, ie = t.code.size(); i < ie; ++i) {
		if (!t.code[i].is_label_defn()) {
			col << "  ";
		}
		col << t.code[i];
	 	if (i+1 != ie) {
			col	<< endl;
		}
	}
	col.filter().next();

	size_t line = 0;
	for (size_t i = 0, ie = t.code.size(); i < ie; ++i) {
		if (!t.code[i].is_label_defn()) {
			col << "# " << dec << line++;
		}
		if (i+1 != ie) {
			col << endl;
		}
	}
	col.filter().done();

	os << endl << endl;
	os << ".size " << t.name << ", .-" << t.name << endl;

	return os;
}

} // namespace stoke
<|endoftext|>


<commit_before>/*
 * Copyright 2016 Google Inc. All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "objc_bazel_support.h"

#include <llvm/ADT/StringRef.h>
#include "re2/re2.h"

#include <sstream>

namespace kythe {

// This is inspiried by Python's commands.mkarg
// https://hg.python.org/cpython/file/tip/Lib/commands.py#l81
std::string SanitizeArgument(const std::string &s) {
  if (s.find("'") == std::string::npos) {
    // There are no single quotes, so we can make the string safe by putting it
    // in single quotes.
    return "'" + s + "'";
  }
  // There are single quotes in the string, so we will wrap it in double quotes
  // and escape backslash, double-quote, dollar, and back-tick.
  std::string ret = s;
  RE2::GlobalReplace(&ret, R"(([\\"$`]))", R"(\\\1)");
  return "\"" + ret + "\"";
}

std::string BuildEnvVarCommandPrefix(const blaze::SpawnInfo &si) {
  std::stringstream ret;
  for (const auto &env : si.variable()) {
    // Neither name nor value are validated or sanitized.
    // This really should be unnecessary, but we don't have any guarantees.
    if (RE2::FullMatch(env.name(), "[a-zA-Z_][a-zA-Z_0-9]*")) {
      ret << env.name() << "=" << SanitizeArgument(env.value()) << " ";
    }
  }
  return ret.str();
}

std::string RunScript(const std::string &cmd) {
  char buffer[256];
  std::string output = "";
  FILE *f = popen(cmd.c_str(), "r");
  if (!f) {
    return output;
  }
  while (!feof(f)) {
    if (fgets(buffer, 256, f) != NULL) {
      output += buffer;
    }
  }
  pclose(f);
  return llvm::StringRef(output).trim();
}

void FillWithFixedArgs(std::vector<std::string> &args,
                       const blaze::CppCompileInfo &ci,
                       const std::string &devdir, const std::string &sdkroot) {
  args.push_back(ci.tool());
  for (const auto &i : ci.compiler_option()) {
    std::string arg = i;
    RE2::GlobalReplace(&arg, "__BAZEL_XCODE_DEVELOPER_DIR__", devdir);
    RE2::GlobalReplace(&arg, "__BAZEL_XCODE_SDKROOT__", sdkroot);
    args.push_back(arg);
  }
  args.push_back(ci.source_file());
}

void FillWithFixedArgs(std::vector<std::string> &args,
                       const blaze::SpawnInfo &si, const std::string &devdir,
                       const std::string &sdkroot) {
  for (const auto &i : si.argument()) {
    std::string arg = i;
    RE2::GlobalReplace(&arg, "__BAZEL_XCODE_DEVELOPER_DIR__", devdir);
    RE2::GlobalReplace(&arg, "__BAZEL_XCODE_SDKROOT__", sdkroot);
    args.push_back(arg);
  }
}

}  // namespace kythe
<commit_msg>Bazel outputs isysroot /foo/bar as a single arg, handle it<commit_after>/*
 * Copyright 2016 Google Inc. All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "objc_bazel_support.h"

#include <llvm/ADT/StringRef.h>
#include "re2/re2.h"

#include <sstream>

namespace kythe {

// This is inspiried by Python's commands.mkarg
// https://hg.python.org/cpython/file/tip/Lib/commands.py#l81
std::string SanitizeArgument(const std::string &s) {
  if (s.find("'") == std::string::npos) {
    // There are no single quotes, so we can make the string safe by putting it
    // in single quotes.
    return "'" + s + "'";
  }
  // There are single quotes in the string, so we will wrap it in double quotes
  // and escape backslash, double-quote, dollar, and back-tick.
  std::string ret = s;
  RE2::GlobalReplace(&ret, R"(([\\"$`]))", R"(\\\1)");
  return "\"" + ret + "\"";
}

std::string BuildEnvVarCommandPrefix(const blaze::SpawnInfo &si) {
  std::stringstream ret;
  for (const auto &env : si.variable()) {
    // Neither name nor value are validated or sanitized.
    // This really should be unnecessary, but we don't have any guarantees.
    if (RE2::FullMatch(env.name(), "[a-zA-Z_][a-zA-Z_0-9]*")) {
      ret << env.name() << "=" << SanitizeArgument(env.value()) << " ";
    }
  }
  return ret.str();
}

std::string RunScript(const std::string &cmd) {
  char buffer[256];
  std::string output = "";
  FILE *f = popen(cmd.c_str(), "r");
  if (!f) {
    return output;
  }
  while (!feof(f)) {
    if (fgets(buffer, 256, f) != NULL) {
      output += buffer;
    }
  }
  pclose(f);
  return llvm::StringRef(output).trim();
}

void FillWithFixedArgs(std::vector<std::string> &args,
                       const blaze::CppCompileInfo &ci,
                       const std::string &devdir, const std::string &sdkroot) {
  args.push_back(ci.tool());
  for (const auto &i : ci.compiler_option()) {
    std::string arg = i;
    // TODO(salguarnieri) revert this when it is fixed in bazel.
    if (arg.find("-isysroot ") == 0) {
      args.push_back("-isysroot");
      // Set arg to the actual isysroot argument now.
      arg = arg.substr(10);
    }
    RE2::GlobalReplace(&arg, "__BAZEL_XCODE_DEVELOPER_DIR__", devdir);
    RE2::GlobalReplace(&arg, "__BAZEL_XCODE_SDKROOT__", sdkroot);
    args.push_back(arg);
  }
  args.push_back(ci.source_file());
}

void FillWithFixedArgs(std::vector<std::string> &args,
                       const blaze::SpawnInfo &si, const std::string &devdir,
                       const std::string &sdkroot) {
  for (const auto &i : si.argument()) {
    std::string arg = i;
    RE2::GlobalReplace(&arg, "__BAZEL_XCODE_DEVELOPER_DIR__", devdir);
    RE2::GlobalReplace(&arg, "__BAZEL_XCODE_SDKROOT__", sdkroot);
    args.push_back(arg);
  }
}

}  // namespace kythe
<|endoftext|>


<commit_before>// Try a strlen suppression, but force the input file to be DOS format (CRLF).
// RUN: %clangxx_asan -O0 %s -o %t
// RUN: echo "interceptor_name:strlen" > %t.supp
// RUN: unix2dos %t.supp
// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t 2>&1 | FileCheck %s

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main() {
  char *a = (char *)malloc(6);
  free(a);
  size_t len = strlen(a); // BOOM
  fprintf(stderr, "strlen ignored, len = %zu\n", len);
}

// CHECK-NOT: AddressSanitizer: heap-use-after-free
// CHECK: strlen ignored
<commit_msg>[windows] Avoid unix2dos, it seems to not work on our bot<commit_after>// Try a strlen suppression, but force the input file to be DOS format (CRLF).
// RUN: %clangxx_asan -O0 %s -o %t
// RUN: python -c 'import sys; sys.stdout.write("interceptor_name:strlen\r\n")' > %t.supp
// RUN: %env_asan_opts=suppressions='"%t.supp"' %run %t 2>&1 | FileCheck %s

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main() {
  char *a = (char *)malloc(6);
  free(a);
  size_t len = strlen(a); // BOOM
  fprintf(stderr, "strlen ignored, len = %zu\n", len);
}

// CHECK-NOT: AddressSanitizer: heap-use-after-free
// CHECK: strlen ignored
<|endoftext|>


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

  Program:   Visualization Toolkit
  Module:    vtkTriangle.cc
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

Copyright (c) 1993-1995 Ken Martin, Will Schroeder, Bill Lorensen.

This software is copyrighted by Ken Martin, Will Schroeder and Bill Lorensen.
The following terms apply to all files associated with the software unless
explicitly disclaimed in individual files. This copyright specifically does
not apply to the related textbook "The Visualization Toolkit" ISBN
013199837-4 published by Prentice Hall which is covered by its own copyright.

The authors hereby grant permission to use, copy, and distribute this
software and its documentation for any purpose, provided that existing
copyright notices are retained in all copies and that this notice is included
verbatim in any distributions. Additionally, the authors grant permission to
modify this software and its documentation for any purpose, provided that
such modifications are not distributed without the explicit consent of the
authors and that existing copyright notices are retained in all copies. Some
of the algorithms implemented by this software are patented, observe all
applicable patent law.

IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY FOR
DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF,
EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, INCLUDING,
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE, AND NON-INFRINGEMENT.  THIS SOFTWARE IS PROVIDED ON AN
"AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE
MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.

=========================================================================*/
#include "vtkTriangle.hh"
#include "vtkPolygon.hh"
#include "vtkPlane.hh"
#include "vtkMath.hh"
#include "vtkCellArray.hh"
#include "vtkLine.hh"

static vtkPolygon poly;
static vtkMath math;
static vtkPlane plane;

// Description:
// Deep copy of cell.
vtkTriangle::vtkTriangle(const vtkTriangle& t)
{
  this->Points = t.Points;
  this->PointIds = t.PointIds;
}

int vtkTriangle::EvaluatePosition(float x[3], float closestPoint[3],
                                 int& subId, float pcoords[3],
                                 float& dist2, float *weights)
{
  int i, j;
  float *pt1, *pt2, *pt3, n[3];
  float rhs[2], c1[2], c2[2];
  float det;
  float maxComponent;
  int idx, indices[2];

  subId = 0;
  pcoords[0] = pcoords[1] = pcoords[2] = 0.0;
//
// Get normal for triangle
//
  pt1 = this->Points.GetPoint(1);
  pt2 = this->Points.GetPoint(2);
  pt3 = this->Points.GetPoint(0);

  poly.ComputeNormal (pt1, pt2, pt3, n);
//
// Project point to plane
//
  plane.ProjectPoint(x,pt1,n,closestPoint);
//
// Construct matrices.  Since we have over determined system, need to find
// which 2 out of 3 equations to use to develop equations. (Any 2 should
// work since we've projected point to plane.)
//
  for (maxComponent=0.0, i=0; i<3; i++)
    {
    if (fabs(n[i]) > maxComponent)
      {
      maxComponent = fabs(n[i]);
      idx = i;
      }
    }
  for (j=0, i=0; i<3; i++)
    {
    if ( i != idx ) indices[j++] = i;
    }

  for (i=0; i<2; i++)
    {
    rhs[i] = closestPoint[indices[i]] - pt3[indices[i]];
    c1[i] = pt1[indices[i]] - pt3[indices[i]];
    c2[i] = pt2[indices[i]] - pt3[indices[i]];
    }

  if ( (det = math.Determinant2x2(c1,c2)) == 0.0 ) return -1;

  pcoords[0] = math.Determinant2x2 (rhs,c2) / det;
  pcoords[1] = math.Determinant2x2 (c1,rhs) / det;
  pcoords[2] = 1.0 - pcoords[0] - pcoords[1];
//
// Okay, now find closest point to element
//
  weights[0] = pcoords[2];
  weights[1] = pcoords[0];
  weights[2] = pcoords[1];

  if ( pcoords[0] >= 0.0 && pcoords[0] <= 1.0 &&
  pcoords[1] >= 0.0 && pcoords[1] <= 1.0 &&
  pcoords[2] >= 0.0 && pcoords[2] <= 1.0 )
    {
    dist2 = math.Distance2BetweenPoints(closestPoint,x); //projection distance
    return 1;
    }
  else
    {
    static vtkLine line;
    float t;

    if ( pcoords[0] < 0.0 && pcoords[1] < 0.0 )
      {
      dist2 = math.Distance2BetweenPoints(x,pt3);
      for (i=0; i<3; i++) closestPoint[i] = pt3[i];
      }
    else if ( pcoords[1] < 0.0 && pcoords[2] < 0.0 )
      {
      dist2 = math.Distance2BetweenPoints(x,pt1);
      for (i=0; i<3; i++) closestPoint[i] = pt1[i];
      }
    else if ( pcoords[0] < 0.0 && pcoords[2] < 0.0 )
      {
      dist2 = math.Distance2BetweenPoints(x,pt2);
      for (i=0; i<3; i++) closestPoint[i] = pt2[i];
      }
    else if ( pcoords[0] < 0.0 )
      {
      dist2 = line.DistanceToLine(x,pt2,pt3,t,closestPoint);
      }
    else if ( pcoords[1] < 0.0 )
      {
      dist2 = line.DistanceToLine(x,pt1,pt3,t,closestPoint);
      }
    else if ( pcoords[2] < 0.0 )
      {
      dist2 = line.DistanceToLine(x,pt1,pt2,t,closestPoint);
      }
    return 0;
    }
}

void vtkTriangle::EvaluateLocation(int& subId, float pcoords[3], float x[3],
                                  float *weights)
{
  float u3;
  float *pt0, *pt1, *pt2;
  int i;

  pt0 = this->Points.GetPoint(0);
  pt1 = this->Points.GetPoint(1);
  pt2 = this->Points.GetPoint(2);

  u3 = 1.0 - pcoords[0] - pcoords[1];

  for (i=0; i<3; i++)
    {
    x[i] = pt0[i]*u3 + pt1[i]*pcoords[0] + pt2[i]*pcoords[1];
    }

  weights[0] = u3;
  weights[1] = pcoords[0];
  weights[2] = pcoords[1];
}

int vtkTriangle::CellBoundary(int subId, float pcoords[3], vtkIdList& pts)
{
  float t1=pcoords[0]-pcoords[1];
  float t2=0.5*(1.0-pcoords[0])-pcoords[1];
  float t3=2.0*pcoords[0]+pcoords[1]-1.0;

  pts.Reset();

  // compare against three lines in parametric space that divide element
  // into three pieces
  if ( t1 >= 0.0 && t2 >= 0.0 )
    {
    pts.SetId(0,this->PointIds.GetId(0));
    pts.SetId(1,this->PointIds.GetId(1));
    }

  else if ( t2 < 0.0 && t3 >= 0.0 )
    {
    pts.SetId(0,this->PointIds.GetId(1));
    pts.SetId(1,this->PointIds.GetId(2));
    }

  else //( t1 < 0.0 && t3 < 0.0 )
    {
    pts.SetId(0,this->PointIds.GetId(2));
    pts.SetId(1,this->PointIds.GetId(0));
    }

  if ( pcoords[0] < 0.0 || pcoords[1] < 0.0 ||
  pcoords[0] > 1.0 || pcoords[1] > 1.0 || (1.0 - pcoords[0] - pcoords[1]) < 0.0 )
    return 0;
  else
    return 1;

}

//
// Marching triangles
//
typedef int EDGE_LIST;
typedef struct {
       EDGE_LIST edges[3];
} LINE_CASES;

static LINE_CASES lineCases[] = {
  {{-1, -1, -1}},
  {{0, 2, -1}},
  {{1, 0, -1}},
  {{1, 2, -1}},
  {{2, 1, -1}},
  {{0, 1, -1}},
  {{2, 0, -1}},
  {{-1, -1, -1}}
};

void vtkTriangle::Contour(float value, vtkFloatScalars *cellScalars,
                         vtkFloatPoints *points,
                         vtkCellArray *verts, vtkCellArray *lines,
                         vtkCellArray *polys, vtkFloatScalars *scalars)
{
  static int CASE_MASK[3] = {1,2,4};
  LINE_CASES *lineCase;
  EDGE_LIST  *edge;
  int i, j, index, *vert;
  static int edges[3][2] = { {0,1}, {1,2}, {2,0} };
  int pts[2];
  float t, *x1, *x2, x[3];

  // Build the case table
  for ( i=0, index = 0; i < 3; i++)
      if (cellScalars->GetScalar(i) >= value)
          index |= CASE_MASK[i];

  lineCase = lineCases + index;
  edge = lineCase->edges;

  for ( ; edge[0] > -1; edge += 2 )
    {
    for (i=0; i<2; i++) // insert line
      {
      vert = edges[edge[i]];
      t = (value - cellScalars->GetScalar(vert[0])) /
          (cellScalars->GetScalar(vert[1]) - cellScalars->GetScalar(vert[0]));
      x1 = this->Points.GetPoint(vert[0]);
      x2 = this->Points.GetPoint(vert[1]);
      for (j=0; j<3; j++) x[j] = x1[j] + t * (x2[j] - x1[j]);
      pts[i] = points->InsertNextPoint(x);
      scalars->InsertNextScalar(value);
      }
    lines->InsertNextCell(2,pts);
    }
}

vtkCell *vtkTriangle::GetEdge(int edgeId)
{
  static vtkLine line;
  int edgeIdPlus1 = edgeId + 1;

  if (edgeIdPlus1 > 2) edgeIdPlus1 = 0;

  // load point id's
  line.PointIds.SetId(0,this->PointIds.GetId(edgeId));
  line.PointIds.SetId(1,this->PointIds.GetId(edgeIdPlus1));

  // load coordinates
  line.Points.SetPoint(0,this->Points.GetPoint(edgeId));
  line.Points.SetPoint(1,this->Points.GetPoint(edgeIdPlus1));

  return &line;
}

//
// Plane intersection plus in/out test on triangle.
//
int vtkTriangle::IntersectWithLine(float p1[3], float p2[3], float tol,
                                  float& t, float x[3], float pcoords[3],
                                  int& subId)
{
  float *pt1, *pt2, *pt3, n[3];
  float tol2 = tol*tol;
  float closestPoint[3];
  float dist2, weights[3];

  subId = 0;
  pcoords[0] = pcoords[1] = pcoords[2] = 0.0;
//
// Get normal for triangle
//
  pt1 = this->Points.GetPoint(1);
  pt2 = this->Points.GetPoint(2);
  pt3 = this->Points.GetPoint(0);

  poly.ComputeNormal (pt1, pt2, pt3, n);
//
// Intersect plane of triangle with line
//
  if ( ! plane.IntersectWithLine(p1,p2,n,pt1,t,x) ) return 0;
//
// Evaluate position
//
  if (this->EvaluatePosition(x, closestPoint, subId, pcoords, dist2, weights)
      >= 0)
    {
    if ( dist2 <= tol2 ) return 1;
    }

  return 0;
}

int vtkTriangle::Triangulate(int index, vtkFloatPoints &pts)
{
  pts.Reset();
  pts.InsertPoint(0,this->Points.GetPoint(0));
  pts.InsertPoint(1,this->Points.GetPoint(1));
  pts.InsertPoint(2,this->Points.GetPoint(2));

  return 1;
}

void vtkTriangle::Derivatives(int subId, float pcoords[3], float *values,
                              int dim, float *derivs)
{
  int i, idx;

  // The following code is incorrect. Will be fixed in future release.
  for (i=0; i<dim; i++)
    {
    idx = i*dim;
    derivs[idx] = 0.0;
    derivs[idx+1] = 0.0;
    derivs[idx+2] = 0.0;
    }
}

// Special dot product definition for 2-vectors
#define DOT(_x,_y) _x[0]*_y[0] + _x[1]*_y[1]

// Description:
// Compute the circumcenter (center[3]) and radius (method return value) of
// a triangle defined by the three points x1, x2, and x3. (Note that the
// coordinates are 2D. 3D points can be used but the z-component will be
// ignored.)
float vtkTriangle::Circumcircle(float  x1[2], float x2[2], float x3[2],
                                float center[2])
{
  float n12[2], n13[2], x12[2], x13[2];
  float c1[2], c2[2], rhs[2], diff, sum, det;
  int i;
//
//  calculate normals and intersection points of bisecting planes.
//
  for (i=0; i<2; i++)
    {
    n12[i] = x2[i] - x1[i];
    n13[i] = x3[i] - x1[i];
    x12[i] = (x2[i] + x1[i])/2.0;
    x13[i] = (x3[i] + x1[i])/2.0;
    }
//
//  Compute solutions to the intersection of two bisecting lines
//  (2-eqns. in 2-unknowns) using Kramer's rule.
//
//  form system matrices
//
  c1[0] = n12[0]; c2[0] = n12[1];
  c1[1] = n13[0]; c2[1] = n13[1];

  rhs[0] = DOT(n12,x12);
  rhs[1] = DOT(n13,x13);
//
// Solve system of equations
//
  if ( (det=math.Determinant2x2(c1,c2)) == 0.0 ||
  fabs((center[0]=math.Determinant2x2(rhs,c2)/det)) > 1.0e04 ||
  fabs((center[1]=math.Determinant2x2(c1,rhs)/det)) > 1.0e04 )
    {
    center[0] = center[1] = 0.0;
    return VTK_LARGE_FLOAT;
    }

  //determine average value of radius squared
  for (sum=0, i=0; i<2; i++)
    {
    diff = x1[i] - center[i];
    sum += diff*diff;
    diff = x2[i] - center[i];
    sum += diff*diff;
    diff = x3[i] - center[i];
    sum += diff*diff;
    }

  return (sum / 3.0);
}
#undef DOT
<commit_msg>ENH: User higher-precision linear solution solver.<commit_after>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkTriangle.cc
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

Copyright (c) 1993-1995 Ken Martin, Will Schroeder, Bill Lorensen.

This software is copyrighted by Ken Martin, Will Schroeder and Bill Lorensen.
The following terms apply to all files associated with the software unless
explicitly disclaimed in individual files. This copyright specifically does
not apply to the related textbook "The Visualization Toolkit" ISBN
013199837-4 published by Prentice Hall which is covered by its own copyright.

The authors hereby grant permission to use, copy, and distribute this
software and its documentation for any purpose, provided that existing
copyright notices are retained in all copies and that this notice is included
verbatim in any distributions. Additionally, the authors grant permission to
modify this software and its documentation for any purpose, provided that
such modifications are not distributed without the explicit consent of the
authors and that existing copyright notices are retained in all copies. Some
of the algorithms implemented by this software are patented, observe all
applicable patent law.

IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY FOR
DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF,
EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, INCLUDING,
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE, AND NON-INFRINGEMENT.  THIS SOFTWARE IS PROVIDED ON AN
"AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE
MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.

=========================================================================*/
#include "vtkTriangle.hh"
#include "vtkPolygon.hh"
#include "vtkPlane.hh"
#include "vtkMath.hh"
#include "vtkCellArray.hh"
#include "vtkLine.hh"

static vtkPolygon poly;
static vtkMath math;
static vtkPlane plane;

// Description:
// Deep copy of cell.
vtkTriangle::vtkTriangle(const vtkTriangle& t)
{
  this->Points = t.Points;
  this->PointIds = t.PointIds;
}

int vtkTriangle::EvaluatePosition(float x[3], float closestPoint[3],
                                 int& subId, float pcoords[3],
                                 float& dist2, float *weights)
{
  int i, j;
  float *pt1, *pt2, *pt3, n[3];
  float rhs[2], c1[2], c2[2];
  float det;
  float maxComponent;
  int idx, indices[2];

  subId = 0;
  pcoords[0] = pcoords[1] = pcoords[2] = 0.0;
//
// Get normal for triangle
//
  pt1 = this->Points.GetPoint(1);
  pt2 = this->Points.GetPoint(2);
  pt3 = this->Points.GetPoint(0);

  poly.ComputeNormal (pt1, pt2, pt3, n);
//
// Project point to plane
//
  plane.ProjectPoint(x,pt1,n,closestPoint);
//
// Construct matrices.  Since we have over determined system, need to find
// which 2 out of 3 equations to use to develop equations. (Any 2 should
// work since we've projected point to plane.)
//
  for (maxComponent=0.0, i=0; i<3; i++)
    {
    if (fabs(n[i]) > maxComponent)
      {
      maxComponent = fabs(n[i]);
      idx = i;
      }
    }
  for (j=0, i=0; i<3; i++)
    {
    if ( i != idx ) indices[j++] = i;
    }

  for (i=0; i<2; i++)
    {
    rhs[i] = closestPoint[indices[i]] - pt3[indices[i]];
    c1[i] = pt1[indices[i]] - pt3[indices[i]];
    c2[i] = pt2[indices[i]] - pt3[indices[i]];
    }

  if ( (det = math.Determinant2x2(c1,c2)) == 0.0 ) return -1;

  pcoords[0] = math.Determinant2x2 (rhs,c2) / det;
  pcoords[1] = math.Determinant2x2 (c1,rhs) / det;
  pcoords[2] = 1.0 - pcoords[0] - pcoords[1];
//
// Okay, now find closest point to element
//
  weights[0] = pcoords[2];
  weights[1] = pcoords[0];
  weights[2] = pcoords[1];

  if ( pcoords[0] >= 0.0 && pcoords[0] <= 1.0 &&
  pcoords[1] >= 0.0 && pcoords[1] <= 1.0 &&
  pcoords[2] >= 0.0 && pcoords[2] <= 1.0 )
    {
    dist2 = math.Distance2BetweenPoints(closestPoint,x); //projection distance
    return 1;
    }
  else
    {
    static vtkLine line;
    float t;

    if ( pcoords[0] < 0.0 && pcoords[1] < 0.0 )
      {
      dist2 = math.Distance2BetweenPoints(x,pt3);
      for (i=0; i<3; i++) closestPoint[i] = pt3[i];
      }
    else if ( pcoords[1] < 0.0 && pcoords[2] < 0.0 )
      {
      dist2 = math.Distance2BetweenPoints(x,pt1);
      for (i=0; i<3; i++) closestPoint[i] = pt1[i];
      }
    else if ( pcoords[0] < 0.0 && pcoords[2] < 0.0 )
      {
      dist2 = math.Distance2BetweenPoints(x,pt2);
      for (i=0; i<3; i++) closestPoint[i] = pt2[i];
      }
    else if ( pcoords[0] < 0.0 )
      {
      dist2 = line.DistanceToLine(x,pt2,pt3,t,closestPoint);
      }
    else if ( pcoords[1] < 0.0 )
      {
      dist2 = line.DistanceToLine(x,pt1,pt3,t,closestPoint);
      }
    else if ( pcoords[2] < 0.0 )
      {
      dist2 = line.DistanceToLine(x,pt1,pt2,t,closestPoint);
      }
    return 0;
    }
}

void vtkTriangle::EvaluateLocation(int& subId, float pcoords[3], float x[3],
                                  float *weights)
{
  float u3;
  float *pt0, *pt1, *pt2;
  int i;

  pt0 = this->Points.GetPoint(0);
  pt1 = this->Points.GetPoint(1);
  pt2 = this->Points.GetPoint(2);

  u3 = 1.0 - pcoords[0] - pcoords[1];

  for (i=0; i<3; i++)
    {
    x[i] = pt0[i]*u3 + pt1[i]*pcoords[0] + pt2[i]*pcoords[1];
    }

  weights[0] = u3;
  weights[1] = pcoords[0];
  weights[2] = pcoords[1];
}

int vtkTriangle::CellBoundary(int subId, float pcoords[3], vtkIdList& pts)
{
  float t1=pcoords[0]-pcoords[1];
  float t2=0.5*(1.0-pcoords[0])-pcoords[1];
  float t3=2.0*pcoords[0]+pcoords[1]-1.0;

  pts.Reset();

  // compare against three lines in parametric space that divide element
  // into three pieces
  if ( t1 >= 0.0 && t2 >= 0.0 )
    {
    pts.SetId(0,this->PointIds.GetId(0));
    pts.SetId(1,this->PointIds.GetId(1));
    }

  else if ( t2 < 0.0 && t3 >= 0.0 )
    {
    pts.SetId(0,this->PointIds.GetId(1));
    pts.SetId(1,this->PointIds.GetId(2));
    }

  else //( t1 < 0.0 && t3 < 0.0 )
    {
    pts.SetId(0,this->PointIds.GetId(2));
    pts.SetId(1,this->PointIds.GetId(0));
    }

  if ( pcoords[0] < 0.0 || pcoords[1] < 0.0 ||
  pcoords[0] > 1.0 || pcoords[1] > 1.0 || (1.0 - pcoords[0] - pcoords[1]) < 0.0 )
    return 0;
  else
    return 1;

}

//
// Marching triangles
//
typedef int EDGE_LIST;
typedef struct {
       EDGE_LIST edges[3];
} LINE_CASES;

static LINE_CASES lineCases[] = {
  {{-1, -1, -1}},
  {{0, 2, -1}},
  {{1, 0, -1}},
  {{1, 2, -1}},
  {{2, 1, -1}},
  {{0, 1, -1}},
  {{2, 0, -1}},
  {{-1, -1, -1}}
};

void vtkTriangle::Contour(float value, vtkFloatScalars *cellScalars,
                         vtkFloatPoints *points,
                         vtkCellArray *verts, vtkCellArray *lines,
                         vtkCellArray *polys, vtkFloatScalars *scalars)
{
  static int CASE_MASK[3] = {1,2,4};
  LINE_CASES *lineCase;
  EDGE_LIST  *edge;
  int i, j, index, *vert;
  static int edges[3][2] = { {0,1}, {1,2}, {2,0} };
  int pts[2];
  float t, *x1, *x2, x[3];

  // Build the case table
  for ( i=0, index = 0; i < 3; i++)
      if (cellScalars->GetScalar(i) >= value)
          index |= CASE_MASK[i];

  lineCase = lineCases + index;
  edge = lineCase->edges;

  for ( ; edge[0] > -1; edge += 2 )
    {
    for (i=0; i<2; i++) // insert line
      {
      vert = edges[edge[i]];
      t = (value - cellScalars->GetScalar(vert[0])) /
          (cellScalars->GetScalar(vert[1]) - cellScalars->GetScalar(vert[0]));
      x1 = this->Points.GetPoint(vert[0]);
      x2 = this->Points.GetPoint(vert[1]);
      for (j=0; j<3; j++) x[j] = x1[j] + t * (x2[j] - x1[j]);
      pts[i] = points->InsertNextPoint(x);
      scalars->InsertNextScalar(value);
      }
    lines->InsertNextCell(2,pts);
    }
}

vtkCell *vtkTriangle::GetEdge(int edgeId)
{
  static vtkLine line;
  int edgeIdPlus1 = edgeId + 1;

  if (edgeIdPlus1 > 2) edgeIdPlus1 = 0;

  // load point id's
  line.PointIds.SetId(0,this->PointIds.GetId(edgeId));
  line.PointIds.SetId(1,this->PointIds.GetId(edgeIdPlus1));

  // load coordinates
  line.Points.SetPoint(0,this->Points.GetPoint(edgeId));
  line.Points.SetPoint(1,this->Points.GetPoint(edgeIdPlus1));

  return &line;
}

//
// Plane intersection plus in/out test on triangle.
//
int vtkTriangle::IntersectWithLine(float p1[3], float p2[3], float tol,
                                  float& t, float x[3], float pcoords[3],
                                  int& subId)
{
  float *pt1, *pt2, *pt3, n[3];
  float tol2 = tol*tol;
  float closestPoint[3];
  float dist2, weights[3];

  subId = 0;
  pcoords[0] = pcoords[1] = pcoords[2] = 0.0;
//
// Get normal for triangle
//
  pt1 = this->Points.GetPoint(1);
  pt2 = this->Points.GetPoint(2);
  pt3 = this->Points.GetPoint(0);

  poly.ComputeNormal (pt1, pt2, pt3, n);
//
// Intersect plane of triangle with line
//
  if ( ! plane.IntersectWithLine(p1,p2,n,pt1,t,x) ) return 0;
//
// Evaluate position
//
  if (this->EvaluatePosition(x, closestPoint, subId, pcoords, dist2, weights)
      >= 0)
    {
    if ( dist2 <= tol2 ) return 1;
    }

  return 0;
}

int vtkTriangle::Triangulate(int index, vtkFloatPoints &pts)
{
  pts.Reset();
  pts.InsertPoint(0,this->Points.GetPoint(0));
  pts.InsertPoint(1,this->Points.GetPoint(1));
  pts.InsertPoint(2,this->Points.GetPoint(2));

  return 1;
}

void vtkTriangle::Derivatives(int subId, float pcoords[3], float *values,
                              int dim, float *derivs)
{
  int i, idx;

  // The following code is incorrect. Will be fixed in future release.
  for (i=0; i<dim; i++)
    {
    idx = i*dim;
    derivs[idx] = 0.0;
    derivs[idx+1] = 0.0;
    derivs[idx+2] = 0.0;
    }
}

// Special dot product definition for 2-vectors
#define VTK_DOT(_x,_y) _x[0]*_y[0] + _x[1]*_y[1]

// Description:
// Compute the circumcenter (center[3]) and radius (method return value) of
// a triangle defined by the three points x1, x2, and x3. (Note that the
// coordinates are 2D. 3D points can be used but the z-component will be
// ignored.)
float vtkTriangle::Circumcircle(float  x1[2], float x2[2], float x3[2],
                                float center[2])
{
  double n12[2], n13[2], x12[2], x13[2];
  double *A[2], rhs[2], sum, diff;
  int i;
//
//  calculate normals and intersection points of bisecting planes.
//
  for (i=0; i<2; i++)
    {
    n12[i] = x2[i] - x1[i];
    n13[i] = x3[i] - x1[i];
    x12[i] = (x2[i] + x1[i])/2.0;
    x13[i] = (x3[i] + x1[i])/2.0;
    }
//
//  Compute solutions to the intersection of two bisecting lines
//  (2-eqns. in 2-unknowns).
//
//  form system matrices
//
  A[0] = n12;
  A[1] = n13;

  rhs[0] = VTK_DOT(n12,x12);
  rhs[1] = VTK_DOT(n13,x13);
//
// Solve system of equations
//
  if ( math.SolveLinearSystem(A,rhs,2) == 0 )
    {
    center[0] = center[1] = 0.0;
    return VTK_LARGE_FLOAT;
    }
  else
    {
    center[0] = rhs[0]; center[1] = rhs[1];
    }

  //determine average value of radius squared
  for (sum=0, i=0; i<2; i++)
    {
    diff = x1[i] - center[i];
    sum += diff*diff;
    diff = x2[i] - center[i];
    sum += diff*diff;
    diff = x3[i] - center[i];
    sum += diff*diff;
    }

  return (float) (sum / 3.0);
}
#undef VTK_DOT
<|endoftext|>