void
  LaserSensorModel2D::setInformationForVertexPoint(EdgeSE2PointXYCov*& edge, VertexPointXYCov*& point, LaserSensorParams& params)
  {
    double beamAngle = atan2(edge->measurement()(1), edge->measurement()(0));
    ///calculate incidence angle in point frame
    Eigen::Vector2d beam = edge->measurement();

    Eigen::Vector2d normal = point->normal();
    beam = beam.normalized();
    normal = normal.normalized();
    double incidenceAngle = 0.0;
    if(point->covariance() != Eigen::Matrix2d::Identity())
      incidenceAngle = acos(normal.dot(beam));

    double d = (tan(params.angularResolution * 0.5) * edge->measurement().norm());
    ///uncertainty of the surface measurement in direction of the beam
    double dk = fabs(params.scale * (d / cos(incidenceAngle)));
    edge->information().setIdentity();
    edge->information()(0,0) = 1.0 / ((dk + params.sensorPrecision) * (dk + params.sensorPrecision));
    double cError = 0.001 * edge->measurement().norm();
    edge->information()(1,1) = 1.0 / (cError * cError);

    Eigen::Rotation2Dd rot(beamAngle);
    Eigen::Matrix2d mrot = rot.toRotationMatrix();
    edge->information() = mrot * edge->information() * mrot.transpose();
  }
Eigen::Vector2d snell_s (double n1, double n2, const Eigen::Vector2d &input_normal_vector, const Eigen::Vector2d &input_incident_vector)
{
	Eigen::Vector2d normal_vector = input_normal_vector.normalized();
	Eigen::Vector2d incident_vector = input_incident_vector.normalized();

	if (n1 > n2) //check for critcal angle 
	{
		double critical_angle = asin(n1/n2);
		double angle_between_n_I = acos(normal_vector.dot(incident_vector)/(normal_vector.norm()*incident_vector.norm()));
		if (angle_between_n_I>critical_angle)
		{
			throw 20;
		}
	}
	double c = normal_vector.dot(incident_vector);
	double r = n1/n2;
	Eigen::Vector2d v_refract = (r*c - sqrt(1-r*r*(1-c*c)))*normal_vector - r*incident_vector;
	return v_refract;
}
/**
Eigen::Vector2d internal_ray_lens_intersection( const Eigen::Vector2d &direction_of_internal, const Eigen::Vector2d &origin_of_internal, const Eigen::Vector2d &centerpoint_of_sphere, double radius_of_sphere)
{
	//https://people.cs.clemson.edu/~dhouse/courses/405/notes/raycast.pdf
	Eigen::Vector2d return_intersection;
	Eigen::Vector2d direction_of_internal_normalized = direction_of_internal.normalized();
	Eigen::Vector2d o_minus_c = origin_of_internal-centerpoint_of_sphere;
	double discriminant = (direction_of_internal_normalized.dot(o_minus_c))*(direction_of_internal_normalized.dot(o_minus_c))-o_minus_c.norm()*o_minus_c.norm()+radius_of_sphere*radius_of_sphere;
	if (discriminant < 0)
	{
		throw 30;
	}
	else
	{
		double d_1 = -1*(direction_of_internal_normalized.dot(o_minus_c))+sqrt((direction_of_internal_normalized.dot(o_minus_c))*(direction_of_internal_normalized.dot(o_minus_c))-o_minus_c.norm()*o_minus_c.norm()+radius_of_sphere*radius_of_sphere);
		double d_2 = -1*(direction_of_internal_normalized.dot(o_minus_c))-sqrt((direction_of_internal_normalized.dot(o_minus_c))*(direction_of_internal_normalized.dot(o_minus_c))-o_minus_c.norm()*o_minus_c.norm()+radius_of_sphere*radius_of_sphere);
		if (d_2=d_1)
		{
			return_intersection = origin_of_internal+d_2*direction_of_internal_normalized;
		}
		else
		{
			Eigen::Vector2d return_intersection_1 = origin_of_internal+d_1*direction_of_internal_normalized;
			Eigen::Vector2d return_intersection_2 = origin_of_internal+d_2*direction_of_internal_normalized;
			if (return_intersection_1.y()<return_intersection_2.y())
			{
				return_intersection = return_intersection_1;
			}
			else
			{
				return_intersection = return_intersection_2;
			}

		}
		cout << "lens choice 1: " << d_1 << endl;
		cout << "lens choice 2: " << d_2 << endl;
	}
	return return_intersection;
}
**/
Eigen::Vector2d internal_ray_lens_intersection( const Eigen::Vector2d &direction_of_internal, const Eigen::Vector2d &origin_of_internal, const Eigen::Vector2d &centerpoint_of_sphere, double radius_of_sphere)
{
	// https://people.cs.clemson.edu/~dhouse/courses/405/notes/raycast.pdf
	Eigen::Vector2d return_intersection;
	Eigen::Vector2d direction_of_internal_normalized = direction_of_internal.normalized(); 
	Eigen::Vector2d o_minus_c = origin_of_internal-centerpoint_of_sphere;
	double t_close = direction_of_internal.dot(centerpoint_of_sphere-origin_of_internal);
	Eigen::Vector2d x_close = origin_of_internal + t_close*direction_of_internal;
	double discriminant = (x_close-centerpoint_of_sphere).norm();
	if (discriminant < radius_of_sphere)
	{
		double a = sqrt(radius_of_sphere*radius_of_sphere-discriminant*discriminant);
		return_intersection = origin_of_internal + (t_close-a)*direction_of_internal;
		//cout << "Centerpoint of sphere : " << centerpoint_of_sphere << endl;
		//cout << "radius of sphere : " << radius_of_sphere << endl;
	}
	else
	{
		throw 30;
	}
	return return_intersection;
}