first commit
commit
954eb18d8d
|
@ -0,0 +1,174 @@
|
||||||
|
#!/usr/bin/python3
|
||||||
|
|
||||||
|
import numpy as np
|
||||||
|
from scipy.spatial import Delaunay
|
||||||
|
import matplotlib.pyplot as plt
|
||||||
|
import shapely.geometry as geo
|
||||||
|
|
||||||
|
#import sys
|
||||||
|
#np.set_printoptions(threshold=sys.maxsize)
|
||||||
|
|
||||||
|
def get_mesh(fd,fh,h0,bbox,pfix):
|
||||||
|
'''
|
||||||
|
A simple mesh generator based on:
|
||||||
|
Persson, G. Strang, A Simple Mesh Generator in MATLAB.
|
||||||
|
SIAM Review, Volume 46 (2), pp. 329-345, June 2004
|
||||||
|
'''
|
||||||
|
geps = 0.001*h0
|
||||||
|
ttol = 0.1
|
||||||
|
Fscale = 1.2
|
||||||
|
deltat = 0.2
|
||||||
|
deps = np.sqrt(np.finfo(float).eps)*h0
|
||||||
|
dptol = 0.001
|
||||||
|
maxIter = 500
|
||||||
|
|
||||||
|
X, Y = np.meshgrid(np.arange(bbox[0,0],bbox[1,0]+h0,h0),\
|
||||||
|
np.arange(bbox[0,1],bbox[1,1]+h0*0.5*np.sqrt(3),h0*0.5*np.sqrt(3)))
|
||||||
|
X[1:-1:2,:] += (0.5*h0)
|
||||||
|
p = np.column_stack((X.flatten('F'),Y.flatten('F')))
|
||||||
|
|
||||||
|
p = p[np.nonzero(np.apply_along_axis(fd,1,p) < geps)].squeeze()
|
||||||
|
r0 = 1/np.apply_along_axis(fh,1,p)**2
|
||||||
|
R0 = np.max(r0)
|
||||||
|
p = p[np.random.rand(p.shape[0]) < r0/R0]
|
||||||
|
if len(pfix):
|
||||||
|
p = np.vstack((pfix, p))
|
||||||
|
N = p.shape[0]
|
||||||
|
|
||||||
|
pold = np.Inf
|
||||||
|
counter = 0
|
||||||
|
while True:
|
||||||
|
if np.max(np.sqrt(np.sum((p-pold)**2,1))/h0) > ttol:
|
||||||
|
pold = np.copy(p)
|
||||||
|
T = Delaunay(p)
|
||||||
|
tri = T.simplices
|
||||||
|
pmid = (p[tri[:,0],:]+p[tri[:,1],:]+p[tri[:,2],:])/3
|
||||||
|
inner = np.apply_along_axis(fd,1,pmid) < -geps
|
||||||
|
tri = tri[inner,:]
|
||||||
|
bars = np.vstack((tri[:,[0,1]],tri[:,[1,2]],tri[:,[0,2]]))
|
||||||
|
bars.sort(1)
|
||||||
|
bars = remove_duplicate_row(bars)
|
||||||
|
|
||||||
|
|
||||||
|
bvec = p[bars[:,0],:] - p[bars[:,1],:]
|
||||||
|
L = np.sqrt(np.sum(bvec**2,1))
|
||||||
|
hbars = np.apply_along_axis(fh, 1,(p[bars[:,0],:]+p[bars[:,1],:])/2)
|
||||||
|
L0 = hbars*Fscale*np.sqrt(np.sum(L**2)/np.sum(hbars**2))
|
||||||
|
F = [np.max(L0 - [L], 0)]
|
||||||
|
Fvec = (F/L).T * bvec
|
||||||
|
|
||||||
|
#sparse and back to full does not work the same in python as in matlab
|
||||||
|
#forced to do the loop, figure out better way
|
||||||
|
row = bars[:,[0,0,1,1]].flatten('F')
|
||||||
|
column = (np.ones(np.shape(F),dtype=np.int32).T @ [[0,1,0,1]]).flatten('F')
|
||||||
|
Ffrac = np.hstack((Fvec,-Fvec)).flatten('F')
|
||||||
|
Ftot = np.zeros([N,2])
|
||||||
|
for i in range(len(row)):
|
||||||
|
Ftot[row[i],column[i]] += Ffrac[i]
|
||||||
|
if len(pfix):
|
||||||
|
Ftot[0:pfix.shape[0]-1,:] = 0
|
||||||
|
p += (deltat*Ftot)
|
||||||
|
|
||||||
|
#bring back to boundary
|
||||||
|
d = np.apply_along_axis(fd,1,p)
|
||||||
|
ix = d>0 #index of points outside boundary
|
||||||
|
dx = np.column_stack((p[ix,0]+deps, p[ix,1]))
|
||||||
|
dy = np.column_stack((p[ix,0], p[ix,1]+deps))
|
||||||
|
|
||||||
|
gradx = (np.apply_along_axis(fd,1,dx)-d[ix])/deps
|
||||||
|
grady = (np.apply_along_axis(fd,1,dy)-d[ix])/deps
|
||||||
|
p[ix,:] -= np.column_stack((d[ix]*gradx,d[ix]*grady))
|
||||||
|
|
||||||
|
#print(np.max(np.sqrt(np.sum(deltat*Ftot[d<-geps,:]**2,1))/h0))
|
||||||
|
|
||||||
|
counter += 1
|
||||||
|
#print(counter)
|
||||||
|
|
||||||
|
if Ftot[d<-geps,:].size == 0 or counter > maxIter:
|
||||||
|
print(counter)
|
||||||
|
return p, tri
|
||||||
|
if np.max(np.sqrt(np.sum(deltat*Ftot[d<-geps,:]**2,1))/h0) < dptol:
|
||||||
|
print(counter)
|
||||||
|
return p, tri
|
||||||
|
|
||||||
|
def remove_duplicate_row(M):
|
||||||
|
#remove dupplicate rows of the array
|
||||||
|
A = np.ascontiguousarray(M).view(np.dtype((np.void,M.dtype.itemsize*M.shape[1])))
|
||||||
|
_, idx = np.unique(A, return_index=True)
|
||||||
|
return M[idx]
|
||||||
|
|
||||||
|
def print_mesh(p, tri, title='', output=''):
|
||||||
|
plt.figure()
|
||||||
|
plt.triplot(p[:,0], p[:,1], tri, color='black')
|
||||||
|
plt.axis('equal')
|
||||||
|
plt.axis(False)
|
||||||
|
if title:
|
||||||
|
plt.title(title)
|
||||||
|
if output:
|
||||||
|
plt.savefig(output)
|
||||||
|
plt.close()
|
||||||
|
return
|
||||||
|
plt.show()
|
||||||
|
return
|
||||||
|
|
||||||
|
def ddiff(d1, d2):
|
||||||
|
return max(d1, -d2)
|
||||||
|
|
||||||
|
def dunion(d1, d2):
|
||||||
|
return min(d1, d2)
|
||||||
|
|
||||||
|
def dintersect(d1, d2):
|
||||||
|
return max(d1, d2)
|
||||||
|
|
||||||
|
def dcircle(p, xc, yc, r):
|
||||||
|
return np.sqrt((p[0]-xc)**2+(p[1]-yc)**2)-r
|
||||||
|
|
||||||
|
def drectangle(p, x1, x2, y1, y2):
|
||||||
|
return -min(min(min(-y1+p[1],y2-p[1]),-x1+p[0]), x2-p[0])
|
||||||
|
|
||||||
|
def protate(p, phi):
|
||||||
|
A = np.array([[np.cos(phi),-np.sin(phi)],[np.sin(phi),np.cos(phi)]])
|
||||||
|
return (A@p.T).T
|
||||||
|
|
||||||
|
def _dpoly(p, poly, ring):
|
||||||
|
ds = ring.distance(p)
|
||||||
|
inside = ring.contains(p) or poly.contains(p)
|
||||||
|
return (-1)**inside*ds
|
||||||
|
|
||||||
|
def dpoly(p, poly):
|
||||||
|
return _dpoly(geo.asPoint(p), geo.asPolygon(poly),geo.asLinearRing(poly))
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
#print("test 1")
|
||||||
|
#fd = lambda x: ddiff(dcircle(x, 0, 0, 1), dcircle(x, 0.5, -0.2, 0.2))
|
||||||
|
#fh = lambda x: 0.8
|
||||||
|
#bbox = np.array([[-1, -1],[1, 1]])
|
||||||
|
#p, tri = get_mesh(fd, fh, 0.1, bbox, [])
|
||||||
|
#print_mesh(p, tri)
|
||||||
|
|
||||||
|
print("test 2")
|
||||||
|
import time
|
||||||
|
poly = np.array([[0,0],[0,1],[1,1],[1,2],[2,2],[2,1],[3,1],[3,0]])
|
||||||
|
polyG = geo.asPolygon(poly)
|
||||||
|
ringG = geo.asLinearRing(poly)
|
||||||
|
fd = lambda x: dpoly(x,poly)
|
||||||
|
fh = lambda x: 0.15-0.22*fd(x)
|
||||||
|
bbox = np.array([[0,0],[3,3]])
|
||||||
|
t = time.time()
|
||||||
|
p, tri = get_mesh(fd, fh, 0.1, bbox, poly)
|
||||||
|
elap = time.time()-t
|
||||||
|
print("prvi = {}s".format(elap))
|
||||||
|
fd = lambda x: _dpoly(geo.asPoint(x), polyG, ringG)
|
||||||
|
fh = lambda x: 0.15-0.22*fd(x)
|
||||||
|
t = time.time()
|
||||||
|
p, tri = get_mesh(fd, fh, 0.1, bbox, poly)
|
||||||
|
elap = time.time()-t
|
||||||
|
print("drugi = {}s".format(elap))
|
||||||
|
print_mesh(p, tri)
|
||||||
|
|
||||||
|
|
||||||
|
#print("test 3")
|
||||||
|
#fd = lambda x: drectangle(protate(x,np.pi/4),0,1,0,1)
|
||||||
|
#bbox = np.array([[-2,-2],[2,2]])
|
||||||
|
#p, tri = get_mesh(fd, fh, 0.08, bbox, [])
|
||||||
|
#print_mesh(p, tri)
|
Loading…
Reference in New Issue