box2f SphericalDeformation::deformedToLocalBounds(const vec3d &deformedCenter, double deformedRadius) const
{
    vec3d p = deformedToLocal(deformedCenter);
    double r = deformedRadius;

    if (isInf(p.x) || isInf(p.y)) {
        return box2f();
    }

    double k = (1.0 - r * r / (2.0 * R * R)) * vec3d(p.x, p.y, R).length();
    double A = k * k - p.x * p.x;
    double B = k * k - p.y * p.y;
    double C = -2.0 * p.x * p.y;
    double D = -2.0 * R * R * p.x;
    double E = -2.0 * R * R * p.y;
    double F = R * R * (k * k - R * R);

    double a = C * C - 4.0 * A * B;
    double b = 2.0 * C * E - 4.0 * B * D;
    double c = E * E - 4.0 * B * F;
    double d = sqrt(b * b - 4.0 * a * c);
    double x1 = (- b - d) / (2.0 * a);
    double x2 = (- b + d) / (2.0 * a);

    b = 2.0 * C * D - 4.0 * A * E;
    c = D * D - 4.0 * A * F;
    d = sqrt(b * b - 4.0 * a * c);
    double y1 = (- b - d) / (2.0 * a);
    double y2 = (- b + d) / (2.0 * a);

    return box2f(vec2f(x1, y1), vec2f(x2, y2));
}
	box2f GraphPane::updateGraphBounds() {
		float2 minPt(std::numeric_limits<float>::max());
		float2 maxPt(std::numeric_limits<float>::min());
		for (GraphDataPtr& curve : curves) {
			for (float2& pt : curve->points) {
				minPt = aly::min(pt, minPt);
				maxPt = aly::max(pt, maxPt);
			}
		}
		graphBounds = box2f(minPt, maxPt - minPt);
		return graphBounds;
	}
	GraphPane::GraphPane(const std::string& name, const AUnit2D& pos, const AUnit2D& dims) :
		Region(name, pos, dims) {
		graphBounds = box2f(float2(0.0f), float2(-1.0f));
		backgroundColor = MakeColor(AlloyApplicationContext()->theme.DARK);
		setRoundCorners(true);
		xAxisLabel = "x";
		yAxisLabel = "y=f(x)";
		cursorPosition.x = -1;
		cursorPosition.y = -1;
		onEvent = [this](const AlloyContext* context, const InputEvent& e) {
			GraphPane* region = this;
			if (context->isMouseOver(region)) {
				cursorPosition = e.cursor;
			}
			else {
				cursorPosition = float2(-1, -1);
			}
			return false;
		};
		Application::addListener(this);
	}
box2f CylindricalDeformation::deformedToLocalBounds(const vec3d &deformedCenter, double deformedRadius) const
{
    assert(false); // TODO
    return box2f();
}