Jelajahi Sumber

mxg:combine all file

mengxiangge 5 tahun lalu
induk
melakukan
1b59e37e7b
1 mengubah file dengan 752 tambahan dan 0 penghapusan
  1. 752 0
      src/system_relation/system_block.py

+ 752 - 0
src/system_relation/system_block.py

@@ -0,0 +1,752 @@
+"""const.
+
+"""
+EQUIPMENT='Equipment'
+COMPONENT='EquipPart'
+FACILITY=[EQUIPMENT,COMPONENT]
+OTHER='Other'
+CONNECTOR='Connector'
+DUCT='Duct'
+PIPE='Pipe'
+MEPCURVE=[DUCT,PIPE]
+
+"""system calc utils.
+1. get connectors where model_id='@model_id' and belong_type='Equipment' and mep_system_type='@system_name'
+2. get path start with connector,end with triple ,cross,equipment,end
+"""
+
+from functools import cmp_to_key
+import vg
+
+
+def path2edge(elements):
+	"""
+	Convert path to GraphtEdge
+	:param elements:
+	:return:
+	"""
+	pass
+
+
+def graph_arrange(graph):
+	"""
+	Combine Vertex that connect to virtul Vertex
+	:param graph:
+	:return:
+	"""
+	pass
+
+
+def connector_sort(connector1, connector2):
+	"""Use Define Sort rule"""
+	dic = {EQUIPMENT: 0, COMPONENT: 1, OTHER: 2, PIPE: 3,
+		   DUCT: 4}
+	x = dic[connector1.belong_type]
+	y = dic[connector2.belong_type]
+	return 1 if x > y else -1
+
+
+def sort_connectors(connectors):
+	"""Sort Connector order by Equipment>EquipPart>Other>Pipe>Duct"""
+	return sorted(connectors, key=cmp_to_key(lambda x, y: connector_sort(x, y)))
+
+
+def is_break_condition(element):
+	"""Path end Condition."""
+	res = element.type in revit_const.FACILITY
+	return res
+
+
+def dic2obj(d):
+	"""Convert Dict to Object.
+	"""
+	top = type('new', (object,), d)
+	seqs = tuple, list, set, frozenset
+	for i, j in d.items():
+		if isinstance(j, dict):
+			setattr(top, i, dic2obj(j))
+		elif isinstance(j, seqs):
+			setattr(top, i,
+					type(j)(dic2obj(sj) if isinstance(sj, dict) else sj for sj in j))
+		else:
+			setattr(top, i, j)
+	return top
+
+
+def list_to_dict(lis):
+	ids = [idx.id for idx in lis]
+	dic = dict(zip(ids, lis))
+	return dic
+
+
+def add_attr_is_used(x):
+	"""
+	Add is_used attribute.
+	:param x:
+	:return:
+	"""
+	x.is_used = False
+	return x
+
+
+def is_xyz_equal(origin1, origin2):
+	"""
+	Judge the two origin are almost equal.
+	:param origin1:
+	:param origin2:
+	:return:
+	"""
+	v1 = [origin1.X, origin1.Y, origin1.Z]
+	v2 = [origin2.X, origin2.Y, origin2.Z]
+	return vg.almost_equal(v1, v2, atol=1e-08)
+
+
+def get_specify_type_parent(vertex, type):
+	parent = vertex
+	try:
+		while not isinstance(parent, type):
+			parent = parent.parent
+	except :
+		parent=None
+
+	return parent
+
+
+"""PipeNetwork Data .
+
+"""
+import test
+import systemutils
+
+
+def get_dicdata(sql,dic):
+	"""
+	Request db for data through sql.
+	Convert data to dict.
+	:param sql:
+	:param dic:
+	:return:
+	"""
+	data=test.get_data(sql)
+	dic_data=[dict(zip(dic,item)) for item in data]
+	return list(dic_data)
+def get_project_models(project_id):
+	'''
+	Get all the models in the project.
+	project-->folder-->model.
+	:param project_id:
+	:return:
+	'''
+	element_data = []
+	sql ="select " \
+		"file.id as file_id" \
+		",file.original_name as file_name" \
+		",file.status as file_status" \
+		",floor.id as floor_id" \
+		",floor.floor_name as floor_name" \
+		",folder.id as folder_id" \
+		",folder.name as folder_name" \
+		",folder.project_id as project_id " \
+		"from revit.model_file as file " \
+		"inner join " \
+		"revit.model_floor as floor " \
+		"on ( file.id=floor.current_model_id) " \
+		"inner join " \
+		"revit.model_folder as folder " \
+		"on  (floor.folder_id=folder.id )" \
+		"where folder.project_id='%s'" \
+		"and folder.id='bbe510dbe26011e999b69b669ea08505'"\
+		 % (project_id)
+	#"and file.status=4 "\
+	COMPONENT_KEYS = [
+		'file_id',
+		'file_name',
+		'file_status',
+		'floor_id',
+		'floor_name',
+		'folder_id',
+		'folder_name',
+		'project_id'
+	]
+	element_data.extend(get_dicdata(sql, COMPONENT_KEYS))
+	element_data = list(map(systemutils.dic2obj, element_data))
+	return element_data
+def get_element_data(model_id):
+	"""
+	Cache all Element from Db
+	:return:
+	"""
+	element_data=[]
+	component_sql="select * from revit.component where model_id='%s'"%(model_id)
+	COMPONENT_KEYS = [
+		'id',
+		'model_id',
+		'local_id',
+		'local_name',
+		'family',
+		'location',
+		'outline',
+		'source_id',
+		'name',
+		'revit_id',
+		'parameters',
+		'type',
+		'tag',
+		'owner',
+		'last_update',
+		'create_time',
+		'owner_id',
+		'family_name',
+		'owner_source_id'
+	]
+	element_data.extend(get_dicdata(component_sql,COMPONENT_KEYS))
+
+	equipment_sql="select * from revit.equipment where model_id='%s'"%(model_id)
+	EQUIPMENT_KEYS = [
+		'id',
+		'model_id',
+		'local_id',
+		'local_name',
+		'family',
+		'location',
+		'outline',
+		'last_update',
+		'create_time',
+		'source_id',
+		'name',
+		'parameters',
+		'revit_id',
+		'type',
+		'tag',
+		'family_name',
+	]
+	element_data.extend(get_dicdata(equipment_sql,EQUIPMENT_KEYS))
+
+	other_sql="select * from revit.other where model_id='%s'"%(model_id)
+	OTHER_KEYS = [
+		'id',
+		'model_id',
+		'connected_ids',
+		'source_id',
+		'name',
+		'revit_id',
+		'type',
+		'create_time',
+		'last_update',
+		'location',
+		'outline'
+	]
+	element_data.extend(get_dicdata(other_sql,OTHER_KEYS))
+
+	pipe_sql = "select * from revit.pipe where model_id='%s'" % (model_id)
+	PIPE_KEYS = [
+		'id',
+		'model_id',
+		'location',
+		'outline',
+		'connected_ids',
+		'mep_system_type',
+		'diameter',
+		'source_id',
+		'name',
+		'revit_id',
+		'type',
+		'last_update',
+		'create_time',
+		'parameters'
+	]
+	element_data.extend(get_dicdata(pipe_sql, PIPE_KEYS))
+
+	duct_sql="select * from revit.duct where model_id='%s'"%(model_id)
+	DUCT_KEYS = [
+		'id',
+		'model_id',
+		'location',
+		'outline',
+		'connected_ids',
+		'mep_system_type',
+		'shape',
+		'diameter',
+		'width',
+		'height',
+		'source_id',
+		'revit_id',
+		'name',
+		'type',
+		'last_update',
+		'create_time',
+		'parameters'
+	]
+	element_data.extend(get_dicdata(duct_sql,DUCT_KEYS))
+	element_data=list(map(systemutils.dic2obj, element_data))
+	return element_data
+
+
+def get_connectors_data(model_id, system_name, domain):
+	"""Cache all connector from Db。"""
+	connector_data=[]
+	connector_sql = "SELECT * FROM revit.connector where model_id='%s' and mep_system_type='%s' and domain='%s'" % (model_id,system_name,domain)
+	print(connector_sql)
+	CONNECTOR_KEYS = [
+		'id',
+		'model_id',
+		'belong',
+		'belong_type',
+		'origin',
+		'domain',
+		'description',
+		'connected',
+		'owner',
+		'connected_ids',
+		'mep_system_type',
+		'source_id',
+		'revit_id',
+		'type',
+		'create_time',
+		'last_update',
+		'connect_id_json'
+	]
+	connector_data.extend(get_dicdata(connector_sql, CONNECTOR_KEYS))
+	connector_data=list(map(systemutils.dic2obj, connector_data))
+	return connector_data
+
+def save_project_data(project_graph,project_id):
+	"""
+	Sava project graph data.
+	:param floor_graph:
+	:return:
+	"""
+	del_project_data(project_id)
+	# Create
+	block_id=0
+	for g in project_graph.groupedsystemgraphs:
+		for s in g.systemgraphs:
+			for e in s.system_edges:
+				save_edge_data(e, block_id)
+		for e in g.connectedges:
+			save_edge_data(e,block_id)
+		block_id+=1
+def save_edge_data(edge,block_id):
+	"""
+	Save edge info using sql
+	:param edge:
+	:param block_id:
+	:return:
+	"""
+	try:
+		vertex1=edge.start_vertex
+		vertex2=edge.end_vertex
+		c1=vertex1.system_data
+		c2=vertex2.system_data
+		model1= vertex1.get_parent_floor()
+		model2 = vertex2.get_parent_floor()
+		sql="insert into revit_calc.connected_block" \
+			"(id1,type1,model_id1,id2,type2,model_id2,block_id,project_id) values " \
+			"('%s','%s','%s','%s','%s','%s','%s','%s')"\
+			%(c1.id,c1.type,model1.file_id,c2.id,c2.type,model2.file_id,block_id,model1.project_id)
+		data = test.save_data(sql)
+	except Exception as e:
+		print(e)
+def del_project_data(project_id):
+	"""
+	Before save.delete old data.
+	:param project_id:
+	:return:
+	"""
+	sql = "delete from revit_calc.connected_block where project_id='%s'"% (project_id)
+	data = test.save_data(sql)
+def get_connected_block_data(project_id,block_id):
+	'''
+	Get all the connected_block .
+	:param project_id:
+	:param block_id:
+	:return:
+	'''
+	element_data = []
+	sql = "select * from revit_calc.connected_block " \
+		  "where project_id='%s'" \
+		  "and block_id='%s'" \
+		  "order by cast(depth as int) asc"\
+		  % (project_id,block_id)
+	KEYS = [
+		'id',
+		'id1',
+		'type1',
+		'model_id1',
+		'id2',
+		'type2',
+		'model_id2',
+		'direction',
+		'block_id',
+		'project_id',
+		'depth',
+	]
+	element_data.extend(get_dicdata(sql, KEYS))
+	element_data = list(map(systemutils.dic2obj, element_data))
+	return element_data
+def get_connected_block_source_data(project_id,block_id):
+	'''
+	Get all the connected_block source .
+	:param project_id:
+	:param block_id:
+	:return:
+	'''
+	element_data = []
+	sql = "select * from revit_calc.connected_block_source " \
+		  "where project_id='%s'" \
+		  "and block_id='%s'" \
+		  % (project_id,block_id)
+	KEYS = [
+		'id',
+		'project_id',
+		'block_id',
+		'source_id',
+	]
+	element_data.extend(get_dicdata(sql, KEYS))
+	element_data = list(map(systemutils.dic2obj, element_data))
+	return element_data
+def update_connected_block_data(block_datas):
+	'''
+	update connected_block direction by id.
+	:param block_datas:
+	:return:
+	'''
+	for block_data in block_datas:
+		sql="update revit_calc.connected_block set direction='%s',depth='%s' where id='%s'"\
+			%(block_data.direction,block_data.depth,block_data.id)
+		data = test.save_data(sql)
+
+
+"""Graph Model.
+"""
+from enum import Enum
+
+
+class SystemVertex:
+	"""Graph Vertex.
+	"""
+	vertex_type = 0
+
+	def __init__(self,parent, connector,system_data):
+		self.connector=connector
+		self.system_data = system_data
+		self.parent= parent
+
+	def __str__(self):
+		return str(systemutils.get_specify_type_parent(self, FloorGraph).model.floor_name) + ':' + str(self.system_data.source_id)
+
+	def __eq__(self, other):
+		return self.system_data.source_id==other.system_data.source_id
+
+	def __hash__(self):
+		return hash(self.system_data.source_id)
+
+	def is_open_vertical_pipe(self):
+		'''
+		Connector to other floor
+		:return:
+		'''
+		if (len(self.connector.connect_id_json)==0):
+			if( self.connector.belong_type in MEPCURVE):
+				return True
+		return False
+	def get_parent_floor(self):
+		'''
+		Get relation floorgraph.
+		:return:
+		'''
+		model = systemutils.get_specify_type_parent(self, FloorGraph).model
+		return model
+class SystemEdge:
+	"""Graph Edge."""
+	# edge data.contain all edge element
+	flow_direction = 0
+
+	def __init__(self,parent, system_data):
+		self.system_data = system_data
+		self.parent = parent
+
+	def get_vertexs(self):
+		return [self.start_vertex,self.end_vertex]
+# @property
+# def start_vertex(self):
+# 	return self.start_vertex
+#
+# @property
+# def end_vertex(self):
+# 	return self.end_vertex
+
+
+class SystemGraph:
+	"""System Graph
+	"""
+	# system edge array.
+	system_graph_id = ''
+	# system type Name
+	system_name = ""
+
+	def __init__(self,parent):
+		self.system_edges = []
+		self.parent=parent
+
+	def add_edge(self, c1, c2, elements):
+		"""
+		Create edge and add to system_edges list
+		:param c1:
+		:param c2:
+		:param elements:
+		:return:
+		"""
+		edge = SystemEdge(self,elements)
+		edge.start_vertex = SystemVertex(edge,c1,elements[0])
+		edge.end_vertex = SystemVertex(edge,c2,elements[-1])
+		self.system_edges.append(edge)
+		return edge
+
+	def get_open_vertical_pipes(self):
+		"""
+		Get all open vertical pipe Vertex
+		:return:
+		"""
+		open_pipes=[]
+		for edge in self.system_edges:
+			for	vertex in edge.get_vertexs():
+				if vertex.is_open_vertical_pipe():
+					open_pipes.append(vertex)
+		return open_pipes
+
+
+class FloorGraph:
+	"""FLoor Graph.
+	May contain one or more SystemGraph.
+	"""
+
+	def __init__(self,model, system_name, domain):
+		self.model=model;
+		self.system_name = system_name
+		self.domain = domain
+		floor_connectors = get_connectors_data(self.model.file_id, system_name, domain)
+		floor_connectors = sort_connectors(floor_connectors)
+		floor_connectors = list(map(systemutils.add_attr_is_used, floor_connectors))
+		self.connector_data = (floor_connectors)
+		self.element_data = list_to_dict(get_element_data(self.model.file_id))
+		self.system_graphs = []
+
+	def get_floor_graphs(self):
+		"""Get current floor graph.
+		system_name,domain
+		"""
+		for connector in self.connector_data:
+			system_graph = SystemGraph(self)
+			graph_next_connectors = [connector]
+			# dept-first
+			for connector in graph_next_connectors:
+				self.get_path(connector, system_graph, graph_next_connectors)
+			if len(system_graph.system_edges) != 0:
+				self.system_graphs.append(system_graph)
+				print("Next loop:",connector.source_id)
+		return self.system_graphs
+
+	def get_path(self, connector, system_graph, graph_next_connectors):
+		"""
+		Get Graph_Edge start with connector,end with triple ,cross,equipment.
+		:param connector:
+		:return:Graph_Edge
+		"""
+		system_edge = None
+		if (connector.is_used):
+			return system_edge
+		try:
+			#Add other side to be spreaded
+			graph_next_connectors.extend(self.get_other_connectors(connector))
+			edge_elements = [self.get_element(connector.belong)]
+			current_connector = connector
+			while (current_connector is not None):
+				current_connector.is_used = True
+				connecteds = self.get_connecteds(current_connector.connect_id_json)
+				if len(connecteds) > 1:
+					raise Exception("connected to many.connector_id:", current_connector.connect_id_json)
+				#Open Connector
+				if len(connecteds) == 0:
+					if current_connector != connector:
+						system_edge = system_graph.add_edge(connector, current_connector, edge_elements)
+					break
+				next_connector = connecteds[0]
+				if next_connector is not None and next_connector.domain == connector.domain and next_connector.mep_system_type == connector.mep_system_type:
+					next_element = self.get_element(next_connector.belong)
+					edge_elements.append(next_element)
+					other_connectors = self.get_other_connectors(next_connector)
+					if systemutils.is_break_condition(next_element) or len(other_connectors) != 1:
+						print(next_connector.source_id)
+						next_connector.is_used = True
+						if(len(other_connectors) != 1):
+							graph_next_connectors.extend(other_connectors)
+						system_edge = system_graph.add_edge(connector, next_connector, edge_elements)
+						break
+					if len(other_connectors)==1:
+						next_connector.is_used = True
+						current_connector = other_connectors[0]
+						continue
+				current_connector = None
+		except Exception as e:
+			print(e)
+
+		return system_edge
+
+	def get_other_connectors(self, use_connector):
+		"""
+		Get the  connector owner other connectors.
+		belong,domian,mep_system_type same.
+		is_used==False.
+		:param use_connector:
+		:return:
+		"""
+		connectors = [connector for connector in self.connector_data if
+					  connector != use_connector and connector.belong == use_connector.belong and connector.domain == use_connector.domain and connector.mep_system_type == use_connector.mep_system_type]
+		connectors = [connector for connector in connectors if bool(1 - connector.is_used)]
+		return connectors
+
+	def get_connecteds(self, connetor_id):
+		"""
+		Get Ref Connector. may have two.like system logic connector
+		:param connetor_id:
+		:return:
+		"""
+		connectors = list(self.get_connector(id) for id in connetor_id)
+		return connectors
+
+	def get_connector(self, connector_id):
+		"""
+		Get Connector by Id.
+		:param connector_id:
+		:return:
+		"""
+		cons = list(c for c in self.connector_data if c.id == connector_id)
+		return cons[0]
+
+	def get_element(self, element_id):
+		"""
+		Get Element by Id.
+		:param eleemnt_id:
+		:return:
+		"""
+		return self.element_data[element_id]
+
+class GroupedSystemGraph:
+	'''
+	Systemgraph be connected  via vertical pipe
+	May contain more system.Different floor;
+	'''
+	def __init__(self, systemgraph):
+		self.systemgraphs=[systemgraph]
+		self.connectedges=[]
+	def add_system(self,systemgraph):
+		'''
+		Add system into groupsystem
+		:param systemgraph:
+		:return:
+		'''
+		self.systemgraphs.append(systemgraph)
+
+	def add_edge(self,vertex1,vertex2):
+		'''
+		Create virtual edge that connect two floor.
+		Add edge to edge list.
+		:param vertex1:
+		:param vertex2:
+		:return:
+		'''
+		edge=SystemEdge(None,None)
+		edge.start_vertex=vertex1
+		edge.end_vertex=vertex2
+		self.connectedges.append(edge)
+
+class ProjectGraph:
+	'''
+	ProjectGraph contain more than one GroupedSystemGraph.
+	'''
+	def __init__(self):
+		self.groupedsystemgraphs=[]
+
+	def remove_groupedsystemgraphs(self, systemgraph):
+		'''
+		Check system has existed in grouped system list.
+		if exist remove it .
+		:param systemgraph:
+		:return:
+		'''
+		try:
+			tt = next(groupedsystemgraph for groupedsystemgraph in self.groupedsystemgraphs if
+					  systemgraph in groupedsystemgraph.systemgraphs)
+			if tt:
+				self.groupedsystemgraphs.remove(tt)
+		except StopIteration:
+			pass
+
+
+class SystemFlowDirection(Enum):
+	"""Edge Flow Direction.
+	"""
+	flow_in = 1
+	flow_out = -1
+	flow_undefine = 0
+
+
+class SystemVertexType(Enum):
+	"""Vertex Type.
+	"""
+	real_point = 0
+	imaginary_point = 1
+	hollow_dot = 2
+
+
+def combine_systemgraph(floorgraphs):
+	"""
+	Consider the riser merger
+	:param floorgraphs:
+	:return:projectgraph
+	"""
+	# get all open vertical pipe
+	open_vertical_pipes = []
+	for floorgraph in floorgraphs:
+		for systemgraph in floorgraph.system_graphs:
+			open_vertical_pipes.extend(systemgraph.get_open_vertical_pipes())
+	# group systemvertex
+	projectgraph = ProjectGraph()
+	for i in range(len(open_vertical_pipes)):
+		v1 = open_vertical_pipes[i]
+		group_pipes = [v1]
+		for j in range(i + 1, len(open_vertical_pipes)):
+			v2 = open_vertical_pipes[j]
+			if systemutils.is_xyz_equal(v1.connector.origin, v2.connector.origin):
+				group_pipes.append(v2)
+			# combine systemgraph
+			for k in range(len(group_pipes)):
+				vertex = group_pipes[k]
+				systemgraph = get_specify_type_parent(vertex, SystemGraph)
+				if not systemgraph:
+					continue
+				projectgraph.remove_groupedsystemgraphs(systemgraph)
+				if (k == 0):
+					temp_groupedsystemgraphs = GroupedSystemGraph(systemgraph)
+				else:
+					prev_vertex = group_pipes[k - 1]
+					temp_groupedsystemgraphs.add_system(systemgraph)
+					temp_groupedsystemgraphs.add_edge(prev_vertex, vertex)
+			if temp_groupedsystemgraphs:
+				projectgraph.groupedsystemgraphs.append(temp_groupedsystemgraphs)
+	return projectgraph
+
+if '__main__'==__name__:
+	project_id="Pj1101010015"
+	system_name="冷冻水供水管"
+	domain="DomainPiping"
+	models= get_project_models(project_id)
+	floorgraphs=[]
+	for model in models:
+		g= FloorGraph(model, system_name, domain)
+		g.get_floor_graphs()
+		floorgraphs.append(g)
+	projectgraph= combine_systemgraph(floorgraphs)
+	save_project_data(projectgraph, project_id)
+	#systemgraph_display.show_project(projectgraph)