def extract(self, u0=0., u1=1., v0=0., v1=1., domain='local'): """ Extract Bezier surface bounded by parameters. :param float u0: Starting parameter in u-direction. :param float u1: Ending parameter in u-direction. :param float v0: Starting parameter in v-direction. :param float v1: Ending parameter in v-direction. :param str domain: Option to use local (0 <= u, v <= 1) or global (a <= u, v <= b) domain ('local', 'l', 'global', 'g'). :return: Extracted Bezier surface. :rtype: :class:`.BezierSurface` """ if not is_local_domain(domain): u0 = self.global_to_local_param('u', u0) u1 = self.global_to_local_param('u', u1) v0 = self.global_to_local_param('v', v0) v1 = self.global_to_local_param('v', v1) qw, ab = extract_bezier_surface(self._n, self._m, self._cpw, u0, u1, v0, v1, self._u0, self._u1, self._v0, self._v1) s = BezierSurface() s.set_cpw(qw) s.set_domain(ab[0, 0], ab[0, 1], ab[1, 0], ab[1, 1]) return s
def eval_params(self, ulist, vlist, rtype='Point', domain='local'): """ Evaluate the surface at multiple parameters. :param array_like ulist: Parameters in u-direction. :param array_like vlist: Parameters in v-direction. :param str rtype: Option to return a NumPy array or Point instance (rtype = 'ndarray' or 'Point'). :param str domain: Option to use local (0 <= u, v <= 1) or global (a <= u, v <= b) domain ('local', 'l', 'global', 'g'). :return: Points on surface. :rtype: List :class:`.Point` instances or ndarray """ if not is_array_like(ulist) or not is_array_like(vlist): return self.eval(ulist, vlist, rtype, domain) if not is_local_domain(domain): ulist = [self.global_to_local_param('u', ui) for ui in ulist] vlist = [self.global_to_local_param('v', vi) for vi in vlist] pnts = bezier_surface_points(self._n, self._m, self._cpw, ulist, vlist) if is_array_type(rtype): return pnts else: return [Point(pi) for pi in pnts]
def refine_knots(self, x, d, inplace=False, domain='local'): """ Refine the knot vector by inserting the elements of *x* in specified direction. :param array_like x: Knot vector to insert. :param str d: Direction to refine knots ('u' or 'v'). :param bool inplace: Option to return new surface or modify existing surface. :param str domain: Option to use local (0 <= u, v <= 1) or global (a <= u, v <= b) domain ('local', 'l', 'global', 'g'). :return: New surface after knot refinement. :rtype: :class:`.NurbsSurface` """ if is_local_domain(domain): x = self.local_to_global_param(d, *x) if isinstance(x, (tuple, list)): x = array(x, dtype=float64) elif isinstance(x, (int, float)): x = array([x], dtype=float64) uk, vk, cpw = refine_knot_vect_surface(self._n, self._p, self._uk, self._m, self._q, self._vk, self._cpw, x, d) if inplace: self.set_cpw(cpw) self.set_knots(uk, vk) return True else: s = NurbsSurface() s.set_cpw(cpw) s.set_knots(uk, vk) return s
def move_seam(self, uv, d, inplace=False, domain='local'): """ Move the seam of a closed surface to a new parameter value. :param float uv: New seam parameter. :param str d: Direction for seam movement (surface must be closed in that direction). :param bool inplace: Option to return new surface or modify inpalce. :param str domain: Option to use local (0 <= u, v <= 1) or global (a <= u, v <= b) domain ('local', 'l', 'global', 'g'). :return: New surface or *True* if successful. :rtype: :class:`.NurbsSurface` or bool """ if not self.is_closed(d): return False if is_local_domain(domain): uv = self.local_to_global_param(d, uv) uq, vq, qw = move_nurbs_surface_seam(self._n, self._p, self._uk, self._m, self._q, self._vk, self._cpw, uv, d) if inplace: return self.set_cpw(qw) and self.set_knots(uq, vq) s = NurbsSurface() s.set_cpw(qw) s.set_knots(uq, vq) s.set_deg(self._p, self._q) return s
def extract(self, u0=0., u1=1., v0=0., v1=1., domain='local'): """ Extract NURBS surface bounded by parameters. :param float u0: Starting parameter in u-direction. :param float u1: Ending parameter in u-direction. :param float v0: Starting parameter in v-direction. :param float v1: Ending parameter in v-direction. :param str domain: Option to use local (0 <= u, v <= 1) or global (a <= u, v <= b) domain ('local', 'l', 'global', 'g'). :return: Extracted NURBS surface. :rtype: :class:`.NurbsSurface` """ if is_local_domain(domain): u0 = self.local_to_global_param('u', u0) u1 = self.local_to_global_param('u', u1) v0 = self.local_to_global_param('v', v0) v1 = self.local_to_global_param('v', v1) _, _, uq, vq, qw = extract_nurbs_surface(self._n, self._p, self._uk, self._m, self._q, self._vk, self._cpw, u0, u1, v0, v1) s = NurbsSurface() s.set_cpw(qw) s.set_knots(uq, vq) return s
def insert_knot(self, uv, d, r=1, inplace=False, domain='local'): """ Insert knot in direction. :param float uv: Knot value to insert. :param str d: Direction to insert knot ('u1 or 'v'). :param int r: Number of times to insert knot. :param bool inplace: Option to return new surface or modify existing surface. :param str domain: Option to use local (0 <= u, v <= 1) or global (a <= u, v <= b) domain ('local', 'l', 'global', 'g'). :return: New surface after knot insertion. :rtype: :class:`.NurbsSurface` """ if is_local_domain(domain): uv = self.local_to_global_param(d, uv) uk, vk, cpw = surface_knot_ins(self._n, self._p, self._uk, self._m, self._q, self._vk, self._cpw, d, uv, r) if inplace: self.set_cpw(cpw) self.set_knots(uk, vk) return True else: s = NurbsSurface() s.set_cpw(cpw) s.set_knots(uk, vk) return s
def insert_knot(self, u, r=1, inplace=False, domain='local'): """ Insert knot. :param float u: Knot value to insert. :param int r: Number of times to insert knot (r + s <= p, where *s* is knot multiplicity). :param bool inplace: Option to return a new curve or modify the curve in place. :param str domain: Option to use local (0 <= u <= 1) or global (a <= u <= b) domain ('local', 'l', 'global', 'g'). :return: New curve after knot insertion. :rtype: :class:`.NurbsCurve` """ if is_local_domain(domain): u = self.local_to_global_param(u) uk, cpw = curve_knot_ins(self._n, self._p, self._uk, self._cpw, u, r) if inplace: self.set_cpw(cpw) self.set_knots(uk) return True else: c = NurbsCurve() c.set_cpw(cpw) c.set_knots(uk) c.set_deg(self._p) return c
def deriv(self, u, k, d=None, rtype='Vector', domain='local'): """ Compute the *k* -th derivative at point *u*. :param float u: Parametric point. :param int k: Derivative to return (0 <= k <= d). :param int d: Highest derivative to compute. If *d* = *None*, then only the *k* th derivative will be computed. :param str rtype: Option to return a NumPy array or a Vector instance (rtype = 'Vector' or 'ndarray'). :param str domain: Option to use local (0 <= u <= 1) or global (a <= u <= b) domain ('local', 'l', 'global', 'g'). :return: Curve *k* -th derivative. :rtype: :class:`.Vector` or ndarray """ if self._cp is None: return None if d is None: d = k if is_local_domain(domain): u = self.local_to_global_param(u) der = rat_curve_derivs(self._n, self._p, self._uk, self._cpw, u, d) if is_array_type(rtype): return der[k] else: p0 = Point(der[0]) return Vector(der[k], p0)
def eval(self, u, v, rtype='Point', domain='local'): """ Evaluate surface at parametric points. :param float u: Parametric point in u-direction. :param float v: Parametric point in v-direction. :param str rtype: Option to return a NumPy array or Point instance (rtype = 'ndarray' or 'Point'). :param str domain: Option to use local (0 <= u, v <= 1) or global (a <= u, v <= b) domain ('local', 'l', 'global', 'g'). :return: Point on surface. :rtype: :class:`.Point` or ndarray """ if is_array_like(u) and is_array_like(v): return self.eval_params(u, v, rtype, domain) if is_local_domain(domain): u = self.local_to_global_param('u', u) v = self.local_to_global_param('v', v) pnt = surface_point(self._n, self._p, self._uk, self._m, self._q, self._vk, self._cpw, u, v) if is_array_type(rtype): return pnt else: return Point(pnt)
def refine_knots(self, x, inplace=False, domain='local'): """ Refine the knot vector by inserting the elements of *x*. :param array_like x: Knot vector to insert. :param bool inplace: Option to return new curve or modify existing curve. :param str domain: Option to use local (0 <= u <= 1) or global (a <= u <= b) domain ('local', 'l', 'global', 'g'). :return: New curve after knot refinement. :rtype: :class:`.NurbsCurve` """ if is_local_domain(domain): x = self.local_to_global_param(*x) if isinstance(x, (tuple, list, ndarray)): x = array(x, dtype=float64) elif isinstance(x, (int, float)): x = array([x], dtype=float64) uq, qw = refine_knot_vect_curve(self._n, self._p, self._uk, self._cpw, x) if inplace: self.set_cpw(qw) self.set_knots(uq) return True else: c = NurbsCurve() c.set_cpw(qw) c.set_knots(uq) c.set_deg(self._p) return c
def deriv(self, u, v, k, l, rtype='Vector', domain='local'): """ Compute the surface derivative. :param float u: Parametric point. :param float v: Parametric point. :param int k: Derivative to return in u-direction (0 <= k <= d). :param int l: Derivative to return in v-direction (0 <= l <= d). :param str rtype: Option to return a NumPy array or a Vector instance (rtype = 'Vector' or 'ndarray'). :param str domain: Option to use local (0 <= u, v <= 1) or global (a <= u, v <= b) domain ('local', 'l', 'global', 'g'). :return: Surface derivative. :rtype: :class:`.Vector` or ndarray """ if self._cp is None: return None # Use NURBS rational curve derivative to compute Bezier derivative. # Convert to global since using a NURBS method. if is_local_domain(domain): u = self.local_to_global_param('u', u) v = self.local_to_global_param('v', v) d = k + l der = rat_surface_derivs(self._n, self._p, self._uk, self._m, self._q, self._vk, self._cpw, u, v, d) if is_array_type(rtype): return der[k, l] else: p0 = Point(der[0, 0]) return Vector(der[k, l], p0)
def reverse_param(self, u, domain='local'): """ Reverse the parameter. :param float u: Original parameter. :param str domain: Option to use local (0 <= u <= 1) or global (a <= u <= b) domain ('local', 'l', 'global', 'g'). :return: Reversed parameter. :rtype: float """ if is_local_domain(domain): u = self.local_to_global_param(u) u = -u + self._a + self._b if not is_local_domain(domain): return u return self.global_to_local_param(u)
def eval2d(self, u, rtype='Point', domain='local', tol=None, sref=None): """ Evaluate the intersection curve in 2-D space for each surface. :param float u: Parametric point. :param str rtype: Option to return a NumPy array or Point2D instance (rtype = 'Point' or 'ndarray'). :param str domain: Option to use local (0 <= u <= 1) or global (a <= u <= b) domain ('local', 'l', 'global', 'g'). :param float tol: Tolerance for point refinement. :param surface_like sref: Option to provide one of the two surfaces used in the intersection curve. If present, the method will only return the 2-D parameters associated to that surface. :return: Point on curve. Will return *None* if *sref* is not in the intersection. :rtype: :class:`.Point2D` or ndarray """ if is_local_domain(domain): u = self.local_to_global_param(u) # Evaluate 2-D curves. s1, s2 = self._s1, self._s2 u1, v1 = self._crv2d_s1.eval(u, rtype='ndarray', domain='global')[:-1] u2, v2 = self._crv2d_s2.eval(u, rtype='ndarray', domain='global')[:-1] # Project 3-D point to surfaces to get initial parameters. # s1, s2 = self._s1, self._s2 # p3d = self._crv3d.eval(u, domain='global') # u1, v1 = invert_point_on_surface(p3d, s1) # if self.is_spi: # u2, v2 = invert_point_on_plane(p3d, s2) # else: # u2, v2 = invert_point_on_surface(p3d, s2) # Refine parameters. if tol is None: tol = Settings.gtol / 100. if self.is_spi: u1, v1, u2, v2 = refine_spi_point(s1, s2, u1, v1, tol)[:-1] else: u1, v1, u2, v2 = refine_ssi_point(s1, s2, u1, v1, u2, v2, tol)[:-1] if is_array_type(rtype): if sref is s1: return array([u1, v1], dtype=float64) if sref is s2: return array([u2, v2], dtype=float64) return (array([u1, v1], dtype=float64), array([u2, v2], dtype=float64)) else: if sref is s1: return Point2D((u1, v1)) if sref is s2: return Point2D((u2, v2)) return Point2D((u1, v1)), Point2D((u2, v2))
def arc_length(self, u0=0., u1=1., domain='local'): """ Estimate the arc length between curve parameters. :param float u0: Starting parameter. :param float u1: Ending parameter. :param str domain: Option to use local or global domain. :return: Arc length of curve between *u0* and *u1*. :rtype: float """ if is_local_domain(domain): u0, u1 = self.local_to_global_param(u0, u1) return arc_length_nurbs(self.n, self.p, self.uk, self.cpw, u0, u1, self.a, self.b)
def extract(self, u0=0., u1=1., domain='local'): """ Extract a curve. :param float u0: Starting parameter. :param float u1: Ending parameter. :param str domain: Option to use local (0 <= u <= 1) or global (a <= u <= b) domain ('local', 'l', 'global', 'g'). :return: Curve between *u0* and *u1*. :rtype: :class:`.BezierCurve` """ if not is_local_domain(domain): u0, u1 = self.global_to_local_param(u0, u1) qw, a, b = extract_bezier_curve(self._cpw, self._n, u0, u1, self._u0, self._u1) c = BezierCurve() c.set_cpw(qw) c.set_domain(a, b) return c
def points_at_kinks(curve, angle=30., u0=0., u1=1., domain='local'): """ Create points at kinks of a curve. """ if is_local_domain(domain): u0, u1 = curve.local_to_global_param(u0, u1) # Get knots and multiplicities. nu, um, uq = curve.get_mult_and_knots() kinks = [] # If p > 1, create a point wherever the knot multiplicity equals the # degree, excluding the endpoints. if curve.p > 1: for mult, ui in zip(um, uq)[1:-1]: if ui <= u0 or ui >= u1: continue if mult == curve.p: pi = curve.eval(ui, domain='global') kinks.append((ui, pi)) return kinks # If p = 1, then use the angle criteria and the control points. angle_tol = abs(angle) n, cp = curve.n, curve.cp for i in range(1, n): ui = uq[i] if ui <= u0 or ui >= u1: continue # Get previous, current, and next points. p0 = cp[i - 1] pi = cp[i] p1 = cp[i + 1] # Calculate angle. v1 = pi - p0 v2 = p1 - pi angle = angle_between_vecs(v1, v2) if angle > angle_tol: pi = curve.eval(ui, domain='global') kinks.append((ui, pi)) return kinks
def extract(self, u0, u1, domain='local'): """ Extract a curve. :param float u0: Starting parameter. :param float u1: Ending parameter. :param str domain: Option to use local (0 <= u <= 1) or global (a <= u <= b) domain ('local', 'l', 'global', 'g'). :return: Curve between *u0* and *u1*. :rtype: :class:`.NurbsCurve` """ if is_local_domain(domain): u0, u1 = self.local_to_global_param(u0, u1) uq, qw = extract_nurbs_curve(self._n, self._p, self._uk, self._cpw, u0, u1) c = NurbsCurve() c.set_cpw(qw) c.set_knots(uq) c.set_deg(self._p) return c
def split(self, u=0.5, domain='local'): """ Split the curve. :param float u: Parametric point to split curve at. :param str domain: Option to use local (0 <= u <= 1) or global (a <= u <= b) domain ('local', 'l', 'global', 'g'). :return: Two new Bezier curves *(c1, c2)*. :rtype: tuple """ if not is_local_domain(domain): u = self.global_to_local_param(u) qw1, a1, b1, qw2, a2, b2 = split_bezier_curve(self._cpw, self._n, u, self._u0, self._u1) c1, c2 = BezierCurve(), BezierCurve() c1.set_cpw(qw1) c2.set_cpw(qw2) c1.set_domain(a1, b1) c2.set_domain(a2, b2) return c1, c2
def isocurve(self, u=None, v=None, domain='local'): """ Extract iso-curve from NURBS surface. :param float u: Parameter *u* to extract curve at (in v-direction). :param float v: Parameter *v* to extract curve at (in u-direction). :param str domain: Option to use local (0 <= u, v <= 1) or global (a <= u, v <= b) domain ('local', 'l', 'global', 'g'). :return: NURBS curve along parameter. :rtype: :class:`.NurbsCurve` """ if is_local_domain(domain): u = self.local_to_global_param('u', u) v = self.local_to_global_param('v', v) uq, qw = extract_nurbs_isocurve(self._n, self._p, self._uk, self._m, self._q, self._vk, self._cpw, u, v) c = NurbsCurve() c.set_cpw(qw) c.set_knots(uq) return c
def eval(self, u, rtype='Point', domain='local', tol=None): """ Evaluate curve at parametric point. :param float u: Parametric point. :param str rtype: Option to return a NumPy array or Point instance (rtype = 'Point' or 'ndarray'). :param str domain: Option to use local (0 <= u <= 1) or global (a <= u <= b) domain ('local', 'l', 'global', 'g'). :param float tol: Tolerance for point refinement. :return: Point on curve. :rtype: :class:`.Point` or ndarray """ if is_local_domain(domain): u = self.local_to_global_param(u) uv1, uv2 = self.eval2d(u, rtype='ndarray', domain='global', tol=tol) p3d = self._s1.eval(uv1[0], uv1[1], rtype='ndarray', domain='global') if is_array_type(rtype): return p3d else: return Point(p3d)
def split(self, u=0.5, domain='local'): """ Split the curve into two segments at *u*. :param float u: Parametric point to split curve at. :param str domain: Option to use local (0 <= u <= 1) or global (a <= u <= b) domain ('local', 'l', 'global', 'g'). :return: Two new NURBS curves *(c1, c2)*. :rtype: tuple """ if is_local_domain(domain): u = self.local_to_global_param(u) uk1, qw1, uk2, qw2 = split_nurbs_curve(self._n, self._p, self._uk, self._cpw, u) c1, c2 = NurbsCurve(), NurbsCurve() c1.set_cpw(qw1) c1.set_knots(uk1) c1.set_deg(self._p) c2.set_cpw(qw2) c2.set_knots(uk2) c2.set_deg(self._p) return c1, c2
def eval_params(self, ulist, rtype='Point', domain='local'): """ Evaluate the curve at multiple parameters. :param array_like ulist: Curve parameters. :param str rtype: Option to return a NumPy array or list of Point instances (rtype = 'Point' or 'ndarray'). :param str domain: Option to use local (0 <= u <= 1) or global (a <= u <= b) domain ('local', 'l', 'global', 'g'). :return: Points at parameters. :rtype: List of :class:`.Point` instances or NumPy array """ if not is_array_like(ulist): return self.eval(ulist, rtype, domain) if is_local_domain(domain): ulist = map(self.global_to_local_param, ulist) pnts = curve_points(self._n, self._p, self._uk, self._cpw, ulist) if is_array_type(rtype): return pnts else: return [Point(pi) for pi in pnts]
def eval(self, u, rtype='Point', domain='local'): """ Evaluate curve at parametric point. :param float u: Parametric point. :param str rtype: Option to return a NumPy array or Point instance (rtype = 'Point' or 'ndarray'). :param str domain: Option to use local (0 <= u <= 1) or global (a <= u <= b) domain ('local', 'l', 'global', 'g'). :return: Point on curve. :rtype: :class:`.Point` or ndarray """ if is_array_like(u): return self.eval_params(u, rtype, domain) if is_local_domain(domain): u = self.local_to_global_param(u) pnt = curve_point(self._n, self._p, self._uk, self._cpw, u) if is_array_type(rtype): return pnt else: return Point(pnt)
def eval(self, u, v, rtype='Point', domain='local'): """ Evaluate surface at parametric points. :param float u: Parametric point in u-direction. :param float v: Parametric point in v-direction. :param str rtype: Option to return a NumPy array or Point instance (rtype = 'Point' or 'ndarray'). :param str domain: Option to use local (0 <= u, v <= 1) or global (a <= u, v <= b) domain ('local', 'l', 'global', 'g'). :return: Point on surface. :rtype: :class:`.Point` or ndarray """ if not is_local_domain(domain): u = self.global_to_local_param('u', u) v = self.global_to_local_param('v', v) pw = deCasteljau2(self._cpw, self._n, self._m, u, v) pnt = pw[:-1] / pw[-1] if is_array_type(rtype): return pnt else: return Point(pnt)
def isocurve(self, u=None, v=None, domain='local'): """ Extract iso-curve from Bezier surface. :param float u: Parameter *u* to extract curve at (in v-direction). :param float v: Parameter *v* to extract curve at (in u-direction). :param str domain: Option to use local (0 <= u, v <= 1) or global (a <= u, v <= b) domain ('local', 'l', 'global', 'g'). :return: Bezier curve along parameter. :rtype: :class:`.BezierCurve` """ if not is_local_domain(domain): u = self.global_to_local_param('u', u) v = self.global_to_local_param('v', v) qw = extract_bezier_isocurve(self._n, self._m, self._cpw, u, v) c = BezierCurve() c.set_cpw(qw) if u is not None: c.set_domain(self._v0, self._v1) if v is not None: c.set_domain(self._u0, self._u1) return c
def deriv(self, u, k=1, d=1, rtype='Vector', domain='local', tol=None): """ Compute the derivative of the intersection curve. Only supports first derivates. :param float u: Parametric point. :param int k: Derivative to return (0 <= k <= 1). :param int d: Highest derivative to compute. Currently only supports first derivative. :param str rtype: Option to return a NumPy array or a Vector instance (rtype = 'Vector' or 'ndarray'). :param str domain: Option to use local (0 <= u <= 1) or global (a <= u <= b) domain ('local', 'l', 'global', 'g'). :param float tol: Tolerance for point refinement. :return: First derivative or intersection curve. :rtype: :class:`.Vector` or ndarray """ if is_local_domain(domain): u = self.local_to_global_param(u) # Evaluate 2-D points. s1, s2 = self._s1, self._s2 uv1, uv2 = self.eval2d(u, rtype='ndarray', domain='global', tol=tol) # Evaluate surface normals. vn1 = s1.norm(uv1[0], uv1[1], rtype='ndarray', domain='global') if self.is_spi: vn2 = s2.vn.ijk else: vn2 = s2.norm(uv2[0], uv2[1], rtype='ndarray', domain='global') # First derivative is cross product du = cross(vn1, vn2) if is_array_type(rtype): return du else: p0 = self.eval(u, domain='global') return Vector(du, p0)
def extract(self, u0, u1, domain='local'): """ Extract a curve. :param float u0: Starting parameter. :param float u1: Ending parameter. :param str domain: Option to use local (0 <= u <= 1) or global (a <= u <= b) domain ('local', 'l', 'global', 'g'). :return: Curve between *u0* and *u1*. :rtype: :class:`.ICurve` """ if is_local_domain(domain): u0, u1 = self.local_to_global_param(u0, u1) if u0 > u1: u0, u1 = u1, u0 # Evaluate points on intersection curve. p3d_0 = self.eval(u0, rtype='ndarray', domain='global') p3d_1 = self.eval(u1, rtype='ndarray', domain='global') uv0_s1_0, uv0_s2_0 = self.eval2d(u0, rtype='ndarray', domain='global') uv0_s1_1, uv0_s2_1 = self.eval2d(u1, rtype='ndarray', domain='global') # Extract curves crv3d = self._crv3d.extract(u0, u1, domain='global') crv2d_s1 = self._crv2d_s1.extract(u0, u1, domain='global') crv2d_s2 = self._crv2d_s2.extract(u0, u1, domain='global') # Force endpoints of curves to match original points by adjusting # first and last control points. crv3d.modify_cp(0, p3d_0) crv3d.modify_cp(-1, p3d_1) crv2d_s1.modify_cp(0, uv0_s1_0) crv2d_s1.modify_cp(-1, uv0_s1_1) crv2d_s2.modify_cp(0, uv0_s2_0) crv2d_s2.modify_cp(-1, uv0_s2_1) return ICurve(self._s1, self._s2, crv3d, crv2d_s1, crv2d_s2, self._ftol)
def split(self, u=None, v=None, domain='local'): """ Split Bezier surface. :param float u: Location of split (in v-direction). :param float v: Location of split (in u-direction). :param str domain: Option to use local (0 <= u, v <= 1) or global (a <= u, v <= b) domain ('local', 'l', 'global', 'g'). :return: Tuple of Bezier surfaces after splitting. :rtype: tuple .. note:: If only one parameter is provided, then two surfaces are created and the length of the tuple is two (s1, s2). If both parameters are provided, four surfaces are created and the length of tuple is four (s1, s2, s3, s4). """ if not is_local_domain(domain): u = self.global_to_local_param('u', u) v = self.global_to_local_param('v', v) if u is None or v is None: # Split in one direction only. qw1, qw2, ab1, ab2 = split_bezier_surface(self._cpw, self._n, self._m, u, v, self._u0, self._u1, self._v0, self._v1) s1, s2 = BezierSurface(), BezierSurface() s1.set_cpw(qw1) s2.set_cpw(qw2) s1.set_domain(ab1[0, 0], ab1[0, 1], ab1[1, 0], ab1[1, 1]) s2.set_domain(ab2[0, 0], ab2[0, 1], ab2[1, 0], ab2[1, 1]) return s1, s2 elif u is not None and v is not None: # Split in both directions, starting at u (in v-direction). qw1, qw2, ab1, ab2 = split_bezier_surface(self._cpw, self._n, self._m, u, None, self._u0, self._u1, self._v0, self._v1) # Split first surface at v (in u-direction). qw3, qw4, ab3, ab4 = split_bezier_surface(qw1, self._n, self._m, None, v, ab1[0, 0], ab1[0, 1], ab1[1, 0], ab1[1, 1]) # Split second surface at v (in u-direction). qw5, qw6, ab5, ab6 = split_bezier_surface(qw2, self._n, self._m, None, v, ab2[0, 0], ab2[0, 1], ab2[1, 0], ab2[1, 1]) # Create surfaces s3, s4, s5, s6 = (BezierSurface(), BezierSurface(), BezierSurface(), BezierSurface()) s3.set_cpw(qw3) s4.set_cpw(qw4) s5.set_cpw(qw5) s6.set_cpw(qw6) s3.set_domain(ab3[0, 0], ab3[0, 1], ab3[1, 0], ab3[1, 1]) s4.set_domain(ab4[0, 0], ab4[0, 1], ab4[1, 0], ab4[1, 1]) s5.set_domain(ab5[0, 0], ab5[0, 1], ab5[1, 0], ab5[1, 1]) s6.set_domain(ab6[0, 0], ab6[0, 1], ab6[1, 0], ab6[1, 1]) return s3, s4, s5, s6
def split(self, u=None, v=None, domain='local'): """ Split NURBS surface. :param float u: Location of split (in v-direction). :param float v: Location of split (in u-direction). :param str domain: Option to use local (0 <= u, v <= 1) or global (a <= u, v <= b) domain ('local', 'l', 'global', 'g'). :return: Tuple of NURBS surfaces after splitting. :rtype: tuple .. note:: If only one parameter is provided, then two surfaces are created and the length of the tuple is two (s1, s2). If both parameters are provided, four surfaces are created and the length of tuple is four (s1, s2, s3, s4). """ if is_local_domain(domain): u = self.local_to_global_param('u', u) v = self.local_to_global_param('v', v) if u is None or v is None: # Split in one direction only. uk1, vk1, qw1, uk2, vk2, qw2 = split_nurbs_surface(self._n, self._p, self._uk, self._m, self._q, self._vk, self._cpw, u, v) s1, s2 = NurbsSurface(), NurbsSurface() s1.set_cpw(qw1) s1.set_knots(uk1, vk1) s2.set_cpw(qw2) s2.set_knots(uk2, vk2) return s1, s2 elif u is not None and v is not None: # Split in both directions, starting at u (in v-direction). uk1, vk1, qw1, uk2, vk2, qw2 = split_nurbs_surface(self._n, self._p, self._uk, self._m, self._q, self._vk, self._cpw, u, None) # Split first surface at v (in u-direction). nm1, nm2 = qw1.shape[:-1], qw2.shape[:-1] n1, m1 = nm1[0] - 1, nm1[1] - 1 uk3, vk3, qw3, uk4, vk4, qw4 = split_nurbs_surface(n1, self._p, uk1, m1, self._q, vk1, qw1, None, v) # Split second surface at v (in u-direction). n2, m2 = nm2[0] - 1, nm2[1] - 1 uk5, vk5, qw5, uk6, vk6, qw6 = split_nurbs_surface(n2, self._p, uk2, m2, self._q, vk2, qw2, None, v) # Create surfaces. s3, s4, s5, s6 = (NurbsSurface(), NurbsSurface(), NurbsSurface(), NurbsSurface()) s3.set_cpw(qw3) s3.set_knots(uk3, vk3) s4.set_cpw(qw4) s4.set_knots(uk4, vk4) s5.set_cpw(qw5) s5.set_knots(uk5, vk5) s6.set_cpw(qw6) s6.set_knots(uk6, vk6) return s3, s4, s5, s6