<commit_before>#ifndef BFC_COMBINE_INC_VISITOR_HPP
#define BFC_COMBINE_INC_VISITOR_HPP

#include "ast/mod.hpp"
#include "ast/base.hpp"
#include "test_visitor.hpp"
#include "types.h"

namespace bfc {
namespace ast {

class combine_inc_visitor : public opt_seq_base_visitor {

public:

    status visit(add &node) {
        // discard any zero value node
        if (node.value() == 0) {
            return CONTINUE;
        }
        // Only attempt to combine if there is a previous node
        if (!opt_seq.empty()) {
            // try to combine with the previous node if possible
            try_combine_inc_visitor v(node.offset(), node.value(), true);
            if (opt_seq.back().accept(v) == CONTINUE) {
                // discard the combined node if it is 0
                if (v.new_value() == 0) {
                    opt_seq.pop_back();
                }
                return CONTINUE;
            }
        }
        // else make node copy
        return opt_seq_base_visitor::handle_add(node);
    }

    status visit(const add &node) {
        // discard any zero value node
        if (node.value() == 0) {
            return CONTINUE;
        }
        // Only attempt to combine if there is a previous node
        if (!opt_seq.empty()) {
            // try to combine with the previous node if possible
            try_combine_inc_visitor v(node.offset(), node.value(), true);
            if (opt_seq.back().accept(v) == CONTINUE) {
                // discard the combined node if it is 0
                if (v.new_value() == 0) {
                    opt_seq.pop_back();
                }
                return CONTINUE;
            }
        }
        // else make node copy
        return opt_seq_base_visitor::handle_add(node);
    }

    status visit(sub &node) {
        // discard any zero value node
        if (node.value() == 0) {
            return CONTINUE;
        }
        // Only attempt to combine if there is a previous node
        if (!opt_seq.empty()) {
            // try to combine with the previous node if possible
            try_combine_inc_visitor v(node.offset(), node.value(), false);
            if (opt_seq.back().accept(v) == CONTINUE) {
                // discard the combined node if it is 0
                if (v.new_value() == 0) {
                    opt_seq.pop_back();
                }
                return CONTINUE;
            }
        }
        // else make node copy
        return opt_seq_base_visitor::handle_sub(node);
    }

    status visit(const sub &node) {
        // discard any zero value node
        if (node.value() == 0) {
            return CONTINUE;
        }
        // Only attempt to combine if there is a previous node
        if (!opt_seq.empty()) {
            // try to combine with the previous node if possible
            try_combine_inc_visitor v(node.offset(), node.value(), false);
            if (opt_seq.back().accept(v) == CONTINUE) {
                // discard the combined node if it is 0
                if (v.new_value() == 0) {
                    opt_seq.pop_back();
                }
                return CONTINUE;
            }
        }
        // else make node copy
        return opt_seq_base_visitor::handle_sub(node);
    }

private:

    class try_combine_inc_visitor : public test_visitor {

        public:
            try_combine_inc_visitor(ptrdiff_t offset, bf_value val, bool isAdd) :
                next_off(offset), next_val(val), isAdd(isAdd) {}

            bf_value new_value() {
                return new_val;
            }

            status visit(set &node) {
                if (node.offset() != next_off) {
                    return BREAK;
                }
                new_val = node.value();
                isAdd ? new_val += next_val : new_val -= next_val;
                node.value(new_val);
                return CONTINUE;
            }

            status visit(const set &node) {
                if (node.offset() != next_off) {
                    return BREAK;
                }
                new_val = node.value();
                isAdd ? new_val += next_val : new_val -= next_val;
                node.value(new_val);
                return CONTINUE;
            }

            status visit(add &node) {
                if (node.offset() != next_off) {
                    return BREAK;
                }
                new_val = node.value();
                isAdd ? new_val += next_val : new_val -= next_val;
                node.value(new_val);
                return CONTINUE;
            }

            status visit(const add &node) {
                if (node.offset() != next_off) {
                    return BREAK;
                }
                new_val = node.value();
                isAdd ? new_val += next_val : new_val -= next_val;
                node.value(new_val);
                return CONTINUE;
            }

            status visit(sub &node) {
                if (node.offset() != next_off) {
                    return BREAK;
                }
                new_val = node.value();
                isAdd ? new_val -= next_val : new_val += next_val;
                node.value(new_val);
                return CONTINUE;
            }

            status visit(const sub &node) {
                if (node.offset() != next_off) {
                    return BREAK;
                }
                new_val = node.value();
                isAdd ? new_val -= next_val : new_val += next_val;
                node.value(new_val);
                return CONTINUE;
            }

        private:
            bool isAdd;
            ptrdiff_t next_off;
            bf_value next_val;
            bf_value new_val;

    };

};

}
}

#endif /* !BFC_COMBINE_INC_VISITOR_HPP */
<commit_msg>Fix mutating const nodes in inc visitor<commit_after>#ifndef BFC_COMBINE_INC_VISITOR_HPP
#define BFC_COMBINE_INC_VISITOR_HPP

#include "ast/mod.hpp"
#include "ast/base.hpp"
#include "test_visitor.hpp"
#include "types.h"

namespace bfc {
namespace ast {

class combine_inc_visitor : public opt_seq_base_visitor {

public:

    status visit(add &node) {
        // discard any zero value node
        if (node.value() == 0) {
            return CONTINUE;
        }
        // Only attempt to combine if there is a previous node
        if (!opt_seq.empty()) {
            // try to combine with the previous node if possible
            try_combine_inc_visitor v(node.offset(), node.value(), true);
            if (opt_seq.back().accept(v) == CONTINUE) {
                opt_seq.pop_back();
                // discard the combined node if it is 0
                if (v.new_value() != 0) {
                    if (v.type() == ADD) {
                        opt_seq.emplace_back(new add(node.loc(), node.offset(), v.new_value());
                    } else {
                        opt_seq.emplace_back(new sub(node.loc(), node.offset(), v.new_value());
                    }
                }
                return CONTINUE;
            }
        }
        // else make node copy
        return opt_seq_base_visitor::handle_add(node);
    }

    status visit(const add &node) {
        // discard any zero value node
        if (node.value() == 0) {
            return CONTINUE;
        }
        // Only attempt to combine if there is a previous node
        if (!opt_seq.empty()) {
            // try to combine with the previous node if possible
            try_combine_inc_visitor v(node.offset(), node.value(), true);
            if (opt_seq.back().accept(v) == CONTINUE) {
                opt_seq.pop_back();
                // discard the combined node if it is 0
                if (v.new_value() != 0) {
                    if (v.type() == ADD) {
                        opt_seq.emplace_back(new add(node.loc(), node.offset(), v.new_value());
                    } else {
                        opt_seq.emplace_back(new sub(node.loc(), node.offset(), v.new_value());
                    }
                }
                return CONTINUE;
            }
        }
        // else make node copy
        return opt_seq_base_visitor::handle_add(node);
    }

    status visit(sub &node) {
        // discard any zero value node
        if (node.value() == 0) {
            return CONTINUE;
        }
        // Only attempt to combine if there is a previous node
        if (!opt_seq.empty()) {
            // try to combine with the previous node if possible
            try_combine_inc_visitor v(node.offset(), node.value(), false);
            if (opt_seq.back().accept(v) == CONTINUE) {
                opt_seq.pop_back();
                // discard the combined node if it is 0
                if (v.new_value() != 0) {
                    if (v.type() == ADD) {
                        opt_seq.emplace_back(new add(node.loc(), node.offset(), v.new_value());
                    } else {
                        opt_seq.emplace_back(new sub(node.loc(), node.offset(), v.new_value());
                    }
                    return CONTINUE;
                }
            }
        }
        // else make node copy
        return opt_seq_base_visitor::handle_sub(node);
    }

    status visit(const sub &node) {
        // discard any zero value node
        if (node.value() == 0) {
            return CONTINUE;
        }
        // Only attempt to combine if there is a previous node
        if (!opt_seq.empty()) {
            // try to combine with the previous node if possible
            try_combine_inc_visitor v(node.offset(), node.value(), false);
            if (opt_seq.back().accept(v) == CONTINUE) {
                opt_seq.pop_back();
                // discard the combined node if it is 0
                if (v.new_value() != 0) {
                    if (v.type() == ADD) {
                        opt_seq.emplace_back(new add(node.loc(), node.offset(), v.new_value());
                    } else {
                        opt_seq.emplace_back(new sub(node.loc(), node.offset(), v.new_value());
                    }
                    return CONTINUE;
                }
                return CONTINUE;
            }
        }
        // else make node copy
        return opt_seq_base_visitor::handle_sub(node);
    }

private:

    class try_combine_inc_visitor : public test_visitor {

        enum node_type {
            ADD = 0,
            SUB
        };

        public:
            try_combine_inc_visitor(ptrdiff_t offset, bf_value val, bool isAdd) :
                next_off(offset), next_val(val), isAdd(isAdd) {}

            bf_value new_value() {
                return new_val;
            }

            node_type type() {
                return type;
            }

            status visit(add &node) {
                if (node.offset() != next_off) {
                    return BREAK;
                }
                new_val = node.value();
                isAdd ? new_val += next_val : new_val -= next_val;
                type = ADD;
                return CONTINUE;
            }

            status visit(const add &node) {
                if (node.offset() != next_off) {
                    return BREAK;
                }
                new_val = node.value();
                isAdd ? new_val += next_val : new_val -= next_val;
                type = ADD;
                return CONTINUE;
            }

            status visit(sub &node) {
                if (node.offset() != next_off) {
                    return BREAK;
                }
                new_val = node.value();
                isAdd ? new_val -= next_val : new_val += next_val;
                type = SUB;
                return CONTINUE;
            }

            status visit(const sub &node) {
                if (node.offset() != next_off) {
                    return BREAK;
                }
                new_val = node.value();
                isAdd ? new_val -= next_val : new_val += next_val;
                type = SUB;
                return CONTINUE;
            }

        private:
            bool isAdd;
            ptrdiff_t next_off;
            bf_value next_val;
            bf_value new_val;
            node_type type;
    };

};

}
}

#endif /* !BFC_COMBINE_INC_VISITOR_HPP */
<|endoftext|>


<commit_before>/*
 * jcom.push (previously names tl.push)
 * By Trond Lossius, Copyright 2011
 *
 * Simple physical modelling: Push an object about within a confined space
 * Can be used for e.g. trajectories
 *
 * License: This code is licensed under the terms of the "New BSD License"
 * http://creativecommons.org/licenses/BSD/
 */

/*
	<---MAXREF

		/maxref/object/name
			jcom.push

		/maxref/object/digest
			Calculate difference between incomming numbers

		/maxref/object/description
			<o>jcom.push</o> calculates the difference between the last incomming value x[n]
			and the previous value received:

			push = x[n]-x[n-1]

		/maxref/metadata/author
			Trond Lossius

		/maxref/metadata/tag
			Jamoma Max Math

		/maxref/inletlist/0
			Calculate Difference, int, float

		/maxref/outletlist/0
			Delta Value

		/maxref/outletlist/1
			Dumpout

		/maxref/argument/
			None

		/maxref/message/float
			Caculate difference using between this and the previous number received.

		/maxref/message/int
			Converted to float

		/maxref/example/image
			jcom.push.gif

		/maxref/example/caption
			Calculate difference between the last two numbers received.

		/maxref/seealso/object/name
			jcom.push2

		/maxref/seealso/object/description
			Calculate the 2nd order difference of incomming numbers.

		/maxref/seealso/object/name
			jcom.velocity

		/maxref/seealso/object/description
			Calculate velocity (rate of change per second) for incomming values.

	MAXREF--->
*/

#include "Jamoma.h"

#define nonzero(x)				((x > 0) ? x : 1.)
#define MAXDIMENSIONS			10

typedef struct _push{								///< Data structure for this object
	t_object	ob;									///< Must always be the first field; used by Max
	float		previousPosition[MAXDIMENSIONS];	///< The previous position
	float		previousVelocity[MAXDIMENSIONS];	///< The previous velocity
	float		attrFriction;						///< Friction coefficient
	int			attrDimensions;						///< The number of dimensions used
	float		attrSize[MAXDIMENSIONS];			///< Room size, defined individually for each dimension
	float		force[MAXDIMENSIONS];				///< Force applied on the object
	void		*outlet;							///< Pointer to outlet. Need one for each outlet
} t_push;

// Prototypes for methods: need a method for each incoming message
void *push_new(t_symbol *msg, long argc, t_atom *argv);
void push_bang(t_push *x);
void push_force(t_push *x, t_symbol *s, long argc, t_atom *argv);
void push_clear(t_push *x);
void push_assist(t_push *x, void *b, long msg, long arg, char *dst);
t_max_err push_attr_setdimensions(t_push *x, void *attr, long argc, t_atom *argv);
t_max_err push_attr_setfriction(t_push *x, void *attr, long argc, t_atom *argv);
t_max_err push_attr_setsize(t_push *x, void *attr, long argc, t_atom *argv);
t_max_err push_attr_getsize(t_push *x, void *attr, long *argc, t_atom **argv);

// Globals
t_class		*this_class;				// Required. Global pointing to this class

/************************************************************************************/
// Main() Function

int JAMOMA_EXPORT_MAXOBJ main(void)
{
	t_class *c;

	jamoma_init();
	common_symbols_init();

	// Define our class
	c = class_new("jcom.push",(method)push_new, (method)0L, sizeof(t_push), (method)0L, A_GIMME, 0);

	// Make methods accessible for our class:
	class_addmethod(c, (method)push_bang,				"bang",		A_CANT,		0);
	class_addmethod(c, (method)push_force,				"force",	A_GIMME,	0);
	class_addmethod(c, (method)push_clear,				"clear",	0);
	class_addmethod(c, (method)push_assist, 			"assist",	A_CANT,		0);
	class_addmethod(c, (method)object_obex_dumpout, 	"dumpout",	A_CANT,		0);

	CLASS_ATTR_FLOAT(c,		"friction",			0,		t_push,	attrFriction);
	CLASS_ATTR_ACCESSORS(c,	"friction",			NULL,	push_attr_setfriction);

	// Add attributes to our class:
	CLASS_ATTR_LONG(c,		"dimensions",		0,		t_push,	attrDimensions);
	CLASS_ATTR_ACCESSORS(c,	"dimensions",		NULL,	push_attr_setdimensions);

	CLASS_ATTR_ATOM(c,		"size",				0,		t_push, attrSize);
	CLASS_ATTR_ACCESSORS(c,	"size",		push_attr_getsize,	push_attr_setsize);

	// Finalize our class
	class_register(CLASS_BOX, c);
	this_class = c;
	return 0;
}

#pragma mark -
#pragma mark Object life
/************************************************************************************/
// Object Life

void *push_new(t_symbol *msg, long argc, t_atom *argv)
{
	t_push *x;
	int i;

	x = (t_push *)object_alloc(this_class);	// create the new instance and return a pointer to it
	if (x) {
		// create inlets and outlets
    	object_obex_store((void *)x, _sym_dumpout, (object *)outlet_new(x,NULL));	// dumpout
		x->outlet = floatout(x);			// velocity
		x->attrDimensions = 3;
		x->attrFriction = 0.1;
		for (i=0; i<MAXDIMENSIONS; i++)
			x->attrSize[i] = 40.0;			// This is the same default as for ViMiC
		push_clear(x);						// initilaize instance
		attr_args_process(x, argc, argv);	// handle attribute args

	}
	return (x);
}

/************************************************************************************/
// Methods bound to attributes
#pragma mark -
#pragma mark attribute accessors

// ATTRIBUTE: dimensions
t_max_err push_attr_setdimensions(t_push *x, void *attr, long argc, t_atom *argv)
{
	long n;

	if (argc && argv) {
		n = atom_getlong(argv);
		if (n<1) n = 1;
		if (n>MAXDIMENSIONS) n = MAXDIMENSIONS;
		x->attrDimensions = n;
	}
	push_clear(x);
	return MAX_ERR_NONE;
}

// ATTRIBUTE: dimensions (1-3)
t_max_err push_attr_setfriction(t_push *x, void *attr, long argc, t_atom *argv)
{
	float f;

	if (argc && argv) {
		f = atom_getfloat(argv);
		if (f<=0.0 || f>=1.0) {
			error("Invalid argument for friction. Must be in the range (0, 1)");
			return MAX_ERR_NONE;
		}
		x->attrFriction = f;
	}
	return MAX_ERR_NONE;
}

t_max_err push_attr_setsize(t_push *x, void *attr, long argc, t_atom *argv)
{
	int i;
	float f;

	if ((argc==x->attrDimensions) && argv) {
		for (i=0; i<x->attrDimensions; i++) {
			f = atom_getfloat(argv);
			if (f>0.0) {
				x->attrSize[i] = f;
				argv++;
			}
			else
				post("jcom.push: Ignored faulty value for size");
		}
	}
	return MAX_ERR_NONE;
}

t_max_err push_attr_getsize(t_push *x, void *attr, long *argc, t_atom **argv)
{
	int i;

	*argc = x->attrDimensions;
	*argv = (t_atom*)sysmem_newptr((sizeof(t_atom))*x->attrDimensions);
	for (i=0; i<x->attrDimensions; i++) {
		atom_setfloat(*argv+i, x->attrSize[i]);
	}

	return MAX_ERR_NONE;
	// TODO: We need to free the memory assigned for argv
}

#pragma mark -
#pragma mark methods
/************************************************************************************/
// Methods bound to input/inlets

// BANG input
void push_bang(t_push *x)
{
	int i;
	float position[MAXDIMENSIONS];
	t_atom a[MAXDIMENSIONS];

	for (i=0; i<x->attrDimensions; i++) {
		position[i] = x->previousPosition[i] + (1.0-x->attrFriction)*x->previousVelocity[i] + x->force[i];
		x->previousVelocity[i] = position[i] - x->previousPosition[i];
		x->previousPosition[i] = position[i];
		atom_setfloat(&a[i], position[i]);
		x->force[i] = 0; 		// Force is reset to zero when it has been applied
	}
	outlet_anything(x->outlet, _sym_list, x->attrDimensions, a);
}

// FORCE input
void push_force(t_push *x, t_symbol *s, long argc, t_atom *argv)
{
	int i;

	if (argc==x->attrDimensions) {
		for (i=0; i<x->attrDimensions; i++) {
			x->force[i] = atom_getfloat(argv);
			argv++;
		}
	}
	else {
		post("jcom.push: force vector has wrong dimension");
		return;
	}
}

// CLEAR input
void push_clear(t_push *x)
{
	int i;

	for (i=0; i< x->attrDimensions; i++) {
		x->previousPosition[i] = 0.0;
		x->previousVelocity[i] = 0.0;
		x->force[i] = 0.0;
	}
	push_bang(x);
}

// Method for Assistance Messages
void push_assist(t_push *x, void *b, long msg, long arg, char *dst)	// Display assistance messages
{
	if (msg==1)
	{
		switch(arg)
		{
			case 0:
				strcpy(dst, "(list) force applied to object");
				break;
		}
	}
	else if (msg==2)
	{
		switch(arg)
		{
			case 0:
				strcpy(dst, "(list) resulting position of object");
				break;
			case 1:
				strcpy(dst, "dumpout");
				break;
		}
	}
}
<commit_msg>Adding boundary mode, currently crashing if opening the inspector<commit_after>/*
 * jcom.push (previously names tl.push)
 * By Trond Lossius, Copyright 2011
 *
 * Simple physical modelling: Push an object about within a confined space
 * Can be used for e.g. trajectories
 *
 * License: This code is licensed under the terms of the "New BSD License"
 * http://creativecommons.org/licenses/BSD/
 */

/*
	<---MAXREF

		/maxref/object/name
			jcom.push

		/maxref/object/digest
			Calculate difference between incomming numbers

		/maxref/object/description
			<o>jcom.push</o> calculates the difference between the last incomming value x[n]
			and the previous value received:

			push = x[n]-x[n-1]

		/maxref/metadata/author
			Trond Lossius

		/maxref/metadata/tag
			Jamoma Max Math

		/maxref/inletlist/0
			Calculate Difference, int, float

		/maxref/outletlist/0
			Delta Value

		/maxref/outletlist/1
			Dumpout

		/maxref/argument/
			None

		/maxref/message/float
			Caculate difference using between this and the previous number received.

		/maxref/message/int
			Converted to float

		/maxref/example/image
			jcom.push.gif

		/maxref/example/caption
			Calculate difference between the last two numbers received.

		/maxref/seealso/object/name
			jcom.push2

		/maxref/seealso/object/description
			Calculate the 2nd order difference of incomming numbers.

		/maxref/seealso/object/name
			jcom.velocity

		/maxref/seealso/object/description
			Calculate velocity (rate of change per second) for incomming values.

	MAXREF--->
*/

#include "Jamoma.h"
#include "TTAudioObject.h"	// use the ttblue clipping functions

#define nonzero(x)				((x > 0) ? x : 1.)
#define MAXDIMENSIONS			10

t_symbol*		ps_clip;

typedef struct _push{								///< Data structure for this object
	t_object	ob;									///< Must always be the first field; used by Max
	float		previousPosition[MAXDIMENSIONS];	///< The previous position
	float		previousVelocity[MAXDIMENSIONS];	///< The previous velocity
	float		attrFriction;						///< Friction coefficient
	int			attrDimensions;						///< The number of dimensions used
	float		attrSize[MAXDIMENSIONS];			///< Room size, defined individually for each dimension
	t_symbol*   attrBoundaryMode;					///< Boundary mode
	float		force[MAXDIMENSIONS];				///< Force applied on the object
	void		*outlet;							///< Pointer to outlet. Need one for each outlet
} t_push;

// Prototypes for methods: need a method for each incoming message
void *push_new(t_symbol *msg, long argc, t_atom *argv);
void push_bang(t_push *x);
void push_force(t_push *x, t_symbol *s, long argc, t_atom *argv);
void push_clear(t_push *x);
void push_assist(t_push *x, void *b, long msg, long arg, char *dst);
t_max_err push_attr_setdimensions(t_push *x, void *attr, long argc, t_atom *argv);
t_max_err push_attr_setfriction(t_push *x, void *attr, long argc, t_atom *argv);
t_max_err push_attr_setsize(t_push *x, void *attr, long argc, t_atom *argv);
t_max_err push_attr_getsize(t_push *x, void *attr, long *argc, t_atom **argv);

// Globals
t_class		*this_class;				// Required. Global pointing to this class

/************************************************************************************/
// Main() Function

int JAMOMA_EXPORT_MAXOBJ main(void)
{
	t_class *c;

	jamoma_init();
	common_symbols_init();
	ps_clip = gensym("clip");

	// Define our class
	c = class_new("jcom.push",(method)push_new, (method)0L, sizeof(t_push), (method)0L, A_GIMME, 0);

	// Make methods accessible for our class:
	class_addmethod(c, (method)push_bang,				"bang",		A_CANT,		0);
	class_addmethod(c, (method)push_force,				"force",	A_GIMME,	0);
	class_addmethod(c, (method)push_clear,				"clear",	0);
	class_addmethod(c, (method)push_assist, 			"assist",	A_CANT,		0);
	class_addmethod(c, (method)object_obex_dumpout, 	"dumpout",	A_CANT,		0);

	CLASS_ATTR_FLOAT(c,		"friction",			0,		t_push,	attrFriction);
	CLASS_ATTR_ACCESSORS(c,	"friction",			NULL,	push_attr_setfriction);

	// Add attributes to our class:
	CLASS_ATTR_LONG(c,		"dimensions",		0,		t_push,	attrDimensions);
	CLASS_ATTR_ACCESSORS(c,	"dimensions",		NULL,	push_attr_setdimensions);

	CLASS_ATTR_ATOM(c,		"size",				0,		t_push, attrSize);
	CLASS_ATTR_ACCESSORS(c,	"size",		push_attr_getsize,	push_attr_setsize);

	// ATTRIBUTE: boundary mode - options are none, clip, wrap, fold, repel
	jamoma_class_attr_new(c, 		"boundary",	 	_sym_symbol, (method)jcom_core_attr_setclipmode, (method)jcom_core_attr_getclipmode);
	CLASS_ATTR_ENUM(c,				"boundary",		0,	(char*)"none clip bounce fold repel");

	// Finalize our class
	class_register(CLASS_BOX, c);
	this_class = c;
	return 0;
}

#pragma mark -
#pragma mark Object life
/************************************************************************************/
// Object Life

void *push_new(t_symbol *msg, long argc, t_atom *argv)
{
	t_push *x;
	int i;

	x = (t_push *)object_alloc(this_class);	// create the new instance and return a pointer to it
	if (x) {
		// create inlets and outlets
    	object_obex_store((void *)x, _sym_dumpout, (object *)outlet_new(x,NULL));	// dumpout
		x->outlet = floatout(x);			// velocity
		x->attrDimensions = 3;
		x->attrFriction = 0.1;
		for (i=0; i<MAXDIMENSIONS; i++)
			x->attrSize[i] = 40.0;			// This is the same default as for ViMiC
		push_clear(x);						// initilaize instance
		attr_args_process(x, argc, argv);	// handle attribute args

	}
	return (x);
}

/************************************************************************************/
// Methods bound to attributes
#pragma mark -
#pragma mark attribute accessors

// ATTRIBUTE: dimensions
t_max_err push_attr_setdimensions(t_push *x, void *attr, long argc, t_atom *argv)
{
	long n;

	if (argc && argv) {
		n = atom_getlong(argv);
		if (n<1) n = 1;
		if (n>MAXDIMENSIONS) n = MAXDIMENSIONS;
		x->attrDimensions = n;
	}
	push_clear(x);
	return MAX_ERR_NONE;
}

// ATTRIBUTE: dimensions (1-3)
t_max_err push_attr_setfriction(t_push *x, void *attr, long argc, t_atom *argv)
{
	float f;

	if (argc && argv) {
		f = atom_getfloat(argv);
		if (f<=0.0 || f>=1.0) {
			error("Invalid argument for friction. Must be in the range (0, 1)");
			return MAX_ERR_NONE;
		}
		x->attrFriction = f;
	}
	return MAX_ERR_NONE;
}

t_max_err push_attr_setsize(t_push *x, void *attr, long argc, t_atom *argv)
{
	int i;
	float f;

	if ((argc==x->attrDimensions) && argv) {
		for (i=0; i<x->attrDimensions; i++) {
			f = atom_getfloat(argv);
			if (f>0.0) {
				x->attrSize[i] = f;
				argv++;
			}
			else
				post("jcom.push: Ignored faulty value for size");
		}
	}
	return MAX_ERR_NONE;
}

t_max_err push_attr_getsize(t_push *x, void *attr, long *argc, t_atom **argv)
{
	int i;

	*argc = x->attrDimensions;
	*argv = (t_atom*)sysmem_newptr((sizeof(t_atom))*x->attrDimensions);
	for (i=0; i<x->attrDimensions; i++) {
		atom_setfloat(*argv+i, x->attrSize[i]);
	}

	return MAX_ERR_NONE;
	// TODO: We need to free the memory assigned for argv
}

#pragma mark -
#pragma mark methods
/************************************************************************************/
// Methods bound to input/inlets

// BANG input
void push_bang(t_push *x)
{
	int i;
	float position, rangeLow, rangeHigh;
	t_atom a[MAXDIMENSIONS];

	for (i=0; i<x->attrDimensions; i++) {
		position = x->previousPosition[i] + (1.0-x->attrFriction)*x->previousVelocity[i] + x->force[i];

		x->previousVelocity[i] = position - x->previousPosition[i];

		rangeHigh = 0.5*x->attrSize[i];
		rangeHigh = - rangeHigh;
		if (x->attrBoundaryMode == ps_clip)
			TTLimit(position, rangeLow, rangeHigh);
		else if (x->attrBoundaryMode == jps_wrap)
			position = TTInfWrap(position, rangeLow, rangeHigh);
		else if (x->attrBoundaryMode == jps_fold)
			position = TTFold(position, rangeLow, rangeHigh);

		x->previousPosition[i] = position;

		atom_setfloat(&a[i], position);
		x->force[i] = 0; 		// Force is reset to zero when it has been applied
	}

	outlet_anything(x->outlet, _sym_list, x->attrDimensions, a);
}

// FORCE input
void push_force(t_push *x, t_symbol *s, long argc, t_atom *argv)
{
	int i;

	if (argc==x->attrDimensions) {
		for (i=0; i<x->attrDimensions; i++) {
			x->force[i] = atom_getfloat(argv);
			argv++;
		}
	}
	else {
		post("jcom.push: force vector has wrong dimension");
		return;
	}
}

// CLEAR input
void push_clear(t_push *x)
{
	int i;

	for (i=0; i< x->attrDimensions; i++) {
		x->previousPosition[i] = 0.0;
		x->previousVelocity[i] = 0.0;
		x->force[i] = 0.0;
	}
	push_bang(x);
}

// Method for Assistance Messages
void push_assist(t_push *x, void *b, long msg, long arg, char *dst)	// Display assistance messages
{
	if (msg==1)
	{
		switch(arg)
		{
			case 0:
				strcpy(dst, "(list) force applied to object");
				break;
		}
	}
	else if (msg==2)
	{
		switch(arg)
		{
			case 0:
				strcpy(dst, "(list) resulting position of object");
				break;
			case 1:
				strcpy(dst, "dumpout");
				break;
		}
	}
}
<|endoftext|>


<commit_before>// ========================================================================================
//  ApproxMVBB
//  Copyright (C) 2014 by Gabriel Nützi <nuetzig (at) imes (d0t) mavt (d0t) ethz (døt) ch>
//
//  This Source Code Form is subject to the terms of the Mozilla Public
//  License, v. 2.0. If a copy of the MPL was not distributed with this
//  file, You can obtain one at http://mozilla.org/MPL/2.0/.
// ========================================================================================

#ifndef ApproxMVBB_Common_MyMatrixTypeDefs_hpp
#define ApproxMVBB_Common_MyMatrixTypeDefs_hpp

#include "ApproxMVBB/Common/Platform.hpp"

//#define EIGEN_DONT_VECTORIZE
//#define EIGEN_DISABLE_UNALIGNED_ARRAY_ASSERT

#include <Eigen/Dense>

namespace ApproxMVBB{

// ================================================================================================
/** @brief This
*	These are some small matrix definitions.
*/

namespace MyMatrix {

    template<typename Scalar>
    using  Matrix44 =  Eigen::Matrix<Scalar, 4, 4>;
    template<typename Scalar>
    using  Matrix43 =  Eigen::Matrix<Scalar, 4, 3>;
    template<typename Scalar>
    using  Matrix34 =  Eigen::Matrix<Scalar, 3, 4>;
    template<typename Scalar>
    using  Matrix33 =  Eigen::Matrix<Scalar, 3, 3>;
    template<typename Scalar>
    using  Matrix32 =  Eigen::Matrix<Scalar, 3, 2>;
    template<typename Scalar>
    using  Matrix23 =  Eigen::Matrix<Scalar, 2, 3>;
    template<typename Scalar>
    using  Matrix22 =  Eigen::Matrix<Scalar, 2, 2>;
    template<typename Scalar>
    using  Vector3 =  Eigen::Matrix<Scalar, 3, 1>;
    template<typename Scalar>
    using  Vector2 =  Eigen::Matrix<Scalar, 2, 1>;

    template<typename Scalar>
    using  Quaternion =  Eigen::Quaternion<Scalar>;
    template<typename Scalar>
    using  AngleAxis =  Eigen::AngleAxis<Scalar>;

    template<typename Scalar>
    using  Vector4 =  Eigen::Matrix<Scalar, 4, 1>;
    template<typename Scalar>
    using  Vector6 =  Eigen::Matrix<Scalar, 6, 1>;
    template<typename Scalar>
    using  VectorDyn =  Eigen::Matrix<Scalar, Eigen::Dynamic , 1 >;

    template<typename Scalar>
    using  MatrixDynDyn =  Eigen::Matrix<Scalar, Eigen::Dynamic , Eigen::Dynamic >;
    template<typename Scalar>
    using  MatrixDiagDyn =  Eigen::DiagonalMatrix<Scalar, Eigen::Dynamic >;
    template<typename Scalar>
    using  MatrixDynDynRow =  Eigen::Matrix<Scalar, Eigen::Dynamic , Eigen::Dynamic, Eigen::RowMajor>;

    template<typename Scalar,  int M>
    using  MatrixStatDyn =  Eigen::Matrix<Scalar, M, Eigen::Dynamic >;
    template<typename Scalar, int N>
    using  MatrixDynStat =  Eigen::Matrix<Scalar, Eigen::Dynamic, N >;
    template<typename Scalar, int M,  int N>
    using  MatrixStatStat =  Eigen::Matrix<Scalar, M, N >;
    template<typename Scalar, int M>
    using  VectorStat =  Eigen::Matrix<Scalar, M, 1 >;

    template<typename Scalar>
    using  AffineTrafo =  Eigen::Transform<Scalar,3,Eigen::TransformTraits::Affine>;
    template<typename Scalar>
    using  AffineTrafo2d =  Eigen::Transform<Scalar,2,Eigen::TransformTraits::Affine>;

    template<typename Scalar, int M>
    using  ArrayStatDyn =  Eigen::Array<Scalar, M, Eigen::Dynamic >;
    template<typename Scalar, int N>
    using  ArrayDynStat =  Eigen::Array<Scalar, Eigen::Dynamic, N >;
    template<typename Scalar, int M,  int N>
    using  ArrayStatStat =  Eigen::Array<Scalar, M, N >;
    template<typename Scalar, int M>
    using  ArrayStat =  Eigen::Array<Scalar, M,1>;

    template<typename Scalar>
    using  Array3 =  Eigen::Array<Scalar, 3, 1>;
    template<typename Scalar>
    using  Array2 =  Eigen::Array<Scalar, 2, 1>;

}

namespace MyMatrix{

    template<typename Derived> using MatrixBase = Eigen::MatrixBase<Derived>;
    template<typename Derived> using ArrayBase = Eigen::ArrayBase<Derived>;

    template<typename Derived>                 using VectorBDyn     = Eigen::VectorBlock<Derived,Eigen::Dynamic>;
    template<typename Derived, unsigned int M> using VectorBStat    = Eigen::VectorBlock<Derived,M>;

    template<typename Derived>                 using MatrixBDynDyn  = Eigen::Block<Derived>;
    template<typename Derived, unsigned int M> using MatrixBStatDyn = Eigen::Block<Derived,M, Eigen::Dynamic>;
    template<typename Derived, unsigned int N> using MatrixBDynStat = Eigen::Block<Derived,Eigen::Dynamic,N>;

    template<typename EigenType> using MatrixRef = Eigen::Ref<EigenType>;

    template<typename EigenType> using MatrixMap = Eigen::Map<EigenType>;

}

struct APPROXMVBB_EXPORT  MyMatrixIOFormat {
     static const  Eigen::IOFormat Matlab;
     static const  Eigen::IOFormat CommaSep;
     static const  Eigen::IOFormat SpaceSep;
};

}

#define ApproxMVBB_DEFINE_MATRIX_SPECIALTYPES \
   template<typename Derived> using MatrixBase = ApproxMVBB::MyMatrix::MatrixBase<Derived>; \
   template<typename Derived> using ArrayBase  = ApproxMVBB::MyMatrix::ArrayBase<Derived>; \
   \
   template<typename Derived> using VectorBDyn = ApproxMVBB::MyMatrix::VectorBDyn<Derived>; \
   template<typename Derived,unsigned int M> using VectorBStat = ApproxMVBB::MyMatrix::VectorBStat<Derived,M>; \
   \
   template<typename Derived> using MatrixBDynDyn = ApproxMVBB::MyMatrix::MatrixBDynDyn<Derived>; \
   template<typename Derived, unsigned int N> using MatrixBDynStat = ApproxMVBB::MyMatrix::MatrixBDynStat<Derived,N>; \
   template<typename Derived, unsigned int M> using MatrixBStatDyn = ApproxMVBB::MyMatrix::MatrixBStatDyn<Derived,M>; \
    \
   template<typename EigenType> using MatrixRef = ApproxMVBB::MyMatrix::MatrixRef< EigenType >; \
   template<typename EigenType> using MatrixMap = ApproxMVBB::MyMatrix::MatrixMap< EigenType >; \

/**
* @brief This macro is used to typedef all custom matrix types which have nothing to do with the system.
*/
#define ApproxMVBB_DEFINE_MATRIX_TYPES_OF( _PREC_ ) \
    using Matrix44 = ApproxMVBB::MyMatrix::Matrix44< _PREC_ >; \
    using Matrix33 = ApproxMVBB::MyMatrix::Matrix33< _PREC_ >; \
    using Matrix22 = ApproxMVBB::MyMatrix::Matrix22< _PREC_ >; \
    using Matrix32 = ApproxMVBB::MyMatrix::Matrix32< _PREC_ >; \
    using Matrix23 = ApproxMVBB::MyMatrix::Matrix23< _PREC_ >; \
    using Matrix43 = ApproxMVBB::MyMatrix::Matrix43< _PREC_ >; \
    using Matrix34 = ApproxMVBB::MyMatrix::Matrix34< _PREC_ >; \
    using Vector3 = ApproxMVBB::MyMatrix::Vector3< _PREC_ >; \
    using Vector2 = ApproxMVBB::MyMatrix::Vector2< _PREC_ >; \
    using Vector4 = ApproxMVBB::MyMatrix::Vector4< _PREC_ >; \
    using Vector6 = ApproxMVBB::MyMatrix::Vector6< _PREC_ >; \
    using Quaternion = ApproxMVBB::MyMatrix::Quaternion< _PREC_ >; \
    using AngleAxis = ApproxMVBB::MyMatrix::AngleAxis< _PREC_ >; \
    using VectorDyn = ApproxMVBB::MyMatrix::VectorDyn< _PREC_ >; \
    using MatrixDynDyn = ApproxMVBB::MyMatrix::MatrixDynDyn< _PREC_ >; \
    using MatrixDiagDyn = ApproxMVBB::MyMatrix::MatrixDiagDyn< _PREC_ >; \
    using MatrixDynDynRow = ApproxMVBB::MyMatrix::MatrixDynDynRow< _PREC_ >; \
    \
    template<unsigned int M> using MatrixStatDyn = ApproxMVBB::MyMatrix::MatrixStatDyn< _PREC_, M>; \
    template<unsigned int N> using MatrixDynStat = ApproxMVBB::MyMatrix::MatrixDynStat< _PREC_, N>; \
    template<unsigned int M,unsigned int N> using MatrixStatStat = ApproxMVBB::MyMatrix::MatrixStatStat< _PREC_, M,N>; \
    template<unsigned int M> using VectorStat = ApproxMVBB::MyMatrix::VectorStat< _PREC_, M>; \
    \
    using AffineTrafo = ApproxMVBB::MyMatrix::AffineTrafo< _PREC_ >; \
    using AffineTrafo2d = ApproxMVBB::MyMatrix::AffineTrafo2d< _PREC_ >; \
    \
    template<unsigned int M> using ArrayStatDyn = ApproxMVBB::MyMatrix::ArrayStatDyn< _PREC_, M>; \
    template<unsigned int N> using ArrayDynStat = ApproxMVBB::MyMatrix::ArrayDynStat< _PREC_, N>; \
    template<unsigned int M,unsigned int N> using ArrayStatStat = ApproxMVBB::MyMatrix::ArrayStatStat< _PREC_, M,N>; \
    template<unsigned int M> using ArrayStat = ApproxMVBB::MyMatrix::ArrayStat< _PREC_, M>; \
    using Array3 = ApproxMVBB::MyMatrix::Array3< _PREC_ >; \
    using Array2 = ApproxMVBB::MyMatrix::Array2< _PREC_ >; \
    \
    ApproxMVBB_DEFINE_MATRIX_SPECIALTYPES

#endif

<commit_msg>corrected some template alias miss match in ApproxMVBB_DEFINE macros<commit_after>// ========================================================================================
//  ApproxMVBB
//  Copyright (C) 2014 by Gabriel Nützi <nuetzig (at) imes (d0t) mavt (d0t) ethz (døt) ch>
//
//  This Source Code Form is subject to the terms of the Mozilla Public
//  License, v. 2.0. If a copy of the MPL was not distributed with this
//  file, You can obtain one at http://mozilla.org/MPL/2.0/.
// ========================================================================================

#ifndef ApproxMVBB_Common_MyMatrixTypeDefs_hpp
#define ApproxMVBB_Common_MyMatrixTypeDefs_hpp

#include "ApproxMVBB/Common/Platform.hpp"

//#define EIGEN_DONT_VECTORIZE
//#define EIGEN_DISABLE_UNALIGNED_ARRAY_ASSERT

#include <Eigen/Dense>

namespace ApproxMVBB{

// ================================================================================================
/** @brief This
*	These are some small matrix definitions.
*/

namespace MyMatrix {

    template<typename Scalar>
    using  Matrix44 =  Eigen::Matrix<Scalar, 4, 4>;
    template<typename Scalar>
    using  Matrix43 =  Eigen::Matrix<Scalar, 4, 3>;
    template<typename Scalar>
    using  Matrix34 =  Eigen::Matrix<Scalar, 3, 4>;
    template<typename Scalar>
    using  Matrix33 =  Eigen::Matrix<Scalar, 3, 3>;
    template<typename Scalar>
    using  Matrix32 =  Eigen::Matrix<Scalar, 3, 2>;
    template<typename Scalar>
    using  Matrix23 =  Eigen::Matrix<Scalar, 2, 3>;
    template<typename Scalar>
    using  Matrix22 =  Eigen::Matrix<Scalar, 2, 2>;
    template<typename Scalar>
    using  Vector3 =  Eigen::Matrix<Scalar, 3, 1>;
    template<typename Scalar>
    using  Vector2 =  Eigen::Matrix<Scalar, 2, 1>;

    template<typename Scalar>
    using  Quaternion =  Eigen::Quaternion<Scalar>;
    template<typename Scalar>
    using  AngleAxis =  Eigen::AngleAxis<Scalar>;

    template<typename Scalar>
    using  Vector4 =  Eigen::Matrix<Scalar, 4, 1>;
    template<typename Scalar>
    using  Vector6 =  Eigen::Matrix<Scalar, 6, 1>;
    template<typename Scalar>
    using  VectorDyn =  Eigen::Matrix<Scalar, Eigen::Dynamic , 1 >;

    template<typename Scalar>
    using  MatrixDynDyn =  Eigen::Matrix<Scalar, Eigen::Dynamic , Eigen::Dynamic >;
    template<typename Scalar>
    using  MatrixDiagDyn =  Eigen::DiagonalMatrix<Scalar, Eigen::Dynamic >;
    template<typename Scalar>
    using  MatrixDynDynRow =  Eigen::Matrix<Scalar, Eigen::Dynamic , Eigen::Dynamic, Eigen::RowMajor>;

    template<typename Scalar,  int M>
    using  MatrixStatDyn =  Eigen::Matrix<Scalar, M, Eigen::Dynamic >;
    template<typename Scalar, int N>
    using  MatrixDynStat =  Eigen::Matrix<Scalar, Eigen::Dynamic, N >;
    template<typename Scalar, int M,  int N>
    using  MatrixStatStat =  Eigen::Matrix<Scalar, M, N >;
    template<typename Scalar, int M>
    using  VectorStat =  Eigen::Matrix<Scalar, M, 1 >;

    template<typename Scalar>
    using  AffineTrafo =  Eigen::Transform<Scalar,3,Eigen::TransformTraits::Affine>;
    template<typename Scalar>
    using  AffineTrafo2d =  Eigen::Transform<Scalar,2,Eigen::TransformTraits::Affine>;

    template<typename Scalar, int M>
    using  ArrayStatDyn =  Eigen::Array<Scalar, M, Eigen::Dynamic >;
    template<typename Scalar, int N>
    using  ArrayDynStat =  Eigen::Array<Scalar, Eigen::Dynamic, N >;
    template<typename Scalar, int M,  int N>
    using  ArrayStatStat =  Eigen::Array<Scalar, M, N >;
    template<typename Scalar, int M>
    using  ArrayStat =  Eigen::Array<Scalar, M,1>;

    template<typename Scalar>
    using  Array3 =  Eigen::Array<Scalar, 3, 1>;
    template<typename Scalar>
    using  Array2 =  Eigen::Array<Scalar, 2, 1>;

}

namespace MyMatrix{

    template<typename Derived> using MatrixBase = Eigen::MatrixBase<Derived>;
    template<typename Derived> using ArrayBase = Eigen::ArrayBase<Derived>;

    template<typename Derived>                 using VectorBDyn     = Eigen::VectorBlock<Derived,Eigen::Dynamic>;
    template<typename Derived, unsigned int M> using VectorBStat    = Eigen::VectorBlock<Derived,M>;

    template<typename Derived>                 using MatrixBDynDyn  = Eigen::Block<Derived>;
    template<typename Derived, unsigned int M> using MatrixBStatDyn = Eigen::Block<Derived,M, Eigen::Dynamic>;
    template<typename Derived, unsigned int N> using MatrixBDynStat = Eigen::Block<Derived,Eigen::Dynamic,N>;

    template<typename EigenType> using MatrixRef = Eigen::Ref<EigenType>;

    template<typename EigenType> using MatrixMap = Eigen::Map<EigenType>;

}

struct APPROXMVBB_EXPORT  MyMatrixIOFormat {
     static const  Eigen::IOFormat Matlab;
     static const  Eigen::IOFormat CommaSep;
     static const  Eigen::IOFormat SpaceSep;
};

}

#define ApproxMVBB_DEFINE_MATRIX_SPECIALTYPES \
   template<typename Derived> using MatrixBase = ApproxMVBB::MyMatrix::MatrixBase<Derived>; \
   template<typename Derived> using ArrayBase  = ApproxMVBB::MyMatrix::ArrayBase<Derived>; \
   \
   template<typename Derived> using VectorBDyn = ApproxMVBB::MyMatrix::VectorBDyn<Derived>; \
   template<typename Derived,unsigned int M> using VectorBStat = ApproxMVBB::MyMatrix::VectorBStat<Derived,M>; \
   \
   template<typename Derived> using MatrixBDynDyn = ApproxMVBB::MyMatrix::MatrixBDynDyn<Derived>; \
   template<typename Derived, unsigned int N> using MatrixBDynStat = ApproxMVBB::MyMatrix::MatrixBDynStat<Derived,N>; \
   template<typename Derived, unsigned int M> using MatrixBStatDyn = ApproxMVBB::MyMatrix::MatrixBStatDyn<Derived,M>; \
    \
   template<typename EigenType> using MatrixRef = ApproxMVBB::MyMatrix::MatrixRef< EigenType >; \
   template<typename EigenType> using MatrixMap = ApproxMVBB::MyMatrix::MatrixMap< EigenType >; \

/**
* @brief This macro is used to typedef all custom matrix types which have nothing to do with the system.
*/
#define ApproxMVBB_DEFINE_MATRIX_TYPES_OF( _PREC_ ) \
    using Matrix44 = ApproxMVBB::MyMatrix::Matrix44< _PREC_ >; \
    using Matrix33 = ApproxMVBB::MyMatrix::Matrix33< _PREC_ >; \
    using Matrix22 = ApproxMVBB::MyMatrix::Matrix22< _PREC_ >; \
    using Matrix32 = ApproxMVBB::MyMatrix::Matrix32< _PREC_ >; \
    using Matrix23 = ApproxMVBB::MyMatrix::Matrix23< _PREC_ >; \
    using Matrix43 = ApproxMVBB::MyMatrix::Matrix43< _PREC_ >; \
    using Matrix34 = ApproxMVBB::MyMatrix::Matrix34< _PREC_ >; \
    using Vector3 = ApproxMVBB::MyMatrix::Vector3< _PREC_ >; \
    using Vector2 = ApproxMVBB::MyMatrix::Vector2< _PREC_ >; \
    using Vector4 = ApproxMVBB::MyMatrix::Vector4< _PREC_ >; \
    using Vector6 = ApproxMVBB::MyMatrix::Vector6< _PREC_ >; \
    using Quaternion = ApproxMVBB::MyMatrix::Quaternion< _PREC_ >; \
    using AngleAxis = ApproxMVBB::MyMatrix::AngleAxis< _PREC_ >; \
    using VectorDyn = ApproxMVBB::MyMatrix::VectorDyn< _PREC_ >; \
    using MatrixDynDyn = ApproxMVBB::MyMatrix::MatrixDynDyn< _PREC_ >; \
    using MatrixDiagDyn = ApproxMVBB::MyMatrix::MatrixDiagDyn< _PREC_ >; \
    using MatrixDynDynRow = ApproxMVBB::MyMatrix::MatrixDynDynRow< _PREC_ >; \
    \
    template<int M> using MatrixStatDyn = ApproxMVBB::MyMatrix::MatrixStatDyn< _PREC_, M>; \
    template<int N> using MatrixDynStat = ApproxMVBB::MyMatrix::MatrixDynStat< _PREC_, N>; \
    template<int M, int N> using MatrixStatStat = ApproxMVBB::MyMatrix::MatrixStatStat< _PREC_, M,N>; \
    template<int M> using VectorStat = ApproxMVBB::MyMatrix::VectorStat< _PREC_, M>; \
    \
    using AffineTrafo = ApproxMVBB::MyMatrix::AffineTrafo< _PREC_ >; \
    using AffineTrafo2d = ApproxMVBB::MyMatrix::AffineTrafo2d< _PREC_ >; \
    \
    template<int M> using ArrayStatDyn = ApproxMVBB::MyMatrix::ArrayStatDyn< _PREC_, M>; \
    template<int N> using ArrayDynStat = ApproxMVBB::MyMatrix::ArrayDynStat< _PREC_, N>; \
    template<int M,int N> using ArrayStatStat = ApproxMVBB::MyMatrix::ArrayStatStat< _PREC_, M,N>; \
    template<int M> using ArrayStat = ApproxMVBB::MyMatrix::ArrayStat< _PREC_, M>; \
    using Array3 = ApproxMVBB::MyMatrix::Array3< _PREC_ >; \
    using Array2 = ApproxMVBB::MyMatrix::Array2< _PREC_ >; \
    \
    ApproxMVBB_DEFINE_MATRIX_SPECIALTYPES

#endif

<|endoftext|>


<commit_before>/* This file is part of Mapnik (c++ mapping toolkit)
 * Copyright (C) 2006 Artem Pavlenko
 *
 * Mapnik is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */

//$Id$

// stl
#include <iostream>

// qt
#include <QtGui>
#include <QSplitter>
#include <QTreeView>
#include <QListView>
#include <QTabWidget>
#include <QList>
#include <QItemDelegate>
#include <QSlider>

// mapnik
#include <mapnik/config_error.hpp>
#include <mapnik/load_map.hpp>
#include <mapnik/save_map.hpp>

// qt
#include "mainwindow.hpp"
#include "layerlistmodel.hpp"
#include "styles_model.hpp"
#include "layerwidget.hpp"
#include "layerdelegate.hpp"
#include "about_dialog.hpp"

MainWindow::MainWindow()
   : filename_(),
     default_extent_(-20037508.3428,-20037508.3428,20037508.3428,20037508.3428)
{
   mapWidget_ = new MapWidget(this);
   QSplitter *splitter = new QSplitter(this);
   QTabWidget *tabWidget=new QTabWidget;
   layerTab_ = new LayerTab;
   layerTab_->setFocusPolicy(Qt::NoFocus);
   layerTab_->setIconSize(QSize(16,16));

   //LayerDelegate *delegate = new LayerDelegate(this);
   //layerTab_->setItemDelegate(delegate);
   //layerTab_->setItemDelegate(new QItemDelegate(this));
   //layerTab_->setViewMode(QListView::IconMode);

   layerTab_->setFlow(QListView::TopToBottom);
   tabWidget->addTab(layerTab_,tr("Layers"));

   // Styles tab
   styleTab_ = new StyleTab;
   tabWidget->addTab(styleTab_,tr("Styles"));
   splitter->addWidget(tabWidget);
   splitter->addWidget(mapWidget_);
   QList<int> list;
   list.push_back(200);
   list.push_back(600);
   splitter->setSizes(list);

   mapWidget_->setFocusPolicy(Qt::StrongFocus);
   mapWidget_->setFocus();

   //setCentralWidget(mapWidget_);
   setCentralWidget(splitter);
   createActions();
   createMenus();
   createToolBars();
   createContextMenu();

   setWindowTitle(tr("Mapnik Viewer"));
   status=new QStatusBar(this);
   status->showMessage(tr(""));
   setStatusBar(status);
   resize(800,600);

   //connect mapview to layerlist
   connect(mapWidget_, SIGNAL(mapViewChanged()),layerTab_, SLOT(update()));
   // slider
   connect(slider_,SIGNAL(valueChanged(int)),mapWidget_,SLOT(zoomToLevel(int)));
   //
   connect(layerTab_,SIGNAL(update_mapwidget()),mapWidget_,SLOT(updateMap()));
   connect(layerTab_,SIGNAL(layerSelected(int)),
           mapWidget_,SLOT(layerSelected(int)));
}

MainWindow::~MainWindow()
{
   delete mapWidget_;
}

void MainWindow::closeEvent(QCloseEvent* event)
{
   event->accept();
}

void MainWindow::createContextMenu()
{
   layerTab_->setContextMenuPolicy(Qt::ActionsContextMenu);
   layerTab_->addAction(openAct);
   layerTab_->addAction(layerInfo);
}

void MainWindow::open(QString const& path)
{
   if (path.isNull())
   {
      filename_ = QFileDialog::getOpenFileName(this,tr("Open Mapnik file"),
                                              currentPath,"*.xml");
   }
   else
   {
      filename_ = path;
   }

   if (!filename_.isEmpty())
   {
      load_map_file(filename_);
      //zoom_all();
      setWindowTitle(tr("%1 - Mapnik Viewer").arg(filename_));
   }

}

void MainWindow::reload()
{
   if (!filename_.isEmpty())
   {
      mapnik::box2d<double> bbox = mapWidget_->getMap()->getCurrentExtent();
      load_map_file(filename_);
      mapWidget_->zoomToBox(bbox);
      setWindowTitle(tr("%1 - *Reloaded*").arg(filename_));
   }
}

void MainWindow::save()
{
   QString initialPath = QDir::currentPath() + "/untitled.xml";
   QString filename = QFileDialog::getSaveFileName(this, tr("Save"),
                                                   initialPath,
                                                   tr("%1 Files (*.xml)")
                                                   .arg(QString("Mapnik definition")));
   if (!filename.isEmpty())
   {
      std::cout<<"saving "<< filename.toStdString() << std::endl;
      mapnik::save_map(*mapWidget_->getMap(),filename.toStdString());
   }
}

void MainWindow::load_map_file(QString const& filename)
{
   std::cout<<"loading "<< filename.toStdString() << std::endl;
   try
   {
      unsigned width = mapWidget_->width();
      unsigned height = mapWidget_->height();
      boost::shared_ptr<mapnik::Map> map(new mapnik::Map(width,height));
      mapnik::load_map(*map,filename.toStdString());

      mapWidget_->setMap(map);
      map->zoom_all();
      mapnik::box2d<double> const& ext = map->getCurrentExtent();
      mapWidget_->zoomToBox(ext);
      layerTab_->setModel(new LayerListModel(map,this));
      styleTab_->setModel(new StyleModel(map,this));
   }
   catch (mapnik::config_error & ex)
   {
      std::cout << ex.what() << "\n";
   }
}

void MainWindow::zoom_all()
{
   mapWidget_->defaultView();
}

void MainWindow::zoom_to_box()
{
   mapWidget_->setTool(MapWidget::ZoomToBox);
}

void MainWindow::pan()
{
   mapWidget_->setTool(MapWidget::Pan);
}

void MainWindow::info()
{
   mapWidget_->setTool(MapWidget::Info);
}

void MainWindow::pan_left()
{
   mapWidget_->panLeft();
}

void MainWindow::pan_right()
{
   mapWidget_->panRight();
}

void MainWindow::pan_up()
{
   mapWidget_->panUp();
}

void MainWindow::pan_down()
{
   mapWidget_->panDown();
}

void MainWindow::about()
{
   about_dialog dlg;
   dlg.exec();
}

void MainWindow::export_as()
{
   QAction *action = qobject_cast<QAction *>(sender());
   QByteArray fileFormat = action->data().toByteArray();
   QString initialPath = QDir::currentPath() + "/map." + fileFormat;

   QString fileName = QFileDialog::getSaveFileName(this, tr("Export As"),
                                                   initialPath,
                                                   tr("%1 Files (*.%2);;All Files (*)")
                                                   .arg(QString(fileFormat.toUpper()))
                                                   .arg(QString(fileFormat)));
   if (!fileName.isEmpty())
   {
      QPixmap const& pix = mapWidget_->pixmap();
      pix.save(fileName);
   }
}

void MainWindow::print()
{

   //Q_ASSERT(mapWidget_->pixmap());
   //QPrintDialog dialog(&printer, this);
   //if (dialog.exec()) {
   //	QPainter painter(&printer);
   //	QRect rect = painter.viewport();
   //	QSize size = mapWidget_->pixmap()->size();
   //	size.scale(rect.size(), Qt::KeepAspectRatio);
   //	painter.setViewport(rect.x(), rect.y(), size.width(), size.height());
   //	painter.setWindow(mapWidget_->pixmap()->rect());
   //	painter.drawPixmap(0, 0, *mapWidget_->pixmap());
   //}
}

void MainWindow::createActions()
{
   //exportAct = new QAction(tr("&Export as ..."),this);
   //exportAct->setShortcut(tr("Ctrl+E"));
   //connect(exportAct, SIGNAL(triggered()), this, SLOT(export_as()));
   zoomAllAct = new QAction(QIcon(":/images/home.png"),tr("Zoom All"),this);
   connect(zoomAllAct, SIGNAL(triggered()), this, SLOT(zoom_all()));

   zoomBoxAct = new QAction(QIcon(":/images/zoombox.png"),tr("Zoom To Box"),this);
   zoomBoxAct->setCheckable(true);
   connect(zoomBoxAct, SIGNAL(triggered()), this, SLOT(zoom_to_box()));

   panAct = new QAction(QIcon(":/images/pan.png"),tr("Pan"),this);
   panAct->setCheckable(true);
   connect(panAct, SIGNAL(triggered()), this, SLOT(pan()));

   infoAct = new QAction(QIcon(":/images/info.png"),tr("Info"),this);
   infoAct->setCheckable(true);
   connect(infoAct, SIGNAL(triggered()), this, SLOT(info()));

   toolsGroup=new QActionGroup(this);
   toolsGroup->addAction(zoomBoxAct);
   toolsGroup->addAction(panAct);
   toolsGroup->addAction(infoAct);
   zoomBoxAct->setChecked(true);

   openAct=new QAction(tr("Open Map definition"),this);
   connect(openAct,SIGNAL(triggered()),this,SLOT(open()));
   saveAct=new QAction(tr("Save Map definition"),this);
   connect(saveAct,SIGNAL(triggered()),this,SLOT(save()));

   panLeftAct = new QAction(QIcon(":/images/left.png"),tr("&Pan Left"),this);
   connect(panLeftAct, SIGNAL(triggered()), this, SLOT(pan_left()));
   panRightAct = new QAction(QIcon(":/images/right.png"),tr("&Pan Right"),this);
   connect(panRightAct, SIGNAL(triggered()), this, SLOT(pan_right()));
   panUpAct = new QAction(QIcon(":/images/up.png"),tr("&Pan Up"),this);
   connect(panUpAct, SIGNAL(triggered()), this, SLOT(pan_up()));
   panDownAct = new QAction(QIcon(":/images/down.png"),tr("&Pan Down"),this);
   connect(panDownAct, SIGNAL(triggered()), this, SLOT(pan_down()));

   reloadAct = new QAction(QIcon(":/images/reload.png"),tr("Reload"),this);
   connect(reloadAct, SIGNAL(triggered()), this, SLOT(reload()));

   layerInfo = new QAction(QIcon(":/images/info.png"),tr("&Layer info"),layerTab_);
   connect(layerInfo, SIGNAL(triggered()), layerTab_,SLOT(layerInfo()));
   connect(layerTab_, SIGNAL(doubleClicked(QModelIndex const&)), layerTab_,SLOT(layerInfo2(QModelIndex const&)));
   foreach (QByteArray format, QImageWriter::supportedImageFormats())
   {
      QString text = tr("%1...").arg(QString(format).toUpper());

      QAction *action = new QAction(text, this);
      action->setData(format);
      connect(action, SIGNAL(triggered()), this, SLOT(export_as()));
      exportAsActs.append(action);
   }

   printAct = new QAction(QIcon(":/images/print.png"),tr("&Print ..."),this);
   printAct->setShortcut(tr("Ctrl+E"));
   connect(printAct, SIGNAL(triggered()), this, SLOT(print()));

   exitAct = new QAction(tr("E&xit"), this);
   exitAct->setShortcut(tr("Ctrl+Q"));
   connect(exitAct, SIGNAL(triggered()), this, SLOT(close()));

   aboutAct = new QAction(QIcon(":/images/about.png"),tr("&About"), this);
   connect(aboutAct, SIGNAL(triggered()), this, SLOT(about()));
}

void MainWindow::createMenus()
{
   exportMenu = new QMenu(tr("&Export As"), this);
   foreach (QAction *action, exportAsActs)
      exportMenu->addAction(action);

   fileMenu = new QMenu(tr("&File"),this);
   fileMenu->addAction(openAct);
   fileMenu->addAction(saveAct);
   fileMenu->addMenu(exportMenu);
   fileMenu->addAction(printAct);
   fileMenu->addSeparator();
   fileMenu->addAction(exitAct);
   menuBar()->addMenu(fileMenu);

   helpMenu = new QMenu(tr("&Help"), this);
   helpMenu->addAction(aboutAct);
   menuBar()->addMenu(helpMenu);
}

void MainWindow::createToolBars()
{
   fileToolBar = addToolBar(tr("Actions"));
   fileToolBar->addAction(zoomAllAct);
   fileToolBar->addAction(zoomBoxAct);
   fileToolBar->addAction(panAct);
   fileToolBar->addAction(panLeftAct);
   fileToolBar->addAction(panRightAct);
   fileToolBar->addAction(panUpAct);
   fileToolBar->addAction(panDownAct);
   fileToolBar->addAction(infoAct);
   fileToolBar->addAction(reloadAct);
   fileToolBar->addAction(printAct);
   slider_ = new QSlider(Qt::Horizontal,fileToolBar);
   slider_->setRange(1,18);
   slider_->setTickPosition(QSlider::TicksBelow);
   slider_->setTickInterval(1);
   slider_->setTracking(false);
   fileToolBar->addWidget(slider_);
   fileToolBar->addAction(aboutAct);
}

void MainWindow::set_default_extent(double x0,double y0, double x1, double y1)
{
    try
    {
       boost::shared_ptr<mapnik::Map> map_ptr = mapWidget_->getMap();
       if (map_ptr)
       {
          mapnik::projection prj(map_ptr->srs());
          prj.forward(x0,y0);
          prj.forward(x1,y1);
          default_extent_=mapnik::box2d<double>(x0,y0,x1,y1);
          mapWidget_->zoomToBox(default_extent_);
          std::cout << "SET DEFAULT EXT\n";
       }
    }
    catch (...) {}

}
<commit_msg>+ don't fail if load_map throws config error<commit_after>/* This file is part of Mapnik (c++ mapping toolkit)
 * Copyright (C) 2006 Artem Pavlenko
 *
 * Mapnik is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */

//$Id$

// stl
#include <iostream>

// qt
#include <QtGui>
#include <QSplitter>
#include <QTreeView>
#include <QListView>
#include <QTabWidget>
#include <QList>
#include <QItemDelegate>
#include <QSlider>

// mapnik
#include <mapnik/config_error.hpp>
#include <mapnik/load_map.hpp>
#include <mapnik/save_map.hpp>

// qt
#include "mainwindow.hpp"
#include "layerlistmodel.hpp"
#include "styles_model.hpp"
#include "layerwidget.hpp"
#include "layerdelegate.hpp"
#include "about_dialog.hpp"

MainWindow::MainWindow()
   : filename_(),
     default_extent_(-20037508.3428,-20037508.3428,20037508.3428,20037508.3428)
{
   mapWidget_ = new MapWidget(this);
   QSplitter *splitter = new QSplitter(this);
   QTabWidget *tabWidget=new QTabWidget;
   layerTab_ = new LayerTab;
   layerTab_->setFocusPolicy(Qt::NoFocus);
   layerTab_->setIconSize(QSize(16,16));

   //LayerDelegate *delegate = new LayerDelegate(this);
   //layerTab_->setItemDelegate(delegate);
   //layerTab_->setItemDelegate(new QItemDelegate(this));
   //layerTab_->setViewMode(QListView::IconMode);

   layerTab_->setFlow(QListView::TopToBottom);
   tabWidget->addTab(layerTab_,tr("Layers"));

   // Styles tab
   styleTab_ = new StyleTab;
   tabWidget->addTab(styleTab_,tr("Styles"));
   splitter->addWidget(tabWidget);
   splitter->addWidget(mapWidget_);
   QList<int> list;
   list.push_back(200);
   list.push_back(600);
   splitter->setSizes(list);

   mapWidget_->setFocusPolicy(Qt::StrongFocus);
   mapWidget_->setFocus();

   //setCentralWidget(mapWidget_);
   setCentralWidget(splitter);
   createActions();
   createMenus();
   createToolBars();
   createContextMenu();

   setWindowTitle(tr("Mapnik Viewer"));
   status=new QStatusBar(this);
   status->showMessage(tr(""));
   setStatusBar(status);
   resize(800,600);

   //connect mapview to layerlist
   connect(mapWidget_, SIGNAL(mapViewChanged()),layerTab_, SLOT(update()));
   // slider
   connect(slider_,SIGNAL(valueChanged(int)),mapWidget_,SLOT(zoomToLevel(int)));
   //
   connect(layerTab_,SIGNAL(update_mapwidget()),mapWidget_,SLOT(updateMap()));
   connect(layerTab_,SIGNAL(layerSelected(int)),
           mapWidget_,SLOT(layerSelected(int)));
}

MainWindow::~MainWindow()
{
   delete mapWidget_;
}

void MainWindow::closeEvent(QCloseEvent* event)
{
   event->accept();
}

void MainWindow::createContextMenu()
{
   layerTab_->setContextMenuPolicy(Qt::ActionsContextMenu);
   layerTab_->addAction(openAct);
   layerTab_->addAction(layerInfo);
}

void MainWindow::open(QString const& path)
{
   if (path.isNull())
   {
      filename_ = QFileDialog::getOpenFileName(this,tr("Open Mapnik file"),
                                              currentPath,"*.xml");
   }
   else
   {
      filename_ = path;
   }

   if (!filename_.isEmpty())
   {
      load_map_file(filename_);
      //zoom_all();
      setWindowTitle(tr("%1 - Mapnik Viewer").arg(filename_));
   }

}

void MainWindow::reload()
{
    if (!filename_.isEmpty())
    {

	mapnik::box2d<double> bbox = mapWidget_->getMap()->getCurrentExtent();
	load_map_file(filename_);
	mapWidget_->zoomToBox(bbox);
	setWindowTitle(tr("%1 - *Reloaded*").arg(filename_));
    }
}

void MainWindow::save()
{
   QString initialPath = QDir::currentPath() + "/untitled.xml";
   QString filename = QFileDialog::getSaveFileName(this, tr("Save"),
                                                   initialPath,
                                                   tr("%1 Files (*.xml)")
                                                   .arg(QString("Mapnik definition")));
   if (!filename.isEmpty())
   {
      std::cout<<"saving "<< filename.toStdString() << std::endl;
      mapnik::save_map(*mapWidget_->getMap(),filename.toStdString());
   }
}

void MainWindow::load_map_file(QString const& filename)
{
   std::cout<<"loading "<< filename.toStdString() << std::endl;
   unsigned width = mapWidget_->width();
   unsigned height = mapWidget_->height();
   boost::shared_ptr<mapnik::Map> map(new mapnik::Map(width,height));
   mapWidget_->setMap(map);
   try
   {
      mapnik::load_map(*map,filename.toStdString());
   }
   catch (mapnik::config_error & ex)
   {
      std::cout << ex.what() << "\n";
   }
   map->zoom_all();
   mapnik::box2d<double> const& ext = map->getCurrentExtent();
   mapWidget_->zoomToBox(ext);
   layerTab_->setModel(new LayerListModel(map,this));
   styleTab_->setModel(new StyleModel(map,this));
}

void MainWindow::zoom_all()
{
   mapWidget_->defaultView();
}

void MainWindow::zoom_to_box()
{
   mapWidget_->setTool(MapWidget::ZoomToBox);
}

void MainWindow::pan()
{
   mapWidget_->setTool(MapWidget::Pan);
}

void MainWindow::info()
{
   mapWidget_->setTool(MapWidget::Info);
}

void MainWindow::pan_left()
{
   mapWidget_->panLeft();
}

void MainWindow::pan_right()
{
   mapWidget_->panRight();
}

void MainWindow::pan_up()
{
   mapWidget_->panUp();
}

void MainWindow::pan_down()
{
   mapWidget_->panDown();
}

void MainWindow::about()
{
   about_dialog dlg;
   dlg.exec();
}

void MainWindow::export_as()
{
   QAction *action = qobject_cast<QAction *>(sender());
   QByteArray fileFormat = action->data().toByteArray();
   QString initialPath = QDir::currentPath() + "/map." + fileFormat;

   QString fileName = QFileDialog::getSaveFileName(this, tr("Export As"),
                                                   initialPath,
                                                   tr("%1 Files (*.%2);;All Files (*)")
                                                   .arg(QString(fileFormat.toUpper()))
                                                   .arg(QString(fileFormat)));
   if (!fileName.isEmpty())
   {
      QPixmap const& pix = mapWidget_->pixmap();
      pix.save(fileName);
   }
}

void MainWindow::print()
{

   //Q_ASSERT(mapWidget_->pixmap());
   //QPrintDialog dialog(&printer, this);
   //if (dialog.exec()) {
   //	QPainter painter(&printer);
   //	QRect rect = painter.viewport();
   //	QSize size = mapWidget_->pixmap()->size();
   //	size.scale(rect.size(), Qt::KeepAspectRatio);
   //	painter.setViewport(rect.x(), rect.y(), size.width(), size.height());
   //	painter.setWindow(mapWidget_->pixmap()->rect());
   //	painter.drawPixmap(0, 0, *mapWidget_->pixmap());
   //}
}

void MainWindow::createActions()
{
   //exportAct = new QAction(tr("&Export as ..."),this);
   //exportAct->setShortcut(tr("Ctrl+E"));
   //connect(exportAct, SIGNAL(triggered()), this, SLOT(export_as()));
   zoomAllAct = new QAction(QIcon(":/images/home.png"),tr("Zoom All"),this);
   connect(zoomAllAct, SIGNAL(triggered()), this, SLOT(zoom_all()));

   zoomBoxAct = new QAction(QIcon(":/images/zoombox.png"),tr("Zoom To Box"),this);
   zoomBoxAct->setCheckable(true);
   connect(zoomBoxAct, SIGNAL(triggered()), this, SLOT(zoom_to_box()));

   panAct = new QAction(QIcon(":/images/pan.png"),tr("Pan"),this);
   panAct->setCheckable(true);
   connect(panAct, SIGNAL(triggered()), this, SLOT(pan()));

   infoAct = new QAction(QIcon(":/images/info.png"),tr("Info"),this);
   infoAct->setCheckable(true);
   connect(infoAct, SIGNAL(triggered()), this, SLOT(info()));

   toolsGroup=new QActionGroup(this);
   toolsGroup->addAction(zoomBoxAct);
   toolsGroup->addAction(panAct);
   toolsGroup->addAction(infoAct);
   zoomBoxAct->setChecked(true);

   openAct=new QAction(tr("Open Map definition"),this);
   connect(openAct,SIGNAL(triggered()),this,SLOT(open()));
   saveAct=new QAction(tr("Save Map definition"),this);
   connect(saveAct,SIGNAL(triggered()),this,SLOT(save()));

   panLeftAct = new QAction(QIcon(":/images/left.png"),tr("&Pan Left"),this);
   connect(panLeftAct, SIGNAL(triggered()), this, SLOT(pan_left()));
   panRightAct = new QAction(QIcon(":/images/right.png"),tr("&Pan Right"),this);
   connect(panRightAct, SIGNAL(triggered()), this, SLOT(pan_right()));
   panUpAct = new QAction(QIcon(":/images/up.png"),tr("&Pan Up"),this);
   connect(panUpAct, SIGNAL(triggered()), this, SLOT(pan_up()));
   panDownAct = new QAction(QIcon(":/images/down.png"),tr("&Pan Down"),this);
   connect(panDownAct, SIGNAL(triggered()), this, SLOT(pan_down()));

   reloadAct = new QAction(QIcon(":/images/reload.png"),tr("Reload"),this);
   connect(reloadAct, SIGNAL(triggered()), this, SLOT(reload()));

   layerInfo = new QAction(QIcon(":/images/info.png"),tr("&Layer info"),layerTab_);
   connect(layerInfo, SIGNAL(triggered()), layerTab_,SLOT(layerInfo()));
   connect(layerTab_, SIGNAL(doubleClicked(QModelIndex const&)), layerTab_,SLOT(layerInfo2(QModelIndex const&)));
   foreach (QByteArray format, QImageWriter::supportedImageFormats())
   {
      QString text = tr("%1...").arg(QString(format).toUpper());

      QAction *action = new QAction(text, this);
      action->setData(format);
      connect(action, SIGNAL(triggered()), this, SLOT(export_as()));
      exportAsActs.append(action);
   }

   printAct = new QAction(QIcon(":/images/print.png"),tr("&Print ..."),this);
   printAct->setShortcut(tr("Ctrl+E"));
   connect(printAct, SIGNAL(triggered()), this, SLOT(print()));

   exitAct = new QAction(tr("E&xit"), this);
   exitAct->setShortcut(tr("Ctrl+Q"));
   connect(exitAct, SIGNAL(triggered()), this, SLOT(close()));

   aboutAct = new QAction(QIcon(":/images/about.png"),tr("&About"), this);
   connect(aboutAct, SIGNAL(triggered()), this, SLOT(about()));
}

void MainWindow::createMenus()
{
   exportMenu = new QMenu(tr("&Export As"), this);
   foreach (QAction *action, exportAsActs)
      exportMenu->addAction(action);

   fileMenu = new QMenu(tr("&File"),this);
   fileMenu->addAction(openAct);
   fileMenu->addAction(saveAct);
   fileMenu->addMenu(exportMenu);
   fileMenu->addAction(printAct);
   fileMenu->addSeparator();
   fileMenu->addAction(exitAct);
   menuBar()->addMenu(fileMenu);

   helpMenu = new QMenu(tr("&Help"), this);
   helpMenu->addAction(aboutAct);
   menuBar()->addMenu(helpMenu);
}

void MainWindow::createToolBars()
{
   fileToolBar = addToolBar(tr("Actions"));
   fileToolBar->addAction(zoomAllAct);
   fileToolBar->addAction(zoomBoxAct);
   fileToolBar->addAction(panAct);
   fileToolBar->addAction(panLeftAct);
   fileToolBar->addAction(panRightAct);
   fileToolBar->addAction(panUpAct);
   fileToolBar->addAction(panDownAct);
   fileToolBar->addAction(infoAct);
   fileToolBar->addAction(reloadAct);
   fileToolBar->addAction(printAct);
   slider_ = new QSlider(Qt::Horizontal,fileToolBar);
   slider_->setRange(1,18);
   slider_->setTickPosition(QSlider::TicksBelow);
   slider_->setTickInterval(1);
   slider_->setTracking(false);
   fileToolBar->addWidget(slider_);
   fileToolBar->addAction(aboutAct);
}

void MainWindow::set_default_extent(double x0,double y0, double x1, double y1)
{
    try
    {
       boost::shared_ptr<mapnik::Map> map_ptr = mapWidget_->getMap();
       if (map_ptr)
       {
          mapnik::projection prj(map_ptr->srs());
          prj.forward(x0,y0);
          prj.forward(x1,y1);
          default_extent_=mapnik::box2d<double>(x0,y0,x1,y1);
          mapWidget_->zoomToBox(default_extent_);
          std::cout << "SET DEFAULT EXT\n";
       }
    }
    catch (...) {}

}
<|endoftext|>


<commit_before>/** @file

  Multiplexes request to other origins.

  @section license License

  Licensed to the Apache Software Foundation (ASF) under one
  or more contributor license agreements.  See the NOTICE file
  distributed with this work for additional information
  regarding copyright ownership.  The ASF licenses this file
  to you 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 <cassert>
#include <limits>

#include "post.h"

#ifndef PLUGIN_TAG
#error Please define a PLUGIN_TAG before including this file.
#endif

PostState::~PostState()
{
  if (buffer != nullptr) {
    TSIOBufferDestroy(buffer);
    buffer = nullptr;
  }
}

PostState::PostState(Requests &r) : buffer(nullptr), reader(nullptr), vio(nullptr)
{
  assert(!r.empty());
  requests.swap(r);
}

static void
postTransform(const TSCont c, PostState &s)
{
  assert(c != nullptr);

  const TSVConn vconnection = TSTransformOutputVConnGet(c);
  assert(vconnection != nullptr);

  const TSVIO vio = TSVConnWriteVIOGet(c);
  assert(vio != nullptr);

  if (!s.buffer) {
    s.buffer = TSIOBufferCreate();
    assert(s.buffer != nullptr);

    const TSIOBufferReader reader = TSIOBufferReaderAlloc(s.buffer);
    assert(reader != nullptr);

    s.reader = TSIOBufferReaderClone(reader);
    assert(s.reader != nullptr);

    s.vio = TSVConnWrite(vconnection, c, reader, std::numeric_limits<int64_t>::max());
    assert(s.vio != nullptr);
  }

  if (!TSVIOBufferGet(vio)) {
    TSVIONBytesSet(s.vio, TSVIONDoneGet(vio));
    TSVIOReenable(s.vio);
    return;
  }

  int64_t toWrite = TSVIONTodoGet(vio);
  assert(toWrite >= 0);

  if (toWrite > 0) {
    toWrite = std::min(toWrite, TSIOBufferReaderAvail(TSVIOReaderGet(vio)));
    assert(toWrite >= 0);

    if (toWrite > 0) {
      TSIOBufferCopy(TSVIOBufferGet(s.vio), TSVIOReaderGet(vio), toWrite, 0);
      TSIOBufferReaderConsume(TSVIOReaderGet(vio), toWrite);
      TSVIONDoneSet(vio, TSVIONDoneGet(vio) + toWrite);
    }
  }

  if (TSVIONTodoGet(vio) > 0) {
    if (toWrite > 0) {
      TSVIOReenable(s.vio);
      CHECK(TSContCall(TSVIOContGet(vio), TS_EVENT_VCONN_WRITE_READY, vio));
    }
  } else {
    TSVIONBytesSet(s.vio, TSVIONDoneGet(vio));
    TSVIOReenable(s.vio);
    CHECK(TSContCall(TSVIOContGet(vio), TS_EVENT_VCONN_WRITE_COMPLETE, vio));
  }
}

int
handlePost(TSCont c, TSEvent e, void *data)
{
  assert(c != nullptr);
  // TODO(dmorilha): assert on possible events.
  PostState *const state = static_cast<PostState *>(TSContDataGet(c));
  assert(state != nullptr);
  if (TSVConnClosedGet(c)) {
    assert(data != nullptr);
    if (state->reader != nullptr) {
      addBody(state->requests, state->reader);
    }
    dispatch(state->requests, timeout);
    delete state;
    TSContDataSet(c, nullptr);
    TSContDestroy(c);
    return 0;
  } else {
    switch (e) {
    case TS_EVENT_ERROR: {
      const TSVIO vio = TSVConnWriteVIOGet(c);
      assert(vio != nullptr);
      CHECK(TSContCall(TSVIOContGet(vio), TS_EVENT_ERROR, vio));
    } break;
    case TS_EVENT_VCONN_WRITE_COMPLETE:
      TSVConnShutdown(TSTransformOutputVConnGet(c), 0, 1);
      break;

    case TS_EVENT_VCONN_WRITE_READY:
    default:
      postTransform(c, *state);
      break;
    }
  }
  return 0;
}
<commit_msg>Removed checking the return value for TSContCall()<commit_after>/** @file

  Multiplexes request to other origins.

  @section license License

  Licensed to the Apache Software Foundation (ASF) under one
  or more contributor license agreements.  See the NOTICE file
  distributed with this work for additional information
  regarding copyright ownership.  The ASF licenses this file
  to you 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 <cassert>
#include <limits>

#include "post.h"

#ifndef PLUGIN_TAG
#error Please define a PLUGIN_TAG before including this file.
#endif

PostState::~PostState()
{
  if (buffer != nullptr) {
    TSIOBufferDestroy(buffer);
    buffer = nullptr;
  }
}

PostState::PostState(Requests &r) : buffer(nullptr), reader(nullptr), vio(nullptr)
{
  assert(!r.empty());
  requests.swap(r);
}

static void
postTransform(const TSCont c, PostState &s)
{
  assert(c != nullptr);

  const TSVConn vconnection = TSTransformOutputVConnGet(c);
  assert(vconnection != nullptr);

  const TSVIO vio = TSVConnWriteVIOGet(c);
  assert(vio != nullptr);

  if (!s.buffer) {
    s.buffer = TSIOBufferCreate();
    assert(s.buffer != nullptr);

    const TSIOBufferReader reader = TSIOBufferReaderAlloc(s.buffer);
    assert(reader != nullptr);

    s.reader = TSIOBufferReaderClone(reader);
    assert(s.reader != nullptr);

    s.vio = TSVConnWrite(vconnection, c, reader, std::numeric_limits<int64_t>::max());
    assert(s.vio != nullptr);
  }

  if (!TSVIOBufferGet(vio)) {
    TSVIONBytesSet(s.vio, TSVIONDoneGet(vio));
    TSVIOReenable(s.vio);
    return;
  }

  int64_t toWrite = TSVIONTodoGet(vio);
  assert(toWrite >= 0);

  if (toWrite > 0) {
    toWrite = std::min(toWrite, TSIOBufferReaderAvail(TSVIOReaderGet(vio)));
    assert(toWrite >= 0);

    if (toWrite > 0) {
      TSIOBufferCopy(TSVIOBufferGet(s.vio), TSVIOReaderGet(vio), toWrite, 0);
      TSIOBufferReaderConsume(TSVIOReaderGet(vio), toWrite);
      TSVIONDoneSet(vio, TSVIONDoneGet(vio) + toWrite);
    }
  }

  if (TSVIONTodoGet(vio) > 0) {
    if (toWrite > 0) {
      TSVIOReenable(s.vio);
      TSContCall(TSVIOContGet(vio), TS_EVENT_VCONN_WRITE_READY, vio);
    }
  } else {
    TSVIONBytesSet(s.vio, TSVIONDoneGet(vio));
    TSVIOReenable(s.vio);
    TSContCall(TSVIOContGet(vio), TS_EVENT_VCONN_WRITE_COMPLETE, vio);
  }
}

int
handlePost(TSCont c, TSEvent e, void *data)
{
  assert(c != nullptr);
  // TODO(dmorilha): assert on possible events.
  PostState *const state = static_cast<PostState *>(TSContDataGet(c));
  assert(state != nullptr);
  if (TSVConnClosedGet(c)) {
    assert(data != nullptr);
    if (state->reader != nullptr) {
      addBody(state->requests, state->reader);
    }
    dispatch(state->requests, timeout);
    delete state;
    TSContDataSet(c, nullptr);
    TSContDestroy(c);
    return 0;
  } else {
    switch (e) {
    case TS_EVENT_ERROR: {
      const TSVIO vio = TSVConnWriteVIOGet(c);
      assert(vio != nullptr);
      TSContCall(TSVIOContGet(vio), TS_EVENT_ERROR, vio);
    } break;
    case TS_EVENT_VCONN_WRITE_COMPLETE:
      TSVConnShutdown(TSTransformOutputVConnGet(c), 0, 1);
      break;

    case TS_EVENT_VCONN_WRITE_READY:
    default:
      postTransform(c, *state);
      break;
    }
  }
  return 0;
}
<|endoftext|>


<commit_before>#include <wayfire/plugin.hpp>
#include <wayfire/signal-definitions.hpp>
#include <wayfire/view-transform.hpp>
#include <wayfire/view.hpp>
#include <wayfire/workspace-manager.hpp>

/*
 * This plugin provides abilities to switch between views.
 * It works similarly to the alt-esc binding in Windows or GNOME
 */

class wayfire_fast_switcher : public wf::plugin_interface_t
{
    wf::option_wrapper_t<wf::keybinding_t> activate_key{"fast-switcher/activate"};
    size_t current_view_index;
    std::vector<wayfire_view> views; // all views on current viewport

    bool active = false;

  public:
    void init() override
    {
        grab_interface->name = "fast-switcher";
        grab_interface->capabilities = wf::CAPABILITY_MANAGE_COMPOSITOR;
        output->add_key(activate_key, &fast_switch);

        using namespace std::placeholders;
        grab_interface->callbacks.keyboard.mod =
            std::bind(std::mem_fn(&wayfire_fast_switcher::handle_mod),
                this, _1, _2);

        grab_interface->callbacks.cancel = [=] ()
        {
            switch_terminate();
        };
    }

    void handle_mod(uint32_t mod, uint32_t st)
    {
        bool mod_released =
            (mod == ((wf::keybinding_t)activate_key).get_modifiers() &&
                st == WLR_KEY_RELEASED);

        if (mod_released)
        {
            switch_terminate();
        }
    }

    void update_views()
    {
        current_view_index = 0;
        views = output->workspace->get_views_on_workspace(
            output->workspace->get_current_workspace(), wf::WM_LAYERS);
    }

    void view_chosen(int i, bool reorder_only)
    {
        /* No view available */
        if (!((0 <= i) && (i < (int)views.size())))
        {
            return;
        }

        set_view_alpha(views[i], 1.0);
        for (int i = (int)views.size() - 1; i >= 0; i--)
        {
            output->workspace->bring_to_front(views[i]);
        }

        if (reorder_only)
        {
            output->workspace->bring_to_front(views[i]);
        } else
        {
            output->focus_view(views[i], true);
        }
    }

    wf::signal_callback_t cleanup_view = [=] (wf::signal_data_t *data)
    {
        auto view = get_signaled_view(data);

        size_t i = 0;
        for (; i < views.size() && views[i] != view; i++)
        {}

        if (i == views.size())
        {
            return;
        }

        views.erase(views.begin() + i);

        if (views.empty())
        {
            switch_terminate();

            return;
        }

        if (i <= current_view_index)
        {
            current_view_index =
                (current_view_index + views.size() - 1) % views.size();
            view_chosen(current_view_index, true);
        }
    };

    const std::string transformer_name = "fast-switcher";

    void set_view_alpha(wayfire_view view, float alpha)
    {
        if (!view->get_transformer(transformer_name))
        {
            view->add_transformer(
                std::make_unique<wf::view_2D>(view), transformer_name);
        }

        auto tr = dynamic_cast<wf::view_2D*>(
            view->get_transformer(transformer_name).get());
        tr->alpha = alpha;
        view->damage();
    }

    wf::key_callback fast_switch = [=] (auto)
    {
        if (active)
        {
            switch_next();

            return true;
        }

        if (!output->activate_plugin(grab_interface))
        {
            return false;
        }

        update_views();

        if (views.size() < 1)
        {
            output->deactivate_plugin(grab_interface);

            return false;
        }

        current_view_index = 0;
        active = true;

        /* Set all to semi-transparent */
        for (auto view : views)
        {
            set_view_alpha(view, 0.7);
        }

        grab_interface->grab();
        switch_next();

        output->connect_signal("view-disappeared", &cleanup_view);

        return true;
    };

    void switch_terminate()
    {
        for (auto view : views)
        {
            view->pop_transformer(transformer_name);
        }

        grab_interface->ungrab();
        output->deactivate_plugin(grab_interface);
        view_chosen(current_view_index, false);

        active = false;

        output->disconnect_signal("view-disappeared", &cleanup_view);
    }

    void switch_next()
    {
#define index current_view_index
        set_view_alpha(views[index], 0.7);
        index = (index + 1) % views.size();
#undef index
        view_chosen(current_view_index, true);
    }

    void fini() override
    {
        if (active)
        {
            switch_terminate();
        }

        output->rem_binding(&fast_switch);
    }
};

DECLARE_WAYFIRE_PLUGIN(wayfire_fast_switcher);
<commit_msg>Fast switcher uses focus order instead of stack order (#907)<commit_after>#include <wayfire/plugin.hpp>
#include <wayfire/signal-definitions.hpp>
#include <wayfire/view-transform.hpp>
#include <wayfire/view.hpp>
#include <wayfire/workspace-manager.hpp>

/*
 * This plugin provides abilities to switch between views.
 * It works similarly to the alt-esc binding in Windows or GNOME
 */

class wayfire_fast_switcher : public wf::plugin_interface_t
{
    wf::option_wrapper_t<wf::keybinding_t> activate_key{"fast-switcher/activate"};
    std::vector<wayfire_view> views; // all views on current viewport
    size_t current_view_index = 0;
    bool active = false;

  public:
    void init() override
    {
        grab_interface->name = "fast-switcher";
        grab_interface->capabilities = wf::CAPABILITY_MANAGE_COMPOSITOR;

        output->add_key(activate_key, &fast_switch);

        using namespace std::placeholders;
        grab_interface->callbacks.keyboard.mod =
            std::bind(std::mem_fn(&wayfire_fast_switcher::handle_mod),
                this, _1, _2);

        grab_interface->callbacks.cancel = [=] () { switch_terminate(); };
    }

    void handle_mod(uint32_t mod, uint32_t st)
    {
        bool mod_released =
            (mod == ((wf::keybinding_t)activate_key).get_modifiers() &&
                st == WLR_KEY_RELEASED);

        if (mod_released)
        {
            switch_terminate();
        }
    }

    void view_chosen(int i, bool reorder_only)
    {
        /* No view available */
        if (!((0 <= i) && (i < (int)views.size())))
        {
            return;
        }

        set_view_alpha(views[i], 1.0);
        for (int i = (int)views.size() - 1; i >= 0; i--)
        {
            output->workspace->bring_to_front(views[i]);
        }

        if (reorder_only)
        {
            output->workspace->bring_to_front(views[i]);
        } else
        {
            output->focus_view(views[i], true);
        }
    }

    wf::signal_callback_t cleanup_view = [=] (wf::signal_data_t *data)
    {
        auto view = get_signaled_view(data);

        size_t i = 0;
        for (; i < views.size() && views[i] != view; i++)
        {}

        if (i == views.size())
        {
            return;
        }

        views.erase(views.begin() + i);

        if (views.empty())
        {
            switch_terminate();

            return;
        }

        if (i <= current_view_index)
        {
            current_view_index =
                (current_view_index + views.size() - 1) % views.size();
            view_chosen(current_view_index, true);
        }
    };

    const std::string transformer_name = "fast-switcher";

    void set_view_alpha(wayfire_view view, float alpha)
    {
        if (!view->get_transformer(transformer_name))
        {
            view->add_transformer(
                std::make_unique<wf::view_2D>(view), transformer_name);
        }

        auto tr = dynamic_cast<wf::view_2D*>(
            view->get_transformer(transformer_name).get());
        tr->alpha = alpha;
        view->damage();
    }

    void update_views()
    {
        views = output->workspace->get_views_on_workspace(
            output->workspace->get_current_workspace(), wf::WM_LAYERS);

        std::sort(views.begin(), views.end(), [] (wayfire_view& a, wayfire_view& b)
        {
            return a->last_focus_timestamp > b->last_focus_timestamp;
        });
    }

    wf::key_callback fast_switch = [=] (auto)
    {
        if (active)
        {
            switch_next();

            return true;
        }

        if (!output->activate_plugin(grab_interface))
        {
            return false;
        }

        update_views();

        if (views.size() < 1)
        {
            output->deactivate_plugin(grab_interface);

            return false;
        }

        current_view_index = 0;
        active = true;

        /* Set all to semi-transparent */
        for (auto view : views)
        {
            set_view_alpha(view, 0.7);
        }

        grab_interface->grab();
        switch_next();

        output->connect_signal("view-disappeared", &cleanup_view);

        return true;
    };

    void switch_terminate()
    {
        for (auto view : views)
        {
            view->pop_transformer(transformer_name);
        }

        grab_interface->ungrab();
        output->deactivate_plugin(grab_interface);
        view_chosen(current_view_index, false);
        active = false;

        output->disconnect_signal("view-disappeared", &cleanup_view);
    }

    void switch_next()
    {
#define index current_view_index
        set_view_alpha(views[index], 0.7);
        index = (index + 1) % views.size();
#undef index
        view_chosen(current_view_index, true);
    }

    void fini() override
    {
        if (active)
        {
            switch_terminate();
        }

        output->rem_binding(&fast_switch);
    }
};

DECLARE_WAYFIRE_PLUGIN(wayfire_fast_switcher);
<|endoftext|>


<commit_before>// Time:  O(n)
// Space: O(n)

class Solution {
public:
    /**
     * @param expression: a vector of strings;
     * @return: an integer
     */
    int evaluateExpression(vector<string> &expression) {
        stack<int> operands;
        stack<string> operators;
        if (expression.empty()) {
            return 0;
        }
        for (int i = expression.size() - 1; i >= 0; --i) {
            if (isdigit(expression[i][0])) {
                operands.emplace(stoi(expression[i]));
            } else if (expression[i] == ")" || expression[i] == "*" ||
                       expression[i] == "/") {
                operators.emplace(expression[i]);
            } else if (expression[i] == "+" || expression[i] == "-") {
                while (!operators.empty() && (operators.top() == "*" ||
                       operators.top() == "/")) {
                     compute(operands, operators);
                }
                operators.emplace(expression[i]);
            } else if (expression[i] == "(") {
                // operators at least one element, i.e. ")".
                while (operators.top() != ")") {
                    compute(operands, operators);
                }
                operators.pop();
            }
        }
        while (!operators.empty()) {
            compute(operands, operators);
        }
        return operands.top();
    }

    void compute(stack<int>& operands, stack<string>& operators) {
        const int left = operands.top();
        operands.pop();
        const int right = operands.top();
        operands.pop();
        const string op = operators.top();
        operators.pop();

        if (op == "+") {
            operands.push(left + right);
        } else if (op == "-") {
            operands.push(left - right);
        } else if (op == "*") {
            operands.push(left * right);
        } else if (op == "/") {
            operands.push(left / right);
        }
    }
};

// Time:  O(n)
// Space: O(n)
class Solution2 {
public:
    /**
     * @param expression: a vector of strings;
     * @return: an integer
     */
    int evaluateExpression(vector<string> &expression) {
        if (expression.empty()) {
            return 0;
        }
        vector<string> postfix;
        infixToPostfix(expression, postfix);
        return evaluatePostfixExpression(postfix);
    }

    // Evaluate Postfix Expression.
    int evaluatePostfixExpression(const vector<string> &postfix) {
        if (postfix.empty()) {
            return 0;
        }
        stack<string> s;
        for (const auto& tok : postfix) {
            if (!is_operator(tok)) {
                s.emplace(tok);
            } else {
                int y = stoi(s.top());
                s.pop();
                int x = stoi(s.top());
                s.pop();
                if (tok[0] == '+') {
                    x += y;
                } else if (tok[0] == '-') {
                    x -= y;
                } else if (tok[0] == '*') {
                    x *= y;
                } else {
                    x /= y;
                }
                s.emplace(to_string(x));
            }
        }
        return stoi(s.top());
    }

    bool is_operator(const string &op) {
        return op.length() == 1 && string("+-*/").find(op) != string::npos;
    }

    // Convert Infix to Postfix Expression.
    void infixToPostfix(vector<string>& infix, vector<string>& postfix) {
        stack<string> s;
        for (auto tok : infix) {
            // Any number would be pushed into stack.
            if (atoi(tok.c_str())) {
                postfix.emplace_back(tok);
            } else if (tok == "(") {
                s.emplace(tok);
            } else if (tok == ")") {
                // Meet ")", then pop until "(".
                while (!s.empty()) {
                    tok = s.top();
                    s.pop();
                    if (tok == "(") {
                        break;
                    }
                    postfix.emplace_back(tok);
                }
            } else {
                // Order of tokens in stack should be like "(-*",
                // The token will be added in an strictly increasing precedence order.
                while (!s.empty() && precedence(tok) <= precedence(s.top())) {
                    postfix.emplace_back(s.top());
                    s.pop();
                }
                s.emplace(tok);
            }
        }
        // Pop the remaining token and add them to the postfix.
        while (!s.empty()) {
            postfix.emplace_back(s.top());
            s.pop();
        }
    }

    int precedence(string x) {
        if (x == "(") {  // The least precedence.
            return 0;
        } else if (x == "+" || x == "-") {
            return 1;
        } else if (x == "*" || x == "/") {
            return 2;
        }
        return 3;
    }
};
<commit_msg>Update expression-evaluation.cpp<commit_after>// Time:  O(n)
// Space: O(n)

class Solution {
public:
    /**
     * @param expression: a vector of strings;
     * @return: an integer
     */
    int evaluateExpression(vector<string> &expression) {
        stack<int> operands;
        stack<string> operators;
        if (expression.empty()) {
            return 0;
        }
        for (int i = expression.size() - 1; i >= 0; --i) {
            if (isdigit(expression[i][0])) {
                operands.emplace(stoi(expression[i]));
            } else if (expression[i] == ")" || expression[i] == "*" ||
                       expression[i] == "/") {
                operators.emplace(expression[i]);
            } else if (expression[i] == "+" || expression[i] == "-") {
                while (!operators.empty() && (operators.top() == "*" ||
                       operators.top() == "/")) {
                     compute(operands, operators);
                }
                operators.emplace(expression[i]);
            } else if (expression[i] == "(") {
                // operators at least one element, i.e. ")".
                while (operators.top() != ")") {
                    compute(operands, operators);
                }
                operators.pop();
            }
        }
        while (!operators.empty()) {
            compute(operands, operators);
        }
        return operands.top();
    }

    void compute(stack<int>& operands, stack<string>& operators) {
        const int left = operands.top();
        operands.pop();
        const int right = operands.top();
        operands.pop();
        const string op = operators.top();
        operators.pop();
        if (op == "+") {
            operands.push(left + right);
        } else if (op == "-") {
            operands.push(left - right);
        } else if (op == "*") {
            operands.push(left * right);
        } else if (op == "/") {
            operands.push(left / right);
        }
    }
};

// Time:  O(n)
// Space: O(n)
class Solution2 {
public:
    /**
     * @param expression: a vector of strings;
     * @return: an integer
     */
    int evaluateExpression(vector<string> &expression) {
        if (expression.empty()) {
            return 0;
        }
        vector<string> postfix;
        infixToPostfix(expression, postfix);
        return evaluatePostfixExpression(postfix);
    }

    // Evaluate Postfix Expression.
    int evaluatePostfixExpression(const vector<string> &postfix) {
        if (postfix.empty()) {
            return 0;
        }
        stack<string> s;
        for (const auto& tok : postfix) {
            if (!is_operator(tok)) {
                s.emplace(tok);
            } else {
                int y = stoi(s.top());
                s.pop();
                int x = stoi(s.top());
                s.pop();
                if (tok[0] == '+') {
                    x += y;
                } else if (tok[0] == '-') {
                    x -= y;
                } else if (tok[0] == '*') {
                    x *= y;
                } else {
                    x /= y;
                }
                s.emplace(to_string(x));
            }
        }
        return stoi(s.top());
    }

    bool is_operator(const string &op) {
        return op.length() == 1 && string("+-*/").find(op) != string::npos;
    }

    // Convert Infix to Postfix Expression.
    void infixToPostfix(vector<string>& infix, vector<string>& postfix) {
        stack<string> s;
        for (auto tok : infix) {
            // Any number would be pushed into stack.
            if (atoi(tok.c_str())) {
                postfix.emplace_back(tok);
            } else if (tok == "(") {
                s.emplace(tok);
            } else if (tok == ")") {
                // Meet ")", then pop until "(".
                while (!s.empty()) {
                    tok = s.top();
                    s.pop();
                    if (tok == "(") {
                        break;
                    }
                    postfix.emplace_back(tok);
                }
            } else {
                // Order of tokens in stack should be like "(-*",
                // The token will be added in an strictly increasing precedence order.
                while (!s.empty() && precedence(tok) <= precedence(s.top())) {
                    postfix.emplace_back(s.top());
                    s.pop();
                }
                s.emplace(tok);
            }
        }
        // Pop the remaining token and add them to the postfix.
        while (!s.empty()) {
            postfix.emplace_back(s.top());
            s.pop();
        }
    }

    int precedence(string x) {
        if (x == "(") {  // The least precedence.
            return 0;
        } else if (x == "+" || x == "-") {
            return 1;
        } else if (x == "*" || x == "/") {
            return 2;
        }
        return 3;
    }
};
<|endoftext|>