PyObject* BSplineSurfacePy::reparametrize(PyObject * args)
{
    int u,v;
    double tol = 0.000001;
    if (!PyArg_ParseTuple(args, "ii|d", &u, &v, &tol))
        return 0;

    // u,v must be at least 2
    u = std::max<int>(u, 2);
    v = std::max<int>(v, 2);

    try {
        Handle_Geom_BSplineSurface surf = Handle_Geom_BSplineSurface::DownCast
            (getGeometryPtr()->handle());

        double maxU = surf->UKnot(surf->NbUKnots()); // 1.0 if normalized surface
        double maxV = surf->VKnot(surf->NbVKnots()); // 1.0 if normalized surface

        GeomBSplineSurface* geom = new GeomBSplineSurface();
        Handle_Geom_BSplineSurface spline = Handle_Geom_BSplineSurface::DownCast
            (geom->handle());
        for (int i=1; i<u-1; i++) {
            double U = i * 1.0 / (u-1.0);
            spline->InsertUKnot(U,i,tol,Standard_True);
        }

        for (int i=1; i<v-1; i++) {
            double V = i * 1.0 / (v-1.0);
            spline->InsertVKnot(V,i,tol,Standard_True);
        }

        for (int j=0; j<u; j++) {
            double U = j * maxU / (u-1.0);
            double newU = j * 1.0 / (u-1.0);
            for (int k=0; k<v; k++) {
                double V = k * maxV / (v-1.0);
                double newV = k * 1.0 / (v-1.0);
                // Get UV point and move new surface UV point
                gp_Pnt point = surf->Value(U,V);
                int ufirst, ulast, vfirst, vlast;
                spline->MovePoint(newU, newV, point, j+1, j+1, k+1, k+1, ufirst, ulast, vfirst, vlast);
            }
        }

        return new BSplineSurfacePy(geom);
    }
    catch (Standard_Failure) {
        Handle_Standard_Failure e = Standard_Failure::Caught();
        PyErr_SetString(PyExc_Exception, e->GetMessageString());
        return 0;
    }
}
Py::List BSplineSurfacePy::getUKnotSequence(void) const
{
    Handle_Geom_BSplineSurface surf = Handle_Geom_BSplineSurface::DownCast
        (getGeometryPtr()->handle());
    Standard_Integer m = 0;
    for (int i=1; i<= surf->NbUKnots(); i++)
        m += surf->UMultiplicity(i);
    TColStd_Array1OfReal k(1,m);
    surf->UKnotSequence(k);
    Py::List list;
    for (Standard_Integer i=k.Lower(); i<=k.Upper(); i++) {
        list.append(Py::Float(k(i)));
    }
    return list;
}
PyObject* BSplineSurfacePy::getUKnots(PyObject *args)
{
    if (!PyArg_ParseTuple(args, ""))
        return 0;
    try {
        Handle_Geom_BSplineSurface surf = Handle_Geom_BSplineSurface::DownCast
            (getGeometryPtr()->handle());
        TColStd_Array1OfReal w(1,surf->NbUKnots());
        surf->UKnots(w);
        Py::List knots;
        for (Standard_Integer i=w.Lower(); i<=w.Upper(); i++) {
            knots.append(Py::Float(w(i)));
        }
        return Py::new_reference_to(knots);
    }
    catch (Standard_Failure) {
        Handle_Standard_Failure e = Standard_Failure::Caught();
        PyErr_SetString(PyExc_Exception, e->GetMessageString());
        return 0;
    }
}
Py::Int BSplineSurfacePy::getNbUKnots(void) const
{
    Handle_Geom_BSplineSurface surf = Handle_Geom_BSplineSurface::DownCast
        (getGeometryPtr()->handle());
    return Py::Int(surf->NbUKnots()); 
}
int convert_to_ifc(const Handle_Geom_Surface& s, IfcSchema::IfcSurface*& surface, bool advanced) {
	if (s->DynamicType() == STANDARD_TYPE(Geom_Plane)) {
		Handle_Geom_Plane plane = Handle_Geom_Plane::DownCast(s);
		IfcSchema::IfcAxis2Placement3D* place;
		/// @todo: Note that the Ax3 is converted to an Ax2 here
		if (!convert_to_ifc(plane->Position().Ax2(), place, advanced)) {
			return 0;
		}
		surface = new IfcSchema::IfcPlane(place);
		return 1;
	}
#ifdef USE_IFC4
	else if (s->DynamicType() == STANDARD_TYPE(Geom_CylindricalSurface)) {
		Handle_Geom_CylindricalSurface cyl = Handle_Geom_CylindricalSurface::DownCast(s);
		IfcSchema::IfcAxis2Placement3D* place;
		/// @todo: Note that the Ax3 is converted to an Ax2 here
		if (!convert_to_ifc(cyl->Position().Ax2(), place, advanced)) {
			return 0;
		}
		surface = new IfcSchema::IfcCylindricalSurface(place, cyl->Radius());
		return 1;
	} else if (s->DynamicType() == STANDARD_TYPE(Geom_BSplineSurface)) {
		typedef IfcTemplatedEntityListList<IfcSchema::IfcCartesianPoint> points_t;

		Handle_Geom_BSplineSurface bspline = Handle_Geom_BSplineSurface::DownCast(s);
		points_t::ptr points(new points_t);

		TColgp_Array2OfPnt poles(1, bspline->NbUPoles(), 1, bspline->NbVPoles());
		bspline->Poles(poles);
		for (int i = 1; i <= bspline->NbUPoles(); ++i) {
			std::vector<IfcSchema::IfcCartesianPoint*> ps;
			ps.reserve(bspline->NbVPoles());
			for (int j = 1; j <= bspline->NbVPoles(); ++j) {
				IfcSchema::IfcCartesianPoint* p;
				if (!convert_to_ifc(poles.Value(i, j), p, advanced)) {
					return 0;
				}
				ps.push_back(p);
			}
			points->push(ps);
		}

		IfcSchema::IfcKnotType::IfcKnotType knot_spec_u = opencascade_knotspec_to_ifc(bspline->UKnotDistribution());
		IfcSchema::IfcKnotType::IfcKnotType knot_spec_v = opencascade_knotspec_to_ifc(bspline->VKnotDistribution());

		if (knot_spec_u != knot_spec_v) {
			knot_spec_u = IfcSchema::IfcKnotType::IfcKnotType_UNSPECIFIED;
		}

		std::vector<int> umults;
		std::vector<int> vmults;
		std::vector<double> uknots;
		std::vector<double> vknots;
		std::vector< std::vector<double> > weights;

		TColStd_Array1OfInteger bspline_umults(1, bspline->NbUKnots());
		TColStd_Array1OfInteger bspline_vmults(1, bspline->NbVKnots());
		TColStd_Array1OfReal bspline_uknots(1, bspline->NbUKnots());
		TColStd_Array1OfReal bspline_vknots(1, bspline->NbVKnots());
		TColStd_Array2OfReal bspline_weights(1, bspline->NbUPoles(), 1, bspline->NbVPoles());

		bspline->UMultiplicities(bspline_umults);
		bspline->VMultiplicities(bspline_vmults);
		bspline->UKnots(bspline_uknots);
		bspline->VKnots(bspline_vknots);
		bspline->Weights(bspline_weights);

		opencascade_array_to_vector(bspline_umults, umults);
		opencascade_array_to_vector(bspline_vmults, vmults);
		opencascade_array_to_vector(bspline_uknots, uknots);
		opencascade_array_to_vector(bspline_vknots, vknots);
		opencascade_array_to_vector2(bspline_weights, weights);

		bool rational = false;
		for (std::vector< std::vector<double> >::const_iterator it = weights.begin(); it != weights.end(); ++it) {
			for (std::vector<double>::const_iterator jt = it->begin(); jt != it->end(); ++jt) {
				if ((*jt) != 1.) {
					rational = true;
					break;
				}
			}
		}

		if (rational) {
			surface = new IfcSchema::IfcRationalBSplineSurfaceWithKnots(
				bspline->UDegree(),
				bspline->VDegree(),
				points,
				IfcSchema::IfcBSplineSurfaceForm::IfcBSplineSurfaceForm_UNSPECIFIED,
				bspline->IsUClosed(),
				bspline->IsVClosed(),
				false,
				umults,
				vmults,
				uknots,
				vknots,
				knot_spec_u,
				weights
				);
		} else {
			surface = new IfcSchema::IfcBSplineSurfaceWithKnots(
				bspline->UDegree(),
				bspline->VDegree(),
				points,
				IfcSchema::IfcBSplineSurfaceForm::IfcBSplineSurfaceForm_UNSPECIFIED,
				bspline->IsUClosed(),
				bspline->IsVClosed(),
				false,
				umults,
				vmults,
				uknots,
				vknots,
				knot_spec_u
				);
		}

		return 1;
	}
#endif
	return 0;
}