<commit_before>// GeometricAlgebraEnv.cpp

/*
 * Copyright (C) 2012 Spencer T. Parkin
 *
 * This software has been released under the MIT License.
 * See the "License.txt" file in the project root directory
 * for more information about this license.
 *
 */

#include "../../CalcLib.h"

using namespace CalcLib;

//=========================================================================================
IMPLEMENT_CALCLIB_CLASS1( GeometricAlgebraEnvironment, Environment );

//=========================================================================================
GeometricAlgebraEnvironment::GeometricAlgebraEnvironment( void )
{
	displayMode = DISPLAY_AS_SUM_OF_BLADES;
}

//=========================================================================================
/*virtual*/ GeometricAlgebraEnvironment::~GeometricAlgebraEnvironment( void )
{
}

//=========================================================================================
/*virtual*/ void GeometricAlgebraEnvironment::PrintEnvironmentInfo( void )
{
	Print(
		"\n"
		"You are in the geometric algebra environment.\n"
		"\n"
	);
}

//=========================================================================================
/*virtual*/ Number* GeometricAlgebraEnvironment::CreateNumber( void )
{
	MultivectorNumber* multivectorNumber = new MultivectorNumber();
	Number* number = multivectorNumber;
	return number;
}

//=========================================================================================
/*virtual*/ FunctionEvaluator* GeometricAlgebraEnvironment::CreateFunction( const char* functionName )
{
	FunctionEvaluator* functionEvaluator = 0;

	if( 0 == strcmp( functionName, "reverse" ) )
		functionEvaluator = new ReverseFunctionEvaluator();
	else if( 0 == strcmp( functionName, "scalar_part" ) )
		functionEvaluator = new ScalarPartFunctionEvaluator();
	else if( 0 == strcmp( functionName, "grade_part" ) )
		functionEvaluator = new GradePartFunctionEvaluator();
	else if( 0 == strcmp( functionName, "inverse" ) )
		functionEvaluator = new InverseFunctionEvaluator();
	else if( 0 == strcmp( functionName, "exp" ) )
		functionEvaluator = new MultivectorMathFunctionEvaluator( MultivectorMathFunctionEvaluator::FUNC_EXP );
	else if( 0 == strcmp( functionName, "log" ) )
		functionEvaluator = new MultivectorMathFunctionEvaluator( MultivectorMathFunctionEvaluator::FUNC_LOG );
	else if( 0 == strcmp( functionName, "pow" ) )
		functionEvaluator = new MultivectorMathFunctionEvaluator( MultivectorMathFunctionEvaluator::FUNC_POW );
	else if( 0 == strcmp( functionName, "sqrt" ) )
		functionEvaluator = new MultivectorMathFunctionEvaluator( MultivectorMathFunctionEvaluator::FUNC_SQRT );
	else if( 0 == strcmp( functionName, "cos" ) )
		functionEvaluator = new MultivectorMathFunctionEvaluator( MultivectorMathFunctionEvaluator::FUNC_COS );
	else if( 0 == strcmp( functionName, "sin" ) )
		functionEvaluator = new MultivectorMathFunctionEvaluator( MultivectorMathFunctionEvaluator::FUNC_SIN );
	else if( 0 == strcmp( functionName, "tan" ) )
		functionEvaluator = new MultivectorMathFunctionEvaluator( MultivectorMathFunctionEvaluator::FUNC_TAN );
	else if( 0 == strcmp( functionName, "abs" ) )
		functionEvaluator = new MultivectorMathFunctionEvaluator( MultivectorMathFunctionEvaluator::FUNC_ABS );
	else if( 0 == strcmp( functionName, "acos" ) )
		functionEvaluator = new MultivectorMathFunctionEvaluator( MultivectorMathFunctionEvaluator::FUNC_ACOS );
	else if( 0 == strcmp( functionName, "asin" ) )
		functionEvaluator = new MultivectorMathFunctionEvaluator( MultivectorMathFunctionEvaluator::FUNC_ASIN );
//	else if( 0 == strcmp( functionName, "conjugate" ) )
//		functionEvaluator = new ConjugateFunctionEvaluator();
	else
		functionEvaluator = Environment::CreateFunction( functionName );

	return functionEvaluator;
}

//=========================================================================================
/*virtual*/ Evaluator* GeometricAlgebraEnvironment::CreateVariable( const char* variableName )
{
	ConstantEvaluator* evaluator = 0;
	MultivectorNumber* multivectorNumber = 0;
	GeometricAlgebra::Vector* vector = 0;
	GeometricAlgebra::Blade* blade = 0;
	GeometricAlgebra::SumOfBlades* sumOfBlades = 0;

	if( 0 == strcmp( variableName, "e0" ) )
		vector = new GeometricAlgebra::Vector_e0();
	else if( 0 == strcmp( variableName, "e1" ) )
		vector = new GeometricAlgebra::Vector_e1();
	else if( 0 == strcmp( variableName, "e2" ) )
		vector = new GeometricAlgebra::Vector_e2();
	else if( 0 == strcmp( variableName, "e3" ) )
		vector = new GeometricAlgebra::Vector_e3();
	else if( 0 == strcmp( variableName, "e0b" ) )
		vector = new GeometricAlgebra::Vector_e0_bar();
	else if( 0 == strcmp( variableName, "e1b" ) )
		vector = new GeometricAlgebra::Vector_e1_bar();
	else if( 0 == strcmp( variableName, "e2b" ) )
		vector = new GeometricAlgebra::Vector_e2_bar();
	else if( 0 == strcmp( variableName, "e3b" ) )
		vector = new GeometricAlgebra::Vector_e3_bar();
	else if( 0 == strcmp( variableName, "no" ) )
		vector = new GeometricAlgebra::Vector_no();
	else if( 0 == strcmp( variableName, "ni" ) )
		vector = new GeometricAlgebra::Vector_ni();
	else if( 0 == strcmp( variableName, "nob" ) )
		vector = new GeometricAlgebra::Vector_no_bar();
	else if( 0 == strcmp( variableName, "nib" ) )
		vector = new GeometricAlgebra::Vector_ni_bar();
	else if( 0 == strcmp( variableName, "i" ) )
	{
		blade = new GeometricAlgebra::Blade();
		Utilities::List vectorProduct;
		vectorProduct.InsertRightOf( vectorProduct.RightMost(), new GeometricAlgebra::Vector_e0() );
		vectorProduct.InsertRightOf( vectorProduct.RightMost(), new GeometricAlgebra::Vector_e1() );
		vectorProduct.InsertRightOf( vectorProduct.RightMost(), new GeometricAlgebra::Vector_e2() );
		blade->AssignBlade( vectorProduct, 1.0 );
	}
	else if( 0 == strcmp( variableName, "I" ) )
	{
		blade = new GeometricAlgebra::Blade();
		Utilities::List vectorProduct;
		vectorProduct.InsertRightOf( vectorProduct.RightMost(), new GeometricAlgebra::Vector_e0() );
		vectorProduct.InsertRightOf( vectorProduct.RightMost(), new GeometricAlgebra::Vector_e1() );
		vectorProduct.InsertRightOf( vectorProduct.RightMost(), new GeometricAlgebra::Vector_e2() );
		vectorProduct.InsertRightOf( vectorProduct.RightMost(), new GeometricAlgebra::Vector_ni() );
		vectorProduct.InsertRightOf( vectorProduct.RightMost(), new GeometricAlgebra::Vector_no() );
		blade->AssignBlade( vectorProduct, 1.0 );
	}
	else if( 0 == strcmp( variableName, "E0" ) )
	{
		blade = new GeometricAlgebra::Blade();
		Utilities::List vectorProduct;
		vectorProduct.InsertRightOf( vectorProduct.RightMost(), new GeometricAlgebra::Vector_e1() );
		vectorProduct.InsertRightOf( vectorProduct.RightMost(), new GeometricAlgebra::Vector_e2() );
		blade->AssignBlade( vectorProduct, 1.0 );
	}
	else if( 0 == strcmp( variableName, "E1" ) )
	{
		blade = new GeometricAlgebra::Blade();
		Utilities::List vectorProduct;
		vectorProduct.InsertRightOf( vectorProduct.RightMost(), new GeometricAlgebra::Vector_e2() );
		vectorProduct.InsertRightOf( vectorProduct.RightMost(), new GeometricAlgebra::Vector_e0() );
		blade->AssignBlade( vectorProduct, 1.0 );
	}
	else if( 0 == strcmp( variableName, "E2" ) )
	{
		blade = new GeometricAlgebra::Blade();
		Utilities::List vectorProduct;
		vectorProduct.InsertRightOf( vectorProduct.RightMost(), new GeometricAlgebra::Vector_e0() );
		vectorProduct.InsertRightOf( vectorProduct.RightMost(), new GeometricAlgebra::Vector_e1() );
		blade->AssignBlade( vectorProduct, 1.0 );
	}
	else if( 0 == strcmp( variableName, "Omega" ) )
	{
		sumOfBlades = new GeometricAlgebra::SumOfBlades();

		Utilities::List vectorProduct;

		GeometricAlgebra::Blade blade_e1e5;
		vectorProduct.InsertRightOf( vectorProduct.RightMost(), new GeometricAlgebra::Vector_e1() );
		vectorProduct.InsertRightOf( vectorProduct.RightMost(), new GeometricAlgebra::Vector_e1_bar() );
		blade_e1e5.AssignBlade( vectorProduct, 1.0 );

		GeometricAlgebra::Blade blade_e2e6;
		vectorProduct.InsertRightOf( vectorProduct.RightMost(), new GeometricAlgebra::Vector_e2() );
		vectorProduct.InsertRightOf( vectorProduct.RightMost(), new GeometricAlgebra::Vector_e2_bar() );
		blade_e2e6.AssignBlade( vectorProduct, 1.0 );

		GeometricAlgebra::Blade blade_e3e7;
		vectorProduct.InsertRightOf( vectorProduct.RightMost(), new GeometricAlgebra::Vector_e3() );
		vectorProduct.InsertRightOf( vectorProduct.RightMost(), new GeometricAlgebra::Vector_e3_bar() );
		blade_e3e7.AssignBlade( vectorProduct, 1.0 );

		sumOfBlades->Accumulate( blade_e1e5 );
		sumOfBlades->Accumulate( blade_e2e6 );
		sumOfBlades->Accumulate( blade_e3e7 );
	}
	else if( 0 == strcmp( variableName, "Alpha" ) )
	{
		blade = new GeometricAlgebra::Blade();
		Utilities::List vectorProduct;
		vectorProduct.InsertRightOf( vectorProduct.RightMost(), new GeometricAlgebra::Vector_e0() );
		vectorProduct.InsertRightOf( vectorProduct.RightMost(), new GeometricAlgebra::Vector_e0_bar() );
		blade->AssignBlade( vectorProduct, 1.0 );
	}

	if( vector )
		multivectorNumber = new MultivectorNumber( *vector );
	else if( blade )
		multivectorNumber = new MultivectorNumber( *blade );
	else if( sumOfBlades )
		multivectorNumber = new MultivectorNumber( *sumOfBlades );

	delete vector;
	delete blade;
	delete sumOfBlades;

	if( multivectorNumber )
		evaluator = new ConstantEvaluator( multivectorNumber );

	return evaluator;
}

//=========================================================================================
/*virtual*/ Evaluator* GeometricAlgebraEnvironment::CreateBinaryOperator( const char* operatorName, Evaluator* leftOperand, Evaluator* rightOperand, bool& isBinaryOperationEvaluator )
{
	BinaryArithmeticOperationEvaluator* evaluator = 0;

	// The geometric product is handled through normal multiplication,
	// but the inner and outer products are a special case.
	if( 0 == strcmp( operatorName, "^" ) )
	{
		evaluator = new BinaryArithmeticOperationEvaluator( BinaryArithmeticOperationEvaluator::ARITHMETIC_OPERATION_OUTER_PRODUCT );
		isBinaryOperationEvaluator = true;
	}
	else if( 0 == strcmp( operatorName, "." ) )
	{
		evaluator = new BinaryArithmeticOperationEvaluator( BinaryArithmeticOperationEvaluator::ARITHMETIC_OPERATION_INNER_PRODUCT );
		isBinaryOperationEvaluator = true;
	}

	return evaluator;
}

//=========================================================================================
/*virtual*/ Evaluator* GeometricAlgebraEnvironment::CreateUnaryOperator( const char* operatorName, Evaluator* operand, bool& isUnaryOperationEvaluator )
{
	Evaluator* evaluator = 0;

	if( 0 == strcmp( operatorName, "~" ) )
	{
		ReverseFunctionEvaluator* reverseFunctionEvaluator = new ReverseFunctionEvaluator();
		FunctionArgumentEvaluator* argument = new FunctionArgumentEvaluator();
		argument->Argument( operand );
		reverseFunctionEvaluator->AddArgument( argument, FunctionEvaluator::APPEND_TO_LIST_OF_ARGS );
		evaluator = reverseFunctionEvaluator;
		isUnaryOperationEvaluator = false;
	}

	return evaluator;
}

// GeometricAlgebraEnv.cpp<commit_msg>fix bug i recently introduced<commit_after>// GeometricAlgebraEnv.cpp

/*
 * Copyright (C) 2012 Spencer T. Parkin
 *
 * This software has been released under the MIT License.
 * See the "License.txt" file in the project root directory
 * for more information about this license.
 *
 */

#include "../../CalcLib.h"

using namespace CalcLib;

//=========================================================================================
IMPLEMENT_CALCLIB_CLASS1( GeometricAlgebraEnvironment, Environment );

//=========================================================================================
GeometricAlgebraEnvironment::GeometricAlgebraEnvironment( void )
{
	displayMode = DISPLAY_AS_SUM_OF_BLADES;
}

//=========================================================================================
/*virtual*/ GeometricAlgebraEnvironment::~GeometricAlgebraEnvironment( void )
{
}

//=========================================================================================
/*virtual*/ void GeometricAlgebraEnvironment::PrintEnvironmentInfo( void )
{
	Print(
		"\n"
		"You are in the geometric algebra environment.\n"
		"\n"
	);
}

//=========================================================================================
/*virtual*/ Number* GeometricAlgebraEnvironment::CreateNumber( void )
{
	MultivectorNumber* multivectorNumber = new MultivectorNumber();
	Number* number = multivectorNumber;
	return number;
}

//=========================================================================================
/*virtual*/ FunctionEvaluator* GeometricAlgebraEnvironment::CreateFunction( const char* functionName )
{
	FunctionEvaluator* functionEvaluator = 0;

	if( 0 == strcmp( functionName, "reverse" ) )
		functionEvaluator = new ReverseFunctionEvaluator();
	else if( 0 == strcmp( functionName, "scalar_part" ) )
		functionEvaluator = new ScalarPartFunctionEvaluator();
	else if( 0 == strcmp( functionName, "grade_part" ) )
		functionEvaluator = new GradePartFunctionEvaluator();
	else if( 0 == strcmp( functionName, "inverse" ) )
		functionEvaluator = new InverseFunctionEvaluator();
	else if( 0 == strcmp( functionName, "exp" ) )
		functionEvaluator = new MultivectorMathFunctionEvaluator( MultivectorMathFunctionEvaluator::FUNC_EXP );
	else if( 0 == strcmp( functionName, "log" ) )
		functionEvaluator = new MultivectorMathFunctionEvaluator( MultivectorMathFunctionEvaluator::FUNC_LOG );
	else if( 0 == strcmp( functionName, "pow" ) )
		functionEvaluator = new MultivectorMathFunctionEvaluator( MultivectorMathFunctionEvaluator::FUNC_POW );
	else if( 0 == strcmp( functionName, "sqrt" ) )
		functionEvaluator = new MultivectorMathFunctionEvaluator( MultivectorMathFunctionEvaluator::FUNC_SQRT );
	else if( 0 == strcmp( functionName, "cos" ) )
		functionEvaluator = new MultivectorMathFunctionEvaluator( MultivectorMathFunctionEvaluator::FUNC_COS );
	else if( 0 == strcmp( functionName, "sin" ) )
		functionEvaluator = new MultivectorMathFunctionEvaluator( MultivectorMathFunctionEvaluator::FUNC_SIN );
	else if( 0 == strcmp( functionName, "tan" ) )
		functionEvaluator = new MultivectorMathFunctionEvaluator( MultivectorMathFunctionEvaluator::FUNC_TAN );
	else if( 0 == strcmp( functionName, "abs" ) )
		functionEvaluator = new MultivectorMathFunctionEvaluator( MultivectorMathFunctionEvaluator::FUNC_ABS );
	else if( 0 == strcmp( functionName, "acos" ) )
		functionEvaluator = new MultivectorMathFunctionEvaluator( MultivectorMathFunctionEvaluator::FUNC_ACOS );
	else if( 0 == strcmp( functionName, "asin" ) )
		functionEvaluator = new MultivectorMathFunctionEvaluator( MultivectorMathFunctionEvaluator::FUNC_ASIN );
//	else if( 0 == strcmp( functionName, "conjugate" ) )
//		functionEvaluator = new ConjugateFunctionEvaluator();
	else
		functionEvaluator = Environment::CreateFunction( functionName );

	return functionEvaluator;
}

//=========================================================================================
/*virtual*/ Evaluator* GeometricAlgebraEnvironment::CreateVariable( const char* variableName )
{
	ConstantEvaluator* evaluator = 0;
	MultivectorNumber* multivectorNumber = 0;
	GeometricAlgebra::Vector* vector = 0;
	GeometricAlgebra::Blade* blade = 0;
	GeometricAlgebra::SumOfBlades* sumOfBlades = 0;

	if( 0 == strcmp( variableName, "e0" ) )
		vector = new GeometricAlgebra::Vector_e0();
	else if( 0 == strcmp( variableName, "e1" ) )
		vector = new GeometricAlgebra::Vector_e1();
	else if( 0 == strcmp( variableName, "e2" ) )
		vector = new GeometricAlgebra::Vector_e2();
	else if( 0 == strcmp( variableName, "e3" ) )
		vector = new GeometricAlgebra::Vector_e3();
	else if( 0 == strcmp( variableName, "e0b" ) )
		vector = new GeometricAlgebra::Vector_e0_bar();
	else if( 0 == strcmp( variableName, "e1b" ) )
		vector = new GeometricAlgebra::Vector_e1_bar();
	else if( 0 == strcmp( variableName, "e2b" ) )
		vector = new GeometricAlgebra::Vector_e2_bar();
	else if( 0 == strcmp( variableName, "e3b" ) )
		vector = new GeometricAlgebra::Vector_e3_bar();
	else if( 0 == strcmp( variableName, "no" ) )
		vector = new GeometricAlgebra::Vector_no();
	else if( 0 == strcmp( variableName, "ni" ) )
		vector = new GeometricAlgebra::Vector_ni();
	else if( 0 == strcmp( variableName, "nob" ) )
		vector = new GeometricAlgebra::Vector_no_bar();
	else if( 0 == strcmp( variableName, "nib" ) )
		vector = new GeometricAlgebra::Vector_ni_bar();
	else if( 0 == strcmp( variableName, "i" ) )
	{
		blade = new GeometricAlgebra::Blade();
		Utilities::List vectorProduct;
		vectorProduct.InsertRightOf( vectorProduct.RightMost(), new GeometricAlgebra::Vector_e1() );
		vectorProduct.InsertRightOf( vectorProduct.RightMost(), new GeometricAlgebra::Vector_e2() );
		vectorProduct.InsertRightOf( vectorProduct.RightMost(), new GeometricAlgebra::Vector_e3() );
		blade->AssignBlade( vectorProduct, 1.0 );
	}
	else if( 0 == strcmp( variableName, "I" ) )
	{
		blade = new GeometricAlgebra::Blade();
		Utilities::List vectorProduct;
		vectorProduct.InsertRightOf( vectorProduct.RightMost(), new GeometricAlgebra::Vector_e1() );
		vectorProduct.InsertRightOf( vectorProduct.RightMost(), new GeometricAlgebra::Vector_e2() );
		vectorProduct.InsertRightOf( vectorProduct.RightMost(), new GeometricAlgebra::Vector_e3() );
		vectorProduct.InsertRightOf( vectorProduct.RightMost(), new GeometricAlgebra::Vector_ni() );
		vectorProduct.InsertRightOf( vectorProduct.RightMost(), new GeometricAlgebra::Vector_no() );
		blade->AssignBlade( vectorProduct, 1.0 );
	}
	else if( 0 == strcmp( variableName, "E2" ) )
	{
		blade = new GeometricAlgebra::Blade();
		Utilities::List vectorProduct;
		vectorProduct.InsertRightOf( vectorProduct.RightMost(), new GeometricAlgebra::Vector_e3() );
		vectorProduct.InsertRightOf( vectorProduct.RightMost(), new GeometricAlgebra::Vector_e1() );
		blade->AssignBlade( vectorProduct, 1.0 );
	}
	else if( 0 == strcmp( variableName, "E1" ) )
	{
		blade = new GeometricAlgebra::Blade();
		Utilities::List vectorProduct;
		vectorProduct.InsertRightOf( vectorProduct.RightMost(), new GeometricAlgebra::Vector_e2() );
		vectorProduct.InsertRightOf( vectorProduct.RightMost(), new GeometricAlgebra::Vector_e0() );
		blade->AssignBlade( vectorProduct, 1.0 );
	}
	else if( 0 == strcmp( variableName, "E3" ) )
	{
		blade = new GeometricAlgebra::Blade();
		Utilities::List vectorProduct;
		vectorProduct.InsertRightOf( vectorProduct.RightMost(), new GeometricAlgebra::Vector_e1() );
		vectorProduct.InsertRightOf( vectorProduct.RightMost(), new GeometricAlgebra::Vector_e2() );
		blade->AssignBlade( vectorProduct, 1.0 );
	}
	else if( 0 == strcmp( variableName, "Omega" ) )
	{
		sumOfBlades = new GeometricAlgebra::SumOfBlades();

		Utilities::List vectorProduct;

		GeometricAlgebra::Blade blade_e1e5;
		vectorProduct.InsertRightOf( vectorProduct.RightMost(), new GeometricAlgebra::Vector_e1() );
		vectorProduct.InsertRightOf( vectorProduct.RightMost(), new GeometricAlgebra::Vector_e1_bar() );
		blade_e1e5.AssignBlade( vectorProduct, 1.0 );

		GeometricAlgebra::Blade blade_e2e6;
		vectorProduct.InsertRightOf( vectorProduct.RightMost(), new GeometricAlgebra::Vector_e2() );
		vectorProduct.InsertRightOf( vectorProduct.RightMost(), new GeometricAlgebra::Vector_e2_bar() );
		blade_e2e6.AssignBlade( vectorProduct, 1.0 );

		GeometricAlgebra::Blade blade_e3e7;
		vectorProduct.InsertRightOf( vectorProduct.RightMost(), new GeometricAlgebra::Vector_e3() );
		vectorProduct.InsertRightOf( vectorProduct.RightMost(), new GeometricAlgebra::Vector_e3_bar() );
		blade_e3e7.AssignBlade( vectorProduct, 1.0 );

		sumOfBlades->Accumulate( blade_e1e5 );
		sumOfBlades->Accumulate( blade_e2e6 );
		sumOfBlades->Accumulate( blade_e3e7 );
	}
	else if( 0 == strcmp( variableName, "Alpha" ) )
	{
		blade = new GeometricAlgebra::Blade();
		Utilities::List vectorProduct;
		vectorProduct.InsertRightOf( vectorProduct.RightMost(), new GeometricAlgebra::Vector_e0() );
		vectorProduct.InsertRightOf( vectorProduct.RightMost(), new GeometricAlgebra::Vector_e0_bar() );
		blade->AssignBlade( vectorProduct, 1.0 );
	}

	if( vector )
		multivectorNumber = new MultivectorNumber( *vector );
	else if( blade )
		multivectorNumber = new MultivectorNumber( *blade );
	else if( sumOfBlades )
		multivectorNumber = new MultivectorNumber( *sumOfBlades );

	delete vector;
	delete blade;
	delete sumOfBlades;

	if( multivectorNumber )
		evaluator = new ConstantEvaluator( multivectorNumber );

	return evaluator;
}

//=========================================================================================
/*virtual*/ Evaluator* GeometricAlgebraEnvironment::CreateBinaryOperator( const char* operatorName, Evaluator* leftOperand, Evaluator* rightOperand, bool& isBinaryOperationEvaluator )
{
	BinaryArithmeticOperationEvaluator* evaluator = 0;

	// The geometric product is handled through normal multiplication,
	// but the inner and outer products are a special case.
	if( 0 == strcmp( operatorName, "^" ) )
	{
		evaluator = new BinaryArithmeticOperationEvaluator( BinaryArithmeticOperationEvaluator::ARITHMETIC_OPERATION_OUTER_PRODUCT );
		isBinaryOperationEvaluator = true;
	}
	else if( 0 == strcmp( operatorName, "." ) )
	{
		evaluator = new BinaryArithmeticOperationEvaluator( BinaryArithmeticOperationEvaluator::ARITHMETIC_OPERATION_INNER_PRODUCT );
		isBinaryOperationEvaluator = true;
	}

	return evaluator;
}

//=========================================================================================
/*virtual*/ Evaluator* GeometricAlgebraEnvironment::CreateUnaryOperator( const char* operatorName, Evaluator* operand, bool& isUnaryOperationEvaluator )
{
	Evaluator* evaluator = 0;

	if( 0 == strcmp( operatorName, "~" ) )
	{
		ReverseFunctionEvaluator* reverseFunctionEvaluator = new ReverseFunctionEvaluator();
		FunctionArgumentEvaluator* argument = new FunctionArgumentEvaluator();
		argument->Argument( operand );
		reverseFunctionEvaluator->AddArgument( argument, FunctionEvaluator::APPEND_TO_LIST_OF_ARGS );
		evaluator = reverseFunctionEvaluator;
		isUnaryOperationEvaluator = false;
	}

	return evaluator;
}

// GeometricAlgebraEnv.cpp<|endoftext|>


<commit_before>/*
 * Copyright 2014 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "SkRecordDraw.h"
#include "SkTSort.h"

void SkRecordDraw(const SkRecord& record,
                  SkCanvas* canvas,
                  const SkBBoxHierarchy* bbh,
                  SkDrawPictureCallback* callback) {
    SkAutoCanvasRestore saveRestore(canvas, true /*save now, restore at exit*/);

    if (NULL != bbh) {
        // Draw only ops that affect pixels in the canvas's current clip.
        SkIRect query;
#if 1   // TODO: Why is this the right way to make the query?  I'd think it'd be the else branch.
        SkRect clipBounds;
        canvas->getClipBounds(&clipBounds);
        clipBounds.roundOut(&query);
#else
        canvas->getClipDeviceBounds(&query);
#endif
        SkTDArray<void*> ops;
        bbh->search(query, &ops);

        SkRecords::Draw draw(canvas);
        for (int i = 0; i < ops.count(); i++) {
            if (NULL != callback && callback->abortDrawing()) {
                return;
            }
            record.visit<void>((uintptr_t)ops[i], draw);  // See FillBounds below.
        }
    } else {
        // Draw all ops.
        for (SkRecords::Draw draw(canvas); draw.index() < record.count(); draw.next()) {
            if (NULL != callback && callback->abortDrawing()) {
                return;
            }
            record.visit<void>(draw.index(), draw);
        }
    }
}

namespace SkRecords {

// FIXME: SkBitmaps are stateful, so we need to copy them to play back in multiple threads.
static SkBitmap shallow_copy(const SkBitmap& bitmap) {
    return bitmap;
}

// NoOps draw nothing.
template <> void Draw::draw(const NoOp&) {}

#define DRAW(T, call) template <> void Draw::draw(const T& r) { fCanvas->call; }
DRAW(Restore, restore());
DRAW(Save, save());
DRAW(SaveLayer, saveLayer(r.bounds, r.paint, r.flags));
DRAW(PopCull, popCull());
DRAW(PushCull, pushCull(r.rect));
DRAW(Clear, clear(r.color));
DRAW(Concat, concat(r.matrix));
DRAW(SetMatrix, setMatrix(SkMatrix::Concat(fInitialCTM, r.matrix)));

DRAW(ClipPath, clipPath(r.path, r.op, r.doAA));
DRAW(ClipRRect, clipRRect(r.rrect, r.op, r.doAA));
DRAW(ClipRect, clipRect(r.rect, r.op, r.doAA));
DRAW(ClipRegion, clipRegion(r.region, r.op));

DRAW(DrawBitmap, drawBitmap(shallow_copy(r.bitmap), r.left, r.top, r.paint));
DRAW(DrawBitmapMatrix, drawBitmapMatrix(shallow_copy(r.bitmap), r.matrix, r.paint));
DRAW(DrawBitmapNine, drawBitmapNine(shallow_copy(r.bitmap), r.center, r.dst, r.paint));
DRAW(DrawBitmapRectToRect,
        drawBitmapRectToRect(shallow_copy(r.bitmap), r.src, r.dst, r.paint, r.flags));
DRAW(DrawDRRect, drawDRRect(r.outer, r.inner, r.paint));
DRAW(DrawOval, drawOval(r.oval, r.paint));
DRAW(DrawPaint, drawPaint(r.paint));
DRAW(DrawPath, drawPath(r.path, r.paint));
DRAW(DrawPatch, drawPatch(r.cubics, r.colors, r.texCoords, r.xmode.get(), r.paint));
DRAW(DrawPicture, drawPicture(r.picture, r.matrix, r.paint));
DRAW(DrawPoints, drawPoints(r.mode, r.count, r.pts, r.paint));
DRAW(DrawPosText, drawPosText(r.text, r.byteLength, r.pos, r.paint));
DRAW(DrawPosTextH, drawPosTextH(r.text, r.byteLength, r.xpos, r.y, r.paint));
DRAW(DrawRRect, drawRRect(r.rrect, r.paint));
DRAW(DrawRect, drawRect(r.rect, r.paint));
DRAW(DrawSprite, drawSprite(shallow_copy(r.bitmap), r.left, r.top, r.paint));
DRAW(DrawText, drawText(r.text, r.byteLength, r.x, r.y, r.paint));
DRAW(DrawTextOnPath, drawTextOnPath(r.text, r.byteLength, r.path, r.matrix, r.paint));
DRAW(DrawVertices, drawVertices(r.vmode, r.vertexCount, r.vertices, r.texs, r.colors,
                                r.xmode.get(), r.indices, r.indexCount, r.paint));
#undef DRAW

// This is an SkRecord visitor that fills an SkBBoxHierarchy.
//
// The interesting part here is how to calculate bounds for ops which don't
// have intrinsic bounds.  What is the bounds of a Save or a Translate?
//
// We answer this by thinking about a particular definition of bounds: if I
// don't execute this op, pixels in this rectangle might draw incorrectly.  So
// the bounds of a Save, a Translate, a Restore, etc. are the union of the
// bounds of Draw* ops that they might have an effect on.  For any given
// Save/Restore block, the bounds of the Save, the Restore, and any other
// non-drawing ("control") ops inside are exactly the union of the bounds of
// the drawing ops inside that block.
//
// To implement this, we keep a stack of active Save blocks.  As we consume ops
// inside the Save/Restore block, drawing ops are unioned with the bounds of
// the block, and control ops are stashed away for later.  When we finish the
// block with a Restore, our bounds are complete, and we go back and fill them
// in for all the control ops we stashed away.
class FillBounds : SkNoncopyable {
public:
    FillBounds(const SkRecord& record, SkBBoxHierarchy* bbh) : fBounds(record.count()) {
        // Calculate bounds for all ops.  This won't go quite in order, so we'll need
        // to store the bounds separately then feed them in to the BBH later in order.
        const SkIRect largest = SkIRect::MakeLargest();
        fCTM.setIdentity();
        fCurrentClipBounds = largest;
        for (fCurrentOp = 0; fCurrentOp < record.count(); fCurrentOp++) {
            record.visit<void>(fCurrentOp, *this);
        }

        // If we have any lingering unpaired Saves, simulate restores to make
        // sure all ops in those Save blocks have their bounds calculated.
        while (!fSaveStack.isEmpty()) {
            this->popSaveBlock();
        }

        // Any control ops not part of any Save/Restore block draw everywhere.
        while (!fControlIndices.isEmpty()) {
            this->popControl(largest);
        }

        // Finally feed all stored bounds into the BBH.  They'll be returned in this order.
        SkASSERT(NULL != bbh);
        for (uintptr_t i = 0; i < record.count(); i++) {
            if (!fBounds[i].isEmpty()) {
                bbh->insert((void*)i, fBounds[i], true/*ok to defer*/);
            }
        }
        bbh->flushDeferredInserts();
    }

    template <typename T> void operator()(const T& op) {
        this->updateCTM(op);
        this->updateClipBounds(op);
        this->trackBounds(op);
    }

private:
    struct SaveBounds {
        int controlOps;        // Number of control ops in this Save block, including the Save.
        SkIRect bounds;        // Bounds of everything in the block.
        const SkPaint* paint;  // Unowned.  If set, adjusts the bounds of all ops in this block.
    };

    template <typename T> void updateCTM(const T&) { /* most ops don't change the CTM */ }
    void updateCTM(const Restore& op)   { fCTM = op.matrix; }
    void updateCTM(const SetMatrix& op) { fCTM = op.matrix; }
    void updateCTM(const Concat& op)    { fCTM.preConcat(op.matrix); }

    template <typename T> void updateClipBounds(const T&) { /* most ops don't change the clip */ }
    // Each of these devBounds fields is the state of the device bounds after the op.
    // So Restore's devBounds are those bounds saved by its paired Save or SaveLayer.
    void updateClipBounds(const Restore& op)    { fCurrentClipBounds = op.devBounds; }
    void updateClipBounds(const ClipPath& op)   { fCurrentClipBounds = op.devBounds; }
    void updateClipBounds(const ClipRRect& op)  { fCurrentClipBounds = op.devBounds; }
    void updateClipBounds(const ClipRect& op)   { fCurrentClipBounds = op.devBounds; }
    void updateClipBounds(const ClipRegion& op) { fCurrentClipBounds = op.devBounds; }
    void updateClipBounds(const SaveLayer& op)  {
        if (op.bounds) {
            fCurrentClipBounds.intersect(this->adjustAndMap(*op.bounds, op.paint));
        }
    }

    // The bounds of these ops must be calculated when we hit the Restore
    // from the bounds of the ops in the same Save block.
    void trackBounds(const Save&)          { this->pushSaveBlock(NULL); }
    // TODO: bounds of SaveLayer may be more complicated?
    void trackBounds(const SaveLayer& op)  { this->pushSaveBlock(op.paint); }
    void trackBounds(const Restore&) { fBounds[fCurrentOp] = this->popSaveBlock(); }

    void trackBounds(const Concat&)     { this->pushControl(); }
    void trackBounds(const SetMatrix&)  { this->pushControl(); }
    void trackBounds(const ClipRect&)   { this->pushControl(); }
    void trackBounds(const ClipRRect&)  { this->pushControl(); }
    void trackBounds(const ClipPath&)   { this->pushControl(); }
    void trackBounds(const ClipRegion&) { this->pushControl(); }

    // For all other ops, we can calculate and store the bounds directly now.
    template <typename T> void trackBounds(const T& op) {
        fBounds[fCurrentOp] = this->bounds(op);
        this->updateSaveBounds(fBounds[fCurrentOp]);
    }

    void pushSaveBlock(const SkPaint* paint) {
        // Starting a new Save block.  Push a new entry to represent that.
        SaveBounds sb = { 0, SkIRect::MakeEmpty(), paint };
        fSaveStack.push(sb);
        this->pushControl();
    }

    SkIRect popSaveBlock() {
        // We're done the Save block.  Apply the block's bounds to all control ops inside it.
        SaveBounds sb;
        fSaveStack.pop(&sb);
        while (sb.controlOps --> 0) {
            this->popControl(sb.bounds);
        }

        // This whole Save block may be part another Save block.
        this->updateSaveBounds(sb.bounds);

        // If called from a real Restore (not a phony one for balance), it'll need the bounds.
        return sb.bounds;
    }

    void pushControl() {
        fControlIndices.push(fCurrentOp);
        if (!fSaveStack.isEmpty()) {
            fSaveStack.top().controlOps++;
        }
    }

    void popControl(const SkIRect& bounds) {
        fBounds[fControlIndices.top()] = bounds;
        fControlIndices.pop();
    }

    void updateSaveBounds(const SkIRect& bounds) {
        // If we're in a Save block, expand its bounds to cover these bounds too.
        if (!fSaveStack.isEmpty()) {
            fSaveStack.top().bounds.join(bounds);
        }
    }

    // TODO: Remove this default when done bounding all ops.
    template <typename T> SkIRect bounds(const T&) { return fCurrentClipBounds; }
    SkIRect bounds(const Clear&) { return SkIRect::MakeLargest(); }  // Ignores the clip
    SkIRect bounds(const NoOp&)  { return SkIRect::MakeEmpty(); }    // NoOps don't draw anywhere.

    // Adjust rect for all paints that may affect its geometry, then map it to device space.
    SkIRect adjustAndMap(SkRect rect, const SkPaint* paint) {
        // Adjust rect for its own paint.
        if (paint) {
            if (paint->canComputeFastBounds()) {
                rect = paint->computeFastBounds(rect, &rect);
            } else {
                // The paint could do anything.  The only safe answer is the current clip.
                return fCurrentClipBounds;
            }
        }

        // Adjust rect for all the paints from the SaveLayers we're inside.
        // For SaveLayers, only image filters will affect the bounds.
        for (int i = fSaveStack.count() - 1; i >= 0; i--) {
            if (fSaveStack[i].paint && fSaveStack[i].paint->getImageFilter()) {
                if (paint->canComputeFastBounds()) {
                    rect = fSaveStack[i].paint->computeFastBounds(rect, &rect);
                } else {
                    // Same deal as above.
                    return fCurrentClipBounds;
                }
            }
        }

        // Map the rect back to device space.
        fCTM.mapRect(&rect);
        SkIRect devRect;
        rect.roundOut(&devRect);
        return devRect;
    }

    // Conservative device bounds for each op in the SkRecord.
    SkAutoTMalloc<SkIRect> fBounds;

    // We walk fCurrentOp through the SkRecord, as we go using updateCTM()
    // and updateClipBounds() to maintain the exact CTM (fCTM) and conservative
    // device bounds of the current clip (fCurrentClipBounds).
    unsigned fCurrentOp;
    SkMatrix fCTM;
    SkIRect fCurrentClipBounds;

    // Used to track the bounds of Save/Restore blocks and the control ops inside them.
    SkTDArray<SaveBounds> fSaveStack;
    SkTDArray<unsigned>   fControlIndices;
};

}  // namespace SkRecords

void SkRecordFillBounds(const SkRecord& record, SkBBoxHierarchy* bbh) {
    SkRecords::FillBounds(record, bbh);
}
<commit_msg>Small tweaks and a bug fix.<commit_after>/*
 * Copyright 2014 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "SkRecordDraw.h"
#include "SkTSort.h"

void SkRecordDraw(const SkRecord& record,
                  SkCanvas* canvas,
                  const SkBBoxHierarchy* bbh,
                  SkDrawPictureCallback* callback) {
    SkAutoCanvasRestore saveRestore(canvas, true /*save now, restore at exit*/);

    if (NULL != bbh) {
        // Draw only ops that affect pixels in the canvas's current clip.
        SkIRect query;
#if 1   // TODO: Why is this the right way to make the query?  I'd think it'd be the else branch.
        SkRect clipBounds;
        canvas->getClipBounds(&clipBounds);
        clipBounds.roundOut(&query);
#else
        canvas->getClipDeviceBounds(&query);
#endif
        SkTDArray<void*> ops;
        bbh->search(query, &ops);

        SkRecords::Draw draw(canvas);
        for (int i = 0; i < ops.count(); i++) {
            if (NULL != callback && callback->abortDrawing()) {
                return;
            }
            record.visit<void>((uintptr_t)ops[i], draw);  // See FillBounds below.
        }
    } else {
        // Draw all ops.
        for (SkRecords::Draw draw(canvas); draw.index() < record.count(); draw.next()) {
            if (NULL != callback && callback->abortDrawing()) {
                return;
            }
            record.visit<void>(draw.index(), draw);
        }
    }
}

namespace SkRecords {

// FIXME: SkBitmaps are stateful, so we need to copy them to play back in multiple threads.
static SkBitmap shallow_copy(const SkBitmap& bitmap) {
    return bitmap;
}

// NoOps draw nothing.
template <> void Draw::draw(const NoOp&) {}

#define DRAW(T, call) template <> void Draw::draw(const T& r) { fCanvas->call; }
DRAW(Restore, restore());
DRAW(Save, save());
DRAW(SaveLayer, saveLayer(r.bounds, r.paint, r.flags));
DRAW(PopCull, popCull());
DRAW(PushCull, pushCull(r.rect));
DRAW(Clear, clear(r.color));
DRAW(Concat, concat(r.matrix));
DRAW(SetMatrix, setMatrix(SkMatrix::Concat(fInitialCTM, r.matrix)));

DRAW(ClipPath, clipPath(r.path, r.op, r.doAA));
DRAW(ClipRRect, clipRRect(r.rrect, r.op, r.doAA));
DRAW(ClipRect, clipRect(r.rect, r.op, r.doAA));
DRAW(ClipRegion, clipRegion(r.region, r.op));

DRAW(DrawBitmap, drawBitmap(shallow_copy(r.bitmap), r.left, r.top, r.paint));
DRAW(DrawBitmapMatrix, drawBitmapMatrix(shallow_copy(r.bitmap), r.matrix, r.paint));
DRAW(DrawBitmapNine, drawBitmapNine(shallow_copy(r.bitmap), r.center, r.dst, r.paint));
DRAW(DrawBitmapRectToRect,
        drawBitmapRectToRect(shallow_copy(r.bitmap), r.src, r.dst, r.paint, r.flags));
DRAW(DrawDRRect, drawDRRect(r.outer, r.inner, r.paint));
DRAW(DrawOval, drawOval(r.oval, r.paint));
DRAW(DrawPaint, drawPaint(r.paint));
DRAW(DrawPath, drawPath(r.path, r.paint));
DRAW(DrawPatch, drawPatch(r.cubics, r.colors, r.texCoords, r.xmode.get(), r.paint));
DRAW(DrawPicture, drawPicture(r.picture, r.matrix, r.paint));
DRAW(DrawPoints, drawPoints(r.mode, r.count, r.pts, r.paint));
DRAW(DrawPosText, drawPosText(r.text, r.byteLength, r.pos, r.paint));
DRAW(DrawPosTextH, drawPosTextH(r.text, r.byteLength, r.xpos, r.y, r.paint));
DRAW(DrawRRect, drawRRect(r.rrect, r.paint));
DRAW(DrawRect, drawRect(r.rect, r.paint));
DRAW(DrawSprite, drawSprite(shallow_copy(r.bitmap), r.left, r.top, r.paint));
DRAW(DrawText, drawText(r.text, r.byteLength, r.x, r.y, r.paint));
DRAW(DrawTextOnPath, drawTextOnPath(r.text, r.byteLength, r.path, r.matrix, r.paint));
DRAW(DrawVertices, drawVertices(r.vmode, r.vertexCount, r.vertices, r.texs, r.colors,
                                r.xmode.get(), r.indices, r.indexCount, r.paint));
#undef DRAW

// This is an SkRecord visitor that fills an SkBBoxHierarchy.
//
// The interesting part here is how to calculate bounds for ops which don't
// have intrinsic bounds.  What is the bounds of a Save or a Translate?
//
// We answer this by thinking about a particular definition of bounds: if I
// don't execute this op, pixels in this rectangle might draw incorrectly.  So
// the bounds of a Save, a Translate, a Restore, etc. are the union of the
// bounds of Draw* ops that they might have an effect on.  For any given
// Save/Restore block, the bounds of the Save, the Restore, and any other
// non-drawing ("control") ops inside are exactly the union of the bounds of
// the drawing ops inside that block.
//
// To implement this, we keep a stack of active Save blocks.  As we consume ops
// inside the Save/Restore block, drawing ops are unioned with the bounds of
// the block, and control ops are stashed away for later.  When we finish the
// block with a Restore, our bounds are complete, and we go back and fill them
// in for all the control ops we stashed away.
class FillBounds : SkNoncopyable {
public:
    FillBounds(const SkRecord& record, SkBBoxHierarchy* bbh) : fBounds(record.count()) {
        // Calculate bounds for all ops.  This won't go quite in order, so we'll need
        // to store the bounds separately then feed them in to the BBH later in order.
        const SkIRect largest = SkIRect::MakeLargest();
        fCTM.setIdentity();
        fCurrentClipBounds = largest;
        for (fCurrentOp = 0; fCurrentOp < record.count(); fCurrentOp++) {
            record.visit<void>(fCurrentOp, *this);
        }

        // If we have any lingering unpaired Saves, simulate restores to make
        // sure all ops in those Save blocks have their bounds calculated.
        while (!fSaveStack.isEmpty()) {
            this->popSaveBlock();
        }

        // Any control ops not part of any Save/Restore block draw everywhere.
        while (!fControlIndices.isEmpty()) {
            this->popControl(largest);
        }

        // Finally feed all stored bounds into the BBH.  They'll be returned in this order.
        SkASSERT(NULL != bbh);
        for (uintptr_t i = 0; i < record.count(); i++) {
            if (!fBounds[i].isEmpty()) {
                bbh->insert((void*)i, fBounds[i], true/*ok to defer*/);
            }
        }
        bbh->flushDeferredInserts();
    }

    template <typename T> void operator()(const T& op) {
        this->updateCTM(op);
        this->updateClipBounds(op);
        this->trackBounds(op);
    }

private:
    struct SaveBounds {
        int controlOps;        // Number of control ops in this Save block, including the Save.
        SkIRect bounds;        // Bounds of everything in the block.
        const SkPaint* paint;  // Unowned.  If set, adjusts the bounds of all ops in this block.
    };

    template <typename T> void updateCTM(const T&) { /* most ops don't change the CTM */ }
    void updateCTM(const Restore& op)   { fCTM = op.matrix; }
    void updateCTM(const SetMatrix& op) { fCTM = op.matrix; }
    void updateCTM(const Concat& op)    { fCTM.preConcat(op.matrix); }

    template <typename T> void updateClipBounds(const T&) { /* most ops don't change the clip */ }
    // Each of these devBounds fields is the state of the device bounds after the op.
    // So Restore's devBounds are those bounds saved by its paired Save or SaveLayer.
    void updateClipBounds(const Restore& op)    { fCurrentClipBounds = op.devBounds; }
    void updateClipBounds(const ClipPath& op)   { fCurrentClipBounds = op.devBounds; }
    void updateClipBounds(const ClipRRect& op)  { fCurrentClipBounds = op.devBounds; }
    void updateClipBounds(const ClipRect& op)   { fCurrentClipBounds = op.devBounds; }
    void updateClipBounds(const ClipRegion& op) { fCurrentClipBounds = op.devBounds; }
    void updateClipBounds(const SaveLayer& op)  {
        if (op.bounds) {
            fCurrentClipBounds.intersect(this->adjustAndMap(*op.bounds, op.paint));
        }
    }

    // The bounds of these ops must be calculated when we hit the Restore
    // from the bounds of the ops in the same Save block.
    void trackBounds(const Save&)          { this->pushSaveBlock(NULL); }
    // TODO: bounds of SaveLayer may be more complicated?
    void trackBounds(const SaveLayer& op)  { this->pushSaveBlock(op.paint); }
    void trackBounds(const Restore&) { fBounds[fCurrentOp] = this->popSaveBlock(); }

    void trackBounds(const Concat&)     { this->pushControl(); }
    void trackBounds(const SetMatrix&)  { this->pushControl(); }
    void trackBounds(const ClipRect&)   { this->pushControl(); }
    void trackBounds(const ClipRRect&)  { this->pushControl(); }
    void trackBounds(const ClipPath&)   { this->pushControl(); }
    void trackBounds(const ClipRegion&) { this->pushControl(); }

    // For all other ops, we can calculate and store the bounds directly now.
    template <typename T> void trackBounds(const T& op) {
        fBounds[fCurrentOp] = this->bounds(op);
        this->updateSaveBounds(fBounds[fCurrentOp]);
    }

    void pushSaveBlock(const SkPaint* paint) {
        // Starting a new Save block.  Push a new entry to represent that.
        SaveBounds sb = { 0, SkIRect::MakeEmpty(), paint };
        fSaveStack.push(sb);
        this->pushControl();
    }

    SkIRect popSaveBlock() {
        // We're done the Save block.  Apply the block's bounds to all control ops inside it.
        SaveBounds sb;
        fSaveStack.pop(&sb);
        while (sb.controlOps --> 0) {
            this->popControl(sb.bounds);
        }

        // This whole Save block may be part another Save block.
        this->updateSaveBounds(sb.bounds);

        // If called from a real Restore (not a phony one for balance), it'll need the bounds.
        return sb.bounds;
    }

    void pushControl() {
        fControlIndices.push(fCurrentOp);
        if (!fSaveStack.isEmpty()) {
            fSaveStack.top().controlOps++;
        }
    }

    void popControl(const SkIRect& bounds) {
        fBounds[fControlIndices.top()] = bounds;
        fControlIndices.pop();
    }

    void updateSaveBounds(const SkIRect& bounds) {
        // If we're in a Save block, expand its bounds to cover these bounds too.
        if (!fSaveStack.isEmpty()) {
            fSaveStack.top().bounds.join(bounds);
        }
    }

    // TODO: Remove this default when done bounding all ops.
    template <typename T> SkIRect bounds(const T&) const { return fCurrentClipBounds; }
    SkIRect bounds(const Clear&) const { return SkIRect::MakeLargest(); }  // Ignores the clip
    SkIRect bounds(const NoOp&)  const { return SkIRect::MakeEmpty(); }    // NoOps don't draw.

    // Returns true if rect was meaningfully adjusted for the effects of paint,
    // false if the paint could affect the rect in unknown ways.
    static bool AdjustForPaint(const SkPaint* paint, SkRect* rect) {
        if (paint) {
            if (paint->canComputeFastBounds()) {
                *rect = paint->computeFastBounds(*rect, rect);
                return true;
            }
            return false;
        }
        return true;
    }

    // Adjust rect for all paints that may affect its geometry, then map it to device space.
    SkIRect adjustAndMap(SkRect rect, const SkPaint* paint) const {
        // Inverted rectangles really confuse our BBHs.
        rect.sort();

        // Adjust the rect for its own paint.
        if (!AdjustForPaint(paint, &rect)) {
            // The paint could do anything to our bounds.  The only safe answer is the current clip.
            return fCurrentClipBounds;
        }

        // Adjust rect for all the paints from the SaveLayers we're inside.
        for (int i = fSaveStack.count() - 1; i >= 0; i--) {
            if (!AdjustForPaint(fSaveStack[i].paint, &rect)) {
                // Same deal as above.
                return fCurrentClipBounds;
            }
        }

        // Map the rect back to device space.
        fCTM.mapRect(&rect);
        SkIRect devRect;
        rect.roundOut(&devRect);

        // Nothing can draw outside the current clip.
        // (Only bounded ops call into this method, so oddballs like Clear don't matter here.)
        devRect.intersect(fCurrentClipBounds);
        return devRect;
    }

    // Conservative device bounds for each op in the SkRecord.
    SkAutoTMalloc<SkIRect> fBounds;

    // We walk fCurrentOp through the SkRecord, as we go using updateCTM()
    // and updateClipBounds() to maintain the exact CTM (fCTM) and conservative
    // device bounds of the current clip (fCurrentClipBounds).
    unsigned fCurrentOp;
    SkMatrix fCTM;
    SkIRect fCurrentClipBounds;

    // Used to track the bounds of Save/Restore blocks and the control ops inside them.
    SkTDArray<SaveBounds> fSaveStack;
    SkTDArray<unsigned>   fControlIndices;
};

}  // namespace SkRecords

void SkRecordFillBounds(const SkRecord& record, SkBBoxHierarchy* bbh) {
    SkRecords::FillBounds(record, bbh);
}
<|endoftext|>


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

/**
 * @file
 *   This file implements ECDSA signing.
 */

#include "ecdsa.hpp"

#include <mbedtls/ecdsa.h>
#include <mbedtls/pk.h>

#include "common/code_utils.hpp"
#include "common/debug.hpp"
#include "common/random.hpp"

namespace ot {
namespace Crypto {

#if OPENTHREAD_ENABLE_ECDSA

otError Ecdsa::Sign(uint8_t *      aOutput,
                    uint16_t *     aOutputLength,
                    const uint8_t *aInputHash,
                    uint16_t       aInputHashLength,
                    const uint8_t *aPrivateKey,
                    uint16_t       aPrivateKeyLength)
{
    otError               error = OT_ERROR_NONE;
    mbedtls_ecdsa_context ctx;
    mbedtls_pk_context    pkCtx;
    mbedtls_ecp_keypair * keypair;
    mbedtls_mpi           rMpi;
    mbedtls_mpi           sMpi;

    mbedtls_pk_init(&pkCtx);
    mbedtls_ecdsa_init(&ctx);

    // Parse a private key in PEM format.
    VerifyOrExit(mbedtls_pk_parse_key(&pkCtx, aPrivateKey, aPrivateKeyLength, NULL, 0) == 0,
                 error = OT_ERROR_INVALID_ARGS);
    VerifyOrExit(mbedtls_pk_get_type(&pkCtx) == MBEDTLS_PK_ECKEY, error = OT_ERROR_INVALID_ARGS);

    keypair = mbedtls_pk_ec(pkCtx);
    assert(keypair != NULL);

    VerifyOrExit(mbedtls_ecdsa_from_keypair(&ctx, keypair) == 0, error = OT_ERROR_FAILED);

    mbedtls_mpi_init(&rMpi);
    mbedtls_mpi_init(&sMpi);

    // Sign using ECDSA.
    VerifyOrExit(mbedtls_ecdsa_sign(&ctx.grp, &rMpi, &sMpi, &ctx.d, aInputHash, aInputHashLength, FillRandom, NULL) ==
                     0,
                 error = OT_ERROR_FAILED);
    VerifyOrExit(mbedtls_mpi_size(&rMpi) + mbedtls_mpi_size(&sMpi) <= *aOutputLength, error = OT_ERROR_NO_BUFS);

    // Concatenate the two octet sequences in the order R and then S.
    VerifyOrExit(mbedtls_mpi_write_binary(&rMpi, aOutput, mbedtls_mpi_size(&rMpi)) == 0, error = OT_ERROR_FAILED);
    *aOutputLength = mbedtls_mpi_size(&rMpi);

    VerifyOrExit(mbedtls_mpi_write_binary(&sMpi, aOutput + *aOutputLength, mbedtls_mpi_size(&sMpi)) == 0,
                 error = OT_ERROR_FAILED);
    *aOutputLength += mbedtls_mpi_size(&sMpi);

exit:
    mbedtls_mpi_free(&rMpi);
    mbedtls_mpi_free(&sMpi);
    mbedtls_ecdsa_free(&ctx);
    mbedtls_pk_free(&pkCtx);

    return error;
}

int Ecdsa::FillRandom(void *, unsigned char *aBuffer, size_t aSize)
{
    Random::FillBuffer(aBuffer, aSize);

    return 0;
}

#endif // OPENTHREAD_ENABLE_ECDSA

} // namespace Crypto
} // namespace ot
<commit_msg>[ecdsa] do not free mpi context before initializing it (#3366)<commit_after>/*
 *  Copyright (c) 2018, The OpenThread Authors.
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *  1. Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *  2. Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *  3. Neither the name of the copyright holder nor the
 *     names of its contributors may be used to endorse or promote products
 *     derived from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *  POSSIBILITY OF SUCH DAMAGE.
 */

/**
 * @file
 *   This file implements ECDSA signing.
 */

#include "ecdsa.hpp"

#include <mbedtls/ecdsa.h>
#include <mbedtls/pk.h>

#include "common/code_utils.hpp"
#include "common/debug.hpp"
#include "common/random.hpp"

namespace ot {
namespace Crypto {

#if OPENTHREAD_ENABLE_ECDSA

otError Ecdsa::Sign(uint8_t *      aOutput,
                    uint16_t *     aOutputLength,
                    const uint8_t *aInputHash,
                    uint16_t       aInputHashLength,
                    const uint8_t *aPrivateKey,
                    uint16_t       aPrivateKeyLength)
{
    otError               error = OT_ERROR_NONE;
    mbedtls_ecdsa_context ctx;
    mbedtls_pk_context    pkCtx;
    mbedtls_ecp_keypair * keypair;
    mbedtls_mpi           rMpi;
    mbedtls_mpi           sMpi;

    mbedtls_pk_init(&pkCtx);
    mbedtls_ecdsa_init(&ctx);
    mbedtls_mpi_init(&rMpi);
    mbedtls_mpi_init(&sMpi);

    // Parse a private key in PEM format.
    VerifyOrExit(mbedtls_pk_parse_key(&pkCtx, aPrivateKey, aPrivateKeyLength, NULL, 0) == 0,
                 error = OT_ERROR_INVALID_ARGS);
    VerifyOrExit(mbedtls_pk_get_type(&pkCtx) == MBEDTLS_PK_ECKEY, error = OT_ERROR_INVALID_ARGS);

    keypair = mbedtls_pk_ec(pkCtx);
    assert(keypair != NULL);

    VerifyOrExit(mbedtls_ecdsa_from_keypair(&ctx, keypair) == 0, error = OT_ERROR_FAILED);

    // Sign using ECDSA.
    VerifyOrExit(mbedtls_ecdsa_sign(&ctx.grp, &rMpi, &sMpi, &ctx.d, aInputHash, aInputHashLength, FillRandom, NULL) ==
                     0,
                 error = OT_ERROR_FAILED);
    VerifyOrExit(mbedtls_mpi_size(&rMpi) + mbedtls_mpi_size(&sMpi) <= *aOutputLength, error = OT_ERROR_NO_BUFS);

    // Concatenate the two octet sequences in the order R and then S.
    VerifyOrExit(mbedtls_mpi_write_binary(&rMpi, aOutput, mbedtls_mpi_size(&rMpi)) == 0, error = OT_ERROR_FAILED);
    *aOutputLength = mbedtls_mpi_size(&rMpi);

    VerifyOrExit(mbedtls_mpi_write_binary(&sMpi, aOutput + *aOutputLength, mbedtls_mpi_size(&sMpi)) == 0,
                 error = OT_ERROR_FAILED);
    *aOutputLength += mbedtls_mpi_size(&sMpi);

exit:
    mbedtls_mpi_free(&rMpi);
    mbedtls_mpi_free(&sMpi);
    mbedtls_ecdsa_free(&ctx);
    mbedtls_pk_free(&pkCtx);

    return error;
}

int Ecdsa::FillRandom(void *, unsigned char *aBuffer, size_t aSize)
{
    Random::FillBuffer(aBuffer, aSize);

    return 0;
}

#endif // OPENTHREAD_ENABLE_ECDSA

} // namespace Crypto
} // namespace ot
<|endoftext|>


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

    ADSR.cpp
    Created: 5 Dec 2014 4:16:24pm
    Author:  Penguinum-tea

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

#include "ADSR.h"
#include <stdio.h>

namespace homu {

void ADSR::start() {
    state = attackState;
    current_sample = 0;
}

void ADSR::setAttack(float a) { attack = int(a * sample_rate); }

void ADSR::setDecay(float d) { decay = int(d * sample_rate); }

void ADSR::setSustain(float s) { sustain = s; }

void ADSR::setRelease(float r) { release = int(r * sample_rate); }

float ADSR::nextSample() {
    const int cur_state = state;
    switch (cur_state) {
    case attackState:
        if (attack == 0) {
            last_value = 1;
            state++;
        } else {
            last_value = float(current_sample) / float(attack);
            if (current_sample >= attack) {
                state++;
                current_sample = 0;
            }
        }
        break;
    case decayState:
        if (decay == 0) {
            last_value = sustain;
            state++;
        } else {
            last_value =
                1 - (1 - sustain) * float(current_sample) / float(decay);
            if (current_sample >= decay) {
                state++;
                current_sample = 0;
            }
        }
        break;
    case sustainState:
        last_value = sustain;
        break;
    case releaseState:
        if (release == 0) {
            last_value = 0;
            state++;
        } else {
            last_value = release_max -
                         release_max * float(current_sample) / float(release);
            if (current_sample >= release) {
                state = finalState;
            }
        }
        break;
    default:
        last_value = 0;
        break;
    }
    current_sample++;
    return last_value;
}

void ADSR::stopSustain() {
    if (state < releaseState) {
        state = releaseState;
        release_max = last_value;
        current_sample = 0;
    }
}

bool ADSR::finished() const {
    return (state == finalState);
}

int ADSR::getState() {
    return state;
}

void ADSR::setState(int s) {
    state = s;
}

}
<commit_msg>fix logic<commit_after>/*
  ==============================================================================

    ADSR.cpp
    Created: 5 Dec 2014 4:16:24pm
    Author:  Penguinum-tea

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

#include "ADSR.h"

namespace homu {

void ADSR::start() {
    state = attackState;
    current_sample = 0;
}

void ADSR::setAttack(float a) { attack = int(a * sample_rate); }

void ADSR::setDecay(float d) { decay = int(d * sample_rate); }

void ADSR::setSustain(float s) { sustain = s; }

void ADSR::setRelease(float r) { release = int(r * sample_rate); }

float ADSR::nextSample() {
    const int cur_state = state;
    switch (cur_state) {
    case attackState:
        if (attack == 0) {
            state++;
        } else {
            last_value = float(current_sample) / float(attack);
            if (current_sample >= attack) {
                state++;
                current_sample = 0;
            }
            break;
        }
    case decayState:
        if (decay == 0) {
            state++;
        } else {
            last_value =
                1 - (1 - sustain) * float(current_sample) / float(decay);
            if (current_sample >= decay) {
                state++;
                current_sample = 0;
            }
            break;
        }
    case sustainState:
        last_value = sustain;
        break;
    case releaseState:
        if (release == 0) {
            last_value = 0;
            state++;
        } else {
            last_value = release_max -
                         release_max * float(current_sample) / float(release);
            if (current_sample >= release) {
                state = finalState;
            }
        }
        break;
    default:
        last_value = 0;
        break;
    }
    current_sample++;
    return last_value;
}

void ADSR::stopSustain() {
    if (state < releaseState) {
        state = releaseState;
        release_max = last_value;
        current_sample = 0;
    }
}

bool ADSR::finished() const {
    return (state == finalState);
}

int ADSR::getState() {
    return state;
}

void ADSR::setState(int s) {
    state = s;
}

}
<|endoftext|>


<commit_before>#include "easypr/core/plate_detect.h"
#include "easypr/util/util.h"

namespace easypr {

  CPlateDetect::CPlateDetect() {
    m_plateLocate = new CPlateLocate();

    m_maxPlates = 3;
    m_type = 0;

    m_showDetect = false;
  }

  CPlateDetect::~CPlateDetect() { SAFE_RELEASE(m_plateLocate); }

  int CPlateDetect::plateDetect(Mat src, std::vector<CPlate> &resultVec, int type,
    bool showDetectArea, int img_index) {

    std::vector<CPlate> color_Plates;
    std::vector<CPlate> sobel_Plates;
    std::vector<CPlate> mser_Plates;

    std::vector<CPlate> all_result_Plates;
    if ( !type || type & PR_DETECT_SOBEL) {
      m_plateLocate->plateSobelLocate(src, sobel_Plates, img_index);
      std::vector<CPlate>& sobel_result_Plates = sobel_Plates;

      for (size_t i = 0; i < sobel_result_Plates.size(); i++) {
        CPlate plate = sobel_result_Plates[i];
        plate.setPlateLocateType(SOBEL);

        all_result_Plates.push_back(plate);
      }
    }

    if ( !type || type & PR_DETECT_COLOR) {
      m_plateLocate->plateColorLocate(src, color_Plates, img_index);
      std::vector<CPlate>& color_result_Plates = color_Plates;

      for (size_t i = 0; i < color_result_Plates.size(); i++) {
        CPlate plate = color_result_Plates[i];

        plate.setPlateLocateType(COLOR);
        all_result_Plates.push_back(plate);
      }
    }

    if ( !type || type & PR_DETECT_CMSER) {
      m_plateLocate->plateMserLocate(src, mser_Plates, img_index);
      std::vector<CPlate>& mser_result_Plates = mser_Plates;

      for (size_t i = 0; i < mser_result_Plates.size(); i++) {
        CPlate plate = mser_result_Plates[i];

        plate.setPlateLocateType(CMSER);
        all_result_Plates.push_back(plate);
      }
    }

    // ʹ÷Ǽֵжϳ
    PlateJudge::instance()->plateJudgeUsingNMS(all_result_Plates, resultVec, m_maxPlates);

    if (showDetectArea || getDetectShow()) {
      int index = 0;

      Mat result;
      src.copyTo(result);

      for (size_t j = 0; j < resultVec.size(); j++) {
        CPlate item = resultVec[j];
        Mat plate = item.getPlateMat();

        int height = 36;
        int width = 136;
        if (height * index + height < result.rows) {
          Mat imageRoi = result(Rect(0, 0 + height * index, width, height));
          addWeighted(imageRoi, 0, plate, 1, 0, imageRoi);
        }
        index++;

        RotatedRect minRect = item.getPlatePos();
        Point2f rect_points[4];
        minRect.points(rect_points);

        Scalar lineColor = Scalar(255, 255, 255);

        if (item.getPlateLocateType() == SOBEL) lineColor = Scalar(255, 0, 0);
        if (item.getPlateLocateType() == COLOR) lineColor = Scalar(0, 255, 0);
        if (item.getPlateLocateType() == CMSER) lineColor = Scalar(0, 0, 255);

        for (int j = 0; j < 4; j++)
          line(result, rect_points[j], rect_points[(j + 1) % 4], lineColor, 2, 8);
      }

      //ʾλͼƬ
      showResult(result, img_index);
    }

    /*if (0) {
      Mat result = src.clone();
      for (size_t i = 0; i < all_result_Plates.size(); i++) {
        CPlate plate = all_result_Plates.at(i);

        Rect_<float> outputRect;
        calcSafeRect(plate.getPlatePos(), src, outputRect);
        cv::rectangle(result, outputRect, Scalar(0, 0, 255));

        if (0){
          std::stringstream ss(std::stringstream::in | std::stringstream::out);
          ss << "resources/image/tmp/plate_" << index << "_" << i << ".jpg";
          imwrite(ss.str(), src(outputRect));
        }
      }

      if (0) {
        imshow("result", result);
        waitKey(0);
        destroyWindow("result");
      }
    }*/

    return 0;
  }

  int CPlateDetect::plateDetect(Mat src, std::vector<CPlate> &resultVec, int img_index) {
    int result = plateDetect(src, resultVec, m_type, false, img_index);
    return result;
  }

  void CPlateDetect::LoadSVM(std::string path) {
    PlateJudge::instance()->LoadModel(path);
  }

  int CPlateDetect::showResult(const Mat &result, int img_index) {
    namedWindow("EasyPR", CV_WINDOW_AUTOSIZE);

    const int RESULTWIDTH = 640;   // 640 930
    const int RESULTHEIGHT = 540;  // 540 710

    Mat img_window;
    img_window.create(RESULTHEIGHT, RESULTWIDTH, CV_8UC3);

    int nRows = result.rows;
    int nCols = result.cols;

    Mat result_resize;
    if (nCols <= img_window.cols && nRows <= img_window.rows) {
      result_resize = result;

    }
    else if (nCols > img_window.cols && nRows <= img_window.rows) {
      float scale = float(img_window.cols) / float(nCols);
      resize(result, result_resize, Size(), scale, scale, CV_INTER_AREA);

    }
    else if (nCols <= img_window.cols && nRows > img_window.rows) {
      float scale = float(img_window.rows) / float(nRows);
      resize(result, result_resize, Size(), scale, scale, CV_INTER_AREA);

    }
    else if (nCols > img_window.cols && nRows > img_window.rows) {
      Mat result_middle;
      float scale = float(img_window.cols) / float(nCols);
      resize(result, result_middle, Size(), scale, scale, CV_INTER_AREA);

      if (result_middle.rows > img_window.rows) {
        float scale = float(img_window.rows) / float(result_middle.rows);
        resize(result_middle, result_resize, Size(), scale, scale, CV_INTER_AREA);
      }
      else {
        result_resize = result_middle;
      }
    }
    else {
      result_resize = result;
    }

    Mat imageRoi = img_window(Rect((RESULTWIDTH - result_resize.cols) / 2,
      (RESULTHEIGHT - result_resize.rows) / 2,
      result_resize.cols, result_resize.rows));
    addWeighted(imageRoi, 0, result_resize, 1, 0, imageRoi);

    if (1) {
      imshow("EasyPR", img_window);
      waitKey(0);
      destroyWindow("EasyPR");
    }

    if (1) {
      std::stringstream ss(std::stringstream::in | std::stringstream::out);
      ss << "resources/image/tmp/Result/plate_" << img_index << ".jpg";
      imwrite(ss.str(), img_window);
    }

    return 0;
  }
}<commit_msg>* fix #93.<commit_after>#include "easypr/core/plate_detect.h"
#include "easypr/util/util.h"

namespace easypr {

  CPlateDetect::CPlateDetect() {
    m_plateLocate = new CPlateLocate();

    m_maxPlates = 3;
    m_type = 0;

    m_showDetect = false;
  }

  CPlateDetect::~CPlateDetect() { SAFE_RELEASE(m_plateLocate); }

  int CPlateDetect::plateDetect(Mat src, std::vector<CPlate> &resultVec, int type,
    bool showDetectArea, int img_index) {

    std::vector<CPlate> color_Plates;
    std::vector<CPlate> sobel_Plates;
    std::vector<CPlate> mser_Plates;

    std::vector<CPlate> all_result_Plates;
    if ( !type || type & PR_DETECT_SOBEL) {
      m_plateLocate->plateSobelLocate(src, sobel_Plates, img_index);
      std::vector<CPlate>& sobel_result_Plates = sobel_Plates;

      for (size_t i = 0; i < sobel_result_Plates.size(); i++) {
        CPlate plate = sobel_result_Plates[i];
        plate.setPlateLocateType(SOBEL);

        all_result_Plates.push_back(plate);
      }
    }

    if ( !type || type & PR_DETECT_COLOR) {
      m_plateLocate->plateColorLocate(src, color_Plates, img_index);
      std::vector<CPlate>& color_result_Plates = color_Plates;

      for (size_t i = 0; i < color_result_Plates.size(); i++) {
        CPlate plate = color_result_Plates[i];

        plate.setPlateLocateType(COLOR);
        all_result_Plates.push_back(plate);
      }
    }

    if ( !type || type & PR_DETECT_CMSER) {
      m_plateLocate->plateMserLocate(src, mser_Plates, img_index);
      std::vector<CPlate>& mser_result_Plates = mser_Plates;

      for (size_t i = 0; i < mser_result_Plates.size(); i++) {
        CPlate plate = mser_result_Plates[i];

        plate.setPlateLocateType(CMSER);
        all_result_Plates.push_back(plate);
      }
    }

    // ʹ÷Ǽֵжϳ
    PlateJudge::instance()->plateJudgeUsingNMS(all_result_Plates, resultVec, m_maxPlates);

    if (showDetectArea || getDetectShow()) {
      int index = 0;

      Mat result;
      src.copyTo(result);

      for (size_t j = 0; j < resultVec.size(); j++) {
        CPlate item = resultVec[j];
        Mat plate = item.getPlateMat();

        int height = 36;
        int width = 136;
        if (height * index + height < result.rows) {
          Mat imageRoi = result(Rect(0, 0 + height * index, width, height));
          addWeighted(imageRoi, 0, plate, 1, 0, imageRoi);
        }
        index++;

        RotatedRect minRect = item.getPlatePos();
        Point2f rect_points[4];
        minRect.points(rect_points);

        Scalar lineColor = Scalar(255, 255, 255);

        if (item.getPlateLocateType() == SOBEL) lineColor = Scalar(255, 0, 0);
        if (item.getPlateLocateType() == COLOR) lineColor = Scalar(0, 255, 0);
        if (item.getPlateLocateType() == CMSER) lineColor = Scalar(0, 0, 255);

        for (int j = 0; j < 4; j++)
          line(result, rect_points[j], rect_points[(j + 1) % 4], lineColor, 2, 8);
      }

      //ʾλͼƬ
      showResult(result, img_index);
    }

    /*if (0) {
      Mat result = src.clone();
      for (size_t i = 0; i < all_result_Plates.size(); i++) {
        CPlate plate = all_result_Plates.at(i);

        Rect_<float> outputRect;
        calcSafeRect(plate.getPlatePos(), src, outputRect);
        cv::rectangle(result, outputRect, Scalar(0, 0, 255));

        if (0){
          std::stringstream ss(std::stringstream::in | std::stringstream::out);
          ss << "resources/image/tmp/plate_" << index << "_" << i << ".jpg";
          imwrite(ss.str(), src(outputRect));
        }
      }

      if (0) {
        imshow("result", result);
        waitKey(0);
        destroyWindow("result");
      }
    }*/

    return 0;
  }

  int CPlateDetect::plateDetect(Mat src, std::vector<CPlate> &resultVec, int img_index) {
    int result = plateDetect(src, resultVec, m_type, false, img_index);
    return result;
  }

  void CPlateDetect::LoadSVM(std::string path) {
    PlateJudge::instance()->LoadModel(path);
  }

  int CPlateDetect::showResult(const Mat &result, int img_index) {
    namedWindow("EasyPR", CV_WINDOW_AUTOSIZE);

    const int RESULTWIDTH = 640;   // 640 930
    const int RESULTHEIGHT = 540;  // 540 710

    Mat img_window;
    img_window.create(RESULTHEIGHT, RESULTWIDTH, CV_8UC3);

    int nRows = result.rows;
    int nCols = result.cols;

    Mat result_resize;
    if (nCols <= img_window.cols && nRows <= img_window.rows) {
      result_resize = result;

    }
    else if (nCols > img_window.cols && nRows <= img_window.rows) {
      float scale = float(img_window.cols) / float(nCols);
      resize(result, result_resize, Size(), scale, scale, CV_INTER_AREA);

    }
    else if (nCols <= img_window.cols && nRows > img_window.rows) {
      float scale = float(img_window.rows) / float(nRows);
      resize(result, result_resize, Size(), scale, scale, CV_INTER_AREA);

    }
    else if (nCols > img_window.cols && nRows > img_window.rows) {
      Mat result_middle;
      float scale = float(img_window.cols) / float(nCols);
      resize(result, result_middle, Size(), scale, scale, CV_INTER_AREA);

      if (result_middle.rows > img_window.rows) {
        float scale = float(img_window.rows) / float(result_middle.rows);
        resize(result_middle, result_resize, Size(), scale, scale, CV_INTER_AREA);
      }
      else {
        result_resize = result_middle;
      }
    }
    else {
      result_resize = result;
    }

    Mat imageRoi = img_window(Rect((RESULTWIDTH - result_resize.cols) / 2,
      (RESULTHEIGHT - result_resize.rows) / 2,
      result_resize.cols, result_resize.rows));
    addWeighted(imageRoi, 0, result_resize, 1, 0, imageRoi);

    if (1) {
      imshow("EasyPR", img_window);
      waitKey(0);
      destroyWindow("EasyPR");
    }

    if (1) {
      std::stringstream ss(std::stringstream::in | std::stringstream::out);
      ss << "resources/image/tmp/Result/plate_" << img_index << ".jpg";
      imwrite(ss.str(), img_window);
    }

    return 0;
  }
}<|endoftext|>