Step
1. open freecad software
2. switch to partdesign workbench
3. create body
4. create Sketch
5. the Sketch must empty Scketch and must be named to "Sketch"
6. select code in Macro --> Macros --> select file --> Edit --> Excecute by click green play button
7. the code may have bug please check the outer polygon and small polygon , triangle may not close form.
import numpy as np
import matplotlib.pyplot as plt
from scipy.spatial import Voronoi, voronoi_plot_2d
def det(a, b):
return a[0] * b[1] - a[1] * b[0]
def line_intersection(line1, line2):
xdiff = (line1[0][0] - line1[1][0], line2[0][0] - line2[1][0])
ydiff = (line1[0][1] - line1[1][1], line2[0][1] - line2[1][1])
div = det(xdiff, ydiff)
if div == 0:
return False
d = (det(*line1), det(*line2))
x = det(d, xdiff) / div
y = det(d, ydiff) / div
return (x, y)
# https://bryceboe.com/2006/10/23/line-segment-intersection-algorithm/
def ccw(A,B,C):
return (C[1]-A[1]) * (B[0]-A[0]) >= (B[1]-A[1]) * (C[0]-A[0])
# Return true if line segments AB and CD intersect
def segment_intersect(A,B,C,D):
return ccw(A,C,D) != ccw(B,C,D) and ccw(A,B,C) != ccw(A,B,D)
def create_line_from_point (A,B,C,bounary,start_x,start_Y,width,height):
R = B
S = B
for i in range(len(bounary)):
if segment_intersect(bounary[i][0],bounary[i][1],A,B):
R= line_intersection(bounary[i], (A,B) )
for i in range(len(bounary)):
if segment_intersect(bounary[i][0],bounary[i][1],B,C):
S= line_intersection(bounary[i], (B,C) )
if R!= False and S != False and R != S :
return [(A,R ),(R,S),(S,C)]
return [(A,B),(B,C)]
def find_intersection_point (A,B,bounary,start_x,start_Y,width,height):
R = B
for i in range(len(bounary)):
if segment_intersect(bounary[i][0],bounary[i][1],A,B):
R= line_intersection(bounary[i], (A,B) )
return R
return False
N= 30
width = 200
height = 200
start_x = -100
start_y = -100
lower_size = 3 # mm
point_close_minimum = 10
FREECAD_LINE_START = -1
IS_FILLTER_OUT_BOUNARY = False
# points = np.array([[0, 0], [0, 1], [0, 2], [1, 0], [1, 1], [1, 2],
# [2, 0], [2, 1], [2, 2]])
# print(points)
# points = np.random.random((N,2))
# points = points * [width,height] + [start_x,start_y]
NUM_X = 10
NUM_Y = 10
N = NUM_X * NUM_Y
step_x = width / NUM_X + 1
step_y = height / NUM_Y + 1
step_x_mid = step_x / 2
step_y_mid = step_y / 2
points = np.zeros((N,2))
k=0
for i in range(NUM_Y):
for j in range(NUM_X):
if i % 2 == 0 :
x = step_x * j
y = step_y * i
else:
x = step_x * j + step_x_mid
if x > width :
continue
y = step_y * i
points[k][0] = x
points[k][1] = y
k+=1
noise = np.random.random((N,2))
noise = noise * [step_x_mid,step_y_mid] - [step_x_mid/2,step_y_mid/2]
points = points+noise + [start_x,start_y]
#check no 2 point close too much
for i in range(len(points)):
for j in range(i+1,len(points)):
x1 = points[i][0]
y1 = points[i][1]
x2 = points[j][0]
y2 = points[j][1]
if (x1-x2)**2 + (y1-y2)**2 < point_close_minimum**2:
points[j][0] = -9999
points[j][1] = -9999
for i in range(len(points)-1 , -1 , -1):
if points[i][0] == -9999 and points[i][1] == -9999:
points = np.delete(points, i, 0)
vor = Voronoi(points)
fig = voronoi_plot_2d(vor)
plt.show()
# print("=======points========")
# print(points)
# print("=======vor.points========")
# print(vor.points)
# print("======vor.vertices=========")
# print(vor.vertices)
for i in range( len(vor.point_region)):
region = vor.regions[ vor.point_region[i] ] #index of vertex
isInfinityPoint = False
for j in range(len (region)):
if region[j] == -1 :
isInfinityPoint = True
break
if isInfinityPoint :
continue
print("region",region)
#find edge
edge = [] #index of ridge
for j in range(len(region)):
for k in range(j+1,len(region)):
for ll in range(len(vor.ridge_vertices)):
if ( (vor.ridge_vertices[ll][0] == region[j] and vor.ridge_vertices[ll][1] == region[k]) or
(vor.ridge_vertices[ll][1] == region[j] and vor.ridge_vertices[ll][0] == region[k])
):
edge.append((region[j],region[k]))
edgesorted = []
edgesorted.append(edge[0])
edge = edge[1:]
while len(edge) > 0:
isRemoved = False
for j in range(len(edge)):
if edge[j][0] == edgesorted[-1][1] :
edgesorted.append(edge[j])
edge.remove(edge[j])
isRemoved= True
break
if edge[j][1] == edgesorted[-1][1] :
edgesorted.append( (edge[j][1] ,edge[j][0] ) )
edge.remove(edge[j])
isRemoved= True
break
if not isRemoved :
break
# print("sorted edge : " , edgesorted)
top_left = [start_x + lower_size , start_y + height - lower_size]
top_right = [start_x + width - lower_size , start_y + height - lower_size]
buttom_left = [start_x + lower_size , start_y + lower_size]
buttom_right = [start_x + width - lower_size , start_y + lower_size]
top_left_inner = [start_x + lower_size + 1 , start_y + height - lower_size - 1 ]
top_right_inner = [start_x + width - lower_size - 1 , start_y + height - lower_size - 1 ]
buttom_left_inner = [start_x + lower_size +1 , start_y + lower_size+1]
buttom_right_inner = [start_x + width - lower_size -1 , start_y + lower_size+1]
innerVertices = np.empty( [len(region),2 ])
# collect all vertex for this region
point_now = {}
for j in range(len (region)):
innerVertices[j][0] = vor.vertices[region[j]][0]
innerVertices[j][1] = vor.vertices[region[j]][1]
point_now[region[j]] = innerVertices[j]
# if innerVertices[j][0] < start_x+ lower_size :
# innerVertices[j][0] = start_x + lower_size
# if innerVertices[j][1] < start_y+ lower_size :
# innerVertices[j][1] = start_y + lower_size
# if innerVertices[j][0] > start_x + width -lower_size:
# innerVertices[j][0] = start_x + width -lower_size
# if innerVertices[j][1] > start_y + height -lower_size :
# innerVertices[j][1] = start_y + height - lower_size
# print("----")
# print(innerVertices)
# print("----")
# print(point_now)
####################################
upper_line = (top_left,top_right)
lower_line = (buttom_left,buttom_right)
left_line = (top_left,buttom_left)
right_line = (top_right,buttom_right)
upper_line_inner = (top_left_inner ,top_right_inner)
lower_line_inner = (buttom_left_inner ,buttom_right_inner)
left_line_inner = (top_left_inner ,buttom_left_inner)
right_line_inner = (top_right_inner ,buttom_right_inner)
bounary = []
bounary.append(upper_line)
bounary.append(lower_line)
bounary.append(left_line)
bounary.append(right_line)
bounary_inner = []
bounary_inner.append(upper_line_inner)
bounary_inner.append(lower_line_inner)
bounary_inner.append(left_line_inner)
bounary_inner.append(right_line_inner)
############################ MOVE POINT OUTSIDE BOUNARY TO BOUNARY ##################
j=0
while j < len(edgesorted):
x1 = point_now[edgesorted[j][0]][0]
y1 = point_now[edgesorted[j][0]][1]
x2 = point_now[edgesorted[j][1]][0]
y2 = point_now[edgesorted[j][1]][1]
line_now = ( [x1,y1],[x2,y2])
Point1Out = False
if x1 < start_x+ lower_size-1 :
Point1Out = True
elif y1 < start_y+ lower_size-1 :
Point1Out = True
elif x1 > start_x + width -lower_size+1:
Point1Out = True
elif y1 > start_y + height -lower_size +1:
Point1Out = True
Point2Out = False
if x2 < start_x+ lower_size -1:
Point2Out = True
elif y2 < start_y+ lower_size -1:
Point2Out = True
elif x2 > start_x + width -lower_size+1:
Point2Out = True
elif y2 > start_y + height -lower_size +1:
Point2Out = True
if Point1Out and Point2Out :
del edgesorted[j]
j-=1
elif ( segment_intersect( [x1,y1],[x2,y2] ,top_left ,top_right) or
segment_intersect( [x1,y1],[x2,y2] ,top_left ,buttom_left) or
segment_intersect( [x1,y1],[x2,y2] ,top_right ,buttom_right) or
segment_intersect( [x1,y1],[x2,y2] ,buttom_left ,buttom_right)
):
# case the line segment interset bounary
if Point1Out :
R = find_intersection_point( (x1,y1),(x2,y2), bounary, start_x , start_y , width , height)
pIndex = len(point_now) + 200000
point_now[pIndex] = [R[0],R[1]]
edgesorted.insert( j+1 ,(pIndex,edgesorted[j][1]))
del edgesorted[j]
elif Point2Out :
R = find_intersection_point( (x1,y1),(x2,y2), bounary, start_x , start_y , width , height)
pIndex = len(point_now) + 200000
point_now[pIndex] = [R[0],R[1]]
edgesorted.insert( j+1 ,(edgesorted[j][0],pIndex) )
del edgesorted[j]
j+=1
print("sorted edge : " , edgesorted)
print("point now",point_now)
if IS_FILLTER_OUT_BOUNARY and len(edgesorted)>3 :
########### filter outside point##############
j=0
while j < len(edgesorted) and len(edgesorted)>3 and False:
x1 = point_now[edgesorted[j][0]][0]
y1 = point_now[edgesorted[j][0]][1]
x2 = point_now[edgesorted[j][1]][0]
y2 = point_now[edgesorted[j][1]][1]
if x1 < start_x+ lower_size-1 :
del edgesorted[j]
j-=1
elif y1 < start_y+ lower_size-1 :
del edgesorted[j]
j-=1
elif x1 > start_x + width -lower_size+1:
del edgesorted[j]
j-=1
elif y1 > start_y + height -lower_size +1:
del edgesorted[j]
j-=1
elif x2 < start_x+ lower_size -1:
del edgesorted[j]
j-=1
elif y2 < start_y+ lower_size -1:
del edgesorted[j]
j-=1
elif x2 > start_x + width -lower_size+1:
del edgesorted[j]
j-=1
elif y2 > start_y + height -lower_size +1:
del edgesorted[j]
j-=1
j+=1
############CONNECT LINE #############
j=0
while j < len(edgesorted)-1 :
x1 = point_now[edgesorted[j][0]][0]
y1 = point_now[edgesorted[j][0]][1]
x2 = point_now[edgesorted[j][1]][0]
y2 = point_now[edgesorted[j][1]][1]
x3 = point_now[edgesorted[j+1][0]][0]
y3 = point_now[edgesorted[j+1][0]][1]
x4 = point_now[edgesorted[j+1][1]][0]
y4 = point_now[edgesorted[j+1][1]][1]
if(x2 != x3 or y2 != y3):
edgesorted.insert(j+1 , (edgesorted[j][1],edgesorted[j+1][0]) )
j+=1
if len(edgesorted)-1 >= 0 :
x1 = point_now[edgesorted[ len(edgesorted)-1][0]][0]
y1 = point_now[edgesorted[ len(edgesorted)-1][0]][1]
x2 = point_now[edgesorted[ len(edgesorted)-1][1]][0]
y2 = point_now[edgesorted[ len(edgesorted)-1][1]][1]
x3 = point_now[edgesorted[0][0]][0]
y3 = point_now[edgesorted[0][0]][1]
x4 = point_now[edgesorted[0][1]][0]
y4 = point_now[edgesorted[0][1]][1]
if(x2 != x3 or y2 != y3):
edgesorted.append( (edgesorted[ len(edgesorted)-1][1],edgesorted[0][0]) )
print(len(edgesorted)-1)
print(edgesorted[ len(edgesorted)-1][0])
print(point_now[edgesorted[ len(edgesorted)-1][0]])
print("edgesorted after add edge -->",edgesorted)
#calculate real point with offset
for key in point_now.keys():
point_now[key][0] = ( point_now[key][0] - vor.points[i][0] )*0.8 + vor.points[i][0]
point_now[key][1] = ( point_now[key][1] - vor.points[i][1] )*0.8 + vor.points[i][1]
###################################################################################
# for j in range (len(edgesorted)) :
Gui.runCommand('Sketcher_CreatePolyline',0)
j=0
while j < len(edgesorted):
x1 = point_now[edgesorted[j][0]][0]
y1 = point_now[edgesorted[j][0]][1]
x2 = point_now[edgesorted[j][1]][0]
y2 = point_now[edgesorted[j][1]][1]
line_now = ( [x1,y1],[x2,y2])
App.getDocument('Unnamed').getObject('Sketch').addGeometry(
Part.LineSegment(App.Vector(x1,y1),
App.Vector(x2,y2))
,False)
# App.ActiveDocument.recompute()
FREECAD_LINE_START = FREECAD_LINE_START + 1
if j == 0:
LINE_START_BEFORE_POLYGON = FREECAD_LINE_START
if j > 0 :
# print("constain --> " ,'Coincident',FREECAD_LINE_START-1,2,FREECAD_LINE_START,1 )
App.getDocument('Unnamed').getObject('Sketch').addConstraint(Sketcher.Constraint('Coincident',FREECAD_LINE_START-1,2,FREECAD_LINE_START,1))
# App.ActiveDocument.recompute()
j=j+1
App.getDocument('Unnamed').getObject('Sketch').addConstraint(Sketcher.Constraint('Coincident',LINE_START_BEFORE_POLYGON,1,FREECAD_LINE_START,2))
App.ActiveDocument.recompute()
#################################
please see the video at
Tag ที่น่าสนใจ: python programming voronoi pattern freecad numpy matplotlib scipy spatial intersection algorithm line segment visualization plotting
หากมีข้อผิดพลาด/ต้องการพูดคุยเพิ่มเติมเกี่ยวกับบทความนี้ กรุณาแจ้งที่ http://m.me/Expert.Programming.Tutor
085-350-7540 (DTAC)
084-88-00-255 (AIS)
026-111-618
หรือทาง EMAIL: NTPRINTF@GMAIL.COM
Copyright (c) 2013 expert-programming-tutor.com. All rights reserved. | 085-350-7540 | 084-88-00-255 | ntprintf@gmail.com