from django.contrib import auth from rest_framework.views import APIView from rest_framework.response import Response from rest_framework import status from rest_framework.authtoken.models import Token from rest_framework.authentication import BasicAuthentication, TokenAuthentication from .serializers import UserRegisterSerializer from django.middleware.csrf import get_token from django.contrib.auth import login from api.utils import * from api.models import Result, Graph, GraphToken, Plan from random import randint import json, csv class ViewGraphByToken(APIView): # 通过验证码看图——供VR使用 authentication_classes = [] permission_classes = [] def get(self, request): print(request.GET) requestToken = request.GET.get('token') print(requestToken) try: token = GraphToken.objects.get(token=str(requestToken)) except GraphToken.DoesNotExist: return failed(message="Token不存在") if token.checkExpire(): return failed(message="Token已过期") graph = token.graph return success(data={ 'nodes': graph.nodes, 'edges': graph.edges, }) class GenerateGraph(APIView): # 生成图数据 def get(self, request): user = request.user method = request.GET.get('method') # 以何种视图查看 planId = request.GET.get('plan') try: plan = Plan.objects.get(id=planId) except Plan.DoesNotExist: print("获取结果的Plan失败") return failed(message="无法找到该结果对应规划") result = plan.own_result # 图表显示不生成图,仅做统计计算 if method == 'chart': nodeJson = result.nodeFile.toJson() edgeJson = result.edgeFile.toJson() def isOriginEdge(edge): for meta in edge['meta']: if meta.get('optimize') == 'new' or meta.get('predict') == 'new': return False return True # 需要完善图表视图统计数据,根据具体图表类型决定 # 通用图数据统计,包括SDI节点数量、边数量,各类型节点度数分布 # 平均链长度,聚类系数即D节点间连接紧密程度 # 分别统计SDI节点的数量和度数:sNodes,dNodes,iNodes sDegree = dDegree = iDegree = [0 for i in range(11)] # 度的取值范围0~10,共11个元素 sNodes = [node for node in nodeJson if node['type'] == 'S'] for s in sNodes: degree = len([edge for edge in edgeJson if edge['from'] == s['id'] or edge['to'] == s['id']]) if degree <= 10: sDegree[degree] += 1 else: sDegree[10] += 1 dNodes = [node for node in nodeJson if node['type'] == 'D'] for d in dNodes: degree = len([edge for edge in edgeJson if edge['from'] == d['id'] or edge['to'] == d['id']]) if degree <= 10: dDegree[degree] += 1 else: dDegree[10] += 1 iNodes = [node for node in nodeJson if node['type'] == 'I'] for i in iNodes: degree = len([edge for edge in edgeJson if edge['from'] == i['id'] or edge['to'] == i['id']]) if degree <= 10: iDegree[degree] += 1 else: iDegree[10] += 1 # 查找所有OODA链路:chains chains = [] for s in sNodes: stack = [(s, [s])] # (当前节点, 路径, 已访问节点) while stack: current, path = stack.pop() # 必须限制链路长度,否则无法结束,除限制长度外还可尝试将不同顺序节点的链路视为同一条,从而减少链路数量 if len(path) > 5: continue # 终止条件:到达I节点 if current['type'] == 'I': chains.append(path) continue # 遍历邻居,注意通用计算只统计原始图 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'])] for neighborId in neighbors: neighbor = [node for node in nodeJson if node.get('id') == neighborId] if len(neighbor) != 1: return failed(message="查找OODA链路时出错:不存在的邻居节点") neighbor = neighbor[0] if neighbor in path: continue # 避免环路 # 不能连线的几种情况 if current['type'] == 'S' and neighbor['type'] == 'I': continue if current['type'] == 'D' and neighbor['type'] == 'S': continue stack.append((neighbor, path + [neighbor])) chainsNum = len(chains) chainsNumByLength = [0 for i in range(5)] for chain in chains: length = len(chain) if length >= 5: length = 5 chainsNumByLength[length-1] += 1 averageChainsLength = round(sum([len(chain) for chain in chains]) / chainsNum, 2) data = { 'sNodesNum': len(sNodes), 'dNodesNum': len(dNodes), 'iNodesNum': len(iNodes), 'sDegree': sDegree, 'dDegree': dDegree, 'iDegree': iDegree, 'chains': { 'num': chainsNum, 'averageLength': averageChainsLength, 'numByLength': chainsNumByLength, }, } # 根据计算类型的不同分别计算特殊数据 if result.plan.algorithm.type in ['optimize', 'predict'] : # 拓扑优化算法应该统计原有图的数据与优化后图的数据,优化应该仅优化边 newChains = [] for s in sNodes: stack = [(s, [s])] # (当前节点, 路径, 已访问节点) while stack: current, path = stack.pop() # 终止条件:到达I节点 if current['type'] == 'I': newChains.append(path) continue # 遍历邻居,注意优化计算只统计新图 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'])] for neighborId in neighbors: neighbor = [node for node in nodeJson if node.get('id') == neighborId] if len(neighbor) != 1: return failed(message="查找OODA链路时出错:不存在的邻居节点") neighbor = neighbor[0] if neighbor in path: continue # 避免环路 # 不能连线的几种情况 if current['type'] == 'S' and neighbor['type'] == 'I': continue if current['type'] == 'D' and neighbor['type'] == 'S': continue stack.append((neighbor, path + [neighbor])) newChainsNum = len(newChains) newAverageChainsLength = 0 if newChainsNum != 0: newAverageChainsLength = round(sum([len(chain) for chain in newChains]) / newChainsNum, 2) data['newChains'] = { 'num': newChainsNum, 'averageLength': newAverageChainsLength, } return success(data=data) # 如果已经生成过图数据,则直接生成新的验证码 if result.own_graphs.exists(): graph = result.own_graphs.first() if method == 'web' or method == '3D' or method == '3d': return success(data={ 'nodes': graph.nodes, 'edges': graph.edges, }) elif method == 'VR': token = graph.generateToken() return success(data={ 'token': token, }) else: nodeJson = result.nodeFile.toJson() edgeJson = result.edgeFile.toJson() ######测试用,添加几个标签 for node in nodeJson: node['meta'].append({'optimize': 'new'}) node['meta'].append({'group': randint(1,5)}) node['meta'].append({'predict': 'new'}) for edge in edgeJson: edge['meta'].append({'optimize': 'new'}) edge['meta'].append({'predict': 'new'}) ######################## # 两种3D视图的数据结构应该是一样的 if result.plan.algorithm.type == 'optimize': # 拓扑优化算法生成的结果,只有网络结构数据 # 检查合法性 for node in nodeJson: if not 'id' in node or not 'type' in node: return failed(message="拓扑优化结果的节点文件存在问题") for edge in edgeJson: if not 'from' in edge or not 'to' in edge: return failed(message="边文件存在问题") # 对于优化算法,边的属性中应该有新旧的区分 missingLabel = True for meta in edge['meta']: if 'optimize' in meta and meta['optimize'] in ['new', 'old']: missingLabel = False if missingLabel: return failed(message="无拓扑优化标签") elif result.plan.algorithm.type == 'group': # 功能体探测算法生成的结果 # 检查合法性 for node in nodeJson: if not 'id' in node or not 'type' in node: return failed(message="节点文件存在问题") # 对于功能体探测算法,节点的属性中应有功能体的编号 missingLabel = True for meta in node['meta']: if 'group' in meta and type(meta['group']) == int: missingLabel = False if missingLabel: return failed(message="无功能体标签") for edge in edgeJson: if not 'from' in edge or not 'to' in edge: return failed(message="边文件存在问题") elif result.plan.algorithm.type == 'predict': # 链路演化预测算法生成的结果 # 检查合法性 for node in nodeJson: if not 'id' in node or not 'type' in node: return failed(message="节点文件存在问题") # 对于演化预测算法,节点的属性中应有新旧区分 missingLabel = True for meta in node['meta']: if 'predict' in meta and meta['predict'] in ['new', 'old']: missingLabel = False if missingLabel: return failed(message="无演化预测标签") for edge in edgeJson: if not 'from' in edge or not 'to' in edge: return failed(message="边文件存在问题") # 对于演化预测算法,边的属性中应有新旧区分 missingLabel = True for meta in edge['meta']: if 'predict' in meta and meta['predict'] in ['new', 'old']: missingLabel = False if missingLabel: return failed(message="无演化预测标签") graph = Graph.objects.createFromResult(result) graph.save() if method == 'web': return success(data={ 'nodes': graph.nodes, 'edges': graph.edges, }) if method == 'VR': token = graph.generateToken() return success(data={ 'token': token, })