PhysicsFrame::PhysicsFrame(const Any& a) {
    const std::string& n = toLower(a.name());
    *this = PhysicsFrame();

    if (beginsWith(n, "vector3")) {
        *this = PhysicsFrame(Vector3(a));
    } else if (beginsWith(n, "matrix3")) {        
        *this = PhysicsFrame(Matrix3(a));
    } else if (beginsWith(n, "cframe") || beginsWith(n, "coordinateframe")) {        
        *this = PhysicsFrame(CoordinateFrame(a));
    } else if (beginsWith(n, "pframe") || beginsWith(n, "physicsframe")) {
        if (a.type() == Any::ARRAY) {
            a.verifySize(2);
            rotation    = a[0];
            translation = a[1];
        } else {
            for (Any::AnyTable::Iterator it = a.table().begin(); it.hasMore(); ++it) {
                const std::string& n = toLower(it->key);
                if (n == "translation") {
                    translation = it->value;
                } else if (n == "rotation") {
                    rotation = it->value;
                } else {
                    a.verify(false, "Illegal table key: " + it->key);
                }
            }
        }
    }
}
CoordinateFrame::CoordinateFrame(const Any& any) {
    *this = CFrame();

    const std::string& n = toUpper(any.name());

    if (beginsWith(n, "VECTOR3")) {
        translation = any;
    } else if (beginsWith(n, "MATRIX3")) {
        rotation = any;
    } else if ((n == "CFRAME") || (n == "COORDINATEFRAME")) {
        any.verifyType(Any::TABLE, Any::ARRAY);
        if (any.type() == Any::ARRAY) {
            any.verifySize(2);
            rotation    = any[0];
            translation = any[1];
        } else {
            for (Any::AnyTable::Iterator it = any.table().begin(); it.hasMore(); ++it) {
                const std::string& n = toLower(it->key);
                if (n == "translation") {
                    translation = Vector3(it->value);
                } else if (n == "rotation") {
                    rotation = Matrix3(it->value);
                } else {
                    any.verify(false, "Illegal table key: " + it->key);
                }
            }
        }
    } else if (beginsWith(n, "PHYSICSFRAME") || beginsWith(n, "PFRAME")) {
        *this = PhysicsFrame(any);
    } else {
        any.verifyName("CFrame::fromXYZYPRDegrees", "CoordinateFrame::fromXYZYPRDegrees");
        any.verifyType(Any::ARRAY);
        any.verifySize(3, 6);

        int s = any.size();

        *this = fromXYZYPRDegrees(any[0], any[1], any[2],
                                  (s > 3) ? any[3].number() : 0.0f,
                                  (s > 4) ? any[4].number() : 0.0f,
                                  (s > 5) ? any[5].number() : 0.0f);
    }
}
CoordinateFrame::CoordinateFrame(const Any& any) {
    *this = CFrame();

    const String& n = toUpper(any.name());

    if (beginsWith(n, "VECTOR3") || beginsWith(n, "POINT3")) {
        translation = Point3(any);
    } else if (beginsWith(n, "MATRIX3")) {
        rotation = Matrix3(any);
    } else if (beginsWith(n, "MATRIX4")) {
        *this = Matrix4(any).approxCoordinateFrame();
    } else if ((n == "CFRAME") || (n == "COORDINATEFRAME")) {
        any.verifyType(Any::TABLE, Any::ARRAY);
        if (any.type() == Any::ARRAY) {
            any.verifySize(2);
            rotation    = any[0];
            translation = any[1];
        } else {
            AnyTableReader r(any);
            r.getIfPresent("translation", translation);
            r.getIfPresent("rotation", rotation);
            r.verifyDone();
        }
    } else if (beginsWith(n, "PHYSICSFRAME") || beginsWith(n, "PFRAME")) {
        *this = PhysicsFrame(any);
//    } else if (beginsWith(n, "UPRIGHTFRAME") || beginsWith(n, "UFRAME")) {
//        *this = UprightFrame(any);
    } else {
        any.verifyName("CFrame::fromXYZYPRDegrees", "CoordinateFrame::fromXYZYPRDegrees");
        any.verifyType(Any::ARRAY);
        any.verifySize(3, 6);

        int s = any.size();

        *this = fromXYZYPRDegrees(any[0], any[1], any[2], 
                                  (s > 3) ? (float)any[3].number() : 0.0f,
                                  (s > 4) ? (float)any[4].number() : 0.0f,
                                  (s > 5) ? (float)any[5].number() : 0.0f);
    }
}