def get_neighbors_around_minima(f, polyData, rd): points = np.array(polyData.GetPoints().GetData()) gaussian = get_curvature_gaussian(rd) Mean = get_curvature_mean(rd) normals = get_normals(rd) T_Tree = vtk.vtkKdTreePointLocator() T_Tree.SetDataSet(polyData) T_Tree.BuildLocator() neighbours = [] neighbours.append([ points[f][0], points[f][1], points[f][2], 0, gaussian[f], Mean[f], normals[f][0], normals[f][1], normals[f][2] ]) f = [points[f][0], points[f][1], points[f][2]] result = vtk.vtkIdList() num_of_neighbors = 200 T_Tree.FindClosestNPoints(num_of_neighbors, f, result) for i in range(0, result.GetNumberOfIds()): point_ind = result.GetId(i) closestPoint = [0.0, 0.0, 0.0] T_Tree.GetDataSet().GetPoint(point_ind, closestPoint) distance = float( math.sqrt(vtk.vtkMath.Distance2BetweenPoints(closestPoint, f))) neighbours.append([ closestPoint[0], closestPoint[1], closestPoint[2], distance, gaussian[point_ind], Mean[point_ind], normals[point_ind][0], normals[point_ind][1], normals[point_ind][2] ]) y = np.array([np.array(xi) for xi in neighbours]) return np.array(neighbours)
def transfer_mesh_scalars_get_weighted_average_n_closest( new_mesh, old_mesh, n=3): kDTree = vtk.vtkKdTreePointLocator() kDTree.SetDataSet(old_mesh) kDTree.BuildLocator() new_scalars = np.zeros(new_mesh.GetNumberOfPoints()) scalars_old_mesh = np.copy( vtk_to_numpy(old_mesh.GetPointData().GetScalars())) for new_mesh_pt_idx in range(new_mesh.GetNumberOfPoints()): point = new_mesh.GetPoint(new_mesh_pt_idx) closest_ids = vtk.vtkIdList() kDTree.FindClosestNPoints(n, point, closest_ids) list_scalars = [] distance_weighting = [] for closest_pts_idx in range(closest_ids.GetNumberOfIds()): pt_idx = closest_ids.GetId(closest_pts_idx) _point = old_mesh.GetPoint(pt_idx) list_scalars.append(scalars_old_mesh[pt_idx]) distance_weighting.append(1 / np.sqrt( np.sum(np.square(np.asarray(point) - np.asarray(_point))))) total_distance = np.sum(distance_weighting) normalized_value = np.sum( np.asarray(list_scalars) * np.asarray(distance_weighting)) / total_distance new_scalars[new_mesh_pt_idx] = normalized_value return new_scalars
def build_kd_tree(mesh): """ This function.. :param mesh: :return: """ kd_tree = vtk.vtkKdTreePointLocator() kd_tree.SetDataSet(mesh) kd_tree.BuildLocator() return kd_tree
def locator(filename): vtk_reader = vtk.vtkXMLUnstructuredGridReader() vtk_reader.SetFileName(filename) vtk_reader.Update() grid = vtk_reader.GetOutput() kdtree = vtk.vtkKdTreePointLocator() kdtree.SetDataSet(grid) kdtree.BuildLocator() time = numpy_support.vtk_to_numpy(grid.GetPointData().GetScalars()) return kdtree, time
def find_closest_point(vtk_obj, point=(0., 0., 0.)): pointTree = vtk.vtkKdTreePointLocator() pointTree.SetDataSet(vtk_obj) pointTree.BuildLocator() radius = None if radius is None: vtkId = pointTree.FindClosestPoint(point) pcoord = vtk_obj.GetPoint(vtkId) return vtkId, pcoord
def find_point_correspondence(mesh, points): """ Find the point IDs of the points on a VTK PolyData Args: mesh: the PolyData to find IDs on points: vtk Points Returns IdList: list containing the IDs """ IdList = [None] * points.GetNumberOfPoints() locator = vtk.vtkKdTreePointLocator() locator.SetDataSet(mesh) locator.BuildLocator() for i in range(len(IdList)): newPt = points.GetPoint(i) IdList[i] = locator.FindClosestPoint(newPt) return IdList
def keyPressEvent(self,obj,event): key = self.parent.GetKeySym() if key == 'Tab': if self.ActiveSelection == 0: self.ActiveSelection = 1 self.textActor.SetInput("Current selection: max point (green)") print("To locate max point") self.parent.GetRenderWindow().Render() else: self.ActiveSelection = 0 self.textActor.SetInput("Current selection: min point (red)") print("To locate min point") self.parent.GetRenderWindow().Render() if key == "space": self.parent.GetPicker().Pick(self.parent.GetEventPosition()[0], self.parent.GetEventPosition()[1], 0, # always zero. self.parent.GetRenderWindow().GetRenderers().GetFirstRenderer()) picked = self.parent.GetPicker().GetPickPosition(); # Create kd tree kDTree = vtk.vtkKdTreePointLocator() kDTree.SetDataSet(self.centerline) kDTree.BuildLocator() # Find the closest points to picked point iD = kDTree.FindClosestPoint(picked) # Get the coordinates of the closest point closestPoint = kDTree.GetDataSet().GetPoint(iD) if self.ActiveSelection == 0: self.minSphereSource.SetCenter(closestPoint) else: self.maxSphereSource.SetCenter(closestPoint) self.parent.GetRenderWindow().Render() if key == "Return": # Close the window self.parent.GetRenderWindow().Finalize() # Stop the interactor self.parent.TerminateApp() return
def FindNewLandmarks(vtkPoints, meanSurfaceFilename, dirOutput): newLandmarks = vtk.vtkPoints() reader = vtk.vtkPolyDataReader() reader.SetFileName(meanSurfaceFilename) reader.Update() meanSurface = reader.GetOutput() print(meanSurface.GetBounds()) kdTree = vtk.vtkKdTreePointLocator() kdTree.SetDataSet(meanSurface) kdTree.BuildLocator() for index in range(vtkPoints.GetNumberOfPoints()): point = [0, 0, 0] closestPoint = [0, 0, 0] vtkPoints.GetPoint(index, point) print(point) idx = kdTree.FindClosestPoint(point) kdTree.GetDataSet().GetPoint(idx, closestPoint) print(closestPoint) newLandmarks.InsertNextPoint(closestPoint) filename = meanSurfaceFilename[:-4] + '.txt' WriteLandmarkFile(newLandmarks, filename)
def translesional_result(centerline_file, wall_file,vtk_file_list, output_dir,minPoint=(0,0,0), prox_dist=5, dist_dist=5): # read centerline centerlineReader = vtk.vtkXMLPolyDataReader() centerlineReader.SetFileName(centerline_file) centerlineReader.Update() centerline = centerlineReader.GetOutput() # read vessel wall wallReader = vtk.vtkSTLReader() wallReader.SetFileName(wall_file) wallReader.Update() # read vtk files vtk_files = [] centerlines = [] if not os.path.exists(output_dir): os.makedirs(output_dir) if not os.path.exists(os.path.join(output_dir,"centerlines")): os.makedirs(os.path.join(output_dir,"centerlines")) # average filter averageFilter = vtk.vtkTemporalStatistics() for file_name in vtk_file_list: reader = vtk.vtkUnstructuredGridReader() reader.SetFileName(file_name) reader.Update() geomFilter = vtk.vtkGeometryFilter() geomFilter.SetInputData(reader.GetOutput()) geomFilter.Update() # scale up the CFD result transform = vtk.vtkTransform() transform.Scale(1000,1000,1000) transformFilter = vtk.vtkTransformPolyDataFilter() transformFilter.SetInputData(geomFilter.GetOutput()) transformFilter.SetTransform(transform) transformFilter.Update() vtk_files.append(transformFilter.GetOutput()) interpolator = vtk.vtkPointInterpolator() interpolator.SetSourceData(transformFilter.GetOutput()) interpolator.SetInputData(centerline) interpolator.Update() # convert to desired unit # get the first element pressure try: first_point_pressure = interpolator.GetOutput().GetPointData().GetArray("p").GetValue(0) except: first_point_pressure = 120 converter = vtk.vtkArrayCalculator() converter.SetInputData(interpolator.GetOutput()) converter.AddScalarArrayName("p") converter.SetFunction("120 + (p - {}) * 921 * 0.0075".format(first_point_pressure)) # 921 = mu/nu = density of blood, 0.0075 converts from Pascal to mmHg, offset 120mmHg at ica converter.SetResultArrayName("p(mmHg)") converter.Update() converter2 = vtk.vtkArrayCalculator() converter2.SetInputData(converter.GetOutput()) converter2.AddVectorArrayName("wallShearStress") converter2.SetFunction("wallShearStress * 921") # 921 = mu/nu = density of blood, 0.0075 converts from Pascal to mmHg, http://aboutcfd.blogspot.com/2017/05/wallshearstress-in-openfoam.html converter2.SetResultArrayName("wallShearStress(Pa)") converter2.Update() # output the probe centerline centerline_output_path = os.path.join( os.path.dirname(centerline_file), output_dir, "centerlines", "centerline_probe_{}.vtp".format(os.path.split(file_name)[1].split("_")[1].split(".")[0]) ) centerlines.append(converter2.GetOutput()) averageFilter.SetInputData(converter2.GetOutput()) averageFilter.Update() centerline = averageFilter.GetOutput() # extract lesion section # get the abscissas of min radius point # Create kd tree kDTree = vtk.vtkKdTreePointLocator() kDTree.SetDataSet(centerline) kDTree.BuildLocator() minIdx = kDTree.FindClosestPoint(minPoint) minPoint_absc = centerline.GetPointData().GetArray("Abscissas_average").GetTuple(minIdx)[0] thresholdFilter = vtk.vtkThreshold() thresholdFilter.ThresholdBetween(minPoint_absc-prox_dist,minPoint_absc+dist_dist) thresholdFilter.SetInputData(centerline) thresholdFilter.SetAllScalars(0) # important !!! thresholdFilter.SetInputArrayToProcess(0, 0, 0, vtk.vtkDataObject.FIELD_ASSOCIATION_POINTS,"Abscissas_average"); thresholdFilter.Update() # to vtkpolydata geometryFilter = vtk.vtkGeometryFilter() geometryFilter.SetInputData(thresholdFilter.GetOutput()) geometryFilter.Update() # get closest line connectFilter = vtk.vtkConnectivityFilter() connectFilter.SetExtractionModeToClosestPointRegion() connectFilter.SetClosestPoint(minPoint) connectFilter.SetInputData(geometryFilter.GetOutput()) connectFilter.Update() # compute result values abscissas = vtk_to_numpy(thresholdFilter.GetOutput().GetPointData().GetArray("Abscissas_average")) abscissas_unique, index = np.unique(sorted(abscissas), axis=0, return_index=True) pressure = vtk_to_numpy(thresholdFilter.GetOutput().GetPointData().GetArray("p(mmHg)_average")) pressure = [x for _, x in sorted(zip(abscissas,pressure))] pressure = [pressure[x] for x in index] pressure_gradient = np.diff(pressure)/np.diff(abscissas_unique) velocity = vtk_to_numpy(thresholdFilter.GetOutput().GetPointData().GetArray("U_average")) velocity = [math.sqrt(value[0]**2 + value[1]**2 +value[2]**2 ) for value in velocity] velocity = [x for _, x in sorted(zip(abscissas,velocity))] velocity = [velocity[x] for x in index] velocity_gradient = np.diff(velocity)/np.diff(abscissas_unique) vorticity = vtk_to_numpy(thresholdFilter.GetOutput().GetPointData().GetArray("vorticity_average")) vorticity = [math.sqrt(value[0]**2 + value[1]**2 +value[2]**2 ) for value in vorticity] vorticity = [x for _, x in sorted(zip(abscissas,vorticity))] vorticity = [vorticity[x] for x in index] vorticity_gradient = np.diff(vorticity)/np.diff(abscissas_unique) wss = vtk_to_numpy(thresholdFilter.GetOutput().GetPointData().GetArray("wallShearStress(Pa)_average")) wss = [math.sqrt(value[0]**2 + value[1]**2 +value[2]**2 ) for value in wss] wss = [wss[x] for x in index] wss = [x for _, x in sorted(zip(abscissas,wss))] wss_gradient = np.diff(wss)/np.diff(abscissas_unique) epsilon = 0.00001 p_ratio = np.mean(pressure[-4:-1])/(np.mean(pressure[0:3])+epsilon) u_ratio = np.mean(velocity[-4:-1])/(np.mean(velocity[0:3])+epsilon) w_ratio = np.mean(vorticity[-4:-1])/(np.mean(vorticity[0:3])+epsilon) wss_ratio = np.mean(wss[-4:-1])/(np.mean(wss[0:3])+epsilon) dp_ratio = np.mean(pressure_gradient[-4:-1])/(np.mean(pressure_gradient[0:3])+epsilon) du_ratio = np.mean(velocity_gradient[-4:-1])/(np.mean(velocity_gradient[0:3])+epsilon) dw_ratio = np.mean(vorticity_gradient[-4:-1])/(np.mean(vorticity_gradient[0:3])+epsilon) dwss_ratio = np.mean(wss_gradient[-4:-1])/(np.mean(wss_gradient[0:3])+epsilon) return_value = { 'translesion peak presssure(mmHg)': np.mean(heapq.nlargest(1, pressure)), 'translesion presssure ratio': p_ratio, 'translesion peak pressure gradient(mmHgmm^-1)': np.mean(heapq.nlargest(1, pressure_gradient)), 'translesion pressure gradient ratio': dp_ratio, 'translesion peak velocity(ms^-1)': np.mean(heapq.nlargest(1, velocity)), 'translesion velocity ratio': u_ratio, 'translesion velocity gradient ratio': du_ratio, 'translesion peak velocity gradient(ms^-1mm^-1)': np.mean(heapq.nlargest(1, velocity_gradient)), 'translesion peak vorticity(ms^-1)': np.mean(heapq.nlargest(1, vorticity)), 'translesion vorticity ratio': w_ratio, 'translesion vorticity gradient ratio': dw_ratio, 'translesion peak vorticity gradient(Pamm^-1)':np.mean(heapq.nlargest(1, vorticity_gradient)), 'translesion peak wss(Pa)': np.mean(heapq.nlargest(1, wss)), 'translesion peak wss gradient(Pamm^-1)': np.mean(heapq.nlargest(1, wss_gradient)), 'translesion wss ratio': wss_ratio, 'translesion wss gradient ratio': dwss_ratio, } return return_value
def probe_min_max_point(centerline_filename, surface_filename, minPoint=(0,0,0), maxPoint=(0,0,0),probe=True): centerlineReader = vtk.vtkXMLPolyDataReader() centerlineReader.SetFileName(centerline_filename) centerlineReader.Update() centerline = centerlineReader.GetOutput() centerline.GetCellData().SetScalars(centerline.GetCellData().GetArray(2)); centerline.GetPointData().SetScalars(centerline.GetPointData().GetArray("Radius")); surfaceReader = vtk.vtkSTLReader() surfaceReader.SetFileName(surface_filename) surfaceReader.Update() surface = surfaceReader.GetOutput() lut = vtk.vtkLookupTable() # lut.SetNumberOfTableValues(3); lut.Build() # Fill in a few known colors, the rest will be generated if needed # lut.SetTableValue(0, 1.0000, 0 , 0, 1); # lut.SetTableValue(1, 0.0000, 1.0000, 0.0000, 1); # lut.SetTableValue(2, 0.0000, 0.0000, 1.0000, 1); centerlineMapper = vtk.vtkPolyDataMapper() centerlineMapper.SetInputData(centerline) centerlineMapper.SetScalarRange(0, centerline.GetPointData().GetScalars().GetMaxNorm()); centerlineMapper.SetLookupTable(lut); centerlineMapper.SetScalarModeToUsePointData() surfaceMapper = vtk.vtkPolyDataMapper() surfaceMapper.SetInputData(surface) scalarBar = vtk.vtkScalarBarActor() scalarBar.SetLookupTable(centerlineMapper.GetLookupTable()); scalarBar.SetTitle("Radius"); scalarBar.SetNumberOfLabels(4); scalarBar.SetWidth(0.08) scalarBar.SetHeight(0.6) scalarBar.SetPosition(0.9,0.1) # auto find the smallest radius point radius = centerline.GetPointData().GetArray("Radius") # build kd tree to locate the nearest point # Create kd tree kDTree = vtk.vtkKdTreePointLocator() kDTree.SetDataSet(centerline) kDTree.BuildLocator() minSource = vtk.vtkSphereSource() if minPoint == (0,0,0): minIdx = vtkArrayMin(radius) closestPoint = centerline.GetPoint(minIdx) else: # Find the closest point to the picked point iD = kDTree.FindClosestPoint(minPoint) # Get the id of the closest point closestPoint = kDTree.GetDataSet().GetPoint(iD) minSource.SetCenter(closestPoint) minSource.SetRadius(0.3); minMapper = vtk.vtkPolyDataMapper() minMapper.SetInputConnection(minSource.GetOutputPort()); minActor = vtk.vtkActor() minActor.SetMapper(minMapper); minActor.GetProperty().SetColor((1.0,0.0,0.0)) maxSource = vtk.vtkSphereSource() if maxPoint == (0,0,0): maxIdx = vtkArrayMin(radius) closestPoint = centerline.GetPoint(maxIdx) else: # Find the closest point to the picked point iD = kDTree.FindClosestPoint(maxPoint) # Get the id of the closest point closestPoint = kDTree.GetDataSet().GetPoint(iD) maxSource.SetCenter(closestPoint) maxSource.SetRadius(0.3); maxMapper = vtk.vtkPolyDataMapper() maxMapper.SetInputConnection(maxSource.GetOutputPort()); maxActor = vtk.vtkActor() maxActor.SetMapper(maxMapper); maxActor.GetProperty().SetColor((0.0,1.0,0.0)) centerlineActor = vtk.vtkActor() centerlineActor.SetMapper(centerlineMapper) surfaceActor = vtk.vtkActor() surfaceActor.SetMapper(surfaceMapper) surfaceActor.GetProperty().SetOpacity(0.3) # text actor usageTextActor = vtk.vtkTextActor() usageTextActor.GetPositionCoordinate().SetCoordinateSystemToNormalizedViewport() usageTextActor.GetPosition2Coordinate().SetCoordinateSystemToNormalizedViewport() usageTextActor.SetPosition([0.001, 0.05]) usageTextActor.SetInput("Tab: Switch max/min point\nSpace: Locate max/min point\nEnter/Close Window: Process") currentSelectionTextActor = vtk.vtkTextActor() currentSelectionTextActor.GetPositionCoordinate().SetCoordinateSystemToNormalizedViewport() currentSelectionTextActor.GetPosition2Coordinate().SetCoordinateSystemToNormalizedViewport() currentSelectionTextActor.SetPosition([0.25, 0.1]) currentSelectionTextActor.SetInput("Current selection: min point (red)") if probe: renderer = vtk.vtkRenderer() renderer.AddActor(centerlineActor) renderer.AddActor(surfaceActor) renderer.AddActor(minActor) renderer.AddActor(maxActor) renderer.AddActor2D(scalarBar) renderer.AddActor(usageTextActor) renderer.AddActor(currentSelectionTextActor) renderWindow = vtk.vtkRenderWindow() renderWindow.AddRenderer(renderer) renderWindowInteractor = vtk.vtkRenderWindowInteractor() renderWindowInteractor.SetRenderWindow(renderWindow) mystyle = MyInteractorStyle(renderWindowInteractor) mystyle.SetMaxSphereSource(maxSource) mystyle.SetMinSphereSource(minSource) mystyle.SetCenterline(centerline) mystyle.SetSelectionTextActor(currentSelectionTextActor) renderWindowInteractor.SetInteractorStyle(mystyle) renderWindow.SetSize(1024,780); #(width, height) renderWindow.Render() renderWindowInteractor.Start() minPoint = minSource.GetCenter() maxPoint = maxSource.GetCenter() # compute degree of stenosis minIdx = kDTree.FindClosestPoint(minPoint) minRadius = centerline.GetPointData().GetArray("Radius").GetTuple(minIdx)[0] maxIdx = kDTree.FindClosestPoint(maxPoint) maxRadius = centerline.GetPointData().GetArray("Radius").GetTuple(maxIdx)[0] DoS = (1-minRadius/maxRadius)*100 tqdm.write("min radius = {:.2f}\nmax radius = {:.2f} mm\nDegree of stenosis = {:.2f} %".format(minRadius,maxRadius,DoS)) return DoS, minPoint, maxPoint
def moving_variance_matrix(centerline,fields, windows, minPoint=(0,0,0), bifurcationPoint=(0,0,0), result_path="", dev_result_path=""): # create input array from centerline thresholdFilter = vtk.vtkThreshold() thresholdFilter.SetInputData(centerline) thresholdFilter.SetInputArrayToProcess(0, 0, 0, vtk.vtkDataObject.FIELD_ASSOCIATION_CELLS, "CenterlineIds_average") thresholdFilter.Update() fig, axs = plt.subplots(len(fields),1) fig.suptitle("CFD Moving Variance") fig.set_size_inches(10,8) fig2, axs2 = plt.subplots(len(fields),1) fig2.suptitle("CFD Derivative Moving Variance") fig2.set_size_inches(10,8) # build kd tree to locate the nearest point # Create kd tree kDTree = vtk.vtkKdTreePointLocator() kDTree.SetDataSet(centerline) kDTree.BuildLocator() # get the abscissas of bifurcation point if bifurcationPoint != (0,0,0): iD = kDTree.FindClosestPoint(bifurcationPoint) # Get the id of the closest point bifPointAbscissas = kDTree.GetDataSet().GetPointData().GetArray("Abscissas_average").GetTuple(iD)[0] - \ vtk_to_numpy(thresholdFilter.GetOutput().GetPointData().GetArray("Abscissas_average"))[0] # get the abscissas of min point if minPoint != (0,0,0): iD = kDTree.FindClosestPoint(minPoint) # Get the id of the closest point minPointAbscissas = kDTree.GetDataSet().GetPointData().GetArray("Abscissas_average").GetTuple(iD)[0] - \ vtk_to_numpy(thresholdFilter.GetOutput().GetPointData().GetArray("Abscissas_average"))[0] col_name = ["branch","window"] + fields pmv_df = pd.DataFrame(columns=col_name) col_name_dy = ["branch","window"] + [y+"_dev" for y in fields] pmv_dy_df = pd.DataFrame(columns=col_name_dy) for lineId in range(int(centerline.GetCellData().GetArray("CenterlineIds_average").GetMaxNorm())): a_x = [] a_y = [] a_dy = [] thresholdFilter.ThresholdBetween(lineId,lineId) thresholdFilter.Update() # need at least 3 points to perform interpolation if thresholdFilter.GetOutput().GetNumberOfPoints() < 4: continue for i in range(len(fields)): x = vtk_to_numpy(thresholdFilter.GetOutput().GetPointData().GetArray("Abscissas_average")) x = [(value - x[0]) for value in x] y = vtk_to_numpy(thresholdFilter.GetOutput().GetPointData().GetArray(fields[i])) if len(y.shape) > 1: if y.shape[1] == 3: y = [math.sqrt(value[0]**2 + value[1]**2 +value[2]**2 ) for value in y] order = np.argsort(x) xs = np.array(x)[order] ys = np.array(y)[order] unique, index = np.unique(xs, axis=-1, return_index=True) xs = xs[index] ys = ys[index] f = interp1d(xs,ys,kind="cubic") xnew = np.linspace(0, np.amax(x), num=50, endpoint=True) ynew = f(xnew) dy = np.gradient(ynew, xnew) a_x.append(xnew) a_y.append(ynew) a_dy.append(dy) a_x = np.array(a_x) a_y = np.array(a_y) a_dy = np.array(a_dy) for window in windows: mv = np.var(rolling_window(a_y, window) , axis=-1) mv_dy = np.var(rolling_window(a_dy, window) , axis=-1) pmv = np.amax(mv,axis=-1) pmv = np.concatenate(([lineId,window],pmv)) pmv_df.loc[len(pmv_df)] = pmv pmv_dy = np.amax(mv_dy,axis=-1) pmv_dy = np.concatenate(([lineId,window],pmv_dy)) pmv_dy_df.loc[len(pmv_dy_df)] = pmv_dy for i in range(len(fields)): # plot moving variance if len(fields) == 1: ax = axs ax2 = axs2 else: ax = axs[i] ax2 = axs2[i] ax.plot(a_x[i,:],mv[i,:]) ax2.plot(a_x[i,:],mv_dy[i,:]) if fields[i] == "Radius_average": ylabel = "Radius (mm)" ymin = 0 ymax = 0.5 elif fields[i] == "U_average": ylabel = "Velocity (ms^-1)" ymin = 0 ymax = 0.5 elif fields[i] == "p(mmHg)_average": ylabel = "Pressure (mmHg)" ymin = 0 ymax = 1e3 elif fields[i] == "vorticity_average": ylabel = "Vorticity (s^-1)" ymin = 0 ymax = 1e7 elif fields[i] == "Curvature_average": ylabel = "Curvature" ymin = 0 ymax = 1e0 elif fields[i] == "Torsion_average": ylabel = "Torsion" ymin = 0 ymax = 1e9 if bifurcationPoint !=(0,0,0): ax.axvline(x=bifPointAbscissas,ymin=0,ymax=1,linestyle="--",color='m') ax2.axvline(x=bifPointAbscissas,ymin=0,ymax=1,linestyle="--",color='m') if minPoint !=(0,0,0): ax.axvline(x=minPointAbscissas,ymin=0,ymax=1,linestyle="--",color='c') ax2.axvline(x=minPointAbscissas,ymin=0,ymax=1,linestyle="--",color='c') ax.set_ylabel(ylabel) ax2.set_ylabel(ylabel) if i == (len(fields)-1): ax.set_xlabel("Abscissas (mm)") ax2.set_xlabel("Abscissas (mm)") else: ax.set_xticklabels([]) ax2.set_xticklabels([]) ax.set_xlim(x[0],x[-1]) ax.set_ylim(ymin,ymax) ax2.set_xlim(x[0],x[-1]) ax2.set_ylim(ymin,ymax) # save the plot fig.savefig(result_path,dpi=100) fig.clf() fig2.savefig(dev_result_path,dpi=100) fig2.clf() plt.close("all") pmv_df = pmv_df.groupby(['window']).max() pmv_df = pmv_df.drop(columns=['branch']) pmv_dy_df = pmv_dy_df.groupby(['window']).max() pmv_dy_df = pmv_dy_df.drop(columns=['branch']) return pmv_df, pmv_dy_df
def plot_centerline_result(centerline, array_names, result_path, dev_result_path ,minPoint=(0,0,0),bifurcationPoint=(0,0,0)): thresholdFilter = vtk.vtkThreshold() thresholdFilter.ThresholdBetween(1,9999) thresholdFilter.SetInputData(centerline) thresholdFilter.SetInputArrayToProcess(0, 0, 0, vtk.vtkDataObject.FIELD_ASSOCIATION_CELLS, "CenterlineIds_average") thresholdFilter.Update() x = vtk_to_numpy(thresholdFilter.GetOutput().GetPointData().GetArray("Abscissas_average")) x = [(value - x[0]) for value in x] kDTree = vtk.vtkKdTreePointLocator() kDTree.SetDataSet(centerline) kDTree.BuildLocator() # get the abscissas of bifurcation point if bifurcationPoint != (0,0,0): iD = kDTree.FindClosestPoint(bifurcationPoint) # Get the id of the closest point bifPointAbscissas = kDTree.GetDataSet().GetPointData().GetArray("Abscissas_average").GetTuple(iD)[0] - \ vtk_to_numpy(thresholdFilter.GetOutput().GetPointData().GetArray("Abscissas_average"))[0] # get the abscissas of min point if minPoint != (0,0,0): iD = kDTree.FindClosestPoint(minPoint) # Get the id of the closest point minPointAbscissas = kDTree.GetDataSet().GetPointData().GetArray("Abscissas_average").GetTuple(iD)[0] - \ vtk_to_numpy(thresholdFilter.GetOutput().GetPointData().GetArray("Abscissas_average"))[0] fig, axs = plt.subplots(len(array_names),1) fig.suptitle("CFD result") fig.set_size_inches(10,8) fig2, axs2 = plt.subplots(len(array_names),1) fig2.suptitle("CFD result derivatives") fig2.set_size_inches(10,8) fit_dict= {} for i in range(len(array_names)): popt_list = [] for lineId in range(int(centerline.GetCellData().GetArray("CenterlineIds_average").GetMaxNorm())): thresholdFilter.ThresholdBetween(lineId,lineId) thresholdFilter.Update() x = vtk_to_numpy(thresholdFilter.GetOutput().GetPointData().GetArray("Abscissas_average")) x = [(value - x[0]) for value in x] if len(x) < 3: continue y = vtk_to_numpy(thresholdFilter.GetOutput().GetPointData().GetArray(array_names[i])) if len(y.shape) > 1: if y.shape[1] == 3: y = [math.sqrt(value[0]**2 + value[1]**2 +value[2]**2 ) for value in y] if len(array_names) == 1: ax = axs ax2 = axs2 else: ax = axs[i] ax2 = axs2[i] order = np.argsort(x) xs = np.array(x)[order] ys = np.array(y)[order] unique, index = np.unique(xs, axis=-1, return_index=True) xs = xs[index] ys = ys[index] f = interp1d(xs,ys,kind="cubic") xs = np.linspace(0, np.amax(x), num=200, endpoint=True) ys = f(xs) dys = np.gradient(ys, xs) ax.plot(xs,ys) ax2.plot(xs,dys) # curve fitting on specific values if array_names[i] == "Radius_average" or array_names[i] == "U_average" or array_names[i] == "p(mmHg)_average": try: popt, pcov = curve_fit(fit_func, xs, dys, p0=[50,0.1,-50]) yfit = fit_func(xs, *popt) ax2.plot(xs, fit_func(xs, *popt), 'k-.',label='fit: a=%5.3f, b=%5.3f, c=%5.3f' % tuple(popt)) except RuntimeError: popt = [0,0,0] popt_list.append(popt) if array_names[i] == "Radius_average": ylabel = "Radius (mm)" ymin=0 ymax = 5 ymin2=-5 ymax2 = 5 elif array_names[i] == "U_average": ylabel = "Velocity (ms^-1)" ymin=0 ymax = 3 ymin2=-3 ymax2 = 3 elif array_names[i] == "p(mmHg)_average": ylabel = "Pressure (mmHg)" ymin=0 ymax = 180 ymin2=-180 ymax2 = 180 elif array_names[i] == "vorticity_average": ylabel = "Vorticity (s^-1)" ymin=0 ymax = 4000 ymin2=-4000 ymax2 = 4000 elif array_names[i] == "Curvature_average": ylabel = "Curvature" ymin = -1.5 ymax = 1.5 ymin2 = -1.5 ymax2 = 1.5 elif array_names[i] == "Torsion_average": ylabel = "Torsion" ymin = -100000 ymax = 100000 ymin2 = -100000 ymax2 = 100000 if bifurcationPoint !=(0,0,0): ax.axvline(x=bifPointAbscissas,ymin=ymin,ymax=ymax,linestyle ="--",color='m') ax2.axvline(x=bifPointAbscissas,ymin=ymin,ymax=ymax,linestyle ="--",color='m') if minPoint !=(0,0,0): ax.axvline(x=minPointAbscissas,ymin=ymin,ymax=ymax,linestyle ="--",color='c') ax2.axvline(x=minPointAbscissas,ymin=ymin,ymax=ymax,linestyle ="--",color='c') ax.set_ylabel(ylabel) ax2.set_ylabel(ylabel) if i == (len(array_names)-1): ax.set_xlabel("Abscissas (mm)") ax2.set_xlabel("Abscissas (mm)") else: ax.set_xticklabels([]) ax2.set_xticklabels([]) x = vtk_to_numpy(centerline.GetPointData().GetArray("Abscissas_average")) ax.set_xlim(x[0],x[-1]) ax.set_ylim(ymin,ymax) ax2.set_xlim(x[0],x[-1]) ax2.set_ylim(ymin2,ymax2) # max of popt[0] if len(popt_list) > 0: fit_dict.update({array_names[i]: np.abs(np.amax(np.array(popt_list),axis=0)[0])}) # save the plot fig.savefig(result_path,dpi=100) fig.clf() fig2.savefig(dev_result_path,dpi=100) fig2.clf() plt.close("all") return fit_dict
def vtu_To_hf3inp_inc_MV_matIDs_Producer(inputfilename, surfaceMesh, outputfilename): # ====================================================================== # Define matIDs -------------------------------------------------------- ID_UP = 21 # preliminary result, which gets overwritten by ID_ANT and ID_POST. ID_DOWN = 20 ID_ANT = 17 ID_POST = 18 # ====================================================================== # get system arguments ------------------------------------------------- valve3dFilename_ = inputfilename valve2dFilename_ = surfaceMesh outputFilename_ = outputfilename print " " print "===========================================================================================" print "=== Execute Python script to produce HiFlow3 inp file (incl. matIDs) for MVR-Simulation ===" print "===========================================================================================" print " " # ====================================================================== # read in files: ------------------------------------------------------- # read in 3d valve # NOTE: ensure that the precedent meshing algorithm (CGAL or similar) # produces consistent/good results w.r.t. the 'normal glyphs'. vtureader = vtk.vtkXMLUnstructuredGridReader() vtureader.SetFileName(valve3dFilename_) vtureader.Update() valve3d_ = vtureader.GetOutput() # get surface mesh of valve3d_ geometryFilter = vtk.vtkGeometryFilter() if vtk.vtkVersion().GetVTKMajorVersion() >= 6: geometryFilter.SetInputData(valve3d_) else: geometryFilter.SetInput(valve3d_) geometryFilter.Update() valve3dSurface_ = geometryFilter.GetOutput() # compute normals of surface mesh normalsSurface_ = vtk.vtkPolyDataNormals() if vtk.vtkVersion().GetVTKMajorVersion() >= 6: normalsSurface_.SetInputData(valve3dSurface_) else: normalsSurface_.SetInput(valve3dSurface_) normalsSurface_.SplittingOn() normalsSurface_.ConsistencyOn() # such that on a surface the normals are oriented either 'all' outward OR 'all' inward. normalsSurface_.AutoOrientNormalsOn() # such that normals point outward or inward. normalsSurface_.ComputePointNormalsOff() # adapt here. On/Off. normalsSurface_.ComputeCellNormalsOn() # adapt here. normalsSurface_.FlipNormalsOff() normalsSurface_.NonManifoldTraversalOn() normalsSurface_.Update() # get cell normals normalsSurfaceRetrieved_ = normalsSurface_.GetOutput().GetCellData().GetNormals() # adapt here. # read in 2d valve ----------------------------------------------------- vtpreader = vtk.vtkXMLPolyDataReader() vtpreader.SetFileName(valve2dFilename_) vtpreader.Update() valve2d_ = vtpreader.GetOutput() # compute normals of valve2d_ normalsValve2d_ = vtk.vtkPolyDataNormals() if vtk.vtkVersion().GetVTKMajorVersion() >= 6: normalsValve2d_.SetInputData(valve2d_) else: normalsValve2d_.SetInput(valve2d_) normalsValve2d_.SplittingOn() normalsValve2d_.ConsistencyOn() normalsValve2d_.ComputePointNormalsOff() # adapt here. normalsValve2d_.ComputeCellNormalsOn() normalsValve2d_.FlipNormalsOff() normalsValve2d_.NonManifoldTraversalOn() normalsValve2d_.Update() # get cell normals normalsValve2dRetrieved_ = normalsValve2d_.GetOutput().GetCellData().GetNormals() # adapt here. print "Reading 3D and 2D-annotated input files: DONE." # ====================================================================== # initialize cell locator for closest cell search ---------------------- # (using vtk methods, that find the closest point in a grid for an arbitrary point in R^3) cellLocator = vtk.vtkCellLocator() cellLocator.SetDataSet(valve2d_) cellLocator.BuildLocator() # ====================================================================== # allocate memory for cell_udlr_list_ (up-down-left-right) ------------- cell_udlr_list_ = [0 for i in range(valve3dSurface_.GetNumberOfCells())] # ====================================================================== # iterate over the cells of the surface and compare normals ------------ for i in range(valve3dSurface_.GetNumberOfCells()): # get cellId of closest point iD = valve3dSurface_.GetCell(i).GetPointId(0) # NOTE: only one (test)point (0) of respective cell testPoint = valve3dSurface_.GetPoint(iD) closestPoint = np.zeros(3) closestPointDist2 = vtk.mutable(0) cellId = vtk.mutable(0) subId = vtk.mutable(0) cellLocator.FindClosestPoint(testPoint, closestPoint, cellId, subId, closestPointDist2) normalSurf_ = np.zeros(3) normalsSurfaceRetrieved_.GetTuple(i, normalSurf_) normalV2d_ = np.zeros(3) normalsValve2dRetrieved_.GetTuple(cellId, normalV2d_) # set cell_udlr_list_ entry to (preliminary) "1", if cell is on upper side of leaflet if np.dot(normalSurf_, normalV2d_) > 0.0: cell_udlr_list_[i] = 1 # NOTE: "cell_udlr_list_[i] = 1" means "cell on upside". # ====================================================================== # iterate over cells on the upper side of the leaflet surface, and set ids for left/right ------------------ kDTree = vtk.vtkKdTreePointLocator() kDTree.SetDataSet(valve2d_) kDTree.BuildLocator() VertexIDs_ = valve2d_.GetPointData().GetArray('VertexIDs') # allocate memory for upCellList_ (indicating if cell is on left/right side) upCellList_ = [i for i in range(valve3dSurface_.GetNumberOfCells()) if cell_udlr_list_[i]] for i in upCellList_: iD = valve3dSurface_.GetCell(i).GetPointId(0) testPoint = valve3dSurface_.GetPoint(iD) result_ = vtk.vtkIdList() counter = 1 cond_ = True while cond_: kDTree.FindClosestNPoints(counter, testPoint, result_) for j in range(result_.GetNumberOfIds()): iD2 = result_.GetId(j) if int(VertexIDs_.GetTuple1(iD2)) == ID_ANT: cond_ = False cell_udlr_list_[i] = 2 # NOTE: "cell_udlr_list_[i] = 2" means "cell on ANT upside". if int(VertexIDs_.GetTuple1(iD2)) == ID_POST: cond_ = False cell_udlr_list_[i] = 3 # NOTE: "cell_udlr_list_[i] = 3" means "cell on POST upside". counter += 1 print "Computing hf3-inp MV matID information: DONE." # ====================================================================== # write results to inp file -------------------------------------------- f = open(outputFilename_, 'w') # write first line s = str(valve3d_.GetNumberOfPoints()) + ' ' + str(valve3dSurface_.GetNumberOfCells()+valve3d_.GetNumberOfCells()) + ' 0 0 0\n' f.write(s) # write point coordinates for i in range(valve3d_.GetNumberOfPoints()): pt = valve3d_.GetPoint(i) s = str(i) + ' ' + str(pt[0]) + ' ' + str(pt[1]) + ' ' + str(pt[2]) + '\n' f.write(s) # write connectivity information of triangles # integer, material id, vertex point ids for i in range(valve3dSurface_.GetNumberOfCells()): cell = valve3dSurface_.GetCell(i) iDs = cell.GetPointIds() if cell_udlr_list_[i] == 2: # NOTE: "cell_udlr_list_[i] = 2" means "cell on ANT upside". matId = ID_ANT elif cell_udlr_list_[i] == 3: # NOTE: "cell_udlr_list_[i] = 3" means "cell on POST upside". matId = ID_POST else: # NOTE: "cell_udlr_list_[i] = 0" means "cell on downside". matId = ID_DOWN s = str(0) + ' ' + str(matId) + ' tri ' + str(iDs.GetId(0)) + ' ' + str(iDs.GetId(1)) + ' ' + str(iDs.GetId(2)) + '\n' f.write(s) # write connectivity information of tetrahedrons # integer, material id, vertex point ids for i in range(valve3d_.GetNumberOfCells()): cell = valve3d_.GetCell(i) iDs = cell.GetPointIds() matId = 10 s = str(0) + ' ' + str(matId) + ' tet ' + str(iDs.GetId(0)) + ' ' + str(iDs.GetId(1)) + ' ' + str(iDs.GetId(2)) + ' ' + str(iDs.GetId(3)) + '\n' f.write(s) # close stream f.close() # ====================================================================== print "Writing HiFlow3 inp output file (incl. MV matIDs): DONE." print "========================================================" print " "
def create_kdtree(self, polydata=None): tree = vtk.vtkKdTreePointLocator() tree.SetDataSet(polydata) tree.BuildLocator() return tree
cN = [0.0, 0.0, 0.0] p = [0.0, 0.0, 0.0] size_points = normFilter.GetOutput().GetNumberOfPoints() pointNormalsArray = vtk.vtkDoubleArray() pointNormalsArray.SetNumberOfComponents(3) pointNormalsArray.SetNumberOfTuples(10000000) pts_Inner = vtk.vtkPoints() for i in range(0, size_points): normFilter.GetOutput().GetPoint(i, p) pointNormalsRetrieved.GetTuple(i, cN) pts_Inner.InsertNextPoint(p) pointNormalsArray.SetTuple(i, cN) kdTree = vtk.vtkKdTreePointLocator() kdTree.SetDataSet(epicardial_wall) kdTree.BuildLocator() ps = [0.0, 0.0, 0.0] pt = [0.0, 0.0, 0.0] x = [0.0, 0.0, 0.0] distmat = [] pts_Intersect = vtk.vtkPoints() size_pts = endocardial_wall.GetNumberOfPoints() for i in range(0, size_pts): pts_Inner.GetPoint(i, ps) iD = kdTree.FindClosestPoint(ps)
def __init__(self, pts): ds = vtk.vtkPolyData() ds.SetPoints(pts) self.locator = vtk.vtkKdTreePointLocator() self.locator.SetDataSet(ds) self.locator.BuildLocator()
def GetSemiUniDistnaceGrid( self, m_holePerSlice, m_numberOfSlice, m_errorTolerance=1, m_startPadding=0, m_endPadding=0, m_bufferDeg=40 ): """ Obtain a set of coordinates roughly equal to a projection of periodic square grid vertex on the arm surface. The gird also can arbitrarily has a buffer zone where no holes are drilled. :param m_holePerSlice: [int] Desired number of holes per slice :param m_numberOfSlice: [int] Desired number of slices :param m_errorTolerance: [float] The maximum allowed deviation of hole coordinate from idea grid :param m_startPadding: [int] Starting side padding where no holes will be drilled :param m_endPadding: [int] Ending side padding where no holes will be drilled :param m_bufferDeg: [float] Angle between planes where buffers zones are in between. Default to 40 :return: [list] List of hole coordinates """ vtkmath = vtk.vtkMath() if not self._centerLine._IS_READ_FLAG: self._centerLine.Read() if self._bufferAngle != None: m_bufferDeg = self._bufferAngle m_totalDistance = 0 for i in xrange( 1 + int(m_startPadding / 0.3), self._centerLine._data.GetNumberOfPoints() - int(m_endPadding / 0.3) ): m_totalDistance += self._centerLine.GetDistance(i, i - 1) # Shrink the distance a bit before deviding it so that all intervals will lie in the padded segment m_sliceSpacing = (m_totalDistance) * 0.98 / (m_numberOfSlice) m_intervalIndexes = self._centerLine.GetEqualDistanceIntervalsIndex( m_sliceSpacing, m_startPadding, m_endPadding ) self._centerLineIntervals = m_intervalIndexes m_tangents = [] for k in xrange(len(m_intervalIndexes)): m_tmp = self._centerLine.GetNormalizedTangent(m_intervalIndexes[k], range=12, step=3) m_tangents.append(m_tmp) m_average = [sum([m_tangents[i][j] for i in xrange(3)]) / float(len(m_tangents)) for j in xrange(3)] m_openingList = [] m_holeList = [] m_alphaNormal = None m_masterPt = self._centerLine.GetPoint(m_intervalIndexes[0]) # Define cast opening zone and start drilling zone if m_bufferDeg != None and self._openingMarker != None: m_kdtree = vtk.vtkKdTreePointLocator() m_kdtree.SetDataSet(self._centerLine._data) m_kdtree.BuildLocator() m_closestCenterlinePointId = m_kdtree.FindClosestPoint(self._openingMarker) m_closestCenterlinePoint = self._centerLine.GetPoint(m_closestCenterlinePointId) m_masterPt = m_closestCenterlinePoint # Drill along intervals for i in xrange(len(m_intervalIndexes)): l_sliceCenter = self._centerLine.GetPoint(m_intervalIndexes[i]) l_slice = self.SliceSurface(l_sliceCenter, m_average) if i == 0: # Define the starting vector for all slice # l_ringAlphaPt = l_slice.GetPoint(i) l_ringAlphaVect = [self._openingMarker[j] - m_masterPt[j] for j in xrange(3)] m_alphaNormal = [0, 0, 0] vtkmath.Cross(m_average, l_ringAlphaVect, m_alphaNormal) m_alphaNormalMag = sum([m_alphaNormal[i] for i in xrange(3)]) m_alphaNormal = [m_alphaNormal[i] / m_alphaNormalMag for i in xrange(3)] # Define an initial accuracy which relax if no suitable points is found, affects calculation speed m_loopAccuracy = 0.25 m_ringSliceAlphaVect = None while m_ringSliceAlphaVect == None: for j in xrange(l_slice.GetNumberOfPoints()): l_ringSliceAlphaVect = [l_slice.GetPoint(j)[k] - l_sliceCenter[k] for k in xrange(3)] # l_ringSliceMasterVect = [l_slice.GetPoint(j)[k] - m_masterPt[k] for k in xrange(3)] if ( math.fabs(vtkmath.Dot(l_ringSliceAlphaVect, m_alphaNormal)) < m_loopAccuracy and vtkmath.Dot(l_ringSliceAlphaVect, l_ringAlphaVect) > 0 ): m_ringSliceAlphaVect = l_ringSliceAlphaVect break m_loopAccuracy *= 2 if m_loopAccuracy >= 10: raise ValueError("Slice Alpha Vector search reaches maximum tolerance") break l_uniformSectionDegree = (360.0 - m_bufferDeg) / m_holePerSlice l_sectionDegree = (360.0 - m_bufferDeg) / m_holePerSlice l_loopbreak = 0 m_openingList.append( [l_ringSliceAlphaVect[k] + l_sliceCenter[k] for k in xrange(3)] ) # Include first vector l_holeList = [] while len(l_holeList) < m_holePerSlice - 1: if len(l_holeList) == 0: l_sectionDegree += m_bufferDeg / 2 for j in xrange(l_slice.GetNumberOfPoints()): l_p1 = [0.0, 0.0, 0.0] l_ringVect = [l_slice.GetPoint(j)[k] - l_sliceCenter[k] for k in xrange(3)] vtkmath.Cross(l_ringSliceAlphaVect, l_ringVect, l_p1) l_p2 = vtkmath.Dot(l_p1, m_average) l_angleBetweenRunningAndInitialVector = vtkmath.AngleBetweenVectors( l_ringSliceAlphaVect, l_ringVect ) if ( l_angleBetweenRunningAndInitialVector > vtkmath.RadiansFromDegrees(l_sectionDegree - m_errorTolerance / 2) and l_angleBetweenRunningAndInitialVector < vtkmath.RadiansFromDegrees(l_sectionDegree + m_errorTolerance / 2.0) and l_p2 > 0 ): l_ringSliceAlphaVect = l_ringVect l_holeList.append([l_ringVect[k] + l_sliceCenter[k] for k in xrange(3)]) l_sectionDegree += l_uniformSectionDegree - vtkmath.DegreesFromRadians( l_angleBetweenRunningAndInitialVector ) break if l_loopbreak == m_holePerSlice: raise RuntimeError("Current error tolerence setting is to low to produce anything.") l_loopbreak += 1 m_holeList.extend(l_holeList) self._openingList = m_openingList return m_holeList
def addCSVFile(self,fname,mode='folded',csvDelimiter=None): self.setCaption(r' File:'+str(fname)) pts=np.loadtxt(fname,csvDelimiter) points = vtk.vtkPoints() r,t,z = rec2cyl(pts[:,0],pts[:,1],pts[:,2]) im_g=getGeomImperfection(r,z,np.mean(r)) if pts.shape[1] == 4: useThickImp=True else: useThickImp=False if useThickImp: im_t=pts[:,3] else: im_t=np.zeros(pts.shape[0]) rid=r-im_g if mode == 'unfolded': tt=t*r.mean() rr=im_g*self.scalingFactor for i in range(0,pts.shape[0]): points.InsertPoint(i,tt[i],z[i],rr[i] ) else: xx,yy,zz=cyl2rec(rid+im_g*self.scalingFactor,t,z) for i in range(0,pts.shape[0]): points.InsertPoint(i,xx[i],yy[i],zz[i] ) polydata = vtk.vtkPolyData() polydata.SetPoints(points) polydata.Update() if useThickImp: imps=im_t else: imps=im_g # imps=vtk.vtkFloatArray() # if useThickImp: # for i in range(0,polydata.GetNumberOfPoints()): # imps.InsertNextValue(im_t[i]) # else: # imps.InsertNextValue(im_g[i]) # polydata.GetPointData().SetScalars(imps); # surf =vtk.vtkSurfaceReconstructionFilter() surf.SetInput(polydata) surf.SetNeighborhoodSize(self.nbSize) surf.SetSampleSpacing(self.sampleSpacing) contourFilter = vtk.vtkContourFilter() contourFilter.SetInputConnection(surf.GetOutputPort()) reverse = vtk.vtkReverseSense() reverse.SetInputConnection(contourFilter.GetOutputPort()) reverse.ReverseCellsOn() reverse.ReverseNormalsOn() reverse.Update() outputPolyData=reverse.GetOutput() newSurf = self.transform_back( points, reverse.GetOutput()); pts2=np.zeros((newSurf.GetNumberOfPoints(),3)) for i in range(0,newSurf.GetNumberOfPoints()): pts2[i,:]=newSurf.GetPoint(i) r2,t2,z2 = rec2cyl(pts2[:,0],pts2[:,1],pts2[:,2]) kDTree = vtk.vtkKdTreePointLocator() kDTree.SetDataSet(polydata) kDTree.BuildLocator() colors=vtk.vtkFloatArray() for i in range(0,len(pts2)): kid=kDTree.FindClosestPoint(pts2[i]) colors.InsertNextValue(imps[kid]) # if mode == 'folded': # im2=getGeomImperfection(r2,z2,np.mean(r2))/self.scalingFactor # # if mode == 'unfolded': # im2=pts2[:,2]/self.scalingFactor # # colors=vtk.vtkFloatArray() # for i in range(0,newSurf.GetNumberOfPoints()): # colors.InsertNextValue(im2[i]) newSurf.GetPointData().SetScalars(colors); self.scalarRange=colors.GetRange() self.lut=vtk.vtkLookupTable() self.lut.SetNumberOfTableValues(100) self.lut.SetTableRange(self.scalarRange) self.lut.SetHueRange(0.667, 0.0) self.lut.Build() self.resP=newSurf.GetProducerPort() self.colors=colors self.outputs.append(newSurf) mapper = vtk.vtkPolyDataMapper(); mapper.SetLookupTable(self.lut) mapper.InterpolateScalarsBeforeMappingOn() mapper.SetInputConnection(newSurf.GetProducerPort()) mapper.SetScalarModeToUsePointData() mapper.ScalarVisibilityOn(); mapper.SetScalarRange(colors.GetRange()) surfaceActor = vtk.vtkActor(); surfaceActor.SetMapper(mapper); self.boundBox=newSurf.GetBounds() self.ren.AddActor(surfaceActor);
def BCdata_for_Hf3Sim_Producer(inputfilename, surfaceMesh, ringFilename, outputfilename): # ====================================================================== # define number of given annulus point IDs ----------------------------- # (see notation/representation of Annuloplasty Rings by DKFZ and corresponding addInfo) numberOfAnnulusPtIDs_ = 16 # get system arguments ------------------------------------------------- valve3dFilename_ = inputfilename valve2dFilename_ = surfaceMesh ringFilename_ = ringFilename outputFilename_ = outputfilename print " " print "=====================================================================================" print "=== Execute Python script to produce BCdata for the HiFlow3-based MVR-Simulation ===" print "=====================================================================================" print " " # ====================================================================== # read in files: ------------------------------------------------------- # read in 3d valve vtureader = vtk.vtkXMLUnstructuredGridReader() vtureader.SetFileName(valve3dFilename_) vtureader.Update() valve3d_ = vtureader.GetOutput() # get surface mesh of valve3d_ geometryFilter = vtk.vtkGeometryFilter() if vtk.vtkVersion().GetVTKMajorVersion() >= 6: geometryFilter.SetInputData(valve3d_) else: geometryFilter.SetInput(valve3d_) geometryFilter.Update() valve3dSurface_ = geometryFilter.GetOutput() # read in 2d valve vtpreader = vtk.vtkXMLPolyDataReader() vtpreader.SetFileName(valve2dFilename_) vtpreader.Update() valve2d_ = vtpreader.GetOutput() # read in ring vtpreader = vtk.vtkXMLPolyDataReader() vtpreader.SetFileName(ringFilename_) vtpreader.Update() ring_ = vtpreader.GetOutput() # get vertex ids of valve2d_ and ring_ --------------------------------- valve2dVertexIds_ = valve2d_.GetPointData().GetArray('VertexIDs') ringVertexIds_ = ring_.GetPointData().GetArray('VertexIDs') print "Reading input files: DONE." # ====================================================================== # init. tree for closest point search ---------------------------------- kDTree = vtk.vtkKdTreePointLocator() kDTree.SetDataSet(valve3dSurface_) kDTree.BuildLocator() # ====================================================================== # arrays for storage of coordinates of annulus points (and interpolated points) on the MV surface and on the ring ----------------- ringPoints_ = np.zeros((2*numberOfAnnulusPtIDs_,3)) valvePoints_ = np.zeros((2*numberOfAnnulusPtIDs_,3)) # Store coordiantes in arrays --------------------------------------------------------------------------- # NOTE: Alternatively, instead of a loop over all points and looking for their IDs, # one could also loop over the array of vertexIDs and get the pointID. # find coordinates of points of ring_ for i in range(ring_.GetNumberOfPoints()): if 0 <= int(ringVertexIds_.GetTuple1(i)) and int(ringVertexIds_.GetTuple1(i)) < numberOfAnnulusPtIDs_: ringPoints_[int(ringVertexIds_.GetTuple1(i))] = np.array(ring_.GetPoint(i)) # find coordinates of points of valve2d_ for i in range(valve2d_.GetNumberOfPoints()): if 0 <= int(valve2dVertexIds_.GetTuple1(i)) and int(valve2dVertexIds_.GetTuple1(i)) < numberOfAnnulusPtIDs_: valvePoints_[int(valve2dVertexIds_.GetTuple1(i))] = np.array(valve2d_.GetPoint(i)) # find closest points to points stored in valvePoints_ on valve3dSurface_ and store (i.e. overwrite) them in valvePoints_ for i in range(numberOfAnnulusPtIDs_): iD = kDTree.FindClosestPoint(valvePoints_[i]) kDTree.GetDataSet().GetPoint(iD, valvePoints_[i]) # ====================================================================== # add additional boundary conditions by linear interpolation ------------------------------------------- # NOTE: this requires the IDs to be ordered and going around annulus once!!! for i in range(numberOfAnnulusPtIDs_): valvePoints_[numberOfAnnulusPtIDs_+i] = 0.5 * (valvePoints_[i]+valvePoints_[(i+1)%numberOfAnnulusPtIDs_]) ringPoints_[numberOfAnnulusPtIDs_+i] = 0.5 * (ringPoints_[i]+ringPoints_[(i+1)%numberOfAnnulusPtIDs_]) # ====================================================================== # Compute displacements ------------------------------------------------ displacement_ = ringPoints_ - valvePoints_ # ====================================================================== # convert arrays to strings -------------------------------------------- valvePointString_ = "" displacementString_ = "" for i in range(2*numberOfAnnulusPtIDs_): for j in range(3): valvePointString_ += str(valvePoints_[i][j]) displacementString_ += str(displacement_[i][j]) if j == 2: if i < 2*numberOfAnnulusPtIDs_-1: valvePointString_ += ";" displacementString_ += ";" else: valvePointString_ += "," displacementString_ += "," print "Computing BC data: DONE." # ====================================================================== # Write BC data to XML file -------------------------------------------- # build a tree structure root = ET.Element("Param") BCData = ET.SubElement(root, "BCData") DisplacementConstraintsBCs = ET.SubElement(BCData, "DisplacementConstraintsBCs") numberOfDPoints = ET.SubElement(DisplacementConstraintsBCs, "NumberOfDisplacedDirichletPoints") numberOfDPoints.text = str(2*numberOfAnnulusPtIDs_) dDPoints = ET.SubElement(DisplacementConstraintsBCs, "dDPoints") dDPoints.text = valvePointString_ dDisplacements = ET.SubElement(DisplacementConstraintsBCs, "dDisplacements") dDisplacements.text = displacementString_ # wrap it in an ElementTree instance, and save as XML tree = ET.ElementTree(root) tree.write(outputFilename_) # ====================================================================== print "Writing mvrSimBCdata.xml output file: DONE." print "===========================================" print " "
def execute(working_dir): # convert vtk to stl reader = vtk.vtkGenericDataObjectReader() reader.SetFileName(os.path.join(working_dir, "surface.vtk")) reader.Update() surface = reader.GetOutput() writer = vtk.vtkSTLWriter() writer.SetFileName(os.path.join(working_dir, "surface.stl")) writer.SetInputData(surface) writer.Update() # compute centerline command = binary_path + " " + \ os.path.join(working_dir,"surface.stl") + " " + \ os.path.join(working_dir,"surface_capped.stl") + " " + \ os.path.join(working_dir,"centerline.vtp") # os.system(command) # crop equal distance from the defected zone # load defected zone coordinate defected_point = open(os.path.join(working_dir, "defected_point.fcsv"), "r").readlines()[3] defected_point = defected_point.split(",")[1:4] defected_point = [float(i) for i in defected_point] # load the centerline file reader = vtk.vtkXMLPolyDataReader() reader.SetFileName(os.path.join(working_dir, "centerline.vtp")) reader.Update() centerline = reader.GetOutput() kdTree = vtk.vtkKdTreePointLocator() kdTree.SetDataSet(centerline) iD = kdTree.FindClosestPoint(defected_point) end_id = centerline.GetNumberOfPoints() - 1 defected_point_absc = centerline.GetPointData().GetArray( "Abscissas").GetComponent(iD, 0) # find the start point start_id = 0 start_point_absc = 0 start_point = [0, 0, 0] start_point_tangent = [1, 0, 0] start_point_normal = [0, 1, 0] start_point_binormal = [0, 0, 1] for i in range(centerline.GetNumberOfPoints() - 1): if defected_point_absc - centerline.GetPointData().GetArray( "Abscissas").GetComponent(i, 0) < dist_from_defect: break else: start_id = i start_point_absc = centerline.GetPointData().GetArray( "Abscissas").GetComponent(i, 0) start_point = list(centerline.GetPoints().GetPoint(i)) start_point_tangent = list(centerline.GetPointData().GetArray( "FrenetTangent").GetTuple(i)) start_point_normal = list( centerline.GetPointData().GetArray("FrenetNormal").GetTuple(i)) start_point_binormal = list(centerline.GetPointData().GetArray( "FrenetBinormal").GetTuple(i)) print(start_id, start_point, start_point_tangent, start_point_normal, start_point_binormal) clipBoxes = [] clipPlanes = [] surface, clipBox, clipPlane = clip_polydata_by_box(surface, start_point, start_point_tangent, start_point_normal, start_point_binormal) centerline, _, _ = clip_polydata_by_box(centerline, start_point, start_point_tangent, start_point_normal, start_point_binormal) clipBoxes.append(clipBox) clipPlanes.append(clipPlane) # find end points # split the polydata by centerline id splitter = vtk.vtkThreshold() splitter.SetInputData(centerline) splitted_centerlines = [] for i in range( int(centerline.GetCellData().GetArray("CenterlineIds").GetRange() [1]) + 1): splitter.ThresholdBetween(i, i) splitter.SetInputArrayToProcess( 0, 0, 0, vtk.vtkDataObject.FIELD_ASSOCIATION_CELLS, "CenterlineIds") splitter.Update() splitted_centerline = vtk.vtkPolyData() splitted_centerline.DeepCopy(splitter.GetOutput()) splitted_centerlines.append(splitted_centerline) end_ids = [] end_points = [] end_points_tangent = [] end_points_normal = [] end_points_binormal = [] for splitted_centerline in splitted_centerlines: end_id = splitted_centerline.GetNumberOfPoints() - 1 end_point_absc = splitted_centerline.GetPointData().GetArray( "Abscissas").GetComponent( splitted_centerline.GetNumberOfPoints() - 1, 0) end_point = list(splitted_centerline.GetPoints().GetPoint( splitted_centerline.GetNumberOfPoints() - 1)) end_point_tangent = list(splitted_centerline.GetPointData().GetArray( "FrenetTangent").GetTuple(splitted_centerline.GetNumberOfPoints() - 1)) end_point_normal = list(splitted_centerline.GetPointData().GetArray( "FrenetNormal").GetTuple(splitted_centerline.GetNumberOfPoints() - 1)) end_point_binormal = list( splitted_centerline.GetPointData().GetArray("FrenetBinormal"). GetTuple(splitted_centerline.GetNumberOfPoints() - 1)) for i in range(splitted_centerline.GetNumberOfPoints()): if splitted_centerline.GetPointData().GetArray( "Abscissas").GetComponent( i, 0) - start_point_absc > 2 * dist_from_defect: end_ids.append(end_id) end_points.append(end_point) end_points_tangent.append(end_point_tangent) end_points_normal.append(end_point_normal) end_points_binormal.append(end_point_binormal) break else: end_id = i end_point_absc = splitted_centerline.GetPointData().GetArray( "Abscissas").GetComponent(i, 0) end_point = list(splitted_centerline.GetPoints().GetPoint(i)) end_point_tangent = list( splitted_centerline.GetPointData().GetArray( "FrenetTangent").GetTuple(i)) end_point_normal = list( splitted_centerline.GetPointData().GetArray( "FrenetNormal").GetTuple(i)) end_point_binormal = list( splitted_centerline.GetPointData().GetArray( "FrenetBinormal").GetTuple(i)) if i == splitted_centerline.GetNumberOfPoints() - 1: end_ids.append(end_id) end_points.append(end_point) end_points_tangent.append(end_point_tangent) end_points_normal.append(end_point_normal) end_points_binormal.append(end_point_binormal) for i in range(len(end_ids)): print(end_ids[i], end_points[i], end_points_tangent[i], end_points_normal[i], end_points_binormal[i]) surface, clipBox, clipPlane = clip_polydata_by_box( surface, end_points[i], end_points_tangent[i], end_points_normal[i], end_points_binormal[i]) centerline, _, _ = clip_polydata_by_box(centerline, end_points[i], end_points_tangent[i], end_points_normal[i], end_points_binormal[i]) clipBoxes.append(clipBox) clipPlanes.append(clipPlane) # connected component calculation on surface and centerline connectedFilter = vtk.vtkConnectivityFilter() # connectedFilter.SetExtractionModeToAllRegions() # connectedFilter.ColorRegionsOn() connectedFilter.SetExtractionModeToClosestPointRegion() connectedFilter.SetClosestPoint(defected_point) connectedFilter.SetInputData(surface) connectedFilter.Update() surface.DeepCopy(connectedFilter.GetOutput()) # output vtpWriter = vtk.vtkXMLPolyDataWriter() vtpWriter.SetFileName(os.path.join(working_dir, "surface_clipped.vtp")) vtpWriter.SetInputData(surface) vtpWriter.Update() connectedFilter.SetInputData(centerline) connectedFilter.Update() centerline.DeepCopy(connectedFilter.GetOutput()) vtpWriter.SetFileName(os.path.join(working_dir, "centerline_clipped.vtp")) vtpWriter.SetInputData(centerline) vtpWriter.Update() for i in range(len(clipBoxes)): writer.SetFileName( os.path.join(working_dir, "clip_box_" + str(i) + ".stl")) writer.SetInputData(clipBoxes[i]) writer.Update() writer.SetFileName( os.path.join(working_dir, "clip_plane_" + str(i) + ".stl")) writer.SetInputData(clipPlanes[i]) writer.Update()
def _run_interface(self, runtime): labelmap = sitk.ReadImage(self.inputs.labels_file) uncleanwm = readPolyData(self.inputs.wm_file) uncleangm = readPolyData(self.inputs.gm_file) if isdefined(self.inputs.atlas_info): atlas_dict = parse_labels_xml(self.inputs.atlas_info) # Clean the data cleanwm = vtk.vtkCleanPolyData() cleanwm.SetInputData(uncleanwm) cleangm = vtk.vtkCleanPolyData() cleangm.SetInputData(uncleangm) cleanwm.Update() cleangm.Update() wmsurf = cleanwm.GetOutput() gmsurf = cleangm.GetOutput() # setup KdTrees for each surface # this will help in finding the closest points kdTreewm = vtk.vtkKdTreePointLocator() kdTreewm.SetDataSet(wmsurf) kdTreewm.BuildLocator() kdTreegm = vtk.vtkKdTreePointLocator() kdTreegm.SetDataSet(gmsurf) kdTreegm.BuildLocator() measurements = dict() wmPD = wmsurf.GetPointData() wmPoints = wmsurf.GetPoints() wmCount = wmPD.GetNumberOfTuples() for i in range(0, wmCount): wmP = wmPoints.GetPoint(i) # Find the closest point to the gray matter surface point gmIndex = kdTreegm.FindClosestPoint(wmP) gmP = kdTreegm.GetDataSet().GetPoint(gmIndex) # Get the gray matter label from the label map gmlabel = vtkPoint_to_label(gmP, labelmap) if gmlabel != 0: label = str(gmlabel) else: # if the gray matter label is not defined try the wm label wmlabel = vtkPoint_to_label(wmP, labelmap) if wmlabel != 0: label = str(wmlabel) else: # label is not known label = 'UNKNOWN' # compute the distance # distance from wm point to gm point dst1 = distance.euclidean(wmP, gmP) wmIndex = kdTreewm.FindClosestPoint(gmP) wmP2 = kdTreegm.GetDataSet().GetPoint(wmIndex) # distnace from gm to closest wm point dst2 = distance.euclidean(gmP, wmP2) # average the two distances thickness = (dst1 + dst2) / 2 if not measurements.has_key(label): # first point in a labeled region measurements[label] = [thickness] else: measurements[label].append(thickness) mu = ["mean"] median = ["median"] std = ["std"] count = ["points"] minimum = ["min"] maximum = ["max"] labels = ["label"] for key in measurements.iterkeys(): labels.append(key) data = np.array(measurements[key]) mu.append(np.mean(data)) median.append(np.median(data)) std.append(np.std(data)) count.append(len(data)) minimum.append(np.min(data)) maximum.append(np.max(data)) out_csv = self._list_outputs()['out_file'] with open(out_csv, 'w') as CSV_file: writer = csv.writer(CSV_file) writer.writerows([labels, mu, std, count, minimum, maximum]) return runtime
polyData = iter.GetCurrentDataObject() if not polyData.IsA("vtkPolyData"): print "ERROR: unexpected input (not vtkPolyData)" exit(1) nc = polyData.GetNumberOfCells() print "boundary",boundary_id,":",nc for i in range(nc): cell = polyData.GetCell(i) midpoint = get_midpoint(cell) boundary_mid_points.InsertNextPoint(midpoint) boundary_id_array.InsertNextValue(boundary_id) boundary_id += 1 iter.GoToNextItem() num_boundaries = boundary_id loc = vtk.vtkKdTreePointLocator() boundary_dataset = vtk.vtkPolyData() boundary_dataset.SetPoints(boundary_mid_points) loc.SetDataSet(boundary_dataset) loc.BuildLocator() # map from boundaries to a list of tuples containing point ids and the cell id boundary_faces = [] for i in range(num_boundaries): boundary_faces.append([]) internal_faces = [] volume.BuildLinks() nc = volume.GetNumberOfCells()
def build_kd_tree(mesh): kd_tree = vtk.vtkKdTreePointLocator() kd_tree.SetDataSet(mesh) kd_tree.BuildLocator() return kd_tree
def normalizeVessels(case_dir, dist_from_bif_inlet=35, dist_from_bif_outlet=35): # phases = ["baseline","baseline-post","12months","followup"] phases = ["baseline"] centerlines = {} surfaces = {} for phase in phases: if not os.path.exists(os.path.join(case_dir, phase, "centerline.vtp")): continue # load the centerline file reader = vtk.vtkXMLPolyDataReader() reader.SetFileName(os.path.join(case_dir, phase, "centerline.vtp")) reader.Update() centerline = reader.GetOutput() centerlines.update({phase: centerline}) # load surface files if not os.path.exists(os.path.join(case_dir, phase, "surface.stl")): continue # reader = vtk.vtkGenericDataObjectReader() reader = vtk.vtkSTLReader() reader.SetFileName(os.path.join(case_dir, phase, "surface.stl")) reader.Update() surface = reader.GetOutput() surfaces.update({phase: surface}) # get the bifurcation point from baseline data # split the polydata by centerline id splitter = vtk.vtkThreshold() splitter.SetInputData(centerlines["baseline"]) splitter.ThresholdBetween(0, 0) splitter.SetInputArrayToProcess(0, 0, 0, vtk.vtkDataObject.FIELD_ASSOCIATION_CELLS, "GroupIds") splitter.Update() mainBranch = splitter.GetOutput() maxAbsc = 0 maxAbscId = 0 for i in range(mainBranch.GetNumberOfPoints()): absc = mainBranch.GetPointData().GetArray("Abscissas").GetComponent( i, 0) if absc > maxAbsc: maxAbsc = absc maxAbscId = i bifPoint = mainBranch.GetPoint(maxAbscId) bifPoint_list = {} bifPoint_absc_list = {} bifPoint_id_list = {} endPoint1_absc_list = {} endPoint1_id_list = {} endPoint2_absc_list = {} endPoint2_id_list = {} for key, centerline in centerlines.items(): kdTree = vtk.vtkKdTreePointLocator() kdTree.SetDataSet(centerline) iD = kdTree.FindClosestPoint(bifPoint) bifPoint_absc_list.update({ key: centerline.GetPointData().GetArray("Abscissas").GetComponent( iD, 0) }) bifPoint_id_list.update({key: iD}) splitter = vtk.vtkThreshold() splitter.SetInputData(centerline) splitter.SetInputArrayToProcess( 0, 0, 0, vtk.vtkDataObject.FIELD_ASSOCIATION_CELLS, "GroupIds") splitter.ThresholdBetween(2, 2) splitter.Update() ACA = splitter.GetOutput() endPoint1_absc_list.update({ key: ACA.GetPointData().GetArray("Abscissas").GetComponent( ACA.GetNumberOfPoints() - 1, 0) - bifPoint_absc_list[key] }) endPoint1_id_list.update({key: ACA.GetNumberOfPoints() - 1}) splitter.ThresholdBetween(3, 3) splitter.Update() MCA = splitter.GetOutput() endPoint2_absc_list.update({ key: ACA.GetPointData().GetArray("Abscissas").GetComponent( MCA.GetNumberOfPoints() - 1, 0) - bifPoint_absc_list[key] }) endPoint2_id_list.update({key: ACA.GetNumberOfPoints() - 1}) # append the bifurcation point bifPoint_list.update({key: bifPoint}) # get the start point coordinate start_id = 0 start_point_absc = 0 start_point = [0, 0, 0] start_point_tangent = [1, 0, 0] start_point_normal = [0, 1, 0] start_point_binormal = [0, 0, 1] for i in range(centerlines["baseline"].GetNumberOfPoints()): if (bifPoint_absc_list["baseline"] - centerlines["baseline"].GetPointData().GetArray("Abscissas").GetComponent(i,0) < min(bifPoint_absc_list.values())) and \ (bifPoint_absc_list["baseline"] - centerlines["baseline"].GetPointData().GetArray("Abscissas").GetComponent(i,0) < dist_from_bif_inlet): break else: start_id = i start_point_absc = centerlines["baseline"].GetPointData().GetArray( "Abscissas").GetComponent(i, 0) start_point = list(centerlines["baseline"].GetPoint(i)) start_point_tangent = list( centerlines["baseline"].GetPointData().GetArray( "FrenetTangent").GetTuple(i)) start_point_normal = list( centerlines["baseline"].GetPointData().GetArray( "FrenetNormal").GetTuple(i)) start_point_binormal = list( centerlines["baseline"].GetPointData().GetArray( "FrenetBinormal").GetTuple(i)) # get the end point coordinates end_ids = [] end_points = [] end_points_tangent = [] end_points_normal = [] end_points_binormal = [] splitter = vtk.vtkThreshold() splitter.SetInputData(centerlines["baseline"]) splitter.SetInputArrayToProcess(0, 0, 0, vtk.vtkDataObject.FIELD_ASSOCIATION_CELLS, "GroupIds") groupdIds = [2, 3] for groupId in groupdIds: splitter.ThresholdBetween(groupId, groupId) splitter.Update() splitted_centerline = splitter.GetOutput() end_id = splitted_centerline.GetNumberOfPoints() - 1 end_point_absc = splitted_centerline.GetPointData().GetArray( "Abscissas").GetComponent( splitted_centerline.GetNumberOfPoints() - 1, 0) end_point = list(splitted_centerline.GetPoints().GetPoint( splitted_centerline.GetNumberOfPoints() - 1)) end_point_tangent = list(splitted_centerline.GetPointData().GetArray( "FrenetTangent").GetTuple(splitted_centerline.GetNumberOfPoints() - 1)) end_point_normal = list(splitted_centerline.GetPointData().GetArray( "FrenetNormal").GetTuple(splitted_centerline.GetNumberOfPoints() - 1)) end_point_binormal = list( splitted_centerline.GetPointData().GetArray("FrenetBinormal"). GetTuple(splitted_centerline.GetNumberOfPoints() - 1)) for i in range(splitted_centerline.GetNumberOfPoints()): if groupId == 2: endPoint_absc_list = endPoint1_absc_list.values() else: endPoint_absc_list = endPoint2_absc_list.values() if (splitter.GetOutput().GetPointData().GetArray("Abscissas").GetComponent(i,0)-bifPoint_absc_list["baseline"]< min(endPoint_absc_list)) and \ (splitter.GetOutput().GetPointData().GetArray("Abscissas").GetComponent(i,0)-bifPoint_absc_list["baseline"] < dist_from_bif_outlet): end_id = i end_point_absc = splitted_centerline.GetPointData().GetArray( "Abscissas").GetComponent(i, 0) end_point = list(splitted_centerline.GetPoints().GetPoint(i)) end_point_tangent = list( splitted_centerline.GetPointData().GetArray( "FrenetTangent").GetTuple(i)) end_point_normal = list( splitted_centerline.GetPointData().GetArray( "FrenetNormal").GetTuple(i)) end_point_binormal = list( splitted_centerline.GetPointData().GetArray( "FrenetBinormal").GetTuple(i)) else: end_ids.append(end_id) end_points.append(end_point) end_points_tangent.append(end_point_tangent) end_points_normal.append(end_point_normal) end_points_binormal.append(end_point_binormal) break if i == splitted_centerline.GetNumberOfPoints() - 1: end_ids.append(end_id) end_points.append(end_point) end_points_tangent.append(end_point_tangent) end_points_normal.append(end_point_normal) end_points_binormal.append(end_point_binormal) # clip the surfaces clipBoxes = {} clipPlanes = {} boundaryCaps = {} surfaces_clipped = {} centerlines_clipped = {} # connected component calculation on surface and centerline connectedFilter = vtk.vtkConnectivityFilter() # connectedFilter.SetExtractionModeToAllRegions() # connectedFilter.ColorRegionsOn() connectedFilter.SetExtractionModeToClosestPointRegion() connectedFilter.SetClosestPoint(bifPoint) key_point_list = {} for key, surface in surfaces.items(): clipBoxes_ = {} clipPlanes_ = {} boundaryCaps_ = {} key_point_list_ = {} kdTree = vtk.vtkKdTreePointLocator() kdTree.SetDataSet(centerlines[key]) iD = kdTree.FindClosestPoint(bifPoint_list[key]) kdTree.Update() bif_point_ = list(centerlines[key].GetPoint(iD)) bif_point_tangent_ = list(centerlines[key].GetPointData().GetArray( "FrenetTangent").GetTuple(iD)) bif_point_normal_ = list(centerlines[key].GetPointData().GetArray( "FrenetNormal").GetTuple(iD)) bif_point_binormal_ = list(centerlines[key].GetPointData().GetArray( "FrenetBinormal").GetTuple(iD)) bif_point_dict = { "coordinate": bif_point_, "tangent": bif_point_tangent_, "normal": bif_point_normal_, "binormal": bif_point_binormal_ } key_point_list_.update({"BifurcationPoint": bif_point_dict}) iD = kdTree.FindClosestPoint(start_point) kdTree.Update() start_point_ = list(centerlines[key].GetPoint(iD)) start_point_tangent_ = list(centerlines[key].GetPointData().GetArray( "FrenetTangent").GetTuple(iD)) start_point_normal_ = list(centerlines[key].GetPointData().GetArray( "FrenetNormal").GetTuple(iD)) start_point_binormal_ = list(centerlines[key].GetPointData().GetArray( "FrenetBinormal").GetTuple(iD)) start_point_dict = { "coordinate": start_point_, "tangent": start_point_tangent_, "normal": start_point_normal_, "binormal": start_point_binormal_ } key_point_list_.update({"ICA": start_point_dict}) clip_result = clip_polydata_by_box(surface, start_point_, start_point_tangent_, start_point_normal_, start_point_binormal_, size=[15, 15, 1], capping=capping) # perform lcc everytime after clipping to guarantee clean result connectedFilter.SetInputData(clip_result["clipped_surface"]) connectedFilter.Update() surface.DeepCopy(connectedFilter.GetOutput()) clipBoxes_.update({"ICA": clip_result["clip_box"]}) clipPlanes_.update({"ICA": clip_result["clip_plane"]}) connectedFilter_cap = vtk.vtkConnectivityFilter() connectedFilter_cap.SetExtractionModeToClosestPointRegion() connectedFilter_cap.SetClosestPoint([ start_point_[i] + start_point_tangent_[i] for i in range(len(start_point_)) ]) connectedFilter_cap.SetInputData(clip_result["boundary_cap"]) connectedFilter_cap.Update() start_cap = vtk.vtkPolyData() start_cap.DeepCopy(connectedFilter_cap.GetOutput()) boundaryCaps_.update({"ICA": start_cap}) for i in range(len(end_points)): if i == 0: outlet_key = "ACA" else: outlet_key = "MCA" kdTree = vtk.vtkKdTreePointLocator() kdTree.SetDataSet(centerlines[key]) iD = kdTree.FindClosestPoint(end_points[i]) kdTree.Update() end_point_ = list(centerlines[key].GetPoint(iD)) end_point_tangent_ = list(centerlines[key].GetPointData().GetArray( "FrenetTangent").GetTuple(iD)) end_point_normal_ = list(centerlines[key].GetPointData().GetArray( "FrenetNormal").GetTuple(iD)) end_point_binormal_ = list( centerlines[key].GetPointData().GetArray( "FrenetBinormal").GetTuple(iD)) end_point_dict = { "coordinate": end_point_, "tangent": end_point_tangent_, "normal": end_point_normal_, "binormal": end_point_binormal_ } key_point_list_.update({outlet_key: start_point_dict}) clip_result = clip_polydata_by_box(surface, end_point_, end_point_tangent_, end_point_normal_, end_point_binormal_, size=[10, 10, 1], capping=capping) # perform lcc everytime after clipping to guarantee clean result connectedFilter.SetInputData(clip_result["clipped_surface"]) connectedFilter.Update() surface.DeepCopy(connectedFilter.GetOutput()) clipBoxes_.update({outlet_key: clip_result["clip_box"]}) clipPlanes_.update({outlet_key: clip_result["clip_plane"]}) connectedFilter_cap = vtk.vtkConnectivityFilter() connectedFilter_cap.SetExtractionModeToClosestPointRegion() connectedFilter_cap.SetClosestPoint([ end_point_[i] - end_point_tangent_[i] for i in range(len(end_point_)) ]) connectedFilter_cap.SetInputData(clip_result["boundary_cap"]) connectedFilter_cap.Update() end_cap = vtk.vtkPolyData() end_cap.DeepCopy(connectedFilter_cap.GetOutput()) # end_cap = clip_result["boundary_cap"] boundaryCaps_.update({outlet_key: end_cap}) clipBoxes.update({key: clipBoxes_}) clipPlanes.update({key: clipPlanes_}) boundaryCaps.update({key: boundaryCaps_}) surfaces_clipped.update({key: surface}) key_point_list.update({key: key_point_list_}) for key, centerline in centerlines.items(): kdTree = vtk.vtkKdTreePointLocator() kdTree.SetDataSet(centerlines[key]) iD = kdTree.FindClosestPoint(start_point) kdTree.Update() start_point_ = list(centerlines[key].GetPoint(iD)) start_point_tangent_ = list(centerlines[key].GetPointData().GetArray( "FrenetTangent").GetTuple(iD)) start_point_normal_ = list(centerlines[key].GetPointData().GetArray( "FrenetNormal").GetTuple(iD)) start_point_binormal_ = list(centerlines[key].GetPointData().GetArray( "FrenetBinormal").GetTuple(iD)) clip_result = clip_polydata_by_box(centerline, start_point_, start_point_tangent_, start_point_normal_, start_point_binormal_, size=[15, 15, 1]) centerline = clip_result["clipped_surface"] for i in range(len(end_ids)): kdTree = vtk.vtkKdTreePointLocator() kdTree.SetDataSet(centerlines[key]) iD = kdTree.FindClosestPoint(end_points[i]) kdTree.Update() end_point_ = list(centerlines[key].GetPoint(iD)) end_point_tangent_ = list(centerlines[key].GetPointData().GetArray( "FrenetTangent").GetTuple(iD)) end_point_normal_ = list(centerlines[key].GetPointData().GetArray( "FrenetNormal").GetTuple(iD)) end_point_binormal_ = list( centerlines[key].GetPointData().GetArray( "FrenetBinormal").GetTuple(iD)) clip_result = clip_polydata_by_box(centerline, end_point_, end_point_tangent_, end_point_normal_, end_point_binormal_, size=[10, 10, 1]) centerline = clip_result["clipped_surface"] connectedFilter.SetInputData(centerline) connectedFilter.Update() centerline.DeepCopy(connectedFilter.GetOutput()) centerlines_clipped.update({key: centerline}) # output vtpWriter = vtk.vtkXMLPolyDataWriter() for key, value in centerlines_clipped.items(): vtpWriter.SetFileName( os.path.join(case_dir, key, "centerline_clipped.vtp")) vtpWriter.SetInputData(value) vtpWriter.Update() stlWriter = vtk.vtkSTLWriter() for key, value in surfaces_clipped.items(): stlWriter.SetFileName( os.path.join(case_dir, key, "surface_clipped.stl")) stlWriter.SetInputData(value) stlWriter.Update() for key, value in clipBoxes.items(): for key_, value_ in value.items(): stlWriter.SetFileName( os.path.join(case_dir, key, "clip_box_" + key_ + ".stl")) stlWriter.SetInputData(value_) stlWriter.Update() for key, value in clipPlanes.items(): for key_, value_ in value.items(): stlWriter.SetFileName( os.path.join(case_dir, key, "clip_plane_" + key_ + ".stl")) stlWriter.SetInputData(value_) stlWriter.Update() for key, value in boundaryCaps.items(): for key_, value_ in value.items(): stlWriter.SetFileName( os.path.join(case_dir, key, "boundary_cap_" + key_ + ".stl")) stlWriter.SetInputData(value_) stlWriter.Update() inletKeys = ["ICA", "ACA", "MCA"] if stl_concat: for phase in phases: if not os.path.exists( os.path.join(case_dir, phase, "surface_clipped.stl")): continue os.remove(os.path.join(case_dir, phase, "surface_capped.stl")) # check nan and correct mesh = trimesh.load_mesh( os.path.join(case_dir, phase, "surface_clipped.stl")) mesh.process() mesh.export(os.path.join(case_dir, phase, "surface_clipped.stl"), file_type='stl_ascii') stl_text = open( os.path.join(case_dir, phase, "surface_clipped.stl")).read().splitlines(True) stl_text[0] = "solid vessel\n" stl_text.append("\n") fout = open(os.path.join(case_dir, phase, "surface_capped.stl"), 'w') fout.writelines(stl_text) for inletKey in inletKeys: # check nan and correct mesh = trimesh.load_mesh( os.path.join( os.path.join(case_dir, phase, "boundary_cap_" + inletKey + ".stl"))) mesh.process() mesh.export(os.path.join(case_dir, phase, "boundary_cap_" + inletKey + ".stl"), file_type='stl_ascii') stl_text = open( os.path.join(case_dir, phase, "boundary_cap_" + inletKey + ".stl")).read().splitlines(True) stl_text[0] = "solid " + inletKey + "\n" stl_text.append("\n") fout.writelines(stl_text) fout.close() # output keypoint as json file for phase in phases: if not os.path.exists(os.path.join(case_dir, phase)): continue with open(os.path.join(case_dir, phase, "inlets.json"), "w") as fp: json.dump(key_point_list[phase], fp, indent=4)