Example #1
0
    def test_on_line(self):
        # Point on the line, but not the segment, of the polygon
        poly = self.setup()
        p = np.array([2, 0])

        inside = cg.is_inside_polygon(poly, p)
        self.assertTrue(not inside[0])
Example #2
0
    def test_outside(self):
        poly = self.setup()
        p = np.array([2, 2])

        inside = cg.is_inside_polygon(poly, p)

        self.assertTrue(not inside[0])
Example #3
0
    def test_multiple_points(self):
        poly = self.setup()
        p = np.array([[0.5, 0.5], [0.5, 1.5]])

        inside = cg.is_inside_polygon(poly, p)

        self.assertTrue(inside[0])
        self.assertTrue(not inside[1])
Example #4
0
 def test_large_polygon(self):
     a = np.array([
         [
             -2.04462568e-01,
             -1.88898782e-01,
             -1.65916617e-01,
             -1.44576869e-01,
             -7.82444375e-02,
             -1.44018389e-16,
             7.82444375e-02,
             1.03961083e-01,
             1.44576869e-01,
             1.88898782e-01,
             2.04462568e-01,
             1.88898782e-01,
             1.44576869e-01,
             7.82444375e-02,
             1.44018389e-16,
             -7.82444375e-02,
             -1.44576869e-01,
             -1.88898782e-01,
         ],
         [
             -1.10953147e-16,
             7.82444375e-02,
             1.19484803e-01,
             1.44576869e-01,
             1.88898782e-01,
             2.04462568e-01,
             1.88898782e-01,
             1.76059749e-01,
             1.44576869e-01,
             7.82444375e-02,
             1.31179355e-16,
             -7.82444375e-02,
             -1.44576869e-01,
             -1.88898782e-01,
             -2.04462568e-01,
             -1.88898782e-01,
             -1.44576869e-01,
             -7.82444375e-02,
         ],
     ])
     b = np.array([[0.1281648, 0.04746067], [-0.22076491, 0.16421546]])
     inside = cg.is_inside_polygon(a, b)
     self.assertTrue(not inside[0])
     self.assertTrue(inside[1])
Example #5
0
 def test_just_inside(self):
     poly = self.setup()
     p = np.array([0.5, 1e-6])
     self.assertTrue(cg.is_inside_polygon(poly, p))
Example #6
0
    def test_on_boundary(self):
        poly = self.setup()
        p = np.array([0, 0.5])

        inside = cg.is_inside_polygon(poly, p)
        self.assertTrue(not inside[0])
Example #7
0
    def test_inside(self):
        poly = self.setup()

        p = np.array([0.5, 0.5])
        self.assertTrue(np.all(cg.is_inside_polygon(poly, p)))
Example #8
0
def cut_fracture_by_plane(
    main_frac, other_frac, reference_point, tol=1e-4, recompute_center=True, **kwargs
):
    """ Cut a fracture by a plane, and confine it to one side of the plane.

    Intended use is to confine abutting fractures (T-intersections) to one side
    of the fracture it hits. This is done by deleting points on the abutting
    fracture.

    Parameters:
        main_frac (Fracture): The fracture to be cut.
        other_frac (Fracture): The fracture that defines the confining plane.
        reference_point (np.array, nd): Point on the main frature that defines
            which side should be kept. Will typically be the other point of the
            exposed line.

    Returns:
        Fracture: A copy of the main fracture, cut by the other fracture.
        double: In cases where one interseciton point extends beyond the other
            fracture, this is the distance between the center of the other
            fracture and the intersection point. If both intersections are
            within the polygon, None will be returned.

    Raises:
        ValueError if the points in the other fracture is too close. This could
        probably be handled by a scaling of coordinates, it is tacitly assumed
        that we're working in something resembling the unit box.

    """
    reference_point = reference_point.reshape((-1, 1))
    if reference_point.size == 2:
        reference_point = np.vstack((reference_point, 0))

    # First determine extent of the main fracture
    main_min = main_frac.p.min(axis=1)
    main_max = main_frac.p.max(axis=1)

    # Equation for the plane through the other fracture, on the form
    #  n_x(x-c_x) + n_y(y-c_y) + n_z(z-c_z) = 0
    n = cg.compute_normal(other_frac.p).reshape((-1, 1))
    c = other_frac.center

    # max and min coordinates that extends outside the main fracture
    main_min -= 1
    main_max += 1

    # Define points in the plane of the second fracture with min and max
    # coordinates picked from the main fracture.
    # The below tricks with indices are needed to find a dimension with a
    # non-zero gradient of the plane, so that we can divide safely.
    # Implementation note: It might have been possible to do this with a
    # rotation to the natural plane of the other fracture, but it is not clear
    # this will really be simpler.

    # Not sure about the tolerance here
    # We should perhaps do a scaling of coordinates.
    non_zero = np.where(np.abs(n) > 1e-8)[0]
    if non_zero.size == 0:
        raise ValueError("Could not compute normal vector of other fracture")
    ind = np.setdiff1d(np.arange(3), non_zero[0])
    i0 = ind[0]
    i1 = ind[1]
    i2 = non_zero[0]

    p = np.zeros((3, 4))
    # A for-loop might have been possible here.
    p[i0, 0] = main_min[i0]
    p[i1, 0] = main_min[i1]
    p[i2, 0] = (
        c[i2]
        - (n[i0] * (main_min[i0] - c[i0]) + n[i1] * (main_min[i1] - c[i1])) / n[i2]
    )

    p[i0, 1] = main_max[i0]
    p[i1, 1] = main_min[i1]
    p[i2, 1] = (
        c[i2]
        - (n[i0] * (main_max[i0] - c[i0]) + n[i1] * (main_min[i1] - c[i1])) / n[i2]
    )

    p[i0, 2] = main_max[i0]
    p[i1, 2] = main_max[i1]
    p[i2, 2] = (
        c[i2]
        - (n[i0] * (main_max[i0] - c[i0]) + n[i1] * (main_max[i1] - c[i1])) / n[i2]
    )

    p[i0, 3] = main_min[i0]
    p[i1, 3] = main_max[i1]
    p[i2, 3] = (
        c[i2]
        - (n[i0] * (main_min[i0] - c[i0]) + n[i1] * (main_max[i1] - c[i1])) / n[i2]
    )

    # Create an auxiliary fracture that spans the same plane as the other
    # fracture, and with a larger extension than the main fracture.
    aux_frac = Fracture(p, check_convexity=False)

    isect_pt, _, _ = main_frac.intersects(aux_frac, tol)

    # The extension of the abutting fracture will cross the other fracture
    # with a certain angle to the vertical. If the other fracture is rotated
    # with a similar angle, point contact results.
    if isect_pt.size == 0:
        warnings.warn(
            """No intersection found in cutting of fractures. This is
                         likely caused by an unfortunate combination of
                         extrusion and rotation angles, which created fractures
                         that only intersect in a single point (the outcrop
                         plane. Will try to continue, but this may cause
                         trouble for meshing etc."""
        )
        return main_frac, None

    # Next step is to eliminate points in the main fracture that are on the
    # wrong side of the other fracture.
    v = main_frac.p - other_frac.center.reshape((-1, 1))
    sgn = np.sign(np.sum(v * n, axis=0))
    ref_v = reference_point - other_frac.center.reshape((-1, 1))
    right_sign = np.sign(np.sum(ref_v * n, axis=0))

    # Eliminate points that are on the other side.
    eliminate = np.where(sgn * right_sign < 0)[0]
    main_frac.remove_points(eliminate)

    # Add intersection points on the main fracture. One of these may already be
    # present, as the point of extrusion, but add_point will uniquify the point
    # cloud.
    # We add the points after elimination, to ensure that the points on the
    # plane are present in the final fracture.
    main_frac.add_points(isect_pt, check_convexity=False)

    if recompute_center:
        main_frac.compute_centroid()

    # If the main fracture is too large compared to the other, the cut line
    # will extend beyond the confining plane. In these cases, compute the
    # distance from the fracture center to the outside intersection point. This
    # can be used to extend the other fracture so as to avoid such strange
    # configurations.
    other_center = other_frac.center.reshape((-1, 1))
    other_p = other_frac.p
    rot = cg.project_plane_matrix(other_p - other_center)

    other_rot = rot.dot(other_p - other_center)[:2]
    isect_rot = rot.dot(isect_pt - other_center)[:2]

    is_inside = cg.is_inside_polygon(other_rot, isect_rot, tol, default=True)
    # At one point (the exposed point) must be in the polygon of the other
    # fracture.
    assert is_inside.any()

    if not is_inside.all():
        hit = np.logical_not(is_inside)
        r = np.sqrt(np.sum(isect_pt[:, hit] ** 2))
        return main_frac, r
    else:
        return main_frac, None