def create_orientated_vids(vids, normal): if SimpleMath.vector_length_3Ex(normal) < SimpleMath.Tol: print ("Degeneracy!!") return vids fNormal = SimpleMath.get_face_normal( [ModelData.dictVertices[vids[0]], ModelData.dictVertices[vids[1]], ModelData.dictVertices[vids[2]]] ) if SimpleMath.dot_product_3(normal, fNormal) > 0: return vids else: return (vids[1], vids[0], vids[2])
def coplaner_neighbors(fid, fNormal, tag): vertexIds = ModelData.dictFaces[fid].get_vids() for i in range(0, 3): j = 0 if i < 2: j = i + 1 face = CarveFunc.get_neighbor_shellface([vertexIds[i], vertexIds[j]], fid) if face not in tag and face is not None: newVertids = ModelData.dictFaces[face].get_vids() Normal = SimpleMath.get_face_normal([ModelData.dictVertices[newVertids[0]], ModelData.dictVertices[newVertids[1]], ModelData.dictVertices[newVertids[2]]]) if SimpleMath.vector_length_3(Normal) > SimpleMath.Tol and SimpleMath.dot_product_3(fNormal, Normal) > SimpleMath.NeighborAngle: tag.append(face) #only select the adjacent neighbors #coplaner_neighbors(face, Normal, tag)
def constraint_5(curTetId, faceIDsInCurTet): bIsInterior = False for i in faceIDsInCurTet: if ModelData.dictFaces[i].get_tag() == ClassFace.FIX: #normal check vIds = ModelData.dictFaces[i].get_vids() vectorNormal = SimpleMath.get_face_normal([ModelData.dictVertices[vIds[0]], ModelData.dictVertices[vIds[1]], ModelData.dictVertices[vIds[2]]]) for v in ModelData.dictTetrahedrons[curTetId].get_vids(): if v not in vIds: #test whether the tetrahedron is in the interior vectorTest = SimpleMath.tuple_minus(ModelData.dictVertices[v], ModelData.dictVertices[vIds[0]]); if SimpleMath.dot_product_3(vectorNormal , vectorTest) < 0: #find one inside return True return bIsInterior
def deduce_semantics_of_face(fid): #detect coplaner neighbours vertexList = ModelData.dictFaces[fid].get_vids() curNormal = SimpleMath.get_face_normal([ModelData.dictVertices[vertexList[0]], ModelData.dictVertices[vertexList[1]], ModelData.dictVertices[vertexList[2]]]) if SimpleMath.vector_length_3(curNormal) > SimpleMath.Tol: #Get the normals of neighbors of this face tag = [fid] coplaner_neighbors(fid, curNormal, tag) #statistic of dominant semantics within tagged faces counterSemantics = Counter() for fid in tag: counterSemantics[(ModelData.dictFaces[fid].get_id(), ModelData.dictFaces[fid].get_type())] += 1 res = counterSemantics.most_common(2) #get the semantics strId = '' strType = '' if len(res) == 1 and res[0][0] == ('', ''): #deduce the semantics based on direction strId = ModelDataFuncs.generate_uuid() angle = SimpleMath.dot_product_3(curNormal, (0.0, 0.0, 1.0)) if angle <= 1 and angle > 0.087: #roof 0 to 85 strType = 'BUILDING_ROOF_SURFACE' elif angle < -0.999: #ground -0 to -1 strType = 'BUILDING_GROUND_SURFACE' else: #wall strType = 'BUILDING_WALL_SURFACE' else: if res[0][0] != ('', ''): strId = res[0][0][0] strType = res[0][0][1] elif res[1][0] != ('', ''): strId = res[1][0][0] strType = res[1][0][1] #assign the semantics to all the raw face in tag for f in tag: if ModelData.dictFaces[f].get_id() == '' : ModelData.dictFaces[f].set_id(strId) if ModelData.dictFaces[f].get_type() == '' : ModelData.dictFaces[f].set_type(strType) else: ModelData.dictFaces[fid].set_id(ModelDataFuncs.generate_uuid()) ModelData.dictFaces[fid].set_type('BUILDING_WALL_SURFACE')
def boundary_of_coplaner_neighbors(fid, fNormal, fVisited, listUnbounded, listSeedFace): vertexIds = ModelData.dictFaces[fid].get_vids() for i in range(0, 3): j = 0 if i < 2: j = i + 1 #test the adjacent face face = get_neighbor_shellface((vertexIds[i], vertexIds[j]), fid) #test the edge code = is_edge_open_fix_boundary((vertexIds[i], vertexIds[j]), fid, face) if code == 1: #is a open fixed boundary then get one unvisited face as a seed if ModelData.dictFaces[face].get_tag() != ClassFace.FIX and face not in fVisited: if TetraFunc.get_dihedral_cos_angle(ModelData.dictFaces[face].get_vids(), ModelData.dictFaces[fid].get_vids()) > SimpleMath.NeighborAngle: if face not in listSeedFace: listSeedFace.append(face) elif code == 2: #is a close fixed boundary if not globalSealConcave: return False else: #not a boundary newVertids = ModelData.dictFaces[face].get_vids() Normal = SimpleMath.get_face_normal((ModelData.dictVertices[newVertids[0]], ModelData.dictVertices[newVertids[1]], ModelData.dictVertices[newVertids[2]])) if (SimpleMath.vector_length_3(Normal) > SimpleMath.Tol and abs(SimpleMath.dot_product_3(fNormal, Normal)) > SimpleMath.NeighborAngle) or \ SimpleMath.vector_length_3(Normal) < SimpleMath.Tol: if face not in fVisited: fVisited.append(face) if SimpleMath.vector_length_3(Normal) < SimpleMath.Tol: if not boundary_of_coplaner_neighbors(face, fNormal, fVisited, listUnbounded, listSeedFace): return False else: #note: False should be not be modified to not if False == boundary_of_coplaner_neighbors(face, Normal, fVisited, listUnbounded, listSeedFace): return False else: if face in listUnbounded: #if in, test if it is connected to an unbounded face return False else: if face not in fVisited: fVisited.append(face) return False
def get_dihedral_cos_angle(vids1, vids2): fNormal1 = SimpleMath.get_face_normal((ModelData.dictVertices[vids1[0]], ModelData.dictVertices[vids1[1]], ModelData.dictVertices[vids1[2]])) fNormal2 = SimpleMath.get_face_normal((ModelData.dictVertices[vids2[0]], ModelData.dictVertices[vids2[1]], ModelData.dictVertices[vids2[2]])) return SimpleMath.dot_product_3(fNormal1, fNormal2)
def optimise_illshaped_shellfaces(): iCount = 0 for key in ModelData.listShellFaceIDs: if key not in ModelData.dictFaces: continue if ( ModelData.global_OPTIMAL_SHP and ModelData.dictFaces[key].get_tag() != ClassFace.FLIP and ModelData.dictFaces[key].get_area() < ModelData.global_TOL_AREA_DISCARD ): print key vert0 = ModelData.dictVertices[ModelData.dictFaces[key].get_vids()[0]] vert1 = ModelData.dictVertices[ModelData.dictFaces[key].get_vids()[1]] vert2 = ModelData.dictVertices[ModelData.dictFaces[key].get_vids()[2]] # face collapse or flip # calculate vectors vector01 = SimpleMath.tuple_minus(vert0, vert1) length01 = SimpleMath.vector_length_3(vector01) if length01 > SimpleMath.Tol: vector01 = SimpleMath.tuple_numproduct(1.0 / length01, vector01) else: iCount += 1 collapse_edge(ModelData.dictFaces[key].get_vids()[0], ModelData.dictFaces[key].get_vids()[1]) continue vector21 = SimpleMath.tuple_minus(vert2, vert1) length21 = SimpleMath.vector_length_3(vector21) if length21 > SimpleMath.Tol: vector21 = SimpleMath.tuple_numproduct(1.0 / length21, vector21) else: iCount += 1 collapse_edge(ModelData.dictFaces[key].get_vids()[2], ModelData.dictFaces[key].get_vids()[1]) continue vector02 = SimpleMath.tuple_minus(vert0, vert2) length02 = SimpleMath.vector_length_3(vector02) if length02 > SimpleMath.Tol: vector02 = SimpleMath.tuple_numproduct(1.0 / length02, vector02) else: iCount += 1 collapse_edge(ModelData.dictFaces[key].get_vids()[0], ModelData.dictFaces[key].get_vids()[2]) continue # calculate angles Ang012 = SimpleMath.dot_product_3(vector01, vector21) Ang102 = SimpleMath.dot_product_3(vector01, vector02) vector12 = SimpleMath.tuple_numproduct(-1, vector21) Ang021 = SimpleMath.dot_product_3(vector02, vector12) # cos value if Ang012 < ModelData.global_TOL_LARGEST_ANGLE: # flip 20 iCount += 1 flip_edge(ModelData.dictFaces[key].get_vids()[2], ModelData.dictFaces[key].get_vids()[0]) elif Ang102 < ModelData.global_TOL_LARGEST_ANGLE: # flip 12 iCount += 1 flip_edge(ModelData.dictFaces[key].get_vids()[1], ModelData.dictFaces[key].get_vids()[2]) elif Ang021 < ModelData.global_TOL_LARGEST_ANGLE: # flip 01 iCount += 1 flip_edge(ModelData.dictFaces[key].get_vids()[0], ModelData.dictFaces[key].get_vids()[1]) # # clean_unreferenced_vertices() print ("{} illshaped ModelData.dictFaces are optimized").format(iCount) if iCount > 0: return True else: return False