#ifndef __RV_SMATH_H_INCLUDED_
#define __RV_SMATH_H_INCLUDED_
 
 

#include <rvb\rvtypes.h> 

 
#define RV_TO_RAD(deg) ((deg) / 180. * RV_PI)
#define RV_TO_DEG(rad) ((rad) / RV_PI * 180.)

#define RV_TO_RAD_F(deg) ((deg) / 180.f * RV_PI_F)
#define RV_TO_DEG_F(rad) ((rad) / RV_PI_F * 180.f)

//相对位置
#define RV_ORI_UNK      (-1)
#define RV_ORI_RIGHT     0  //右侧
#define RV_ORI_LEFT      1
#define RV_ORI_INSIDE    0  //里面
#define RV_ORI_OUTSIDE   1
#define RV_ORI_CW        0  //顺时针
#define RV_ORI_CCW       1



#define SMATH_API   WINAPI

 
//geometry
extern "C" BOOL   SMATH_API  rvCalcArcCenter(RvPoint p1, RvPoint p2, RvPoint p3, float *x, float *y, float* radius=NULL) ;
extern "C" BOOL   SMATH_API  rvCalcArcCenterEx(RvPoint p1, RvPoint p2, RvPoint p3, double *x, double *y, double* radius=NULL) ;
extern "C" BOOL   SMATH_API  rvCalcArcCenterF64(RvPoint_f64 p1, RvPoint_f64 p2, RvPoint_f64 p3, double *x, double *y, double* radius=NULL) ;
extern "C" BOOL   SMATH_API  rvCalcArcCenterE1(RvPoint_f p1, RvPoint_f p2, RvPoint_f p3, float *x, float *y, float* radius=NULL) ;


extern "C" BOOL   SMATH_API  rvIsAdequateArc(RvPoint p1, RvPoint p2, RvPoint p3);

extern "C" double  SMATH_API rvGetNormalAngle(double x0, double y0, double x1, double y1, BOOL bDegree=FALSE);
 
extern "C" double  SMATH_API rvGetNormalAngleE1(double y, double x,  BOOL bDegree=FALSE );
extern "C" float  SMATH_API rvGetNormalAngleE2(float y, float x,  BOOL bDegree=FALSE );

 

//accuracy表示angle包含小数点后面的位数
extern "C" RvPoint SMATH_API   rvRotateLine(RvPoint p0, RvPoint p1,  int angle,   int accuracy);
extern "C" RvPoint SMATH_API   rvRotateLineE1(int x0, int y0, RvPoint  p1,   int angle,   int accuracy);

extern "C" RvPoint_f  SMATH_API  rvRotateLineE2(RvPoint_f p0, RvPoint_f p1, double angle);
extern "C" RvPoint_f SMATH_API   rvRotateLineE3(double x0, double y0,  RvPoint_f  p1,  double angle);
extern "C" RvPoint_f64  SMATH_API  rvRotateLineE4( double x0, double y0, double x1, double y1 ,  double angle);


extern "C" RvPoint      SMATH_API  rvRotatePoint(RvPoint point,  int x, int y, float angle );
extern "C" RvPoint_f64  SMATH_API  rvRotatePointE1(RvPoint_f64 point,  double x, double y, double angle );



extern "C" void  SMATH_API  rvRotateVertex( RvPoint* pVertex,  int count, int x, int y, float angle );

extern "C" void  SMATH_API  rvRotateVertexE1( RvPoint_f* pVertex,  int count, float x, float  y, float angle );
extern "C" void   SMATH_API rvRotateVertexE2( RvPoint_f64* pVertex,  int count, double x, double  y, double angle );

extern "C" void   SMATH_API rvScaleVertex( RvPoint* pVertex,  int count, float scaleX, float scaleY );
extern "C" void   SMATH_API rvScaleVertexE1( RvPoint_f64* pVertex,  int count, double scaleX, double scaleY  );
extern "C" void   SMATH_API rvScaleVertexE2( RvPoint_f* pVertex,   int count, float scaleX , float scaleY );

//沿起点开始，计算直线上距离起点位置为n的点
//点坐标可能在线外，也可能在线上。
//如果dist为负值，反方向计算。
extern "C" RvPoint_f64  SMATH_API rvCalcPointAlongLineE2(RvPoint_f64 start, RvPoint_f64 end, double dist);
extern "C" RvPoint_f   SMATH_API rvCalcPointAlongLineE1(RvPoint_f  start, RvPoint_f  end, float dist);
extern "C" RvPoint     SMATH_API rvCalcPointAlongLine (RvPoint  start, RvPoint  end, int dist);






//简单拟合成线段，必需是连续边缘点。
//这个函数有些问题，最好暂时不用
extern "C" int  SMATH_API rvApproxLine(RvPoint * pPointSet, int count );

 

//获得顶点数组的外包围矩形
extern "C" RvRect SMATH_API  rvCalcBoundRect( RvPoint* pVertex,  int count );

//获得顶点数组的外包围矩形
extern "C" RvRect_f  SMATH_API rvCalcBoundRectE1( RvPoint_f* pVertex,  int count );

extern "C" RvRect_f64  SMATH_API rvCalcBoundRectE2( RvPoint_f64* pVertex,  int count );


extern "C" BOOL  SMATH_API rvIsPointInPolygon (RvPoint point, RvPoint* pPolygon, int nCount) ;
extern "C" BOOL  SMATH_API rvIsPointInPolygonE1 (int x, int y, RvPoint* pPolygon, int nCount) ;
extern "C"  BOOL SMATH_API rvIsPointInPolygonE2 (RvPoint_f point, RvPoint_f* pPolygon, int nCount) ;
extern "C" BOOL  SMATH_API rvIsPointInPolygonE3 (float x, float y, RvPoint_f* pPolygon, int nCount) ;

extern "C"  BOOL SMATH_API rvIsPointInPolygonE4 (int x, int y, RvPoint* pInnerArray, int nInnerCount, RvPoint* pOuterArray, int nOuterCount) ;

//下面的顶点数组可以包含过个轮廓的点
extern "C" BOOL SMATH_API rvIsPointInPolygonE5 (int x, int y, RvPoint* pVertexArray, int nVertexCount, BOOL* pOnBorder) ;


extern "C" BOOL  SMATH_API rvIsPointInPolygonE6 (double x, double y, RvPoint_f64* pPolygon, int nCount) ;


////////////////////////////////////////////////////////////////////////////


//生成圆边缘点
extern "C" int SMATH_API rvGenEllipse (int cx,int cy, int radius0, int radius1, RvPoint* pPointArray, int nArrayCount) ;

//将多变型平移扩大或缩小,distance为正扩大，
extern "C" void SMATH_API rvOffsetPolygon(RvPoint_f* pVertexArray, int nArraySize, float distance);

extern "C" void SMATH_API rvOffsetPolygonI32(RvPoint* pVertexArray, int nArraySize, int distance);



//将多变型平移扩大或缩小,distance为正扩大，
//结果保存在pResultArray
//nArraySize 为pVertexArray 和pResultArray
////使用clipper库
extern "C" int SMATH_API rvOffsetPolygonE1(const RvPoint* pVertexArray, int nArraySize, int distance, RvPoint* pResultArray, int nResultSize);
extern "C" int SMATH_API rvOffsetPolygonE2(  RvPoint* pVertexArray, int nArraySize, int distance );

  


//计算某天在直线段上的垂直点,如果垂点在线段外，返回FALSE.
extern "C" BOOL SMATH_API rvCalcPerpdPoint(RvPoint_f start, RvPoint_f end, RvPoint_f outer, RvPoint_f* pResult);

 //计算某天在直线段上的垂直点,如果垂点在线段外，返回FALSE.
extern "C" BOOL SMATH_API rvCalcPerpdPointEx(RvLine_f line, RvPoint_f outer, RvPoint_f* pResult);

  //计算某天在直线段上的垂直点,如果垂点在线段外，返回FALSE.
extern "C" BOOL SMATH_API rvCalcPerpdPointE1(RvPoint  start, RvPoint  end, RvPoint  outer, RvPoint * pResult);

extern "C" BOOL SMATH_API rvCalcPerpdPointE2(RvPoint_f64  start, RvPoint_f64  end, RvPoint_f64  outer, RvPoint_f64 * pResult);
extern "C" BOOL SMATH_API rvCalcPerpdPointE3(RvLine_f64 line, RvPoint_f64  outer, RvPoint_f64 * pResult);
 


//计算直线段夹角或3点围成的夹角
extern "C" double SMATH_API rvCalcLineAngle(RvLine_f line0, RvLine_f line1, BOOL bDegree);
extern "C" double SMATH_API rvCalcLineAngleE1(RvLine_f64 line0, RvLine_f64 line1, BOOL bDegree);

extern "C" double SMATH_API rvCalc3PAngle(RvPoint_f oripos, RvPoint_f start, RvPoint_f end,  BOOL bDegree);
extern "C" double SMATH_API rvCalc3PAngleE1(RvPoint_f64 oripos, RvPoint_f64 start, RvPoint_f64 end,  BOOL bDegree);


extern "C" BOOL SMATH_API rvCalcIntersection(RvLine_f64 line0, RvLine_f64 line1, RvPoint_f64* pResult);

//派生平行线
//负值为反方向
extern "C" RvLine_f64 SMATH_API rvDeriveParallel(RvLine_f64 line, double distance);

extern "C" RvLine   SMATH_API rvDeriveParallelE1(RvLine  line, int distance);
extern "C" RvLine_f  SMATH_API rvDeriveParallelE2(RvLine_f  line, float distance);


extern "C" RvPoint SMATH_API rvDeriveMidPoint(RvPoint p0, RvPoint p1);
extern "C" RvPoint_f SMATH_API rvDeriveMidPointE1(RvPoint_f p0, RvPoint_f p1);
extern "C" RvPoint_f SMATH_API rvDeriveMidPointE2(int x0, int y0, int x1, int y1);
extern "C" RvPoint_f64 SMATH_API rvDeriveMidPointE3(RvPoint_f64 p0, RvPoint_f64 p1);
extern "C" RvPoint_f64 SMATH_API rvDeriveMidPointE4(double x0, double y0, double x1, double y1);


//派生垂直线
//bFullSize为TRUE, length只能为正,直线为穿过端点的线。
//否者如果为正，顺时针90度直线；为负的话，逆时针90度直线。
extern "C" RvLine_f64 SMATH_API rvDerivePerpend(RvLine_f64 line, double length, BOOL bFullSize, BOOL bStartPos);
extern "C" RvLine  SMATH_API    rvDerivePerpendE1(RvLine  line, int length, BOOL bFullSize, BOOL bStartPos);


 
//延长直线长度
//负值为p0反方向
//正值为p1正方向
extern "C" RvLine_f64 SMATH_API rvExtendLine(RvLine_f64 line, double length);

//index =0 , 起始端被剪裁;  index=1，结束端被剪彩
extern "C" RvLine_f64 SMATH_API rvTrimLine(RvLine_f64 line, RvLine_f64 base, int index);
  


extern "C" double SMATH_API rvCalcPolygonArea(RvPoint_f* pVertexArray, int nArraySize);
extern "C" double SMATH_API rvCalcPolygonAreaE1(RvPoint * pVertexArray, int nArraySize);

extern "C" double SMATH_API rvCalcPolylineLength(RvPoint_f* pVertexArray, int nArraySize, BOOL bClosed);
extern "C" double SMATH_API rvCalcPolylineLengthE1(RvPoint* pVertexArray, int nArraySize, BOOL bClosed);
extern "C" double SMATH_API rvCalcPolylineLengthE2(RvPoint_f64* pVertexArray, int nArraySize, BOOL bClosed);
 
extern "C" RvPoint SMATH_API rvCalcPolygonCenter(RvPoint* pVertexArray, int nArraySize);
extern "C" RvPoint_f  SMATH_API rvCalcPolygonCenterE1(RvPoint_f * pVertexArray, int nArraySize);
extern "C" RvPoint_f64 SMATH_API rvCalcPolygonCenterE2(RvPoint_f64* pVertexArray, int nArraySize);




 //计算点到多段线（多边形）的最短距离
extern "C" int SMATH_API rvCalcPointToPolylineDistance(int x, int y, RvPoint* pVertexArray, int nArraySize, BOOL bClosed);

 //点到直线的距离,先计算垂足点。如果垂点在线段上，那么返回垂直距离，否则，返回点距离线段中端点最短的距离。
//bUprightDisance： 是否仅计算为垂直距离
//该函数过时@250525
extern "C" int SMATH_API   rvCalcPointToLineDistance(int x, int y, RvPoint p0,  RvPoint p1,BOOL bUprightDisance);
extern "C" float SMATH_API rvCalcPointToLineDistanceE1(int x, int y, RvPoint p0,  RvPoint p1,BOOL bUprightDisance);
extern "C" float SMATH_API rvCalcPointToLineDistanceE2(float x, float y, RvPoint_f p0,  RvPoint_f p1,BOOL bUprightDisance);
//endof @250525
extern "C" int SMATH_API   rvCalcPointToLineDist(RvPoint p0,  RvPoint p1, RvPoint outer, BOOL bUprightDisance);
extern "C" float SMATH_API rvCalcPointToLineDistE1(RvPoint_f p0,  RvPoint_f p1, RvPoint_f outer,BOOL bUprightDisance);
extern "C" double SMATH_API rvCalcPointToLineDistE2(RvPoint_f64 p0,  RvPoint_f64 p1, RvPoint_f64 outer, BOOL bUprightDisance);



extern "C" void SMATH_API rvMovePolylineI32(RvPoint * pVertexArray, int nArraySize, int dx, int dy);
extern "C" void SMATH_API rvMovePolylineF64(RvPoint_f64 * pVertexArray, int nArraySize,  double dx, double dy);
extern "C" void SMATH_API rvMovePolylineF32(RvPoint_f  * pVertexArray, int nArraySize,  float dx, float dy);

 
//点到直线的距离
extern "C" double SMATH_API rvDistPL(RvPoint_f64 point, RvLine_f64 line  );
  


//直线到直线的距离
extern "C" double SMATH_API rvDistLL(RvLine_f64 line1, RvLine_f64 line2  );

extern "C" RvRect  SMATH_API rvAdaptRect(RvRect container, int width, int height, double *ratio);

 //可以支持left,top为0
extern "C" RvRect  SMATH_API rvAdaptRectE1(RvRect container, int width, int height, BOOL bNoAlignCenter, double *ratio);



extern "C" double SMATH_API rvPower(double base, int index ) ;
extern "C" int   SMATH_API  rvPowerE1(int base, int index ) ;

//下面的函数至少顶点数量最少为4
extern "C" int SMATH_API  rvBox2dToVertex(RvBox2D  box, RvPoint* pPointArray, int size ) ;
extern "C" int SMATH_API  rvBox2dToVertexE1(RvBox2D  box, RvPoint_f* pPointArray, int size ) ;
extern "C" int  SMATH_API rvBox2dToVertexE2(RvBox2D  box, RvPoint_f64* pPointArray, int size ) ;
 
 //矩形转顶点数组， 顶点数量最少为4
extern "C" int SMATH_API  rvRectToVertex(RvRect rect, RvPoint* pPointArray, int size ) ;
extern "C" int SMATH_API  rvRectToVertexE1(RvRect rect, RvPoint_f* pPointArray, int size ) ;
extern "C" int SMATH_API  rvRectToVertexE2(RvRect rect, RvPoint_f64* pPointArray, int size ) ;
 


extern "C" RvRect SMATH_API rvBox2dToRect(RvBox2D  box);
extern "C" BOOL SMATH_API rvIsBox2dInRect(RvBox2D  box, RvRect rect);


extern "C" RvPoint SMATH_API rvGetRectCenter(RvRect rect);
extern "C" RvSize SMATH_API  rvGetRectSize(RvRect rect, BOOL bIncludeBorder=FALSE);
extern "C" int SMATH_API  rvGetRectWidth(RvRect rect, BOOL bIncludeBorder=FALSE);
extern "C" int SMATH_API  rvGetRectHeight(RvRect rect, BOOL bIncludeBorder=FALSE);

extern "C" RvRect SMATH_API   rvRotateRect(RvRect rect, double angle);
extern "C" RvRect SMATH_API   rvMoveRect(RvRect rect, int dx, int dy);



extern "C" RvRect SMATH_API rvScaleRect(RvRect rect, double scale);
extern "C" RvRect SMATH_API rvScaleRectE1(RvRect rect, double scaleX, double scaleY);




extern "C" RvRect SMATH_API  rvRectIntersect(RvRect rect, RvRect other);
extern "C"  BOOL  SMATH_API rvIsRectEmpty(RvRect rect);


 
 //level >= 0
extern "C" int SMATH_API rvGetMipUpScale(int level);
extern "C" float SMATH_API rvGetMipDownScale(int level);
 //level <0缩小比例，大于0为放大比率
extern "C"  float SMATH_API rvGetMipScale(int level, BOOL bOpposite=FALSE); 
  

extern "C" void SMATH_API rvFft(RvReal32* pArray, int size) ;
extern "C" void  SMATH_API rvFftE1(RvReal64* pArray, int size) ;
extern "C" void  SMATH_API rvFftE2(RvComplex32* pArray, int size) ;
extern "C" void SMATH_API  rvFftE3(RvComplex64* pArray, int size) ;

extern "C" void  SMATH_API rvUnfft(RvReal32* pArray, int size, BOOL bScale=TRUE) ;
extern "C" void  SMATH_API rvUnfftE1(RvReal64* pArray, int size, BOOL bScale=TRUE) ;
extern "C" void  SMATH_API rvUnfftE2(RvComplex32* pArray, int size, BOOL bScale=TRUE) ;
extern "C" void SMATH_API rvUnfftE3(RvComplex64* pArray, int size, BOOL bScale=TRUE) ;


extern "C" void  SMATH_API rvFftMul(RvReal32* pArray0, RvReal32* pArray1, int size) ;
extern "C" void SMATH_API  rvFftMulE1(RvReal64* pArray0, RvReal64* pArray1,  int size) ;
extern "C" void SMATH_API rvFftMulE2(RvComplex32* pArray0, RvComplex32* pArray1,  int size) ;
extern "C" void SMATH_API rvFftMulE3(RvComplex64* pArray0, RvComplex64* pArray1,  int size) ;

extern "C" void SMATH_API  rvFftScale(RvReal32* pArray, int size) ;
extern "C" void SMATH_API rvFftScaleE1(RvReal64* pArray, int size) ;
extern "C" void SMATH_API rvFftScaleE2(RvComplex32* pArray, int size) ;
extern "C" void SMATH_API rvFftScaleE3(RvComplex64* pArray, int size) ;
  
#define rvDft(arr, size)    rvFft(arr, size) 
#define rvIdft(arr, size)   rvUnfft(arr, size) 



//左边大于右边，或上边大于下边
extern "C"  BOOL SMATH_API rvIsNullRect(RvRect rect);

//四点相等
extern "C"  BOOL SMATH_API  rvIsRectEqual(RvRect rect0, RvRect rect1 ) ;

extern "C"  void SMATH_API  rvNormalizeRect(RvRect* pRect) ;


//比较 矩形大小，
//如rect0 == rect1，返回0
//如rect0 < rect1，返回-1
//如rect0 > rect1，返回1

extern "C" int SMATH_API rvCompareRect(RvRect rect0, RvRect rect1 );

//判断点在直线左侧还是右侧,左侧为顺时针
extern "C" BOOL SMATH_API rvIsPointLeftToLine(RvPoint_f64 p0, RvPoint_f64 p1, RvPoint_f64 outer );
extern "C" BOOL SMATH_API rvIsPointLeftToLineE1(RvLine_f64 line, RvPoint_f64 outer );
//左侧为顺时针
extern "C" int SMATH_API rvCalcPointToLineOrient(RvPoint   p0, RvPoint  p1, RvPoint   outer );
extern "C" int SMATH_API rvCalcPointToLineOrientE1(RvPoint_f  p0, RvPoint_f p1, RvPoint_f  outer );
extern "C" int SMATH_API rvCalcPointToLineOrientE2(RvPoint_f64   p0, RvPoint_f64  p1, RvPoint_f64   outer );




//判断点在多边型的内侧还是外侧
//extern "C" int SMATH_API rvIsPointInsidePolygon(RvPoint_f64* pVertexArray, int nArraySize, RvPoint_f64 outer );
//extern "C" int SMATH_API rvIsPointInsidePolygonE1(RvPoint * pVertexArray, int nArraySize, RvPoint_f64 outer );


//判断点在圆的内侧还是外侧
extern "C" int SMATH_API rvIsPointInsideCircle(RvPoint_f64  p0, RvPoint_f64  p1, RvPoint_f64  p2, RvPoint_f64 outer );
extern "C" int SMATH_API rvIsPointInsideCircleE1(RvPoint_f64  center, double radius, RvPoint_f64 outer );
extern "C" int SMATH_API rvIsPointInsideCircleE2(RvPoint_f64  center, double rx, double ry, RvPoint_f64 outer );


extern "C" BOOL SMATH_API rvIsPointInsideRect(RvRect rect, RvPoint  pos, BOOL bOnBorderOnly =FALSE );
 



//rect1的所有点都在rect0之中 ,是否不再判断相等
extern "C" BOOL SMATH_API rvIsRectSurround(RvRect rect0, RvRect rect1 );



extern "C" BOOL SMATH_API rvIsRectSurroundE1(RvRect* pRect0, RvRect* pRect1 );


//depth表示一个像素多少位
extern "C"  int SMATH_API rvCalcPitch(int pixbits, int width);
extern "C"  int SMATH_API rvCalcDepth(RV_IMAGE_TYPE type);

//percent: 0-1, 越大越黑
extern "C"  RvRgb SMATH_API rvGetBrighterPixel(RvRgb color,   float percent);
extern "C"  RvColor SMATH_API rvGetBrighterPixelE1(RvColor color,  float percent);

//percent: 0-1, 越大越白
extern "C"  RvRgb SMATH_API  rvGetDarkerPixel(RvRgb color,   float percent);
extern "C"  RvColor SMATH_API rvGetDarkerPixelE1(RvColor color,  float percent);

// 
#define RV_CG_HSV    1
extern "C"  int SMATH_API rvCalcGray(RvColor color, int method = RV_CG_HSV);

//计算最佳的阈值,按照otsu
extern "C"  int SMATH_API rvCalcOtsu(int maxValue, UINT* pMagArr, int arrSize);

//从现有的多边形重提取一段连续的点
//startIndex and endIndex >=0 and < inSize
//子多边形包含的点中有startIndex和endIndex两点
extern "C"  int SMATH_API rvGetSubPolygonVertex(const RvPoint* pArrIn, int inCount, int startIndex, int endIndex,   RvPoint* pArrOut, int outCount);
//多边形子边缘的长度
extern "C"   double SMATH_API rvGetSubPolygonPerimeter(const RvPoint* pArrIn, int inCount, int startIndex, int endIndex);

//bIncludeBorder ： 如果点与顶点重合也算内部点
extern "C"   BOOL SMATH_API rvIsSubPolygon(const RvPoint* pArrBig, int bigCount, const RvPoint* pArrSmall, int smallCount, BOOL bIncludeBorder);





//该函数会根据box角度旋转成0度角度
extern "C" BOOL  SMATH_API rvApproxEllipse(RvPoint* pEdgePoints, int count, RvBox2D*  pBox2d, double* pAvgError, double* pMaxError, double* pMinError );


extern "C" BOOL  SMATH_API rvIsClockWise(RvPoint start, RvPoint mid, RvPoint end);
extern "C" BOOL  SMATH_API rvIsClockWiseE1(RvPoint_f64 start, RvPoint_f64 mid, RvPoint_f64 end);
extern "C" BOOL  SMATH_API rvIsClockWiseE2(RvPoint_f  start, RvPoint_f  mid, RvPoint_f  end);








#endif


