Skip to content
Snippets Groups Projects
measure.py 4.29 KiB
Newer Older
  • Learn to ignore specific revisions
  • import numpy as np
    import overlap
    
    
    from polygon_triangulate import polygon_triangulate, PlotTriangulation
    from tetrahedralize_triangles import tetrahedralize
    
    
    logging.basicConfig(filename='warnings.log', level=logging.DEBUG)
    
    
    def measure_volume(V_tet, T, origin, r):
    
        sphere = overlap.Sphere(origin, r)
        volume = 0.0
    
    
        for tet in T:
            vertices = V_tet[tet]
            overlap_tet = overlap.Tetrahedron(vertices)
            overlap_volume = overlap.overlap(sphere, overlap_tet)
    
            volumes.append(overlap_volume)
            if overlap_volume < 0:
                print('Encountered negative volume overlap')
                logging.warning('Encountered negative volume overlap')
    
            volume += overlap_volume
    
    
        #import matplotlib.pyplot as plt
        #plt.title(f'radius {r} total {volume}')
        #plt.plot(np.arange(len(volumes)), volumes)
        #plt.show()
    
    
        return volume
    
    def same_point(x, y):
        return np.linalg.norm(x - y) < 1e-10
    
    def remove_duplicate_contour_points(P):
        n = len(P)
        for i in range(n):
            j = (i + 1) % n
            if same_point(P[i], P[j]):
                return remove_duplicate_contour_points(np.delete(P, i, axis=0))
        return P
    
    
    def remove_line_triangles(P, F):
        n = len(F)
        for i in range(n-1, -1, -1):
            PF = P[F[i]]
            v1 = PF[0] - PF[1]
            v2 = PF[1] - PF[2]
            if np.isclose(np.abs(np.dot(v1/np.linalg.norm(v1),v2/np.linalg.norm(v2))),1):
                F = np.delete(F, i, axis=0)
        return F
    
    
    def measure_cumulative_volume(z, P, thickness, origin, R):
        '''
        Integration of the intersecting volume of a thick polygon and a sphere of increasing radius.
    
        Parameters
            ----------
            z : float
                The z depth-wise coordinate of the thick polygon.
            P : (N, 2) array_like
                A real array of ordered contour points of the polygon.
            thickness : float
                The thickness of the polygon.
            origin : (3,) array_like
                The center of the sphere from which to integrate from.
            R : (M,) array_like
                The discrete sphere radii from which to measure the polygon in.
            
            Returns
            -------
            mu: (M,) array_like
                The intersecting volumes of the sphere and the thick polygon at radii determined by R.
        '''
    
        P = np.array(P)
        origin = np.array(origin)
    
        P = remove_duplicate_contour_points(P)
    
        z0 = z - thickness / 2
        z1 = z + thickness / 2
        _, V_tri, F = polygon_triangulate(P)
    
    
        F = remove_line_triangles(V_tri, F)
    
        #import matplotlib.pyplot as plt
        #print(V_tri[:5,:])
        #PlotTriangulation(V_tri, F)
        #plt.show()
    
    
        V_tet, T = tetrahedralize(V_tri, F, z0, z1)
    
        mu = np.zeros(len(R))
        for i, r in enumerate(R):
    
            if r <= 0:
                continue
    
            mu[i] = measure_volume(V_tet, T, origin, r)
    
        return mu
    
    def measure_cumulative_points(z, X, thickness, origin, R):
        '''
        Integration of the points placed in a thick section integrated intersecting with a sphere of increasing size.
    
        Parameters
            ----------
            z : float
                The z depth-wise coordinate of the section with the points.
            X : (N, 2) array_like
                A real array of points inside the section.
            thickness : float
                The thickness of the section of which the points are in.
            origin : (3,) array_like
                The center of the sphere from which to integrate from.
            R : (M,) array_like
                The discrete sphere radii from which to measure the points inside.
            
            Returns
            -------
            mu: (M,) array_like
                The integrated point masses inside the sphere of radii determined by R.
        '''
    
        oz = origin[2]
        oxy = origin[:2]
    
        dxy = np.array([np.linalg.norm(x - oxy) for x in X])
    
        mu = np.zeros(len(R))
    
        if z == oz:
            for i, r in enumerate(R):
                s = np.sqrt(np.clip(r**2 - dxy**2, 0, None))
                mu[i] = np.sum(np.clip(2*s/thickness, 0, 1))
    
            return mu
    
        # plane is below, mirror it above to simplify calculations
        if z < oz:
            z = z + 2*(oz - z)
    
        z0 = z - thickness / 2
        z1 = z + thickness / 2
    
        d0 = z0 - oz
    
        for i, r in enumerate(R):
            h = np.sqrt(np.clip(r**2 - dxy**2, 0, None))
            s = h - d0
            mu[i] = np.sum(np.clip(s/thickness, 0, 1))