Module sverchok.utils.curve.biarc

Expand source code
# This file is part of project Sverchok. It's copyrighted by the contributors
# recorded in the version control history of the file, available from
# its original location https://github.com/nortikin/sverchok/commit/master
#
# SPDX-License-Identifier: GPL3
# License-Filename: LICENSE

import numpy as np
from math import sin, cos, acos
from cmath import exp as cexp, phase as arg

from mathutils import Vector, Matrix

from sverchok.utils.curve.core import SvCurve
from sverchok.utils.curve.primitives import SvCircle
from sverchok.utils.curve.algorithms import SvConcatCurve, concatenate_curves

class SvBiArc(SvConcatCurve):
    def __init__(self, arc1, arc2):
        super().__init__([arc1, arc2])
        self.arc1 = arc1
        self.arc2 = arc2

    def __repr__(self):
        return f"<BiArc C1={self.arc1.center} R1={self.arc1.radius} C2={self.arc2.center} R2={self.arc2.radius}>"

    @staticmethod
    def calc(point_a, point_b, tangent_a, tangent_b, p, planar_tolerance=1e-6):
        xx = point_b - point_a
        xx /= np.linalg.norm(xx)
        tangent_normal = np.cross(tangent_a, tangent_b)
        volume = np.dot(xx, tangent_normal)
        if abs(volume) > planar_tolerance:
            raise Exception(f"Provided tangents are not coplanar, volume={volume}")

        zz_a = np.cross(tangent_a, xx)
        zz_b = np.cross(tangent_b, xx)
        zz = (zz_a + zz_b)
        zz /= np.linalg.norm(zz)
        yy = np.cross(zz, xx)

        c = np.linalg.norm(point_b - point_a) * 0.5
        
        tangent_a /= np.linalg.norm(tangent_a)
        tangent_b /= np.linalg.norm(tangent_b)

        to_center_a = np.cross(zz, tangent_a)
        to_center_b = - np.cross(zz, tangent_b)

        matrix_inv = np.stack((xx, yy, zz))
        matrix = np.linalg.inv(matrix_inv)

        # TODO: sin(arccos(...)) = ...
        alpha = acos(np.dot(tangent_a, xx))
        beta = acos(np.dot(tangent_b, xx))
        if np.dot(tangent_a, yy) > 0:
            alpha = - alpha
        if np.dot(tangent_b, yy) > 0:
            beta = - beta
        #print("A", alpha, "B", beta)

        omega = (alpha + beta) * 0.5
        r1 = c/(sin(alpha) + sin(omega) / p)
        r2 = c/(sin(beta) + p * sin(omega))
        #print("R1", r1, "R2", r2)
        theta1 = 2 * arg(cexp(-1j * alpha) + cexp(-1j*omega)/p)
        theta2 = 2 * arg(cexp(1j*beta) + p*cexp(1j*omega))
        #print("T1", theta1, "T2", theta2)

        vectorx_a = r1 * to_center_a
        center1 = point_a + vectorx_a
        center2 = point_b + r2 * to_center_b

        arc1 = SvCircle(#radius = r1,
                    center = center1,
                    normal = -zz, vectorx = point_a - center1)
        if theta1 > 0:
            arc1.u_bounds = (0.0, theta1)
        else:
            theta1 = -theta1
            arc1.u_bounds = (0.0, theta1)
            arc1.set_normal(-arc1.normal)

        junction = arc1.evaluate(theta1)
        #print("J", junction)

        arc2 = SvCircle(#radius = r2,
                    center = center2,
                    normal = -zz, vectorx = junction - center2)
        if theta2 > 0:
            arc2.u_bounds = (0.0, theta2)
        else:
            theta2 = -theta2
            arc2.u_bounds = (0.0, theta2)
            arc2.set_normal(-arc2.normal)

        curve = SvBiArc(arc1, arc2)
        curve.p = p
        curve.junction = junction

        return curve

    def to_nurbs(self, implementation=None):
        return concatenate_curves([self.arc1.to_nurbs(), self.arc2.to_nurbs()], allow_generic=False)

    def make_revolution_surface(self, point, direction, v_min, v_max, global_origin):
        return self.to_nurbs().make_revolution_surface(point, direction, v_min, v_max, global_origin)
    
    def extrude_along_vector(self, vector):
        return self.to_nurbs().extrude_along_vector(vector)

    def make_ruled_surface(self, curve2, vmin, vmax):
        return self.to_nurbs().make_ruled_surface(curve2, vmin, vmax)

    def extrude_to_point(self, point):
        return self.to_nurbs().extrude_to_point(point)

    def lerp_to(self, curve2, coefficient):
        if isinstance(curve2, SvBezierCurve) and curve2.degree == self.degree:
            points = (1.0 - coefficient) * self.points + coefficient * curve2.points
            return SvBezierCurve(points)
        return self.to_nurbs().lerp_to(curve2, coefficient)
    
    def split_at(self, t):
        return self.to_nurbs().split_at(t)

    def cut_segment(self, new_t_min, new_t_max, rescale=False):
        return self.to_nurbs().cut_segment(new_t_min, new_t_max, rescale=rescale)

Classes

class SvBiArc (arc1, arc2)
Expand source code
class SvBiArc(SvConcatCurve):
    def __init__(self, arc1, arc2):
        super().__init__([arc1, arc2])
        self.arc1 = arc1
        self.arc2 = arc2

    def __repr__(self):
        return f"<BiArc C1={self.arc1.center} R1={self.arc1.radius} C2={self.arc2.center} R2={self.arc2.radius}>"

    @staticmethod
    def calc(point_a, point_b, tangent_a, tangent_b, p, planar_tolerance=1e-6):
        xx = point_b - point_a
        xx /= np.linalg.norm(xx)
        tangent_normal = np.cross(tangent_a, tangent_b)
        volume = np.dot(xx, tangent_normal)
        if abs(volume) > planar_tolerance:
            raise Exception(f"Provided tangents are not coplanar, volume={volume}")

        zz_a = np.cross(tangent_a, xx)
        zz_b = np.cross(tangent_b, xx)
        zz = (zz_a + zz_b)
        zz /= np.linalg.norm(zz)
        yy = np.cross(zz, xx)

        c = np.linalg.norm(point_b - point_a) * 0.5
        
        tangent_a /= np.linalg.norm(tangent_a)
        tangent_b /= np.linalg.norm(tangent_b)

        to_center_a = np.cross(zz, tangent_a)
        to_center_b = - np.cross(zz, tangent_b)

        matrix_inv = np.stack((xx, yy, zz))
        matrix = np.linalg.inv(matrix_inv)

        # TODO: sin(arccos(...)) = ...
        alpha = acos(np.dot(tangent_a, xx))
        beta = acos(np.dot(tangent_b, xx))
        if np.dot(tangent_a, yy) > 0:
            alpha = - alpha
        if np.dot(tangent_b, yy) > 0:
            beta = - beta
        #print("A", alpha, "B", beta)

        omega = (alpha + beta) * 0.5
        r1 = c/(sin(alpha) + sin(omega) / p)
        r2 = c/(sin(beta) + p * sin(omega))
        #print("R1", r1, "R2", r2)
        theta1 = 2 * arg(cexp(-1j * alpha) + cexp(-1j*omega)/p)
        theta2 = 2 * arg(cexp(1j*beta) + p*cexp(1j*omega))
        #print("T1", theta1, "T2", theta2)

        vectorx_a = r1 * to_center_a
        center1 = point_a + vectorx_a
        center2 = point_b + r2 * to_center_b

        arc1 = SvCircle(#radius = r1,
                    center = center1,
                    normal = -zz, vectorx = point_a - center1)
        if theta1 > 0:
            arc1.u_bounds = (0.0, theta1)
        else:
            theta1 = -theta1
            arc1.u_bounds = (0.0, theta1)
            arc1.set_normal(-arc1.normal)

        junction = arc1.evaluate(theta1)
        #print("J", junction)

        arc2 = SvCircle(#radius = r2,
                    center = center2,
                    normal = -zz, vectorx = junction - center2)
        if theta2 > 0:
            arc2.u_bounds = (0.0, theta2)
        else:
            theta2 = -theta2
            arc2.u_bounds = (0.0, theta2)
            arc2.set_normal(-arc2.normal)

        curve = SvBiArc(arc1, arc2)
        curve.p = p
        curve.junction = junction

        return curve

    def to_nurbs(self, implementation=None):
        return concatenate_curves([self.arc1.to_nurbs(), self.arc2.to_nurbs()], allow_generic=False)

    def make_revolution_surface(self, point, direction, v_min, v_max, global_origin):
        return self.to_nurbs().make_revolution_surface(point, direction, v_min, v_max, global_origin)
    
    def extrude_along_vector(self, vector):
        return self.to_nurbs().extrude_along_vector(vector)

    def make_ruled_surface(self, curve2, vmin, vmax):
        return self.to_nurbs().make_ruled_surface(curve2, vmin, vmax)

    def extrude_to_point(self, point):
        return self.to_nurbs().extrude_to_point(point)

    def lerp_to(self, curve2, coefficient):
        if isinstance(curve2, SvBezierCurve) and curve2.degree == self.degree:
            points = (1.0 - coefficient) * self.points + coefficient * curve2.points
            return SvBezierCurve(points)
        return self.to_nurbs().lerp_to(curve2, coefficient)
    
    def split_at(self, t):
        return self.to_nurbs().split_at(t)

    def cut_segment(self, new_t_min, new_t_max, rescale=False):
        return self.to_nurbs().cut_segment(new_t_min, new_t_max, rescale=rescale)

Ancestors

Static methods

def calc(point_a, point_b, tangent_a, tangent_b, p, planar_tolerance=1e-06)
Expand source code
@staticmethod
def calc(point_a, point_b, tangent_a, tangent_b, p, planar_tolerance=1e-6):
    xx = point_b - point_a
    xx /= np.linalg.norm(xx)
    tangent_normal = np.cross(tangent_a, tangent_b)
    volume = np.dot(xx, tangent_normal)
    if abs(volume) > planar_tolerance:
        raise Exception(f"Provided tangents are not coplanar, volume={volume}")

    zz_a = np.cross(tangent_a, xx)
    zz_b = np.cross(tangent_b, xx)
    zz = (zz_a + zz_b)
    zz /= np.linalg.norm(zz)
    yy = np.cross(zz, xx)

    c = np.linalg.norm(point_b - point_a) * 0.5
    
    tangent_a /= np.linalg.norm(tangent_a)
    tangent_b /= np.linalg.norm(tangent_b)

    to_center_a = np.cross(zz, tangent_a)
    to_center_b = - np.cross(zz, tangent_b)

    matrix_inv = np.stack((xx, yy, zz))
    matrix = np.linalg.inv(matrix_inv)

    # TODO: sin(arccos(...)) = ...
    alpha = acos(np.dot(tangent_a, xx))
    beta = acos(np.dot(tangent_b, xx))
    if np.dot(tangent_a, yy) > 0:
        alpha = - alpha
    if np.dot(tangent_b, yy) > 0:
        beta = - beta
    #print("A", alpha, "B", beta)

    omega = (alpha + beta) * 0.5
    r1 = c/(sin(alpha) + sin(omega) / p)
    r2 = c/(sin(beta) + p * sin(omega))
    #print("R1", r1, "R2", r2)
    theta1 = 2 * arg(cexp(-1j * alpha) + cexp(-1j*omega)/p)
    theta2 = 2 * arg(cexp(1j*beta) + p*cexp(1j*omega))
    #print("T1", theta1, "T2", theta2)

    vectorx_a = r1 * to_center_a
    center1 = point_a + vectorx_a
    center2 = point_b + r2 * to_center_b

    arc1 = SvCircle(#radius = r1,
                center = center1,
                normal = -zz, vectorx = point_a - center1)
    if theta1 > 0:
        arc1.u_bounds = (0.0, theta1)
    else:
        theta1 = -theta1
        arc1.u_bounds = (0.0, theta1)
        arc1.set_normal(-arc1.normal)

    junction = arc1.evaluate(theta1)
    #print("J", junction)

    arc2 = SvCircle(#radius = r2,
                center = center2,
                normal = -zz, vectorx = junction - center2)
    if theta2 > 0:
        arc2.u_bounds = (0.0, theta2)
    else:
        theta2 = -theta2
        arc2.u_bounds = (0.0, theta2)
        arc2.set_normal(-arc2.normal)

    curve = SvBiArc(arc1, arc2)
    curve.p = p
    curve.junction = junction

    return curve

Methods

def cut_segment(self, new_t_min, new_t_max, rescale=False)
Expand source code
def cut_segment(self, new_t_min, new_t_max, rescale=False):
    return self.to_nurbs().cut_segment(new_t_min, new_t_max, rescale=rescale)
def extrude_along_vector(self, vector)
Expand source code
def extrude_along_vector(self, vector):
    return self.to_nurbs().extrude_along_vector(vector)
def extrude_to_point(self, point)
Expand source code
def extrude_to_point(self, point):
    return self.to_nurbs().extrude_to_point(point)
def lerp_to(self, curve2, coefficient)
Expand source code
def lerp_to(self, curve2, coefficient):
    if isinstance(curve2, SvBezierCurve) and curve2.degree == self.degree:
        points = (1.0 - coefficient) * self.points + coefficient * curve2.points
        return SvBezierCurve(points)
    return self.to_nurbs().lerp_to(curve2, coefficient)
def make_revolution_surface(self, point, direction, v_min, v_max, global_origin)
Expand source code
def make_revolution_surface(self, point, direction, v_min, v_max, global_origin):
    return self.to_nurbs().make_revolution_surface(point, direction, v_min, v_max, global_origin)
def make_ruled_surface(self, curve2, vmin, vmax)
Expand source code
def make_ruled_surface(self, curve2, vmin, vmax):
    return self.to_nurbs().make_ruled_surface(curve2, vmin, vmax)
def split_at(self, t)
Expand source code
def split_at(self, t):
    return self.to_nurbs().split_at(t)
def to_nurbs(self, implementation=None)
Expand source code
def to_nurbs(self, implementation=None):
    return concatenate_curves([self.arc1.to_nurbs(), self.arc2.to_nurbs()], allow_generic=False)

Inherited members