Skip to content
Snippets Groups Projects
geometry_utils.py 6.2 KiB
Newer Older
  • Learn to ignore specific revisions
  • # -*- coding: utf-8 -*-
    # ##### BEGIN GPL LICENSE BLOCK #####
    #
    #  This program is free software; you can redistribute it and/or
    #  modify it under the terms of the GNU General Public License
    #  as published by the Free Software Foundation; either version 2
    #  of the License, or (at your option) any later version.
    #
    #  This program is distributed in the hope that it will be useful,
    #  but WITHOUT ANY WARRANTY; without even the implied warranty of
    #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    #  GNU General Public License for more details.
    #
    #  You should have received a copy of the GNU General Public License
    #  along with this program; if not, write to the Free Software Foundation,
    #  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
    #
    # ##### END GPL LICENSE BLOCK #####
    
    
    rtsell's avatar
    rtsell committed
    from mathutils import Vector, Matrix
    from mathutils import geometry
    
    
    
    # 3D Geometry
    class G3:
    
        @classmethod
        def distanceP2P(cls, p1, p2):
            return (p1-p2).length
    
        @classmethod
        def closestP2L(cls, p, l1, l2):
            vA = p - l1
            vL = l2- l1
            vL.normalize()
            return vL * (vL.dot(vA)) + l1
    
        @classmethod
        def closestP2E(cls, p, e1, e2):
            q = G3.closestP2L(p, e1, e2)
            de = G3.distanceP2P(e1, e2)
            d1 = G3.distanceP2P(q, e1)
            d2 = G3.distanceP2P(q, e2)
            if d1>de and d1>d2:
                q = e2
            if d2>de and d2>d1:
                q = e1
            return q
    
        @classmethod
        def heightP2S(cls, p, sO, sN):
            return (p-sO).dot(sN) / sN.dot(sN)
    
        @classmethod
        def closestP2S(cls, p, sO, sN):
            k = - G3.heightP2S(p, sO, sN)
            q = p+sN*k
            return q
    
        @classmethod
        def closestP2F(cls, p, fv, sN):
            q = G3.closestP2S(p, fv[0], sN)
            #pi = MeshEditor.addVertex(p)
            #qi = MeshEditor.addVertex(q)
            #MeshEditor.addEdge(pi, qi)
            #print ([d0,d1,d2])
            
            if len(fv)==3:
                h = G3.closestP2L(fv[0], fv[1], fv[2])
                d = (fv[0]-h).dot(q-h)
                if d<=0:
                    return G3.closestP2E(q, fv[1], fv[2])
                h = G3.closestP2L(fv[1], fv[2], fv[0])
                d = (fv[1]-h).dot(q-h)
                if d<=0:
                    return G3.closestP2E(q, fv[2], fv[0])
                h = G3.closestP2L(fv[2], fv[0], fv[1])
                d = (fv[2]-h).dot(q-h)
                if d<=0:
                    return G3.closestP2E(q, fv[0], fv[1])
                return q
            if len(fv)==4:
                h = G3.closestP2L(fv[0], fv[1], fv[2])
                d = (fv[0]-h).dot(q-h)
                if d<=0:
                    return G3.closestP2E(q, fv[1], fv[2])
                h = G3.closestP2L(fv[1], fv[2], fv[3])
                d = (fv[1]-h).dot(q-h)
                if d<=0:
                    return G3.closestP2E(q, fv[2], fv[3])
                h = G3.closestP2L(fv[2], fv[3], fv[0])
                d = (fv[2]-h).dot(q-h)
                if d<=0:
                    return G3.closestP2E(q, fv[3], fv[0])
                h = G3.closestP2L(fv[3], fv[0], fv[1])
                d = (fv[3]-h).dot(q-h)
                if d<=0:
                    return G3.closestP2E(q, fv[0], fv[1])
                return q
    
        @classmethod
        def medianTriangle(cls, vv):
            m0 = (vv[1]+vv[2])/2
            m1 = (vv[0]+vv[2])/2
            m2 = (vv[0]+vv[1])/2
            return [m0, m1, m2]
    
        @classmethod
        def orthoCenter(cls, fv):
            try:
                h0 = G3.closestP2L(fv[0], fv[1], fv[2])
                h1 = G3.closestP2L(fv[1], fv[0], fv[2])
                #h2 = G3.closestP2L(fm[2], fm[0], fm[1])
                return geometry.intersect_line_line (fv[0], h0, fv[1], h1)[0]
            except(RuntimeError, TypeError):
                return None
    
    
    rtsell's avatar
    rtsell committed
        # Poor mans approach of finding center of circle
    
        @classmethod
        def circumCenter(cls, fv):
            fm = G3.medianTriangle(fv)
            return G3.orthoCenter(fm)
    
        @classmethod
        def ThreePnormal(cls, fv):
            n = (fv[1]-fv[0]).cross(fv[2]-fv[0])
            n.normalize()
            return n
    
        @classmethod
        def closestP2CylinderAxis(cls, p, fv):
            n = G3.ThreePnormal(fv)
            c = G3.circumCenter(fv)
    
    rtsell's avatar
    rtsell committed
            if(c==None):
    
    rtsell's avatar
    rtsell committed
        # Poor mans approach of finding center of sphere
    
        @classmethod
        def centerOfSphere(cls, fv):
            try:
                if len(fv)==3:
    
    rtsell's avatar
    rtsell committed
                    return G3.circumCenter(fv) # Equator
    
                if len(fv)==4:
                    fv3 = [fv[0],fv[1],fv[2]]
                    c1 = G3.circumCenter(fv)
                    n1 = G3.ThreePnormal(fv)
                    fv3 = [fv[1],fv[2],fv[3]]
                    c2 = G3.circumCenter(fv3)
                    n2 = G3.ThreePnormal(fv3)
                    d1 = c1+n1
                    d2 = c2+n2
                    return geometry.intersect_line_line (c1, d1, c2, d2)[0]
            except(RuntimeError, TypeError):
                return None
    
        @classmethod
        def closestP2Sphere(cls, p, fv):
            #print ("G3.closestP2Sphere")
            try:
                c = G3.centerOfSphere(fv)
    
    rtsell's avatar
    rtsell committed
                if c==None:
    
                    return None
                pc = p-c
                if pc.length == 0:
                    pc = pc + Vector((1,0,0))
                else:
                    pc.normalize()
                return c + (pc * G3.distanceP2P(c, fv[0]))
            except(RuntimeError, TypeError):
                return None
    
        @classmethod
        def closestP2Cylinder(cls, p, fv):
            #print ("G3.closestP2Sphere")
            c = G3.closestP2CylinderAxis(p, fv)
    
    rtsell's avatar
    rtsell committed
            if c==None:
    
                return None
            r = (fv[0] - G3.centerOfSphere(fv)).length
            pc = p-c
            if pc.length == 0:
                pc = pc + Vector((1,0,0))
            else:
                pc.normalize()
            return c + (pc * r)
    
        #@classmethod
        #def closestP2Sphere4(cls, p, fv4):
            ##print ("G3.closestP2Sphere")
            #fv = [fv4[0],fv4[1],fv4[2]]
            #c1 = G3.circumCenter(fv)
            #n1 = G3.ThreePnormal(fv)
            #fv = [fv4[1],fv4[2],fv4[3]]
            #c2 = G3.circumCenter(fv)
            #n2 = G3.ThreePnormal(fv)
            #d1 = c1+n1
            #d2 = c2+n2
            #c = geometry.intersect_line_line (c1, d1, c2, d2)[0]
            #pc = p-c
            #if pc.length == 0:
                #pc = pc + Vector((1,0,0))
            #else:
                #pc.normalize()
            #return c + (pc * G3.distanceP2P(c, fv[0]))