| 
									
										
										
										
											2002-10-12 11:37:38 +00:00
										 |  |  | // Operator2Expr.cpp: implementation of the COperator2Expr class.
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * Copyright (c) 1996-2000 Erwin Coumans <coockie@acm.org> | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Permission to use, copy, modify, distribute and sell this software | 
					
						
							|  |  |  |  * and its documentation for any purpose is hereby granted without fee, | 
					
						
							|  |  |  |  * provided that the above copyright notice appear in all copies and | 
					
						
							|  |  |  |  * that both that copyright notice and this permission notice appear | 
					
						
							|  |  |  |  * in supporting documentation.  Erwin Coumans makes no | 
					
						
							|  |  |  |  * representations about the suitability of this software for any | 
					
						
							|  |  |  |  * purpose.  It is provided "as is" without express or implied warranty. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | // 31 dec 1998 - big update: try to use the cached data for updating, instead of
 | 
					
						
							|  |  |  | // rebuilding completely it from left and right node. Modified flags and bounding boxes
 | 
					
						
							|  |  |  | // have to do the trick
 | 
					
						
							|  |  |  | // when expression is cached, there will be a call to UpdateCalc() instead of Calc()
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "Operator2Expr.h"
 | 
					
						
							|  |  |  | #include "StringValue.h"
 | 
					
						
							|  |  |  | #include "VoidValue.h"
 | 
					
						
							| 
									
										
										
										
											2002-11-25 15:29:57 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | #ifdef HAVE_CONFIG_H
 | 
					
						
							|  |  |  | #include <config.h>
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-10-12 11:37:38 +00:00
										 |  |  | //////////////////////////////////////////////////////////////////////
 | 
					
						
							|  |  |  | // Construction/Destruction
 | 
					
						
							|  |  |  | //////////////////////////////////////////////////////////////////////
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | COperator2Expr::COperator2Expr(VALUE_OPERATOR op, CExpression *lhs, CExpression *rhs) | 
					
						
							|  |  |  | : 	 | 
					
						
							|  |  |  | m_cached_calculate(NULL), | 
					
						
							|  |  |  | m_op(op), | 
					
						
							|  |  |  | m_lhs(lhs), | 
					
						
							|  |  |  | m_rhs(rhs) | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  | pre: | 
					
						
							|  |  |  | effect: constucts a COperator2Expr with op, lhs and rhs in it | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | COperator2Expr::COperator2Expr(): | 
					
						
							|  |  |  | m_cached_calculate(NULL), | 
					
						
							|  |  |  | m_lhs(NULL), | 
					
						
							|  |  |  | m_rhs(NULL) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  | pre: | 
					
						
							|  |  |  | effect: constucts an empty COperator2Expr | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | COperator2Expr::~COperator2Expr() | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  | pre: | 
					
						
							|  |  |  | effect: deletes the object | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if (m_lhs) | 
					
						
							|  |  |  | 		m_lhs->Release(); | 
					
						
							|  |  |  | 	if (m_rhs) | 
					
						
							|  |  |  | 		m_rhs->Release(); | 
					
						
							|  |  |  | 	if (m_cached_calculate) | 
					
						
							|  |  |  | 		m_cached_calculate->Release(); | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | CValue* COperator2Expr::Calculate() | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  | pre: | 
					
						
							|  |  |  | ret: a new object containing the result of applying operator m_op to m_lhs | 
					
						
							|  |  |  | and m_rhs | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	bool leftmodified,rightmodified; | 
					
						
							|  |  |  | 	leftmodified = m_lhs->NeedsRecalculated(); | 
					
						
							|  |  |  | 	rightmodified = m_rhs->NeedsRecalculated(); | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	// if no modifications on both left and right subtree, and result is already calculated
 | 
					
						
							|  |  |  | 	// then just return cached result...
 | 
					
						
							|  |  |  | 	if (!leftmodified && !rightmodified && (m_cached_calculate)) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		// not modified, just return m_cached_calculate
 | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		// if not yet calculated, or modified...
 | 
					
						
							|  |  |  | 		 | 
					
						
							|  |  |  | 		 | 
					
						
							|  |  |  | 		if (m_cached_calculate) { | 
					
						
							|  |  |  | 			m_cached_calculate->Release(); | 
					
						
							|  |  |  | 			m_cached_calculate=NULL; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		 | 
					
						
							|  |  |  | 		CValue* ffleft = m_lhs->Calculate(); | 
					
						
							|  |  |  | 		CValue* ffright = m_rhs->Calculate(); | 
					
						
							|  |  |  | 		 | 
					
						
							|  |  |  | 		ffleft->SetOwnerExpression(this);//->m_pOwnerExpression=this;
 | 
					
						
							|  |  |  | 		ffright->SetOwnerExpression(this);//->m_pOwnerExpression=this;
 | 
					
						
							|  |  |  | 		 | 
					
						
							|  |  |  | 		m_cached_calculate = ffleft->Calc(m_op,ffright); | 
					
						
							|  |  |  | 		 | 
					
						
							|  |  |  | 		//if (m_cached_calculate)				
 | 
					
						
							|  |  |  | 		//	m_cached_calculate->Action(CValue::SETOWNEREXPR,&CVoidValue(this,false,CValue::STACKVALUE));
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		ffleft->Release(); | 
					
						
							|  |  |  | 		ffright->Release(); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	return m_cached_calculate->AddRef(); | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  | bool COperator2Expr::IsInside(float x, float y, float z,bool bBorderInclude) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	bool inside; | 
					
						
							|  |  |  | 	inside = false; | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	switch (m_op)  | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 	case VALUE_ADD_OPERATOR: { | 
					
						
							|  |  |  | 	//	inside = first || second; // optimized with early out if first is inside
 | 
					
						
							|  |  |  | 		// todo: calculate smallest leaf first ! is much faster...
 | 
					
						
							|  |  |  | 			 | 
					
						
							|  |  |  | 		bool second;//first ;//,second;
 | 
					
						
							|  |  |  | 		 | 
					
						
							|  |  |  | 		//first = m_lhs->IsInside(x,y,z) ;
 | 
					
						
							|  |  |  | 		second = m_rhs->IsInside(x,y,z,bBorderInclude) ; | 
					
						
							|  |  |  | 		if (second) | 
					
						
							|  |  |  | 			return true; //early out
 | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	//	second = m_rhs->IsInside(x,y,z) ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		return m_lhs->IsInside(x,y,z,bBorderInclude) ; | 
					
						
							|  |  |  | 			 | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 							 } | 
					
						
							|  |  |  | 		 | 
					
						
							|  |  |  | 	case VALUE_SUB_OPERATOR: { | 
					
						
							|  |  |  | 		//inside = first && !second; // optimized with early out
 | 
					
						
							|  |  |  | 		// todo: same as with add_operator: calc smallest leaf first
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		bool second;//first ;//,second;
 | 
					
						
							|  |  |  | 		//first = m_lhs->IsInside(x,y,z) ;
 | 
					
						
							|  |  |  | 		second = m_rhs->IsInside(x,y,z,bBorderInclude); | 
					
						
							|  |  |  | 		if (second) | 
					
						
							|  |  |  | 			return false; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// second space get subtracted -> negate!
 | 
					
						
							|  |  |  | 		//second = m_rhs->IsInside(x,y,z);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		return (m_lhs->IsInside(x,y,z,bBorderInclude)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		 | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 							 } | 
					
						
							|  |  |  | 	default:{ | 
					
						
							|  |  |  | 		assert(false); | 
					
						
							|  |  |  | 		// not yet implemented, only add or sub csg operations
 | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	return inside;	 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool COperator2Expr::IsRightInside(float x, float y, float z,bool bBorderInclude) { | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	return m_rhs->IsInside(x,y,z,bBorderInclude) ; | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool COperator2Expr::IsLeftInside(float x, float y, float z,bool bBorderInclude) { | 
					
						
							|  |  |  | 	return m_lhs->IsInside(x,y,z,bBorderInclude); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | bool COperator2Expr::NeedsRecalculated() { | 
					
						
							|  |  |  | 	// added some lines, just for debugging purposes, it could be a one-liner :)
 | 
					
						
							|  |  |  | 	//bool modleft
 | 
					
						
							|  |  |  | 	//bool modright;
 | 
					
						
							|  |  |  | 	assertd(m_lhs); | 
					
						
							|  |  |  | 	assertd(m_rhs); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	//modright = m_rhs->NeedsRecalculated();
 | 
					
						
							|  |  |  | 	if (m_rhs->NeedsRecalculated()) // early out
 | 
					
						
							|  |  |  | 		return true; | 
					
						
							|  |  |  | 	return m_lhs->NeedsRecalculated(); | 
					
						
							|  |  |  | 	//modleft = m_lhs->NeedsRecalculated();
 | 
					
						
							|  |  |  | 	//return (modleft || modright);
 | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | CExpression* COperator2Expr::CheckLink(std::vector<CBrokenLinkInfo*>& brokenlinks) { | 
					
						
							|  |  |  | // if both children are 'dead', return NULL
 | 
					
						
							|  |  |  | // if only one child is alive, return that child
 | 
					
						
							|  |  |  | // if both childresn are alive, return this
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | //  	bool leftalive = true,rightalive=true;
 | 
					
						
							|  |  |  | 	/* Does this mean the function will always bomb? */ | 
					
						
							|  |  |  | 	assertd(false); | 
					
						
							|  |  |  | 	assert(m_lhs); | 
					
						
							|  |  |  | 	assert(m_rhs); | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  | 	if (m_cached_calculate) | 
					
						
							|  |  |  | 		m_cached_calculate->Action(CValue::REFRESH_CACHE); | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	CExpression* newlhs = m_lhs->CheckLink(brokenlinks); | 
					
						
							|  |  |  | 	CExpression* newrhs = m_rhs->CheckLink(brokenlinks); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (m_lhs != newlhs) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		brokenlinks.push_back(new CBrokenLinkInfo(&m_lhs,m_lhs)); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (m_rhs != newrhs) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		brokenlinks.push_back(new CBrokenLinkInfo(&m_rhs,m_rhs)); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	m_lhs = newlhs; | 
					
						
							|  |  |  | 	m_rhs = newrhs; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (m_lhs && m_rhs) { | 
					
						
							|  |  |  | 		return this; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	AddRef(); | 
					
						
							|  |  |  | 	if (m_lhs)  | 
					
						
							|  |  |  | 		return Release(m_lhs->AddRef()); | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	if (m_rhs) | 
					
						
							|  |  |  | 		return Release(m_rhs->AddRef()); | 
					
						
							|  |  |  | /		 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   */ | 
					
						
							|  |  |  |   return Release(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |    | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool COperator2Expr::MergeExpression(CExpression *otherexpr) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if (m_lhs) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		if (m_lhs->GetExpressionID() == CExpression::CCONSTEXPRESSIONID) | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			// cross fingers ;) replace constexpr by new tree...
 | 
					
						
							|  |  |  | 			m_lhs->Release(); | 
					
						
							|  |  |  | 			m_lhs = otherexpr->AddRef(); | 
					
						
							|  |  |  | 			return true; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	assertd(false); | 
					
						
							|  |  |  | 	return false; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void COperator2Expr::BroadcastOperators(VALUE_OPERATOR op) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if (m_lhs) | 
					
						
							|  |  |  | 		m_lhs->BroadcastOperators(m_op); | 
					
						
							|  |  |  | 	if (m_rhs) | 
					
						
							|  |  |  | 		m_rhs->BroadcastOperators(m_op); | 
					
						
							|  |  |  | } |