Example #1
0
def get_contour_mask(doselut, dosegridpoints, contour):
    """Get the mask for the contour with respect to the dose plane."""

    if matplotlib.__version__ > '1.2':
        grid = mpl_Path(contour).contains_points(dosegridpoints)
    else:
        grid = nx.points_inside_poly(dosegridpoints, contour)
    grid = grid.reshape((len(doselut[1]), len(doselut[0])))

    return grid
Example #2
0
def polygonsOverlap(poly1, poly2):
    """Determine if two polygons intersect; can fail for pointy polygons.

    Accepts two polygons, as lists of vertices (x,y) pairs. If given `ShapeStim`-based
    instances, will use rendered (vertices + pos) as the polygon.

    Checks if any vertex of one polygon is inside the other polygon; will fail in
    some cases, especially for pointy polygons. "crossed-swords" configurations
    overlap but may not be detected by the algorithm.

    Used by :class:`~psychopy.visual.ShapeStim` `.overlaps()`
    """
    try:  #do this using try:...except rather than hasattr() for speed
        poly1 = poly1.verticesPix  #we want to access this only once
    except:
        pass
    try:  #do this using try:...except rather than hasattr() for speed
        poly2 = poly2.verticesPix  #we want to access this only once
    except:
        pass
    # faster if have matplotlib tools:
    if haveMatplotlib:
        if matplotlib.__version__ > '1.2':
            if any(mpl_Path(poly1).contains_points(poly2)):
                return True
            return any(mpl_Path(poly2).contains_points(poly1))
        else:
            try:  # deprecated in matplotlib 1.2
                if any(nxutils.points_inside_poly(poly1, poly2)):
                    return True
                return any(nxutils.points_inside_poly(poly2, poly1))
            except:
                pass

    # fall through to pure python:
    for p1 in poly1:
        if pointInPolygon(p1[0], p1[1], poly2):
            return True
    for p2 in poly2:
        if pointInPolygon(p2[0], p2[1], poly1):
            return True
    return False
Example #3
0
def polygonsOverlap(poly1, poly2):
    """Determine if two polygons intersect; can fail for pointy polygons.

    Accepts two polygons, as lists of vertices (x,y) pairs. If given `ShapeStim`-based
    instances, will use rendered (vertices + pos) as the polygon.

    Checks if any vertex of one polygon is inside the other polygon; will fail in
    some cases, especially for pointy polygons. "crossed-swords" configurations
    overlap but may not be detected by the algorithm.

    Used by :class:`~psychopy.visual.ShapeStim` `.overlaps()`
    """
    try:  # do this using try:...except rather than hasattr() for speed
        poly1 = poly1.verticesPix  # we want to access this only once
    except:
        pass
    try:  # do this using try:...except rather than hasattr() for speed
        poly2 = poly2.verticesPix  # we want to access this only once
    except:
        pass
    # faster if have matplotlib tools:
    if haveMatplotlib:
        if matplotlib.__version__ > "1.2":
            if any(mpl_Path(poly1).contains_points(poly2)):
                return True
            return any(mpl_Path(poly2).contains_points(poly1))
        else:
            try:  # deprecated in matplotlib 1.2
                if any(nxutils.points_inside_poly(poly1, poly2)):
                    return True
                return any(nxutils.points_inside_poly(poly2, poly1))
            except:
                pass

    # fall through to pure python:
    for p1 in poly1:
        if pointInPolygon(p1[0], p1[1], poly2):
            return True
    for p2 in poly2:
        if pointInPolygon(p2[0], p2[1], poly1):
            return True
    return False
Example #4
0
def polygonsOverlap(poly1, poly2):
    """Determine if two polygons intersect; can fail for very pointy polygons.

    Accepts two polygons, as lists of vertices (x,y) pairs. If given an object
    with with (vertices + pos), will try to use that as the polygon.

    Checks if any vertex of one polygon is inside the other polygon. Same as
    the `.overlaps()` method elsewhere.
    """
    try:  #do this using try:...except rather than hasattr() for speed
        poly1 = poly1.verticesPix  #we want to access this only once
    except:
        pass
    try:  #do this using try:...except rather than hasattr() for speed
        poly2 = poly2.verticesPix  #we want to access this only once
    except:
        pass
    # faster if have matplotlib tools:
    if haveMatplotlib:
        if matplotlib.__version__ > '1.2':
            if any(mpl_Path(poly1).contains_points(poly2)):
                return True
            return any(mpl_Path(poly2).contains_points(poly1))
        else:
            try:  # deprecated in matplotlib 1.2
                if any(nxutils.points_inside_poly(poly1, poly2)):
                    return True
                return any(nxutils.points_inside_poly(poly2, poly1))
            except:
                pass

    # fall through to pure python:
    for p1 in poly1:
        if pointInPolygon(p1[0], p1[1], poly2):
            return True
    for p2 in poly2:
        if pointInPolygon(p2[0], p2[1], poly1):
            return True
    return False
Example #5
0
def polygonsOverlap(poly1, poly2):
    """Determine if two polygons intersect; can fail for very pointy polygons.

    Accepts two polygons, as lists of vertices (x,y) pairs. If given an object
    with with (vertices + pos), will try to use that as the polygon.

    Checks if any vertex of one polygon is inside the other polygon. Same as
    the `.overlaps()` method elsewhere.
    """
    try:  # do this using try:...except rather than hasattr() for speed
        poly1 = poly1.verticesPix  # we want to access this only once
    except Exception:
        pass
    try:  # do this using try:...except rather than hasattr() for speed
        poly2 = poly2.verticesPix  # we want to access this only once
    except Exception:
        pass
    # faster if have matplotlib tools:
    if haveMatplotlib:
        if matplotlib.__version__ > '1.2':
            if any(mpl_Path(poly1).contains_points(poly2)):
                return True
            return any(mpl_Path(poly2).contains_points(poly1))
        else:
            try:  # deprecated in matplotlib 1.2
                if any(nxutils.points_inside_poly(poly1, poly2)):
                    return True
                return any(nxutils.points_inside_poly(poly2, poly1))
            except Exception:
                pass

    # fall through to pure python:
    for p1 in poly1:
        if pointInPolygon(p1[0], p1[1], poly2):
            return True
    for p2 in poly2:
        if pointInPolygon(p2[0], p2[1], poly1):
            return True
    return False
Example #6
0
def pointInPolygon(x, y, poly):
    """Determine if a point is inside a polygon; returns True if inside.

    (`x`, `y`) is the point to test. `poly` is a list of 3 or more vertices as
    (x,y) pairs. If given an object, such as a `ShapeStim`, will try to use its
    vertices and position as the polygon.

    Same as the `.contains()` method elsewhere.
    """
    try: #do this using try:...except rather than hasattr() for speed
        poly = poly.verticesPix #we want to access this only once
    except:
        pass
    nVert = len(poly)
    if nVert < 3:
        msg = 'pointInPolygon expects a polygon with 3 or more vertices'
        logging.warning(msg)
        return False

    # faster if have matplotlib tools:
    if haveMatplotlib:
        if matplotlib.__version__ > '1.2':
            return mpl_Path(poly).contains_point([x,y])
        else:
            try:
                return bool(nxutils.pnpoly(x, y, poly))
            except:
                pass

    # fall through to pure python:
    # as adapted from http://local.wasp.uwa.edu.au/~pbourke/geometry/insidepoly/
    # via http://www.ariel.com.au/a/python-point-int-poly.html

    inside = False
    # trace (horizontal?) rays, flip inside status if cross an edge:
    p1x, p1y = poly[-1]
    for p2x, p2y in poly:
        if y > min(p1y, p2y) and y <= max(p1y, p2y) and x <= max(p1x, p2x):
            if p1y != p2y:
                xints = (y - p1y) * (p2x - p1x) / (p2y - p1y) + p1x
            if p1x == p2x or x <= xints:
                inside = not inside
        p1x, p1y = p2x, p2y
    return inside
Example #7
0
def pointInPolygon(x, y, poly):
    """Determine if a point (`x`, `y`) is inside a polygon, using the ray casting method.

    `poly` is a list of 3+ vertices as (x,y) pairs.
    If given a `ShapeStim`-based object, will use the
    rendered vertices and position as the polygon.

    Returns True (inside) or False (outside). Used by :class:`~psychopy.visual.ShapeStim` `.contains()`
    """
    try:  #do this using try:...except rather than hasattr() for speed
        poly = poly.verticesPix  #we want to access this only once
    except:
        pass
    nVert = len(poly)
    if nVert < 3:
        msg = 'pointInPolygon expects a polygon with 3 or more vertices'
        logging.warning(msg)
        return False

    # faster if have matplotlib tools:
    if haveMatplotlib:
        if matplotlib.__version__ > '1.2':
            return mpl_Path(poly).contains_point([x, y])
        else:
            try:
                return bool(nxutils.pnpoly(x, y, poly))
            except:
                pass

    # fall through to pure python:
    # as adapted from http://local.wasp.uwa.edu.au/~pbourke/geometry/insidepoly/
    # via http://www.ariel.com.au/a/python-point-int-poly.html

    inside = False
    # trace (horizontal?) rays, flip inside status if cross an edge:
    p1x, p1y = poly[-1]
    for p2x, p2y in poly:
        if y > min(p1y, p2y) and y <= max(p1y, p2y) and x <= max(p1x, p2x):
            if p1y != p2y:
                xints = (y - p1y) * (p2x - p1x) / (p2y - p1y) + p1x
            if p1x == p2x or x <= xints:
                inside = not inside
        p1x, p1y = p2x, p2y
    return inside
Example #8
0
def pointInPolygon(x, y, poly):
    """Determine if a point (`x`, `y`) is inside a polygon, using the ray casting method.

    `poly` is a list of 3+ vertices as (x,y) pairs.
    If given a `ShapeStim`-based object, will use the
    rendered vertices and position as the polygon.

    Returns True (inside) or False (outside). Used by :class:`~psychopy.visual.ShapeStim` `.contains()`
    """
    if hasattr(poly, '_verticesRendered') and hasattr(poly, '_posRendered'):
        poly = poly._verticesRendered + poly._posRendered
    nVert = len(poly)
    if nVert < 3:
        msg = 'pointInPolygon expects a polygon with 3 or more vertices'
        logging.warning(msg)
        return False

    # faster if have matplotlib tools:
    if haveMatplotlib:
        if matplotlib.__version__ > '1.2':
            return mpl_Path(poly).contains_point([x,y])
        else:
            try:
                return bool(nxutils.pnpoly(x, y, poly))
            except:
                pass

    # fall through to pure python:
    # as adapted from http://local.wasp.uwa.edu.au/~pbourke/geometry/insidepoly/
    # via http://www.ariel.com.au/a/python-point-int-poly.html

    inside = False
    # trace (horizontal?) rays, flip inside status if cross an edge:
    p1x, p1y = poly[-1]
    for p2x, p2y in poly:
        if y > min(p1y, p2y) and y <= max(p1y, p2y) and x <= max(p1x, p2x):
            if p1y != p2y:
                xints = (y - p1y) * (p2x - p1x) / (p2y - p1y) + p1x
            if p1x == p2x or x <= xints:
                inside = not inside
        p1x, p1y = p2x, p2y
    return inside
Example #9
0
def overlaps(left, right):
    poly_left  = mpl_Path( left, closed=True)
    poly_right = mpl_Path(right, closed=True)
    return poly_left.intersects_path(poly_right, filled=True)
Example #10
0
    def MultiPolygon(self):
        # not used here but might be relevant:
        # https://stackoverflow.com/questions/22100453/gdal-python-creating-contourlines
        try:
            return self.__MultiPolygon
        except AttributeError:
            pass

        # fully external tile.
        if np.all(self.values > self.zmax) or np.all(self.values < self.zmin):
            self.__MultiPolygon = self.__get_empty_MultiPolygon()
            return self.__MultiPolygon

        # fully internal tile
        elif np.min(self.values) > self.zmin \
                and np.max(self.values) < self.zmax:
            _LinearRing = self.__get_empty_LinearRing()
            bbox = self.bbox.get_points()
            x0, y0 = float(bbox[0][0]), float(bbox[0][1])
            x1, y1 = float(bbox[1][0]), float(bbox[1][1])
            _LinearRing.AddPoint(x0, y0, float(self.get_value(x0, y0)))
            _LinearRing.AddPoint(x1, y0, float(self.get_value(x1, y0)))
            _LinearRing.AddPoint(x1, y1, float(self.get_value(x1, y1)))
            _LinearRing.AddPoint(x0, y1, float(self.get_value(x0, y1)))
            _LinearRing.AddPoint(*_LinearRing.GetPoint(0))
            _Polygon = self.__get_empty_Polygon()
            _Polygon.AddGeometry(_LinearRing)
            _MultiPolygon = self.__get_empty_MultiPolygon()
            _MultiPolygon.AddGeometry(_Polygon)
            self.__MultiPolygon = _MultiPolygon
            return self.__MultiPolygon

        # tile containing boundary
        _QuadContourSet = plt.contourf(self.x,
                                       self.y,
                                       self.values,
                                       levels=[self.zmin, self.zmax])
        plt.close(plt.gcf())
        for _PathCollection in _QuadContourSet.collections:
            _LinearRings = list()
            for _Path in _PathCollection.get_paths():
                linear_rings = _Path.to_polygons(closed_only=True)
                for linear_ring in linear_rings:
                    _LinearRing = ogr.Geometry(ogr.wkbLinearRing)
                    _LinearRing.AssignSpatialReference(self.SpatialReference)
                    for x, y in linear_ring:
                        _LinearRing.AddPoint(float(x), float(y),
                                             float(self.get_value(x, y)))
                    _LinearRing.CloseRings()
                    _LinearRings.append(_LinearRing)
        # create output object
        _MultiPolygon = ogr.Geometry(ogr.wkbMultiPolygon)
        _MultiPolygon.AssignSpatialReference(self.SpatialReference)
        # sort list of linear rings into polygons
        areas = [_LinearRing.GetArea() for _LinearRing in _LinearRings]
        idx = np.where(areas == np.max(areas))[0][0]
        _Polygon = ogr.Geometry(ogr.wkbPolygon)
        _Polygon.AssignSpatialReference(self.SpatialReference)
        _Polygon.AddGeometry(_LinearRings.pop(idx))
        while len(_LinearRings) > 0:
            _Path = mpl_Path(np.asarray(
                _Polygon.GetGeometryRef(0).GetPoints())[:, :2],
                             closed=True)
            for i, _LinearRing in reversed(list(enumerate(_LinearRings))):
                x = _LinearRing.GetX(0)
                y = _LinearRing.GetY(0)
                if _Path.contains_point((x, y)):
                    _Polygon.AddGeometry(_LinearRings.pop(i))
            _Polygon.CloseRings()
            _MultiPolygon.AddGeometry(_Polygon)
            if len(_LinearRings) > 0:
                areas = [_LinearRing.GetArea() for _LinearRing in _LinearRings]
                idx = np.where(areas == np.max(areas))[0][0]
                _Polygon = ogr.Geometry(ogr.wkbPolygon)
                _Polygon.AssignSpatialReference(self.SpatialReference)
                _Polygon.AddGeometry(_LinearRings.pop(idx))
        self.__MultiPolygon = _MultiPolygon
        return self.__MultiPolygon
Example #11
0
def calculate_dvh(structure, dose, limit=None, callback=None):
    """Calculate the differential DVH for the given structure and dose grid."""

    sPlanes = structure['planes']
    logger.debug("Calculating DVH of %s %s", structure['id'],
                 structure['name'])

    # Get the dose to pixel LUT
    doselut = dose.GetPatientToPixelLUT()

    # Generate a 2d mesh grid to create a polygon mask in dose coordinates
    # Code taken from Stack Overflow Answer from Joe Kington:
    # http://stackoverflow.com/questions/3654289/scipy-create-2d-polygon-mask/3655582
    # Create vertex coordinates for each grid cell
    x, y = np.meshgrid(np.array(doselut[0]), np.array(doselut[1]))
    x, y = x.flatten(), y.flatten()
    dosegridpoints = np.vstack((x, y)).T

    # Create an empty array of bins to store the histogram in cGy
    # only if the structure has contour data or the dose grid exists
    if ((len(sPlanes)) and ("PixelData" in dose.ds)):

        # Get the dose and image data information
        dd = dose.GetDoseData()
        id = dose.GetImageData()

        maxdose = int(dd['dosemax'] * dd['dosegridscaling'] * 100)
        # Remove values above the limit (cGy) if specified
        if not (limit == None):
            if (limit < maxdose):
                maxdose = limit
        hist = np.zeros(maxdose)
    else:
        hist = np.array([0])
    volume = 0

    plane = 0
    # Iterate over each plane in the structure
    for z, sPlane in sPlanes.iteritems():

        # Get the contours with calculated areas and the largest contour index
        contours, largestIndex = calculate_contour_areas(sPlane)

        # Get the dose plane for the current structure plane
        doseplane = dose.GetDoseGrid(z)

        # If there is no dose for the current plane, go to the next plane
        if not len(doseplane):
            break

        # Calculate the histogram for each contour
        for i, contour in enumerate(contours):
            m = get_contour_mask(doselut, dosegridpoints, contour['data'])
            h, vol = calculate_contour_dvh(m, doseplane, maxdose, dd, id,
                                           structure)
            # If this is the largest contour, just add to the total histogram
            if (i == largestIndex):
                hist += h
                volume += vol
            # Otherwise, determine whether to add or subtract histogram
            # depending if the contour is within the largest contour or not
            else:
                contour['inside'] = False
                for point in contour['data']:
                    if matplotlib.__version__ > '1.2':
                        if mpl_Path(np.array(contours[largestIndex]
                                             ['data'])).contains_point(point):
                            contour['inside'] = True
                            # Assume if one point is inside, all will be inside
                            break
                    else:
                        if nx.pnpoly(point[0], point[1],
                                     np.array(contours[largestIndex]['data'])):
                            contour['inside'] = True
                            # Assume if one point is inside, all will be inside
                            break
                # If the contour is inside, subtract it from the total histogram
                if contour['inside']:
                    hist -= h
                    volume -= vol
                # Otherwise it is outside, so add it to the total histogram
                else:
                    hist += h
                    volume += vol
        plane += 1
        if not (callback == None):
            callback(plane, len(sPlanes))
    # Volume units are given in cm^3
    volume = volume / 1000
    # Rescale the histogram to reflect the total volume
    hist = hist * volume / sum(hist)
    # Remove the bins above the max dose for the structure
    hist = np.trim_zeros(hist, trim='b')

    return hist