api_graph.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  1. from django.contrib import auth
  2. from rest_framework.views import APIView
  3. from rest_framework.response import Response
  4. from rest_framework import status
  5. from rest_framework.authtoken.models import Token
  6. from rest_framework.authentication import BasicAuthentication, TokenAuthentication
  7. from .serializers import UserRegisterSerializer
  8. from django.middleware.csrf import get_token
  9. from django.contrib.auth import login
  10. from api.utils import *
  11. from api.models import Result, Graph, GraphToken
  12. from random import randint
  13. import json, csv
  14. class ViewGraphByToken(APIView):
  15. # 通过验证码看图——供VR使用
  16. authentication_classes = []
  17. permission_classes = []
  18. def get(self, request):
  19. print(request.GET)
  20. requestToken = request.GET.get('token')
  21. print(requestToken)
  22. try:
  23. token = GraphToken.objects.get(token=str(requestToken))
  24. except GraphToken.DoesNotExist:
  25. return failed(message="Token不存在")
  26. if token.checkExpire():
  27. return failed(message="Token已过期")
  28. graph = token.graph
  29. return success(data={
  30. 'nodes': graph.nodes,
  31. 'edges': graph.edges,
  32. })
  33. class GenerateGraph(APIView):
  34. # 生成图数据
  35. def get(self, request):
  36. user = request.user
  37. method = request.GET.get('method') # 以何种视图查看
  38. resultId = request.GET.get('result')
  39. # 测试用,固定result值,省略计算
  40. resultId = 57
  41. # 检查result的传递值是否正确
  42. try:
  43. if type(resultId) == int:
  44. result = Result.objects.get(id=resultId)
  45. elif type(resultId) == str:
  46. result = Result.objects.get(id=int(resultId))
  47. elif type(resultId) == dict:
  48. if 'id' in resultId:
  49. result = Result.objects.get(id=resultId['id'])
  50. else:
  51. return failed(message="输入信息错误")
  52. except Exception as error:
  53. return failed(message="输入信息错误", data=error)
  54. # 图表显示不生成图,仅做统计计算
  55. if method == 'chart':
  56. nodeJson = result.nodeFile.toJson()
  57. edgeJson = result.edgeFile.toJson()
  58. def isOriginEdge(edge):
  59. for meta in edge['meta']:
  60. if meta.get('optimize') == 'new' or meta.get('predict') == 'new':
  61. return False
  62. return True
  63. # 需要完善图表视图统计数据,根据具体图表类型决定
  64. # 通用图数据统计,包括SDI节点数量、边数量,各类型节点度数分布
  65. # 平均链长度,聚类系数即D节点间连接紧密程度
  66. # 分别统计SDI节点的数量和度数:sNodes,dNodes,iNodes
  67. sDegree = dDegree = iDegree = [0 for i in range(11)] # 度的取值范围0~10,共11个元素
  68. sNodes = [node for node in nodeJson if node['type'] == 'S']
  69. for s in sNodes:
  70. degree = len([edge for edge in edgeJson if edge['from'] == s['id'] or edge['to'] == s['id']])
  71. if degree <= 10:
  72. sDegree[degree] += 1
  73. else:
  74. sDegree[10] += 1
  75. dNodes = [node for node in nodeJson if node['type'] == 'D']
  76. for d in dNodes:
  77. degree = len([edge for edge in edgeJson if edge['from'] == d['id'] or edge['to'] == d['id']])
  78. if degree <= 10:
  79. dDegree[degree] += 1
  80. else:
  81. dDegree[10] += 1
  82. iNodes = [node for node in nodeJson if node['type'] == 'I']
  83. for i in iNodes:
  84. degree = len([edge for edge in edgeJson if edge['from'] == i['id'] or edge['to'] == i['id']])
  85. if degree <= 10:
  86. iDegree[degree] += 1
  87. else:
  88. iDegree[10] += 1
  89. # 查找所有OODA链路:chains
  90. chains = []
  91. for s in sNodes:
  92. stack = [(s, [s])] # (当前节点, 路径, 已访问节点)
  93. while stack:
  94. current, path = stack.pop()
  95. # 必须限制链路长度,否则无法结束,除限制长度外还可尝试将不同顺序节点的链路视为同一条,从而减少链路数量
  96. if len(path) > 5:
  97. continue
  98. # 终止条件:到达I节点
  99. if current['type'] == 'I':
  100. chains.append(path)
  101. continue
  102. # 遍历邻居,注意通用计算只统计原始图
  103. neighbors = [edge['to'] for edge in edgeJson if (isOriginEdge(edge) and edge['from'] == current['id'])] + [edge['from'] for edge in edgeJson if (isOriginEdge(edge) and edge['to'] == current['id'])]
  104. for neighborId in neighbors:
  105. neighbor = [node for node in nodeJson if node.get('id') == neighborId]
  106. if len(neighbor) != 1:
  107. return failed(message="查找OODA链路时出错:不存在的邻居节点")
  108. neighbor = neighbor[0]
  109. if neighbor in path: continue # 避免环路
  110. # 不能连线的几种情况
  111. if current['type'] == 'S' and neighbor['type'] == 'I':
  112. continue
  113. if current['type'] == 'D' and neighbor['type'] == 'S':
  114. continue
  115. stack.append((neighbor, path + [neighbor]))
  116. chainsNum = len(chains)
  117. chainsNumByLength = [0 for i in range(5)]
  118. for chain in chains:
  119. length = len(chain)
  120. if length >= 5:
  121. length = 5
  122. chainsNumByLength[length-1] += 1
  123. averageChainsLength = round(sum([len(chain) for chain in chains]) / chainsNum, 2)
  124. data = {
  125. 'sNodesNum': len(sNodes),
  126. 'dNodesNum': len(dNodes),
  127. 'iNodesNum': len(iNodes),
  128. 'sDegree': sDegree,
  129. 'dDegree': dDegree,
  130. 'iDegree': iDegree,
  131. 'chains': {
  132. 'num': chainsNum,
  133. 'averageLength': averageChainsLength,
  134. 'numByLength': chainsNumByLength,
  135. },
  136. }
  137. # 根据计算类型的不同分别计算特殊数据
  138. if result.plan.algorithm.type in ['optimize', 'predict'] :
  139. # 拓扑优化算法应该统计原有图的数据与优化后图的数据,优化应该仅优化边
  140. newChains = []
  141. for s in sNodes:
  142. stack = [(s, [s])] # (当前节点, 路径, 已访问节点)
  143. while stack:
  144. current, path = stack.pop()
  145. # 终止条件:到达I节点
  146. if current['type'] == 'I':
  147. newChains.append(path)
  148. continue
  149. # 遍历邻居,注意优化计算只统计新图
  150. neighbors = [edge['to'] for edge in edgeJson if (not isOriginEdge(edge) and edge['from'] == current['id'])] + [edge['from'] for edge in edgeJson if (not isOriginEdge(edge) and edge['to'] == current['id'])]
  151. for neighborId in neighbors:
  152. neighbor = [node for node in nodeJson if node.get('id') == neighborId]
  153. if len(neighbor) != 1:
  154. return failed(message="查找OODA链路时出错:不存在的邻居节点")
  155. neighbor = neighbor[0]
  156. if neighbor in path: continue # 避免环路
  157. # 不能连线的几种情况
  158. if current['type'] == 'S' and neighbor['type'] == 'I':
  159. continue
  160. if current['type'] == 'D' and neighbor['type'] == 'S':
  161. continue
  162. stack.append((neighbor, path + [neighbor]))
  163. newChainsNum = len(newChains)
  164. newAverageChainsLength = 0
  165. if newChainsNum != 0:
  166. newAverageChainsLength = round(sum([len(chain) for chain in newChains]) / newChainsNum, 2)
  167. data['newChains'] = {
  168. 'num': newChainsNum,
  169. 'averageLength': newAverageChainsLength,
  170. }
  171. return success(data=data)
  172. # 如果已经生成过图数据,则直接生成新的验证码
  173. if result.own_graphs.exists():
  174. graph = result.own_graphs.first()
  175. if method == 'web' or method == '3D' or method == '3d':
  176. return success(data={
  177. 'nodes': graph.nodes,
  178. 'edges': graph.edges,
  179. })
  180. elif method == 'VR':
  181. token = graph.generateToken()
  182. return success(data={
  183. 'token': token,
  184. })
  185. else:
  186. nodeJson = result.nodeFile.toJson()
  187. edgeJson = result.edgeFile.toJson()
  188. ######测试用,添加几个标签
  189. for node in nodeJson:
  190. node['meta'].append({'optimize': 'new'})
  191. node['meta'].append({'group': randint(1,5)})
  192. node['meta'].append({'predict': 'new'})
  193. for edge in edgeJson:
  194. edge['meta'].append({'optimize': 'new'})
  195. edge['meta'].append({'predict': 'new'})
  196. ########################
  197. # 两种3D视图的数据结构应该是一样的
  198. if result.plan.algorithm.type == 'optimize':
  199. # 拓扑优化算法生成的结果,只有网络结构数据
  200. # 检查合法性
  201. for node in nodeJson:
  202. if not 'id' in node or not 'type' in node:
  203. return failed(message="拓扑优化结果的节点文件存在问题")
  204. for edge in edgeJson:
  205. if not 'from' in edge or not 'to' in edge:
  206. return failed(message="边文件存在问题")
  207. # 对于优化算法,边的属性中应该有新旧的区分
  208. missingLabel = True
  209. for meta in edge['meta']:
  210. if 'optimize' in meta and meta['optimize'] in ['new', 'old']:
  211. missingLabel = False
  212. if missingLabel:
  213. return failed(message="无拓扑优化标签")
  214. elif result.plan.algorithm.type == 'group':
  215. # 功能体探测算法生成的结果
  216. # 检查合法性
  217. for node in nodeJson:
  218. if not 'id' in node or not 'type' in node:
  219. return failed(message="节点文件存在问题")
  220. # 对于功能体探测算法,节点的属性中应有功能体的编号
  221. missingLabel = True
  222. for meta in node['meta']:
  223. if 'group' in meta and type(meta['group']) == int:
  224. missingLabel = False
  225. if missingLabel:
  226. return failed(message="无功能体标签")
  227. for edge in edgeJson:
  228. if not 'from' in edge or not 'to' in edge:
  229. return failed(message="边文件存在问题")
  230. elif result.plan.algorithm.type == 'predict':
  231. # 链路演化预测算法生成的结果
  232. # 检查合法性
  233. for node in nodeJson:
  234. if not 'id' in node or not 'type' in node:
  235. return failed(message="节点文件存在问题")
  236. # 对于演化预测算法,节点的属性中应有新旧区分
  237. missingLabel = True
  238. for meta in node['meta']:
  239. if 'predict' in meta and meta['predict'] in ['new', 'old']:
  240. missingLabel = False
  241. if missingLabel:
  242. return failed(message="无演化预测标签")
  243. for edge in edgeJson:
  244. if not 'from' in edge or not 'to' in edge:
  245. return failed(message="边文件存在问题")
  246. # 对于演化预测算法,边的属性中应有新旧区分
  247. missingLabel = True
  248. for meta in edge['meta']:
  249. if 'predict' in meta and meta['predict'] in ['new', 'old']:
  250. missingLabel = False
  251. if missingLabel:
  252. return failed(message="无演化预测标签")
  253. graph = Graph.objects.createFromResult(result)
  254. graph.save()
  255. if method == 'web':
  256. return success(data={
  257. 'nodes': graph.nodes,
  258. 'edges': graph.edges,
  259. })
  260. if method == 'VR':
  261. token = graph.generateToken()
  262. return success(data={
  263. 'token': token,
  264. })