在ANSA二次开发中经常获取当前视角下被选中单元和视角一致的法向量以备后续操作。本文主要通过创建视角向量和被选中单元的法向量来展示这一过程。首先,需要对中的错误进行更正:ansa中GetViewAngles函数旋转顺序为Z->Y->Z;且以顺时针为正,和一般笛卡尔坐标相反。因此有:import mathfrom typing import List, Tuplefrom ansa import basefrom ansa import constantsfrom ansa import calcclass ANSATYPE(object): ''' 不同求解器对应关键字名字 ''' @class method def eshell(cls, deck:int)->str: typDict:dict = { constants.LSDYNA: 'ELEMENT_SHELL', constants.ABAQUS:'SHELL', constants.NASTRAN: 'SHELL', constants.RADIOSS: 'SHELL', constants.ANSYS: 'SHELL', 22: 'SHELL', # OPTISTRUCT 23: 'SHELL' # MARC } try: _type = typDict[deck] except KeyError: raise ValueError('ERROR: 模型Deck设置有误') return _type @class method def node(cls, deck:int)->str: typDict:dict = { constants.LSDYNA: 'NODE', constants.ABAQUS:'NODE', constants.NASTRAN: 'GRID', constants.RADIOSS: 'NODE', constants.ANSYS: 'NODE', 22: 'GRID', # OPTISTRUCT 23: 'NODE' # MARC } try: _type = typDict[deck] except KeyError: raise ValueError('ERROR: 模型Deck设置有误') return _typeclass Vector(object): @class method def point2Point(cls, point1:List[float], point2:List[float], unit:bool=True)->List[float]: ''' 计算两点构成的向量. 向量由point1指向point2,即point2-point1 ''' if isinstance(point1, base.Entity): point1 = point1.position if isinstance(point2, base.Entity): point2 = point2.position vect:List[float] = [p2-p1 for p1, p2 in zip(point1, point2)] return cls.unit(vect) if unit else vect @staticmethod def unit(vector:List[float])->List[float]: ''' 将一个向量单位化 ''' return calc.Normalize(vector) @staticmethod def distance(point1:List[float], point2:List[float])->float: ''' 计算两点间的距离 ''' if isinstance(point1, base.Entity): point1 = point1.position if isinstance(point2, base.Entity): point2 = point2.position return math.dist(point1, point2) @class method def angleCos(cls, vector1:List[float], vector2:List[float])->float: ''' 计算两个空间向量的夹角的余弦值。 ''' unit_vect01 = cls.unit(vector1) unit_vect02 = cls.unit(vector2) return sum([v1*v2 for v1, v2 in zip(unit_vect01, unit_vect02)]) @staticmethod def angle(vector1:List[float], vector2:List[float])->float: ''' 计算两个空间向量的夹角,返回值以弧度形式存在 ''' return calc.CalcAngleOfVectors(vector1, vector2) @class method def elemNormal(cls, shellElem:base.Entity)->List[float]: ''' 根据单元的前三个节点计算单元的法向量 ''' vect:List[float] = base.GetNormalVectorOfShell(shellElem) if isinstance(vect, list): return vect else: nodeType:str = ANSATYPE.node(DECK) nodes:List[base.Entity] = base.CollectEntities(DECK, shellElem, nodeType, recursive=True) return cls.vec3Point(nodes[0], nodes[1], nodes[2]) @class method def vec3Point(cls, point1:List[float], point2:List[float], point3:List[float])->List[float]: ''' 计算空间三点构成平面的法向量 ''' vect1:List[float] = cls.point2Point(point1, point2) vect2:List[float] = cls.point2Point(point1, point3) return calc.CrossProduct(vect1, vect2)def getViewVector()->List[float]: ''' 通过视角函数获取视角旋转角并将其装换为视角向量 ''' # 获取视角转动角 angles:List[float] = base.GetViewAngles() angleRad = list(map(math.radians, angles)) angleSin: List[float] = list(map(math.sin, angleRad)) angleCos: List[float] = list(map(math.cos, angleRad)) # 计算视角向量三分量 x:float = -angleSin[1] y:float = angleSin[0]*angleCos[1] z:float = angleCos[0]*angleCos[1] return [x, y, z]def getShellViewVector(elem:base.Entity)->List[float]: ''' 名称: getShellViewVector 描述: 获取shell单元与当前视角方向一致的法向向量 参数: elem object shell类型单元 返回值: 返回一个向量(list),该向量表示输入shell单元与当前视角一致的单元法向量。 ''' # 对输入对象进行参数检查 if not isinstance(elem, base.Entity): raise TypeError('请输入ansa对象') shellType = ANSATYPE.eshell(DECK) elemType = elem.ansa_type(DECK) if elemType != shellType and elemType != 'SOLIDFACET': raise TypeError(f'''输入ansaType类型有误, 此函数要求输入的为shell单元或solid单元的表面类型(SOLIDFACET), 现输入类型为{elemType}''') # 获取单元法向量 elemVect:List[float] = Vector.elemNormal(elem) # 获取视角向量 viewVect:List[float] = getViewVector() # 计算两个向量的夹角,若为锐角,单元法向量为所求方向;若为钝角,单元法向量反方向为所求方向 angle:float = Vector.angle(elemVect, viewVect) if angle==-math.pi: raise ValueError(f'输入向量有误, 现输入向量为{elemVect}和{viewVect}, 请核查') if angle>math.pi/2.0: elemVect = [-vect for vect in elemVect] return elemVectdef calcCog(entities:List[base.Entity])->List[float]: ''' 名称: calcCog 描述: 计算输入的entities对象的cog 参数: entities List[base.Entity] 存在cog的可迭代对象或entity对象 返回值: 返回一个Cog向量(list) ''' if isinstance(entities, base.Entity): entities = [entities] length = len(entities) if length==0: return[0.0, 0.0, 0.0] if length==1: return base.Cog(entities[0]) x, y, z = 0.0, 0.0, 0.0 for ent in entities: cog = base.Cog(ent) x += cog[0] y += cog[1] z += cog[2] return [x/length, y/length, z/length]def getMinDistEntityFromPoint(point:List[float], entities:List[base.Entity])->base.Entity: ''' 名称: getMinDistEntityFromPoint 描述: 从输入的entities对象中选出距point最近的对象。 参数: point List[float] 参考点坐标 entities List[base.Entity] 存在cog的可迭代对象或entity对象 返回值: 返回距point点最近的对象。 ''' if not entities: return None if isinstance(entities, base.Entity): return entities if len(entities)==1: return entities[0] minDistance:float = math.inf minEntity:base.Entity = None for ent in entities: cog = base.Cog(ent) distance = Vector.distance(cog, point) if distance<minDistance: minDistance = distance minEntity = ent return minEntitydef main(): types:Tuple[str] = (ANSATYPE.eshell(DECK), 'SOLIDFACET') entities:List[base.Entity] = base.PickEntities(DECK, types, initial_type=types[0]) if not entities: return None if len(entities)==1: entity = entities[0] cog = base.Cog(entity) else: cog = calcCog(entities) entity = getMinDistEntityFromPoint(cog, entities) vect = getShellViewVector(entity) fields = {'XT': cog[0], 'YT': cog[1], 'ZT': cog[2], 'XH': cog[0]+vect[0], 'YH': cog[1]+vect[1], 'ZH': cog[2]+vect[2], 'Name': 'element normal vector'} base.CreateEntity(DECK, 'DEFINE_VECTOR', fields) viewVect = getViewVector() fields = {'XT': cog[0], 'YT': cog[1], 'ZT': cog[2], 'XH': cog[0]+viewVect[0], 'YH': cog[1]+viewVect[1], 'ZH': cog[2]+viewVect[2], 'Name': 'view vector'} base.CreateEntity(DECK, 'DEFINE_VECTOR', fields) return Noneif __name__ == '__main__': main()来源:檐苔