def generateBaseMesh(cls, region, options): """ Generate the base tricubic Hermite mesh. See also generateMesh(). :param region: Zinc region to define model in. Must be empty. :param options: Dict containing options. See getDefaultOptions(). :return: annotationGroups """ centralPath = options['Central path'] segmentProfile = options['Segment profile'] segmentCount = options['Number of segments'] startPhase = options['Start phase'] % 360.0 proximalLength = options['Proximal length'] transverseLength = options['Transverse length'] proximalInnerRadius = options['Proximal inner radius'] proximalTCWidth = options['Proximal tenia coli width'] proximalTransverseInnerRadius = options['Proximal-transverse inner radius'] proximalTransverseTCWidth = options['Proximal-transverse tenia coli width'] transverseDistalInnerRadius = options['Transverse-distal inner radius'] transverseDistalTCWidth = options['Transverse-distal tenia coli width'] distalInnerRadius = options['Distal inner radius'] distalTCWidth = options['Distal tenia coli width'] segmentSettings = segmentProfile.getScaffoldSettings() elementsCountAroundTC = segmentSettings['Number of elements around tenia coli'] elementsCountAroundHaustrum = segmentSettings['Number of elements around haustrum'] cornerInnerRadiusFactor = segmentSettings['Corner inner radius factor'] haustrumInnerRadiusFactor = segmentSettings['Haustrum inner radius factor'] segmentLengthEndDerivativeFactor = segmentSettings['Segment length end derivative factor'] segmentLengthMidDerivativeFactor = segmentSettings['Segment length mid derivative factor'] tcCount = segmentSettings['Number of tenia coli'] tcThickness = segmentSettings['Tenia coli thickness'] elementsCountAround = (elementsCountAroundTC + elementsCountAroundHaustrum)*tcCount elementsCountAlongSegment = segmentSettings['Number of elements along segment'] elementsCountThroughWall = segmentSettings['Number of elements through wall'] wallThickness = segmentSettings['Wall thickness'] useCrossDerivatives = segmentSettings['Use cross derivatives'] useCubicHermiteThroughWall = not(segmentSettings['Use linear through wall']) elementsCountAlong = int(elementsCountAlongSegment*segmentCount) firstNodeIdentifier = 1 firstElementIdentifier = 1 # Central path tmpRegion = region.createRegion() centralPath.generate(tmpRegion) cx, cd1, cd2, cd12 = extractPathParametersFromRegion(tmpRegion) # for i in range(len(cx)): # print(i, '[', cx[i], ',', cd1[i], ',', cd2[i], ',', cd12[i], '],') del tmpRegion # find arclength of colon length = 0.0 elementsCountIn = len(cx) - 1 sd1 = interp.smoothCubicHermiteDerivativesLine(cx, cd1, fixAllDirections = True, magnitudeScalingMode = interp.DerivativeScalingMode.HARMONIC_MEAN) for e in range(elementsCountIn): arcLength = interp.getCubicHermiteArcLength(cx[e], sd1[e], cx[e + 1], sd1[e + 1]) # print(e+1, arcLength) length += arcLength segmentLength = length / segmentCount # print('Length = ', length) elementAlongLength = length / elementsCountAlong # Sample central path sx, sd1, se, sxi, ssf = interp.sampleCubicHermiteCurves(cx, cd1, elementsCountAlong) sd2, sd12 = interp.interpolateSampleCubicHermite(cd2, cd12, se, sxi, ssf) # Generate variation of radius & tc width along length lengthList = [0.0, proximalLength, proximalLength + transverseLength, length] innerRadiusList = [proximalInnerRadius, proximalTransverseInnerRadius, transverseDistalInnerRadius, distalInnerRadius] innerRadiusAlongElementList, dInnerRadiusAlongElementList = interp.sampleParameterAlongLine(lengthList, innerRadiusList, elementsCountAlong) tcWidthList = [proximalTCWidth, proximalTransverseTCWidth, transverseDistalTCWidth, distalTCWidth] tcWidthAlongElementList, dTCWidthAlongElementList = interp.sampleParameterAlongLine(lengthList, tcWidthList, elementsCountAlong) # Account for reduced haustrum appearance in transverse and distal pig colon if tcCount == 2: haustrumInnerRadiusFactorList = [haustrumInnerRadiusFactor, haustrumInnerRadiusFactor*0.75, haustrumInnerRadiusFactor*0.5, haustrumInnerRadiusFactor*0.2] haustrumInnerRadiusFactorAlongElementList = \ interp.sampleParameterAlongLine(lengthList, haustrumInnerRadiusFactorList, elementsCountAlong)[0] else: haustrumInnerRadiusFactorAlongElementList = [haustrumInnerRadiusFactor]*(elementsCountAlong+1) # Create annotation groups for colon sections elementsAlongInProximal = round(proximalLength/elementAlongLength) elementsAlongInTransverse = round(transverseLength/elementAlongLength) elementsAlongInDistal = elementsCountAlong - elementsAlongInProximal - elementsAlongInTransverse elementsCountAlongGroups = [elementsAlongInProximal, elementsAlongInTransverse, elementsAlongInDistal] colonGroup = AnnotationGroup(region, get_colon_term("colon")) if tcCount == 1: proximalGroup = AnnotationGroup(region, get_colon_term("proximal colon")) transverseGroup = AnnotationGroup(region, get_colon_term("transverse colon")) distalGroup = AnnotationGroup(region, get_colon_term("distal colon")) annotationGroupAlong = [[colonGroup, proximalGroup], [colonGroup, transverseGroup], [colonGroup, distalGroup]] elif tcCount == 2: spiralGroup = AnnotationGroup(region, get_colon_term("spiral colon")) transverseGroup = AnnotationGroup(region, get_colon_term("transverse colon")) distalGroup = AnnotationGroup(region, get_colon_term("distal colon")) annotationGroupAlong = [[colonGroup, spiralGroup], [colonGroup, transverseGroup], [colonGroup, distalGroup]] elif tcCount == 3: ascendingGroup = AnnotationGroup(region, get_colon_term("ascending colon")) transverseGroup = AnnotationGroup(region, get_colon_term("transverse colon")) descendingGroup = AnnotationGroup(region, get_colon_term("descending colon")) annotationGroupAlong = [[colonGroup, ascendingGroup], [colonGroup, transverseGroup], [colonGroup, descendingGroup]] annotationGroupsAlong = [] for i in range(len(elementsCountAlongGroups)): elementsCount = elementsCountAlongGroups[i] for n in range(elementsCount): annotationGroupsAlong.append(annotationGroupAlong[i]) annotationGroupsThroughWall = [] for i in range(elementsCountThroughWall): annotationGroupsThroughWall.append([ ]) xExtrude = [] d1Extrude = [] d2Extrude = [] d3UnitExtrude = [] sxRefExtrudeList = [] # Create object colonSegmentTubeMeshInnerPoints = ColonSegmentTubeMeshInnerPoints( region, elementsCountAroundTC, elementsCountAroundHaustrum, elementsCountAlongSegment, tcCount, segmentLengthEndDerivativeFactor, segmentLengthMidDerivativeFactor, segmentLength, wallThickness, cornerInnerRadiusFactor, haustrumInnerRadiusFactorAlongElementList, innerRadiusAlongElementList, dInnerRadiusAlongElementList, tcWidthAlongElementList, startPhase) for nSegment in range(segmentCount): # Create inner points xInner, d1Inner, d2Inner, transitElementList, segmentAxis, annotationGroupsAround \ = colonSegmentTubeMeshInnerPoints.getColonSegmentTubeMeshInnerPoints(nSegment) # Project reference point for warping onto central path start = nSegment * elementsCountAlongSegment end = (nSegment + 1) * elementsCountAlongSegment + 1 sxRefList, sd1RefList, sd2ProjectedListRef, zRefList = \ tubemesh.getPlaneProjectionOnCentralPath(xInner, elementsCountAround, elementsCountAlongSegment, segmentLength, sx[start:end], sd1[start:end], sd2[start:end], sd12[start:end]) # Warp segment points xWarpedList, d1WarpedList, d2WarpedList, d3WarpedUnitList = tubemesh.warpSegmentPoints( xInner, d1Inner, d2Inner, segmentAxis, sxRefList, sd1RefList, sd2ProjectedListRef, elementsCountAround, elementsCountAlongSegment, zRefList, innerRadiusAlongElementList[start:end], closedProximalEnd=False) # Store points along length xExtrude += xWarpedList if nSegment == 0 else xWarpedList[elementsCountAround:] d1Extrude += d1WarpedList if nSegment == 0 else d1WarpedList[elementsCountAround:] d2Extrude += d2WarpedList if nSegment == 0 else d2WarpedList[elementsCountAround:] d3UnitExtrude += d3WarpedUnitList if nSegment == 0 else d3WarpedUnitList[elementsCountAround:] sxRefExtrudeList += sxRefList if nSegment == 0 else sxRefList[elementsCountAround:] contractedWallThicknessList = colonSegmentTubeMeshInnerPoints.getContractedWallThicknessList() # Create coordinates and derivatives xList, d1List, d2List, d3List, curvatureList = tubemesh.getCoordinatesFromInner(xExtrude, d1Extrude, d2Extrude, d3UnitExtrude, contractedWallThicknessList, elementsCountAround, elementsCountAlong, elementsCountThroughWall, transitElementList) relaxedLengthList, xiList = colonSegmentTubeMeshInnerPoints.getRelaxedLengthAndXiList() closedProximalEnd = False if tcThickness > 0: tubeTCWidthList = colonSegmentTubeMeshInnerPoints.getTubeTCWidthList() xList, d1List, d2List, d3List, annotationArrayAround = getTeniaColi( region, xList, d1List, d2List, d3List, curvatureList, tcCount, elementsCountAroundTC, elementsCountAroundHaustrum, elementsCountAlong, elementsCountThroughWall, tubeTCWidthList, tcThickness, sxRefExtrudeList, annotationGroupsAround, closedProximalEnd) # Create flat and texture coordinates xFlat, d1Flat, d2Flat, xTexture, d1Texture, d2Texture = createFlatAndTextureCoordinatesTeniaColi( xiList, relaxedLengthList, length, wallThickness, tcCount, tcThickness, elementsCountAroundTC, elementsCountAroundHaustrum, elementsCountAlong, elementsCountThroughWall, transitElementList, closedProximalEnd) # Create nodes and elements nextNodeIdentifier, nextElementIdentifier, annotationGroups = createNodesAndElementsTeniaColi( region, xList, d1List, d2List, d3List, xFlat, d1Flat, d2Flat, xTexture, d1Texture, d2Texture, elementsCountAroundTC, elementsCountAroundHaustrum, elementsCountAlong, elementsCountThroughWall, tcCount, annotationGroupsAround, annotationGroupsAlong, annotationGroupsThroughWall, firstNodeIdentifier, firstElementIdentifier, useCubicHermiteThroughWall, useCrossDerivatives, closedProximalEnd) else: # Create flat and texture coordinates xFlat, d1Flat, d2Flat, xTexture, d1Texture, d2Texture = tubemesh.createFlatAndTextureCoordinates( xiList, relaxedLengthList, length, wallThickness, elementsCountAround, elementsCountAlong, elementsCountThroughWall, transitElementList) # Create nodes and elements nextNodeIdentifier, nextElementIdentifier, annotationGroups = tubemesh.createNodesAndElements( region, xList, d1List, d2List, d3List, xFlat, d1Flat, d2Flat, xTexture, d1Texture, d2Texture, elementsCountAround, elementsCountAlong, elementsCountThroughWall, annotationGroupsAround, annotationGroupsAlong, annotationGroupsThroughWall, firstNodeIdentifier, firstElementIdentifier, useCubicHermiteThroughWall, useCrossDerivatives, closedProximalEnd) return annotationGroups
def generateBaseMesh(cls, region, options): """ Generate the base tricubic Hermite mesh. See also generateMesh(). :param region: Zinc region to define model in. Must be empty. :param options: Dict containing options. See getDefaultOptions(). :return: annotationGroups """ centralPath = options['Central path'] segmentCount = options['Number of segments'] elementsCountAround = options['Number of elements around'] elementsCountAlongSegment = options['Number of elements along segment'] elementsCountThroughWall = options['Number of elements through wall'] duodenumLength = options['Duodenum length'] jejunumLength = options['Jejunum length'] duodenumInnerRadius = options['Duodenum inner radius'] duodenumJejunumInnerRadius = options['Duodenum-jejunum inner radius'] jejunumIleumInnerRadius = options['Jejunum-ileum inner radius'] ileumInnerRadius = options['Ileum inner radius'] wallThickness = options['Wall thickness'] useCrossDerivatives = options['Use cross derivatives'] useCubicHermiteThroughWall = not(options['Use linear through wall']) elementsCountAlong = int(elementsCountAlongSegment*segmentCount) startPhase = 0.0 firstNodeIdentifier = 1 firstElementIdentifier = 1 # Central path tmpRegion = region.createRegion() centralPath.generate(tmpRegion) cx, cd1, cd2, cd12 = extractPathParametersFromRegion(tmpRegion) # for i in range(len(cx)): # print(i, '[', cx[i], ',', cd1[i], ',', cd2[i],',', cd12[i], '],') del tmpRegion # find arclength of colon length = 0.0 elementsCountIn = len(cx) - 1 sd1 = interp.smoothCubicHermiteDerivativesLine(cx, cd1, fixAllDirections = True, magnitudeScalingMode = interp.DerivativeScalingMode.HARMONIC_MEAN) for e in range(elementsCountIn): arcLength = interp.getCubicHermiteArcLength(cx[e], sd1[e], cx[e + 1], sd1[e + 1]) # print(e+1, arcLength) length += arcLength segmentLength = length / segmentCount elementAlongLength = length / elementsCountAlong # print('Length = ', length) # Sample central path sx, sd1, se, sxi, ssf = interp.sampleCubicHermiteCurves(cx, cd1, elementsCountAlongSegment*segmentCount) sd2, sd12 = interp.interpolateSampleCubicHermite(cd2, cd12, se, sxi, ssf) # Generate variation of radius & tc width along length lengthList = [0.0, duodenumLength, duodenumLength + jejunumLength, length] innerRadiusList = [duodenumInnerRadius, duodenumJejunumInnerRadius, jejunumIleumInnerRadius, ileumInnerRadius] innerRadiusSegmentList, dInnerRadiusSegmentList = interp.sampleParameterAlongLine(lengthList, innerRadiusList, segmentCount) # Create annotation groups for small intestine sections elementsAlongDuodenum = round(duodenumLength / elementAlongLength) elementsAlongJejunum = round(jejunumLength / elementAlongLength) elementsAlongIleum = elementsCountAlong - elementsAlongDuodenum - elementsAlongJejunum elementsCountAlongGroups = [elementsAlongDuodenum, elementsAlongJejunum, elementsAlongIleum] smallintestineGroup = AnnotationGroup(region, get_smallintestine_term("small intestine")) duodenumGroup = AnnotationGroup(region, get_smallintestine_term("duodenum")) jejunumGroup = AnnotationGroup(region, get_smallintestine_term("jejunum")) ileumGroup = AnnotationGroup(region, get_smallintestine_term("ileum")) annotationGroupAlong = [[smallintestineGroup, duodenumGroup], [smallintestineGroup, jejunumGroup], [smallintestineGroup, ileumGroup]] annotationGroupsAlong = [] for i in range(len(elementsCountAlongGroups)): elementsCount = elementsCountAlongGroups[i] for n in range(elementsCount): annotationGroupsAlong.append(annotationGroupAlong[i]) annotationGroupsAround = [] for i in range(elementsCountAround): annotationGroupsAround.append([ ]) annotationGroupsThroughWall = [] for i in range(elementsCountThroughWall): annotationGroupsThroughWall.append([ ]) xExtrude = [] d1Extrude = [] d2Extrude = [] d3UnitExtrude = [] # Create object smallIntestineSegmentTubeMeshInnerPoints = CylindricalSegmentTubeMeshInnerPoints( elementsCountAround, elementsCountAlongSegment, segmentLength, wallThickness, innerRadiusSegmentList, dInnerRadiusSegmentList, startPhase) for nSegment in range(segmentCount): # Create inner points xInner, d1Inner, d2Inner, transitElementList, segmentAxis, radiusAlongSegmentList = \ smallIntestineSegmentTubeMeshInnerPoints.getCylindricalSegmentTubeMeshInnerPoints(nSegment) # Project reference point for warping onto central path start = nSegment*elementsCountAlongSegment end = (nSegment + 1)*elementsCountAlongSegment + 1 sxRefList, sd1RefList, sd2ProjectedListRef, zRefList = \ tubemesh.getPlaneProjectionOnCentralPath(xInner, elementsCountAround, elementsCountAlongSegment, segmentLength, sx[start:end], sd1[start:end], sd2[start:end], sd12[start:end]) # Warp segment points xWarpedList, d1WarpedList, d2WarpedList, d3WarpedUnitList = tubemesh.warpSegmentPoints( xInner, d1Inner, d2Inner, segmentAxis, sxRefList, sd1RefList, sd2ProjectedListRef, elementsCountAround, elementsCountAlongSegment, zRefList, radiusAlongSegmentList, closedProximalEnd=False) # Store points along length xExtrude = xExtrude + (xWarpedList if nSegment == 0 else xWarpedList[elementsCountAround:]) d1Extrude = d1Extrude + (d1WarpedList if nSegment == 0 else d1WarpedList[elementsCountAround:]) # Smooth d2 for nodes between segments and recalculate d3 if nSegment == 0: d2Extrude = d2Extrude + (d2WarpedList[:-elementsCountAround]) d3UnitExtrude = d3UnitExtrude + (d3WarpedUnitList[:-elementsCountAround]) else: xSecondFace = xWarpedList[elementsCountAround:elementsCountAround*2] d2SecondFace = d2WarpedList[elementsCountAround:elementsCountAround*2] for n1 in range(elementsCountAround): nx = [xLastTwoFaces[n1], xLastTwoFaces[n1 + elementsCountAround], xSecondFace[n1]] nd2 = [d2LastTwoFaces[n1], d2LastTwoFaces[n1 + elementsCountAround], d2SecondFace[n1]] d2 = interp.smoothCubicHermiteDerivativesLine(nx, nd2, fixStartDerivative = True, fixEndDerivative = True)[1] d2Extrude.append(d2) d3Unit = vector.normalise(vector.crossproduct3(vector.normalise(d1LastTwoFaces[n1 + elementsCountAround]), vector.normalise(d2))) d3UnitExtrude.append(d3Unit) d2Extrude = d2Extrude + \ (d2WarpedList[elementsCountAround:-elementsCountAround] if nSegment < segmentCount - 1 else d2WarpedList[elementsCountAround:]) d3UnitExtrude = d3UnitExtrude + \ (d3WarpedUnitList[elementsCountAround:-elementsCountAround] if nSegment < segmentCount - 1 else d3WarpedUnitList[elementsCountAround:]) xLastTwoFaces = xWarpedList[-elementsCountAround*2:] d1LastTwoFaces = d1WarpedList[-elementsCountAround*2:] d2LastTwoFaces = d2WarpedList[-elementsCountAround*2:] # Create coordinates and derivatives xList, d1List, d2List, d3List, curvatureList = tubemesh.getCoordinatesFromInner(xExtrude, d1Extrude, d2Extrude, d3UnitExtrude, [wallThickness]*(elementsCountAlong+1), elementsCountAround, elementsCountAlong, elementsCountThroughWall, transitElementList) flatWidthList, xiList = smallIntestineSegmentTubeMeshInnerPoints.getFlatWidthAndXiList() # Create flat and texture coordinates xFlat, d1Flat, d2Flat, xTexture, d1Texture, d2Texture = tubemesh.createFlatAndTextureCoordinates( xiList, flatWidthList, length, wallThickness, elementsCountAround, elementsCountAlong, elementsCountThroughWall, transitElementList) # Create nodes and elements nextNodeIdentifier, nextElementIdentifier, annotationGroups = tubemesh.createNodesAndElements( region, xList, d1List, d2List, d3List, xFlat, d1Flat, d2Flat, xTexture, d1Texture, d2Texture, elementsCountAround, elementsCountAlong, elementsCountThroughWall, annotationGroupsAround, annotationGroupsAlong, annotationGroupsThroughWall, firstNodeIdentifier, firstElementIdentifier, useCubicHermiteThroughWall, useCrossDerivatives, closedProximalEnd=False) return annotationGroups
def generateBaseMesh(cls, region, options): """ Generate the base tricubic Hermite mesh. See also generateMesh(). :param region: Zinc region to define model in. Must be empty. :param options: Dict containing options. See getDefaultOptions(). :return: annotationGroups """ centralPath = options['Central path'] elementsCountAround = options['Number of elements around'] elementsCountAlong = options['Number of elements along'] elementsCountThroughWall = options['Number of elements through wall'] wallThickness = options['Wall thickness'] mucosaRelThickness = options['Mucosa relative thickness'] submucosaRelThickness = options['Submucosa relative thickness'] circularRelThickness = options[ 'Circular muscle layer relative thickness'] longitudinalRelThickness = options[ 'Longitudinal muscle layer relative thickness'] useCrossDerivatives = options['Use cross derivatives'] useCubicHermiteThroughWall = not (options['Use linear through wall']) firstNodeIdentifier = 1 firstElementIdentifier = 1 # Central path esophagusTermsAlong = [ None, 'cervical part of esophagus', 'thoracic part of esophagus', 'abdominal part of esophagus' ] arcLengthOfGroupsAlong = [] for i in range(len(esophagusTermsAlong)): tmpRegion = region.createRegion() centralPath.generate(tmpRegion) cxGroup, cd1Group, cd2Group, cd3Group, cd12Group, cd13Group = \ extractPathParametersFromRegion(tmpRegion, [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D2_DS1DS3], groupName=esophagusTermsAlong[i]) arcLength = 0.0 for e in range(len(cxGroup) - 1): arcLength += interp.getCubicHermiteArcLength( cxGroup[e], cd1Group[e], cxGroup[e + 1], cd1Group[e + 1]) arcLengthOfGroupsAlong.append(arcLength) if i == 0: cx = cxGroup cd1 = cd1Group cd2 = cd2Group cd3 = cd3Group cd12 = cd12Group cd13 = cd13Group del tmpRegion # Sample central path sx, sd1, se, sxi, ssf = interp.sampleCubicHermiteCurves( cx, cd1, elementsCountAlong) sd2, sd12 = interp.interpolateSampleCubicHermite( cd2, cd12, se, sxi, ssf) sd3, sd13 = interp.interpolateSampleCubicHermite( cd3, cd13, se, sxi, ssf) centralPathLength = arcLengthOfGroupsAlong[0] elementAlongLength = centralPathLength / elementsCountAlong elementsCountAlongGroups = [] groupLength = 0.0 e = 0 elementsCount = 1 length = elementAlongLength for i in range(1, len(esophagusTermsAlong)): groupLength += arcLengthOfGroupsAlong[i] if e == elementsCountAlong - 2: elementsCount += 1 elementsCountAlongGroups.append(elementsCount) else: while length < groupLength: elementsCount += 1 e += 1 length += elementAlongLength # check which end is grouplength closer to distToUpperEnd = abs(length - groupLength) distToLowerEnd = abs(groupLength - (length - elementsCountAlong)) if distToLowerEnd < distToUpperEnd: elementsCount -= 1 elementsCountAlongGroups.append(elementsCount) e -= 1 length -= elementAlongLength else: elementsCountAlongGroups.append(elementsCount) elementsCount = 0 majorRadiusElementList = sd2 minorRadiusElementList = sd3 # Create annotation groups along esophagus esophagusGroup = AnnotationGroup(region, get_esophagus_term("esophagus")) cervicalGroup = AnnotationGroup( region, get_esophagus_term("cervical part of esophagus")) thoracicGroup = AnnotationGroup( region, get_esophagus_term("thoracic part of esophagus")) abdominalGroup = AnnotationGroup( region, get_esophagus_term("abdominal part of esophagus")) annotationGroupAlong = [[esophagusGroup, cervicalGroup], [esophagusGroup, thoracicGroup], [esophagusGroup, abdominalGroup]] annotationGroupsAlong = [] for i in range(len(elementsCountAlongGroups)): elementsCount = elementsCountAlongGroups[i] for n in range(elementsCount): annotationGroupsAlong.append(annotationGroupAlong[i]) annotationGroupsAround = [] for i in range(elementsCountAround): annotationGroupsAround.append([]) # Groups through wall longitudinalMuscleGroup = AnnotationGroup( region, get_esophagus_term("esophagus smooth muscle longitudinal layer")) circularMuscleGroup = AnnotationGroup( region, get_esophagus_term("esophagus smooth muscle circular layer")) submucosaGroup = AnnotationGroup( region, get_esophagus_term("submucosa of esophagus")) mucosaGroup = AnnotationGroup(region, get_esophagus_term("esophagus mucosa")) if elementsCountThroughWall == 1: relativeThicknessList = [1.0] annotationGroupsThroughWall = [[]] else: relativeThicknessList = [ mucosaRelThickness, submucosaRelThickness, circularRelThickness, longitudinalRelThickness ] annotationGroupsThroughWall = [[mucosaGroup], [submucosaGroup], [circularMuscleGroup], [longitudinalMuscleGroup]] xToSample = [] d1ToSample = [] for n2 in range(elementsCountAlong + 1): # Create inner points cx = [0.0, 0.0, elementAlongLength * n2] axis1 = [vector.magnitude(majorRadiusElementList[n2]), 0.0, 0.0] axis2 = [0.0, vector.magnitude(minorRadiusElementList[n2]), 0.0] xInner, d1Inner = geometry.createEllipsePoints(cx, 2 * math.pi, axis1, axis2, elementsCountAround, startRadians=0.0) xToSample += xInner d1ToSample += d1Inner d2ToSample = [[0.0, 0.0, elementAlongLength] ] * (elementsCountAround * (elementsCountAlong + 1)) # Sample along length xInnerRaw = [] d2InnerRaw = [] xToWarp = [] d1ToWarp = [] d2ToWarp = [] flatWidthList = [] xiList = [] for n1 in range(elementsCountAround): xForSamplingAlong = [] d2ForSamplingAlong = [] for n2 in range(elementsCountAlong + 1): idx = n2 * elementsCountAround + n1 xForSamplingAlong.append(xToSample[idx]) d2ForSamplingAlong.append(d2ToSample[idx]) xSampled, d2Sampled = interp.sampleCubicHermiteCurves( xForSamplingAlong, d2ForSamplingAlong, elementsCountAlong, arcLengthDerivatives=True)[0:2] xInnerRaw.append(xSampled) d2InnerRaw.append(d2Sampled) # Re-arrange sample order & calculate dx_ds1 and dx_ds3 from dx_ds2 for n2 in range(elementsCountAlong + 1): xAround = [] d2Around = [] for n1 in range(elementsCountAround): x = xInnerRaw[n1][n2] d2 = d2InnerRaw[n1][n2] xAround.append(x) d2Around.append(d2) d1Around = [] for n1 in range(elementsCountAround): v1 = xAround[n1] v2 = xAround[(n1 + 1) % elementsCountAround] d1 = d2 = [v2[c] - v1[c] for c in range(3)] arcLengthAround = interp.computeCubicHermiteArcLength( v1, d1, v2, d2, True) dx_ds1 = [c * arcLengthAround for c in vector.normalise(d1)] d1Around.append(dx_ds1) d1Smoothed = interp.smoothCubicHermiteDerivativesLoop( xAround, d1Around) xToWarp += xAround d1ToWarp += d1Smoothed d2ToWarp += d2Around # Flat width and xi flatWidth = 0.0 xiFace = [] for n1 in range(elementsCountAround): v1 = xAround[n1] d1 = d1Smoothed[n1] v2 = xAround[(n1 + 1) % elementsCountAround] d2 = d1Smoothed[(n1 + 1) % elementsCountAround] flatWidth += interp.getCubicHermiteArcLength(v1, d1, v2, d2) flatWidthList.append(flatWidth) for n1 in range(elementsCountAround + 1): xi = 1.0 / elementsCountAround * n1 xiFace.append(xi) xiList.append(xiFace) # Project reference point for warping onto central path sxRefList, sd1RefList, sd2ProjectedListRef, zRefList = \ tubemesh.getPlaneProjectionOnCentralPath(xToWarp, elementsCountAround, elementsCountAlong, centralPathLength, sx, sd1, sd2, sd12) # Warp points segmentAxis = [0.0, 0.0, 1.0] closedProximalEnd = False innerRadiusAlong = [] for n2 in range(elementsCountAlong + 1): firstNodeAlong = xToWarp[n2 * elementsCountAround] midptSegmentAxis = [0.0, 0.0, elementAlongLength * n2] radius = vector.magnitude(firstNodeAlong[c] - midptSegmentAxis[c] for c in range(3)) innerRadiusAlong.append(radius) xWarpedList, d1WarpedList, d2WarpedList, d3WarpedUnitList = \ tubemesh.warpSegmentPoints(xToWarp, d1ToWarp, d2ToWarp, segmentAxis, sxRefList, sd1RefList, sd2ProjectedListRef, elementsCountAround, elementsCountAlong, zRefList, innerRadiusAlong, closedProximalEnd) # Create coordinates and derivatives transitElementList = [0] * elementsCountAround xList, d1List, d2List, d3List, curvatureList = \ tubemesh.getCoordinatesFromInner(xWarpedList, d1WarpedList, d2WarpedList, d3WarpedUnitList, [wallThickness]*(elementsCountAlong+1), relativeThicknessList, elementsCountAround, elementsCountAlong, elementsCountThroughWall, transitElementList) # Create flat coordinates xFlat, d1Flat, d2Flat = tubemesh.createFlatCoordinates( xiList, flatWidthList, length, wallThickness, relativeThicknessList, elementsCountAround, elementsCountAlong, elementsCountThroughWall, transitElementList) # Create nodes and elements xOrgan = [] d1Organ = [] d2Organ = [] nodeIdentifier, elementIdentifier, annotationGroups = \ tubemesh.createNodesAndElements(region, xList, d1List, d2List, d3List, xFlat, d1Flat, d2Flat, xOrgan, d1Organ, d2Organ, None, elementsCountAround, elementsCountAlong, elementsCountThroughWall, annotationGroupsAround, annotationGroupsAlong, annotationGroupsThroughWall, firstNodeIdentifier, firstElementIdentifier, useCubicHermiteThroughWall, useCrossDerivatives, closedProximalEnd) # annotation fiducial points fm = region.getFieldmodule() fm.beginChange() mesh = fm.findMeshByDimension(3) cache = fm.createFieldcache() markerGroup = findOrCreateFieldGroup(fm, "marker") markerName = findOrCreateFieldStoredString(fm, name="marker_name") markerLocation = findOrCreateFieldStoredMeshLocation( fm, mesh, name="marker_location") nodes = fm.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES) markerPoints = findOrCreateFieldNodeGroup(markerGroup, nodes).getNodesetGroup() markerTemplateInternal = nodes.createNodetemplate() markerTemplateInternal.defineField(markerName) markerTemplateInternal.defineField(markerLocation) markerNames = [ "proximodorsal midpoint on serosa of upper esophageal sphincter", "proximoventral midpoint on serosa of upper esophageal sphincter", "distal point of lower esophageal sphincter serosa on the greater curvature of stomach", "distal point of lower esophageal sphincter serosa on the lesser curvature of stomach" ] totalElements = elementIdentifier radPerElementAround = math.pi * 2.0 / elementsCountAround elementAroundHalfPi = int(0.25 * elementsCountAround) xi1HalfPi = (math.pi * 0.5 - radPerElementAround * elementAroundHalfPi) / radPerElementAround elementAroundPi = int(0.5 * elementsCountAround) xi1Pi = (math.pi - radPerElementAround * elementAroundPi) / radPerElementAround markerElementIdentifiers = [ elementsCountAround * elementsCountThroughWall - elementAroundHalfPi, elementAroundHalfPi + 1 + elementsCountAround * (elementsCountThroughWall - 1), totalElements - elementsCountAround, totalElements - elementsCountAround + elementAroundPi ] markerXis = [[1.0 - xi1HalfPi, 0.0, 1.0], [xi1HalfPi, 0.0, 1.0], [0.0, 1.0, 1.0], [xi1Pi, 1.0, 1.0]] for n in range(len(markerNames)): markerGroup = findOrCreateAnnotationGroupForTerm( annotationGroups, region, get_esophagus_term(markerNames[n])) markerElement = mesh.findElementByIdentifier( markerElementIdentifiers[n]) markerXi = markerXis[n] cache.setMeshLocation(markerElement, markerXi) markerPoint = markerPoints.createNode(nodeIdentifier, markerTemplateInternal) nodeIdentifier += 1 cache.setNode(markerPoint) markerName.assignString(cache, markerGroup.getName()) markerLocation.assignMeshLocation(cache, markerElement, markerXi) for group in [esophagusGroup, markerGroup]: group.getNodesetGroup(nodes).addNode(markerPoint) fm.endChange() return annotationGroups
def generateBaseMesh(region, options): """ Generate the base tricubic Hermite mesh. See also generateMesh(). :param region: Zinc region to define model in. Must be empty. :param options: Dict containing options. See getDefaultOptions(). :return: annotationGroups """ centralPath = options['Central path'] segmentProfile = options['Segment profile'] segmentCount = options['Number of segments'] startPhase = options['Start phase'] % 360.0 proximalLength = options['Proximal length'] transverseLength = options['Transverse length'] distalLength = options['Distal length'] proximalInnerRadius = options['Proximal inner radius'] proximalTCWidth = options['Proximal tenia coli width'] proximalTransverseInnerRadius = options[ 'Proximal-transverse inner radius'] proximalTransverseTCWidth = options[ 'Proximal-transverse tenia coli width'] transverseDistalInnerRadius = options['Transverse-distal inner radius'] transverseDistalTCWidth = options['Transverse-distal tenia coli width'] distalInnerRadius = options['Distal inner radius'] distalTCWidth = options['Distal tenia coli width'] segmentSettings = segmentProfile.getScaffoldSettings() elementsCountAroundTC = segmentSettings[ 'Number of elements around tenia coli'] elementsCountAroundHaustrum = segmentSettings[ 'Number of elements around haustrum'] cornerInnerRadiusFactor = segmentSettings['Corner inner radius factor'] haustrumInnerRadiusFactor = segmentSettings[ 'Haustrum inner radius factor'] segmentLengthEndDerivativeFactor = segmentSettings[ 'Segment length end derivative factor'] segmentLengthMidDerivativeFactor = segmentSettings[ 'Segment length mid derivative factor'] tcCount = segmentSettings['Number of tenia coli'] tcThickness = segmentSettings['Tenia coli thickness'] elementsCountAround = (elementsCountAroundTC + elementsCountAroundHaustrum) * tcCount elementsCountAlongSegment = segmentSettings[ 'Number of elements along segment'] elementsCountThroughWall = segmentSettings[ 'Number of elements through wall'] wallThickness = segmentSettings['Wall thickness'] useCrossDerivatives = segmentSettings['Use cross derivatives'] useCubicHermiteThroughWall = not ( segmentSettings['Use linear through wall']) elementsCountAlong = int(elementsCountAlongSegment * segmentCount) firstNodeIdentifier = 1 firstElementIdentifier = 1 # Central path tmpRegion = region.createRegion() centralPath.generate(tmpRegion) cx, cd1, cd2, cd12 = extractPathParametersFromRegion(tmpRegion) # for i in range(len(cx)): # print(i, '[', cx[i], ',', cd1[i], ',', cd2[i], ',', cd12[i], '],') del tmpRegion # find arclength of colon length = 0.0 elementsCountIn = len(cx) - 1 sd1 = interp.smoothCubicHermiteDerivativesLine( cx, cd1, fixAllDirections=True, magnitudeScalingMode=interp.DerivativeScalingMode.HARMONIC_MEAN) for e in range(elementsCountIn): arcLength = interp.getCubicHermiteArcLength( cx[e], sd1[e], cx[e + 1], sd1[e + 1]) # print(e+1, arcLength) length += arcLength segmentLength = length / segmentCount # print('Length = ', length) # Sample central path sx, sd1, se, sxi, ssf = interp.sampleCubicHermiteCurves( cx, cd1, elementsCountAlongSegment * segmentCount) sd2 = interp.interpolateSampleCubicHermite(cd2, cd12, se, sxi, ssf)[0] # Generate variation of radius & tc width along length lengthList = [ 0.0, proximalLength, proximalLength + transverseLength, length ] innerRadiusList = [ proximalInnerRadius, proximalTransverseInnerRadius, transverseDistalInnerRadius, distalInnerRadius ] innerRadiusAlongElementList, dInnerRadiusAlongElementList = interp.sampleParameterAlongLine( lengthList, innerRadiusList, elementsCountAlong) tcWidthList = [ proximalTCWidth, proximalTransverseTCWidth, transverseDistalTCWidth, distalTCWidth ] tcWidthAlongElementList, dTCWidthAlongElementList = interp.sampleParameterAlongLine( lengthList, tcWidthList, elementsCountAlong) xExtrude = [] d1Extrude = [] d2Extrude = [] d3UnitExtrude = [] # Create object colonSegmentTubeMeshInnerPoints = ColonSegmentTubeMeshInnerPoints( region, elementsCountAroundTC, elementsCountAroundHaustrum, elementsCountAlongSegment, tcCount, segmentLengthEndDerivativeFactor, segmentLengthMidDerivativeFactor, segmentLength, wallThickness, cornerInnerRadiusFactor, haustrumInnerRadiusFactor, innerRadiusAlongElementList, dInnerRadiusAlongElementList, tcWidthAlongElementList, startPhase) for nSegment in range(segmentCount): # Create inner points xInner, d1Inner, d2Inner, transitElementList, segmentAxis, annotationGroups, annotationArray, \ faceMidPointsZ = colonSegmentTubeMeshInnerPoints.getColonSegmentTubeMeshInnerPoints(nSegment) # Warp segment points xWarpedList, d1WarpedList, d2WarpedList, d3WarpedUnitList = tubemesh.warpSegmentPoints( xInner, d1Inner, d2Inner, segmentAxis, segmentLength, sx, sd1, sd2, elementsCountAround, elementsCountAlongSegment, nSegment, faceMidPointsZ) # Store points along length xExtrude = xExtrude + (xWarpedList if nSegment == 0 else xWarpedList[elementsCountAround:]) d1Extrude = d1Extrude + (d1WarpedList if nSegment == 0 else d1WarpedList[elementsCountAround:]) d2Extrude = d2Extrude + (d2WarpedList if nSegment == 0 else d2WarpedList[elementsCountAround:]) d3UnitExtrude = d3UnitExtrude + ( d3WarpedUnitList if nSegment == 0 else d3WarpedUnitList[elementsCountAround:]) contractedWallThicknessList = colonSegmentTubeMeshInnerPoints.getContractedWallThicknessList( ) # Create coordinates and derivatives xList, d1List, d2List, d3List, curvatureList = tubemesh.getCoordinatesFromInner( xExtrude, d1Extrude, d2Extrude, d3UnitExtrude, contractedWallThicknessList, elementsCountAround, elementsCountAlong, elementsCountThroughWall, transitElementList) relaxedLengthList, xiList = colonSegmentTubeMeshInnerPoints.getRelaxedLengthAndXiList( ) if tcThickness > 0: tubeTCWidthList = colonSegmentTubeMeshInnerPoints.getTubeTCWidthList( ) xList, d1List, d2List, d3List, annotationGroups, annotationArray = getTeniaColi( region, xList, d1List, d2List, d3List, curvatureList, tcCount, elementsCountAroundTC, elementsCountAroundHaustrum, elementsCountAlong, elementsCountThroughWall, tubeTCWidthList, tcThickness, sx, annotationGroups, annotationArray) # Create flat and texture coordinates xFlat, d1Flat, d2Flat, xTexture, d1Texture, d2Texture = createFlatAndTextureCoordinatesTeniaColi( xiList, relaxedLengthList, length, wallThickness, tcCount, tcThickness, elementsCountAroundTC, elementsCountAroundHaustrum, elementsCountAlong, elementsCountThroughWall, transitElementList) # Create nodes and elements nextNodeIdentifier, nextElementIdentifier, annotationGroups = createNodesAndElementsTeniaColi( region, xList, d1List, d2List, d3List, xFlat, d1Flat, d2Flat, xTexture, d1Texture, d2Texture, elementsCountAroundTC, elementsCountAroundHaustrum, elementsCountAlong, elementsCountThroughWall, tcCount, annotationGroups, annotationArray, firstNodeIdentifier, firstElementIdentifier, useCubicHermiteThroughWall, useCrossDerivatives) else: # Create flat and texture coordinates xFlat, d1Flat, d2Flat, xTexture, d1Texture, d2Texture = tubemesh.createFlatAndTextureCoordinates( xiList, relaxedLengthList, length, wallThickness, elementsCountAround, elementsCountAlong, elementsCountThroughWall, transitElementList) # Create nodes and elements nextNodeIdentifier, nextElementIdentifier, annotationGroups = tubemesh.createNodesAndElements( region, xList, d1List, d2List, d3List, xFlat, d1Flat, d2Flat, xTexture, d1Texture, d2Texture, elementsCountAround, elementsCountAlong, elementsCountThroughWall, annotationGroups, annotationArray, firstNodeIdentifier, firstElementIdentifier, useCubicHermiteThroughWall, useCrossDerivatives) return annotationGroups