+namespace
+{
+ struct TMiddle
+ {
+ gp_XY operator()(const gp_XY& uv1, const gp_XY& uv2) const { return ( uv1 + uv2 ) / 2.; }
+ };
+ struct TAdd
+ {
+ gp_XY operator()(const gp_XY& uv1, const gp_XY& uv2) const { return ( uv1 + uv2 ); }
+ };
+ struct TSubtract
+ {
+ gp_XY operator()(const gp_XY& uv1, const gp_XY& uv2) const { return ( uv1 - uv2 ); }
+ };
+
+ //================================================================================
+ /*!
+ * \brief Perform given operation on two points in parametric space of given surface
+ * Example: gp_XY uvSum = applyXYFUN( surf, uv1, uv2, gp_XYFun(Added))
+ */
+ //================================================================================
+
+ template<typename FUNC>
+ gp_XY applyFunc(const Handle(Geom_Surface)& surface,
+ const gp_XY& uv1,
+ gp_XY uv2,
+ const bool resultInPeriod=true)
+ {
+ Standard_Boolean isUPeriodic = surface.IsNull() ? false : surface->IsUPeriodic();
+ Standard_Boolean isVPeriodic = surface.IsNull() ? false : surface->IsVPeriodic();
+ if ( !isUPeriodic && !isVPeriodic )
+ return FUNC()(uv1,uv2);
+
+ // move uv2 not far than half-period from uv1
+ if ( isUPeriodic )
+ uv2.SetX( uv2.X()+ShapeAnalysis::AdjustByPeriod(uv2.X(),uv1.X(),surface->UPeriod()) );
+ if ( isVPeriodic )
+ uv2.SetY( uv2.Y()+ShapeAnalysis::AdjustByPeriod(uv2.Y(),uv1.Y(),surface->VPeriod()) );
+
+ // execute operation
+ gp_XY res = FUNC()(uv1,uv2);
+
+ // move result within period
+ if ( resultInPeriod )
+ {
+ Standard_Real UF,UL,VF,VL;
+ surface->Bounds(UF,UL,VF,VL);
+ if ( isUPeriodic )
+ res.SetX( res.X() + ShapeAnalysis::AdjustToPeriod(res.X(),UF,UL));
+ if ( isVPeriodic )
+ res.SetY( res.Y() + ShapeAnalysis::AdjustToPeriod(res.Y(),VF,VL));
+ }
+
+ return res;
+ }
+}