
| Current Path : /home/cgabriel/20_dev/12_procpy/dataninja/ |
Linux ift1.ift-informatik.de 5.4.0-216-generic #236-Ubuntu SMP Fri Apr 11 19:53:21 UTC 2025 x86_64 |
| Current File : //home/cgabriel/20_dev/12_procpy/dataninja/rearr_grid.py |
import os
import sys
import re
import math
import procpy
import tkinter
import random
try:
import json
except:
import pip
pip.main(["install","json"])
import json
#************************************************************************
class Rearr_grid (object):
def __init__ (self,graph):
self.graph = graph
self.max_w = graph.zoom_factor*70
self.min_w = graph.zoom_factor*10
#************************************************************************
# not execute anywhere.
def rearrange (self,griddata,mode):
if mode == 0:
self.fit_blocks_to_grid(griddata)
self.newbends_for_arrows()
return(griddata)
# This function never be used by any model except reaarange
#************************************************************************
# This function never be used by any model
def fit_blocks_to_grid (self,griddata):
for block in self.graph.blocks:
x = griddata['X'] * int((block.bbox[0] + 0.5*griddata['X'])/griddata['X'])
y = griddata['Y'] * int((block.bbox[1] + 0.5*griddata['Y'])/griddata['Y'])
dx = block.bbox[0] - x
dy = block.bbox[1] - y
block.newbbox = [ block.bbox[0] - dx, block.bbox[1] - dy,
block.bbox[2] - dx, block.bbox[3] - dy ]
return()
#************************************************************************
def newbends_for_arrows (self):
print("newbends_for_arrows-nxs")
for block in self.graph.blocks:
block.define_exit_and_enter() # set back to general exit/entrance
for block in self.graph.blocks:
for arrow in block.arrows_out:
try:
del arrow.channels # old channelas are removed
del arrow.dir # old direction of arrow is removed
except:
continue
for arrow in block.arrows_out:
jump = arrow.target_block
# block is source, arrow out; jump is target, arrow in. by nxs
arrow.channels, arrow.dir = self.compute_channels(block,jump)
arrow.anchorline = 0
self.compare_channels()
self.choose_points_from_channels()
#************************************************************************
#
def choose_direction(self, source, target, var):
# use local variable
var1 = var
# if there is only one single main direction in var (w, n, s, e): return
if len(var1)==1:
return var1
# calculate target midpoint and bisecting lines of the source block (calc. at target_midpoint)
target_midpoint = [(target.bbox[0]+target.bbox[2])/2,(target.bbox[1]+target.bbox[3])/2]
# define two main directions for the general comparison below
if "w" in var1 and "e" in var1 and "n" in var1 and "s" in var1:
dir1 = "n"
dir2 = "wse"
elif "w" in var1 and "e" in var1:
dir1 = var1.replace("w","").replace("e","")
dir2 = "we"
elif "n" in var1 and "s" in var1:
dir1 = var1.replace("n","").replace("s","")
dir2 = "ns"
elif "s" in var1: # len of var1 is two
dir1 = var1.replace("s","")
dir2 = "s"
elif "n" in var1:
dir2 = "n" # len of var1 is two
dir1 = var1.replace("n","")
G1 = 0
if dir2 == "we" or dir2=="wse":
t = target_midpoint[0]
if dir1 in "sn":
G1 = source.newbbox[0]
G2 = source.newbbox[2]
else:
G1 = 0
G2 = (source.newbbox[0]+source.newbbox[2])/2
dir1 = "w"
dir2 = "e"
else:
t = target_midpoint[1]
G1 = source.newbbox[1]
G2 = source.newbbox[3]
if dir2 == "n":
G2 = 999999
elif dir2 == "s":
G1 = 0
elif dir1 == "":
G1 = 0
G2 = (source.newbbox[1]+source.newbbox[3])/2
dir1 = "n"
dir2 = "s"
if G1 < t < G2:
re = dir1
else:
re = dir2
if len(re)>1:
re = self.choose_direction(source, target, re)
# print re
return re
#************************************************************************
def adjust_exit_and_entrance(self, block,shape,exit="",entrance=""):
'''
gives the possibility to change the exit and entrance definition of the block
depending on the shape of the block
'''
if block.shape in shape:
exit = block.exit.replace(exit, "")
entrance = block.entrance.replace(entrance, "")
block.define_exit_and_enter(exit, entrance)
#************************************************************************
# define the arrow exit position , by nxs
def define_starting_channel(self,source, target, nextdirection):
exit = self.choose_direction(source,target, source.exit)
self.adjust_exit_and_entrance(source,"iwfm", exit,"")# SHAPE-002 VALID: for diamonds: only one arrow exit on each side
if exit in "we": #arrows should exit in east or west
newchannel = [source.newbbox[1],source.newbbox[3]]
first_dir = 'X' #modify by nxs
if exit == "e":
channel_length = [source.newbbox[2]]
channel_length.append({True: nextdirection['Y'][1], False:source.newbbox[2]+self.max_w}[target.newbbox[0]>source.newbbox[2]+self.min_w])
elif exit == "w":
channel_length = [max(0,min(nextdirection['Y'][0],source.newbbox[0]-self.max_w)),source.newbbox[0]]
elif exit in "ns": #arrows should exit in north or south
newchannel = [source.newbbox[0],source.newbbox[2]]
first_dir = 'Y'
if exit == "n" :
channel_length = [max(0,min(source.newbbox[1]-self.max_w,nextdirection['X'][0])),source.newbbox[1]]
elif exit == "s":
channel_length = [source.newbbox[3],max(source.newbbox[3]+self.max_w,nextdirection['X'][1])]
# else: #####
# newchannel = [source.newbbox[1],source.newbbox[3]]
# channel_length = [min(source.newbbox[2],nextdirection['Y'][0]),max(source.newbbox[0],nextdirection['Y'][1])]
# first_dir = 'X'
return newchannel, channel_length, first_dir, exit
#************************************************************************
def define_nextdirection(self,source, target):
nextdirection = {'Y':[],'X':[]}
#by NXS
entrance = self.choose_direction(target, source, target.entrance)
self.adjust_exit_and_entrance(target,"iwfm", "",entrance)# SHAPE-002 VALID: for diamonds: only one arrow enter on each side
#### define nextdirection if entrance is west/east
### nxs
if entrance =="w":
nextdirection['Y'].append({True: max(source.newbbox[2],target.newbbox[0]-self.max_w),
False: max(0,target.newbbox[0]-self.max_w)}[source.newbbox[2]<target.newbbox[0]-self.min_w])
nextdirection['Y'].append(target.newbbox[0])
elif entrance == "e":
nextdirection['Y'].append(target.newbbox[2])
nextdirection['Y'].append({True: min(source.newbbox[0],target.newbbox[2]+self.max_w),
False: target.newbbox[2]+self.max_w}[source.newbbox[0]>target.newbbox[2]+self.min_w])
else:
nextdirection['Y'] = [target.newbbox[0],target.newbbox[2]]
#### define nextdirection if entrance is north/south
if entrance =="n":
nextdirection['X'].append({True: max(source.newbbox[3],target.newbbox[1]-self.max_w),
False: max(0,target.newbbox[1]-self.max_w)}[source.newbbox[3]<target.newbbox[1]-self.min_w])
nextdirection['X'].append(target.newbbox[1])
elif entrance == "s":
nextdirection['X'].append(target.newbbox[3])
nextdirection['X'].append({True: min(source.newbbox[1],target.newbbox[3]+self.max_w),
False: target.newbbox[3]+self.max_w}[source.newbbox[1]>target.newbbox[3]+self.min_w])
else:
nextdirection['X'] = [target.newbbox[1],target.newbbox[3]]
return nextdirection # <-- ENDREQ
#************************************************************************
def compute_channels(self,source, target):
nextdirection = self.define_nextdirection(source, target) # define nextdirection depending on entrance of target
newchannel, channel_length, first_dir, arrow_dir = self.define_starting_channel(source, target, nextdirection)
direction = first_dir # the direction of the current newchannel, x or y
target_dock ={'Y':[target.newbbox[1],target.newbbox[3]],'X':[target.newbbox[0],target.newbbox[2]]}
target_reached = 0 # is 1 if target is reached
channel = [] # the computed channels
count = 0 # counts the channels
secondrun = True # determines the trys to create fitting channels
### Definition of mode: how to go around blocks #####
if source.newbbox[3]>=target.newbbox[3]: # evtl. anpassung noetig in y-direction
mode = 1
else:
mode = 0
while target_reached == 0:
### Not-Stopp ####################################
if count>=20:
if not secondrun:
mode = {1:0,0:1}[mode]
newchannel = channel[0]
channel = []
count = 0
secondrun = True
else:
print("*********************************************")
print("**** Please reorder your blocks *************")
print("*********************************************")
return
direction = {'X':'Y','Y':'X'}[direction]
### calculate optimal width of newchannel ############
newchannel = self.channel_optimal_width(newchannel, channel_length, direction)
### append optimal newchannel to channel #############
channel.append(newchannel)
leftright=nextdirection[direction][1]>=channel_length[1]
#target.newbbox[3]>=channel_length[1],'Y':target.newbbox[2]>=channel_length[1]}
# unten_ leftright[direction]
### new channel ####################################
newchannel = self.new_channel(newchannel,channel_length, direction,
nextdirection[direction][1]>=channel_length[1])
### if old direction is chosen again ###############
if len(channel)>=2 and newchannel!="" and (abs(newchannel[0]-channel[-2][0])<1 or abs(newchannel[1]-channel[-2][1])<1): # and in or geaendert
if mode == 0:
newchannel= [max(0,channel[-1][0]-self.max_w), channel[-1][0]]
else:
newchannel= [channel[-1][1], channel[-1][1]+self.max_w]
del channel[-1]
direction={'X':'Y','Y':'X'}[direction]
### no newchannel was calculated ####################
if newchannel=="":
### nextdirection can not be taken because it does not intersect with current channel
if nextdirection[direction][1]<=channel_length[0] or nextdirection[direction][0]>=channel_length[1]: # --> SHAPE-001-VALID
newchannel = channel_length # <-- ENDREQ
elif channel[-1][0] < (target_dock[direction][0]+target_dock[direction][1])/2 < channel[-1][1]:
# target_block and channel overlap but are note exactly on the same level; only if source doesnt have diamond/circle shape!
target_reached = 1
channel[-1] = self.docking(channel[-1], source, target, target_dock[direction])
elif (target_dock[direction][0]-channel[-1][0]<=0.5 and # --> BUG-0002-VALID
target_dock[direction][1]-channel[-1][1]>=-0.5): # <-- ENDREQ
### target is reached
target_reached = 1
else:
### take the shortest possible way
newchannel = nextdirection[direction]
#### Channel length ################################
diff1 = nextdirection[{'X':'Y','Y':'X'}[direction]][0] - channel[-1][0] # --> SHAPE-001-VALID
diff2 = nextdirection[{'X':'Y','Y':'X'}[direction]][1] - channel[-1][1]
if (diff1<=0) and (diff2>=0):
channel_length = channel[-1]
else:
channel_length = [min(channel[-1][0],nextdirection[{'X':'Y','Y':'X'}[direction]][0]),
max(channel[-1][1],nextdirection[{'X':'Y','Y':'X'}[direction]][1])] # <-- ENDREQ
count += 1
return channel, arrow_dir
#**************************************************************
def docking(self, channel, source, target, target_dock):
# target_block and channel overlap but are note exactly on the same level
if target.shape in "iwfm":
# use target midpoint
midpoint = (target_dock[0]+target_dock[1])/2
dist = min(abs(midpoint - channel[0]),abs(midpoint - channel[1]))
channel = [midpoint-dist, midpoint+dist]
elif source.shape in "iwfmce":
# use channel (=source) midpoint
midpoint = (channel[0]+channel[1])/2
dist = min(abs(midpoint - target_dock[0]),abs(midpoint - target_dock[1]))
channel = [midpoint-dist, midpoint+dist]
else:
# use intermediate channel
channel = [max(channel[0],target_dock[0]), min(channel[1],target_dock[1])]
return(channel)
#**************************************************************
def block_coordinates(self,block, direction):
if direction == 'Y':
cx1 = block.newbbox[0]
cx2 = block.newbbox[2]
cy1 = block.newbbox[1]
cy2 = block.newbbox[3]
else:
cx1 = block.newbbox[1]
cx2 = block.newbbox[3]
cy1 = block.newbbox[0]
cy2 = block.newbbox[2]
return cx1, cx2, cy1, cy2
#**************************************************************
def new_channel(self,channel,channel_length,direction,leftright):
#Coordinates of channel
ax1 = channel_length[0]
ax2 = channel_length[1]
ay1 = channel[0]
ay2 = channel[1]
newchannel = ""
for block in self.graph.blocks:
cx1,cx2,cy1,cy2 = self.block_coordinates(block, direction)
if (ax1<cx1<ax2 or ax1<cx2<ax2) and (ay1<cy1<ay2 or ay1<cy2<ay2 or (cy1<=ay1 and cy2>=ay2)):
if leftright == 1:
ax1 = min(ax1,cx2)
ax2 = min(cx1,ax2)
else:
ax1 = max(ax1,cx2)
ax2 = max(cx1,ax2)
newchannel = [ax1,ax2]
return newchannel
#************************************************************************
def channel_optimal_width(self,channel, channel_length, direction):
optimal_channel = [channel[0],channel[1]]
minimal_width = self.min_w
#Coordinates of channel
ax1 = channel_length[0]
ax2 = channel_length[1]
ay1 = channel[0]
ay2 = channel[1]
for block in self.graph.blocks: #blocklist:
cx1,cx2,cy1,cy2 = self.block_coordinates(block, direction)
if (ax1 <= cx1 < ax2) or (ax1 < cx2 <= ax2):
if ay1 <= cy1 < ay2:
optimal_channel[1] = min(cy1,ay2)
elif ay1 < cy2 <= ay2:
optimal_channel[0] = max(cy2,ay1)
if (optimal_channel[1]-optimal_channel[0])<minimal_width:
optimal_channel = channel
return optimal_channel
#************************************************************************
def choose_points_from_channels(self):
for block in self.graph.blocks:
for arrow in block.arrows_out:
if not 'channels' in vars(arrow):
continue
jump = arrow.target_block
arrow.newbends = []
p = {'X': None, 'Y': None }
if arrow.dir in "ns": # --> SHAPE-001-VALID
act_direction = 'Y'
else:
act_direction = 'X' # <-- ENDREQ
for channel in arrow.channels:
act_direction = { 'X': 'Y', 'Y': 'X'}[act_direction]
#pos = random.uniform(0.01,0.99)
pos = 0.5
p[act_direction] = pos*channel[0] + (1-pos)*channel[1]
if len(arrow.channels)==1:
if act_direction=='Y':
p['X']= (jump.newbbox[0]+block.newbbox[2])/2
else:
p['Y']= (jump.newbbox[1]+block.newbbox[3])/2
if p['X'] and p['Y']:
arrow.newbends.append([p['X'],p['Y']])
return()
#************************************************************************
def compare_channels(self):
for block in self.graph.blocks:
for arrow in block.arrows_out:
if not 'channels' in vars(arrow):
continue
pos = 0
for channel in arrow.channels:
arrow.channels[pos] = self.fit_to_parallel_channels(block, arrow.target_block, arrow.channels, pos, arrow.dir)
pos += 1
return()
#****************************************************************
def fit_to_parallel_channels(self,source, target, channels, pos, dir):
a = channels[pos]
direction_a = {True: 'X', False: 'Y'}[(dir in "ns")^(pos%2==0)]
# the direction of the current channel depends on the direction fo the arrow and the channel number
ax1, ax2 = self.get_channel_length(source, target, channels, pos, direction_a)
for block in self.graph.blocks:
for arrow in block.arrows_out:
pos_b = 0
for chan in arrow.channels:
direction_b = {True: 'X', False: 'Y'}[
(arrow.dir in "ns")^(pos_b%2==0)]
bx1, bx2 = self.get_channel_length(block, arrow.target_block, arrow.channels, pos_b, direction_b)
if block==source and arrow.target_block==target and pos_b==pos:
pass
elif direction_a == direction_b and ((ax1 <= bx1 < ax2) or (ax1 < bx2 <= ax2)
or (bx1<=ax1 and bx2>=ax2)):
if a[0] < chan[0] < a[1] and a[1]-chan[1]<chan[0]-a[0]:
a[1] = chan[0]
elif a[0] < chan[1] < a[1] and a[1]-chan[1]> chan[0]-a[0]:
a[0] = chan[1]
elif (chan[0]<= a[0] and chan[1]>= a[1]) or (a[1]-chan[1])==(chan[0]-a[0]):
a[1] = (a[0]+a[1])/2
pos_b += 1
return(a)
#******************************************************
def get_channel_length(self,source, target,channels, pos,direction):
if pos == 0 and direction == 'X': # --> BUG-0004-VALID
x1 = (source.newbbox[0]+source.newbbox[2])/2 # arrow starts from diamond shape in
elif pos == 0 and direction == 'Y': # y-direction, must be taken care off
x1 = (source.newbbox[1]+source.newbbox[3])/2 # here
else:
x1 = (channels[pos-1][0]+channels[pos-1][1])/2
if pos == len(channels)-1 and direction=='X':
x2 = (target.newbbox[0]+target.newbbox[2])/2
elif pos == len(channels)-1 and direction=='Y':
x2 = (target.newbbox[1]+target.newbbox[3])/2
else:
x2 = (channels[pos+1][0]+channels[pos+1][1])/2 # <-- ENDREQ
xx1 = min(x1,x2)
xx2 = max(x1,x2)
return(xx1,xx2)