/************************************************************************
* 文件名    ：  dsuQuery.c
* 版权说明  ：  北京交控科技有限公司
* 版本号  	：  1.0
* 创建时间	：	2009.09.26
* 作者  		软件部	
* 功能描述	：	dsu查询函数文件  
* 使用注意	： 
* 修改记录	：	
************************************************************************/
#ifdef ZCAPP_VXWORKS_CODECONTROL
#include <vxWorks.h>
#endif /*End of ZCAPP_VXWORKS_CODECONTROL*/

#include "dquQuery.h"
#include "dquQueryExp.h"
#include "dquCbtcType.h"

static DSU_EMAP_STRU *qds_dsuEmapStru=NULL;
static DSU_STC_LIMIT_LINKIDX_STRU *qds_dsuLimitStcLinkIdx=NULL;

/*设置当前数据源*/
UINT8 dquSetCurrentQueryDataSource(DSU_EMAP_STRU *pDsuEmapStru,DSU_STC_LIMIT_LINKIDX_STRU *pDsuLimitStcLinkIdx)
{
	UINT8 chReturnValue=0U;             /*用于函数返回值*/
	UINT8 CbtcVersionType=0U;

	CbtcVersionType = GetCbtcSysType();

	if ((DQU_CBTC_FAO == CbtcVersionType)||(DQU_CBTC_HLT == CbtcVersionType))
	{
		if (NULL!=pDsuEmapStru)
		{
			qds_dsuEmapStru=pDsuEmapStru;
			chReturnValue=1;
		}
		else
		{
			chReturnValue=0U;
		}
	} 
	else
	{
		if ((NULL!=pDsuEmapStru) && (NULL!=pDsuLimitStcLinkIdx))
		{
			qds_dsuEmapStru=pDsuEmapStru;
			qds_dsuLimitStcLinkIdx=pDsuLimitStcLinkIdx;
			chReturnValue=1;
		}
		else if((NULL != pDsuEmapStru) && (DQU_CBTC_CC == CbtcVersionType))
		{
			qds_dsuEmapStru = pDsuEmapStru;
			chReturnValue = 1;
		}
		else
		{
			chReturnValue=0U;
		}
	}
	return chReturnValue;
}
/*
* 功能描述： 利用运行方向信息以及道岔状态信息，查询得到当前link沿运行方向的相邻link。
* 输入参数： UINT16 LinkId, 当前Link编号
*            UCHAR Direction, 当前方向
*            UCHAR PointNum,  道岔信息，道岔个数
*            const POINT_STRU *pPointStru, 道岔信息
* 输出参数： UINT16 *pLinkId，当前Link的相邻Link编号
* 返回值：   1,查询成功
*            0,查询失败,输入数据无效，道岔失表
*		      	 0xFF,线路终点，未找到道岔
*             
*/
UINT8 dsuGetAdjacentLinkID(UINT16 LinkId, UCHAR Direction, UCHAR PointNum,const DQU_POINT_STATUS_STRU *pPointStru,UINT16 *pLinkId)
{
	return dsuGetAdjacentLinkIDExp(qds_dsuEmapStru,LinkId,Direction,PointNum,pPointStru,pLinkId);
}


/*
* 功能描述： 功能函数，根据当前位置，和位移以及输入的道岔信息，得到新位置.
如果一个点即当前Lnk起点，又是下一个Link终点，按照离当前点pLODStru最近的Link Id返回
* 输入参数： const LOD_STRU * pLODStru, 当前位置
*            INT32 Displacement,        位移，有符号，如果符号为负表示方向取反
*            UCHAR PointNum,            道岔数量
*            const POINT_STRU * pPointStru,  道岔信息
* 输出参数： LOD_STRU *pNewLODStru       新位置
* 返回值：   1,成功
*            0,失败
*/
UCHAR dsuLODCalcu(const LOD_STRU *pLODStru, INT32 Displacement, UCHAR PointNum, const DQU_POINT_STATUS_STRU *pPointStru, LOD_STRU *pNewLODStru) 
{
	return dsuLODCalcuExp(qds_dsuEmapStru,pLODStru,Displacement, PointNum,pPointStru,pNewLODStru);
}

/*
*访问接口
* 功能描述： 由A，B两者位置得到两者位移。
* 输入参数： const LOD_STRU * pLODAStru, A点位置
*            const LOD_STRU * pLODBStru, B点位置
*            UINT8 PointNum,             道岔数量
*            const POINT_STRU * pPointStru, 道岔信息结构体
* 输出参数： INT32 *Displacement，       AB位移，是有符号数。符号表示方向，            
* 返回值：   1,成功
*            0,失败
* 使用注意：合库和燕房项目:按照B的方向查找，AB位移以LinkB方向为参照；
            互联互通项目因增加逻辑方向变化点，算法改为按照A的方向查找，AB位移以LinkA方向为参照。
* author:qxt 20170811
*/
UINT8 dsuDispCalcuByLOC(const LOD_STRU *pLODAStru, const LOD_STRU *pLODBStru, 
	UINT8 PointNum, const DQU_POINT_STATUS_STRU *pPointStru, INT32 *Displacement)
{
	return dsuDispCalcuByLOCExp(qds_dsuEmapStru, pLODAStru, pLODBStru,PointNum,pPointStru,Displacement);
}


/*
* 函数功能：	此函数的功能是查询两个位置间包含的link序列。
* ****************************************************************************************************
*        1          2              3                4                    5              6
*       -----×---------*--×--------------×--------------------×-------*-----×------------
*                       S                                                 E
*        图例：  ×，Link端点。*，查询输入的位置。1，2，3...Link示意编号
*        如图所示：Link3，4为所求结果。
*        此处方向按照pLODEndStru方向来查找，
*        S沿着pLODEndStru->Dir方向查找，找到E则返回成功，找不到则返回失败。
* ****************************************************************************************************
* 入口参数：	const LOD_STRU * pLODStartStru,	始端位置
*               const LOD_STRU * pLODEndStru	终端位置
*               const UINT8 PointNum			道岔数目 
*               const POINT_STRU * pPointStru	道岔信息
* 出口参数：	UINT16 wLinkID[DSU_MAX_LINK_BETWEEN]				Link序列数组
*               UINT16 *wLinkNumber                             Link个数
* 返回值：   	0,  查询失败
*               1,  查询成功                                                             
* 使用注意：    目前的做法没有包含两端的Link Id。
*               函数要求两个点之间可以形成区域，否则返回0
*/

UINT8 dsuGetLinkBtwLoc(const LOD_STRU *pLODStartStru, const LOD_STRU *pLODEndStru,
	UINT8 PointNum,const DQU_POINT_STATUS_STRU *pPointStru, 
	UINT16 wLinkID[DSU_MAX_LINK_BETWEEN], UINT16 *wLinkNumber)
{
	return dsuGetLinkBtwLocExp(qds_dsuEmapStru,pLODStartStru,pLODEndStru,PointNum,pPointStru,wLinkID,wLinkNumber);	
}


/*
* 函数功能： 此函数的功能是将判断当前位置是否在指定区域范围内。
* ****************************************************************************************************
*
*       --------------*--------------------*---------------------*-----------------
*                     S                    C                     E
*  合库和燕房项目： 查找算法为，计算位移DisplacementSC，DisplacementCE。如果两个位移符号相同，说明C在SE区域内
*  互联互通项目（新增逻辑方向变化点）：   查找算法为，计算位移DisplacementCS，DisplacementCE。如果两个位移符号不相同，说明C在SE区域内
* ****************************************************************************************************
* 入口参数： const LOD_STRU * pLODStartStru,	区域始端位置
*            const LOD_STRU * pLODEndStru,	区域终端位置
*            const UINT8 PointNum,			道岔数目 
*            const POINT_STRU * pPointStru,	道岔信息
*			 const LOD_STRU * pCurrentLODStru,当前位置
* 出口参数： UINT8 *pLocInArea         1,在指定区域
*                                     0,不在指定区域
* 返回值：   0，查询失败
*            1，查询成功
* 使用注意：1.在当前位置在区域端点位置时，暂时按如下规则判断：
*             1) 当前位置在区域起点，认为该点属于本区域；
*             2) 当前位置在区域终点，认为该点不属于本区域；
*             3) 3点重合返回在区域内。
*           2.如果待查找的起点与终点都在区域内，可以调用两次本函数，互换始端与终端位置，只要两次调用有一次在区域内，说明在点在始端与终端形成的闭区域内
*           3.如果SE区域不存在，则函数返回0失败。如果SC,或者SE不存在，则函数返回1成功，但是点C不在区域内
*           4.燕房和合库项目：始端位置和终端位置传入的方向需保证一致
*             互联互通：保证始端位置的方向正确即可。
*/
UINT8 dsuCheckLocInArea(const LOD_STRU * pLODStartStru, const LOD_STRU *pLODEndStru,
	UINT8 PointNum, const DQU_POINT_STATUS_STRU *pPointStru, 
	const LOD_STRU *pCurrentLODStru,UINT8 *pLocInArea)
{
	return dsuCheckLocInAreaExp(qds_dsuEmapStru,pLODStartStru,pLODEndStru,PointNum,pPointStru,pCurrentLODStru,pLocInArea);
}

/************************************************************************

函数功能：	此函数的功能是利用link的ID信息查询link的长度信息
入口参数：	const UINT16 wLinkID		link的ID	
出口参数：	无
返回值：	UINT32 dwLinkLength	查询失败: 0xffffffff; 查询成功: 返回查找到的link长度                                                                
************************************************************************/
/*功能函数，查询link长度*/
UINT32 LinkLength(UINT16 wLinkID)
{
	return LinkLengthExp(qds_dsuEmapStru,wLinkID);
}

/*
* 函数功能： 此函数的功能是将判断当前位置是否在指定区域范围内。
此函数的功能与CheckLocInArea是有区别的。CheckLocInArea对方向没有要求，假设所有涉及的方向都是正确的。
而CheckLocInAreaQuick要求从StartLOD能够到达EndLOD。
* ****************************************************************************************************
*
*       --------------*--------------------*---------------------*-----------------
*                     S                    C                     E
*       查找算法为，首先判断当前位置与输入的S，E是否在同一Link上，
*       如果在同一Link上，根据方向和位移判断是否在区域内，如果不在同一Link，判断CLinkId是否与SE之间的某一LinkId相同
*       由于两点之间的Link可以保存下来，所以对于多次调用本函数查询是否在区域内的函数效率很有帮助
*
* ****************************************************************************************************
* 入口参数： const LOD_STRU * pLODStartStru,	区域始端位置
*            const LOD_STRU * pLODEndStru,	区域终端位置
* 出口参数：	UINT16 wLinkID[DSU_MAX_LINK_BETWEEN]				Link序列数组
*               UINT16 *wLinkNumber                             Link个数
*			 const LOD_STRU * pCurrentLODStru,当前位置
* 出口参数： UINT8 *pLocInArea         1,在指定区域
*                                     0,不在指定区域
* 返回值：   0，查询失败
*            1，查询成功
* 使用注意：1.在当前位置在区域端点位置时，暂时按如下规则判断：
*             1) 当前位置在区域起点，认为该点属于本区域；
*             2) 当前位置在区域终点，认为该点不属于本区域；
*             3) 3点重合返回在区域内。
*           2.如果待查找的起点与终点都在区域内，可以调用两次本函数，互换始端与终端位置，只要两次调用有一次在区域内，说明在点在始端与终端形成的闭区域内
*           3.如果SE区域不存在，则函数返回0失败。如果SC,或者SE不存在，则函数返回1成功，但是点C不在区域内
*/
UINT8 dsuCheckLocInAreaQuick(const LOD_STRU * pLODStartStru, const LOD_STRU * pLODEndStru,
	UINT16 wLinkNumber,UINT16 wLinkID[DSU_MAX_LINK_BETWEEN],
	const LOD_STRU * pCurrentLODStru,UINT8 *pLocInArea)
{
	return dsuCheckLocInAreaQuickExp(qds_dsuEmapStru,pLODStartStru,pLODEndStru,wLinkNumber,wLinkID,pCurrentLODStru,pLocInArea);
}

/*
* 函数功能： 此函数的功能是判断当前位置是否在指定区域范围内，此函数是对dsuCheckLocInAreaQuick
的一个补充。用于将当前方向取反，再计算是否在区域内。
* 入口参数： const LOD_STRU * pLODStartStru,	区域始端位置
*            const LOD_STRU * pLODEndStru,	区域终端位置
* 出口参数： UINT16 wLinkID[DSU_MAX_LINK_BETWEEN]				Link序列数组
*            UINT16 *wLinkNumber                             Link个数
*			 const LOD_STRU * pCurrentLODStru,当前位置
*            UINT8 *pLocInArea         1,在指定区域
*                                     0,不在指定区域
* 返回值：   0，查询失败
*            1，查询成功
*/
UINT8 dsuCheckLocInAreaQuick2(const LOD_STRU * pLODStartStru, const LOD_STRU * pLODEndStru,
	UINT16 wLinkNumber,UINT16 wLinkID[DSU_MAX_LINK_BETWEEN],
	const LOD_STRU * pCurrentLODStru,UINT8 *pLocInArea)
{
	return dsuCheckLocInAreaQuickExp2( qds_dsuEmapStru,pLODStartStru,pLODEndStru,wLinkNumber,wLinkID,pCurrentLODStru,pLocInArea);
}

/*****************************以下为坡度平缓计算过程中需要用到的函数**************************/
/************************************************************************

函数功能：	此函数的功能是查询当前Garde的相邻Grade
入口参数：	const UINT16 wCurrentGradeID	当前坡度编号
const UCHAR chDirection			期望运行方向
const UCHAR PointNum			MA范围内道岔数目
const DQU_POINT_STATUS_STRU * pPointStru	MA范围内道岔信息		
出口参数：	无
返回值：	UINT16 wFindGradeID	查询失败: 0xffff; 查询成功: 返回相邻的坡度ID                                                              
************************************************************************/
/*功能函数,查询当前Garde的相邻Grade*/
UINT16 FindAdjacentGradeID(const UINT16 wCurrentGradeID, const UCHAR chDirection, const UCHAR PointNum,
	const DQU_POINT_STATUS_STRU * pPointStru)
{
	return FindAdjacentGradeIDExp(qds_dsuEmapStru,wCurrentGradeID,chDirection,PointNum,pPointStru);
}
/*
*函数功能：查询某点所在坡度ID
*输入参数：UINT16 linkId,UINT32 offset待计算点
*输出参数：UINT16 GradeID所在坡度ID
*返回值：  0函数执行失败，1成功
*/
UINT8 dsuGetGradeIdbyLoc(const UINT16 linkId,const UINT32 offset,UINT16* GradeID)
{
	return dsuGetGradeIdbyLocExp(qds_dsuEmapStru,linkId,offset,GradeID);
}
/*************
*函数功能：计算某点坡度平缓后的坡度值
*输入参数：Point 所求坡度点
*输出参数： 
*返回值：  0函数执行失败 1 点在坡度第一段 2 点在坡度第2段 3 点在坡度第3段
****************/
UINT8 dsuCalculateGradeValue(UINT16 LinkId,UINT32 ofst,FLOAT32* GradeVal)
{
	return dsuCalculateGradeValueExp(qds_dsuEmapStru,LinkId,ofst,GradeVal); 
}

/*************
*函数功能：计算某坡度平缓后，分成的几个部分的分界点与起点的距离
*输入参数：gradeId 坡度ID
*输出参数：UINT32* endPointDistance UINT32* startPointDistance
*返回值：  0函数执行失败   1成功
备注：     如果不需要平缓计算的点，设为无效值ffffffff  返回值为1
****************/
UINT8 dsuDividPointDistanceFromOrigin(UINT16 GradeId,UINT16 linkId,UINT32* endPointDistance,UINT32* startPointDistance)
{
	return dsuDividPointDistanceFromOriginExp(qds_dsuEmapStru,GradeId,linkId,endPointDistance,startPointDistance);
}

/*************
*函数功能：给定坡度上某一点及坡度id，计算该点距离坡度起点的距离
*输入参数：gradeId 坡度ID
UINT16 linkId UINT32 Ofst
*输出参数：UINT32 *length  长度

*返回值：  0函数执行失败   1成功  
****************/
UINT8 dsuGetDistanceFromOrigin(UINT16 GradeId,UINT16 linkId,UINT32 Ofst,UINT32* length)
{
	return dsuGetDistanceFromOriginExp(qds_dsuEmapStru,GradeId,linkId,Ofst,length);	
}

/************************************************************************

函数功能：	此函数的功能是查询给定的两位置间的最差坡度。函数查询起点至
终点范围内所有的线路坡度，并挑出最差坡度（最大下坡）。规定
上坡为正，下坡为负，函数的功能即为挑出范围内坡度的最小值。
函数返回最差坡度的千分数。

入口参数：	const LOD_STRU * pLODStartStru		查询起点位置和方向（实际为列车车尾位置和方向）
const LOD_STRU * pLODEndStru		查询终点位置和方向
const UCHAR PointNum				MA中的道岔数量
const POINT_STRU * pPointStru		道岔信息结构体
出口参数：	FLOAT64 * Gradient					列车车尾至MA终点范围内最差坡度的千分数（上坡为正，下坡为负）
返回值：	UCHAR bReturnValue					 	
0：查询失败；
1：查询正确；
注：在计算的过程中，用的万分值，返回值前，有/10的操作，因此返回
的坡度值为千分值                                                     
************************************************************************/
/*14 两位置间最差坡度查询*/
UCHAR dsuGradientGet(const LOD_STRU * pLODStartStru, const LOD_STRU * pLODEndStru,
	const UCHAR PointNum, const DQU_POINT_STATUS_STRU * pPointStru, FLOAT32 * Gradient)
{
	return dsuGradientGetExp(qds_dsuEmapStru,pLODStartStru,pLODEndStru,PointNum,pPointStru,Gradient);
}

/*
函数功能：判断后一坡度的坡度值相比前一个坡度的坡度值是增加，不变化还是减少 
输入参数：UINT16 fistGradeID,UINT16 secondGradeID
输出参数：GradeTrend 坡度 
1： 减少  
2： 增加
0： 不变化
返回值：0失败 1成功
*/
UINT8 dquGradeTrend(UINT16 fistGradeID,UINT16 secondGradeID,UINT8 *GradeTrend)
{
	return dquGradeTrendExp(qds_dsuEmapStru,fistGradeID,secondGradeID,GradeTrend);
}

/*
函数功能：获取前面的坡度
输入参数：UINT16 linkId,当前link
输出参数：gradeFrnt 坡度 
Null：  线路终点或前面坡度为统一坡度  
非Null：前面坡度在坡度表中可查
返回值：0失败 1成功 2线路终点
*/
UINT8 dsuGetGradeFrnt(UINT16 linkId, DSU_GRADE_STRU** gradeFrnt)
{
	return dsuGetGradeFrntExp(qds_dsuEmapStru,linkId,gradeFrnt); 
}

/*
函数功能：获取后面的坡度
输入参数：UINT16 linkId,当前link
输出参数：gradeRear 坡度 
Null：  线路终点或后面坡度为统一坡度  
非Null：后面坡度在坡度表中可查
返回值：0失败 1成功 2线路终点
*/
UINT8 dsuGetGradeRear(UINT16 linkId, DSU_GRADE_STRU** gradeRear)
{
	return dsuGetGradeRearExp(qds_dsuEmapStru,linkId,gradeRear); 
}

/**
函数功能：获取当前LINK的静态限速个数
输入参数：
@linkId：当前link
输出参数：无
返回值：静态限速个数
*/
UINT8 GetStcLmtSpdCntByLnkId(const UINT16 linkId)
{
	return GetStcLmtSpdCntByLnkIdExp(qds_dsuEmapStru,qds_dsuLimitStcLinkIdx,linkId);
}

/**
函数功能：获取制定LINK的的指定下标的静态临时限速的对象指针
输入参数：
@linkId：当前Link编号
@idx：对应Link的第几个限速，下标取值范围0-9
返回值：
@NULL：获取失败 
@非空：对应限速结构体指针
*/
DSU_STATIC_RES_SPEED_STRU *GetStcLmtSpdInfoByLnkId(const UINT16 linkId,const UINT8 idx)
{
	return GetStcLmtSpdInfoByLnkIdExp(qds_dsuEmapStru,qds_dsuLimitStcLinkIdx,linkId,idx);
}


/*
函数功能：将多开道岔转为虚拟道岔
输入参数：multiPointId 多开道岔编号
          multiPointState 多开道岔状态

输出参数：wVirtualPointIds 拆分后虚拟道岔编号 
          wVirtualPointStates 拆分后虚拟道岔状态
返回值：返回值：拆分后虚拟道岔个数, 0失败  

函数算法：多开道岔包含的虚拟道岔： N位，R1位，L1位，R2位，L2位
            所对应在数组中的索引： 0，  1，   2，   3，   4
		    所对应的多开道岔状态： 1，  2，   3，   4，   5
		   因此当 索引=多开道岔状态multiPointState-1 时，所对应的虚拟道岔保持原值，其余虚拟道岔状态取反（定位<=>反位）

注意事项：输出参数虚拟道岔wVirtualPointIds和状态wVirtualPointStates，对于无效道岔其道岔状态设置为3。如
         
		               / L                                      / L
		              /                                        /
		             /                                        /       101                
		-|------------------------         ===》   ---|------/----------------- N      
		   1         \           N                          102       \
		              \                                                \
					   \                                                \
		              R                                                 R
		           图1.实体三开道岔                            图2.虚拟单开道岔

		   当图1实体三开道岔1的状态为3时，推出图2虚拟单开道岔为L位。此时101为无效道岔，输出其状态为3，返回值道岔个数为2，如下
		   wVirtualPointIds[0]=102;
		   wVirtualPointStates[0]=2;
		   wVirtualPointIds[1]=101;
		   wVirtualPointStates[1]=3;
author:单轨项目 add by qxt 20170622
*/
UINT8 ConvertToVirtualSwitches(const UINT16 multiPointId,const UINT8 multiPointState,UINT16 wVirtualPointIds[MAX_VIRTUAL_SWITCH_NUM],UINT8 wVirtualPointStates[MAX_VIRTUAL_SWITCH_NUM])
{
     return ConvertToVirtualSwitchesExp(qds_dsuEmapStru,multiPointId,multiPointState,wVirtualPointIds, wVirtualPointStates);
}

/*
函数功能：将虚拟道岔转为多开道岔
输入参数：wVirtualPointIds[] 虚拟道岔编号 
          wVirtualPointStates[] 虚拟道岔状态
		  wVirtualPointNum    虚拟道岔数量
输出参数：multiPointId 对应多开道岔编号
          multiPointState 对应多开道岔状态
返回值：0失败 1成功

注意事项：输入参数虚拟道岔wVirtualPointIds和状态wVirtualPointStates，对于无效的虚拟道岔，不需要传入。如
           
		 		      /L                                                 L
		             /                                                /
		            /                                                /
		           /                                                /
		---|------/-----------\------ N      =====>        ------------------ N
		          1          2 \                                    \
							    \                                    \
		                          R                                      R
		         图1.虚拟单开道岔                             图2.实体三开道岔
		 
		 当图1虚拟道岔编号1的状态为2时，推出图2多开道岔的状态为L位。此时图一虚拟道岔2为无效的，其输入参数可设置为如下：
         wVirtualPointIds[0]=1;
		 wVirtualPointStates[0]=2;
         wVirtualPointNum=1;
author:单轨项目 add by qxt 20170622
*/
UINT8 ConvertToMultiSwitch(const UINT16 wVirtualPointIds[MAX_VIRTUAL_SWITCH_NUM],const UINT8 wVirtualPointStates[MAX_VIRTUAL_SWITCH_NUM],const UINT8 wVirtualPointNum,UINT16 *multiPointId,UINT8 *multiPointState)
{
      return ConvertToMultiSwitchExp(qds_dsuEmapStru,wVirtualPointIds, wVirtualPointStates,  wVirtualPointNum,multiPointId,multiPointState);
}

/************************************************
*函数功能:查询AB两端之间的距离
*输入参数:		pLODAStru	A点
*				pLODBStru	B点
*输出参数:		pLinkNum	输出路径的link数量
*				szLinkId	输出路径的linkId序列
*				pDir		输出A->B的方向
*返回值:失败:DSU_NULL_32
*		成功:距离
*备注： add by lxc 2021-2-28
************************************************/
UINT32 dsuLenByPoint(const LOD_STRU *pLODAStru, const LOD_STRU *pLODBStru, UINT16* pLinkNum, UINT16 szLinkId[100], UINT8* pDir)
{
	UINT8 cLinkDirChangedNum = 0U;

	return dsuLenByPointExp(qds_dsuEmapStru, pLODAStru, pLODBStru, pLinkNum, szLinkId, pDir, &cLinkDirChangedNum);
}

/************************************************
*函数功能:查询AB两端之间的距离（根据道岔位置）
*输入参数:		pLODAStru	A点
*				pLODBStru	B点
*				cSwitchSum 道岔数量
*				pSwitchInfo 道岔信息
*输出参数:		pLinkNum	输出路径的link数量
*				szLinkId	输出路径的linkId序列
*				pDir		输出A->B的方向
*返回值:失败:DSU_NULL_32
*		成功:距离
*备注： add by lxc 2022-6-17
************************************************/
UINT32 dsuLenByPointAndSwitch(const LOD_STRU *pLODAStru, const LOD_STRU *pLODBStru, const UINT8 cSwitchSum, const DQU_POINT_STATUS_STRU *pSwitchInfo ,UINT16* pLinkNum, UINT16 szLinkId[100], UINT8* pDir)
{
	return dsuLenByPointBySwitchStateExp(qds_dsuEmapStru, pLODAStru, pLODBStru, cSwitchSum, pSwitchInfo,pLinkNum, szLinkId, pDir);
}

/************************************************
*函数功能：查询AB两点之间的Link方向变化点数量
*输入参数：const LOD_STRU* pLODAStru A点
*		   const LOD_STRU* pLODBStru B点
*输出参数：无
*返回值：失败：UINT8_MAX
*		 成功：方向变化点数量
************************************************/
UINT8 GetDirChangeNumBtwPoints(const LOD_STRU* pLODAStru, const LOD_STRU* pLODBStru)
{
	UINT8 cDirChangedNum = UINT8_MAX;
	UINT16 cLinkNum = 0U;
	UINT16 szLinkId[100] = { 0U };
	UINT8 cDir = 0U;
	UINT32 dwLen = 0U;

	if ((NULL != pLODAStru) && (NULL != pLODBStru))
	{
		dwLen = dsuLenByPointExp(qds_dsuEmapStru, pLODAStru, pLODBStru, &cLinkNum, szLinkId, &cDir, &cDirChangedNum);
	}
	else
	{
		/*入参错误，不处理*/
	}

	return cDirChangedNum;
}

/************************************************
*函数功能:查询AB两端之间的距离（返回方向和方向变化点数量）
*输入参数:		pLODAStru	A点
*				pLODBStru	B点
*输出参数:		pLinkNum	输出路径的link数量
*				szLinkId	输出路径的linkId序列
*				pDir		输出A->B的方向
*返回值:失败:DSU_NULL_32
*		成功:距离
*备注： add by lxc 2021-2-28
************************************************/
UINT32 dsuLenByPoint_GetDir(const LOD_STRU* pLODAStru, const LOD_STRU* pLODBStru, UINT16* pLinkNum, UINT16 szLinkId[100], UINT8* pDir, UINT8* pLinkDirChangedNum)
{
	
	return dsuLenByPointExp(qds_dsuEmapStru, pLODAStru, pLODBStru, pLinkNum, szLinkId, pDir, pLinkDirChangedNum);
}

/************************************************
*函数功能:两点之间路径查询
*输入参数:		pDsuEmapStru 电子地图数据
*				pLODAStru	A点
*				pLODBStru	B点
*输出参数:		pLinkNum	输出路径的link数量
*				szLinkId	输出路径的linkId序列
*返回值:CI_ERROR：失败
*		CI_SUCCESS：成功:
* by cgh 20250310
************************************************/
UINT8 TwoPointPathExp(DSU_EMAP_STRU* pDsuEmapStru, const LOD_STRU* pLODAStru, const LOD_STRU* pLODBStru, UINT16* pLinkNum, UINT16 szLinkId[100])
{
	UINT8 chReval = 0U;
	/* 两点沿两个方向上的所有路径数据 */
	UINT16 szSameDirPathA[25][50] = { 0U }; /*逻辑正方向路径数据数组*/
	UINT16 szPathASameDirLinkNum[25] = { 0U };/*逻辑正方向路径对应LINK数目*/
	UINT8 chSameDirPathANum = 0U;/*逻辑正方向路径对应路径数目*/
	UINT8 szASameQueryDir[25] = { 0U };     /*点A同向查询各路径的方向*/
	UINT8 chSearchNum = 0U;/*查询次数*/
	UINT8 chKeepSearchPathFlag = 0U;/*继续查询路径标志*/
	UINT8 chSameSearchFinishFlag = 0U;/*同向查找完成标志*/
	UINT8 ii = 0U;
	UINT16 jj = 0U;
	UINT16 wAllPathLinkSum = 0U;/*所有路径LINK数目*/
	UINT16 szTempLinkId[100] = { 0U };/*所有路径LINK数组*/
	UINT16 wSzLinkIndex = 0U;/*数组LINK索引*/

	if ((NULL != pDsuEmapStru) && (NULL != pLODAStru) && (NULL != pLODBStru) && (NULL != pLinkNum) && (NULL != szLinkId))
	{
		(void)CommonMemSet(szASameQueryDir, (UINT32)(sizeof(UINT8) * 25U), pLODAStru->Dir, (UINT32)(sizeof(UINT8) * 25U));

		szSameDirPathA[0][0] = pLODAStru->Lnk;
		szPathASameDirLinkNum[0] = 1U;
		chSameDirPathANum = 1U;

		/*查询结果初始赋值为查找成功*/
		chKeepSearchPathFlag = 1U;
		chSameSearchFinishFlag = 1U;

		chSearchNum = 1U;
		while (1U == chKeepSearchPathFlag)
		{
			chKeepSearchPathFlag = 0U;

			if (2U != chSameSearchFinishFlag)
			{
				chSameSearchFinishFlag = PointBeginEndPathExp(pDsuEmapStru, pLODBStru, szASameQueryDir, &chSameDirPathANum, szSameDirPathA, szPathASameDirLinkNum);
			}
			else
			{
				;
			}

			if (2U == chSameSearchFinishFlag)
			{
				/* 查询到了终点退出循环 */
				chKeepSearchPathFlag = 0U;
			}
			else
			{
				/* 存在新的路径或者路径未到终点 */
				chKeepSearchPathFlag = 1U;
			}

			if (49U <= chSearchNum)
			{
				break;
			}
			else
			{
				; /*继续查找*/
			}
			chSearchNum++;
		}


		wAllPathLinkSum = 0U;
		chReval = 1U;
		for (ii = 0U; ii < chSameDirPathANum; ii++)
		{
			if (pLODBStru->Lnk == szSameDirPathA[ii][szPathASameDirLinkNum[ii] - 1U])
			{
				/*检查当前路径重点是否是数据中配置的终点*/
				for (jj = 0; jj < szPathASameDirLinkNum[ii]; jj++)
				{
					for (wSzLinkIndex == 0U; wSzLinkIndex < wAllPathLinkSum; wSzLinkIndex++)
					{
						if (szSameDirPathA[ii][jj] == szTempLinkId[wSzLinkIndex])
						{
							/*已存在该LINK*/
							break;
						}
						else
						{
							;
						}
					}

					if (wSzLinkIndex == wAllPathLinkSum)
					{
						/*当前不存在该LINK，添加*/
						if (100U > wAllPathLinkSum)
						{
							szTempLinkId[wAllPathLinkSum] = szSameDirPathA[ii][jj];
							wAllPathLinkSum++;
						}
						else
						{
							chReval = 0U;
							break;
						}
					}
					else
					{
						;
					}

				}

				if (0U == chReval)
				{
					break;
				}
				else
				{
					;
				}
			}
			else
			{
				; /*不是，跳过，不初始化*/
			}
		}


		if (1U == chReval)
		{
#if 0
			if (0U == wAllPathLinkSum)
			{
				/*所有路径都没有找到终点LINK，数据有问题*/
				chReval = 0U;
			}
			else
			{
				*pLinkNum = wAllPathLinkSum;
				(void)CommonMemCpy((void*)szLinkId, (UINT32)(sizeof(UINT16) * 100U), (const void*)szTempLinkId, (UINT32)(sizeof(UINT16) * 100U));
			}
#endif
			* pLinkNum = wAllPathLinkSum;
			(void)CommonMemCpy((void*)szLinkId, (UINT32)(sizeof(UINT16) * 100U), (const void*)szTempLinkId, (UINT32)(sizeof(UINT16) * 100U));

		}
		else
		{
			;
		}

	}
	else
	{
		; /*返回失败*/
	}

	return chReval;
}

/************************************************
*函数功能:起终点路径查询
*输入参数:		pDsuEmapStru		数据
*				pLODBStru	B点
*				szLinkQueryDir      link查询方向
*				pPathNum			路径数量
*				szPath				路径数据
*				szLinkNum			每条路径的长度
*输出参数:		pPathNum			路径数量
*				szPath				路径数据
*				szLinkNum			每条路径的长度
*返回值:0:失败 1:查询成功，且各路径未到终点 2：查询成功，且各路径到达终点
* by cgh 20250310
************************************************/
UINT8 PointBeginEndPathExp(DSU_EMAP_STRU* pDsuEmapStru, const LOD_STRU* pLODBStru, UINT8 szLinkQueryDir[25], UINT8* pPathNum, UINT16 szPath[25][50], UINT16 szLinkNum[25])
{
	UINT8 chReval = 0U;
	UINT8 ii = 0U;
	UINT8 jj = 0U;
	UINT8 chPathNum = 0U;/*最终输出路径数目*/
	/*传参调用涉及的全局变量*/
	UINT16 LINKINDEXNUM = 0;
	UINT16* pdsuLinkIndex = NULL;
	DSU_STATIC_HEAD_STRU* pdsuStaticHeadStru = NULL;
	UINT8 chTmpPathNum = 0U;/*临时新增路径数目*/
	UINT16 wTmpEndLinkId = 0U;/*当前输入的路径终点LINK ID*/
	UINT8 chMainQueryDir = 0U;  /*主线路径的查询方向*/
	UINT8 chSideQueryDir = 0U;  /*侧线路径的查询方向*/
	UINT8 chTmpEndPathNum = 0U; /*最终找到终点时查到的路径数目*/
	UINT8 chCurLinkDirChanged = LINK_DIRCHANGE_NONE;  /*当前Link方向变化点*/
	UINT8 chNxtLinkDirChanged = LINK_DIRCHANGE_NONE;  /*下一Link方向变化点*/
	UINT16 wTmpEndLinkIndex = 0U;/*当前输入的路径终点LINK 索引*/
	DSU_LINK_STRU* pTmpEndLinkStru = NULL;   /*当前Link,获取本地数据使用*/
	UINT16 wTmpNextMainLinkId = 0U;	/* 下一段正线link */
	UINT16 wTmpNextSideLinkId = 0U;	/* 下一段侧线link */
	UINT8 chFunFlag = 0U;				/* 为0时延申当前路径，为1时延申当前路径并开辟新路径 */
	UINT16 wAddLinkId = 0U;/*当前路径需要添加的LINK ID*/
	UINT16 wNewLinkId = 0U;/*需要延伸路径的LINK ID*/
	UINT16 wTmpPathLinkNum = 0U; /*临时路径LINK 数目*/
	UINT8 chTempPathIndex = 0U;/*临时路径索引*/
	UINT16 szTmpAddLinkNum[12] = { 0U };/*新增路径LINK数目*/
	UINT16 szTmpAddPath[12][50] = { 0U };/*新增路径LINK信息数组*/

	if ((NULL != pDsuEmapStru) && (NULL != pLODBStru) && (NULL != szLinkQueryDir) && (NULL != pPathNum) && ((25U > *pPathNum)) && (NULL != szPath) && (NULL != szLinkNum))
	{
		for (ii = 0U; ii < 25U; ii++)
		{
			/*方向检查*/
			if ((EMAP_SAME_DIR == szLinkQueryDir[ii]) || (EMAP_CONVER_DIR == szLinkQueryDir[ii]))
			{
				chReval = 1U;
			}
			else
			{
				chReval = 0U;
				break;
			}
		}

		/* 入参承接 */
		chPathNum = *pPathNum;
		/* 全局变量透传 */
		LINKINDEXNUM = pDsuEmapStru->dsuEmapIndexStru->LINKINDEXNUM;
		pdsuLinkIndex = pDsuEmapStru->dsuEmapIndexStru->dsuLinkIndex;
		pdsuStaticHeadStru = pDsuEmapStru->dsuStaticHeadStru;

		if (1U == chReval)
		{
			chTmpPathNum = 0U;

			for (ii = 0U; ii < chPathNum; ii++)
			{
				wTmpEndLinkId = szPath[ii][(szLinkNum[ii] - 1U)];
				chMainQueryDir = szLinkQueryDir[ii];
				chSideQueryDir = szLinkQueryDir[ii];

				/*第一步 ：查找下一LINK->找到终点或者已经查询了50个LINK*/
				if ((pLODBStru->Lnk != wTmpEndLinkId) && (DSU_NULL_16 != wTmpEndLinkId))
				{
					/*说明还没找到终点*/
					chCurLinkDirChanged = pdsuStaticHeadStru->pLinkStru[pdsuLinkIndex[wTmpEndLinkId]].wLogicDirChanged;		/*获取当前link的方向变化点*/
					/*根据LinkID获取当前link结构体*/
					wTmpEndLinkIndex = pdsuLinkIndex[wTmpEndLinkId];
					pTmpEndLinkStru = pdsuStaticHeadStru->pLinkStru + wTmpEndLinkIndex;

					/* 获取查询方向上的端点类型,与查询方向上的下一个link */
					if (EMAP_SAME_DIR == chMainQueryDir)
					{
						wTmpNextMainLinkId = pTmpEndLinkStru->wTmnlJointMainLkId;
						wTmpNextSideLinkId = pTmpEndLinkStru->wTmnlJointSideLkId;
					}
					else
					{
						wTmpNextMainLinkId = pTmpEndLinkStru->wOrgnJointMainLkId;
						wTmpNextSideLinkId = pTmpEndLinkStru->wOrgnJointSideLkId;
					}

					/*第二步：判断路径是否需要延伸*/
					wAddLinkId = wTmpNextMainLinkId;
					wNewLinkId = wTmpNextSideLinkId;

					if (DSU_NULL_16 != wNewLinkId)
					{
						/* 需要新建路径 */
						chFunFlag = 1u;
					}
					else
					{
						chFunFlag = 0U;
					}

					/*第三步：路径处理*/
					wTmpPathLinkNum = szLinkNum[ii];

					/* 延申当前路径,判断当前路径link容量是否达到上限 */
					if (49U == szLinkNum[ii])
					{
						/* 容量未达上限，但最后一个link只能存为终点 */
						szPath[ii][wTmpPathLinkNum] = DSU_NULL_16;
						szLinkNum[ii]++;
					}
					else
					{
						/* 可以延申 */
						szPath[ii][wTmpPathLinkNum] = wAddLinkId;
						szLinkNum[ii]++;

						if (DSU_NULL_16 != wAddLinkId)
						{
							/*判断是否存在方向变化点*/
							chNxtLinkDirChanged = pdsuStaticHeadStru->pLinkStru[pdsuLinkIndex[wAddLinkId]].wLogicDirChanged;
							if (((LINK_DIRCHANGE_BEGIN == chNxtLinkDirChanged) || (LINK_DIRCHANGE_END == chNxtLinkDirChanged))
								&& (chNxtLinkDirChanged == chCurLinkDirChanged))
							{
								/*存在方向变化点*/
								chMainQueryDir = ~chMainQueryDir;
							}
							else
							{
								/*不存在方向变化点，不处理*/
							}

							szLinkQueryDir[ii] = chMainQueryDir;  /*存储此路径下的查询方向*/
						}
						else
						{
							; /*该退出查询过程了*/
						}
					}

					/*第四步：路径延伸处理*/
					if (1U == chFunFlag)
					{
						/* 生成一条新路径 */
						/* 1.判断当前路径link容量是否达到上限 */
						if (49U == wTmpPathLinkNum)
						{
							/* 容量未达上限，但最后一个link只能存为终点，新开辟路径也没有意义 */
						}
						else
						{
							/* 2.判断路径数量是否达到上限 */
							if ((12U > chTmpPathNum) && (DSU_NULL_16 != wNewLinkId))
							{
								/*为新增路径添加查询方向*/
								chTempPathIndex = chTmpPathNum + chPathNum;  /*当前路径与新增路径总数索引*/
								if (25U > chTempPathIndex)
								{
									/*判断是否存在方向变化点*/
									chNxtLinkDirChanged = pdsuStaticHeadStru->pLinkStru[pdsuLinkIndex[wNewLinkId]].wLogicDirChanged;
									if (((LINK_DIRCHANGE_BEGIN == chNxtLinkDirChanged) || (LINK_DIRCHANGE_END == chNxtLinkDirChanged))
										&& (chNxtLinkDirChanged == chCurLinkDirChanged))
									{
										/*存在方向变化点*/
										chSideQueryDir = ~chSideQueryDir;
									}
									else
									{
										/*不存在方向变化点，不处理*/
									}
									szLinkQueryDir[chTempPathIndex] = chSideQueryDir;  /*存储新增路径下的查询方向*/
								}
								else
								{
									/*路径达到上限，不处理*/
								}

								/* 新增一条路径 */
								szTmpAddLinkNum[chTmpPathNum] = wTmpPathLinkNum;
								for (jj = 0U; jj < wTmpPathLinkNum; jj++)
								{
									/*把原路径里的LINK继续保留下来*/
									szTmpAddPath[chTmpPathNum][jj] = szPath[ii][jj];
								}
								szTmpAddPath[chTmpPathNum][wTmpPathLinkNum] = wNewLinkId;
								szTmpAddLinkNum[chTmpPathNum]++;
								chTmpPathNum++;
							}
						}
					}
				}
				else
				{
					/*已经找到了终点*/
					chTmpEndPathNum++;
				}

			}

			/*第五步：输出最终路径*/
			for (ii = 0U; ii < chTmpPathNum; ii++)
			{
				if (25U <= chPathNum)
				{
					/* 先判断是否超出路径容量 */
					break;
				}
				else
				{
					for (jj = 0u; jj < szTmpAddLinkNum[ii]; jj++)
					{
						szPath[chPathNum][jj] = szTmpAddPath[ii][jj];
					}

					szLinkNum[chPathNum] = szTmpAddLinkNum[ii];
					chPathNum++;
				}

			}

			*pPathNum = chPathNum;

		}
		else
		{
			;
		}
	}
	else
	{

	}

	if ((1U == chReval) && (chPathNum == chTmpEndPathNum))
	{
		chReval = 2U;
	}
	else
	{
		;
	}

	return chReval;
}

/************************************************
*函数功能:两点之间路径查询(不含电子地图全局变量)
*输入参数:		pLODAStru	A点
*				pLODBStru	B点
*输出参数:		pLinkNum	输出路径的link数量
*				szLinkId	输出路径的linkId序列
*返回值:CI_ERROR：失败
*		CI_SUCCESS：成功:
* by cgh 20250310
************************************************/
UINT8 TwoPointPathSearch(const LOD_STRU* pLODAStru, const LOD_STRU* pLODBStru, UINT16* pLinkNum, UINT16 szLinkId[100])
{
	return TwoPointPathExp(qds_dsuEmapStru, pLODAStru,pLODBStru, pLinkNum, szLinkId);
}














