get continuous edges respect to relative angle from group of edges

Need help, or want to share a macro? Post here!
Forum rules
Be nice to others! Respect the FreeCAD code of conduct!
Post Reply
User avatar
ebrahim raeyat
Posts: 619
Joined: Sun Sep 09, 2018 7:00 pm
Location: Iran
Contact:

get continuous edges respect to relative angle from group of edges

Post by ebrahim raeyat »

Hi. first, I don't know if it is a related topic.
I have a series of edges that meet each other on some point or not. I want to extract a series of continuous edges from this edges with one rule:

if angle between two edges is between for example 180 - 45 and 180. the 45 degree maybe vary from 0 to 45. for example in this shape:
1.png
1.png (17.91 KiB) Viewed 1422 times
2.png
2.png (21.62 KiB) Viewed 1422 times
I wrote a algorithm for this. It creates a table for each node and each edge that connect to it, the other edges of node that connect with this node with respect the angle between this edges and other edges.

I want to know is there a simple solution for this? thanks.

this is my functions, it needs pandas library.

Code: Select all

def get_similar_edge_direction_in_common_points_from_edges(edges : list) -> 'pd.DataFram':
	'''
	This function give a list of edges, find the common points of those edges.
	then for each point and each edge of all edges that connected to this point,
	it search for similarity direction with this edge. the df columns output is
	like "point edge 1 2 3 4" 
	'''

	import pandas as pd
	cols = ['edge', 'is_first', 'is_end', 'x', 'y', 'z']
	df = pd.DataFrame()
	for e in edges:
		v1, v2 = e.firstVertex(), e.lastVertex()
		se = pd.Series([e, True, False, v1.X, v1.Y, v1.Z], index=cols)
		df = df.append(se, ignore_index=True)
		se = pd.Series([e, False, True, v2.X, v2.Y, v2.Z], index=cols)
		df = df.append(se, ignore_index=True)
	group = df.groupby(['x','y', 'z'])
	max_number_edges_connect_to_point = group['edge'].count().max()
	additional_cols = [n for n in range(1, max_number_edges_connect_to_point)]
	df1 = pd.DataFrame(columns=['point', 'edge'] + additional_cols)
	for state, frame in group:
		edges_from_point = list(frame['edge'])
		for edge in edges_from_point:
			edges_without_curr_edge = set(edges_from_point).difference([edge])
			preferable_edges = get_in_direction_priority(edge, edges_without_curr_edge)
			none_exist_edge_len = max_number_edges_connect_to_point -  len(preferable_edges) - 1
			preferable_edges += none_exist_edge_len * [None]
			se = pd.Series([state, edge] +  preferable_edges, index=df1.columns)
			df1 = df1.append(se, ignore_index=True)
	map_dict_edges_to_num = dict()
	for i, e in enumerate(edges, start=1):
		map_dict_edges_to_num[e] = i
	edges_cols = ['edge'] + additional_cols
	for col in (edges_cols):
		df1[col] = df1[col].map(map_dict_edges_to_num)
	df1 = df1.fillna(0)
	for col in (edges_cols):
		df1[col] = df1[col].astype(int)
	return df1

def get_continuous_edges(edges : list):
	'''
	This function get a list of egdes and search for groups of egdes that create continuous edges in x or y direction
	'''
	df = get_similar_edge_direction_in_common_points_from_edges(edges)
	all_edges = []
	end = False
	used_edges = []
	continues_edges = []
	edges_cols = list(df.columns)[1:]
	additional_cols = edges_cols[1:]
	for i, row in df.iterrows():
		if end:
			all_edges.append(continues_edges)
			end = False
			df['edge'] = df['edge'].replace([previous_edge], 0)
			if df[edges_cols].sum().sum() == 0:
				break
			continues_edges = []
		while not end:
			if len(continues_edges) == 0:
				filt = (df['edge'] == 0) | (df[edges_cols].sum(axis=1) == 0)
				temp_df = df[~filt]
				if len(temp_df) == 0:
					end = True
					break
				j, temp_row = next(temp_df.iterrows())
				edge_num = temp_row['edge']
				point = row['point']
				if not edge_num in used_edges:
					continues_edges.append(edge_num)
					used_edges.append(edge_num)
				for col in edges_cols:
					df.at[j, col] = 0
				df[additional_cols] = df[additional_cols].replace([edge_num], 0)
				
			else:
				previous_edge = continues_edges[-1]
				filt = (df['edge'] == previous_edge) & (df['point'] != point)
				if not True in filt.values:
					end = True
					break
				temp_df = df.loc[filt]
				row_num = temp_df.index.to_list()[0]
				end = True
				for col in additional_cols:
					edge_num = temp_df.at[row_num, col]
					if edge_num != 0 and not edge_num in used_edges:
						continues_edges.append(edge_num)
						used_edges.append(edge_num)
						end = False
						point = df.at[row_num, 'point']
						df[additional_cols] = df[additional_cols].replace([edge_num], 0)
						df['edge'] = df['edge'].replace([previous_edge], 0)
						break
	return all_edges
	
def get_in_direction_priority(edge, edges,
		angle: int = 45):
	'''
	Getting an edge and calculate angle between edge and each member of edges and then
	sort them from large to small. angle is acceptable angle that ilustrate edge is in direction
	of other edges
	'''
	acceptable_anlge = 180 - angle
	if len(edges) == 0:
		return []
	edges_angles = []
	for e in edges:
		angle = angle_between_two_edges(edge, e)
		if angle == 0:
			angle = 180
		if angle < acceptable_anlge:
			continue
		edges_angles.append((e, angle))
	edges_angles.sort(key=lambda x: x[1], reverse=True)
	return [a[0] for a in edges_angles]

def dot(vector_a, vector_b):
	return vector_a[0]*vector_b[0]+vector_a[1]*vector_b[1]

def angle_between_two_edges(
	edge1 : Part.Edge,
	edge2 : Part.Edge,
	):
	# v1 = edge1.tangentAt(0)
	# dx1, dy1 = v1.x, v1.y
	# v2 = edge2.tangentAt(0)
	# dx2, dy2 = v2.x, v2.y
	# if abs(dx1) == abs(dx2): # if two edges are in the same direction, also if dx = 0
	# 	return 180
	p1, p2 = [v.Point for v in edge1.Vertexes]
	p3, p4 = [v.Point for v in edge2.Vertexes]
	p1, p2, p3, p4 = find_common_point(p1, p2, p3, p4)

	x1, x2, y1, y2 = p1.x, p2.x, p1.y, p2.y
	x3, x4, y3, y4 = p3.x, p4.x, p3.y, p4.y
	vector_a = [(x1 - x2), (y1 - y2)]
	vector_b = [(x3 - x4), (y3 - y4)]
	dot_prod = dot(vector_a, vector_b)
	magnitudes_a = dot(vector_a, vector_a) ** 0.5
	magnitudes_b = dot(vector_b, vector_b) ** 0.5
	angle = math.acos(dot_prod / magnitudes_b / magnitudes_a)
	ang_deg = math.degrees(angle)%360
	if ang_deg-180>=0:
		return 360 - ang_deg
	else: 
		return ang_deg

def find_common_point(p1, p2, p3, p4):
	if p1.isEqual(p3, .001):
		return p1, p2, p1, p4
	elif p1.isEqual(p4, .001):
		return p1, p2, p1, p3
	elif p2.isEqual(p3, .001):
		return p2, p1, p2, p4
	elif p2.isEqual(p4, .001):
		return p2, p1, p2, p3
User avatar
sliptonic
Veteran
Posts: 3457
Joined: Tue Oct 25, 2011 10:46 pm
Location: Columbia, Missouri
Contact:

Re: get continuous edges respect to relative angle from group of edges

Post by sliptonic »

Not really a Path/CAM topic. Moving to Python Scripting and Macros
User avatar
ebrahim raeyat
Posts: 619
Joined: Sun Sep 09, 2018 7:00 pm
Location: Iran
Contact:

Re: get continuous edges respect to relative angle from group of edges

Post by ebrahim raeyat »

sliptonic wrote: Sun Nov 14, 2021 3:56 pm Not really a Path/CAM topic. Moving to Python Scripting and Macros
Thanks, I completed the code. user can choose acceptable angle between edges to be continuous:
beams.png
beams.png (13.18 KiB) Viewed 1037 times
this is 45 degree angle:
45.png
45.png (30.64 KiB) Viewed 1037 times
and 20 degree:
20.png
20.png (32.76 KiB) Viewed 1037 times
if user reduce the acceptable angle, more continuous edges creates.
Post Reply