OverviewFilesCommitsIssuesDocsReleasesPeers

Attila772-hypergodot commits / 2b79876

Offset circle error fixed
There was an error where the edges overlapped, and even got the same offset circle, so they sat on the same arc, overlapping completely. This is now solved, as the offset circles are calculated correctly.
2b79876c693016aa9b1ecc72b38abe613394e755
by Attila772 <71554727+Attila772@users.noreply.github.com> · 2024-10-29T10:34:16.000Z

Changed files (8) +97 -91

HyperEdge.gd +9 -46
……@@ -24,10 +24,14 @@ func _draw():
2424 var points = []
2525 for node_id in nodes:
2626 var node = get_node_from_group(node_id)
27
2728 if node:
2829 var center = node.position
29 var radius = nodes[node_id] * node.scale.x # Adjust radius based on node scale
30 points += generate_circle_points(center, radius, 100) # Generate circle points
30 var radius = nodes[node_id]
31 points += generate_circle_points(center, radius,50) # Generate circle points
32 # Draw each point as a small circle for visibility
33 for point in points:
34 draw_circle(point, 2, Color(1, 0, 0)) # Red color, radius 2
3135
3236 # Compute the convex hull of the points
3337 var hull = andrew_monotone_chain(points)
……@@ -79,60 +83,20 @@ func find_lowest_point(points):
7983 lowest = point
8084 return lowest
8185
82func sort_points_by_angle(points, p0):
83 points.sort_custom(func(a, b):
84 var angle_a = calculate_polar_angle(a, p0)
85 var angle_b = calculate_polar_angle(b, p0)
86 return angle_a < angle_b # For ascending order; use '>' for descending
87 )
88 return points
89
90func calculate_polar_angle(a, p0):
91 var dy = a.y - p0.y
92 var dx = a.x - p0.x
93 var angle = atan2(dy, dx)
94 return angle
95
96func compare_polar_angle(p0, a, b):
97 var o = orientation(p0, a, b)
98 if o == 0: # Collinear
99 return p0.distance_to(a) < p0.distance_to(b)
100 return o == 2 # Clockwise or counterclockwise
101
102func graham_scan(points):
103 if points.size() < 3:
104 return []
105
106 var p0 = find_lowest_point(points)
107 var sorted_points = sort_points_by_angle(points.duplicate(), p0)
108 var stack = []
109 stack.append(p0)
110 stack.append(sorted_points[1])
111 stack.append(sorted_points[2])
112
113 for i in range(3, sorted_points.size()):
114 while stack.size() >= 2 and orientation(stack[stack.size() - 2], stack[stack.size() - 1], sorted_points[i]) != 2:
115 stack.pop_back()
116 stack.append(sorted_points[i])
117
118 return stack
11986
12087func andrew_monotone_chain(points):
12188 if points.size() < 3:
12289 return points
123
12490 # Sort points
12591 points.sort_custom(func(a, b):
12692 return a.x < b.x if a.x != b.x else a.y < b.y
12793 )
128
129 # BLower hull
94 # Lower hull
13095 var lower = []
13196 for p in points:
13297 while lower.size() >= 2 and cross(lower[lower.size() - 2], lower[lower.size() - 1], p) <= 0:
13398 lower.pop_back()
13499 lower.append(p)
135
136100 # Upper hull
137101 var upper = []
138102 for i in range(points.size() - 1, -1, -1):
……@@ -140,10 +104,9 @@ func andrew_monotone_chain(points):
140104 while upper.size() >= 2 and cross(upper[upper.size() - 2], upper[upper.size() - 1], p) <= 0:
141105 upper.pop_back()
142106 upper.append(p)
143
144 # Concatenate the lower and upper hulls
107 # Concatenate the hulls
145108 # The first and last points in lower will be the same as the last two points in upper,
146 # so we omit them from the result
109 # so we pop them from the result
147110 lower.pop_back()
148111 upper.pop_back()
149112 return lower + upper
HyperNode.gd +18 -7
……@@ -69,15 +69,26 @@ func update_size(size_scale: float, new_centrality_score: float):
6969
7070func make_offset_circles():
7171 offset_circles.clear()
72 var circle_count = edges.size()
7372 var scale_factor = (scale.x + scale.y) / 2
7473 var base_radius = 25 * scale_factor
75 var radius_increment = 10 * scale_factor
76
77 for i in range(circle_count):
78 var radius = base_radius + i * radius_increment
79 offset_circles.append(radius)
80
74 var cumulative_radius = base_radius
75 var edge_widths = []
76 for edge_id in edges.keys():
77 var edge_support = edges[edge_id]
78 var edge_width = pow(edge_support, 0.35) # Function to calculate edge width based on support
79 edge_widths.append(edge_width)
80
81 for i in range(edge_widths.size()):
82 var edge_width = edge_widths[i]
83 # Increase the radius by half of the previous edge's width and half of the current edge's width
84 # This ensures that the edges do not overlap
85 if i == 0:
86 cumulative_radius += edge_width / 2
87 else:
88 cumulative_radius += (edge_widths[i - 1] / 2) + (edge_width / 2)
89
90 offset_circles.append(cumulative_radius)
91 # cumulative_radius += edge_width / 2 # Prepare for the next edge (not needed here)
8192 queue_redraw()
8293
8394
Times New Roman.ttf.import +1 -0
……@@ -15,6 +15,7 @@ dest_files=["res://.godot/imported/Times New Roman.ttf-5309258ee4eb8e8a0e31d33c7
1515Rendering=null
1616antialiasing=1
1717generate_mipmaps=false
18disable_embedded_bitmaps=true
1819multichannel_signed_distance_field=false
1920msdf_pixel_range=8
2021msdf_size=48
main.gd +57 -30
……@@ -40,52 +40,78 @@ func create_nodes(nodes: Dictionary):
4040
4141func populate_edge_data(file_data):
4242 var hyperedge_scene = load("res://HyperEdge.tscn")
43 var nodes = file_data["nodes"] # Retrieve nodes from the file data
44 var edges = file_data["edges"] # Retrieve edges from the file data
45
43 var nodes = file_data["nodes"] # Retrieve nodes from the file data
44 var edges = file_data["edges"] # Retrieve edges from the file data
45
4646 var group_names = []
4747 for edge_id in edges:
4848 var group_name = edges[edge_id]["group"]
4949 if group_name not in group_names:
5050 group_names.append(group_name)
5151 Global.initialize_groups(group_names)
52 # Iterate over nodes to build edge data based on node connections
52
53 # Step 1: Build a per-node mapping of edge IDs to radii
54 var node_edge_radius_map = {} # Dictionary mapping node_id to {edge_id: radius}
5355 for node_id in nodes:
5456 var node_edges = nodes[node_id].edges
55 var circle_ref = get_node(str(node_id)) # Assuming this gets a node instance with 'offset_circles'
56 var offset_circles = circle_ref.offset_circles # List of radii for offset circles
57 for edge_index in range(node_edges.size()):
58 var edge_id = node_edges.keys()[edge_index]
59 if not edges.has(edge_id):
60 edges[edge_id] = {"nodes": [], "radii": [], "support": 0, "group": ""}
61
62
63 if edge_index < offset_circles.size(): # Ensure there's a corresponding circle
64 var radius = offset_circles[edge_index]
65 print(offset_circles[edge_index])
66
67 # Append node and radius information for the edge
68
69 edges[edge_id]["radii"].append(radius)
70 edges[edge_id]["support"] = nodes[node_id].edges[edge_id] # Support value
71 edges[edge_id]["group"] = edges[edge_id]["group"] # Group is already stored in the edges dictionary
72
57 var circle_ref = get_node(str(node_id)) # Get node instance with 'offset_circles'
58 var offset_circles = circle_ref.offset_circles # List of radii for offset circles
59
60 var edge_ids = node_edges.keys()
61 var edge_radius_map = {}
62
63 # Ensure there are enough radii for each edge
64 if offset_circles.size() < edge_ids.size():
65 print("Error: Node %s has more edges (%s) than offset circles provided." % [node_id, edge_ids.size()])
66 continue # Skip this node if radii are insufficient
67
68 # Map each edge_id to its corresponding radius for this node
69 for i in range(edge_ids.size()):
70 var edge_id = edge_ids[i]
71 var radius = offset_circles[i]
72 edge_radius_map[edge_id] = radius
73
74 node_edge_radius_map[node_id] = edge_radius_map
75
76 # Step 2: Build edges data using node_edge_radius_map
77 for edge_id in edges:
78 var edge_nodes = edges[edge_id]["nodes"] # Nodes connected by this edge
79 var edge_radii = []
80 var edge_node_ids = []
81
82 for node_id in edge_nodes:
83 if node_edge_radius_map.has(node_id):
84 var edge_radius_map = node_edge_radius_map[node_id]
85 if edge_radius_map.has(edge_id):
86 var radius = edge_radius_map[edge_id]
87 edge_node_ids.append(node_id)
88 edge_radii.append(radius)
89 else:
90 print("Error: Edge radius not found for node %s and edge %s" % [node_id, edge_id])
7391 else:
74 print("Error: Node %s has more edges (%s) than offset circles provided." % [node_id, node_edges.size()])
75 break
92 print("Error: Node %s not found in node_edge_radius_map" % node_id)
7693
77 # Instantiate hyperedges and visualize them
94 # Update edges[edge_id] with aligned nodes and radii
95 edges[edge_id]["nodes"] = edge_node_ids
96 edges[edge_id]["radii"] = edge_radii
97
98 # Step 3: Instantiate hyperedges and visualize them
7899 for edge_id in edges:
79100 var hyperedge_instance = hyperedge_scene.instantiate()
80101 var edge_data = edges[edge_id]
81102 var node_radii_pairs = {}
82103
104 # Ensure nodes and radii arrays are aligned
105 if edge_data["nodes"].size() != edge_data["radii"].size():
106 print("Error: Mismatch between nodes and radii sizes for edge", edge_id)
107 continue # Skip this edge if there's a mismatch
108
83109 # Map each node to its radius
84110 for i in range(edge_data["nodes"].size()):
85111 var nodeid = edge_data["nodes"][i]
86112 var radius = edge_data["radii"][i]
87113 node_radii_pairs[nodeid] = radius
88
114
89115 # Assign the nodes and radii to the hyperedge instance
90116 hyperedge_instance.nodes = node_radii_pairs
91117
……@@ -93,7 +119,7 @@ func populate_edge_data(file_data):
93119 var color = Color(randf(), randf(), randf(), 0.3) # Generate a random color
94120 hyperedge_instance.color = color
95121
96 # Set the group name (2021 or 2022) to the hyperedge instance for future use
122 # Set the group name to the hyperedge instance for future use
97123 hyperedge_instance.group = edge_data["group"]
98124
99125 hyperedge_instance.add_to_group("edges")
……@@ -101,10 +127,11 @@ func populate_edge_data(file_data):
101127
102128 # Set the width of the hyperedge based on the support value
103129 hyperedge_instance.width = pow(edges[edge_id]["support"], 0.35)
104
130
105131 # Add the hyperedge instance to the scene tree
106132 add_child(hyperedge_instance)
107133
134
108135
109136
110137func _ready():
……@@ -282,12 +309,12 @@ func calculate_centrality_and_resize_nodes(file_data):
282309 var centrality_scores = {}
283310
284311 # Calculate centrality (degree centrality in this case)
285 print(nodes)
312
286313 for node_id in nodes:
287314 var degree = nodes[node_id].edges.size()
288315 centrality_scores[node_id] = degree
289316 max_centrality = max(max_centrality, degree)
290 print(centrality_scores)
317
291318 # Resize nodes based on centrality
292319 for node_id in nodes:
293320 var node_instance = get_node(str(node_id))
pat704F.tmp +4 -0
……@@ -0,0 +1,4 @@
1Energy_and_Extractives Oil_and_Gas_Policy,_Strategy_and_Institutions #SUP: 457 #GROUP 2022
2Energy_and_Extractives Environment_and_Natural_Resources Renewable_Energy #SUP: 211 #GROUP 2022
3Energy_and_Extractives Climate_Change Renewable_Energy #SUP: 213 #GROUP 2022
4Health_Emergency_Preparedness_and_Disaster_Response Energy_and_Extractives #SUP: 657 #GROUP 2022
patD2D1.tmp +4 -0
……@@ -0,0 +1,4 @@
1Energy_and_Extractives Oil_and_Gas_Policy,_Strategy_and_Institutions #SUP: 457
2Energy_and_Extractives Environment_and_Natural_Resources Renewable_Energy #SUP: 211
3Energy_and_Extractives Climate_Change Renewable_Energy #SUP: 213
4Health_Emergency_Preparedness_and_Disaster_Response Energy_and_Extractives #SUP: 657
patterns.txt +2 -2
……@@ -1,6 +1,6 @@
11Environment_and_Natural_Resources Pollution_Management #SUP: 2662 #GROUP 2022
22Energy_and_Extractives Energy_Efficiency #SUP: 3163 #GROUP 2022
3Health_Emergency_Preparedness_and_Disaster_Response Energy_and_Extractives #SUP: 7720 #GROUP 2022
3Energy_and_Extractives Health_Emergency_Preparedness_and_Disaster_Response #SUP: 7720 #GROUP 2022
44Environment_and_Natural_Resources Pollution_Management Air_Pollution #SUP: 3312 #GROUP 2023
5Energy_and_Extractives Climate_Change Environment_and_Natural_Resources Renewable_Energy #SUP: 3301 #GROUP 2023
5Environment_and_Natural_Resources Energy_and_Extractives Climate_Change Renewable_Energy #SUP: 3301 #GROUP 2023
66Energy_and_Extractives Health_Emergency_Preparedness_and_Disaster_Response #SUP: 5647 #GROUP 2023
project.godot +2 -6
……@@ -12,17 +12,13 @@ config_version=5
1212
1313config/name="Hypergodot"
1414run/main_scene="res://main.tscn"
15config/features=PackedStringArray("4.2", "Forward Plus")
15config/features=PackedStringArray("4.3", "Forward Plus")
1616config/icon="res://icon.svg"
1717
1818[autoload]
1919
2020Global="*res://Global.gd"
2121
22[debug]
23
24settings/stdout/print_fps=true
25
2622[display]
2723
2824window/vsync/vsync_mode=0
……@@ -33,7 +29,7 @@ project/assembly_name="Hypergodot"
3329
3430[editor_plugins]
3531
36enabled=PackedStringArray("res://addons/kanban_tasks/plugin.cfg")
32enabled=PackedStringArray()
3733
3834[input]
3935