#pragma once#include"Constraint.h"#include"Eigen/Core"#include"vnl/vnl_math.h"namespaceitk{classSphereConstraint:publicConstraint{public:boolisViolated(constvnl_vector<double>&pt)const{Eigen::Vector3dpt_eigen;pt_eigen(0)=pt[0];pt_eigen(1)=pt[1];pt_eigen(2)=pt[2];returnisViolated(pt_eigen);}boolisViolated(constEigen::Vector3d&pt)const{doubledistance_from_center=sqrt(pow(pt(0)-center(0),2)+pow(pt(1)-center(1),2)+pow(pt(2)-center(2),2));if(distance_from_center<radius)returntrue;returnfalse;}voidprintC()const{std::cout<<"radius "<<radius<<" center "<<center.transpose()<<std::endl;}Eigen::Vector3dGetCenter(){returncenter;}voidSetCenter(Eigen::Vector3dinCenter){center=inCenter;}doubleGetRadius(){returnradius;}voidSetRadius(doubleinRadius){radius=inRadius;}Eigen::Vector3dConstraintGradient(constEigen::Vector3d&pt)const{Eigen::Vector3dgrad=(pt-center)/(pt-center).norm();return-grad;}Eigen::Vector3dConstraintGradientSphere(constEigen::Vector3d&pt,constEigen::Vector3d&updpt)const{// Section computes the intersections between line segment and sphere and determines if they exist// <-----// Compute projection of center to line// proj = pt + dot(ptcenter, update) / dot(update, update) * updateEigen::Vector3dupdate=updpt-pt;Eigen::Vector3dptcenter=center-pt;// If update is none, then return distance from center without considering the updateif(update.dot(update)==0){returnConstraintGradient(updpt);}Eigen::Vector3dproj=pt+ptcenter.dot(update)/update.dot(update)*update;// Computes the distance between line and centerdoubleline_dist_from_center=(proj-center).norm();if(line_dist_from_center<radius){// Use pithagorean theorem to figure out the intersections of line with sphere.doubledist_from_projection_to_intersection=sqrt(radius*radius-line_dist_from_center*line_dist_from_center);Eigen::Vector3dunit_update=update/update.norm();Eigen::Vector3dintersection1=proj+dist_from_projection_to_intersection*unit_update;Eigen::Vector3dintersection2=proj-dist_from_projection_to_intersection*unit_update;if((pt-intersection1).norm()>(pt-intersection2).norm()){Eigen::Vector3dtemp=intersection1;intersection1=intersection2;intersection2=temp;}// ----->if(dist_from_projection_to_intersection>0&&update.norm()>(pt-intersection1).norm()){// Center-repel method//return -(intersection1 - center)/(intersection1 - center).norm();// Projection-repel methodreturn-(intersection1-updpt)/(intersection1-updpt).norm();}}// If intersections don't exist, then just return regular gradient.returnConstraintGradient(updpt);}doubleConstraintEval(constEigen::Vector3d&pt)const{doubleval=(pt-center).norm()-radius;return-val;}doubleConstraintEvalSphere(constEigen::Vector3d&pt,constEigen::Vector3d&updpt)const{// Section computes the intersections between line segment and sphere and determines if they exist// <-----// Compute projection of center to line// proj = pt + dot(ptcenter, update) / dot(update, update) * updateEigen::Vector3dupdate=updpt-pt;Eigen::Vector3dptcenter=center-pt;// If update is none, then return distance from center without considering the updateif(update.dot(update)==0){returnConstraintEval(updpt);}Eigen::Vector3dproj=pt+ptcenter.dot(update)/update.dot(update)*update;// Computes the distance between line and centerdoubleline_dist_from_center=(proj-center).norm();if(line_dist_from_center<radius){// Use pithagorean theorem to figure out the intersections of line with sphere.doubledist_from_projection_to_intersection=sqrt(radius*radius-line_dist_from_center*line_dist_from_center);Eigen::Vector3dunit_update=update/update.norm();Eigen::Vector3dintersection1=proj+dist_from_projection_to_intersection*unit_update;Eigen::Vector3dintersection2=proj-dist_from_projection_to_intersection*unit_update;if((pt-intersection1).norm()>(pt-intersection2).norm()){Eigen::Vector3dtemp=intersection1;intersection1=intersection2;intersection2=temp;}// ----->if(dist_from_projection_to_intersection>0&&update.norm()>(pt-intersection1).norm()){// Center-repel method//return (intersection1 - center).norm();// Projection-repel methodreturn-(intersection1-updpt).norm();}}// If intersections don't exist, then just return regular gradient.returnConstraintEval(updpt);}Eigen::Vector3dLagragianGradient(constEigen::Vector3d&pt,constEigen::Vector3d&updpt,doubleC){// Augmented lagrangian inequality equation: f(x) = mu*(g(x)+z^2) + C/2|g(x)+z^2|^2// f'(x) = mu*g'(x) + C*y' where by substitution// y = √(u^2) where by substitution// u = g(x) + z^2//// Then we compute y'// y' = (dy / du) (du / dx)// = (1/2)*(2 * u) / √(u^2) (du / dx)// = u * u' / | u |// = sgn(u) * u'//// So we substitute// f'(x) = mu*g'(x) + C*sgn(g(x)+z^2)*g'(x)/* Eigen::Vector3d constraint_grad = ConstraintGradient(pt); Eigen::Vector3d first_term = mu*constraint_grad; double eval = ConstraintEval(pt); Eigen::Vector3d second_term = C*constraint_grad*sgn(eval + z*z); return first_term+second_term; */Eigen::Vector3dconstraint_grad=ConstraintGradientSphere(pt,updpt);doubleeval=ConstraintEvalSphere(pt,updpt);doublemaxterm=mu+C*eval;if(maxterm<0){returnEigen::Vector3d(0,0,0);}else{returnmaxterm*constraint_grad;}}private:doubleradius;Eigen::Vector3dcenter;};}