在ANSA二次开发中经常获取当前视角下被选中单元和视角一致的法向量以备后续操作。本文主要通过创建视角向量和被选中单元的法向量来展示这一过程。
首先,需要对中的错误进行更正:ansa中GetViewAngles函数旋转顺序为Z->Y->Z;且以顺时针为正,和一般笛卡尔坐标相反。因此有:

import mathfrom typing import List, Tuplefrom ansa import basefrom ansa import constantsfrom ansa import calcclass ANSATYPE(object):'''不同求解器对应关键字名字'''@class methoddef 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', # OPTISTRUCT23: 'SHELL' # MARC}try:_type = typDict[deck]except KeyError:raise ValueError('ERROR: 模型Deck设置有误')return _type@class methoddef node(cls, deck:int)->str:typDict:dict = {constants.LSDYNA: 'NODE',constants.ABAQUS:'NODE',constants.NASTRAN: 'GRID',constants.RADIOSS: 'NODE',constants.ANSYS: 'NODE',22: 'GRID', # OPTISTRUCT23: 'NODE' # MARC}try:_type = typDict[deck]except KeyError:raise ValueError('ERROR: 模型Deck设置有误')return _typeclass Vector(object):@class methoddef point2Point(cls, point1:List[float], point2:List[float], unit:bool=True)->List[float]:'''计算两点构成的向量. 向量由point1指向point2,即point2-point1'''if isinstance(point1, base.Entity): point1 = point1.positionif isinstance(point2, base.Entity): point2 = point2.positionvect:List[float] = [p2-p1 for p1, p2 in zip(point1, point2)]return cls.unit(vect) if unit else vect@staticmethoddef unit(vector:List[float])->List[float]:'''将一个向量单位化'''return calc.Normalize(vector)@staticmethoddef distance(point1:List[float], point2:List[float])->float:'''计算两点间的距离'''if isinstance(point1, base.Entity): point1 = point1.positionif isinstance(point2, base.Entity): point2 = point2.positionreturn math.dist(point1, point2)@class methoddef 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)])@staticmethoddef angle(vector1:List[float], vector2:List[float])->float:'''计算两个空间向量的夹角,返回值以弧度形式存在'''return calc.CalcAngleOfVectors(vector1, vector2)@class methoddef elemNormal(cls, shellElem:base.Entity)->List[float]:'''根据单元的前三个节点计算单元的法向量'''vect:List[float] = base.GetNormalVectorOfShell(shellElem)if isinstance(vect, list):return vectelse: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 methoddef 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.0for 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 Noneif isinstance(entities, base.Entity): return entitiesif len(entities)==1: return entities[0]minDistance:float = math.infminEntity:base.Entity = Nonefor ent in entities:cog = base.Cog(ent)distance = Vector.distance(cog, point)if distance<minDistance:minDistance = distanceminEntity = entreturn 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 Noneif 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()