@sunilpai Finally I found a simpler solution:
In the 3d space a planar polygon with holes is defined as a go.Surface instance.
First we have to identify the biggest polygon, bigpolygon, i.e. the outer boundary of our surface, and the minimal rectangle with sides parallel with axes, that contains it.
Then we define a dense meshgrid on this rectangle, and for each pair, (bigpolygon, hole_polygon), we identify the meshgrid positions that are outside the bigpolygon , or inside the hole_polygon.
For, we are calling the function skimage.measure.points_in_poly() that returns a mask.
The final mask defined as a chained np.bitwise_and() of the intermediary masks helps us to remove the meshgrid points that are outside the bigpolygon or inside the polygons defining the holes.
import numpy as np
import plotly.graph_objects as go
from skimage.measure import points_in_poly
np.random.seed(100)
def random_poly(avg_r, regularity, spike_amp, spike_freq, num_v, center=(0, 0), ecc=1):
# generate n angle steps
angle_steps = np.sort(np.random.dirichlet(regularity * np.ones(num_v + 1)) * 2 * np.pi)
angles = np.cumsum(angle_steps) + np.random.rand() * 2 * np.pi
# now generate the points
rs = spike_amp * np.sin(angles * spike_freq + np.random.rand() * 2 * np.pi) ** 2 + avg_r
return np.asarray([rs * np.cos(angles), ecc * rs * np.sin(angles)]) + np.asarray(center)[:, np.newaxis]
holepoly1 = random_poly(100, 0.05, 30, 3, 300, ecc=1, center=(-100, 0))
holepoly2 = random_poly(100, 0.05, 30, 3, 300, ecc=0.5, center=(100, 200))
bigpoly = random_poly(500, 0.05, 100, 3, 300, ecc=1)
# points_in_poly() works with arrays of shape (N,2). Hence we are working with the transpose of the above defined e polygon arrays
polygon1 = np.concatenate((bigpoly.T, holepoly1.T), axis=0)
polygon2 = np.concatenate((bigpoly.T, holepoly2.T), axis=0)
xmin, xmax = bigpoly.T[:, 0].min(), bigpoly.T[:, 0].max()
ymin, ymax = bigpoly.T[:, 1].min(), bigpoly.T[:, 0].max()
n = 100 #choose m, n such that to get a sufficiently narrow grid/meshgrid
m = 200
X = np.linspace(xmin, xmax, n)
Y = np.linspace(ymin, ymax, m)
x, y = np.meshgrid(X,Y)
pts = np.dstack((x,y))
m, n, _ = pts.shape
pts = pts.reshape((m*n, 2))
mask = np.bitwise_and(points_in_poly(pts, polygon1), points_in_poly(pts, polygon2))
mask = mask.reshape((m,n))
z = np.ones(mask.shape)
z[np.where(~mask)] = np.nan # to avoid importing numpy.ma
surf = go.Surface(x= X, y=Y, z=z, colorscale=[[0, 'rgb(255,0,0)'], [1, 'rgb(255,0,0)']], showscale=False)
fig = go.Figure(data=[surf])