RealFde CFormulaNode::getAscent( const SizeFde &sz )
{
	RealFde vc = sz.height() / 2.0;

	switch( getAlignmentType() )
	{
	case FBtnChildPos::TableCenter2Baseline:
		if( (getAlignmentValue() - 1) >= 0 && (getAlignmentValue() - 1) < GetChildCount() )
		{
			CNode *pNode = GetChild( getAlignmentValue() - 1 );
			if( pNode != NULL )
				vc = pNode->GetPosition().y() + pNode->GetSize().height() / 2.0;
		}
		break;

	case FBtnChildPos::TableTop2Baseline:
		if( (getAlignmentValue() - 1) >= 0 && (getAlignmentValue() - 1) < GetChildCount() )
		{
			CNode *pNode = GetChild( getAlignmentValue() - 1 );
			if( pNode != NULL )
				vc = pNode->GetPosition().y();
			else
				vc = 0.0;
		}
		else
			vc = 0.0;
		break;

	case FBtnChildPos::TableBottom2Baseline:
		if( (getAlignmentValue() - 1) >= 0 && (getAlignmentValue() - 1) < GetChildCount() )
		{
			CNode *pNode = GetChild( getAlignmentValue() - 1 );
			if( pNode != NULL )
				vc = pNode->GetPosition().y() + pNode->GetSize().height();
			else
				vc = sz.height();
		}
		else
			vc = sz.height();
		break;
	default:
		vc = sz.height() - ::calculateCurrentTextDescent( GetLevel() );
		break;
	}

	return vc;
}
void CFormulaNode::RecalculateSize( int bRecalc )
{
	SizeFde sz( 0, 0 );
	int i = 0;

	sz = CFormulaExCalc::RecalculateSize( this );
	if( (i = RecalculateGrph( this, regetActiveCalc() )) != 0 )
	{
		sz = CFormulaExCalc::RecalculateSize( this );
		i = RecalculateGrph( this, regetActiveCalc() );
	}
	if( isHiddenNDisabled() )
	{
		sz.rwidth() = 0;
		if( GetParent() && GetParent()->GetSize().height() > 0 )
			sz.rheight() = GetParent()->GetSize().height();
		else
			sz.rheight() = GetDefaultSize().height();
	}
	Recalculate_VerticalCenter( sz );

	//=== 'mpadded' MathML element
	if( !isHiddenNDisabled() &&
		getAlignmentType() == FBtnChildPos::MSPACE_Exact_HeightDepth )
	{
		RealFde newValues[ MML_MPADDED_UNITS_LEN ] = { 0.0, 0.0, 0.0, 0.0 };
		RealFde childValues[ MML_MPADDED_UNITS_LEN ] = { 0.0, 0.0, 0.0, 0.0 };
		int iRet[ MML_MPADDED_UNITS_LEN ] = { -1, -1, -1, -1 };
		getChildDimensions_Vertical( childValues );
		getChildDimensions_Horizontal( childValues );

		getMathMLAttr().parseMPaddedAttr( newValues, childValues, iRet, ::getCurrentFormulatorStyle().getUnit2PX() );

		RealFde paddedLSpace = 0.0, paddedRSpace = 0.0;
		if( iRet[ MML_MPADDED_UNITS_LSPACE ] == 0 )
		{
			paddedLSpace = newValues[ MML_MPADDED_UNITS_LSPACE ];
		}
		if( iRet[ MML_MPADDED_UNITS_WIDTH ] == 0 )
		{
			RealFde width = newValues[ MML_MPADDED_UNITS_WIDTH ];
			RealFde delta = width - (paddedLSpace + childValues[ MML_MPADDED_UNITS_WIDTH ]);
			if( delta >= 0.0 )
				paddedRSpace = delta;
			else
			{
				paddedLSpace = width - childValues[ MML_MPADDED_UNITS_WIDTH ];
				if( paddedLSpace < 0.0 )
				{
					sz.rwidth() = width;
					paddedLSpace = 0.0;
				}
			}
		}

		RealFde paddedTSpace = 0.0, paddedBSpace = 0.0;
		if( iRet[ MML_MPADDED_UNITS_HEIGHT ] == 0 )
		{
			RealFde height = newValues[ MML_MPADDED_UNITS_HEIGHT ];
			RealFde delta = height - childValues[ MML_MPADDED_UNITS_HEIGHT ];
			if( delta >= 0 )
				paddedTSpace = delta;
			else
			{
				// not feasible 
			}
		}
		if( iRet[ MML_MPADDED_UNITS_DEPTH ] == 0 )
		{
			RealFde delta = newValues[ MML_MPADDED_UNITS_DEPTH ] - childValues[ MML_MPADDED_UNITS_DEPTH ];
			if( delta >= 0 )
				paddedBSpace = delta;
			else
			{
				// not feasible 
			}
		}

		if( paddedLSpace || paddedRSpace || paddedTSpace || paddedBSpace )
		{
			CNode *pNode = GetFirstChild();
			if( pNode && pNode->GetType() == NODE_FRAME )
			{
				CFrameNode *n1st = (CFrameNode*)pNode;
				n1st->setLeftIndent( paddedLSpace );
				n1st->setRightIndent( paddedRSpace );
				n1st->setTopIndent( paddedTSpace );
				n1st->setBottomIndent( paddedBSpace );
			}
		}
	}

	if( sz != GetSize() || i )
		SetSize( sz );

	if( bRecalc )
		GetParent()->RecalculateSize( bRecalc );
}
void CFormulaNode::Recalculate_VerticalCenter( const SizeFde &sz )
{
	RealFde vc = sz.height() / 2.0;

	switch( getAlignmentType() )
	{
	case FBtnChildPos::Child:
		if( getAlignmentValue() >= 1 && (getAlignmentValue() - 1) < getGraphPrimNumber() )
		{
			const RectFde& _t = getGraphPrimitivePositionRect( getAlignmentValue() - 1 );
			vc = (_t.top() + _t.bottom()) / 2.0;
		}
		break;
	case FBtnChildPos::Child_Average:
		if( getAlignmentValue() >= 1 && (getAlignmentValue() - 1) < getGraphPrimNumber() )
		{
			vc = 0.0;
			for( long i = 0; i <= getAlignmentValue() - 1; i++ )
			{
				const RectFde& _t = getGraphPrimitivePositionRect( i );
				vc += _t.top() + _t.bottom();
			}
			vc = vc / (getAlignmentValue() * 2.0);
		}
		break;
	case FBtnChildPos::MSPACE_Exact_HeightDepth:
	case FBtnChildPos::Frame:
		if( (getAlignmentValue() - 1) >= 0 && (getAlignmentValue() - 1) < GetChildCount() )
		{
			CNode *pNode = GetChild( getAlignmentValue() - 1 );
			if( pNode )
				vc = pNode->GetPosition().y() + pNode->GetVerticalCenter();
		}
		break;
	case FBtnChildPos::Frame_Blank_Average:
		{
			CNode *pNodeFirst = GetFirstChild();
			CNode *pNodeLast  = GetLastChild();
			if( pNodeFirst != NULL && pNodeLast != NULL )
			{
				vc = (pNodeFirst->GetPosition().y() + pNodeFirst->GetSize().height() + pNodeLast->GetPosition().y()) / 2.0;
			}
		}
		break;
	case FBtnChildPos::Half:
		break;

	case FBtnChildPos::TableAxis:
		if( (getAlignmentValue() - 1) >= 0 && (getAlignmentValue() - 1) < GetChildCount() )
		{
			CNode *pNode = GetChild( getAlignmentValue() - 1 );
			if( pNode )
				vc = pNode->GetPosition().y() + pNode->GetSize().height() / 2.0;
		}
		break;

	case FBtnChildPos::TableCenter2Baseline:
	case FBtnChildPos::TableTop2Baseline:
	case FBtnChildPos::TableBottom2Baseline:
		{
			RealFde asc = ::getCurrentDefaultAscent( GetLevel() );
			RealFde h = ::getCurrentDefaultSize( GetLevel() ).height();
			vc = getAscent( sz ) - asc + h - asc / 2.0;
		}
		break;

	default:
		break;
	}

	SetVerticalCenter( vc );
}
void OpenInfraPlatform::UserInterface::VerticalAlignmentScene::v_drawAlignment(
	buw::ReferenceCounted<buw::Alignment2DBased3D> a, 
	std::map<buw::eHorizontalAlignmentType, QPainterPath>& horizontalPainter,
	std::map<buw::eVerticalAlignmentType, QPainterPath>& verticalPainter)
{
	buw::ReferenceCounted<buw::HorizontalAlignment2D> h = a->getHorizontalAlignment();
	buw::ReferenceCounted<buw::VerticalAlignment2D> v = a->getVerticalAlignment();

	if (v != nullptr)
	{
		auto start = v->getPosition(v->getStartStation());
		auto end = v->getPosition(v->getEndStation());
				
		bounds[0] = bounds[1] = start.x();
		bounds[2] = bounds[3] = -start.y();

		double prevX = bounds[0], prevY = bounds[2];
		buw::eHorizontalAlignmentType lastType = buw::eHorizontalAlignmentType::Unknown;
		buw::eVerticalAlignmentType lastVerticalType = buw::eVerticalAlignmentType::Unknown;

		verticalPainter[lastVerticalType].moveTo(prevX, prevY);
		horizontalPainter[lastType].moveTo(prevX, prevY);

		for (double s = v->getStartStation(); s < v->getEndStation() ; s+=0.8)
		{
			auto position = v->getPosition(s);
			double x = position.x();
			double y = -position.y();

			if (differentColorsForVerticalAlignmentElements_)
			{
				auto ve = v->getAlignmentElementByStationing(s);
				buw::eVerticalAlignmentType type = ve->getAlignmentType();

				if (ve != nullptr)
				{
					if (verticalPainter.find(type) == verticalPainter.end())
						verticalPainter[type] = QPainterPath();

					if (lastVerticalType != type)
						verticalPainter[type].moveTo(prevX, prevY);
					verticalPainter[type].lineTo(x, y);
				}

				lastVerticalType = type;				
			}
			else if (differentColorsForHorizontalAlignmentElements_)
			{
				auto he = h->getAlignmentElementByStationing(s);
				buw::eHorizontalAlignmentType type = he->getAlignmentType();

				if (horizontalPainter.find(type) == horizontalPainter.end())
					horizontalPainter[type] = QPainterPath();

				if (lastType != type)
					horizontalPainter[type].moveTo(prevX, prevY);
				horizontalPainter[type].lineTo(x, y);

				lastType = type;
			}
			else
			{
				buw::eHorizontalAlignmentType type = buw::eHorizontalAlignmentType::Unknown;
				if (horizontalPainter.find(type) == horizontalPainter.end())
					horizontalPainter[type] = QPainterPath();

				horizontalPainter[type].lineTo(x, y);

				lastType = type;
			}

			bounds[0] = std::min(bounds[0], x);
			bounds[1] = std::max(bounds[1], x);
			bounds[2] = std::min(bounds[2], y);
			bounds[3] = std::max(bounds[3], y);

			prevX = x;
			prevY = y;
		}

		arcPoints.clear();
		parabolaPoints.clear();

		for (int ai = 0; ai < v->getAlignmentElementCount(); ai++)
		{
			auto ve = v->getAlignmentElementByIndex(ai);

			if (ve->getAlignmentType() == buw::eVerticalAlignmentType::Arc)
			{
				buw::vector2d start; 
				ve->genericQuery(OpenInfraPlatform::Infrastructure::eAlignmentElementQueryId::StartPosition, &start);

				buw::vector2d end; 
				ve->genericQuery(OpenInfraPlatform::Infrastructure::eAlignmentElementQueryId::EndPosition, &end);

				start[1] *= -1;
				end[1] *= -1;

				arcPoints.push_back(std::make_tuple(ai, start, end));
			}
			if (ve->getAlignmentType() == buw::eVerticalAlignmentType::Parabola)
			{
				buw::vector2d start;
				ve->genericQuery(OpenInfraPlatform::Infrastructure::eAlignmentElementQueryId::StartPosition, &start);

				buw::vector2d end;

				ve->genericQuery(OpenInfraPlatform::Infrastructure::eAlignmentElementQueryId::EndPosition, &end);
				buw::vector2d pvi;
				ve->genericQuery(OpenInfraPlatform::Infrastructure::eAlignmentElementQueryId::PVI, &pvi);

				start[1] *= -1;
				end[1] *= -1;
				pvi[1] *= -1;

				parabolaPoints.push_back(std::make_tuple(ai, start, end, pvi));
			}
		}
	}
}