From e051a3d493f7837aee3cdef69ff4e841977aae22 Mon Sep 17 00:00:00 2001 From: mlin865 Date: Fri, 30 Jun 2023 13:50:11 +1200 Subject: [PATCH 01/24] Initial commit of cecum derived from network --- .../annotation/smallintestine_terms.py | 1 + .../meshtypes/meshtype_3d_cecum2.py | 2391 +++++++++++++++++ .../meshtypes/meshtype_3d_ostium2.py | 1112 ++++++++ src/scaffoldmaker/scaffolds.py | 4 + 4 files changed, 3508 insertions(+) create mode 100644 src/scaffoldmaker/meshtypes/meshtype_3d_cecum2.py create mode 100644 src/scaffoldmaker/meshtypes/meshtype_3d_ostium2.py diff --git a/src/scaffoldmaker/annotation/smallintestine_terms.py b/src/scaffoldmaker/annotation/smallintestine_terms.py index abc3a0df..c2ac7e03 100644 --- a/src/scaffoldmaker/annotation/smallintestine_terms.py +++ b/src/scaffoldmaker/annotation/smallintestine_terms.py @@ -7,6 +7,7 @@ ("circular-longitudinal muscle interface of first segment of the duodenum along the gastric-omentum attachment", "ILX:0793090"), ("circular muscle layer of small intestine", "ILX:0772669"), ("duodenum", "UBERON:0002114", "FMA:7206", "ILX:0726125"), + ("ileocecal junction", "UBERON:0001073", "FMA:11338", "ILX:0730012"), ("ileum", "UBERON:0002116", "FMA:7208", "ILX:0728151"), ("jejunum", "UBERON:0002115", "FMA:7207", "ILX:0724224"), ("longitudinal muscle layer of small intestine", "ILX:0772125"), diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_cecum2.py b/src/scaffoldmaker/meshtypes/meshtype_3d_cecum2.py new file mode 100644 index 00000000..bdd19b4e --- /dev/null +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_cecum2.py @@ -0,0 +1,2391 @@ +""" +Generates a 3-D cecum mesh along the central line, with variable +numbers of elements around, along and through wall, with +variable radius and thickness along. +""" + +import copy +import math + +from cmlibs.maths.vectorops import add, sub +from cmlibs.utils.zinc.field import findOrCreateFieldCoordinates # KM +from cmlibs.zinc.element import Element, Elementbasis +from cmlibs.zinc.field import Field +from cmlibs.zinc.node import Node +from scaffoldmaker.annotation.annotationgroup import AnnotationGroup, mergeAnnotationGroups +from scaffoldmaker.annotation.cecum_terms import get_cecum_term +from scaffoldmaker.annotation.smallintestine_terms import get_smallintestine_term +from scaffoldmaker.meshtypes.meshtype_1d_network_layout1 import MeshType_1d_network_layout1 +from scaffoldmaker.meshtypes.meshtype_3d_colonsegment1 import ColonSegmentTubeMeshInnerPoints, \ + getFullProfileFromHalfHaustrum, getTeniaColi, createNodesAndElementsTeniaColi +from scaffoldmaker.meshtypes.meshtype_3d_ostium2 import MeshType_3d_ostium2, generateOstiumMesh +from scaffoldmaker.meshtypes.scaffold_base import Scaffold_base +from scaffoldmaker.scaffoldpackage import ScaffoldPackage +from scaffoldmaker.utils import interpolation as interp +from scaffoldmaker.utils import matrix +from scaffoldmaker.utils import tubemesh +from scaffoldmaker.utils import vector +from scaffoldmaker.utils.geometry import createEllipsePoints # KM +from scaffoldmaker.utils.annulusmesh import createAnnulusMesh3d +from scaffoldmaker.utils.eftfactory_bicubichermitelinear import eftfactory_bicubichermitelinear +from scaffoldmaker.utils.eftfactory_tricubichermite import eftfactory_tricubichermite +from scaffoldmaker.utils.eft_utils import setEftScaleFactorIds, remapEftNodeValueLabel, remapEftNodeValueLabelsVersion +from scaffoldmaker.utils.networkmesh import NetworkMesh, NetworkNode +from scaffoldmaker.utils.tracksurface import TrackSurface, TrackSurfacePosition +from scaffoldmaker.utils.zinc_utils import exnode_string_from_nodeset_field_parameters, \ + mesh_destroy_elements_and_nodes_by_identifiers, get_nodeset_path_field_parameters, \ + get_nodeset_path_ordered_field_parameters + + +class MeshType_3d_cecum2(Scaffold_base): + ''' + Generates a 3-D cecum mesh with variable numbers + of elements around, along the central line, and through wall. + The cecum is created by a function that generates a cecum + segment and uses tubemesh to map the segment along a central + line profile. The proximal end of the cecum is closed up with + an apex plate. An ostium is included to generate the + ileo-cecal junction. + ''' + + parameterSetStructureStrings = { + 'Human 1': ScaffoldPackage(MeshType_1d_network_layout1, { + 'scaffoldSettings': { + "Structure": "1-2-3.2, 4-3-5" + }, + 'meshEdits': exnode_string_from_nodeset_field_parameters( + [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ + (1, [[7.50,-20.00,0.00], [0.00,8.28,0.00], [-1.50,0.00,0.00], [0.00,0.00,0.00], [0.00,-0.00,1.50], [0.00,0.00,0.00]]), + (2, [[7.50,-10.86,0.00], [0.00,10.00,0.00], [-4.50,0.00,0.00], [0.00,0.00,0.00], [0.00,-0.00,4.50], [0.00,0.00,0.00]]), + (3, [[7.50,0.00,0.00], [[7.50,0.00,0.00],[0.00,11.72,0.00]], [[0.00,10.00,0.00],[-4.50,0.00,0.00]], [[1.02,6.79,0.00],[0.00,0.00,0.00]], [[0.00,0.00,10.00],[0.00,-0.00,4.50]], [[0.00,0.00,5.77],[0.00,0.00,0.00]]]), + (4, [[0.00,0.00,0.00], [7.50,0.00,0.00], [0.00,10.00,0.00], [0.00,0.00,0.00], [0.00,0.00,10.00], [0.00,0.00,0.00]]), + (5, [[15.00,0.00,0.00], [7.50,0.00,0.00], [0.00,10.00,0.00], [0.00,0.00,0.00], [0.00,0.00,10.00], [0.00,0.00,0.00]])]), + + 'userAnnotationGroups': [ + { + '_AnnotationGroup': True, + 'dimension': 1, + 'identifierRanges': '3-4', + 'name': get_cecum_term('caecum')[0], + 'ontId': get_cecum_term('caecum')[1] + }, + { + '_AnnotationGroup': True, + 'dimension': 1, + 'identifierRanges': '1-2', + 'name': get_smallintestine_term('ileum')[0], + 'ontId': get_smallintestine_term('ileum')[1] + }] + }), + 'Human 2': ScaffoldPackage(MeshType_1d_network_layout1, { + 'scaffoldSettings': { + "Structure": "1-2-3.2, 4-3-5" + }, + 'meshEdits': exnode_string_from_nodeset_field_parameters( + [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ + (1, [[9.21,-19.56,6.43], [-2.02,7.27,-6.55], [-1.46,-0.27,0.15], [0.00,0.00,0.00], [-0.06,0.99,1.12], [0.00,0.00,0.00]]), + (2, [[7.72,-10.79,1.37], [-0.90,10.04,-3.37], [-4.48,-0.36,0.11], [0.00,0.00,0.00], [-0.01,1.43,4.27], [0.00,0.00,0.00]]), + (3, [[7.50,0.00,0.00], [[7.50,0.00,0.00],[0.45,11.25,0.61]], [[0.00,10.00,0.00],[-4.50,0.18,0.01]], [[1.02,6.79,0.00],[0.00,0.00,0.00]], [[0.00,0.00,10.00],[0.00,-0.24,4.49]], [[0.00,0.00,5.77],[0.00,0.00,0.00]]]), + (4, [[0.00,0.00,0.00], [7.50,0.00,0.00], [0.00,10.00,0.00], [0.00,0.00,0.00], [0.00,0.00,10.00], [0.00,0.00,0.00]]), + (5, [[15.00,0.00,0.00], [7.50,0.00,0.00], [0.00,10.00,0.00], [0.00,0.00,0.00], [0.00,0.00,10.00], [0.00,0.00,0.00]])]), + + 'userAnnotationGroups': [ + { + '_AnnotationGroup': True, + 'dimension': 1, + 'identifierRanges': '3-4', + 'name': get_cecum_term('caecum')[0], + 'ontId': get_cecum_term('caecum')[1] + }, + { + '_AnnotationGroup': True, + 'dimension': 1, + 'identifierRanges': '1-2', + 'name': get_smallintestine_term('ileum')[0], + 'ontId': get_smallintestine_term('ileum')[1] + }] + }), + 'Pig 1': ScaffoldPackage(MeshType_1d_network_layout1, { + 'scaffoldSettings': { + "Structure": "1-2-3.2, 4-5-6-3-7" + }, + 'meshEdits': exnode_string_from_nodeset_field_parameters( + [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ + (1, [[160.00,29.75,51.53], [0.00,-9.63,-16.67], [-4.0,-0.0,0.0], [0.00,0.00,0.00], [0.0,6.64,-3.83], [0.00,0.00,0.00]]), + (2, [[160.00,17.50,30.31], [0.00,-14.87,-25.76], [-15.00,-0.0,0.0], [0.00,0.00,0.00], [0.0,10.49,-6.05], [0.00,0.00,0.00]]), + (3, [[160.00,0.00,0.00], [[30.00,0.00,0.00],[0.00,-20.13,-34.86]], [[0.00,35.00,0.00],[-15.0,0.0,0.0]], [[0.00,0.00,0.00],[0.00,0.00,0.00]], [[0.00,0.00,35.00],[0.00,8.49,-4.90]], [[0.00,0.00,0.00],[0.00,0.00,0.00]]]), + (4, [[0.00,0.00,0.00], [60.00,0.00,0.00], [0.00,35.00,0.00], [0.00,0.00,0.00], [0.00,0.00,35.00], [0.00,0.00,0.00]]), + (5, [[60.00,0.00,0.00], [60.00,0.00,0.00], [0.00,35.00,0.00], [0.00,0.00,0.00], [0.00,0.00,35.00], [0.00,0.00,0.00]]), + (6, [[120.00,0.00,0.00], [50.00,0.00,0.00], [0.00,35.00,0.00], [0.00,0.00,0.00], [0.00,0.00,35.00], [0.00,0.00,0.00]]), + (7, [[180.00,0.00,0.00], [10.00,0.00,0.00], [0.00,35.00,0.00], [0.00,0.00,0.00], [0.00,0.00,35.00], [0.00,0.00,0.00]])]), + + 'userAnnotationGroups': [ + { + '_AnnotationGroup': True, + 'dimension': 1, + 'identifierRanges': '3-6', + 'name': get_cecum_term('caecum')[0], + 'ontId': get_cecum_term('caecum')[1] + }, + { + '_AnnotationGroup': True, + 'dimension': 1, + 'identifierRanges': '1-2', + 'name': get_smallintestine_term('ileum')[0], + 'ontId': get_smallintestine_term('ileum')[1] + }] + }), + } + + ostiumDefaultScaffoldPackages = { + 'Human 1': ScaffoldPackage(MeshType_3d_ostium2, { + 'scaffoldSettings': { + 'Number of elements around ostium': 8, + 'Number of elements along': 2, + 'Number of elements through wall': 1, + 'Unit scale': 1.0, + 'Outlet': False, + 'Ostium wall thickness': 1.6, + 'Ostium wall relative thicknesses': [0.55, 0.15, 0.25, 0.05], + 'Use linear through ostium wall': True, + 'Vessel wall thickness': 0.45, + 'Vessel wall relative thicknesses': [0.55, 0.15, 0.25, 0.05], + 'Use linear through vessel wall': True, + 'Use cross derivatives': False, + 'Refine': False, + 'Refine number of elements around': 4, + 'Refine number of elements along': 4, + 'Refine number of elements through wall': 1 + }, + }), + 'Pig 1': ScaffoldPackage(MeshType_3d_ostium2, { + 'scaffoldSettings': { + 'Number of elements around ostium': 8, + 'Number of elements along': 2, + 'Number of elements through wall': 1, # not implemented for > 1 + 'Unit scale': 1.0, + 'Outlet': False, + 'Ostium wall thickness': 2.0, + 'Use linear through ostium wall': True, + 'Vessel wall thickness': 2.0, + 'Use linear through vessel wall': True, + 'Use cross derivatives': False, + 'Refine': False, + 'Refine number of elements around': 4, + 'Refine number of elements along': 4, + 'Refine number of elements through wall': 1 + }, + }) + } + + @staticmethod + def getName(): + return '3D Cecum 2' + + @staticmethod + def getParameterSetNames(): + return [ + 'Default', + 'Human 1', + 'Human 2', + 'Pig 1'] + + @classmethod + def getDefaultOptions(cls, parameterSetName='Default'): + if 'Human 2' in parameterSetName: + centralPathOption = cls.parameterSetStructureStrings['Human 2'] + ostiumOption = cls.ostiumDefaultScaffoldPackages['Human 1'] + elif 'Pig 1' in parameterSetName: + centralPathOption = cls.parameterSetStructureStrings['Pig 1'] + ostiumOption = cls.ostiumDefaultScaffoldPackages['Pig 1'] + else: + centralPathOption = cls.parameterSetStructureStrings['Human 1'] + ostiumOption = cls.ostiumDefaultScaffoldPackages['Human 1'] + + options = { + 'Central path': copy.deepcopy(centralPathOption), + 'Number of segments': 1, + 'Number of elements around tenia coli': 2, + 'Number of elements around haustrum': 8, + 'Number of elements along segment': 8, + 'Number of elements through wall': 1, # 4 later! + 'Corner inner radius factor': 0.5, + 'Haustrum inner radius factor': 0.4, + 'Segment length end derivative factor': 0.5, + 'Segment length mid derivative factor': 1.0, # 3.0, + 'Number of tenia coli': 3, + 'Start tenia coli width': 2.0, #10.0, + 'Start tenia coli width derivative': 2.0, #0.0, + 'End tenia coli width': 4.0, #10.0, + 'End tenia coli width derivative': 2.0, #0.0, + 'Tenia coli thickness': 0.5, #1.6, + 'Wall thickness': 1.6, + 'Mucosa relative thickness': 0.55, + 'Submucosa relative thickness': 0.15, + 'Circular muscle layer relative thickness': 0.25, + 'Longitudinal muscle layer relative thickness': 0.05, + 'Ileocecal junction': copy.deepcopy(ostiumOption), + 'Use cross derivatives': False, + 'Use linear through wall': True, + 'Refine': False, + 'Refine number of elements around': 1, + 'Refine number of elements along': 1, + 'Refine number of elements through wall': 1 + } + + if 'Pig 1' in parameterSetName: + options['Number of segments'] = 5 + options['Haustrum inner radius factor'] = 0.25 + options['Segment length end derivative factor'] = 1.0 + options['Segment length mid derivative factor'] = 4.0 + options['Start tenia coli width'] = 5.0 + options['Start tenia coli width derivative'] = 0.0 + options['End tenia coli width'] = 5.0 + options['End tenia coli width derivative'] = 0.0 + options['Wall thickness'] = 2.0 + + cls.updateSubScaffoldOptions(options) + return options + + @staticmethod + def getOrderedOptionNames(): + return [ + 'Central path', + 'Number of segments', + 'Number of elements around tenia coli', + 'Number of elements around haustrum', + 'Number of elements along segment', + 'Number of elements through wall', + 'Corner inner radius factor', + 'Haustrum inner radius factor', + 'Segment length end derivative factor', + 'Segment length mid derivative factor', + 'Number of tenia coli', + 'Start tenia coli width', + 'Start tenia coli width derivative', + 'End tenia coli width', + 'End tenia coli width derivative', + 'Tenia coli thickness', + 'Wall thickness', + 'Mucosa relative thickness', + 'Submucosa relative thickness', + 'Circular muscle layer relative thickness', + 'Longitudinal muscle layer relative thickness', + 'Ileocecal junction', + 'Use cross derivatives', + 'Use linear through wall', + 'Refine', + 'Refine number of elements around', + 'Refine number of elements along', + 'Refine number of elements through wall'] + + @classmethod + def getOptionValidScaffoldTypes(cls, optionName): + if optionName == 'Central path': + return [ MeshType_1d_network_layout1 ] + if optionName == 'Ileocecal junction': + return [ MeshType_3d_ostium2 ] + return [] + + @classmethod + def getOptionScaffoldTypeParameterSetNames(cls, optionName, scaffoldType): + if optionName == 'Central path': + return list(cls.parameterSetStructureStrings.keys()) + if optionName == 'Ileocecal junction': + return list(cls.ostiumDefaultScaffoldPackages.keys()) + assert scaffoldType in cls.getOptionValidScaffoldTypes(optionName), cls.__name__ + '.getOptionScaffoldTypeParameterSetNames. ' + \ + 'Invalid option \'' + optionName + '\' scaffold type ' + scaffoldType.getName() + return scaffoldType.getParameterSetNames() + + @classmethod + def getOptionScaffoldPackage(cls, optionName, scaffoldType, parameterSetName=None): + ''' + :param parameterSetName: Name of valid parameter set for option Scaffold, or None for default. + :return: ScaffoldPackage. + ''' + if parameterSetName: + assert parameterSetName in cls.getOptionScaffoldTypeParameterSetNames(optionName, scaffoldType), \ + 'Invalid parameter set ' + str(parameterSetName) + ' for scaffold ' + str(scaffoldType.getName()) + ' in option ' + str(optionName) + ' of scaffold ' + cls.getName() + if optionName == 'Central path': + if not parameterSetName: + parameterSetName = list(cls.parameterSetStructureStrings.keys())[0] + return copy.deepcopy(cls.parameterSetStructureStrings[parameterSetName]) + if optionName == 'Ileocecal junction': + if not parameterSetName: + parameterSetName = list(cls.ostiumDefaultScaffoldPackages.keys())[0] + return copy.deepcopy(cls.ostiumDefaultScaffoldPackages[parameterSetName]) + assert False, cls.__name__ + '.getOptionScaffoldPackage: Option ' + optionName + ' is not a scaffold' + + @classmethod + def checkOptions(cls, options): + if not options['Central path'].getScaffoldType() in cls.getOptionValidScaffoldTypes('Central path'): + options['Central path'] = cls.getOptionScaffoldPackage('Central path', MeshType_1d_network_layout1) + if not options['Ileocecal junction'].getScaffoldType() in cls.getOptionValidScaffoldTypes('Ileocecal junction'): + options['Ileocecal junction'] = cls.getOptionScaffoldPackage('Ileocecal junction', MeshType_3d_ostium2) + for key in [ + 'Number of segments', + 'Refine number of elements around', + 'Refine number of elements along', + 'Refine number of elements through wall']: + if options[key] < 1: + options[key] = 1 + for key in [ + 'Number of elements around tenia coli', + 'Number of elements around haustrum', + 'Number of elements along segment', + 'Corner inner radius factor', + 'Haustrum inner radius factor', + 'Segment length end derivative factor', + 'Segment length mid derivative factor', + 'Number of tenia coli', + 'Start tenia coli width', + 'Start tenia coli width derivative', + 'End tenia coli width', + 'End tenia coli width derivative', + 'Tenia coli thickness', + 'Wall thickness']: + if options[key] < 0.0: + options[key] = 0.0 + if options['Number of elements through wall'] != (1 or 4): + options['Number of elements through wall'] = 4 + cls.updateSubScaffoldOptions(options) + + @classmethod + def updateSubScaffoldOptions(cls, options): + ''' + Update ostium sub-scaffold options which depend on parent options. + ''' + wallThickness = options['Wall thickness'] + ostiumOptions = options['Ileocecal junction'] + ostiumSettings = ostiumOptions.getScaffoldSettings() + ostiumSettings['Ostium wall thickness'] = wallThickness + elementsCountThroughWall = options['Number of elements through wall'] + ostiumSettings['Number of elements through wall'] = elementsCountThroughWall + if elementsCountThroughWall == 1: + ostiumSettings['Ostium wall relative thicknesses'] = [1.0] + ostiumSettings['Vessel wall relative thicknesses'] = [1.0] + else: + mucosaRelThickness = options['Mucosa relative thickness'] + submucosaRelThickness = options['Submucosa relative thickness'] + circularRelThickness = options['Circular muscle layer relative thickness'] + longRelThickness = options['Longitudinal muscle layer relative thickness'] + relThicknesses = [mucosaRelThickness, submucosaRelThickness, circularRelThickness, longRelThickness] + ostiumSettings['Ostium wall relative thicknesses'] = relThicknesses + ostiumSettings['Vessel wall relative thicknesses'] = relThicknesses + + @classmethod + def generateBaseMesh(cls, region, options): + """ + Generate the base tricubic Hermite mesh. + :param region: Zinc region to define model in. Must be empty. + :param options: Dict containing options. See getDefaultOptions(). + :return: annotationGroups + """ + + nextNodeIdentifier = 1 + nextElementIdentifier = 1 + cls.updateSubScaffoldOptions(options) + geometricCentralPath = options['Central path'] + cecumTermsAlong = ['caecum', 'ileum'] + geometricCentralPath = CecumCentralPath(region, geometricCentralPath, cecumTermsAlong) + annotationGroups, nextNodeIdentifier, nextElementIdentifier = \ + createCecumMesh3d(region, options, geometricCentralPath, nextNodeIdentifier, + nextElementIdentifier) + + return annotationGroups, None + + @classmethod + def refineMesh(cls, meshrefinement, options): + """ + Refine source mesh into separate region, with change of basis. + :param meshrefinement: MeshRefinement, which knows source and target region. + :param options: Dict containing options. See getDefaultOptions(). + """ + refineElementsCountAround = options['Refine number of elements around'] + refineElementsCountAlong = options['Refine number of elements along'] + refineElementsCountThroughWall = options['Refine number of elements through wall'] + + meshrefinement.refineAllElementsCubeStandard3d(refineElementsCountAround, refineElementsCountAlong, + refineElementsCountThroughWall) + return + +def getApexSegmentForCecum(xInner, d1Inner, d2Inner, elementsCountAroundHalfHaustrum, + elementsCountAroundTC, elementsCountAround, elementsCountAlongSegment, tcCount): + """ + Generates the inner coordinates and derivatives for a cecum segment on the closed end. + The closed end is a single node and segment is created by sampling curves between the + point on closed end with nodes on the length along second half of a colon segment. + :param xInner: coordinates of a colon segment. + :param d1Inner: derivative around colon segment. + :param d2Inner: derivative along colon segment. + :param elementsCountAroundHalfHaustrum: half of total number of elements in haustrum and tenia coli. + :param elementsCountAroundTC: number of elements around a tenia coli. + :param elementsCountAround: number of elements around a cecum. + :param elementsCountAlongSegment: number of elements along a segment of cecum. + :param tcCount: number of tenia coli. + :return: coordinates and derivatives around and along closed segment of cecum, and directional derivative for node + on middle of tenia coli. + """ + + # Make apex cap - apex points like multiple points + xFirstSegment = [[0.0, 0.0, 0.0] for c in range(elementsCountAround)] + + # Compile nodes and d2 for sampling + xFirstSegment += xInner[elementsCountAround * int(elementsCountAlongSegment * 0.5):] # second half of first regular segment + d1FirstDirectionVector = vector.normalise(d1Inner[elementsCountAround]) # Store direction vector of first d1 intra-haustral for later + d2Vector = xInner[elementsCountAround * int(elementsCountAlongSegment * 0.5): + elementsCountAround * (int(elementsCountAlongSegment * 0.5) + 1)] # half face of segment - apex + d2FirstSegment = [] + for c in range(elementsCountAround): + d2 = [d2Vector[c][0], d2Vector[c][1], 0.0 ] # project onto x-y plane to get d2 pointing vertically + d2FirstSegment.append(d2) + d2FirstSegment += d2Inner[elementsCountAround * int(elementsCountAlongSegment*0.5):] + + # Sample along first segment + xFirstSegmentSampledRaw = [] + d2FirstSegmentSampledRaw = [] + xFirstSegmentSampled = [] + d1FirstSegmentSampled = [] + d2FirstSegmentSampled = [] + + for n1 in range(elementsCountAround): + xForSamplingAlong = [] + d2ForSamplingAlong = [] + for n2 in range(1 + elementsCountAlongSegment - int(elementsCountAlongSegment * 0.5) + 1): + idx = elementsCountAround * n2 + n1 + xForSamplingAlong.append(xFirstSegment[idx]) + d2ForSamplingAlong.append(d2FirstSegment[idx]) + xResampled, d1Resampled, se, sxi, _ = interp.sampleCubicHermiteCurves(xForSamplingAlong, d2ForSamplingAlong, + elementsCountAlongSegment, + arcLengthDerivatives = True) + + xFirstSegmentSampledRaw.append(xResampled) + d2FirstSegmentSampledRaw.append(d1Resampled) + + # Re-arrange sample order + for n2 in range(elementsCountAlongSegment + 1): + xAround = [] + for n1 in range(elementsCountAround): + x = xFirstSegmentSampledRaw[n1][n2] + d2 = d2FirstSegmentSampledRaw[n1][n2] + if n1 < elementsCountAroundHalfHaustrum + 1: + xAround.append(x) + xFirstSegmentSampled.append(x) + d2FirstSegmentSampled.append(d2) + if n2 == 0: + d1 = matrix.rotateAboutZAxis(d2, math.pi*0.5) + d1FirstSegmentSampled.append(d1) + + if n2 > 0: + d1Around = [] + for n1 in range(elementsCountAroundHalfHaustrum): + v1 = xAround[n1] + v2 = xAround[n1 + 1] + d1 = d1FirstDirectionVector if n1 == 0 else [v2[c] - v1[c] for c in range(3)] + 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) + # Account for d1 of node sitting on half haustrum + d1 = vector.normalise( + [xAround[elementsCountAroundHalfHaustrum][c] - xAround[elementsCountAroundHalfHaustrum - 1][c] + for c in range(3)]) + dx_ds1 = [c * arcLengthAround for c in d1] + d1Around.append(dx_ds1) + + d1Smoothed = interp.smoothCubicHermiteDerivativesLine(xAround, d1Around, fixStartDerivative=True) + d1TCEdge = vector.setMagnitude(d1Smoothed[int(elementsCountAroundTC * 0.5)], + vector.magnitude(d1Smoothed[int(elementsCountAroundTC * 0.5 - 1)])) + d1Transition = vector.setMagnitude(d1Smoothed[int(elementsCountAroundTC * 0.5 + 1)], + vector.magnitude(d1Smoothed[int(elementsCountAroundTC * 0.5 + 2)])) + d1Corrected = [] + d1Corrected = d1Corrected + d1Smoothed[:int(elementsCountAroundTC * 0.5)] + d1Corrected.append(d1TCEdge) + d1Corrected.append(d1Transition) + d1Corrected = d1Corrected + d1Smoothed[int(elementsCountAroundTC * 0.5 + 2):] + d1Full = getD1ForFullProfileFromHalfHaustrum(d1Corrected, tcCount) + d1FirstSegmentSampled += d1Full + + return xFirstSegmentSampled, d1FirstSegmentSampled, d2FirstSegmentSampled, d1FirstDirectionVector + +def getD1ForFullProfileFromHalfHaustrum(d1HaustrumHalfSet, tcCount): + """ + Get full profile from half haustrum + :param d1HaustrumHalfSet: + :param tcCount: + :return: + """ + d1HaustrumHalfSet2 = [] + d1Haustra = [] + + rotAng = 2 * math.pi / tcCount + for n in range(1, len(d1HaustrumHalfSet)): + idx = -n + len(d1HaustrumHalfSet) - 1 + d1 = d1HaustrumHalfSet[idx] + d1Reflect = [d1[0], -d1[1], d1[2]] + d1Rot = [-(d1Reflect[0] * math.cos(rotAng) - d1Reflect[1] * math.sin(rotAng)), + -(d1Reflect[0] * math.sin(rotAng) + d1Reflect[1] * math.cos(rotAng)), + -d1Reflect[2]] + d1HaustrumHalfSet2.append(d1Rot) + + d1Haustrum = d1HaustrumHalfSet + d1HaustrumHalfSet2 + + # Rotate to get all 3 sectors + d1Haustra = d1Haustra + d1Haustrum[:-1] + ang = [2 / 3 * math.pi, -2 / 3 * math.pi] if tcCount == 3 else [math.pi] + for i in range(tcCount - 1): + rotAng = ang[i] + cosRotAng = math.cos(rotAng) + sinRotAng = math.sin(rotAng) + for n in range(len(d1Haustrum) - 1): + d1 = d1Haustrum[n] + dx_ds1 = [d1[0] * cosRotAng - d1[1] * sinRotAng, d1[0] * sinRotAng + d1[1] * cosRotAng, d1[2]] + d1Haustra.append(dx_ds1) + + return d1Haustra + +def sampleCecumAlongLength(xToSample, d1ToSample, d2ToSample, d1FirstDirectionVector, elementsCountAroundHalfHaustrum, + elementsCountAroundTC, elementsCountAround, elementsCountAlong, tcCount): + """ + Get systematically spaced points and derivatives over cubic Hermite interpolated curves along the + length of the cecum. + :param xToSample: coordinates of nodes. + :param d1ToSample: derivative around elements. + :param d2ToSample: derivative along cecum length. + :param d1FirstDirectionVector: directional vector of derivative around for node on the middle of the tenia coli. + :param elementsCountAroundHalfHaustrum:half the total number of elements around tenia coli and haustrum. + :param elementsCountAroundTC: number of elements around tenia coli. + :param elementsCountAround: number of elements around cecum. + :param elementsCountAlong: number of elements along cecum length. + :param tcCount: number of tenia coli. + :return: nodes and derivatives for equally spaced points. + """ + + xInnerRaw = [] + d2InnerRaw = [] + xSampledAlongLength = [] + d1SampledAlongLength = [] + d2SampledAlongLength = [] + + for n1 in range(elementsCountAroundHalfHaustrum + 1): + xForSamplingAlong = [] + d2ForSamplingAlong = [] + for n2 in range(elementsCountAlong + 1): + idx = n2 * elementsCountAround + n1 + xForSamplingAlong.append(xToSample[idx]) + d2ForSamplingAlong.append(d2ToSample[idx]) + xSampled, d2Sampled, se, sxi, _ = interp.sampleCubicHermiteCurves(xForSamplingAlong, d2ForSamplingAlong, + elementsCountAlong, + arcLengthDerivatives=True) + 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(elementsCountAroundHalfHaustrum + 1): + x = xInnerRaw[n1][n2] + d2 = d2InnerRaw[n1][n2] + xAround.append(x) + d2Around.append(d2) + + d1InnerAroundList = [] + if n2 == 0: + d1Corrected = d1ToSample[:elementsCountAroundHalfHaustrum + 1] + + else: + for n1 in range(elementsCountAroundHalfHaustrum): + v1 = xAround[n1] + v2 = xAround[n1 + 1] + d1 = d1FirstDirectionVector if n1 == 0 else [v2[c] - v1[c] for c in range(3)] + 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)] + d1InnerAroundList.append(dx_ds1) + # Account for d1 of node sitting on half haustrum + d1 = vector.normalise([xAround[elementsCountAroundHalfHaustrum][c] - + xAround[elementsCountAroundHalfHaustrum - 1][c] for c in range(3)]) + dx_ds1 = [c * arcLengthAround for c in d1] + d1InnerAroundList.append(dx_ds1) + + if d1InnerAroundList: + d1Smoothed = interp.smoothCubicHermiteDerivativesLine(xAround, d1InnerAroundList, fixStartDerivative=True) + d1TCEdge = vector.setMagnitude(d1Smoothed[int(elementsCountAroundTC * 0.5)], + vector.magnitude(d1Smoothed[int(elementsCountAroundTC * 0.5 - 1)])) + d1Transition = vector.setMagnitude(d1Smoothed[int(elementsCountAroundTC * 0.5 + 1)], + vector.magnitude(d1Smoothed[int(elementsCountAroundTC * 0.5 + 2)])) + d1Corrected = [] + d1Corrected = d1Corrected + d1Smoothed[:int(elementsCountAroundTC * 0.5)] + d1Corrected.append(d1TCEdge) + d1Corrected.append(d1Transition) + d1Corrected = d1Corrected + d1Smoothed[int(elementsCountAroundTC * 0.5 + 2):] + + xAlongList, d1AlongList, d2AlongList = getFullProfileFromHalfHaustrum(xAround, d1Corrected, d2Around, tcCount) + + xSampledAlongLength += xAlongList + d1SampledAlongLength += d1AlongList + d2SampledAlongLength += d2AlongList + + return xSampledAlongLength, d1SampledAlongLength, d2SampledAlongLength + +def getElementIdxOfOstiumBoundary(centrePosition, trackSurfaceOstium, ostiumDiameter): + """ + Finds the element indices of the boundaries of elements on tracksurface that surround + the ostium. Indices based on numbering for elements around and along tracksurface. + Boundary lies on xi=0 of elements on left and bottom boundaries and xi = 1 for right and + top boundaries. + :param centrePosition: surface description for centre of ostium. + :param trackSurfaceOstium: surface description for tracksurface. + :param ostiumDiameter: Diameter of ostium. + :return: element indices on the left, right, bottom and top boundaries around tracksurface. + """ + + elementsAroundTrackSurface = trackSurfaceOstium.elementsCount1 + elementsAlongTrackSurface = trackSurfaceOstium.elementsCount2 + ei1 = centrePosition.e1 + ei2 = centrePosition.e2 + xi1 = centrePosition.xi1 + xi2 = centrePosition.xi2 + xCentre, d1Centre, d2Centre = trackSurfaceOstium.evaluateCoordinates(centrePosition, derivatives=True) + + # Left boundary + leftPositionOfCentreElement = TrackSurfacePosition(ei1, ei2, 0, xi2) + xLeft, d1Left, _ = trackSurfaceOstium.evaluateCoordinates(leftPositionOfCentreElement, derivatives=True) + distxLeftToxCentre = interp.computeCubicHermiteArcLength(xLeft, d1Left, xCentre, d1Centre, False) + remainingLength = ostiumDiameter * 0.5 - distxLeftToxCentre + xCurrent = xLeft + d1Current = d1Left + + for n1 in range(ei1, -1, -1): + if remainingLength > 0.0: + prevPosition = TrackSurfacePosition(n1-1, ei2, 0, xi2) + xPrev, d1Prev, _ = trackSurfaceOstium.evaluateCoordinates(prevPosition, derivatives=True) + distPrevToxCurrent = interp.computeCubicHermiteArcLength(xPrev, d1Prev, xCurrent, d1Current, False) + remainingLength -= distPrevToxCurrent + xCurrent = xPrev + d1Current = d1Prev + else: + ei1Left = n1 + break + + # Right boundary + rightPositionOfCentreElement = TrackSurfacePosition(ei1, ei2, 1.0, xi2) + xRight, d1Right, _ = trackSurfaceOstium.evaluateCoordinates(rightPositionOfCentreElement, derivatives=True) + distxCentreToxRight = interp.computeCubicHermiteArcLength(xCentre, d1Centre, xRight, d1Right, False) + remainingLength = ostiumDiameter * 0.5 - distxCentreToxRight + xCurrent = xRight + d1Current = d1Right + + for n1 in range(ei1, elementsAroundTrackSurface): + if remainingLength > 0.0: + nextPosition = TrackSurfacePosition(n1+1, ei2, 1.0, xi2) + xNext, d1Next, _ = trackSurfaceOstium.evaluateCoordinates(nextPosition, derivatives=True) + distxCurrentToxNext = interp.computeCubicHermiteArcLength(xCurrent, d1Current, xNext, d1Next, False) + remainingLength -= distxCurrentToxNext + xCurrent = xNext + d1Current = d1Next + else: + ei1Right = n1 + break + + # Bottom boundary + bottomPositionOfCentreElement = TrackSurfacePosition(ei1, ei2, xi1, 0) + xBottom, _, d2Bottom = trackSurfaceOstium.evaluateCoordinates(bottomPositionOfCentreElement, derivatives=True) + distxBottomToxCentre = interp.computeCubicHermiteArcLength(xBottom, d2Bottom, xCentre, d2Centre, False) + remainingLength = ostiumDiameter * 0.5 - distxBottomToxCentre + xCurrent = xBottom + d2Current = d2Bottom + + for n2 in range(ei2, -1, -1): + if remainingLength > 0.0: + prevPosition = TrackSurfacePosition(ei1, n2 - 1, xi1, 0) + xPrev, _, d2Prev = trackSurfaceOstium.evaluateCoordinates(prevPosition, derivatives=True) + distPrevToxCurrent = interp.computeCubicHermiteArcLength(xPrev, d2Prev, xCurrent, d2Current, False) + remainingLength -= distPrevToxCurrent + xCurrent = xPrev + d2Current = d2Prev + else: + ei2Bottom = n2 + break + + # Top boundary + topPositionOfCentreElement = TrackSurfacePosition(ei1, ei2, xi1, 1.0) + xTop, _, d2Top = trackSurfaceOstium.evaluateCoordinates(topPositionOfCentreElement, derivatives=True) + distxCentreToxTop = interp.computeCubicHermiteArcLength(xCentre, d2Centre, xTop, d2Top, False) + remainingLength = ostiumDiameter * 0.5 - distxCentreToxTop + xCurrent = xTop + d2Current = d2Top + + for n2 in range(ei2, elementsAlongTrackSurface): + if remainingLength > 0.0: + nextPosition = TrackSurfacePosition(ei1, n2+1, xi1, 1.0) + xNext, _, d2Next = trackSurfaceOstium.evaluateCoordinates(nextPosition, derivatives=True) + distxCurrentToxNext = interp.computeCubicHermiteArcLength(xCurrent, d2Current, xNext, d2Next, False) + remainingLength -= distxCurrentToxNext + xCurrent = xNext + d2Current = d2Next + else: + ei2Top = n2 + break + + return ei1Left, ei1Right, ei2Bottom, ei2Top + +def findDerivativeBetweenPoints(v1, v2): + """ + Find vector difference between two points and rescale vector difference using cubic hermite arclength + between the points to derive the derivative between the points. + :param v1: start vector + :param v2: end vector + :return: derivative of between v1 and v2 + """ + d = [v2[c] - v1[c] for c in range(3)] + arcLengthAround = interp.computeCubicHermiteArcLength(v1, d, v2, d, True) + d = [c * arcLengthAround for c in vector.normalise(d)] + + return d + + +def findCurvatureAroundLoop(nx, nd, radialVectors): + """ + Calculate curvature for points lying along a loop. + :param nx: points on loop + :param nd: derivative of points on loop + :param radialVectors: radial direction, assumed normal to curve tangent at point + :return: curvatures along points on loop + """ + curvature = [] + for n in range(len(nx)): + prevIdx = n - 1 if n > 0 else -1 + nextIdx = n + 1 if n < len(nx) - 1 else 0 + kappam = interp.getCubicHermiteCurvature(nx[prevIdx], nd[prevIdx], nx[n], nd[n], radialVectors[n], 1.0) + kappap = interp.getCubicHermiteCurvature(nx[n], nd[n], nx[nextIdx], nd[nextIdx], radialVectors[n], 0.0) + curvature.append(0.5 * (kappam + kappap)) + + return curvature + +def findCurvatureAlongLine(nx, nd, radialVectors): + """ + Calculate curvature for points lying along a line. + :param nx: points on line + :param nd: derivative of points on line + :param radialVectors: radial direction, assumed normal to curve tangent at point + :return: curvatures along points on line + """ + curvature = [] + for n in range(len(nx)): + if n == 0: + curvature.append(interp.getCubicHermiteCurvature(nx[n], nd[n], nx[n + 1], nd[n + 1], radialVectors[n], 0.0)) + elif n == len(nx) - 1: + curvature.append(interp.getCubicHermiteCurvature(nx[n - 1], nd[n - 1], nx[n], nd[n], radialVectors[n], 1.0)) + else: + curvature.append(0.5 * ( + interp.getCubicHermiteCurvature(nx[n], nd[n], nx[n + 1], nd[n + 1], radialVectors[n], 0.0) + + interp.getCubicHermiteCurvature(nx[n - 1], nd[n - 1], nx[n], nd[n], radialVectors[n], 1.0))) + + return curvature + +def createCecumMesh3d(region, options, centralPath, nextNodeIdentifier, nextElementIdentifier): + """ + + """ + segmentCount = options['Number of segments'] + startPhase = 0.0 + elementsCountAroundTC = options['Number of elements around tenia coli'] + elementsCountAroundHaustrum = options['Number of elements around haustrum'] + elementsCountAlongSegment = options['Number of elements along segment'] + elementsCountThroughWall = options['Number of elements through wall'] + cornerInnerRadiusFactor = options['Corner inner radius factor'] + haustrumInnerRadiusFactor = options['Haustrum inner radius factor'] + segmentLengthEndDerivativeFactor = options['Segment length end derivative factor'] + segmentLengthMidDerivativeFactor = options['Segment length mid derivative factor'] + tcCount = options['Number of tenia coli'] + startTCWidth = options['Start tenia coli width'] + startTCWidthDerivative = options['Start tenia coli width derivative'] + endTCWidth = options['End tenia coli width'] + endTCWidthDerivative = options['End tenia coli width derivative'] + tcThickness = options['Tenia coli thickness'] + 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']) + elementsCountAlong = int(elementsCountAlongSegment * segmentCount) + elementsCountAround = (elementsCountAroundTC + elementsCountAroundHaustrum) * tcCount + + ostiumOptions = options['Ileocecal junction'] + ostiumSettings = ostiumOptions.getScaffoldSettings() + + zero = [0.0, 0.0, 0.0] + firstNodeIdentifier = nextNodeIdentifier + firstElementIdentifier = nextElementIdentifier + startNode = nextNodeIdentifier + startElement = nextElementIdentifier + + fm = region.getFieldmodule() + coordinates = findOrCreateFieldCoordinates(fm) + cache = fm.createFieldcache() + + nodes = fm.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES) + nodetemplate = nodes.createNodetemplate() + nodetemplate.defineField(coordinates) + nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_VALUE, 1) + nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D_DS1, 1) + nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D_DS2, 1) + if useCrossDerivatives: + nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D2_DS1DS2, 1) + if useCubicHermiteThroughWall: + nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D_DS3, 1) + if useCrossDerivatives: + nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D2_DS1DS3, 1) + nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D2_DS2DS3, 1) + nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D3_DS1DS2DS3, 1) + + if elementsCountThroughWall == 1: + relativeThicknessList = [1.0] + annotationGroupsThroughWall = [[]] + else: + relativeThicknessList = [mucosaRelThickness, submucosaRelThickness, + circularRelThickness, longitudinalRelThickness] + longitudinalMuscleGroup = AnnotationGroup(region, get_cecum_term("longitudinal muscle layer of cecum")) + circularMuscleGroup = AnnotationGroup(region, get_cecum_term("circular muscle layer of cecum")) + submucosaGroup = AnnotationGroup(region, get_cecum_term("submucosa of cecum")) + mucosaGroup = AnnotationGroup(region, get_cecum_term("cecum mucosa")) + annotationGroupsThroughWall = [[mucosaGroup], + [submucosaGroup], + [circularMuscleGroup], + [longitudinalMuscleGroup]] + + # Sample central path along cecum + # print(len(centralPath.cxGroups)) + cecumLength = centralPath.arcLengthOfGroupsAlong[0] + cx = centralPath.cxGroups[0] + cd1 = centralPath.cd1Groups[0] + cd2 = centralPath.cd2Groups[0] + cd12 = centralPath.cd12Groups[0] + + cxIleum = centralPath.cxGroups[1] + cd1Ileum = centralPath.cd1Groups[1] + cd2Ileum = centralPath.cd2Groups[1] + cd3Ileum = centralPath.cd3Groups[1] + cd12Ileum = centralPath.cd12Groups[1] + cd13Ileum = centralPath.cd13Groups[1] + + # xBranchPt = centralPath.xBranchPt + d2BranchPt = centralPath.d2BranchPt + + # smoothd1 = interp.smoothCubicHermiteDerivativesLine(cx, cd1, fixAllDirections=True, + # magnitudeScalingMode=interp.DerivativeScalingMode.HARMONIC_MEAN) + sxCecum, sd1Cecum, se, sxi, ssf = interp.sampleCubicHermiteCurves(cx, cd1, elementsCountAlong) + sd2Cecum, sd12Cecum = interp.interpolateSampleCubicHermite(cd2, cd12, se, sxi, ssf) + + # Calculate segment length + segmentLength = cecumLength / segmentCount + + # Generate variation of radius & tc width along length + innerRadiusAlongCecum = [] + dInnerRadiusAlongCecum = [] + tcWidthAlongCecum = [] + + closedProximalEnd = True + + innerRadiusListCP = [vector.magnitude(c) for c in cd2] + dInnerRadiusListCP = [] + for n in range(len(innerRadiusListCP) - 1): + dInnerRadiusListCP.append(innerRadiusListCP[n + 1] - innerRadiusListCP[n]) + dInnerRadiusListCP.append(innerRadiusListCP[-1] - innerRadiusListCP[-2]) + innerRadiusAlongElementList, dInnerRadiusAlongElementList = \ + interp.interpolateSampleCubicHermite(innerRadiusListCP, dInnerRadiusListCP, se, sxi, ssf) + + for n2 in range(elementsCountAlongSegment * segmentCount + 1): + xi = 1 / (elementsCountAlongSegment * segmentCount) * n2 + + radius = innerRadiusAlongElementList[n2] + innerRadiusAlongCecum.append(radius) + dRadius = dInnerRadiusAlongElementList[n2] + dInnerRadiusAlongCecum.append(dRadius) + tcWidth = interp.interpolateCubicHermite([startTCWidth], [startTCWidthDerivative], + [endTCWidth], [endTCWidthDerivative], xi)[0] + tcWidthAlongCecum.append(tcWidth) + + haustrumInnerRadiusFactorAlongCecum = [haustrumInnerRadiusFactor] * (elementsCountAlong + 1) + + xToSample = [] + d1ToSample = [] + d2ToSample = [] + + elementsCountAroundHalfHaustrum = int((elementsCountAroundTC + elementsCountAroundHaustrum) * 0.5) + + # Create object + colonSegmentTubeMeshInnerPoints = ColonSegmentTubeMeshInnerPoints( + region, elementsCountAroundTC, elementsCountAroundHaustrum, elementsCountAlongSegment, + tcCount, segmentLengthEndDerivativeFactor, segmentLengthMidDerivativeFactor, + segmentLength, wallThickness, cornerInnerRadiusFactor, haustrumInnerRadiusFactorAlongCecum, + innerRadiusAlongCecum, dInnerRadiusAlongCecum, tcWidthAlongCecum, startPhase) + + # Create annotation + cecumGroup = AnnotationGroup(region, get_cecum_term("caecum")) + annotationGroupsAlong = [] + for i in range(elementsCountAlong): + annotationGroupsAlong.append([cecumGroup]) + + for nSegment in range(segmentCount): + # Make regular segments + xInner, d1Inner, d2Inner, transitElementList, segmentAxis, annotationGroupsAround \ + = colonSegmentTubeMeshInnerPoints.getColonSegmentTubeMeshInnerPoints(nSegment) + + # Replace first half of first segment with apex and sample along apex and second half of segment + if nSegment == 0: + xFirstSegmentSampled, d1FirstSegmentSampled, d2FirstSegmentSampled, d1FirstDirectionVector = \ + getApexSegmentForCecum(xInner, d1Inner, d2Inner, elementsCountAroundHalfHaustrum, + elementsCountAroundTC, elementsCountAround, elementsCountAlongSegment, + tcCount) + + xToSample += xFirstSegmentSampled + d1ToSample += d1FirstSegmentSampled + d2ToSample += d2FirstSegmentSampled + else: + xInnerExtrude = [] + for n in range(len(xInner)): + xInnerExtrude.append([xInner[n][0], xInner[n][1], xInner[n][2] + segmentLength * nSegment]) + xToSample += xInnerExtrude[elementsCountAround:] + d1ToSample += d1Inner[elementsCountAround:] + d2ToSample += d2Inner[elementsCountAround:] + + # Sample along length + xToWarp, d1ToWarp, d2ToWarp = sampleCecumAlongLength(xToSample, d1ToSample, d2ToSample, d1FirstDirectionVector, + elementsCountAroundHalfHaustrum, elementsCountAroundTC, + elementsCountAround, elementsCountAlong, tcCount) + + # Ensure cecum starts at z = 0.0 + minZ = xToWarp[0][2] + for n2 in range(elementsCountAlong + 1): + zFirstNodeAlong = xToWarp[n2 * elementsCountAround][2] + if zFirstNodeAlong < minZ: + minZ = zFirstNodeAlong + + for n in range(len(xToWarp)): + xToWarp[n][2] = xToWarp[n][2] - minZ + + # Project reference point for warping onto central path + sxRefList, sd1RefList, sd2ProjectedListRef, zRefList = \ + tubemesh.getPlaneProjectionOnCentralPath(xToWarp, elementsCountAround, elementsCountAlong, + cecumLength, sxCecum, sd1Cecum, sd2Cecum, sd12Cecum) + + # Warp points + xWarpedList, d1WarpedList, d2WarpedList, d3WarpedUnitList = \ + tubemesh.warpSegmentPoints(xToWarp, d1ToWarp, d2ToWarp, segmentAxis, sxRefList, sd1RefList, + sd2ProjectedListRef, elementsCountAround, elementsCountAlong, zRefList) + + # Create coordinates and derivatives + wallThicknessList = [wallThickness] * (elementsCountAlong + 1) + + xList, d1List, d2List, d3List, curvatureList = \ + tubemesh.getCoordinatesFromInner(xWarpedList, d1WarpedList,d2WarpedList, d3WarpedUnitList, + wallThicknessList, relativeThicknessList, elementsCountAround, + elementsCountAlong, elementsCountThroughWall, transitElementList) + + # Deal with multiple nodes at end point for closed proximal end + xApexInner = xList[0] + # arclength between apex point and corresponding point on next face + mag = interp.getCubicHermiteArcLength(xList[0], d2List[0], + xList[elementsCountAround * (elementsCountThroughWall + 1)], + d2List[elementsCountAround * (elementsCountThroughWall + 1)]) + d2ApexInner = vector.setMagnitude(sd2Cecum[0], mag * 0.5) + d1ApexInner = vector.crossproduct3(sd1Cecum[0], d2ApexInner) + d1ApexInner = vector.setMagnitude(d1ApexInner, mag * 0.5) + d3ApexUnit = vector.normalise(vector.crossproduct3(vector.normalise(d1ApexInner), + vector.normalise(d2ApexInner))) + d3ApexInner = [d3ApexUnit[c] * wallThickness / elementsCountThroughWall for c in range(3)] + + xCecum = [] + d1Cecum = [] + d2Cecum = [] + d3Cecum = [] + + for n3 in range(elementsCountThroughWall + 1): + xApex = [xApexInner[c] + d3ApexUnit[c] * wallThickness / elementsCountThroughWall * n3 for c in range(3)] + xCecum.append(xApex) + d1Cecum.append(d1ApexInner) + d2Cecum.append(d2ApexInner) + d3Cecum.append(d3ApexInner) + + xCecum += xList[(elementsCountThroughWall + 1) * elementsCountAround:] + d1Cecum += d1List[(elementsCountThroughWall + 1) * elementsCountAround:] + d2Cecum += d2List[(elementsCountThroughWall + 1) * elementsCountAround:] + d3Cecum += d3List[(elementsCountThroughWall + 1) * elementsCountAround:] + + xFlat = d1Flat = d2Flat = [] + xOrgan = d1Organ = d2Organ = [] + + # Create nodes and elements + if tcThickness > 0: + tubeTCWidthList = colonSegmentTubeMeshInnerPoints.getTubeTCWidthList() + xCecum, d1Cecum, d2Cecum, d3Cecum, annotationArrayAround = getTeniaColi( + region, xCecum, d1Cecum, d2Cecum, d3Cecum, curvatureList, tcCount, elementsCountAroundTC, + elementsCountAroundHaustrum, elementsCountAlong, elementsCountThroughWall, + tubeTCWidthList, tcThickness, sxRefList, annotationGroupsAround, closedProximalEnd) + + nextNodeIdentifier, nextElementIdentifier, allAnnotationGroups = createNodesAndElementsTeniaColi( + region, xCecum, d1Cecum, d2Cecum, d3Cecum, xFlat, d1Flat, d2Flat, xOrgan, d1Organ, d2Organ, None, + elementsCountAroundTC, elementsCountAroundHaustrum, elementsCountAlong, elementsCountThroughWall, + tcCount, annotationGroupsAround, annotationGroupsAlong, annotationGroupsThroughWall, + firstNodeIdentifier, firstElementIdentifier, useCubicHermiteThroughWall, useCrossDerivatives, + closedProximalEnd) + + else: + nextNodeIdentifier, nextElementIdentifier, allAnnotationGroups = tubemesh.createNodesAndElements( + region, xCecum, d1Cecum, d2Cecum, d3Cecum, xFlat, d1Flat, d2Flat, xOrgan, d1Organ, d2Organ, None, + elementsCountAround, elementsCountAlong, elementsCountThroughWall, + annotationGroupsAround, annotationGroupsAlong, annotationGroupsThroughWall, + firstNodeIdentifier, firstElementIdentifier, useCubicHermiteThroughWall, useCrossDerivatives, + closedProximalEnd) + + nodeIdentifierCecum = nextNodeIdentifier + for n2 in range(len(cx)): + node = nodes.createNode(nextNodeIdentifier, nodetemplate) + cache.setNode(node) + coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, cx[n2]) + coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, cd1[n2]) + coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, cd2[n2]) + coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, [0.0, 0.0, 0.0]) + nextNodeIdentifier += 1 + + ################# + # Create elements + ################# + + mesh = fm.findMeshByDimension(1) + cubicHermiteBasis = fm.createElementbasis(1, Elementbasis.FUNCTION_TYPE_CUBIC_HERMITE) + eft = mesh.createElementfieldtemplate(cubicHermiteBasis) + elementtemplate = mesh.createElementtemplate() + elementtemplate.setElementShapeType(Element.SHAPE_TYPE_LINE) + result = elementtemplate.defineField(coordinates, -1, eft) + + elementIdentifier = nextElementIdentifier + for e in range(len(cx) - 1): + element = mesh.createElement(elementIdentifier, elementtemplate) + element.setNodesByIdentifier(eft, [nodeIdentifierCecum + e, nodeIdentifierCecum + 1 + e]) + elementIdentifier = elementIdentifier + 1 + + cx = centralPath.cxGroups[1] + cd1 = centralPath.cd1Groups[1] + cd2 = centralPath.cd2Groups[1] + + nodeIdentifierIleum = nextNodeIdentifier + for n2 in range(len(cx)): + node = nodes.createNode(nextNodeIdentifier, nodetemplate) + cache.setNode(node) + coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, cx[n2]) + coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, cd1[n2]) + coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, cd2[n2]) + coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, [0.0, 0.0, 0.0]) + nextNodeIdentifier += 1 + + for e in range(2): + element = mesh.createElement(elementIdentifier, elementtemplate) + element.setNodesByIdentifier(eft, [nodeIdentifierIleum + e, nodeIdentifierIleum + 1 + e]) + elementIdentifier = elementIdentifier + 1 + + # Add ostium on track surface + elementsAroundTrackSurface = elementsCountAroundHaustrum + elementsAlongTrackSurface = elementsCountAlongSegment + + # Find region where ostium sits + # angle between d2 of branch point and vector between branch point and 1st point on ileum + dV = [cxIleum[0][c] - cxIleum[-1][c] for c in range(3)] + ostiumPositionAngleAround = math.acos(vector.dotproduct(dV, d2BranchPt)/ + (vector.magnitude(dV) * vector.magnitude(d2BranchPt))) + sectorIdx = ostiumPositionAngleAround // (2 * math.pi / tcCount) + sectorStartAngle = sectorIdx * (2 * math.pi / tcCount) + + startIdxElementsAround = int((elementsCountAroundHaustrum + elementsCountAroundTC) * sectorIdx + + elementsCountAroundTC * 0.5) + + segmentIdx = int(centralPath.arcLengthToBranchPt // segmentLength) + + baseNodesIdx = (elementsCountThroughWall + 1) + \ + + (elementsCountAround * (elementsCountThroughWall + 1) + + ((elementsCountAroundTC - 1) * tcCount if tcThickness > 0.0 else 0)) * \ + (elementsCountAlongSegment * segmentIdx - 1) + elementsCountAround + + # Elements to delete + deleteElementIdentifier = [] + for n2 in range(elementsCountAlongSegment): + for n3 in range(elementsCountThroughWall): + for n1 in range(elementsCountAroundHaustrum): + elementIdx = \ + startIdxElementsAround + int(elementsCountAroundTC * (0.5 if tcThickness > 0.0 else 0)) + \ + n1 + (elementsCountAround * n3) + (elementsCountAround * elementsCountThroughWall + + elementsCountAroundTC * (tcCount if tcThickness > 0.0 else 0)) \ + * n2 + startElement - 1 + segmentIdx * ((elementsCountAround * n3) + + (elementsCountAround * elementsCountThroughWall + + elementsCountAroundTC * + (tcCount if tcThickness > 0.0 else 0)) * + elementsCountAlongSegment) + + deleteElementIdentifier.append(elementIdx) + + xTrackSurface = [] + d1TrackSurface = [] + d2TrackSurface = [] + nodesOnLHS = [] + nodesOnRHS = [] + nodesOnDistal = [] + nodesOnProximal = [] + + for n2 in range(elementsCountAlongSegment + 1): + for n1 in range(elementsCountAroundHaustrum + 1): + if n2 == 0 and segmentIdx == 0: + xTrackSurface.append(xApex) + d1TrackSurface.append(d1ApexInner) + d2TrackSurface.append(d2ApexInner) + else: + idx = baseNodesIdx + \ + (elementsCountAround * (elementsCountThroughWall + 1) + + ((elementsCountAroundTC - 1) * tcCount if tcThickness > 0.0 else 0)) * n2 + \ + startIdxElementsAround + n1 + (elementsCountAround * (elementsCountThroughWall - 1)) + xTrackSurface.append(xCecum[idx]) + d1TrackSurface.append(d1Cecum[idx]) + d2TrackSurface.append(d2Cecum[idx]) + + if n1 == 1: + nodeWall = [] + for n3 in range(elementsCountThroughWall, -1, -1): + nodeWall.append(idx - elementsCountAround * n3) + nodesOnLHS.append(nodeWall) + if n1 == elementsCountAroundHaustrum: + nodeWall = [] + for n3 in range(elementsCountThroughWall, -1, -1): + nodeWall.append(idx + 1 - elementsCountAround * n3) + nodesOnRHS.append(nodeWall) + if segmentIdx and n2 == 0 and n1 > 0 and n1 < elementsCountAroundHaustrum: + nodeWall = [] + for n3 in range(elementsCountThroughWall, -1, -1): + nodeWall.append(idx + 1 - elementsCountAround * n3) + nodesOnProximal.append(nodeWall) + if n2 == elementsCountAlongSegment and n1 > 0 and n1 < elementsCountAroundHaustrum: + nodeWall = [] + for n3 in range(elementsCountThroughWall, -1, -1): + nodeWall.append(idx + 1 - elementsCountAround * n3) + nodesOnDistal.append(nodeWall) + + sideNodes = [] + for n2 in range(elementsCountAlongSegment + 1): + for n3 in range(elementsCountThroughWall + 1): + if n2 == 0 and segmentIdx == 0: + sideNodes.append((n2 + 1) * (n3 + 1)) + elif segmentIdx and n2 == 0: + sideNodes.append(nodesOnLHS[n2][n3]) + for n in range(len(nodesOnProximal)): + sideNodes.append(nodesOnProximal[n][n3]) + sideNodes.append(nodesOnRHS[n2][n3]) + elif n2 == elementsCountAlongSegment: + sideNodes.append(nodesOnLHS[n2 + (0 if segmentIdx else -1)][n3]) + for n in range(len(nodesOnDistal)): + sideNodes.append(nodesOnDistal[n][n3]) + sideNodes.append(nodesOnRHS[n2 + (0 if segmentIdx else -1)][n3]) + else: + for n1 in range(2): + if n1 == 0: + sideNodes.append(nodesOnLHS[n2 + (0 if segmentIdx else -1)][n3]) + else: + sideNodes.append(nodesOnRHS[n2 + (0 if segmentIdx else -1)][n3]) + + # # Visualise track surface + # for n1 in range(len(xTrackSurface)): + # node = nodes.createNode(nextNodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xTrackSurface[n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d2TrackSurface[n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d1TrackSurface[n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, [0.0, 0.0, 0.0]) + # nextNodeIdentifier += 1 + + trackSurfaceOstium = TrackSurface(elementsAroundTrackSurface, elementsAlongTrackSurface, + xTrackSurface, d1TrackSurface, d2TrackSurface) + + # Find centre position + # track along ileum path and since cxIleum[1] could be above or below the track surface, we check both side to determine direction to track + # At each point, find the nearest position and take the diff between nearest point to the point in line, keep tracking till diff is close to zero. + xTol = 1.0E-6 + arcStart = 0.0 + arcEnd = centralPath.arcLengthOfGroupsAlong[1] + nearestPosition = trackSurfaceOstium.findNearestPosition(cxIleum[0]) + xNearestStart = trackSurfaceOstium.evaluateCoordinates(nearestPosition, derivatives=False) + distStart = vector.magnitude([cxIleum[0][c] - xNearestStart[c] for c in range(3)]) + nearestPosition = trackSurfaceOstium.findNearestPosition(cxIleum[-1]) + xNearestEnd = trackSurfaceOstium.evaluateCoordinates(nearestPosition, derivatives=False) + distEnd = vector.magnitude([cxIleum[-1][c] - xNearestEnd[c] for c in range(3)]) + + for iter in range(100): + arcDistance = (arcStart + arcEnd) * 0.5 + x, d1 = interp.getCubicHermiteCurvesPointAtArcDistance(cxIleum, cd1Ileum, arcDistance)[0:2] + nearestPosition = trackSurfaceOstium.findNearestPosition(x) + xNearest = trackSurfaceOstium.evaluateCoordinates(nearestPosition, derivatives=False) + dist = vector.magnitude([x[c] - xNearest[c] for c in range(3)]) + + if abs(distStart - distEnd) > xTol: + if distStart < distEnd: + arcEnd = arcDistance + distEnd = dist + else: + arcStart = arcDistance + distStart = dist + + else: + xCentre, d1Centre, d2Centre = trackSurfaceOstium.evaluateCoordinates(nearestPosition, derivatives=True) + normAxis = vector.normalise([-d for d in d1]) + eIdx = interp.getNearestPointIndex(cxIleum, xCentre) - 1 + arcLenghtSum = 0.0 + for e in range(eIdx): + arcLenghtSum += interp.getCubicHermiteArcLength(cxIleum[e], cd1Ileum[e], + cxIleum[e + 1], cd1Ileum[e + 1]) + xi = (arcDistance - arcLenghtSum)/\ + interp.getCubicHermiteArcLength(cxIleum[eIdx], cd1Ileum[eIdx], cxIleum[eIdx + 1], cd1Ileum[eIdx + 1]) + d2Centre = interp.interpolateCubicHermite(cd2Ileum[eIdx], cd12Ileum[eIdx], cd2Ileum[eIdx + 1], cd12Ileum[eIdx + 1], xi) + break + if iter > 98: + print('Search for ileum entry centre - Max iters reached:', iter) + + # node = nodes.createNode(nextNodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xNearest) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, [0.0, 0.0, 0.0]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, [0.0, 0.0, 0.0]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, [0.0, 0.0, 0.0]) + # print('x', nextNodeIdentifier) + # nextNodeIdentifier += 1 + + # node = nodes.createNode(nextNodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, cxIleum[eIdx]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, [0.0, 0.0, 0.0]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, cd2Ileum[eIdx]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, [0.0, 0.0, 0.0]) + # nextNodeIdentifier += 1 + # + # + # node = nodes.createNode(nextNodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, cxIleum[eIdx + 1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, [0.0, 0.0, 0.0]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, cd2Ileum[eIdx + 1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, [0.0, 0.0, 0.0]) + # nextNodeIdentifier += 1 + # + # node = nodes.createNode(nextNodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xCentre) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d1Centre) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d2Centre) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, normAxis) + # nextNodeIdentifier += 1 + + ostiumSettings['Number of elements around ostium'] = elementsCountAlongSegment + elementsCountAroundOstium = ostiumSettings['Number of elements around ostium'] + + fm = region.getFieldmodule() + mesh = fm.findMeshByDimension(3) + nodes = fm.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES) + + ileumGroup = AnnotationGroup(region, get_smallintestine_term("ileum")) + ileumMeshGroup = ileumGroup.getMeshGroup(mesh) + ileocecalJunctionGroup = AnnotationGroup(region, get_smallintestine_term("ileocecal junction")) + ileocecalJunctionMeshGroup = ileocecalJunctionGroup.getMeshGroup(mesh) + smallIntestineGroup = AnnotationGroup(region, get_smallintestine_term("small intestine")) + smallIntestineMeshGroup = smallIntestineGroup.getMeshGroup(mesh) + cecumMeshGroup = cecumGroup.getMeshGroup(mesh) + allAnnotationGroups += [ileumGroup, ileocecalJunctionGroup, smallIntestineGroup] + + ostiumWallAnnotationGroups = [] + if elementsCountThroughWall == 4: + ileumMucosaGroup = AnnotationGroup(region, get_smallintestine_term("mucosa of ileum")) + ileumSubmucosaGroup = AnnotationGroup(region, get_smallintestine_term("submucosa of ileum")) + ileumCircularGroup = AnnotationGroup(region, get_smallintestine_term("circular muscle layer of ileum")) + ileumLongitudinalGroup = AnnotationGroup(region, + get_smallintestine_term("longitudinal muscle layer of ileum")) + + ostiumWallAnnotationGroups = [[ileumMucosaGroup, mucosaGroup], + [ileumSubmucosaGroup, submucosaGroup], + [ileumCircularGroup, circularMuscleGroup], + [ileumLongitudinalGroup, longitudinalMuscleGroup]] + + allAnnotationGroups += [ileumMucosaGroup, ileumSubmucosaGroup, + ileumCircularGroup, ileumLongitudinalGroup] + + # Points from track surface and vessel end + xPath = [cxIleum[0], xCentre] + d1Path = [cd1Ileum[0], [-d for d in normAxis]] + d2Path = [cd2Ileum[0], d2Centre] + d3Path = [cd3Ileum[0], [-d for d in d1Centre]] + d12Path = [cd2Ileum[0], [0.0, 0.0, 0.0]] + d13Path = [cd3Ileum[0], [0.0, 0.0, 0.0]] + + centralPathIleum = CustomCentralPath(xPath, d1Path, d2Path, d3Path, d12Path, d13Path) + + # for n in range(2): + # node = nodes.createNode(nextNodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xPath[n]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d1Path[n]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d2Path[n]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, d3Path[n]) + # nextNodeIdentifier += 1 + + nextNodeIdentifier, nextElementIdentifier, (o1_x, o1_d1, o1_d2, o1_d3, o1_NodeId, o1_Positions) = \ + generateOstiumMesh(region, ostiumSettings, trackSurfaceOstium, centralPathIleum, + startNodeIdentifier=nextNodeIdentifier, startElementIdentifier=nextElementIdentifier, + vesselMeshGroups=[[cecumMeshGroup, smallIntestineMeshGroup, ileumMeshGroup]], + ostiumMeshGroups=[cecumMeshGroup, ileocecalJunctionMeshGroup], + wallAnnotationGroups=ostiumWallAnnotationGroups, coordinates=None) + + ostiumFaceStartNode = nextNodeIdentifier + ostiumFaceStartElement = nextElementIdentifier + + # Create location of annulus + xAnnulusOuter = [[] for x in range(elementsCountAroundOstium)] + xAnnulusOuterPosition = [[] for x in range(elementsCountAroundOstium)] + d1AnnulusNorm = [] + d1AnnulusOuter = [] + e1Left = elementsAroundTrackSurface + e1Right = 0 + e2Top = 0 + e2Bottom = elementsAlongTrackSurface + sf = vector.magnitude(centralPathIleum.cd2Path[-1]) * 0.25 + for n1 in range(elementsCountAroundOstium): + normD2 = vector.normalise(o1_d2[-1][n1]) + d1AnnulusNorm.append(normD2) + d1AnnulusOuter.append(vector.setMagnitude(o1_d2[-1][n1], sf)) + x = [o1_x[-1][n1][c] + sf * normD2[c] for c in range(3)] + nearestPosition = trackSurfaceOstium.findNearestPosition(x) + e1 = nearestPosition.e1 + e2 = nearestPosition.e2 + if e1 < e1Left: + e1Left = e1 + if e1 > e1Right: + e1Right = e1 + if e2 > e2Top: + e2Top = e2 + if e2 < e2Bottom: + e2Bottom = e2 + xAnnulusOuterPosition[n1] = nearestPosition + xAnnulusOuter[n1] = trackSurfaceOstium.evaluateCoordinates(nearestPosition) + + d2AnnulusOuter = [] + for n in range(elementsCountAlongSegment): + d = findDerivativeBetweenPoints(xAnnulusOuter[n], xAnnulusOuter[(n + 1) % elementsCountAroundOstium]) + d2AnnulusOuter.append(d) + d2AnnulusOuter = interp.smoothCubicHermiteDerivativesLoop(xAnnulusOuter, d2AnnulusOuter) + d3Annulus = [] + for n in range(elementsCountAroundOstium): + d3 = vector.normalise(vector.crossproduct3(vector.normalise(d2AnnulusOuter[n]), d1AnnulusNorm[n])) + d3Annulus.append(d3) + annulusD2Curvature = findCurvatureAroundLoop(xAnnulusOuter, d2AnnulusOuter, d3Annulus) + + # # Visualise annulus + # for n1 in range(len(xAnnulusOuter)): + # node = nodes.createNode(nextNodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xAnnulusOuter[n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d1AnnulusOuter[n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d2AnnulusOuter[n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, [0.0, 0.0, 0.0]) + # nextNodeIdentifier += 1 + + # base row counts with 8 elements around ostium + rowsIncrement = int((elementsCountAlongSegment - 8) / 4) + rowsAbove = 1 + rowsIncrement + rowsOstium = 4 + rowsIncrement * 2 + rowsBelow = 3 + rowsIncrement + + # # rowIdx along segment + startRowIdx = rowsBelow + 1 + endRowIdx = rowsBelow + rowsOstium - 1 + + # sample along the midline of ostium + rotAngle = math.pi + rotFrame = matrix.getRotationMatrixFromAxisAngle(d3ApexUnit, rotAngle) + # d2A = [rotFrame[j][0] * d2Cecum[1][0] + rotFrame[j][1] * d2Cecum[1][1] + + # rotFrame[j][2] * d2Cecum[1][2] for j in range(3)] + d1A = [rotFrame[j][0] * d1Cecum[1][0] + rotFrame[j][1] * d1Cecum[1][1] + + rotFrame[j][2] * d1Cecum[1][2] for j in range(3)] + + rotAngle = math.pi + rotFrame = matrix.getRotationMatrixFromAxisAngle(vector.normalise(d3Annulus[0]), rotAngle) + d2B = [rotFrame[j][0] * d1AnnulusOuter[0][0] + rotFrame[j][1] * d1AnnulusOuter[0][1] + + rotFrame[j][2] * d1AnnulusOuter[0][2] for j in range(3)] + + # sample along from apex to annulus start + if segmentIdx == 0: + xStart = xCecum[1] + else: + idx = int(elementsAroundTrackSurface * 0.5) + xStart = xTrackSurface[idx] + + xPositionA = trackSurfaceOstium.findNearestPosition(xStart) + xProportionA = trackSurfaceOstium.getProportion(xPositionA) + derivativeA = trackSurfaceOstium.evaluateCoordinates(xPositionA, derivatives=True)[2] + # derivativeMagnitudeA = vector.magnitude(derivativeA) + + xPositionB = trackSurfaceOstium.findNearestPosition(xAnnulusOuter[0]) + xProportionB = trackSurfaceOstium.getProportion(xPositionB) + derivativeB = d2B + derivativeMagnitudeB = vector.magnitude(derivativeB) + + nx, nd1, nd2, nd3, proportions = \ + trackSurfaceOstium.createHermiteCurvePoints( + xProportionA[0], xProportionA[1], xProportionB[0], xProportionB[1], + rowsBelow + 1, derivativeStart=derivativeA, derivativeEnd=derivativeB) + + pxAlongMidLine, pd2AlongMidLine, pd1AlongMidLine = \ + trackSurfaceOstium.resampleHermiteCurvePointsSmooth( + nx, nd1, nd2, nd3, proportions, #derivativeMagnitudeStart=derivativeMagnitudeB, + derivativeMagnitudeEnd=derivativeMagnitudeB)[0:3] + + for n in range(len(pd1AlongMidLine)): + pd1AlongMidLine[n] = [-d for d in pd1AlongMidLine[n]] + + # for n1 in range(len(nx)): + # node = nodes.createNode(nextNodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, nx[n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, nd2[n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, [0.0, 0.0, 0.0]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, [0.0, 0.0, 0.0]) + # # print(n1, nextNodeIdentifier) + # nextNodeIdentifier += 1 + + # Apex half + # print(startRowIdx) + # pxAlongMidLine, pd2AlongMidLine = \ + # interp.sampleCubicHermiteCurvesSmooth( + # nx, nd2, rowsBelow + 1, + # # derivativeMagnitudeStart=vector.magnitude([nx[1][c] - nx[0][c] for c in range(3)]), + # derivativeMagnitudeEnd=vector.magnitude(d2B))[:2] + + # for n1 in range(len(pxAlongMidLine)): + # node = nodes.createNode(nextNodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, pxAlongMidLine[n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, pd2AlongMidLine[n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, pd1AlongMidLine[n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, [0.0, 0.0, 0.0]) + # nextNodeIdentifier += 1 + + # Next haustrum half + # nx = [xAnnulusOuter[int(elementsCountAlongSegment * 0.5)]] + # nd2 = [d1AnnulusOuter[int(elementsCountAlongSegment * 0.5)]] + # nd1 = [d2AnnulusOuter[int(elementsCountAlongSegment * 0.5)]] + # + # for n in range(elementsAlongTrackSurface - e2Top): + # n1 = e2Top + 1 + n + # idx = elementsCountAroundHalfHaustrum + n1 * (elementsCountAroundHaustrum + 1) - 1 + # nx.append(xTrackSurface[idx]) + # nd2.append(d2TrackSurface[idx]) + # nd1.append(d1TrackSurface[idx]) + # + # pxAlongMidLineBottom, pd2AlongMidLineBottom, pe, pxi, psf = \ + # interp.sampleCubicHermiteCurvesSmooth( + # nx, nd2, rowsAbove + 1, + # derivativeMagnitudeStart=vector.magnitude(nd2[0]), + # derivativeMagnitudeEnd=vector.magnitude(nd2[-1])) + # + # pd1AlongMidLineBottom = nd1 + + xPositionA = trackSurfaceOstium.findNearestPosition(xAnnulusOuter[int(elementsCountAlongSegment * 0.5)]) + xProportionA = trackSurfaceOstium.getProportion(xPositionA) + xA, derivative2A, derivativeA = trackSurfaceOstium.evaluateCoordinates(xPositionA, derivatives=True) + derivativeMagnitudeA = vector.magnitude(d2AnnulusOuter[int(elementsCountAlongSegment * 0.5)]) # derivativeA) + + xB = xTrackSurface[-elementsCountAroundHalfHaustrum] + xPositionB = trackSurfaceOstium.findNearestPosition(xB) + xProportionB = trackSurfaceOstium.getProportion(xPositionB) + derivativeB = d2TrackSurface[-elementsCountAroundHalfHaustrum] + + nx, nd1, nd2, nd3, proportions = \ + trackSurfaceOstium.createHermiteCurvePoints( + xProportionA[0], xProportionA[1], xProportionB[0], xProportionB[1], + rowsAbove + 1, derivativeStart=derivativeA, derivativeEnd=derivativeB) + + pxAlongMidLineBottom, pd2AlongMidLineBottom, pd1AlongMidLineBottom = \ + trackSurfaceOstium.resampleHermiteCurvePointsSmooth( + nx, nd1, nd2, nd3, proportions, derivativeMagnitudeStart=derivativeMagnitudeA, + derivativeMagnitudeEnd=derivativeMagnitudeA)[0:3] + + for n in range(len(pd1AlongMidLineBottom)): + pd1AlongMidLineBottom[n] = [-d for d in pd1AlongMidLineBottom[n]] + + # for n1 in range(len(pxAlongMidLineBottom)): + # node = nodes.createNode(nextNodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, pxAlongMidLineBottom[n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, pd2AlongMidLineBottom[n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, pd1AlongMidLineBottom[n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, [0.0, 0.0, 0.0]) + # nextNodeIdentifier += 1 + + # sample points around colon to ostium + annulusIdx = 1 + xAroundAlong = [] + d1AroundAlong = [] + + sideElements = int(elementsCountAroundHaustrum * 0.5) + for n2 in range(elementsCountAlongSegment): + xAround = [] + d1Around = [] + if n2 == 0 and segmentIdx == 0: + for n1 in range(elementsCountAroundHaustrum + 1): + xAround.append(xApex) + d1Around.append(d1A) + else: + for n in range(2): + # LHS + if n == 0: + xPositionA = trackSurfaceOstium.findNearestPosition( + xTrackSurface[n2 * (elementsCountAroundHaustrum + 1)]) + xProportionA = trackSurfaceOstium.getProportion(xPositionA) + derivativeA = d1TrackSurface[n2 * (elementsCountAroundHaustrum + 1)] + derivativeMagnitudeA = vector.magnitude(derivativeA) + + if n2 < rowsBelow + 1: + xPositionB = trackSurfaceOstium.findNearestPosition(pxAlongMidLine[n2]) + derivativeB = None #pd1AlongMidLine[n2] + + elif n2 >= rowsBelow + rowsOstium: + idx = n2 - (rowsBelow + rowsOstium) + 1 + xPositionB = trackSurfaceOstium.findNearestPosition(pxAlongMidLineBottom[idx]) + derivativeB = None #pd1AlongMidLineBottom[idx] + + else: + xPositionB = trackSurfaceOstium.findNearestPosition(xAnnulusOuter[annulusIdx]) + rotAngle = math.pi + rotFrame = matrix.getRotationMatrixFromAxisAngle(vector.normalise(d3Annulus[annulusIdx]), + rotAngle) + derivativeB = [rotFrame[j][0] * d1AnnulusOuter[annulusIdx][0] + + rotFrame[j][1] * d1AnnulusOuter[annulusIdx][1] + + rotFrame[j][2] * d1AnnulusOuter[annulusIdx][2] for j in range(3)] + + # xB = trackSurfaceOstium.evaluateCoordinates(xPositionB) + xProportionB = trackSurfaceOstium.getProportion(xPositionB) + # derivativeMagnitudeB = vector.magnitude(derivativeB) + + # node = nodes.createNode(nextNodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xTrackSurface[n2 * (elementsCountAroundHaustrum + 1)]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, [0.0, 0.0, 0.0]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, derivativeA) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, [0.0, 0.0, 0.0]) + # nextNodeIdentifier += 1 + # + # node = nodes.createNode(nextNodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xB) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, [0.0, 0.0, 0.0]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, derivativeB) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, [0.0, 0.0, 0.0]) + # nextNodeIdentifier += 1 + + else: # RHS + if n2 < rowsBelow + 1: + xPositionA = trackSurfaceOstium.findNearestPosition(pxAlongMidLine[n2]) + derivativeA = None #pd1AlongMidLine[n2] + + elif n2 >= rowsBelow + rowsOstium: + idx = n2 - (rowsBelow + rowsOstium) + 1 + xPositionA = trackSurfaceOstium.findNearestPosition(pxAlongMidLineBottom[idx]) + derivativeA = None #pd1AlongMidLineBottom[idx] + + else: + xPositionA = trackSurfaceOstium.findNearestPosition(xAnnulusOuter[-annulusIdx]) + derivativeA = d1AnnulusOuter[-annulusIdx] + xProportionA = trackSurfaceOstium.getProportion(xPositionA) + # derivativeMagnitudeA = vector.magnitude(derivativeA) + + xPositionB = trackSurfaceOstium.findNearestPosition( + xTrackSurface[n2 * (elementsCountAroundHaustrum + 1) + elementsCountAroundHaustrum]) + xProportionB = trackSurfaceOstium.getProportion(xPositionB) + derivativeB = d1TrackSurface[n2 * (elementsCountAroundHaustrum + 1) + elementsCountAroundHaustrum] + # derivativeMagnitudeB = vector.magnitude(derivativeB) + + nx, nd1, nd2, nd3, proportions = \ + trackSurfaceOstium.createHermiteCurvePoints( + xProportionA[0], xProportionA[1], xProportionB[0], xProportionB[1], + sideElements +(0 if (n2 < rowsBelow + 1 or n2 >= rowsBelow + rowsOstium) else -1), + derivativeStart=derivativeA, derivativeEnd=derivativeB) + + nx, nd1 = \ + trackSurfaceOstium.resampleHermiteCurvePointsSmooth( + nx, nd1, nd2, nd3, proportions)[0:2] #, derivativeMagnitudeStart=derivativeMagnitudeB, + # derivativeMagnitudeEnd=derivativeMagnitudeB)[0:2] + + # for n in range(len(nx)): + # node = nodes.createNode(nextNodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, nx[n]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, nd1[n]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, [0.0, 0.0, 0.0]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, [0.0, 0.0, 0.0]) + # nextNodeIdentifier += 1 + + if n2 == rowsBelow + 1 or n2 == rowsBelow + rowsOstium - 1: # n2 == 5 or n2 == 9 + mag = 0.5 * (vector.magnitude(d1AnnulusOuter[0]) + vector.magnitude( + d2AnnulusOuter[0])) if n2 == startRowIdx else vector.magnitude(d1AnnulusOuter[0]) + if n == 0: + nd1[-1] = vector.setMagnitude(nd1[-1], mag) + else: + nd1[0] = vector.setMagnitude(nd1[0], mag) + if n == 0: + xAround += nx + d1Around += nd1 + else: + xAround += nx[(1 if (n2 < rowsBelow + 1 or n2 >= rowsBelow + rowsOstium) else 0):] + d1Around += nd1[(1 if (n2 < rowsBelow + 1 or n2 >= rowsBelow + rowsOstium) else 0):] + if n2 < rowsBelow + 1 or n2 >= rowsBelow + rowsOstium: + d1Around = interp.smoothCubicHermiteDerivativesLine(xAround, d1Around, fixStartDerivative=True, + fixEndDerivative=True) + + if n2 >= rowsBelow + 1 and n2 < rowsBelow + rowsOstium: + annulusIdx += 1 + + xAroundAlong.append(xAround) + d1AroundAlong.append(d1Around) + + xAround = [] + d1Around = [] + for n1 in range(elementsCountAroundHaustrum + 1): + xAround.append(xTrackSurface[n1 + (elementsCountAroundHaustrum + 1) * elementsCountAlongSegment]) + d1Around.append(d1TrackSurface[n1 + (elementsCountAroundHaustrum + 1) * elementsCountAlongSegment]) + xAroundAlong.append(xAround) + d1AroundAlong.append(d1Around) + + # Calculate d2 along segment + d2AroundAlong = [] + xAlongAll = [] + d2AlongAll = [] + + for n2 in range(len(xAroundAlong)): + d2Around = [] + for n1 in range(len(xAroundAlong[n2])): + d2Around.append([0.0, 0.0, 0.0]) + d2AroundAlong.append(d2Around) + + for n1 in range(elementsCountAroundHaustrum + 1): + nxAlong = [] + nd2Along = [] + if n1 < elementsCountAroundHalfHaustrum - 1: + for n2 in range(elementsCountAlongSegment): + nxAlong.append(xAroundAlong[n2][n1]) + nd2Along.append(findDerivativeBetweenPoints(xAroundAlong[n2][n1], xAroundAlong[n2 + 1][n1])) + nxAlong.append(xAroundAlong[n2 + 1][n1]) + nd2Along.append(d2TrackSurface[(elementsCountAroundHaustrum + 1) * elementsCountAlongSegment + n1]) + nd2Along = interp.smoothCubicHermiteDerivativesLine(nxAlong, nd2Along, fixStartDerivative=True, + fixEndDerivative=True) + + # Rescale d2 on node along annulus LHS to help with corners + if n1 == elementsCountAroundHalfHaustrum - 2: + nd2Along[startRowIdx] = \ + vector.setMagnitude(nd2Along[startRowIdx], + 0.5 * (vector.magnitude(nd2Along[startRowIdx]) + + vector.magnitude(d1AnnulusOuter[1]))) + nd2Along[endRowIdx] = \ + vector.setMagnitude(nd2Along[endRowIdx], + 0.5 * (vector.magnitude(nd2Along[endRowIdx]) + + vector.magnitude(d1AnnulusOuter[1]))) + xAlongAll.append(nxAlong) + d2AlongAll.append(nd2Along) + + for n2 in range(len(nd2Along)): + d2AroundAlong[n2][n1] = nd2Along[n2] + + elif n1 == elementsCountAroundHalfHaustrum - 1: + for n2 in range(len(pxAlongMidLine)): + d2AroundAlong[n2][n1] = pd2AlongMidLine[n2] + for n in range(1, len(pxAlongMidLineBottom)): + d2AroundAlong[n + endRowIdx][n1] = pd2AlongMidLineBottom[n] + nxAlong = pxAlongMidLine + pxAlongMidLineBottom + xAlongAll.append(nxAlong) + d2AlongAll.append(pd2AlongMidLine + pd2AlongMidLineBottom) + + else: + for n2 in range(elementsCountAlongSegment): + nxAlong.append(xAroundAlong[n2][n1 + (0 if (n2 < startRowIdx or n2 > endRowIdx) else -1)]) + if n2 < startRowIdx - 1 or n2 > endRowIdx -1: + nxAlongNext = xAroundAlong[n2 + 1][n1] + else: + nxAlongNext = xAroundAlong[n2 + 1][n1 - 1] + nd2Along.append(findDerivativeBetweenPoints( + xAroundAlong[n2][n1 + (0 if (n2 < startRowIdx or n2 > endRowIdx) else -1)], nxAlongNext)) + + nxAlong.append(xAroundAlong[n2 + 1][n1]) + nd2Along.append(d2TrackSurface[(elementsCountAroundHaustrum + 1) * elementsCountAlongSegment + n1]) + nd2Along = interp.smoothCubicHermiteDerivativesLine(nxAlong, nd2Along, fixStartDerivative=True, + fixEndDirection=True) + # Rescale d2 on node along annulus RHS to help with corners + if n1 == elementsCountAroundHalfHaustrum: + nd2Along[startRowIdx] = \ + vector.setMagnitude(nd2Along[startRowIdx], + 0.5 * (vector.magnitude(nd2Along[startRowIdx]) + + vector.magnitude(d1AnnulusOuter[1]))) + nd2Along[endRowIdx] = \ + vector.setMagnitude(nd2Along[endRowIdx], + 0.5 * (vector.magnitude(nd2Along[endRowIdx]) + + vector.magnitude(d1AnnulusOuter[1]))) + + xAlongAll.append(nxAlong) + d2AlongAll.append(nd2Along) + + for n2 in range(len(nd2Along)): + if n2 < startRowIdx or n2 > endRowIdx: + n1Idx = n1 + else: + n1Idx = n1 - 1 + d2AroundAlong[n2][n1Idx] = nd2Along[n2] + + # Calculate d3 + d3UnitAroundAlong = [] + for n2 in range(len(xAroundAlong)): + d3Around = [] + for n1 in range(len(xAroundAlong[n2])): + d3Around.append(vector.normalise( + vector.crossproduct3(vector.normalise(d1AroundAlong[n2][n1]), + vector.normalise(d2AroundAlong[n2][n1])))) + d3UnitAroundAlong.append(d3Around) + + # for n2 in range(len(xAroundAlong)): + # for n1 in range(len(xAroundAlong[n2])): + # node = nodes.createNode(nextNodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xAroundAlong[n2][n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d1AroundAlong[n2][n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d2AroundAlong[n2][n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, d3UnitAroundAlong[n2][n1]) + # nextNodeIdentifier += 1 + + # Calculate curvatures + # Curvatures around + d1Curvature = [] + if segmentIdx == 0: + d1Curvature.append([0.0]) # Check + + for n2 in range(1 if segmentIdx == 0 else 0, elementsCountAlongSegment + 1): + if n2 < startRowIdx or n2 == elementsCountAlongSegment: + d1Curvature.append(findCurvatureAlongLine(xAroundAlong[n2], d1AroundAlong[n2], d3UnitAroundAlong[n2])) + else: + d1CurvatureLeft = findCurvatureAlongLine(xAroundAlong[n2][:int(0.5 * len(xAroundAlong[n2]))], + d1AroundAlong[n2][:int(0.5 * len(xAroundAlong[n2]))], + d3UnitAroundAlong[n2][:int(0.5 * len(xAroundAlong[n2]))]) + + d1CurvatureRight = findCurvatureAlongLine(xAroundAlong[n2][int(0.5 * len(xAroundAlong[n2])):], + d1AroundAlong[n2][int(0.5 * len(xAroundAlong[n2])):], + d3UnitAroundAlong[n2][int(0.5 * len(xAroundAlong[n2])):]) + + d1Curvature.append(d1CurvatureLeft + d1CurvatureRight) + + # Curvatures along + d2Curvature = [] + for n2 in range(len(xAroundAlong)): + d2CurvatureAround = [] + for n1 in range(len(xAroundAlong[n2])): + d2CurvatureAround.append(0.0) + d2Curvature.append(d2CurvatureAround) + + for n1 in range(elementsCountAroundHaustrum + 1): + xAlong = xAlongAll[n1] + d2Along = d2AlongAll[n1] + d3UnitAlong = [] + + if n1 < elementsCountAroundHalfHaustrum - 1: + for n2 in range(elementsCountAlongSegment): + d3UnitAlong.append(d3UnitAroundAlong[n2][n1]) + d3UnitAlong.append(d3UnitAroundAlong[n2 + 1][n1]) + d2CurvatureAlong = findCurvatureAlongLine(xAlong, d2Along, d3UnitAlong) + # Adjust for corners + if n1 == elementsCountAroundHalfHaustrum - 2: + d2CurvatureAlong[endRowIdx] = annulusD2Curvature[int(elementsCountAlongSegment * 0.5) - 1] + + for n2 in range(len(d2CurvatureAlong)): + d2Curvature[n2][n1] = d2CurvatureAlong[n2] + + elif n1 == elementsCountAroundHalfHaustrum - 1: + xAlong = [] + d2Along = [] + d3UnitAlong = [] + for n2 in range(len(pd2AlongMidLine)): + xAlong.append(xAroundAlong[n2][n1]) + d2Along.append(d2AroundAlong[n2][n1]) + d3UnitAlong.append(d3UnitAroundAlong[n2][n1]) + d2CurvatureAlong = findCurvatureAlongLine(xAlong, d2Along, d3UnitAlong) + for n2 in range(len(pd2AlongMidLine)): + d2Curvature[n2][n1] = d2CurvatureAlong[n2] + + # Calculate curvature for node on edge + xAlong = [] + d2Along = [] + d3UnitAlong = [] + for n in range(1, len(pd2AlongMidLineBottom)): + nIdx = n + endRowIdx + xAlong.append(xAroundAlong[nIdx][n1]) + d2Along.append(d2AroundAlong[nIdx][n1]) + d3UnitAlong.append(d3UnitAroundAlong[nIdx][n1]) + d2CurvatureAlong = findCurvatureAlongLine(xAlong, d2Along, d3UnitAlong) + for n in range(len(pd2AlongMidLineBottom) - 1): + nIdx = n + endRowIdx + 1 + d2Curvature[nIdx][n1] = d2CurvatureAlong[n] + else: + for n2 in range(elementsCountAlongSegment): + d3UnitAlong.append(d3UnitAroundAlong[n2][n1 + (0 if (n2 < startRowIdx or n2 > endRowIdx) else -1)]) + d3UnitAlong.append(d3UnitAroundAlong[n2 + 1][n1]) + d2CurvatureAlong = findCurvatureAlongLine(xAlong, d2Along, d3UnitAlong) + + # Adjust for corners + if n1 == elementsCountAroundHalfHaustrum: + d2CurvatureAlong[endRowIdx] = annulusD2Curvature[int(elementsCountAlongSegment * 0.5) + 1] + + for n2 in range(len(d2CurvatureAlong)): + if n2 < startRowIdx or n2 > endRowIdx: + n1Idx = n1 + else: + n1Idx = n1 - 1 + d2Curvature[n2][n1Idx] = d2CurvatureAlong[n2] + + # Slot in annulus points along the midline + rotFrame = matrix.getRotationMatrixFromAxisAngle(d3Annulus[0], math.pi) + rotD2 = [rotFrame[j][0] * d2AnnulusOuter[0][0] + rotFrame[j][1] * d2AnnulusOuter[0][1] + + rotFrame[j][2] * d2AnnulusOuter[0][2] for j in range(3)] + xAroundAlong[startRowIdx].insert(int(elementsCountAroundHaustrum * 0.5), xAnnulusOuter[0]) + d1AroundAlong[startRowIdx].insert(int(elementsCountAroundHaustrum * 0.5), rotD2) + d2AroundAlong[startRowIdx].insert(int(elementsCountAroundHaustrum * 0.5), d1AnnulusOuter[0]) + d3UnitAroundAlong[startRowIdx].insert(int(elementsCountAroundHaustrum * 0.5), d3Annulus[0]) + d1Curvature[startRowIdx].insert(int(elementsCountAroundHaustrum * 0.5), annulusD2Curvature[0]) + d2Curvature[startRowIdx].insert(int(elementsCountAroundHaustrum * 0.5), annulusD2Curvature[0]) # need to update + + idx = int(elementsCountAlongSegment * 0.5) + xAroundAlong[endRowIdx].insert(int(elementsCountAroundHaustrum * 0.5), xAnnulusOuter[idx]) + d1AroundAlong[endRowIdx].insert(int(elementsCountAroundHaustrum * 0.5), d2AnnulusOuter[idx]) + d2AroundAlong[endRowIdx].insert(int(elementsCountAroundHaustrum * 0.5), d1AnnulusOuter[idx]) + d3UnitAroundAlong[endRowIdx].insert(int(elementsCountAroundHaustrum * 0.5), d3Annulus[idx]) + d1Curvature[endRowIdx].insert(int(elementsCountAroundHaustrum * 0.5), annulusD2Curvature[idx]) + d2Curvature[endRowIdx].insert(int(elementsCountAroundHaustrum * 0.5), annulusD2Curvature[idx]) # need to update + + # for n2 in range(len(xAroundAlong)): + # for n1 in range(len(xAroundAlong[n2])): + # node = nodes.createNode(nextNodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xAroundAlong[n2][n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d1AroundAlong[n2][n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d2AroundAlong[n2][n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, d3UnitAroundAlong[n2][n1]) + # nextNodeIdentifier += 1 + + # Create inner nodes + sideNodesToDelete = [] + xList = [] + d1List = [] + d2List = [] + d3List = [] + nodeIdx = ostiumFaceStartNode + idxMat = [] + + if elementsCountThroughWall > 1: + thicknessProportionsUI = [0.0, mucosaRelThickness, submucosaRelThickness, circularRelThickness, + longitudinalRelThickness, longitudinalRelThickness] + thicknessProportions = [thicknessProportion / sum(thicknessProportionsUI[:-1]) + for thicknessProportion in thicknessProportionsUI] + + xi3List = [] + xi3 = 0.0 + for i in range(len(thicknessProportions) - 1): + xi3 += thicknessProportions[i] + xi3List.append(xi3) + + count = 0 + for n2 in range(len(xAroundAlong)): + idxThroughWall = [] + for n3 in range(elementsCountThroughWall + 1): + xi3 = xi3List[n3] if elementsCountThroughWall > 1 else 1.0 / elementsCountThroughWall * n3 + idxAround = [] + + for n1 in range(1 if (n2 == 0 and segmentIdx == 0) else len(xAroundAlong[n2])): + if n1 == 0 or n1 == len(xAroundAlong[n2]) - 1: + sideNodesToDelete.append(nodeIdx) + newNodeIdx = sideNodes[count] + startNode - 1 + count += 1 + + elif n2 == 0 and segmentIdx and n1 > 0 and n1 < len(xAroundAlong[n2]) - 1: + sideNodesToDelete.append(nodeIdx) + newNodeIdx = sideNodes[count] + startNode - 1 + count += 1 + + elif n2 == len(xAroundAlong) - 1 and n1 > 0 and n1 < len(xAroundAlong[n2]) - 1: + sideNodesToDelete.append(nodeIdx) + newNodeIdx = sideNodes[count] + startNode - 1 + count += 1 + + else: + newNodeIdx = nodeIdx + + # Coordinates + norm = d3UnitAroundAlong[n2][n1] + xOut = xAroundAlong[n2][n1] + xIn = [xOut[i] - norm[i] * wallThickness for i in range(3)] + dWall = [wallThickness * c for c in norm] + x = interp.interpolateCubicHermite(xIn, dWall, xOut, dWall, xi3) + xList.append(x) + + # d1 + factor = 1.0 + wallThickness * (1.0 - xi3) * d1Curvature[n2][n1] + d1 = [factor * c for c in d1AroundAlong[n2][n1]] + d1List.append(d1) + + # d2 + factor = 1.0 + wallThickness * (1.0 - xi3) * d2Curvature[n2][n1] + d2 = [factor * c for c in d2AroundAlong[n2][n1]] + d2List.append(d2) + + # d3 + d3 = [c * wallThickness * (thicknessProportions[n3 + 1] if elementsCountThroughWall > 1 else 1.0) + for c in norm] + d3List.append(d3) + + idxAround.append(newNodeIdx) + nodeIdx += 1 + idxThroughWall.append(idxAround) + idxMat.append(idxThroughWall) + + for n in range(len(xList)): + if nextNodeIdentifier in sideNodesToDelete: + nextNodeIdentifier += 1 + continue + else: + node = nodes.createNode(nextNodeIdentifier, nodetemplate) + cache.setNode(node) + coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xList[n]) + coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d1List[n]) + coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d2List[n]) + coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, d3List[n]) + if useCrossDerivatives: + coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D2_DS1DS2, 1, zero) + coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D2_DS1DS3, 1, zero) + coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D2_DS2DS3, 1, zero) + coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D3_DS1DS2DS3, 1, zero) + nextNodeIdentifier += 1 + + # Create elements + elementIdxMat = [] + + if useCubicHermiteThroughWall: + eftfactory = eftfactory_tricubichermite(mesh, useCrossDerivatives) + else: + eftfactory = eftfactory_bicubichermitelinear(mesh, useCrossDerivatives) + eftStandard = eftfactory.createEftBasic() + + elementtemplateStandard = mesh.createElementtemplate() + elementtemplateStandard.setElementShapeType(Element.SHAPE_TYPE_CUBE) + elementtemplateStandard.defineField(coordinates, -1, eftStandard) + + elementtemplateX = mesh.createElementtemplate() + elementtemplateX.setElementShapeType(Element.SHAPE_TYPE_CUBE) + + radiansPerElementAround = math.pi * 2.0 / elementsCountAround + elementIdentifier = ostiumFaceStartElement + + for e2 in range(elementsCountAlongSegment): + elementIdxThroughWall = [] + if segmentIdx == 0 and e2 == 0: # pole + for e3 in range(elementsCountThroughWall): + elementIdxAround = [] + for e1 in range(elementsCountAroundHaustrum): + va = e1 + vb = (e1 + 1) + eft1 = eftfactory.createEftShellPoleBottom(va * 100, vb * 100) + elementtemplateX.defineField(coordinates, -1, eft1) + element = mesh.createElement(elementIdentifier, elementtemplateX) + bni1 = e3 + 1 + startNode - 1 + bni2 = idxMat[e2 + 1][e3][e1] + bni3 = idxMat[e2 + 1][e3][e1 + 1] + bni4 = bni1 + 1 + bni5 = idxMat[e2 + 1][e3 + 1][e1] + bni6 = idxMat[e2 + 1][e3 + 1][e1 + 1] + nodeIdentifiers = [bni1, bni2, bni3, bni4, bni5, bni6] + element.setNodesByIdentifier(eft1, nodeIdentifiers) + # set general linear map coefficients + radiansAround = (e1 + 1) * radiansPerElementAround + sectorStartAngle + radiansAroundNext = (e1 + 2) * radiansPerElementAround + sectorStartAngle + scalefactors = [ + -1.0, + math.sin(radiansAround), math.cos(radiansAround), radiansPerElementAround, + math.sin(radiansAroundNext), math.cos(radiansAroundNext), radiansPerElementAround, + math.sin(radiansAround), math.cos(radiansAround), radiansPerElementAround, + math.sin(radiansAroundNext), math.cos(radiansAroundNext), radiansPerElementAround] + element.setScaleFactors(eft1, scalefactors) + elementIdxAround.append(elementIdentifier) + elementIdentifier += 1 + annotationGroups = annotationGroupsAlong[e2] + annotationGroupsThroughWall[e3] + if annotationGroups: + allAnnotationGroups = mergeAnnotationGroups(allAnnotationGroups, annotationGroups) + for annotationGroup in annotationGroups: + meshGroup = annotationGroup.getMeshGroup(mesh) + meshGroup.addElement(element) + elementIdxThroughWall.append(elementIdxAround) + elementIdxMat.append(elementIdxThroughWall) + else: + for e3 in range(elementsCountThroughWall): + elementIdxAround = [] + for e1 in range(len(xAroundAlong[e2]) - 1): + offset = 0 + if endRowIdx - startRowIdx > 1: + if e2 == startRowIdx and e1 > int(0.5 * len(xAroundAlong[e2])): + offset = -1 + elif e2 == endRowIdx - 1 and e1 >= int(0.5 * len(xAroundAlong[e2])): + offset = 1 + + if (startRowIdx <= e2 <= endRowIdx - 1) and 0.5 * len(xAroundAlong[e2]) - 2 < e1 < 0.5 * len( + xAroundAlong[e2]): + continue + else: + eft1 = eftStandard + scaleFactors = [] + elementtemplate1 = elementtemplateStandard + bni111 = idxMat[e2][e3][e1] + bni211 = idxMat[e2][e3][e1 + 1] + bni121 = idxMat[e2 + 1][e3][e1 + offset] + bni221 = idxMat[e2 + 1][e3][e1 + 1 + offset] + bni112 = idxMat[e2][e3 + 1][e1] + bni212 = idxMat[e2][e3 + 1][e1 + 1] + bni122 = idxMat[e2 + 1][e3 + 1][e1 + offset] + bni222 = idxMat[e2 + 1][e3 + 1][e1 + 1 + offset] + nodeIdentifiers = [bni111, bni211, bni121, bni221, + bni112, bni212, bni122, bni222] + + if e2 == startRowIdx - 1 and e1 == elementsCountAroundHalfHaustrum - 2: # LHS bottom + scaleFactors = [-1.0] + eft1 = eftfactory.createEftNoCrossDerivatives() + setEftScaleFactorIds(eft1, [1], []) + remapEftNodeValueLabel(eft1, [4, 8], Node.VALUE_LABEL_D_DS2, + [(Node.VALUE_LABEL_D_DS2, [1])]) + remapEftNodeValueLabel(eft1, [3, 7], Node.VALUE_LABEL_D_DS1, + [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [1])]) + remapEftNodeValueLabel(eft1, [3, 7], Node.VALUE_LABEL_D_DS2, + [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [])]) + elementtemplateX.defineField(coordinates, -1, eft1) + elementtemplate1 = elementtemplateX + + elif e2 == startRowIdx - 1 and e1 == elementsCountAroundHalfHaustrum - 1: # RHS bottom + scaleFactors = [-1.0] + eft1 = eftfactory.createEftNoCrossDerivatives() + setEftScaleFactorIds(eft1, [1], []) + remapEftNodeValueLabel(eft1, [3, 7], Node.VALUE_LABEL_D_DS2, + [(Node.VALUE_LABEL_D_DS2, [1])]) + remapEftNodeValueLabel(eft1, [4, 8], Node.VALUE_LABEL_D_DS2, + [(Node.VALUE_LABEL_D_DS1, [1]), (Node.VALUE_LABEL_D_DS2, [])]) + remapEftNodeValueLabel(eft1, [4, 8], Node.VALUE_LABEL_D_DS1, + [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [])]) + elementtemplateX.defineField(coordinates, -1, eft1) + elementtemplate1 = elementtemplateX + + elif e2 == startRowIdx - 1 and e1 == elementsCountAroundHalfHaustrum: # RHS bottom + 1 + scaleFactors = [-1.0] + eft1 = eftfactory.createEftNoCrossDerivatives() + setEftScaleFactorIds(eft1, [1], []) + remapEftNodeValueLabel(eft1, [3, 7], Node.VALUE_LABEL_D_DS2, + [(Node.VALUE_LABEL_D_DS1, [1]), (Node.VALUE_LABEL_D_DS2, [])]) + elementtemplateX.defineField(coordinates, -1, eft1) + elementtemplate1 = elementtemplateX + + elif e2 == startRowIdx - 1 and e1 == elementsCountAroundHalfHaustrum - 3: # LHS Bottom Left - 1 + eft1 = eftfactory.createEftNoCrossDerivatives() + remapEftNodeValueLabel(eft1, [4, 8], Node.VALUE_LABEL_D_DS2, + [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [])]) + elementtemplateX.defineField(coordinates, -1, eft1) + elementtemplate1 = elementtemplateX + + elif e2 == startRowIdx and e1 == elementsCountAroundHalfHaustrum - 3: # Start row LHS + scaleFactors = [-1.0] + eft1 = eftfactory.createEftNoCrossDerivatives() + setEftScaleFactorIds(eft1, [1], []) + remapEftNodeValueLabel(eft1, [2, 6], Node.VALUE_LABEL_D_DS2, + [(Node.VALUE_LABEL_D_DS1, [1]), (Node.VALUE_LABEL_D_DS2, [])]) + if elementsCountAlongSegment == 6: + remapEftNodeValueLabel(eft1, [4, 8], Node.VALUE_LABEL_D_DS2, + [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [])]) + elementtemplateX.defineField(coordinates, -1, eft1) + elementtemplate1 = elementtemplateX + + elif e2 == startRowIdx and e1 == elementsCountAroundHalfHaustrum: # Start row RHS + eft1 = eftfactory.createEftNoCrossDerivatives() + remapEftNodeValueLabel(eft1, [1, 5], Node.VALUE_LABEL_D_DS2, + [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [])]) + if elementsCountAlongSegment == 6: + scaleFactors = [-1.0] + setEftScaleFactorIds(eft1, [1], []) + remapEftNodeValueLabel(eft1, [3, 7], Node.VALUE_LABEL_D_DS2, + [(Node.VALUE_LABEL_D_DS1, [1]), + (Node.VALUE_LABEL_D_DS2, [])]) + elementtemplateX.defineField(coordinates, -1, eft1) + elementtemplate1 = elementtemplateX + + elif e2 == endRowIdx and e1 == elementsCountAroundHalfHaustrum - 2: # end LHS + scaleFactors = [-1.0] + eft1 = eftfactory.createEftNoCrossDerivatives() + setEftScaleFactorIds(eft1, [1], []) + remapEftNodeValueLabel(eft1, [1, 5], Node.VALUE_LABEL_D_DS2, + [(Node.VALUE_LABEL_D_DS1, [1]), (Node.VALUE_LABEL_D_DS2, [])]) + remapEftNodeValueLabel(eft1, [1, 5], Node.VALUE_LABEL_D_DS1, + [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [])]) + elementtemplateX.defineField(coordinates, -1, eft1) + elementtemplate1 = elementtemplateX + + elif e2 == endRowIdx and e1 == elementsCountAroundHalfHaustrum - 3: # end LHS -1 + scaleFactors = [-1.0] + eft1 = eftfactory.createEftNoCrossDerivatives() + setEftScaleFactorIds(eft1, [1], []) + remapEftNodeValueLabel(eft1, [2, 6], Node.VALUE_LABEL_D_DS2, + [(Node.VALUE_LABEL_D_DS1, [1]), (Node.VALUE_LABEL_D_DS2, [])]) + elementtemplateX.defineField(coordinates, -1, eft1) + elementtemplate1 = elementtemplateX + + elif e2 == endRowIdx - 1 and e1 == elementsCountAroundHalfHaustrum - 3: # side end LHS + eft1 = eftfactory.createEftNoCrossDerivatives() + remapEftNodeValueLabel(eft1, [4, 8], Node.VALUE_LABEL_D_DS2, + [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [])]) + elementtemplateX.defineField(coordinates, -1, eft1) + elementtemplate1 = elementtemplateX + + elif e2 == endRowIdx and e1 == elementsCountAroundHalfHaustrum - 1: # end RHS + scaleFactors = [-1.0] + eft1 = eftfactory.createEftNoCrossDerivatives() + setEftScaleFactorIds(eft1, [1], []) + remapEftNodeValueLabel(eft1, [2, 6], Node.VALUE_LABEL_D_DS2, + [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [])]) + remapEftNodeValueLabel(eft1, [2, 6], Node.VALUE_LABEL_D_DS1, + [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [1])]) + elementtemplateX.defineField(coordinates, -1, eft1) + elementtemplate1 = elementtemplateX + + elif e2 == endRowIdx and e1 == elementsCountAroundHalfHaustrum: # end RHS + 1 + eft1 = eftfactory.createEftNoCrossDerivatives() + remapEftNodeValueLabel(eft1, [1, 5], Node.VALUE_LABEL_D_DS2, + [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [])]) + elementtemplateX.defineField(coordinates, -1, eft1) + elementtemplate1 = elementtemplateX + + elif e2 == endRowIdx - 1 and e1 == elementsCountAroundHalfHaustrum - 1: # end RHS down + scaleFactors = [-1.0] + eft1 = eftfactory.createEftNoCrossDerivatives() + setEftScaleFactorIds(eft1, [1], []) + remapEftNodeValueLabel(eft1, [3, 7], Node.VALUE_LABEL_D_DS2, + [(Node.VALUE_LABEL_D_DS1, [1]), (Node.VALUE_LABEL_D_DS2, [])]) + elementtemplateX.defineField(coordinates, -1, eft1) + elementtemplate1 = elementtemplateX + + element = mesh.createElement(elementIdentifier, elementtemplate1) + element.setNodesByIdentifier(eft1, nodeIdentifiers) + if scaleFactors: + element.setScaleFactors(eft1, scaleFactors) + elementIdxAround.append(elementIdentifier) + elementIdentifier += 1 + annotationGroups = annotationGroupsAlong[e2] + annotationGroupsThroughWall[e3] + if annotationGroups: + allAnnotationGroups = mergeAnnotationGroups(allAnnotationGroups, annotationGroups) + for annotationGroup in annotationGroups: + meshGroup = annotationGroup.getMeshGroup(mesh) + meshGroup.addElement(element) + elementIdxThroughWall.append(elementIdxAround) + elementIdxMat.append(elementIdxThroughWall) + + # Annulus + # Assemble endPoints for annulus + endPoints_x = [[None] * elementsCountAroundOstium for n3 in range(elementsCountThroughWall + 1)] + endPoints_d1 = [[None] * elementsCountAroundOstium for n3 in range(elementsCountThroughWall + 1)] + endPoints_d2 = [[None] * elementsCountAroundOstium for n3 in range(elementsCountThroughWall + 1)] + endNode_Id = [[None] * elementsCountAroundOstium for n3 in range(elementsCountThroughWall + 1)] + endDerivativesMap = [[None] * elementsCountAroundOstium for n3 in range(elementsCountThroughWall + 1)] + endProportions = [] + + for n3 in range(elementsCountThroughWall + 1): + n1 = 0 + for nAround in range(elementsCountAroundOstium): + if nAround == 0: + idx = idxMat[startRowIdx][n3][elementsCountAroundHalfHaustrum - 1] + elif 0 < nAround < (elementsCountAroundOstium * 0.5): + idx = idxMat[startRowIdx + n1][n3][elementsCountAroundHalfHaustrum - 2] + n1 += 1 + elif nAround == int(elementsCountAroundOstium * 0.5): + n1 -= 1 + idx = idxMat[startRowIdx + n1][n3][elementsCountAroundHalfHaustrum - 1] + else: + idx = idxMat[startRowIdx + n1][n3][ + elementsCountAroundHalfHaustrum - 1 + ( + 1 if (n1 == int(elementsCountAroundOstium * 0.5) - 2 or n1 == 0) else 0)] + n1 -= 1 + + endPoints_x[n3][nAround] = xList[idx - ostiumFaceStartNode] + endPoints_d1[n3][nAround] = d1List[idx - ostiumFaceStartNode] + endPoints_d2[n3][nAround] = d2List[idx - ostiumFaceStartNode] + endNode_Id[n3][nAround] = idx + + if n3 == elementsCountThroughWall: # outer layer + endPosition = trackSurfaceOstium.findNearestPosition(endPoints_x[n3][nAround]) + endProportions.append(trackSurfaceOstium.getProportion(endPosition)) + + for n3 in range(elementsCountThroughWall + 1): + for nAround in range(elementsCountAroundOstium): + if nAround == 0: + endDerivativesMap[n3][nAround] = ((-1, 0, 0), (0, 1, 0), None) + elif nAround == 1: + endDerivativesMap[n3][nAround] = ((-1, 1, 0), (-1, -1, 0), None) + elif 1 < nAround < int(elementsCountAroundOstium * 0.5) - 1: + endDerivativesMap[n3][nAround] = ((0, 1, 0), (-1, 0, 0), None) + elif nAround == int(elementsCountAroundOstium * 0.5) - 1: + endDerivativesMap[n3][nAround] = ((1, 1, 0), (-1, 1, 0), None) + elif nAround == int(elementsCountAroundOstium * 0.5): + endDerivativesMap[n3][nAround] = (None, None, None) + elif nAround == int(elementsCountAroundOstium * 0.5) + 1: + endDerivativesMap[n3][nAround] = ((1, -1, 0), (1, 1, 0), None) + elif int(elementsCountAroundOstium * 0.5) + 1 < nAround < elementsCountAroundOstium - 1: + endDerivativesMap[n3][nAround] = ((0, -1, 0), (1, 0, 0), None) + elif nAround == elementsCountAroundOstium - 1: + endDerivativesMap[n3][nAround] = ((-1, -1, 0), (1, -1, 0), None) + + startProportions = [] + for n in range(elementsCountAroundOstium): + startProportions.append(trackSurfaceOstium.getProportion(o1_Positions[n])) + + cecumWallAnnotationGroups = [] + if elementsCountThroughWall == 4: + cecumWallAnnotationGroups = [[mucosaGroup], [submucosaGroup], [circularMuscleGroup], + [longitudinalMuscleGroup]] + + nextNodeIdentifier, nextElementIdentifier = createAnnulusMesh3d( + nodes, mesh, nextNodeIdentifier, elementIdentifier, + o1_x, o1_d1, o1_d2, None, o1_NodeId, None, + endPoints_x, endPoints_d1, endPoints_d2, None, endNode_Id, endDerivativesMap, + elementsCountRadial=1, meshGroups=[cecumMeshGroup], + wallAnnotationGroups=cecumWallAnnotationGroups, + tracksurface=trackSurfaceOstium, + startProportions=startProportions, endProportions=endProportions, + rescaleStartDerivatives=True, rescaleEndDerivatives=True, sampleBlend=0.0, fixMinimumStart=True, + coordinates=coordinates) + + # Delete elements in new haustrum + mesh_destroy_elements_and_nodes_by_identifiers(mesh, deleteElementIdentifier) + + return allAnnotationGroups, nextNodeIdentifier, nextElementIdentifier #, nodeIdDistal, xDistal, d1Distal, \ + # d2Distal, d3Distal + + +class CecumCentralPath: + """ + Generates sampled central path for cecum scaffold. + """ + def __init__(self, region, centralPath, termsAlong=[None]): + """ + :param region: Zinc region to define model in. + :param centralPath: Central path subscaffold from meshtype_1d_path1 + :param termsAlong: Annotation terms along length of central path + """ + # Extract length of each group along stomach from central path + arcLengthOfGroupsAlong = [] + cxGroups = [] + cd1Groups = [] + cd2Groups = [] + cd3Groups = [] + cd12Groups = [] + cd13Groups = [] + + tmpRegion = region.createRegion() + centralPath.generate(tmpRegion) + pathNetworkMesh = centralPath.getConstructionObject() + tmpFieldmodule = tmpRegion.getFieldmodule() + tmpNodes = tmpFieldmodule.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES) + tmpCoordinates = tmpFieldmodule.findFieldByName('coordinates') + networkSegments = pathNetworkMesh.getNetworkSegments() + + cxGroup = [] + cd1Group = [] + cd2Group = [] + cd3Group = [] + cd12Group = [] + cd13Group = [] + + for termName in termsAlong: + tmpGroup = tmpFieldmodule.findFieldByName(termName).castGroup() if termName else None + tmpNodeset = tmpGroup.getFieldNodeGroup(tmpNodes).getNodesetGroup() if tmpGroup else tmpNodes + + if termName == "caecum": + for i in range(2): + cx, cd1, cd2, cd3, cd12, cd13 = get_nodeset_path_ordered_field_parameters( + tmpNodeset, tmpCoordinates, + [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], + networkSegments[i + 1].getNodeIdentifiers(), networkSegments[i + 1].getNodeVersions()) + + cxGroup += cx[(1 if i else 0):] + cd1Group += cd1[(1 if i else 0):] + cd2Group += cd2[(1 if i else 0):] + cd3Group += cd3[(1 if i else 0):] + cd12Group += cd12[(1 if i else 0):] + cd13Group += cd13[(1 if i else 0):] + + if i == 0: + xbranchpt = cx[-1] + d2branchpt = cd2[-1] + arcLengthToBranchPt = 0.0 + for n in range(len(cx) - 1): + arcLengthToBranchPt += interp.getCubicHermiteArcLength(cx[n], cd1[n], cx[n + 1], cd1[n + 1]) + + elif termName == "ileum": + cxGroup, cd1Group, cd2Group, cd3Group, cd12Group, cd13Group = get_nodeset_path_ordered_field_parameters( + tmpNodes, tmpCoordinates, + [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], + networkSegments[0].getNodeIdentifiers(), networkSegments[0].getNodeVersions()) + + 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) + cxGroups.append(cxGroup) + cd1Groups.append(cd1Group) + cd2Groups.append(cd2Group) + cd3Groups.append(cd3Group) + cd12Groups.append(cd12Group) + cd13Groups.append(cd13Group) + + del tmpNodeset + del tmpGroup + + del tmpCoordinates + del tmpNodes + del tmpFieldmodule + del tmpRegion + + self.arcLengthOfGroupsAlong = arcLengthOfGroupsAlong + self.cxGroups = cxGroups + self.cd1Groups = cd1Groups + self.cd2Groups = cd2Groups + self.cd3Groups = cd3Groups + self.cd12Groups = cd12Groups + self.cd13Groups = cd13Groups + self.xBranchPt = xbranchpt + self.d2BranchPt = d2branchpt + self.arcLengthToBranchPt = arcLengthToBranchPt + +class CustomCentralPath: + """ + Generates sampled central path for part of central path. + """ + def __init__(self, cx, cd1, cd2, cd3, cd12, cd13): + self.cxPath = cx + self.cd1Path = cd1 + self.cd2Path = cd2 + self.cd3Path = cd3 + self.cd12Path = cd12 + self.cd13Path = cd13 \ No newline at end of file diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_ostium2.py b/src/scaffoldmaker/meshtypes/meshtype_3d_ostium2.py new file mode 100644 index 00000000..c9c98f16 --- /dev/null +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_ostium2.py @@ -0,0 +1,1112 @@ +""" +Generates a single or double/common ostium, where one or more vessels enters a chamber. +""" + +from __future__ import division + +import copy +import math + +from cmlibs.utils.zinc.field import findOrCreateFieldCoordinates +from cmlibs.zinc.element import Element, Elementbasis +from cmlibs.zinc.field import Field +from cmlibs.zinc.node import Node +from scaffoldmaker.meshtypes.meshtype_1d_path1 import MeshType_1d_path1 +from scaffoldmaker.meshtypes.scaffold_base import Scaffold_base +from scaffoldmaker.scaffoldpackage import ScaffoldPackage +from scaffoldmaker.utils import interpolation as interp +from scaffoldmaker.utils import vector +from scaffoldmaker.utils.annulusmesh import createAnnulusMesh3d +from scaffoldmaker.utils.eftfactory_tricubichermite import eftfactory_tricubichermite +from scaffoldmaker.utils.geometry import createCirclePoints, getCircleProjectionAxes +from scaffoldmaker.utils.meshrefinement import MeshRefinement +from scaffoldmaker.utils.tracksurface import TrackSurface, TrackSurfacePosition, calculate_surface_axes +from scaffoldmaker.utils.zinc_utils import exnode_string_from_nodeset_field_parameters, get_nodeset_path_field_parameters + + + +class MeshType_3d_ostium2(Scaffold_base): + """ + Generates a 3-D single or double/common ostium inlet or outlet. + """ + centralPathDefaultScaffoldPackages = { + 'Default': ScaffoldPackage(MeshType_1d_path1, { + 'scaffoldSettings': { + 'Coordinate dimensions': 3, + 'D2 derivatives': True, + 'D3 derivatives': True, + 'Length': 1.0, + 'Number of elements': 2 + }, + 'meshEdits': exnode_string_from_nodeset_field_parameters( + [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ + (1, [[0.00,0.00,1.00], [0.00,0.00,-0.50], [0.00,0.50,0.00], [0.00,0.00,0.00], [1.00,0.00,0.00], [0.00,0.00,0.00]]), + (2, [[0.00,0.00,0.50], [0.00,0.00,-0.50], [0.00,1.00,0.00], [0.00,0.00,0.00], [1.00,0.00,0.00], [0.00,0.00,0.00]]), + (3, [[0.00,0.00,0.00], [0.00,0.00,-0.50], [0.00,1.00,0.00], [0.00,0.00,0.00], [1.00,0.00,0.00], [0.00,0.00,0.00]])]) + }) + } + + @staticmethod + def getName(): + return '3D Ostium 2' + + @classmethod + def getDefaultOptions(cls, parameterSetName='Default'): + centralPathOption = cls.centralPathDefaultScaffoldPackages['Default'] + options = { + 'Central path': copy.deepcopy(centralPathOption), + # 'Number of vessels': 1, + # 'Number of elements across common': 2, + 'Number of elements around ostium': 8, + 'Number of elements along': 2, #1, + 'Number of elements through wall': 1, + 'Unit scale': 1.0, + 'Outlet': False, + # 'Ostium diameter': 1.0, + # 'Ostium length': 0.4, + 'Ostium wall thickness': 0.08, + 'Ostium wall relative thicknesses': [1.0], + # 'Ostium inter-vessel distance': 0.8, + # 'Ostium inter-vessel height': 0.0, + 'Use linear through ostium wall': False, + # 'Vessel end length factor': 1.0, + # 'Vessel inner diameter': 0.6, + 'Vessel wall thickness': 0.04, + 'Vessel wall relative thicknesses': [1.0], + # 'Vessel angle 1 degrees': 0.0, + # 'Vessel angle 1 spread degrees': 0.0, + # 'Vessel angle 2 degrees': 0.0, + 'Use linear through vessel wall': True, + # 'Use cross derivatives': False, + 'Refine': False, + 'Refine number of elements around': 4, + 'Refine number of elements along': 4, + 'Refine number of elements through wall': 1 + } + + return options + + @staticmethod + def getOrderedOptionNames(): + return [ + 'Central path', + # 'Number of vessels', + # 'Number of elements across common', + 'Number of elements around ostium', + 'Number of elements along', + 'Number of elements through wall', + 'Unit scale', + 'Outlet', + # 'Ostium diameter', + # 'Ostium length', + 'Ostium wall thickness', + 'Ostium wall relative thicknesses', + # 'Ostium inter-vessel distance', + # 'Ostium inter-vessel height', + 'Use linear through ostium wall', + # 'Vessel end length factor', + # 'Vessel inner diameter', + 'Vessel wall thickness', + 'Vessel wall relative thicknesses', + # 'Vessel angle 1 degrees', + # 'Vessel angle 1 spread degrees', + # 'Vessel angle 2 degrees', + 'Use linear through vessel wall', + # 'Use cross derivatives', # not implemented + 'Refine', + 'Refine number of elements around', + 'Refine number of elements along', + 'Refine number of elements through wall' + ] + + @classmethod + def getOptionValidScaffoldTypes(cls, optionName): + if optionName == 'Central path': + return [MeshType_1d_path1] + + @classmethod + def getOptionScaffoldTypeParameterSetNames(cls, optionName, scaffoldType): + if optionName == 'Central path': + return list(cls.centralPathDefaultScaffoldPackages.keys()) + assert scaffoldType in cls.getOptionValidScaffoldTypes(optionName), \ + cls.__name__ + '.getOptionScaffoldTypeParameterSetNames. ' + \ + 'Invalid option \'' + optionName + '\' scaffold type ' + scaffoldType.getName() + return scaffoldType.getParameterSetNames() + + @classmethod + def getOptionScaffoldPackage(cls, optionName, scaffoldType, parameterSetName=None): + """ + :param parameterSetName: Name of valid parameter set for option Scaffold, or None for default. + :return: ScaffoldPackage. + """ + if parameterSetName: + assert parameterSetName in cls.getOptionScaffoldTypeParameterSetNames(optionName, scaffoldType), \ + 'Invalid parameter set ' + str(parameterSetName) + ' for scaffold ' + str(scaffoldType.getName()) + \ + ' in option ' + str(optionName) + ' of scaffold ' + cls.getName() + if optionName == 'Central path': + if not parameterSetName: + parameterSetName = list(cls.centralPathDefaultScaffoldPackages.keys())[0] + return copy.deepcopy(cls.centralPathDefaultScaffoldPackages[parameterSetName]) + assert False, cls.__name__ + '.getOptionScaffoldPackage: Option ' + optionName + ' is not a scaffold' + + @classmethod + def checkOptions(cls, options): + dependentChanges = False + if not options['Central path'].getScaffoldType() in cls.getOptionValidScaffoldTypes('Central path'): + options['Central path'] = cls.getOptionScaffoldPackage('Central path', MeshType_1d_path1) + # vesselsCount = options['Number of vessels'] + # if vesselsCount != 1: + # vesselsCount = options['Number of vessels'] = 1 + for key in [ + # 'Number of elements across common', + 'Number of elements along', + 'Number of elements through wall', + 'Refine number of elements around', + 'Refine number of elements along', + 'Refine number of elements through wall']: + if options[key] < 1: + options[key] = 1 + # if options['Number of elements around ostium'] < 2 * vesselsCount: + # options['Number of elements around ostium'] = 2 * vesselsCount + # dependentChanges = True # because can happen by changing number of vessels + # currently must have even number around ostium if multiple vessels: + # if (vesselsCount > 1) and (options['Number of elements around ostium'] % 2): + # options['Number of elements around ostium'] += 1 + # dependentChanges = True # because can happen by changing number of vessels + for key in [ + 'Unit scale', + # 'Ostium length', + 'Ostium wall thickness', + # 'Ostium inter-vessel distance', + # 'Vessel inner diameter', + 'Vessel wall thickness']: + if options[key] < 0.0: + options[key] = 0.0 + # if options['Ostium diameter'] <= 0.0: + # options['Ostium diameter'] = 0.000001 # avoid division by zero + elementsThroughWall = options['Number of elements through wall'] + ostiumThicknessProportionsCountKey = 'Ostium wall relative thicknesses' + vesselThicknessProportionsCountKey = 'Vessel wall relative thicknesses' + ostiumWallCount = len(options[ostiumThicknessProportionsCountKey]) + vesselWallCount = len(options[vesselThicknessProportionsCountKey]) + if elementsThroughWall == 1: + options[ostiumThicknessProportionsCountKey] = options[vesselThicknessProportionsCountKey] = [1.0] + if ostiumWallCount < elementsThroughWall: + options[ostiumThicknessProportionsCountKey] += \ + [options[ostiumThicknessProportionsCountKey][-1] for i in range(elementsThroughWall - ostiumWallCount)] + dependentChanges = True + elif ostiumWallCount > elementsThroughWall: + options[ostiumThicknessProportionsCountKey] = \ + options[ostiumThicknessProportionsCountKey][:elementsThroughWall] + dependentChanges = True + if vesselWallCount < elementsThroughWall: + options[vesselThicknessProportionsCountKey] += \ + [options[vesselThicknessProportionsCountKey][-1] for i in range(elementsThroughWall - vesselWallCount)] + dependentChanges = True + elif vesselWallCount > elementsThroughWall: + options[vesselThicknessProportionsCountKey] = \ + options[vesselThicknessProportionsCountKey][:elementsThroughWall] + dependentChanges = True + return dependentChanges + + @classmethod + def generateBaseMesh(cls, region, options): + """ + Generate the base tricubic/bicubic Hermite mesh. + :param region: Zinc region to define model in. Must be empty. + :param options: Dict containing options. See getDefaultOptions(). + :return: [] empty list of AnnotationGroup, None + """ + unitScale = options['Unit scale'] + centralPath = options['Central path'] + centralPath = CentralPath(region, centralPath, unitScale) + + # ostiumRadius = 0.5 * unitScale * options['Ostium diameter'] + # interVesselDistance = unitScale * options['Ostium inter-vessel distance'] + ox = centralPath.cxPath[-1] + od2 = centralPath.cd2Path[-1] + od3 = centralPath.cd3Path[-1] + scale = 2.0 * vector.magnitude([od2[c] + od3[c] for c in range(3)]) + + nxOffset = [vector.setMagnitude([-od3[c] - od2[c] for c in range(3)], scale), + vector.setMagnitude([od3[c] - od2[c] for c in range(3)], scale), + vector.setMagnitude([-od3[c] + od2[c] for c in range(3)], scale), + vector.setMagnitude([od3[c] + od2[c] for c in range(3)], scale)] + + nx = [] + for n in range(len(nxOffset)): + nx.append([ox[c] + nxOffset[n][c] for c in range(3)]) + + nd1 = [vector.setMagnitude(od3, 2.0 * scale)] * 4 + nd2 = [vector.setMagnitude(od2, 2.0 * scale)] * 4 + + # fm = region.getFieldmodule() + # fm.beginChange() + # cache = fm.createFieldcache() + # coordinates = findOrCreateFieldCoordinates(fm) + # + # nodes = fm.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES) + # nodeIdentifier = 1000 + # + # nodetemplate = nodes.createNodetemplate() + # nodetemplate.defineField(coordinates) + # nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_VALUE, 1) + # nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D_DS1, 1) + # nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D_DS2, 1) + # nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D_DS3, 1) + # + # for n1 in range(len(nx)): + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, nx[n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, nd1[n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, nd2[n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, [0.0, 0.0, 0.0]) + # nodeIdentifier += 1 + + # # curve track surface: + # zf = 2.0 + # nd1 = [ [ 2.0 * scale, 0.0, zf * scale ], [ 2.0 * scale, 0.0, -zf * scale ], + # [ 2.0 * scale, 0.0, zf * scale ], [ 2.0 * scale, 0.0, -zf * scale ] ] + # nd2 = [ [ 0.0, 2.0 * scale, zf * scale ], [ 0.0, 2.0 * scale, zf * scale ], + # [ 0.0, 2.0 * scale, -zf * scale ], [ 0.0, 2.0 * scale, -zf * scale ] ] + trackSurface = TrackSurface(1, 1, nx, nd1, nd2) + # centrePosition = TrackSurfacePosition(0, 0, 0.5, 0.5) + # axis1 = [1.0, 0.0, 0.0] + generateOstiumMesh(region, options, trackSurface, centralPath) #centrePosition, axis1) + return [], None + + @classmethod + def refineMesh(cls, meshrefinement, options): + """ + :param meshrefinement: MeshRefinement, which knows source and target region. + :param options: Dict containing options. See getDefaultOptions(). + """ + assert isinstance(meshrefinement, MeshRefinement) + refineElementsCountAround = options['Refine number of elements around'] + refineElementsCountAlong = options['Refine number of elements along'] + refineElementsCountThroughWall = options['Refine number of elements through wall'] + meshrefinement.refineAllElementsCubeStandard3d(refineElementsCountAround, refineElementsCountAlong, + refineElementsCountThroughWall) + + +def getOstiumElementsCountsAroundVessels(elementsCountAroundOstium, elementsCountAcross, vesselsCount): + """ + Determine numbers of elements around each vessel to fit numbers of elements around ostium. + :param elementsCountAroundOstium: Number of elements around outside of ostium. + Minimum of 2 + 2 * vesselsCount. Must be even if more than 1 vessels. + :param elementsCountAcross: Number of elements across ostium between multiple vessels. + Unused if vesselsCount is 1. + :param vesselsCount: Number of vessels from 1 to 3. + :return: List of numbers of elements around each vessel to fit numbers around ostium, + number of elements mid side (non-zero only for 3+ vessels). + """ + assert 1 <= vesselsCount <= 3 + assert elementsCountAroundOstium >= 2 * vesselsCount + assert (1 == vesselsCount) or (elementsCountAroundOstium % 2 == 0) + assert elementsCountAcross > 0 + if vesselsCount == 1: + return [elementsCountAroundOstium], 0 + if vesselsCount == 2: + count = elementsCountAroundOstium // 2 + elementsCountAcross + return [count, count], 0 + # vesselsCount == 3: + # Around oinc Total:Vessels 1 Total:Vessels 2 + # 6 1 8: 3-4-3 10: 4-6-4 + # 8 1 10: 4-4-4 12: 5-6-5 + # 10 1 12: 5-4-5 14: 6-6-6 + # 12 2 14: 5-6-5 16: 6-8-6 + # 14 2 16: 6-6-6 18: 7-8-7 + # 16 2 18: 7-6-7 20: 8-8-8 + elementsCountAroundMid = ((elementsCountAroundOstium + 1) // 6) + countInner = 2 * (elementsCountAroundMid + elementsCountAcross) + countOuter = (elementsCountAroundOstium - 2 * elementsCountAroundMid) // 2 + elementsCountAcross + return [countOuter, countInner, countOuter], elementsCountAroundMid + + +def generateOstiumMesh(region, options, trackSurface, centralPath, startNodeIdentifier=1, + startElementIdentifier=1, vesselMeshGroups=None, ostiumMeshGroups=None, + wallAnnotationGroups=None, coordinates=None): + """ + :param vesselMeshGroups: List (over number of vessels) of list of mesh groups to add vessel elements to. + :param ostiumMeshGroups: List of mesh groups to add only row of elements at ostium end to. + :param wallAnnotationGroups: list of annotation groups to add to wall elements. + :return: nextNodeIdentifier, nextElementIdentifier, Ostium points tuple + (ox[n3][n1][c], od1[n3][n1][c], od2[n3][n1][c], od3[n3][n1][c], oNodeId[n3][n1], oPositions). + """ + + vesselsCount = 1 #options['Number of vessels'] + elementsCountAroundOstium = options['Number of elements around ostium'] + # elementsCountAcross = options['Number of elements across common'] + elementsCountAroundVessel = elementsCountAroundOstium + # elementsCountsAroundVessels, elementsCountAroundMid = \ + # getOstiumElementsCountsAroundVessels(elementsCountAroundOstium, elementsCountAcross, vesselsCount) + # elementsCountAroundEnd = (elementsCountAroundOstium - 2 * elementsCountAroundMid) // 2 + # print('\nvesselsCount', vesselsCount, 'elementsCountsAroundOstium', elementsCountAroundOstium, + # 'elementsCountAcross', elementsCountAcross) + # print('--> elementsCountsAroundVessels', elementsCountsAroundVessels, + # 'elementsCountAroundMid', elementsCountAroundMid) + elementsCountAlong = options['Number of elements along'] + elementsCountThroughWall = options['Number of elements through wall'] + unitScale = options['Unit scale'] + + isOutlet = options['Outlet'] + # ostiumRadius = 0.5 * unitScale * options['Ostium diameter'] + # ostiumLength = unitScale * options['Ostium length'] + ostiumWallThickness = unitScale * options['Ostium wall thickness'] + ostiumWallThicknessProportionsUI = copy.deepcopy(options['Ostium wall relative thicknesses']) + # interVesselHeight = unitScale * options['Ostium inter-vessel height'] + # interVesselDistance = unitScale * options['Ostium inter-vessel distance'] if (vesselsCount > 1) else 0.0 + # halfInterVesselDistance = 0.5 * interVesselDistance + useCubicHermiteThroughOstiumWall = not(options['Use linear through ostium wall']) + # vesselEndDerivative = ostiumLength * options['Vessel end length factor'] / elementsCountAlong + # vesselInnerRadius = 0.5 * unitScale * options['Vessel inner diameter'] + vesselWallThickness = unitScale * options['Vessel wall thickness'] + vesselWallThicknessProportionsUI = copy.deepcopy(options['Vessel wall relative thicknesses']) + # vesselOuterRadius = vesselInnerRadius + vesselWallThickness + # vesselAngle1Radians = math.radians(options['Vessel angle 1 degrees']) + # vesselAngle1SpreadRadians = math.radians(options['Vessel angle 1 spread degrees']) + # vesselAngle2Radians = math.radians(options['Vessel angle 2 degrees']) + useCubicHermiteThroughVesselWall = not(options['Use linear through vessel wall']) + useCrossDerivatives = False # options['Use cross derivatives'] # not implemented + + ostiumRadius = vector.magnitude(centralPath.cd2Path[-1]) + # ostiumD3Radius = vector.magnitude(cd3Path[0]) * unitScale + + arcLength = 0.0 + for e in range(len(centralPath.cxPath) - 1): + arcLength += interp.getCubicHermiteArcLength(centralPath.cxPath[e], centralPath.cd1Path[e], + centralPath.cxPath[e + 1], centralPath.cd1Path[e + 1]) + + fm = region.getFieldmodule() + fm.beginChange() + cache = fm.createFieldcache() + if not coordinates: + coordinates = findOrCreateFieldCoordinates(fm) + + nodes = fm.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES) + nodeIdentifier = startNodeIdentifier + + nodetemplate = nodes.createNodetemplate() + nodetemplate.defineField(coordinates) + nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_VALUE, 1) + nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D_DS1, 1) + nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D_DS2, 1) + nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D_DS3, 1) + nodetemplateLinearS3 = nodes.createNodetemplate() + nodetemplateLinearS3.defineField(coordinates) + nodetemplateLinearS3.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_VALUE, 1) + nodetemplateLinearS3.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D_DS1, 1) + nodetemplateLinearS3.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D_DS2, 1) + + mesh = fm.findMeshByDimension(3) + elementIdentifier = startElementIdentifier + + # track points in shape of ostium + # get directions in plane of surface at centre: + centrePosition = trackSurface.findNearestPosition(centralPath.cxPath[-1]) + cx, cd1, cd2 = trackSurface.evaluateCoordinates(centrePosition, True) + trackDirection1, trackDirection2, centreNormal = calculate_surface_axes(cd1, cd2, cd1) + # trackDirection2reverse = [-d for d in trackDirection2] + + halfCircumference = math.pi * ostiumRadius + circumference = 2.0 * halfCircumference + distance = 0.0 + # elementLengthAroundOstiumMid = 0.0 + # vesselsSpanAll = interVesselDistance * (vesselsCount - 1) + # vesselsSpanMid = interVesselDistance * (vesselsCount - 2) + + elementLengthAroundOstiumEnd = circumference / elementsCountAroundOstium + + # if vesselsCount == 1: + # elementLengthAroundOstiumEnd = circumference / elementsCountAroundOstium + # vesselOstiumPositions = [centrePosition] + # ocx = [cx] + # ocd1 = [trackDirection1] + # ocd2 = [trackDirection2] + # ocd3 = [centreNormal] + + # else: + # elementLengthAroundOstiumEnd = (circumference + 2.0 * interVesselDistance) / \ + # (elementsCountAroundOstium - 2 * elementsCountAroundMid) + # if elementsCountAroundMid > 0: + # elementLengthAroundOstiumMid = interVesselDistance * (vesselsCount - 2) / elementsCountAroundMid + # vesselOstiumPositions = [] + # ocx = [] + # ocd1 = [] + # ocd2 = [] + # ocd3 = [] + # for v in range(vesselsCount): + # vesselOstiumPositions.append(trackSurface.trackVector(centrePosition, trackDirection1, + # (v / (vesselsCount - 1) - 0.5) * vesselsSpanAll)) + # x, d1, d2 = trackSurface.evaluateCoordinates(vesselOstiumPositions[-1], -1) + # d1, d2, d3 = calculate_surface_axes(d1, d2, trackDirection1) + # ocx .append(x) + # ocd1.append(d1) + # ocd2.append(d2) + # ocd3.append(d3) + + # coordinates around ostium + ox = [[] for n3 in range(elementsCountThroughWall + 1)] + od1 = [[] for n3 in range(elementsCountThroughWall + 1)] + od2 = [[] for n3 in range(elementsCountThroughWall + 1)] + od3 = [[] for n3 in range(elementsCountThroughWall + 1)] + oPositions = [] + ostiumWallThicknessProportions = [ostiumWallThicknessProportion / sum(ostiumWallThicknessProportionsUI) + for ostiumWallThicknessProportion in ostiumWallThicknessProportionsUI] + vesselWallThicknessProportions = [vesselWallThicknessProportion / sum(vesselWallThicknessProportionsUI) + for vesselWallThicknessProportion in vesselWallThicknessProportionsUI] + + ostiumWallThicknessProportions.append(ostiumWallThicknessProportions[-1]) + vesselWallThicknessProportions.append(vesselWallThicknessProportions[-1]) + + xOstiumInner, d1OstiumInner = createCirclePoints(centralPath.cxPath[-1], + vector.setMagnitude(centralPath.cd2Path[-1], ostiumRadius), + vector.setMagnitude(centralPath.cd3Path[-1], ostiumRadius), + elementsCountAroundOstium) + + for n1 in range(elementsCountAroundOstium): + elementLength = elementLengthAroundOstiumEnd + # if distance <= (vesselsSpanMid + halfInterVesselDistance): + # print('1') + # position = trackSurface.trackVector(centrePosition, trackDirection1, 0.5 * vesselsSpanMid - distance) + # sideDirection = trackDirection2reverse + # if n1 < elementsCountAroundMid: + # elementLength = elementLengthAroundOstiumMid + # elif distance < (vesselsSpanMid + halfInterVesselDistance + halfCircumference): + # position = vesselOstiumPositions[0] + # angleRadians = (distance - (vesselsSpanMid + halfInterVesselDistance)) / ostiumRadius + # w1 = -math.sin(angleRadians) + # w2 = -math.cos(angleRadians) + # print('2', math.degrees(w1), math.degrees(w2)) + # sideDirection = [(w1 * trackDirection1[c] + w2 * trackDirection2[c]) for c in range(3)] + # elif distance < (2.0 * vesselsSpanMid + halfInterVesselDistance + halfCircumference + interVesselDistance): + # position = trackSurface.trackVector(centrePosition, trackDirection1, distance - + # (1.5 * vesselsSpanMid + interVesselDistance + halfCircumference)) + # sideDirection = trackDirection2 + # if 0 <= (n1 - elementsCountAroundEnd - elementsCountAroundMid) < elementsCountAroundMid: + # elementLength = elementLengthAroundOstiumMid + # print('3') + # elif distance < (2.0 * vesselsSpanMid + halfInterVesselDistance + circumference + interVesselDistance): + # position = vesselOstiumPositions[-1] + # angleRadians = (distance - (2.0 * vesselsSpanMid + halfInterVesselDistance + halfCircumference + + # interVesselDistance)) / ostiumRadius + # w1 = math.sin(angleRadians) + # w2 = math.cos(angleRadians) + # sideDirection = [(w1 * trackDirection1[c] + w2 * trackDirection2[c]) for c in range(3)] + # print('4', math.degrees(w1), math.degrees(w2)) + # else: + # position = \ + # trackSurface.trackVector(centrePosition, trackDirection1, + # 0.5 * vesselsSpanMid + (circumference + 2.0 * + # (vesselsSpanMid + interVesselDistance)) - distance) + # sideDirection = trackDirection2reverse + # print('5') + + position = trackSurface.findNearestPosition(xOstiumInner[n1]) + # position = trackSurface.trackVector(position, sideDirection, ostiumRadius) + oPositions.append(position) + px, d1, d2 = trackSurface.evaluateCoordinates(position, True) + angleRadians = 2.0 * math.pi / elementsCountAroundOstium * n1 + + cosTheta1 = vector.dotproduct(d1, centralPath.cd3Path[-1])/\ + (vector.magnitude(d1) * vector.magnitude(centralPath.cd3Path[-1])) + cosTheta2 = vector.dotproduct(d2, centralPath.cd2Path[-1]) / \ + (vector.magnitude(d2) * vector.magnitude(centralPath.cd2Path[-1])) + signed1 = cosTheta1 / abs(cosTheta1) + signed2 = cosTheta2 / abs(cosTheta2) + + w1 = signed1 * math.sin(angleRadians) + w2 = signed2 * math.cos(angleRadians) + sideDirection = [(w1 * trackDirection1[c] + w2 * trackDirection2[c]) for c in range(3)] + pd2, pd1, pd3 = calculate_surface_axes(d1, d2, sideDirection) + + # get outer coordinates + opx = px + opd1 = vector.setMagnitude([-d for d in pd1], elementLengthAroundOstiumEnd) + opd2 = vector.setMagnitude(pd2, vector.magnitude(centralPath.cd2Path[0])) # smoothed later + opd3 = vector.setMagnitude(pd3, ostiumWallThickness) + + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, opx) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, opd1) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, opd2) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, opd3) + # print(nodeIdentifier) + # nodeIdentifier += 1 + + ostiumTotalXi3 = 0.0 + vesselTotalXi3 = 0.0 + ostiumWallThicknessXi3List = [0.0] + vesselWallThicknessXi3List = [0.0] + + for n3 in range(elementsCountThroughWall): + ostiumTotalXi3 += ostiumWallThicknessProportions[n3] + vesselTotalXi3 += vesselWallThicknessProportions[n3] + ostiumWallThicknessXi3List.append(ostiumTotalXi3) + vesselWallThicknessXi3List.append(vesselTotalXi3) + # set coordinates through wall (use copy to avoid references to same list later) + for n3 in range(elementsCountThroughWall + 1): + xi3 = 1 - ostiumWallThicknessXi3List[n3] + ox[n3].append([(opx[c] - opd3[c] * xi3) for c in range(3)]) + od1[n3].append(copy.copy(opd1)) + od2[n3].append(copy.copy(opd2)) + if useCubicHermiteThroughOstiumWall: + od3[n3].append([opd3[c] * ostiumWallThicknessProportions[n3] for c in range(3)]) + distance += elementLength + for n3 in range(elementsCountThroughWall + 1): + od1[n3] = interp.smoothCubicHermiteDerivativesLoop(ox[n3], od1[n3], fixAllDirections=True) + + # for n3 in range(len(ox)): + # for n1 in range(len(ox[n3])): + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, ox[n3][n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, od1[n3][n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, od2[n3][n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, od3[n3][n1]) + # nodeIdentifier += 1 + + if (vesselWallThickness > 0.0) and (ostiumWallThickness > 0.0): + # commonOstiumWallThickness = 2.0 / (1.0 / vesselWallThickness + 1.0 / ostiumWallThickness) + commonOstiumWallThicknessProportions = [] + commonOstiumWallTotalXi3 = 0.0 + commonOstiumWallThicknessXi3List = [0.0] + for c in range(elementsCountThroughWall + 1): + commonOstiumWallThicknessProportions.append( + (vesselWallThicknessProportions[c] + ostiumWallThicknessProportions[c]) * 0.5) + for n3 in range(elementsCountThroughWall): + commonOstiumWallTotalXi3 += commonOstiumWallThicknessProportions[n3] + commonOstiumWallThicknessXi3List.append(commonOstiumWallTotalXi3) + else: + commonOstiumWallThickness = vesselWallThickness + commonOstiumWallThicknessProportions = vesselWallThicknessProportions + commonOstiumWallThicknessXi3List = vesselWallThicknessXi3List + + # xx = [] + # xd1 = [] + # xd2 = [] + # xd3 = [] + # # coordinates across common ostium, between vessels + # nodesCountFreeEnd = elementsCountsAroundVessels[0] + 1 - elementsCountAcross + # oinc = 0 if (vesselsCount <= 2) else elementsCountAroundMid // (vesselsCount - 2) + # for iv in range(vesselsCount - 1): + # xx .append([None for n3 in range(elementsCountThroughWall + 1)]) + # xd1.append([None for n3 in range(elementsCountThroughWall + 1)]) + # xd2.append([None for n3 in range(elementsCountThroughWall + 1)]) + # xd3.append([None for n3 in range(elementsCountThroughWall + 1)]) + # oa = elementsCountAroundMid - iv * oinc + # ob = elementsCountAroundMid + nodesCountFreeEnd - 1 + iv * oinc + # nx = [ox[elementsCountThroughWall][oa], ox[elementsCountThroughWall][ob]] + # nd1 = [[-d for d in od1[elementsCountThroughWall][oa]], od1[elementsCountThroughWall][ob]] + # nd2 = [[-d for d in od2[elementsCountThroughWall][oa]], od2[elementsCountThroughWall][ob]] + # + # if elementsCountAcross > 1: + # # add centre point, displaced by interVesselHeight + # if vesselsCount == 2: + # position = centrePosition + # else: + # position = trackSurface.trackVector(centrePosition, trackDirection1, + # (iv / (vesselsCount - 2) - 0.5) * vesselsSpanMid) + # mx, d1, d2 = trackSurface.evaluateCoordinates(position, derivatives=True) + # md1, md2, md3 = calculate_surface_axes(d1, d2, trackDirection1) + # nx .insert(1, [(mx[c] + interVesselHeight * md3[c]) for c in range(3)]) + # nd1.insert(1, vector.setMagnitude(md1, elementLengthAroundOstiumMid if (0 < iv < (vesselsCount - 2)) else + # elementLengthAroundOstiumEnd)) + # nd2.insert(1, vector.setMagnitude(md2, ostiumRadius)) + # nd2 = interp.smoothCubicHermiteDerivativesLine(nx, nd2, fixAllDirections=True) + # px, pd2, pe, pxi = interp.sampleCubicHermiteCurves(nx, nd2, elementsCountAcross)[0:4] + # pd1 = interp.interpolateSampleLinear(nd1, pe, pxi) + # pd3 = [vector.setMagnitude(vector.crossproduct3(pd1[n2], pd2[n2]), commonOstiumWallThickness) + # for n2 in range(elementsCountAcross + 1)] + # for n3 in range(elementsCountThroughWall + 1): + # xi3 = 1 - commonOstiumWallThicknessXi3List[n3] + # lx = [([(px[n2][c] - xi3 * pd3[n2][c]) for c in range(3)]) for n2 in range(elementsCountAcross + 1)] + # ld2 = interp.smoothCubicHermiteDerivativesLine(lx, pd2, fixAllDirections=True) + # xx[iv][n3] = lx[1:elementsCountAcross] + # xd1[iv][n3] = copy.deepcopy(pd1[1:elementsCountAcross]) # to be smoothed later + # xd2[iv][n3] = ld2[1:elementsCountAcross] + # # set smoothed d2 on ostium circumference + # od2[n3][oa] = [-d for d in ld2[0]] + # od2[n3][ob] = ld2[-1] + # if useCubicHermiteThroughOstiumWall: + # pd3Element = [vector.setMagnitude(vector.crossproduct3(pd1[n2], pd2[n2]), + # commonOstiumWallThickness * commonOstiumWallThicknessProportions[n3]) + # for n2 in range(elementsCountAcross + 1)] + # xd3[iv][n3] = copy.deepcopy(pd3Element[1:elementsCountAcross]) + # + # get positions of vessel end centres and rings + # vcx = [] + # vcd1 = [] + # vcd2 = [] + # vcd3 = [] + vox = [] + vod1 = [] + vod2 = [] + vod3 = [] + for v in range(vesselsCount): + # elementsCountAroundVessel = elementsCountsAroundVessels[v] + radiansPerElementVessel = 2.0 * math.pi / elementsCountAroundVessel + # useVesselAngleRadians = vesselAngle1Radians + # if vesselsCount > 1: + # useVesselAngleRadians += (v / (vesselsCount - 1) - 0.5) * vesselAngle1SpreadRadians + # vx, vd1, vd2, vd3 = getCircleProjectionAxes(ocx[v], ocd1[v], ocd2[v], ocd3[v], ostiumLength, + # useVesselAngleRadians, vesselAngle2Radians) + # + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, vx) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, vd1) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, vd2) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, vd3) + # nodeIdentifier += 1 + + # vx, vd1 = createCirclePoints(cxPath[-1], cd2Path[-1], cd3Path[-1], elementsCountsAroundVessels) + # vd1 = [vesselOuterRadius * d for d in vd1] + # vd2 = [-vesselOuterRadius * d for d in vd2] + # vd3 = [-vesselEndDerivative * d for d in vd3] + # vcx.append(vx) + # vcd1.append(vd1) + # vcd2.append(vd2) + # vcd3.append(vd3) + vox.append([]) + vod1.append([]) + vod2.append([]) + vod3.append([]) + for n3 in range(elementsCountThroughWall + 1): + radius = vector.magnitude(centralPath.cd2Path[0]) + vesselWallThicknessXi3List[n3] * vesselWallThickness + vAxis1 = vector.setMagnitude(centralPath.cd2Path[0], radius) + vAxis2 = vector.setMagnitude(centralPath.cd3Path[0], radius) + # print(centralPath.cd2Path[0], centralPath.cd3Path[0]) + # if vesselsCount == 1: + startRadians = 0.0 # 0.5 * math.pi + # else: + # startRadians = 0.5 * radiansPerElementVessel * elementsCountAcross + # if v == (vesselsCount - 1): + # startRadians -= math.pi + px, pd1 = createCirclePoints(centralPath.cxPath[0], vAxis1, vAxis2, elementsCountAroundVessel, startRadians) + vox[-1].append(px) + vod1[-1].append(pd1) + vesselEndDerivative = vector.setMagnitude(centralPath.cd1Path[0], arcLength/elementsCountAlong) + vod2[-1].append([vesselEndDerivative] * elementsCountAroundVessel) # need to scale with bending? + if useCubicHermiteThroughVesselWall: + vod3[-1].append([vector.setMagnitude(vector.crossproduct3(d1, vesselEndDerivative), #cd1Path[-1]), + vesselWallThickness * vesselWallThicknessProportions[n3]) + for d1 in pd1]) + + # for v in range(len(vox)): + # for n3 in range(len(vox[v])): + # for n1 in range(len(vox[v][n3])): + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, vox[v][n3][n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, vod1[v][n3][n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, vod2[v][n3][n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, vod3[v][n3][n1]) + # nodeIdentifier += 1 + + # calculate common ostium vessel node derivatives map + mvPointsx = [None] * vesselsCount + mvPointsd1 = [None] * vesselsCount + mvPointsd2 = [None] * vesselsCount + mvPointsd3 = [None] * vesselsCount + mvDerivativesMap = [None] * vesselsCount + mvMeanCount = [None] * vesselsCount # stores 1 if first reference to common point between vessels, 2 if second. Otherwise 0. + for v in range(vesselsCount): + if vesselsCount == 1: + mvPointsx[v], mvPointsd1[v], mvPointsd2[v], mvPointsd3[v], mvDerivativesMap[v] = \ + ox, od1, od2, od3 if useCubicHermiteThroughOstiumWall else None, None + mvMeanCount[v] = [0] * elementsCountAroundVessel # elementsCountsAroundVessels[v] + # else: + # iv = max(0, v - 1) + # oa = elementsCountAroundMid - iv * oinc + # ob = elementsCountAroundMid + nodesCountFreeEnd - 1 + iv * oinc + # mvPointsx[v] = [] + # mvPointsd1[v] = [] + # mvPointsd2[v] = [] + # mvPointsd3[v] = [] if useCubicHermiteThroughOstiumWall else None + # mvDerivativesMap[v] = [] + # for n3 in range(elementsCountThroughWall + 1): + # mvPointsd1[v].append([]) + # mvPointsd2[v].append([]) + # mvPointsx[v].append([]) + # if useCubicHermiteThroughOstiumWall: + # mvPointsd3[v].append([]) + # mvDerivativesMap[v].append([]) + # if v == 0: # first end vessel + # mvPointsd1[v][n3] += od1[n3][oa:ob + 1] + # mvPointsd2[v][n3] += od2[n3][oa:ob + 1] + # mvPointsx[v][n3] += ox[n3][oa:ob + 1] + # if useCubicHermiteThroughOstiumWall: + # mvPointsd3[v][n3] += od3[n3][oa:ob + 1] + # mvDerivativesMap[v][n3].append(((0, 1, 0), (-1, 1, 0), None, (1, 0, 0))) + # for i in range(nodesCountFreeEnd - 2): + # mvDerivativesMap[v][n3].append((None, None, None)) + # mvDerivativesMap[v][n3].append(((1, 0, 0), (1, 1, 0), None, (0, -1, 0))) + # mvPointsx[v][n3] += reversed(xx[iv][n3]) + # mvPointsd1[v][n3] += reversed(xd1[iv][n3]) + # mvPointsd2[v][n3] += reversed(xd2[iv][n3]) + # if useCubicHermiteThroughOstiumWall: + # mvPointsd3[v][n3] += reversed(xd3[iv][n3]) + # for i in range(elementsCountAcross - 1): + # mvDerivativesMap[v][n3].append(((0, -1, 0), (1, 0, 0), None)) + # if n3 == 0: + # mvMeanCount[v] = [1] + [0] * (nodesCountFreeEnd - 2) + [1] * elementsCountAcross + # elif v < (vesselsCount - 1): # middle vessels + # # left: + # mvPointsx[v][n3] += ox[n3][oa - oinc:oa + 1] + # mvPointsd1[v][n3] += od1[n3][oa - oinc:oa + 1] + # mvPointsd2[v][n3] += od2[n3][oa - oinc:oa + 1] + # if useCubicHermiteThroughOstiumWall: + # mvPointsd3[v][n3] += od3[n3][oa - oinc:oa + 1] + # mvDerivativesMap[v][n3].append(((0, 1, 0), (-1, 1, 0), None, (1, 0, 0))) + # for i in range(oinc - 1): + # mvDerivativesMap[v][n3].append((None, None, None)) + # mvDerivativesMap[v][n3].append(((1, 0, 0), (1, 1, 0), None, (0, -1, 0))) + # # across + # mvPointsx[v][n3] += xx[iv][n3] + # mvPointsd1[v][n3] += xd1[iv][n3] + # mvPointsd2[v][n3] += xd2[iv][n3] + # if useCubicHermiteThroughOstiumWall: + # mvPointsd3[v][n3] += xd3[iv][n3] + # for i in range(elementsCountAcross - 1): + # mvDerivativesMap[v][n3].append(((0, 1, 0), (-1, 0, 0), None)) + # # right + # mvPointsx[v][n3] += ox[n3][ob:ob + oinc + 1] + # mvPointsd1[v][n3] += od1[n3][ob:ob + oinc + 1] + # mvPointsd2[v][n3] += od2[n3][ob:ob + oinc + 1] + # if useCubicHermiteThroughOstiumWall: + # mvPointsd3[v][n3] += od3[n3][ob:ob + oinc + 1] + # mvDerivativesMap[v][n3].append(((0, 1, 0), (-1, 1, 0), None, (1, 0, 0))) + # for i in range(oinc - 1): + # mvDerivativesMap[v][n3].append((None, None, None)) + # mvDerivativesMap[v][n3].append(((1, 0, 0), (1, 1, 0), None, (0, -1, 0))) + # # across reverse + # mvPointsx[v][n3] += reversed(xx[iv + 1][n3]) + # mvPointsd1[v][n3] += reversed(xd1[iv + 1][n3]) + # mvPointsd2[v][n3] += reversed(xd2[iv + 1][n3]) + # if useCubicHermiteThroughOstiumWall: + # mvPointsd3[v][n3] += reversed(xd3[iv + 1][n3]) + # for i in range(elementsCountAcross - 1): + # mvDerivativesMap[v][n3].append(((0, -1, 0), (1, 0, 0), None)) + # if n3 == 0: + # mvMeanCount[v] = [1] + [0] * (oinc - 1) + [2] * (elementsCountAcross + 1) + [0] * (oinc - 1) + \ + # [1] * elementsCountAcross + # else: # last end vessel + # mvPointsx[v][n3] += ox[n3][ob:] + [ox[n3][0]] + # mvPointsd1[v][n3] += od1[n3][ob:] + [od1[n3][0]] + # mvPointsd2[v][n3] += od2[n3][ob:] + [od2[n3][0]] + # if useCubicHermiteThroughOstiumWall: + # mvPointsd3[v][n3] += od3[n3][ob:] + [od3[n3][0]] + # mvDerivativesMap[v][n3].append(((0, 1, 0), (-1, 1, 0), None, (1, 0, 0))) + # for i in range(nodesCountFreeEnd - 2): + # mvDerivativesMap[v][n3].append((None, None, None)) + # mvDerivativesMap[v][n3].append(((1, 0, 0), (1, 1, 0), None, (0, -1, 0))) + # mvPointsx[v][n3] += xx[iv][n3] + # mvPointsd1[v][n3] += xd1[iv][n3] + # mvPointsd2[v][n3] += xd2[iv][n3] + # if useCubicHermiteThroughOstiumWall: + # mvPointsd3[v][n3] += xd3[iv][n3] + # for i in range(elementsCountAcross - 1): + # mvDerivativesMap[v][n3].append(((0, 1, 0), (-1, 0, 0), None)) + # if n3 == 0: + # mvMeanCount[v] = [2] + [0] * (nodesCountFreeEnd - 2) + [2] * elementsCountAcross + + # calculate derivative 2 around free sides of inlets to fit vessel derivatives + for v in range(vesselsCount): + for n3 in [elementsCountThroughWall]: # was range(2), now using curvature for inside: + # print('v',v,'n3',n3,'elementsAround',elementsCountsAroundVessels[v]) + # print('mvPointsx [v][n3]', mvPointsx [v][n3]) + # print('mvPointsd1[v][n3]', mvPointsd1[v][n3]) + # print('mvPointsd2[v][n3]', mvPointsd2[v][n3]) + # print('mvDerivativesMap[v][n3]', mvDerivativesMap[v][n3]) + for n1 in range(elementsCountAroundVessel): #elementsCountsAroundVessels[v]): + d2Map = mvDerivativesMap[v][n3][n1][1] if (mvDerivativesMap[v] and mvDerivativesMap[v][n3][n1]) \ + else None + sf1 = d2Map[0] if d2Map else 0.0 + sf2 = d2Map[1] if d2Map else 1.0 + nx = [vox[v][n3][n1], mvPointsx[v][n3][n1]] + nd2 = [[d * elementsCountAlong for d in vod2[v][n3][n1]], + [(sf1 * mvPointsd1[v][n3][n1][c] + sf2 * mvPointsd2[v][n3][n1][c]) for c in range(3)]] + nd2f = interp.smoothCubicHermiteDerivativesLine(nx, nd2, fixStartDirection=True, fixEndDirection=True) + ndf = [d / elementsCountAlong for d in nd2f[1]] + # assign components to set original values: + if sf1 == 0: + for c in range(3): + mvPointsd2[v][n3][n1][c] = sf2 * ndf[c] + elif sf2 == 0: + if mvMeanCount[v][n1] < 2: + for c in range(3): + mvPointsd1[v][n3][n1][c] = sf1 * ndf[c] + else: + # take mean of values from this and last vessel + for c in range(3): + mvPointsd1[v][n3][n1][c] = 0.5 * (mvPointsd1[v][n3][n1][c] + sf1 * ndf[c]) + else: + # print('v', v, 'n3', n3, 'n1', n1, ':', vector.magnitude(ndf), 'vs.', vector.magnitude(nd2[1]), + # 'd2Map', d2Map) + pass + + # calculate inner d2 derivatives around ostium from outer using track surface curvature + factor = 1.0 + for n1 in range(elementsCountAroundOstium): + trackDirection = vector.normalise(od2[elementsCountThroughWall][n1]) + trackDistance = factor * vector.magnitude(od2[elementsCountThroughWall][n1]) + tx = [None, ox[elementsCountThroughWall][n1], None] + td1 = [None, vector.setMagnitude(od2[elementsCountThroughWall][n1], trackDistance), None] + td2 = [None, vector.setMagnitude(od1[elementsCountThroughWall][n1], -trackDistance), None] + positionBackward = trackSurface.trackVector(oPositions[n1], trackDirection, -trackDistance) + tx[0], d1, d2 = trackSurface.evaluateCoordinates(positionBackward, derivatives=True) + sd1, sd2, sd3 = calculate_surface_axes(d1, d2, trackDirection) + td1[0] = vector.setMagnitude(sd1, trackDistance) + td2[0] = vector.setMagnitude(sd2, trackDistance) + positionForward = trackSurface.trackVector(oPositions[n1], trackDirection, trackDistance) + tx[2], d1, d2 = trackSurface.evaluateCoordinates(positionForward, derivatives=True) + sd1, sd2, sd3 = calculate_surface_axes(d1, d2, trackDirection) + td1[2] = vector.setMagnitude(sd1, trackDistance) + td2[2] = vector.setMagnitude(sd2, trackDistance) + for n3 in range(elementsCountThroughWall): + xi3 = 1 - ostiumWallThicknessXi3List[n3] + newd2 = interp.projectHermiteCurvesThroughWall(tx, td1, td2, 1, -ostiumWallThickness * xi3)[1] + # assign components to set in all lists: + for c in range(3): + od2[n3][n1][c] = newd2[c] / factor + # for n in [ 0, 1, 2 ]: + # node = nodes.createNode(nodeIdentifier, nodetemplateLinearS3) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, tx [n]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, td1[n]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, td2[n]) + # nodeIdentifier += 1 + + if isOutlet: + # reverse directions of d1 and d2 on vessels and ostium base + for c in range(3): + for n3 in range(elementsCountThroughWall + 1): + for n1 in range(elementsCountAroundOstium): + od1[n3][n1][c] = -od1[n3][n1][c] + od2[n3][n1][c] = -od2[n3][n1][c] + # for iv in range(vesselsCount - 1): + # for n1 in range(elementsCountAcross - 1): + # xd1[iv][n3][n1][c] = -xd1[iv][n3][n1][c] + # xd2[iv][n3][n1][c] = -xd2[iv][n3][n1][c] + for v in range(vesselsCount): + vod2[0][n3][0][c] = -vod2[0][n3][0][c] + for n1 in range(elementsCountAroundVessel): #elementsCountsAroundVessels[v]): + vod1[v][n3][n1][c] = -vod1[v][n3][n1][c] + + # # d2 is referenced all around, so only change once per vessel - NA + # for v in range(vesselsCount): + # vod2[v][0][0][c] = -vod2[v][0][0][c] + # vod2[v][1][0][c] = -vod2[v][1][0][c] + + ############## + # Create nodes + ############## + + oNodeId = [] + for n3 in range(elementsCountThroughWall + 1): + oNodeId.append([]) + for n1 in range(elementsCountAroundOstium): + node = nodes.createNode(nodeIdentifier, + nodetemplate if useCubicHermiteThroughOstiumWall else nodetemplateLinearS3) + cache.setNode(node) + coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, ox[n3][n1]) + coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, od1[n3][n1]) + coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, od2[n3][n1]) + if useCubicHermiteThroughOstiumWall: + coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, od3[n3][n1]) + oNodeId[n3].append(nodeIdentifier) + # print(nodeIdentifier) + nodeIdentifier += 1 + + # xNodeId = [] + # for iv in range(vesselsCount - 1): + # xNodeId.append([]) + # for n3 in range(elementsCountThroughWall + 1): + # xNodeId[iv].append([]) + # for n2 in range(elementsCountAcross - 1): + # node = nodes.createNode(nodeIdentifier, + # nodetemplate if useCubicHermiteThroughOstiumWall else nodetemplateLinearS3) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xx[iv][n3][n2]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, xd1[iv][n3][n2]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, xd2[iv][n3][n2]) + # if useCubicHermiteThroughOstiumWall: + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, xd3[iv][n3][n2]) + # xNodeId[iv][n3].append(nodeIdentifier) + # nodeIdentifier += 1 + + # for v in range(vesselsCount): + # node = nodes.createNode(nodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, vcx [v]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, vcd1[v]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, vcd2[v]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, vcd3[v]) + # nodeIdentifier += 1 + # for v in range(vesselsCount): + # for n3 in range(elementsCountThroughWall + 1): + # for n1 in range(elementsCountAroundVessel): + # node = nodes.createNode(nodeIdentifier, + # nodetemplate if useCubicHermiteThroughVesselWall else nodetemplateLinearS3) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, vox [v][n3][n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, vod1[v][n3][n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, vod2[v][n3][n1]) + # if useCubicHermiteThroughVesselWall: + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, vod3[v][n3][n1]) + # #vNodeId.append(nodeIdentifier) + # nodeIdentifier += 1 + + # get identifiers of nodes around each vessel at ostium end + mvNodeId = [None] * vesselsCount + for v in range(vesselsCount): + if vesselsCount == 1: + mvNodeId[v] = oNodeId + # else: + # iv = max(0, v - 1) + # mvNodeId[v] = [None for n3 in range(elementsCountThroughWall + 1)] + # oa = elementsCountAroundMid - iv * oinc + # ob = elementsCountAroundMid + nodesCountFreeEnd - 1 + iv * oinc + # for n3 in range(elementsCountThroughWall + 1): + # if v == 0: # first end vessel + # mvNodeId[v][n3] = oNodeId[n3][oa:ob + 1] + \ + # (list(reversed(xNodeId[iv][n3])) if (v == 0) else xNodeId[iv][n3]) + # elif v == (vesselsCount - 1): # last end vessels + # mvNodeId[v][n3] = oNodeId[n3][ob:] + [oNodeId[n3][0]] + \ + # (list(reversed(xNodeId[iv][n3])) if (v == 0) else xNodeId[iv][n3]) + # else: # mid vessels + # mvNodeId[v][n3] = oNodeId[n3][oa - oinc:oa + 1] + xNodeId[iv][n3] + \ + # oNodeId[n3][ob:ob + oinc + 1] + list(reversed(xNodeId[iv + 1][n3])) + + ################# + # Create elements + ################# + tricubichermite = eftfactory_tricubichermite(mesh, useCrossDerivatives) + tricubicHermiteBasis = fm.createElementbasis(3, Elementbasis.FUNCTION_TYPE_CUBIC_HERMITE) + + eft = tricubichermite.createEftBasic() + elementtemplate = mesh.createElementtemplate() + elementtemplate.setElementShapeType(Element.SHAPE_TYPE_CUBE) + elementtemplate.defineField(coordinates, -1, eft) + + elementtemplateX = mesh.createElementtemplate() + elementtemplateX.setElementShapeType(Element.SHAPE_TYPE_CUBE) + + for v in range(vesselsCount): + if vesselMeshGroups or ostiumMeshGroups: + rowMeshGroups = [] + for i in range(elementsCountAlong): + rowMeshGroups.append(copy.copy(vesselMeshGroups[v]) if vesselMeshGroups else []) + else: + rowMeshGroups = None + if isOutlet: + startPointsx, startPointsd1, startPointsd2, startPointsd3, startNodeId, startDerivativesMap = \ + mvPointsx[v], mvPointsd1[v], mvPointsd2[v], mvPointsd3[v], mvNodeId[v], mvDerivativesMap[v] + endPointsx, endPointsd1, endPointsd2, endPointsd3, endNodeId, endDerivativesMap = \ + vox[v], vod1[v], vod2[v], vod3[v] if useCubicHermiteThroughVesselWall else None, None, None + # reverse order of nodes around: + for px in [startPointsx, startPointsd1, startPointsd2, startPointsd3, startNodeId, startDerivativesMap, + endPointsx, endPointsd1, endPointsd2, endPointsd3, endNodeId, endDerivativesMap]: + if px: + for n3 in range(elementsCountThroughWall + 1): + px[n3] = [px[n3][0]] + px[n3][len(px[n3]) - 1:0:-1] + if vesselsCount > 1: + # must switch in and out xi1 maps around corners in startDerivativesMap + for n3 in range(elementsCountThroughWall + 1): + for n1 in range(elementsCountAroundVessel): #elementsCountsAroundVessels[v]): + derivativesMap = startDerivativesMap[n3][n1] + if len(derivativesMap) == 4: + startDerivativesMap[n3][n1] = derivativesMap[3], derivativesMap[1], \ + derivativesMap[2], derivativesMap[0] + if ostiumMeshGroups: + rowMeshGroups[0] += ostiumMeshGroups + else: + startPointsx, startPointsd1, startPointsd2, startPointsd3, startNodeId, startDerivativesMap = \ + vox[v], vod1[v], vod2[v], vod3[v] if useCubicHermiteThroughVesselWall else None, None, None + endPointsx, endPointsd1, endPointsd2, endPointsd3, endNodeId, endDerivativesMap = \ + mvPointsx[v], mvPointsd1[v], mvPointsd2[v], mvPointsd3[v], mvNodeId[v], mvDerivativesMap[v] + if ostiumMeshGroups: + rowMeshGroups[-1] += ostiumMeshGroups + + # print('endPointsx ', endPointsx ) + # print('endPointsd1', endPointsd1) + # print('endPointsd2', endPointsd2) + # print('endPointsd3', endPointsd3) + # print('endNodeId', endNodeId) + # print('endDerivativesMap', endDerivativesMap) + + nodeIdentifier, elementIdentifier = createAnnulusMesh3d( + nodes, mesh, nodeIdentifier, elementIdentifier, + startPointsx, startPointsd1, startPointsd2, startPointsd3, startNodeId, startDerivativesMap, + endPointsx, endPointsd1, endPointsd2, endPointsd3, endNodeId, endDerivativesMap, + forceMidLinearXi3=not useCubicHermiteThroughVesselWall, + maxStartThickness=vesselWallThickness, maxEndThickness=vesselWallThickness, + elementsCountRadial=elementsCountAlong, meshGroups=rowMeshGroups, wallAnnotationGroups=wallAnnotationGroups, + coordinates=coordinates) + # + # nodeIdentifierLine = nodeIdentifier + # for n1 in range(len(centralPath.cxPath)): + # node = nodes.createNode(nodeIdentifier, nodetemplate ) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, centralPath.cxPath[n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, centralPath.cd1Path[n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, centralPath.cd2Path[n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, centralPath.cd3Path[n1]) + # nodeIdentifier += 1 + # + # mesh = fm.findMeshByDimension(1) + # cubicHermiteBasis = fm.createElementbasis(1, Elementbasis.FUNCTION_TYPE_CUBIC_HERMITE) + # eft = mesh.createElementfieldtemplate(cubicHermiteBasis) + # elementtemplate = mesh.createElementtemplate() + # elementtemplate.setElementShapeType(Element.SHAPE_TYPE_LINE) + # result = elementtemplate.defineField(coordinates, -1, eft) + # + # for e in range(len(centralPath.cxPath) - 1): + # element = mesh.createElement(elementIdentifier, elementtemplate) + # element.setNodesByIdentifier(eft, [nodeIdentifierLine + e, nodeIdentifierLine + 1 + e]) + # elementIdentifier = elementIdentifier + 1 + + fm.endChange() + return nodeIdentifier, elementIdentifier, (ox, od1, od2, od3, oNodeId, oPositions) + +class CentralPath: + """ + Extracts central path parameters. + """ + def __init__(self, region, centralPath, unitScale, termsAlong=[None]): + """ + :param region: Zinc region to define model in. + :param centralPath: Central path subscaffold from meshtype_1d_path1 + :param unitScale: + :param termsAlong: Annotation terms along length of central path + """ + # Extract length of each group along stomach from central path + tmpRegion = region.createRegion() + centralPath.generate(tmpRegion) + tmpFieldmodule = tmpRegion.getFieldmodule() + tmpNodes = tmpFieldmodule.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES) + tmpCoordinates = tmpFieldmodule.findFieldByName('coordinates') + + cxPath, cd1Path, cd2Path, cd3Path, cd12Path, cd13Path = \ + get_nodeset_path_field_parameters(tmpNodes, tmpCoordinates, + [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]) + + self.cxPath = [] + self.cd1Path = [] + self.cd2Path = [] + self.cd3Path = [] + self.cd12Path = [] + self.cd13Path = [] + + for i in range(len(cxPath)): + self.cxPath.append([unitScale * x for x in cxPath[i]]) + self.cd1Path.append([unitScale * cd1 for cd1 in cd1Path[i]]) + self.cd2Path.append([unitScale * cd2 for cd2 in cd2Path[i]]) + self.cd3Path.append([unitScale * cd3 for cd3 in cd3Path[i]]) + self.cd12Path.append([unitScale * cd12 for cd12 in cd12Path[i]]) + self.cd13Path.append([unitScale * cd13 for cd13 in cd13Path[i]]) diff --git a/src/scaffoldmaker/scaffolds.py b/src/scaffoldmaker/scaffolds.py index 272ab906..a03d751a 100644 --- a/src/scaffoldmaker/scaffolds.py +++ b/src/scaffoldmaker/scaffolds.py @@ -19,6 +19,7 @@ from scaffoldmaker.meshtypes.meshtype_3d_boxnetwork1 import MeshType_3d_boxnetwork1 from scaffoldmaker.meshtypes.meshtype_3d_brainstem import MeshType_3d_brainstem1 from scaffoldmaker.meshtypes.meshtype_3d_cecum1 import MeshType_3d_cecum1 +from scaffoldmaker.meshtypes.meshtype_3d_cecum2 import MeshType_3d_cecum2 from scaffoldmaker.meshtypes.meshtype_3d_colon1 import MeshType_3d_colon1 from scaffoldmaker.meshtypes.meshtype_3d_colonsegment1 import MeshType_3d_colonsegment1 from scaffoldmaker.meshtypes.meshtype_3d_esophagus1 import MeshType_3d_esophagus1 @@ -38,6 +39,7 @@ from scaffoldmaker.meshtypes.meshtype_3d_lung2 import MeshType_3d_lung2 from scaffoldmaker.meshtypes.meshtype_3d_musclefusiform1 import MeshType_3d_musclefusiform1 from scaffoldmaker.meshtypes.meshtype_3d_ostium1 import MeshType_3d_ostium1 +from scaffoldmaker.meshtypes.meshtype_3d_ostium2 import MeshType_3d_ostium2 from scaffoldmaker.meshtypes.meshtype_3d_smallintestine1 import MeshType_3d_smallintestine1 from scaffoldmaker.meshtypes.meshtype_3d_solidcylinder1 import MeshType_3d_solidcylinder1 from scaffoldmaker.meshtypes.meshtype_3d_solidsphere1 import MeshType_3d_solidsphere1 @@ -73,6 +75,7 @@ def __init__(self): MeshType_3d_boxnetwork1, MeshType_3d_brainstem1, MeshType_3d_cecum1, + MeshType_3d_cecum2, MeshType_3d_colon1, MeshType_3d_colonsegment1, MeshType_3d_esophagus1, @@ -92,6 +95,7 @@ def __init__(self): MeshType_3d_lung2, MeshType_3d_musclefusiform1, MeshType_3d_ostium1, + MeshType_3d_ostium2, MeshType_3d_smallintestine1, MeshType_3d_solidcylinder1, MeshType_3d_solidsphere1, From a458308fdeb65eb836bf62e9cd46c07f6113b1d5 Mon Sep 17 00:00:00 2001 From: mlin865 Date: Mon, 10 Jul 2023 12:08:16 +1200 Subject: [PATCH 02/24] Update code for zinc group changes --- src/scaffoldmaker/meshtypes/meshtype_3d_cecum2.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_cecum2.py b/src/scaffoldmaker/meshtypes/meshtype_3d_cecum2.py index bdd19b4e..bec8e8c4 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_cecum2.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_cecum2.py @@ -1973,7 +1973,7 @@ def createCecumMesh3d(region, options, centralPath, nextNodeIdentifier, nextElem coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D2_DS2DS3, 1, zero) coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D3_DS1DS2DS3, 1, zero) nextNodeIdentifier += 1 - + # Create elements elementIdxMat = [] @@ -2314,7 +2314,7 @@ def __init__(self, region, centralPath, termsAlong=[None]): for termName in termsAlong: tmpGroup = tmpFieldmodule.findFieldByName(termName).castGroup() if termName else None - tmpNodeset = tmpGroup.getFieldNodeGroup(tmpNodes).getNodesetGroup() if tmpGroup else tmpNodes + tmpNodeset = tmpGroup.getNodesetGroup(tmpNodes) if tmpGroup else tmpNodes if termName == "caecum": for i in range(2): From 5f0d63f747b9d01aee16e77d25033e37a31b8904 Mon Sep 17 00:00:00 2001 From: mlin865 Date: Tue, 11 Jul 2023 17:33:09 +1200 Subject: [PATCH 03/24] Keep apex smooth --- src/scaffoldmaker/meshtypes/meshtype_3d_cecum2.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_cecum2.py b/src/scaffoldmaker/meshtypes/meshtype_3d_cecum2.py index bec8e8c4..8f98c513 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_cecum2.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_cecum2.py @@ -1999,8 +1999,8 @@ def createCecumMesh3d(region, options, centralPath, nextNodeIdentifier, nextElem for e3 in range(elementsCountThroughWall): elementIdxAround = [] for e1 in range(elementsCountAroundHaustrum): - va = e1 - vb = (e1 + 1) + va = e1 + startIdxElementsAround + vb = (e1 + startIdxElementsAround + 1) eft1 = eftfactory.createEftShellPoleBottom(va * 100, vb * 100) elementtemplateX.defineField(coordinates, -1, eft1) element = mesh.createElement(elementIdentifier, elementtemplateX) From 6e885e22351a5ef5ff3e1b237b281ce2230ea411 Mon Sep 17 00:00:00 2001 From: mlin865 Date: Wed, 12 Jul 2023 16:16:43 +1200 Subject: [PATCH 04/24] Correct linear mapping for elements around annulus --- .../meshtypes/meshtype_3d_cecum2.py | 140 +++++------------- 1 file changed, 36 insertions(+), 104 deletions(-) diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_cecum2.py b/src/scaffoldmaker/meshtypes/meshtype_3d_cecum2.py index 8f98c513..2eb174a0 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_cecum2.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_cecum2.py @@ -111,13 +111,13 @@ class MeshType_3d_cecum2(Scaffold_base): }, 'meshEdits': exnode_string_from_nodeset_field_parameters( [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ - (1, [[160.00,29.75,51.53], [0.00,-9.63,-16.67], [-4.0,-0.0,0.0], [0.00,0.00,0.00], [0.0,6.64,-3.83], [0.00,0.00,0.00]]), - (2, [[160.00,17.50,30.31], [0.00,-14.87,-25.76], [-15.00,-0.0,0.0], [0.00,0.00,0.00], [0.0,10.49,-6.05], [0.00,0.00,0.00]]), - (3, [[160.00,0.00,0.00], [[30.00,0.00,0.00],[0.00,-20.13,-34.86]], [[0.00,35.00,0.00],[-15.0,0.0,0.0]], [[0.00,0.00,0.00],[0.00,0.00,0.00]], [[0.00,0.00,35.00],[0.00,8.49,-4.90]], [[0.00,0.00,0.00],[0.00,0.00,0.00]]]), - (4, [[0.00,0.00,0.00], [60.00,0.00,0.00], [0.00,35.00,0.00], [0.00,0.00,0.00], [0.00,0.00,35.00], [0.00,0.00,0.00]]), - (5, [[60.00,0.00,0.00], [60.00,0.00,0.00], [0.00,35.00,0.00], [0.00,0.00,0.00], [0.00,0.00,35.00], [0.00,0.00,0.00]]), - (6, [[120.00,0.00,0.00], [50.00,0.00,0.00], [0.00,35.00,0.00], [0.00,0.00,0.00], [0.00,0.00,35.00], [0.00,0.00,0.00]]), - (7, [[180.00,0.00,0.00], [10.00,0.00,0.00], [0.00,35.00,0.00], [0.00,0.00,0.00], [0.00,0.00,35.00], [0.00,0.00,0.00]])]), + (1, [[167.00,29.75,51.53], [0.00,-9.63,-16.67], [-4.00,-0.00,0.00], [0.00,0.00,0.00], [0.00,6.64,-3.83], [0.00,0.00,0.00]]), + (2, [[167.00,17.50,30.31], [0.00,-14.87,-25.77], [-15.00,-0.00,0.00], [0.00,0.00,0.00], [0.00,10.49,-6.05], [0.00,0.00,0.00]]), + (3, [[167.00,0.00,0.00], [[30.00,0.00,0.00],[0.00,-20.13,-34.85]], [[0.00,35.00,0.00],[-15.00,0.00,0.00]], [[0.00,0.00,0.00],[0.00,0.00,0.00]], [[0.00,0.00,35.00],[0.00,8.49,-4.90]], [[0.00,0.00,0.00],[0.00,0.00,0.00]]]), + (4, [[0.00,0.00,0.00], [60.00,0.00,0.00], [0.00,35.00,0.00], [0.00,0.00,0.00], [0.00,0.00,35.00], [0.00,0.00,0.00]]), + (5, [[60.00,0.00,0.00], [60.00,0.00,0.00], [0.00,35.00,0.00], [0.00,0.00,0.00], [0.00,0.00,35.00], [0.00,0.00,0.00]]), + (6, [[120.00,0.00,0.00], [53.50,0.00,0.00], [0.00,35.00,0.00], [0.00,0.00,0.00], [0.00,0.00,35.00], [0.00,0.00,0.00]]), + (7, [[180.00,0.00,0.00], [4.00,-0.00,-0.00], [0.00,35.00,0.00], [0.00,0.00,0.00], [0.00,0.00,35.00], [0.00,0.00,0.00]])]), 'userAnnotationGroups': [ { @@ -1409,8 +1409,6 @@ def createCecumMesh3d(region, options, centralPath, nextNodeIdentifier, nextElem # sample along the midline of ostium rotAngle = math.pi rotFrame = matrix.getRotationMatrixFromAxisAngle(d3ApexUnit, rotAngle) - # d2A = [rotFrame[j][0] * d2Cecum[1][0] + rotFrame[j][1] * d2Cecum[1][1] + - # rotFrame[j][2] * d2Cecum[1][2] for j in range(3)] d1A = [rotFrame[j][0] * d1Cecum[1][0] + rotFrame[j][1] * d1Cecum[1][1] + rotFrame[j][2] * d1Cecum[1][2] for j in range(3)] @@ -1429,7 +1427,6 @@ def createCecumMesh3d(region, options, centralPath, nextNodeIdentifier, nextElem xPositionA = trackSurfaceOstium.findNearestPosition(xStart) xProportionA = trackSurfaceOstium.getProportion(xPositionA) derivativeA = trackSurfaceOstium.evaluateCoordinates(xPositionA, derivatives=True)[2] - # derivativeMagnitudeA = vector.magnitude(derivativeA) xPositionB = trackSurfaceOstium.findNearestPosition(xAnnulusOuter[0]) xProportionB = trackSurfaceOstium.getProportion(xPositionB) @@ -1443,7 +1440,7 @@ def createCecumMesh3d(region, options, centralPath, nextNodeIdentifier, nextElem pxAlongMidLine, pd2AlongMidLine, pd1AlongMidLine = \ trackSurfaceOstium.resampleHermiteCurvePointsSmooth( - nx, nd1, nd2, nd3, proportions, #derivativeMagnitudeStart=derivativeMagnitudeB, + nx, nd1, nd2, nd3, proportions, derivativeMagnitudeEnd=derivativeMagnitudeB)[0:3] for n in range(len(pd1AlongMidLine)): @@ -1549,16 +1546,15 @@ def createCecumMesh3d(region, options, centralPath, nextNodeIdentifier, nextElem xTrackSurface[n2 * (elementsCountAroundHaustrum + 1)]) xProportionA = trackSurfaceOstium.getProportion(xPositionA) derivativeA = d1TrackSurface[n2 * (elementsCountAroundHaustrum + 1)] - derivativeMagnitudeA = vector.magnitude(derivativeA) if n2 < rowsBelow + 1: xPositionB = trackSurfaceOstium.findNearestPosition(pxAlongMidLine[n2]) - derivativeB = None #pd1AlongMidLine[n2] + derivativeB = None elif n2 >= rowsBelow + rowsOstium: idx = n2 - (rowsBelow + rowsOstium) + 1 xPositionB = trackSurfaceOstium.findNearestPosition(pxAlongMidLineBottom[idx]) - derivativeB = None #pd1AlongMidLineBottom[idx] + derivativeB = None else: xPositionB = trackSurfaceOstium.findNearestPosition(xAnnulusOuter[annulusIdx]) @@ -1569,9 +1565,7 @@ def createCecumMesh3d(region, options, centralPath, nextNodeIdentifier, nextElem rotFrame[j][1] * d1AnnulusOuter[annulusIdx][1] + rotFrame[j][2] * d1AnnulusOuter[annulusIdx][2] for j in range(3)] - # xB = trackSurfaceOstium.evaluateCoordinates(xPositionB) xProportionB = trackSurfaceOstium.getProportion(xPositionB) - # derivativeMagnitudeB = vector.magnitude(derivativeB) # node = nodes.createNode(nextNodeIdentifier, nodetemplate) # cache.setNode(node) @@ -1592,24 +1586,22 @@ def createCecumMesh3d(region, options, centralPath, nextNodeIdentifier, nextElem else: # RHS if n2 < rowsBelow + 1: xPositionA = trackSurfaceOstium.findNearestPosition(pxAlongMidLine[n2]) - derivativeA = None #pd1AlongMidLine[n2] + derivativeA = None elif n2 >= rowsBelow + rowsOstium: idx = n2 - (rowsBelow + rowsOstium) + 1 xPositionA = trackSurfaceOstium.findNearestPosition(pxAlongMidLineBottom[idx]) - derivativeA = None #pd1AlongMidLineBottom[idx] + derivativeA = None else: xPositionA = trackSurfaceOstium.findNearestPosition(xAnnulusOuter[-annulusIdx]) derivativeA = d1AnnulusOuter[-annulusIdx] xProportionA = trackSurfaceOstium.getProportion(xPositionA) - # derivativeMagnitudeA = vector.magnitude(derivativeA) xPositionB = trackSurfaceOstium.findNearestPosition( xTrackSurface[n2 * (elementsCountAroundHaustrum + 1) + elementsCountAroundHaustrum]) xProportionB = trackSurfaceOstium.getProportion(xPositionB) derivativeB = d1TrackSurface[n2 * (elementsCountAroundHaustrum + 1) + elementsCountAroundHaustrum] - # derivativeMagnitudeB = vector.magnitude(derivativeB) nx, nd1, nd2, nd3, proportions = \ trackSurfaceOstium.createHermiteCurvePoints( @@ -1619,8 +1611,7 @@ def createCecumMesh3d(region, options, centralPath, nextNodeIdentifier, nextElem nx, nd1 = \ trackSurfaceOstium.resampleHermiteCurvePointsSmooth( - nx, nd1, nd2, nd3, proportions)[0:2] #, derivativeMagnitudeStart=derivativeMagnitudeB, - # derivativeMagnitudeEnd=derivativeMagnitudeB)[0:2] + nx, nd1, nd2, nd3, proportions)[0:2] # for n in range(len(nx)): # node = nodes.createNode(nextNodeIdentifier, nodetemplate) @@ -1631,7 +1622,7 @@ def createCecumMesh3d(region, options, centralPath, nextNodeIdentifier, nextElem # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, [0.0, 0.0, 0.0]) # nextNodeIdentifier += 1 - if n2 == rowsBelow + 1 or n2 == rowsBelow + rowsOstium - 1: # n2 == 5 or n2 == 9 + if n2 == rowsBelow + 1 or n2 == rowsBelow + rowsOstium - 1: mag = 0.5 * (vector.magnitude(d1AnnulusOuter[0]) + vector.magnitude( d2AnnulusOuter[0])) if n2 == startRowIdx else vector.magnitude(d1AnnulusOuter[0]) if n == 0: @@ -1685,16 +1676,11 @@ def createCecumMesh3d(region, options, centralPath, nextNodeIdentifier, nextElem nd2Along = interp.smoothCubicHermiteDerivativesLine(nxAlong, nd2Along, fixStartDerivative=True, fixEndDerivative=True) - # Rescale d2 on node along annulus LHS to help with corners + # Replace d2 on node along annulus LHS with d2Annulus if n1 == elementsCountAroundHalfHaustrum - 2: - nd2Along[startRowIdx] = \ - vector.setMagnitude(nd2Along[startRowIdx], - 0.5 * (vector.magnitude(nd2Along[startRowIdx]) + - vector.magnitude(d1AnnulusOuter[1]))) - nd2Along[endRowIdx] = \ - vector.setMagnitude(nd2Along[endRowIdx], - 0.5 * (vector.magnitude(nd2Along[endRowIdx]) + - vector.magnitude(d1AnnulusOuter[1]))) + nd2Along[startRowIdx] = d2AnnulusOuter[1] + nd2Along[endRowIdx] = d2AnnulusOuter[int(elementsCountAroundOstium * 0.5) - 1] + xAlongAll.append(nxAlong) d2AlongAll.append(nd2Along) @@ -1724,16 +1710,11 @@ def createCecumMesh3d(region, options, centralPath, nextNodeIdentifier, nextElem nd2Along.append(d2TrackSurface[(elementsCountAroundHaustrum + 1) * elementsCountAlongSegment + n1]) nd2Along = interp.smoothCubicHermiteDerivativesLine(nxAlong, nd2Along, fixStartDerivative=True, fixEndDirection=True) - # Rescale d2 on node along annulus RHS to help with corners + + # Replace d2 on node along annulus RHS with d2Annulus if n1 == elementsCountAroundHalfHaustrum: - nd2Along[startRowIdx] = \ - vector.setMagnitude(nd2Along[startRowIdx], - 0.5 * (vector.magnitude(nd2Along[startRowIdx]) + - vector.magnitude(d1AnnulusOuter[1]))) - nd2Along[endRowIdx] = \ - vector.setMagnitude(nd2Along[endRowIdx], - 0.5 * (vector.magnitude(nd2Along[endRowIdx]) + - vector.magnitude(d1AnnulusOuter[1]))) + nd2Along[startRowIdx] = [-d for d in d2AnnulusOuter[-1]] + nd2Along[endRowIdx] = [-d for d in d2AnnulusOuter[int(elementsCountAroundOstium * 0.5) + 1]] xAlongAll.append(nxAlong) d2AlongAll.append(nd2Along) @@ -1769,7 +1750,7 @@ def createCecumMesh3d(region, options, centralPath, nextNodeIdentifier, nextElem # Curvatures around d1Curvature = [] if segmentIdx == 0: - d1Curvature.append([0.0]) # Check + d1Curvature.append([0.0]) for n2 in range(1 if segmentIdx == 0 else 0, elementsCountAlongSegment + 1): if n2 < startRowIdx or n2 == elementsCountAlongSegment: @@ -1861,7 +1842,7 @@ def createCecumMesh3d(region, options, centralPath, nextNodeIdentifier, nextElem d2AroundAlong[startRowIdx].insert(int(elementsCountAroundHaustrum * 0.5), d1AnnulusOuter[0]) d3UnitAroundAlong[startRowIdx].insert(int(elementsCountAroundHaustrum * 0.5), d3Annulus[0]) d1Curvature[startRowIdx].insert(int(elementsCountAroundHaustrum * 0.5), annulusD2Curvature[0]) - d2Curvature[startRowIdx].insert(int(elementsCountAroundHaustrum * 0.5), annulusD2Curvature[0]) # need to update + d2Curvature[startRowIdx].insert(int(elementsCountAroundHaustrum * 0.5), annulusD2Curvature[0]) idx = int(elementsCountAlongSegment * 0.5) xAroundAlong[endRowIdx].insert(int(elementsCountAroundHaustrum * 0.5), xAnnulusOuter[idx]) @@ -1869,7 +1850,7 @@ def createCecumMesh3d(region, options, centralPath, nextNodeIdentifier, nextElem d2AroundAlong[endRowIdx].insert(int(elementsCountAroundHaustrum * 0.5), d1AnnulusOuter[idx]) d3UnitAroundAlong[endRowIdx].insert(int(elementsCountAroundHaustrum * 0.5), d3Annulus[idx]) d1Curvature[endRowIdx].insert(int(elementsCountAroundHaustrum * 0.5), annulusD2Curvature[idx]) - d2Curvature[endRowIdx].insert(int(elementsCountAroundHaustrum * 0.5), annulusD2Curvature[idx]) # need to update + d2Curvature[endRowIdx].insert(int(elementsCountAroundHaustrum * 0.5), annulusD2Curvature[idx]) # for n2 in range(len(xAroundAlong)): # for n1 in range(len(xAroundAlong[n2])): @@ -2065,12 +2046,12 @@ def createCecumMesh3d(region, options, centralPath, nextNodeIdentifier, nextElem scaleFactors = [-1.0] eft1 = eftfactory.createEftNoCrossDerivatives() setEftScaleFactorIds(eft1, [1], []) - remapEftNodeValueLabel(eft1, [4, 8], Node.VALUE_LABEL_D_DS2, - [(Node.VALUE_LABEL_D_DS2, [1])]) - remapEftNodeValueLabel(eft1, [3, 7], Node.VALUE_LABEL_D_DS1, - [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [1])]) + remapEftNodeValueLabel(eft1, [3, 7], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS2, [1])]) remapEftNodeValueLabel(eft1, [3, 7], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [])]) + remapEftNodeValueLabel(eft1, [4, 8], Node.VALUE_LABEL_D_DS2, + [(Node.VALUE_LABEL_D_DS2, [1])]) + elementtemplateX.defineField(coordinates, -1, eft1) elementtemplate1 = elementtemplateX @@ -2083,7 +2064,7 @@ def createCecumMesh3d(region, options, centralPath, nextNodeIdentifier, nextElem remapEftNodeValueLabel(eft1, [4, 8], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS1, [1]), (Node.VALUE_LABEL_D_DS2, [])]) remapEftNodeValueLabel(eft1, [4, 8], Node.VALUE_LABEL_D_DS1, - [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [])]) + [(Node.VALUE_LABEL_D_DS2, [])]) elementtemplateX.defineField(coordinates, -1, eft1) elementtemplate1 = elementtemplateX @@ -2103,39 +2084,13 @@ def createCecumMesh3d(region, options, centralPath, nextNodeIdentifier, nextElem elementtemplateX.defineField(coordinates, -1, eft1) elementtemplate1 = elementtemplateX - elif e2 == startRowIdx and e1 == elementsCountAroundHalfHaustrum - 3: # Start row LHS - scaleFactors = [-1.0] - eft1 = eftfactory.createEftNoCrossDerivatives() - setEftScaleFactorIds(eft1, [1], []) - remapEftNodeValueLabel(eft1, [2, 6], Node.VALUE_LABEL_D_DS2, - [(Node.VALUE_LABEL_D_DS1, [1]), (Node.VALUE_LABEL_D_DS2, [])]) - if elementsCountAlongSegment == 6: - remapEftNodeValueLabel(eft1, [4, 8], Node.VALUE_LABEL_D_DS2, - [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [])]) - elementtemplateX.defineField(coordinates, -1, eft1) - elementtemplate1 = elementtemplateX - - elif e2 == startRowIdx and e1 == elementsCountAroundHalfHaustrum: # Start row RHS - eft1 = eftfactory.createEftNoCrossDerivatives() - remapEftNodeValueLabel(eft1, [1, 5], Node.VALUE_LABEL_D_DS2, - [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [])]) - if elementsCountAlongSegment == 6: - scaleFactors = [-1.0] - setEftScaleFactorIds(eft1, [1], []) - remapEftNodeValueLabel(eft1, [3, 7], Node.VALUE_LABEL_D_DS2, - [(Node.VALUE_LABEL_D_DS1, [1]), - (Node.VALUE_LABEL_D_DS2, [])]) - elementtemplateX.defineField(coordinates, -1, eft1) - elementtemplate1 = elementtemplateX - elif e2 == endRowIdx and e1 == elementsCountAroundHalfHaustrum - 2: # end LHS scaleFactors = [-1.0] eft1 = eftfactory.createEftNoCrossDerivatives() setEftScaleFactorIds(eft1, [1], []) remapEftNodeValueLabel(eft1, [1, 5], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS1, [1]), (Node.VALUE_LABEL_D_DS2, [])]) - remapEftNodeValueLabel(eft1, [1, 5], Node.VALUE_LABEL_D_DS1, - [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [])]) + remapEftNodeValueLabel(eft1, [1, 5], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS2, [])]) elementtemplateX.defineField(coordinates, -1, eft1) elementtemplate1 = elementtemplateX @@ -2148,21 +2103,15 @@ def createCecumMesh3d(region, options, centralPath, nextNodeIdentifier, nextElem elementtemplateX.defineField(coordinates, -1, eft1) elementtemplate1 = elementtemplateX - elif e2 == endRowIdx - 1 and e1 == elementsCountAroundHalfHaustrum - 3: # side end LHS - eft1 = eftfactory.createEftNoCrossDerivatives() - remapEftNodeValueLabel(eft1, [4, 8], Node.VALUE_LABEL_D_DS2, - [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [])]) - elementtemplateX.defineField(coordinates, -1, eft1) - elementtemplate1 = elementtemplateX - elif e2 == endRowIdx and e1 == elementsCountAroundHalfHaustrum - 1: # end RHS scaleFactors = [-1.0] eft1 = eftfactory.createEftNoCrossDerivatives() setEftScaleFactorIds(eft1, [1], []) + remapEftNodeValueLabel(eft1, [2, 6], Node.VALUE_LABEL_D_DS1, + [(Node.VALUE_LABEL_D_DS2, [1])]) remapEftNodeValueLabel(eft1, [2, 6], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [])]) - remapEftNodeValueLabel(eft1, [2, 6], Node.VALUE_LABEL_D_DS1, - [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [1])]) + elementtemplateX.defineField(coordinates, -1, eft1) elementtemplate1 = elementtemplateX @@ -2173,15 +2122,6 @@ def createCecumMesh3d(region, options, centralPath, nextNodeIdentifier, nextElem elementtemplateX.defineField(coordinates, -1, eft1) elementtemplate1 = elementtemplateX - elif e2 == endRowIdx - 1 and e1 == elementsCountAroundHalfHaustrum - 1: # end RHS down - scaleFactors = [-1.0] - eft1 = eftfactory.createEftNoCrossDerivatives() - setEftScaleFactorIds(eft1, [1], []) - remapEftNodeValueLabel(eft1, [3, 7], Node.VALUE_LABEL_D_DS2, - [(Node.VALUE_LABEL_D_DS1, [1]), (Node.VALUE_LABEL_D_DS2, [])]) - elementtemplateX.defineField(coordinates, -1, eft1) - elementtemplate1 = elementtemplateX - element = mesh.createElement(elementIdentifier, elementtemplate1) element.setNodesByIdentifier(eft1, nodeIdentifiers) if scaleFactors: @@ -2236,20 +2176,12 @@ def createCecumMesh3d(region, options, centralPath, nextNodeIdentifier, nextElem for nAround in range(elementsCountAroundOstium): if nAround == 0: endDerivativesMap[n3][nAround] = ((-1, 0, 0), (0, 1, 0), None) - elif nAround == 1: - endDerivativesMap[n3][nAround] = ((-1, 1, 0), (-1, -1, 0), None) - elif 1 < nAround < int(elementsCountAroundOstium * 0.5) - 1: + elif 1 <= nAround < int(elementsCountAroundOstium * 0.5): endDerivativesMap[n3][nAround] = ((0, 1, 0), (-1, 0, 0), None) - elif nAround == int(elementsCountAroundOstium * 0.5) - 1: - endDerivativesMap[n3][nAround] = ((1, 1, 0), (-1, 1, 0), None) elif nAround == int(elementsCountAroundOstium * 0.5): endDerivativesMap[n3][nAround] = (None, None, None) - elif nAround == int(elementsCountAroundOstium * 0.5) + 1: - endDerivativesMap[n3][nAround] = ((1, -1, 0), (1, 1, 0), None) - elif int(elementsCountAroundOstium * 0.5) + 1 < nAround < elementsCountAroundOstium - 1: + else: endDerivativesMap[n3][nAround] = ((0, -1, 0), (1, 0, 0), None) - elif nAround == elementsCountAroundOstium - 1: - endDerivativesMap[n3][nAround] = ((-1, -1, 0), (1, -1, 0), None) startProportions = [] for n in range(elementsCountAroundOstium): From acc32a379144dc2ae7ffff4a480423e859b9471c Mon Sep 17 00:00:00 2001 From: mlin865 Date: Wed, 12 Jul 2023 16:23:18 +1200 Subject: [PATCH 05/24] Replace cecum1 with cecum2 --- .../meshtypes/meshtype_3d_cecum1.py | 2296 ++++++++++++---- .../meshtypes/meshtype_3d_cecum2.py | 2323 ----------------- src/scaffoldmaker/scaffolds.py | 2 - 3 files changed, 1786 insertions(+), 2835 deletions(-) delete mode 100644 src/scaffoldmaker/meshtypes/meshtype_3d_cecum2.py diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_cecum1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_cecum1.py index ec841a0b..81e7e28f 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_cecum1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_cecum1.py @@ -7,24 +7,35 @@ import copy import math +from cmlibs.maths.vectorops import add, sub +from cmlibs.utils.zinc.field import findOrCreateFieldCoordinates # KM +from cmlibs.zinc.element import Element, Elementbasis from cmlibs.zinc.field import Field from cmlibs.zinc.node import Node -from scaffoldmaker.annotation.annotationgroup import AnnotationGroup +from scaffoldmaker.annotation.annotationgroup import AnnotationGroup, mergeAnnotationGroups from scaffoldmaker.annotation.cecum_terms import get_cecum_term -from scaffoldmaker.meshtypes.meshtype_1d_path1 import MeshType_1d_path1 +from scaffoldmaker.annotation.smallintestine_terms import get_smallintestine_term +from scaffoldmaker.meshtypes.meshtype_1d_network_layout1 import MeshType_1d_network_layout1 from scaffoldmaker.meshtypes.meshtype_3d_colonsegment1 import ColonSegmentTubeMeshInnerPoints, \ getFullProfileFromHalfHaustrum, getTeniaColi, createNodesAndElementsTeniaColi -from scaffoldmaker.meshtypes.meshtype_3d_ostium1 import MeshType_3d_ostium1, generateOstiumMesh +from scaffoldmaker.meshtypes.meshtype_3d_ostium2 import MeshType_3d_ostium2, generateOstiumMesh from scaffoldmaker.meshtypes.scaffold_base import Scaffold_base from scaffoldmaker.scaffoldpackage import ScaffoldPackage from scaffoldmaker.utils import interpolation as interp from scaffoldmaker.utils import matrix from scaffoldmaker.utils import tubemesh from scaffoldmaker.utils import vector +from scaffoldmaker.utils.geometry import createEllipsePoints # KM from scaffoldmaker.utils.annulusmesh import createAnnulusMesh3d +from scaffoldmaker.utils.eftfactory_bicubichermitelinear import eftfactory_bicubichermitelinear +from scaffoldmaker.utils.eftfactory_tricubichermite import eftfactory_tricubichermite +from scaffoldmaker.utils.eft_utils import setEftScaleFactorIds, remapEftNodeValueLabel, remapEftNodeValueLabelsVersion +from scaffoldmaker.utils.networkmesh import NetworkMesh, NetworkNode from scaffoldmaker.utils.tracksurface import TrackSurface, TrackSurfacePosition from scaffoldmaker.utils.zinc_utils import exnode_string_from_nodeset_field_parameters, \ - mesh_destroy_elements_and_nodes_by_identifiers, get_nodeset_path_field_parameters + mesh_destroy_elements_and_nodes_by_identifiers, get_nodeset_path_field_parameters, \ + get_nodeset_path_ordered_field_parameters + class MeshType_3d_cecum1(Scaffold_base): ''' @@ -37,46 +48,126 @@ class MeshType_3d_cecum1(Scaffold_base): ileo-cecal junction. ''' - centralPathDefaultScaffoldPackages = { - 'Pig 1': ScaffoldPackage(MeshType_1d_path1, { + parameterSetStructureStrings = { + 'Human 1': ScaffoldPackage(MeshType_1d_network_layout1, { 'scaffoldSettings': { - 'Coordinate dimensions': 3, - 'D2 derivatives': True, - 'Length': 120.0, - 'Number of elements': 3 + "Structure": "1-2-3.2, 4-3-5" }, 'meshEdits': exnode_string_from_nodeset_field_parameters( - [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2], [ - (1, [[0.0, 0.0, 0.0], [0.0, 0.0, 60.0], [1.0, 0.0, 0.0], [0.0, 0.0, 0.0]]), - (2, [[0.0, 0.0, 60.0], [0.0, 0.0, 60.0], [1.0, 0.0, 0.0], [0.0, 0.0, 0.0]]), - (3, [[0.0, 0.0, 120.0], [0.0, 0.0, 60.0], [1.0, 0.0, 0.0], [0.0, 0.0, 0.0]]), - (4, [[0.0, 0.0, 180.0], [0.0, 0.0, 60.0], [1.0, 0.0, 0.0], [0.0, 0.0, 0.0]]) - ]) - } ) - } - + [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ + (1, [[7.50,-20.00,0.00], [0.00,8.28,0.00], [-1.50,0.00,0.00], [0.00,0.00,0.00], [0.00,-0.00,1.50], [0.00,0.00,0.00]]), + (2, [[7.50,-10.86,0.00], [0.00,10.00,0.00], [-4.50,0.00,0.00], [0.00,0.00,0.00], [0.00,-0.00,4.50], [0.00,0.00,0.00]]), + (3, [[7.50,0.00,0.00], [[7.50,0.00,0.00],[0.00,11.72,0.00]], [[0.00,10.00,0.00],[-4.50,0.00,0.00]], [[1.02,6.79,0.00],[0.00,0.00,0.00]], [[0.00,0.00,10.00],[0.00,-0.00,4.50]], [[0.00,0.00,5.77],[0.00,0.00,0.00]]]), + (4, [[0.00,0.00,0.00], [7.50,0.00,0.00], [0.00,10.00,0.00], [0.00,0.00,0.00], [0.00,0.00,10.00], [0.00,0.00,0.00]]), + (5, [[15.00,0.00,0.00], [7.50,0.00,0.00], [0.00,10.00,0.00], [0.00,0.00,0.00], [0.00,0.00,10.00], [0.00,0.00,0.00]])]), + + 'userAnnotationGroups': [ + { + '_AnnotationGroup': True, + 'dimension': 1, + 'identifierRanges': '3-4', + 'name': get_cecum_term('caecum')[0], + 'ontId': get_cecum_term('caecum')[1] + }, + { + '_AnnotationGroup': True, + 'dimension': 1, + 'identifierRanges': '1-2', + 'name': get_smallintestine_term('ileum')[0], + 'ontId': get_smallintestine_term('ileum')[1] + }] + }), + 'Human 2': ScaffoldPackage(MeshType_1d_network_layout1, { + 'scaffoldSettings': { + "Structure": "1-2-3.2, 4-3-5" + }, + 'meshEdits': exnode_string_from_nodeset_field_parameters( + [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ + (1, [[9.21,-19.56,6.43], [-2.02,7.27,-6.55], [-1.46,-0.27,0.15], [0.00,0.00,0.00], [-0.06,0.99,1.12], [0.00,0.00,0.00]]), + (2, [[7.72,-10.79,1.37], [-0.90,10.04,-3.37], [-4.48,-0.36,0.11], [0.00,0.00,0.00], [-0.01,1.43,4.27], [0.00,0.00,0.00]]), + (3, [[7.50,0.00,0.00], [[7.50,0.00,0.00],[0.45,11.25,0.61]], [[0.00,10.00,0.00],[-4.50,0.18,0.01]], [[1.02,6.79,0.00],[0.00,0.00,0.00]], [[0.00,0.00,10.00],[0.00,-0.24,4.49]], [[0.00,0.00,5.77],[0.00,0.00,0.00]]]), + (4, [[0.00,0.00,0.00], [7.50,0.00,0.00], [0.00,10.00,0.00], [0.00,0.00,0.00], [0.00,0.00,10.00], [0.00,0.00,0.00]]), + (5, [[15.00,0.00,0.00], [7.50,0.00,0.00], [0.00,10.00,0.00], [0.00,0.00,0.00], [0.00,0.00,10.00], [0.00,0.00,0.00]])]), + + 'userAnnotationGroups': [ + { + '_AnnotationGroup': True, + 'dimension': 1, + 'identifierRanges': '3-4', + 'name': get_cecum_term('caecum')[0], + 'ontId': get_cecum_term('caecum')[1] + }, + { + '_AnnotationGroup': True, + 'dimension': 1, + 'identifierRanges': '1-2', + 'name': get_smallintestine_term('ileum')[0], + 'ontId': get_smallintestine_term('ileum')[1] + }] + }), + 'Pig 1': ScaffoldPackage(MeshType_1d_network_layout1, { + 'scaffoldSettings': { + "Structure": "1-2-3.2, 4-5-6-3-7" + }, + 'meshEdits': exnode_string_from_nodeset_field_parameters( + [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ + (1, [[167.00,29.75,51.53], [0.00,-9.63,-16.67], [-4.00,-0.00,0.00], [0.00,0.00,0.00], [0.00,6.64,-3.83], [0.00,0.00,0.00]]), + (2, [[167.00,17.50,30.31], [0.00,-14.87,-25.77], [-15.00,-0.00,0.00], [0.00,0.00,0.00], [0.00,10.49,-6.05], [0.00,0.00,0.00]]), + (3, [[167.00,0.00,0.00], [[30.00,0.00,0.00],[0.00,-20.13,-34.85]], [[0.00,35.00,0.00],[-15.00,0.00,0.00]], [[0.00,0.00,0.00],[0.00,0.00,0.00]], [[0.00,0.00,35.00],[0.00,8.49,-4.90]], [[0.00,0.00,0.00],[0.00,0.00,0.00]]]), + (4, [[0.00,0.00,0.00], [60.00,0.00,0.00], [0.00,35.00,0.00], [0.00,0.00,0.00], [0.00,0.00,35.00], [0.00,0.00,0.00]]), + (5, [[60.00,0.00,0.00], [60.00,0.00,0.00], [0.00,35.00,0.00], [0.00,0.00,0.00], [0.00,0.00,35.00], [0.00,0.00,0.00]]), + (6, [[120.00,0.00,0.00], [53.50,0.00,0.00], [0.00,35.00,0.00], [0.00,0.00,0.00], [0.00,0.00,35.00], [0.00,0.00,0.00]]), + (7, [[180.00,0.00,0.00], [4.00,-0.00,-0.00], [0.00,35.00,0.00], [0.00,0.00,0.00], [0.00,0.00,35.00], [0.00,0.00,0.00]])]), + + 'userAnnotationGroups': [ + { + '_AnnotationGroup': True, + 'dimension': 1, + 'identifierRanges': '3-6', + 'name': get_cecum_term('caecum')[0], + 'ontId': get_cecum_term('caecum')[1] + }, + { + '_AnnotationGroup': True, + 'dimension': 1, + 'identifierRanges': '1-2', + 'name': get_smallintestine_term('ileum')[0], + 'ontId': get_smallintestine_term('ileum')[1] + }] + }), + } + ostiumDefaultScaffoldPackages = { - 'Pig 1': ScaffoldPackage(MeshType_3d_ostium1, { + 'Human 1': ScaffoldPackage(MeshType_3d_ostium2, { + 'scaffoldSettings': { + 'Number of elements around ostium': 8, + 'Number of elements along': 2, + 'Number of elements through wall': 1, + 'Unit scale': 1.0, + 'Outlet': False, + 'Ostium wall thickness': 1.6, + 'Ostium wall relative thicknesses': [0.55, 0.15, 0.25, 0.05], + 'Use linear through ostium wall': True, + 'Vessel wall thickness': 0.45, + 'Vessel wall relative thicknesses': [0.55, 0.15, 0.25, 0.05], + 'Use linear through vessel wall': True, + 'Use cross derivatives': False, + 'Refine': False, + 'Refine number of elements around': 4, + 'Refine number of elements along': 4, + 'Refine number of elements through wall': 1 + }, + }), + 'Pig 1': ScaffoldPackage(MeshType_3d_ostium2, { 'scaffoldSettings': { - 'Number of vessels': 1, - 'Number of elements across common': 2, 'Number of elements around ostium': 8, 'Number of elements along': 2, 'Number of elements through wall': 1, # not implemented for > 1 'Unit scale': 1.0, 'Outlet': False, - 'Ostium diameter': 20.0, - 'Ostium length': 10.0, 'Ostium wall thickness': 2.0, - 'Ostium inter-vessel distance': 0.0, - 'Ostium inter-vessel height': 0.0, 'Use linear through ostium wall': True, - 'Vessel end length factor': 1.0, - 'Vessel inner diameter': 10.0, 'Vessel wall thickness': 2.0, - 'Vessel angle 1 degrees': 0.0, - 'Vessel angle 1 spread degrees': 0.0, - 'Vessel angle 2 degrees': 0.0, 'Use linear through vessel wall': True, 'Use cross derivatives': False, 'Refine': False, @@ -95,38 +186,45 @@ def getName(): def getParameterSetNames(): return [ 'Default', + 'Human 1', + 'Human 2', 'Pig 1'] @classmethod def getDefaultOptions(cls, parameterSetName='Default'): - centralPathOption = cls.centralPathDefaultScaffoldPackages['Pig 1'] - ostiumOption = cls.ostiumDefaultScaffoldPackages['Pig 1'] + if 'Human 2' in parameterSetName: + centralPathOption = cls.parameterSetStructureStrings['Human 2'] + ostiumOption = cls.ostiumDefaultScaffoldPackages['Human 1'] + elif 'Pig 1' in parameterSetName: + centralPathOption = cls.parameterSetStructureStrings['Pig 1'] + ostiumOption = cls.ostiumDefaultScaffoldPackages['Pig 1'] + else: + centralPathOption = cls.parameterSetStructureStrings['Human 1'] + ostiumOption = cls.ostiumDefaultScaffoldPackages['Human 1'] options = { 'Central path': copy.deepcopy(centralPathOption), - 'Number of segments': 5, + 'Number of segments': 1, 'Number of elements around tenia coli': 2, 'Number of elements around haustrum': 8, 'Number of elements along segment': 8, - 'Number of elements through wall': 1, - 'Start inner radius': 35.0, - 'Start inner radius derivative': 3.0, - 'End inner radius': 38.0, - 'End inner radius derivative': 3.0, + 'Number of elements through wall': 1, # 4 later! 'Corner inner radius factor': 0.5, - 'Haustrum inner radius factor': 0.25, - 'Segment length end derivative factor': 1.0, - 'Segment length mid derivative factor': 4.0, + 'Haustrum inner radius factor': 0.4, + 'Segment length end derivative factor': 0.5, + 'Segment length mid derivative factor': 1.0, # 3.0, 'Number of tenia coli': 3, - 'Start tenia coli width': 5.0, - 'Start tenia coli width derivative': 0.0, - 'End tenia coli width': 5.0, - 'End tenia coli width derivative': 0.0, - 'Tenia coli thickness': 0.5, - 'Wall thickness': 2.0, + 'Start tenia coli width': 2.0, #10.0, + 'Start tenia coli width derivative': 2.0, #0.0, + 'End tenia coli width': 4.0, #10.0, + 'End tenia coli width derivative': 2.0, #0.0, + 'Tenia coli thickness': 0.5, #1.6, + 'Wall thickness': 1.6, + 'Mucosa relative thickness': 0.55, + 'Submucosa relative thickness': 0.15, + 'Circular muscle layer relative thickness': 0.25, + 'Longitudinal muscle layer relative thickness': 0.05, 'Ileocecal junction': copy.deepcopy(ostiumOption), - 'Ileocecal junction angular position degrees': 60.0, - 'Ileocecal junction position along factor': 0.5, 'Use cross derivatives': False, 'Use linear through wall': True, 'Refine': False, @@ -134,6 +232,18 @@ def getDefaultOptions(cls, parameterSetName='Default'): 'Refine number of elements along': 1, 'Refine number of elements through wall': 1 } + + if 'Pig 1' in parameterSetName: + options['Number of segments'] = 5 + options['Haustrum inner radius factor'] = 0.25 + options['Segment length end derivative factor'] = 1.0 + options['Segment length mid derivative factor'] = 4.0 + options['Start tenia coli width'] = 5.0 + options['Start tenia coli width derivative'] = 0.0 + options['End tenia coli width'] = 5.0 + options['End tenia coli width derivative'] = 0.0 + options['Wall thickness'] = 2.0 + cls.updateSubScaffoldOptions(options) return options @@ -146,10 +256,6 @@ def getOrderedOptionNames(): 'Number of elements around haustrum', 'Number of elements along segment', 'Number of elements through wall', - 'Start inner radius', - 'Start inner radius derivative', - 'End inner radius', - 'End inner radius derivative', 'Corner inner radius factor', 'Haustrum inner radius factor', 'Segment length end derivative factor', @@ -161,9 +267,11 @@ def getOrderedOptionNames(): 'End tenia coli width derivative', 'Tenia coli thickness', 'Wall thickness', + 'Mucosa relative thickness', + 'Submucosa relative thickness', + 'Circular muscle layer relative thickness', + 'Longitudinal muscle layer relative thickness', 'Ileocecal junction', - 'Ileocecal junction angular position degrees', - 'Ileocecal junction position along factor', 'Use cross derivatives', 'Use linear through wall', 'Refine', @@ -174,15 +282,15 @@ def getOrderedOptionNames(): @classmethod def getOptionValidScaffoldTypes(cls, optionName): if optionName == 'Central path': - return [ MeshType_1d_path1 ] + return [ MeshType_1d_network_layout1 ] if optionName == 'Ileocecal junction': - return [ MeshType_3d_ostium1 ] + return [ MeshType_3d_ostium2 ] return [] @classmethod def getOptionScaffoldTypeParameterSetNames(cls, optionName, scaffoldType): if optionName == 'Central path': - return list(cls.centralPathDefaultScaffoldPackages.keys()) + return list(cls.parameterSetStructureStrings.keys()) if optionName == 'Ileocecal junction': return list(cls.ostiumDefaultScaffoldPackages.keys()) assert scaffoldType in cls.getOptionValidScaffoldTypes(optionName), cls.__name__ + '.getOptionScaffoldTypeParameterSetNames. ' + \ @@ -200,8 +308,8 @@ def getOptionScaffoldPackage(cls, optionName, scaffoldType, parameterSetName=Non 'Invalid parameter set ' + str(parameterSetName) + ' for scaffold ' + str(scaffoldType.getName()) + ' in option ' + str(optionName) + ' of scaffold ' + cls.getName() if optionName == 'Central path': if not parameterSetName: - parameterSetName = list(cls.centralPathDefaultScaffoldPackages.keys())[0] - return copy.deepcopy(cls.centralPathDefaultScaffoldPackages[parameterSetName]) + parameterSetName = list(cls.parameterSetStructureStrings.keys())[0] + return copy.deepcopy(cls.parameterSetStructureStrings[parameterSetName]) if optionName == 'Ileocecal junction': if not parameterSetName: parameterSetName = list(cls.ostiumDefaultScaffoldPackages.keys())[0] @@ -211,9 +319,9 @@ def getOptionScaffoldPackage(cls, optionName, scaffoldType, parameterSetName=Non @classmethod def checkOptions(cls, options): if not options['Central path'].getScaffoldType() in cls.getOptionValidScaffoldTypes('Central path'): - options['Central path'] = cls.getOptionScaffoldPackage('Central path', MeshType_1d_path1) + options['Central path'] = cls.getOptionScaffoldPackage('Central path', MeshType_1d_network_layout1) if not options['Ileocecal junction'].getScaffoldType() in cls.getOptionValidScaffoldTypes('Ileocecal junction'): - options['Ileocecal junction'] = cls.getOptionScaffoldPackage('Ileocecal junction', MeshType_3d_ostium1) + options['Ileocecal junction'] = cls.getOptionScaffoldPackage('Ileocecal junction', MeshType_3d_ostium2) for key in [ 'Number of segments', 'Refine number of elements around', @@ -225,10 +333,6 @@ def checkOptions(cls, options): 'Number of elements around tenia coli', 'Number of elements around haustrum', 'Number of elements along segment', - 'Start inner radius', - 'Start inner radius derivative', - 'End inner radius', - 'End inner radius derivative', 'Corner inner radius factor', 'Haustrum inner radius factor', 'Segment length end derivative factor', @@ -238,14 +342,12 @@ def checkOptions(cls, options): 'Start tenia coli width derivative', 'End tenia coli width', 'End tenia coli width derivative', - 'Ileocecal junction angular position degrees', - 'Ileocecal junction position along factor', 'Tenia coli thickness', 'Wall thickness']: if options[key] < 0.0: options[key] = 0.0 - if options['Number of elements through wall'] != 1: - options['Number of elements through wall'] = 1 + if options['Number of elements through wall'] != (1 or 4): + options['Number of elements through wall'] = 4 cls.updateSubScaffoldOptions(options) @classmethod @@ -257,6 +359,19 @@ def updateSubScaffoldOptions(cls, options): ostiumOptions = options['Ileocecal junction'] ostiumSettings = ostiumOptions.getScaffoldSettings() ostiumSettings['Ostium wall thickness'] = wallThickness + elementsCountThroughWall = options['Number of elements through wall'] + ostiumSettings['Number of elements through wall'] = elementsCountThroughWall + if elementsCountThroughWall == 1: + ostiumSettings['Ostium wall relative thicknesses'] = [1.0] + ostiumSettings['Vessel wall relative thicknesses'] = [1.0] + else: + mucosaRelThickness = options['Mucosa relative thickness'] + submucosaRelThickness = options['Submucosa relative thickness'] + circularRelThickness = options['Circular muscle layer relative thickness'] + longRelThickness = options['Longitudinal muscle layer relative thickness'] + relThicknesses = [mucosaRelThickness, submucosaRelThickness, circularRelThickness, longRelThickness] + ostiumSettings['Ostium wall relative thicknesses'] = relThicknesses + ostiumSettings['Vessel wall relative thicknesses'] = relThicknesses @classmethod def generateBaseMesh(cls, region, options): @@ -264,447 +379,18 @@ def generateBaseMesh(cls, region, options): Generate the base tricubic Hermite mesh. :param region: Zinc region to define model in. Must be empty. :param options: Dict containing options. See getDefaultOptions(). - :return: list of AnnotationGroup, None + :return: annotationGroups """ - cls.updateSubScaffoldOptions(options) - centralPath = options['Central path'] - segmentCount = options['Number of segments'] - startPhase = 0.0 - elementsCountAroundTC = options['Number of elements around tenia coli'] - elementsCountAroundHaustrum = options['Number of elements around haustrum'] - elementsCountAlongSegment = options['Number of elements along segment'] - elementsCountThroughWall = options['Number of elements through wall'] - startInnerRadius = options['Start inner radius'] - startInnerRadiusDerivative = options['Start inner radius derivative'] - endInnerRadius = options['End inner radius'] - endInnerRadiusDerivative = options['End inner radius derivative'] - cornerInnerRadiusFactor = options['Corner inner radius factor'] - haustrumInnerRadiusFactor = options['Haustrum inner radius factor'] - segmentLengthEndDerivativeFactor = options['Segment length end derivative factor'] - segmentLengthMidDerivativeFactor = options['Segment length mid derivative factor'] - tcCount = options['Number of tenia coli'] - startTCWidth = options['Start tenia coli width'] - startTCWidthDerivative = options['Start tenia coli width derivative'] - endTCWidth = options['End tenia coli width'] - endTCWidthDerivative = options['End tenia coli width derivative'] - tcThickness = options['Tenia coli thickness'] - wallThickness = options['Wall thickness'] - useCrossDerivatives = options['Use cross derivatives'] - useCubicHermiteThroughWall = not(options['Use linear through wall']) - elementsCountAlong = int(elementsCountAlongSegment*segmentCount) - elementsCountAround = (elementsCountAroundTC + elementsCountAroundHaustrum)*tcCount - # Angle between the middle of first tenia coli to ostium location - ostiumPositionAngleAround = math.radians(options['Ileocecal junction angular position degrees']) - # Factor when scaled with segmentLength will give distance between the - # junction and distal end of the cecum - ostiumPositionAlongFactor = options['Ileocecal junction position along factor'] - ostiumOptions = options['Ileocecal junction'] - ostiumSettings = ostiumOptions.getScaffoldSettings() - ostiumDiameter = ostiumSettings['Ostium diameter'] - - firstNodeIdentifier = 1 - firstElementIdentifier = 1 - - # Central path - tmpRegion = region.createRegion() - centralPath.generate(tmpRegion) - tmpFieldmodule = tmpRegion.getFieldmodule() - cx, cd1, cd2, cd12 = get_nodeset_path_field_parameters( - tmpFieldmodule.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES), - tmpFieldmodule.findFieldByName('coordinates'), - [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2]) - del tmpFieldmodule - del tmpRegion - - # find arclength of cecum - cecumLength = 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) - cecumLength += arcLength - - # Sample central path - smoothd1 = interp.smoothCubicHermiteDerivativesLine(cx, cd1, - magnitudeScalingMode = interp.DerivativeScalingMode.HARMONIC_MEAN) - sxCecum, sd1Cecum, se, sxi, ssf = interp.sampleCubicHermiteCurves(cx, smoothd1, elementsCountAlong) - sd2Cecum, sd12Cecum = interp.interpolateSampleCubicHermite(cd2, cd12, se, sxi, ssf) - - # Calculate segment length - segmentLength = cecumLength / segmentCount - - # Generate variation of radius & tc width along length - innerRadiusAlongCecum = [] - dInnerRadiusAlongCecum = [] - tcWidthAlongCecum = [] - - closedProximalEnd = True - - for n2 in range(elementsCountAlongSegment*segmentCount + 1): - xi = 1/(elementsCountAlongSegment*segmentCount) * n2 - - radius = interp.interpolateCubicHermite([startInnerRadius], [startInnerRadiusDerivative], - [endInnerRadius], [endInnerRadiusDerivative], xi)[0] - innerRadiusAlongCecum.append(radius) - dRadius = interp.interpolateCubicHermiteDerivative([startInnerRadius], [startInnerRadiusDerivative], - [endInnerRadius], [endInnerRadiusDerivative], xi)[0] - dInnerRadiusAlongCecum.append(dRadius) - tcWidth = interp.interpolateCubicHermite([startTCWidth], [startTCWidthDerivative], - [endTCWidth], [endTCWidthDerivative], xi)[0] - tcWidthAlongCecum.append(tcWidth) - - haustrumInnerRadiusFactorAlongCecum = [haustrumInnerRadiusFactor] * (elementsCountAlong + 1) - - xToSample = [] - d1ToSample = [] - d2ToSample = [] - - elementsCountAroundHalfHaustrum = int((elementsCountAroundTC + elementsCountAroundHaustrum)*0.5) - - # Create object - colonSegmentTubeMeshInnerPoints = ColonSegmentTubeMeshInnerPoints( - region, elementsCountAroundTC, elementsCountAroundHaustrum, elementsCountAlongSegment, - tcCount, segmentLengthEndDerivativeFactor, segmentLengthMidDerivativeFactor, - segmentLength, wallThickness, cornerInnerRadiusFactor, haustrumInnerRadiusFactorAlongCecum, - innerRadiusAlongCecum, dInnerRadiusAlongCecum, tcWidthAlongCecum, startPhase) - - # Create annotation - cecumGroup = AnnotationGroup(region, get_cecum_term("caecum")) - annotationGroupsAlong = [] - for i in range(elementsCountAlong): - annotationGroupsAlong.append([cecumGroup]) - - annotationGroupsThroughWall = [] - for i in range(elementsCountThroughWall): - annotationGroupsThroughWall.append([ ]) - - for nSegment in range(segmentCount): - # Make regular segments - xInner, d1Inner, d2Inner, transitElementList, segmentAxis, annotationGroupsAround \ - = colonSegmentTubeMeshInnerPoints.getColonSegmentTubeMeshInnerPoints(nSegment) - - # Replace first half of first segment with apex and sample along apex and second half of segment - if nSegment == 0: - xFirstSegmentSampled, d1FirstSegmentSampled, d2FirstSegmentSampled, d1FirstDirectionVector = \ - getApexSegmentForCecum(xInner, d1Inner, d2Inner, elementsCountAroundHalfHaustrum, - elementsCountAroundTC, elementsCountAround, elementsCountAlongSegment, - tcCount) - - xToSample += xFirstSegmentSampled - d1ToSample += d1FirstSegmentSampled - d2ToSample += d2FirstSegmentSampled - else: - xInnerExtrude = [] - for n in range(len(xInner)): - xInnerExtrude.append([xInner[n][0], xInner[n][1], xInner[n][2] + segmentLength*nSegment]) - xToSample += xInnerExtrude[elementsCountAround:] - d1ToSample += d1Inner[elementsCountAround:] - d2ToSample += d2Inner[elementsCountAround:] - - # Sample along length - xToWarp, d1ToWarp, d2ToWarp = sampleCecumAlongLength(xToSample, d1ToSample, d2ToSample, d1FirstDirectionVector, - elementsCountAroundHalfHaustrum, elementsCountAroundTC, - elementsCountAround, elementsCountAlong, tcCount) - - # Ensure cecum starts at z = 0.0 - minZ = xToWarp[0][2] - for n2 in range(elementsCountAlong + 1): - zFirstNodeAlong = xToWarp[n2 * elementsCountAround][2] - if zFirstNodeAlong < minZ: - minZ = zFirstNodeAlong - - for n in range(len(xToWarp)): - xToWarp[n][2] = xToWarp[n][2] - minZ - - # Project reference point for warping onto central path - sxRefList, sd1RefList, sd2ProjectedListRef, zRefList = \ - tubemesh.getPlaneProjectionOnCentralPath(xToWarp, elementsCountAround, elementsCountAlong, - cecumLength, sxCecum, sd1Cecum, sd2Cecum, sd12Cecum) - - # Warp points - xWarpedList, d1WarpedList, d2WarpedList, d3WarpedUnitList = \ - tubemesh.warpSegmentPoints(xToWarp, d1ToWarp, d2ToWarp, segmentAxis, sxRefList, sd1RefList, - sd2ProjectedListRef, elementsCountAround, elementsCountAlong, - zRefList) - - # Create coordinates and derivatives - wallThicknessList = [wallThickness] * (elementsCountAlong + 1) - - relativeThicknessList = [] - xList, d1List, d2List, d3List, curvatureList = tubemesh.getCoordinatesFromInner(xWarpedList, d1WarpedList, - d2WarpedList, d3WarpedUnitList, wallThicknessList, relativeThicknessList, - elementsCountAround, elementsCountAlong, elementsCountThroughWall, transitElementList) - - # Deal with multiple nodes at end point for closed proximal end - xApexInner = xList[0] - # arclength between apex point and corresponding point on next face - mag = interp.getCubicHermiteArcLength(xList[0], d2List[0], xList[elementsCountAround*2], - d2List[elementsCountAround*2]) - d2ApexInner = vector.setMagnitude(sd2Cecum[0], mag) - d1ApexInner = vector.crossproduct3(sd1Cecum[0], d2ApexInner) - d1ApexInner = vector.setMagnitude(d1ApexInner, mag) - d3ApexUnit = vector.normalise(vector.crossproduct3(vector.normalise(d1ApexInner), - vector.normalise(d2ApexInner))) - d3ApexInner = [d3ApexUnit[c] * wallThickness/elementsCountThroughWall for c in range(3)] - - xCecum = [] - d1Cecum = [] - d2Cecum = [] - d3Cecum = [] - - for n3 in range(elementsCountThroughWall + 1): - xApex = [xApexInner[c] + d3ApexUnit[c] * wallThickness/elementsCountThroughWall * n3 for c in range(3)] - xCecum.append(xApex) - d1Cecum.append(d1ApexInner) - d2Cecum.append(d2ApexInner) - d3Cecum.append(d3ApexInner) - - xCecum += xList[(elementsCountThroughWall+1)*elementsCountAround:] - d1Cecum += d1List[(elementsCountThroughWall + 1) * elementsCountAround:] - d2Cecum += d2List[(elementsCountThroughWall + 1) * elementsCountAround:] - d3Cecum += d3List[(elementsCountThroughWall + 1) * elementsCountAround:] - - xFlat = d1Flat = d2Flat = [] - xOrgan = d1Organ = d2Organ = [] - - # Create nodes and elements - if tcThickness > 0: - tubeTCWidthList = colonSegmentTubeMeshInnerPoints.getTubeTCWidthList() - xCecum, d1Cecum, d2Cecum, d3Cecum, annotationGroupsAround = getTeniaColi( - region, xCecum, d1Cecum, d2Cecum, d3Cecum, curvatureList, tcCount, elementsCountAroundTC, - elementsCountAroundHaustrum, elementsCountAlong, elementsCountThroughWall, - tubeTCWidthList, tcThickness, sxRefList, annotationGroupsAround, closedProximalEnd) - - nextNodeIdentifier, nextElementIdentifier, annotationGroups = createNodesAndElementsTeniaColi( - region, xCecum, d1Cecum, d2Cecum, d3Cecum, xFlat, d1Flat, d2Flat, xOrgan, d1Organ, d2Organ, None, - elementsCountAroundTC, elementsCountAroundHaustrum, elementsCountAlong, elementsCountThroughWall, - tcCount, annotationGroupsAround, annotationGroupsAlong, annotationGroupsThroughWall, - firstNodeIdentifier, firstElementIdentifier, useCubicHermiteThroughWall, useCrossDerivatives, - closedProximalEnd) - - else: - nextNodeIdentifier, nextElementIdentifier, annotationGroups = tubemesh.createNodesAndElements( - region, xCecum, d1Cecum, d2Cecum, d3Cecum, xFlat, d1Flat, d2Flat, xOrgan, d1Organ, d2Organ, None, - elementsCountAround, elementsCountAlong, elementsCountThroughWall, - annotationGroupsAround, annotationGroupsAlong, annotationGroupsThroughWall, - firstNodeIdentifier, firstElementIdentifier, useCubicHermiteThroughWall, useCrossDerivatives, - closedProximalEnd) - - # Add ostium on track surface between two tenia on the last segment - elementsAroundTrackSurface = elementsCountAroundHaustrum - elementsAlongTrackSurface = elementsCountAlongSegment - - # Find region where ostium sits - sectorIdx = ostiumPositionAngleAround // (2*math.pi/tcCount) - startIdxElementsAround = int((elementsCountAroundHaustrum + elementsCountAroundTC)*sectorIdx + - elementsCountAroundTC*0.5) - baseNodesIdx = (elementsCountThroughWall + 1) + \ - + (elementsCountAround * (elementsCountThroughWall + 1) + - ((elementsCountAroundTC - 1)*tcCount if tcThickness > 0.0 else 0)) * \ - (elementsCountAlongSegment * (segmentCount - 1) - 1) + elementsCountAround - xTrackSurface = [] - d1TrackSurface = [] - d2TrackSurface = [] - for n2 in range(elementsCountAlongSegment + 1): - for n1 in range(elementsCountAroundHaustrum + 1): - idx = baseNodesIdx + \ - (elementsCountAround * (elementsCountThroughWall + 1) + - ((elementsCountAroundTC - 1)*tcCount if tcThickness > 0.0 else 0)) * n2 + \ - startIdxElementsAround + n1 - xTrackSurface.append(xCecum[idx]) - d1TrackSurface.append(d1Cecum[idx]) - d2TrackSurface.append(d2Cecum[idx]) - - trackSurfaceOstium = TrackSurface(elementsAroundTrackSurface, elementsAlongTrackSurface, - xTrackSurface, d1TrackSurface, d2TrackSurface) - # Find centre position - v1 = xList[0] - v2 = xList[int(elementsCountAroundTC*0.5)] - d1 = d1List[0] - d2 = d1List[int(elementsCountAroundTC*0.5)] - arcLengthTC = interp.getCubicHermiteArcLength(v1, d1, v2, d2) - angleToTCEdge = arcLengthTC / startInnerRadius - angleOstium = ostiumDiameter / startInnerRadius - dAngle = (2 * math.pi / tcCount - 2 * angleToTCEdge) / elementsCountAroundHaustrum - angleAroundInSector = ostiumPositionAngleAround % (2 * math.pi / tcCount) - assert angleAroundInSector > angleToTCEdge + angleOstium * 0.5 and \ - angleAroundInSector < (2*math.pi/tcCount) - angleToTCEdge - angleOstium*0.5,\ - 'Ileocecal junction cannot sit on tenia coli' - - ei1Centre = int((angleAroundInSector - angleToTCEdge) // dAngle) - xi1 = ((angleAroundInSector - angleToTCEdge) - dAngle * ei1Centre) / dAngle - - ostiumDistanceFromCecumDistal = segmentLength * ostiumPositionAlongFactor - - arcLength = interp.getCubicHermiteArcLength(sxRefList[-1], sd1RefList[-1], - sxRefList[-2], sd1RefList[-2]) - distance = arcLength - - for e in range(len(sxRefList)-2, 0, -1): - if ostiumDistanceFromCecumDistal > distance: - arcLength = interp.getCubicHermiteArcLength(sxRefList[e - 1], sd1RefList[e - 1], - sxRefList[e], sd1RefList[e]) - distance += arcLength - else: - ei2Centre = e - elementsCountAlongSegment*(segmentCount-1) - xi2 = (distance - ostiumDistanceFromCecumDistal) / arcLength - break - - centrePosition = TrackSurfacePosition(ei1Centre, ei2Centre, xi1, xi2) - xCentre, d1Centre, d2Centre = trackSurfaceOstium.evaluateCoordinates(centrePosition, derivatives=True) - axis1 = d1Centre - - # Find boundary of ostium on tracksurface - ei1Left, ei1Right, ei2Bottom, ei2Top = getElementIdxOfOstiumBoundary(centrePosition, trackSurfaceOstium, - ostiumDiameter) - - # Extend boundary - ei1Left -= 1 - ei1Right += 1 - ei2Bottom -= 1 - ei2Top += 1 - - assert (ei1Left >= 0 and ei1Right < elementsAroundTrackSurface and - ei2Bottom >= 0 and ei2Top < elementsAlongTrackSurface), \ - 'cecum1.py: Insufficient elements around ostium on tracksurface to make annulus mesh.' - - nodeStart = int(baseNodesIdx + ei2Bottom * (elementsCountAround * (elementsCountThroughWall + 1) + \ - ((elementsCountAroundTC - 1)*tcCount if tcThickness > 0.0 else 0)) + ei1Centre + \ - sectorIdx*(elementsCountAroundHaustrum + elementsCountAroundTC) + elementsCountAroundTC*0.5) - \ - elementsCountAround + 1 # only for 1 layer through wall - - # Store elements and nodes to be deleted later from tracked surface - deleteElementsCountAcross = ei1Right - ei1Left + 1 - deleteElementsCountAlong = ei2Top - ei2Bottom + 1 - deleteElementIdxStart = int((elementsCountAround * elementsCountThroughWall + - (elementsCountAroundTC * tcCount if tcThickness > 0.0 else 0.0)) * - (elementsCountAlong - elementsCountAlongSegment + ei2Bottom) + - elementsCountAroundTC * 0.5 + - (elementsCountAroundTC + elementsCountAroundHaustrum) * sectorIdx + ei1Left + 1) - - deleteElementIdentifier = [] - for n2 in range(deleteElementsCountAlong): - for n1 in range(deleteElementsCountAcross): - elementIdx = deleteElementIdxStart + n1 + n2 * (elementsCountAround + - (int(elementsCountAroundTC * tcCount) - if tcThickness > 0.0 else 0)) - deleteElementIdentifier.append(elementIdx) - - deleteNodeIdxStart = nodeStart - int(deleteElementsCountAcross * 0.5) - deleteNodeIdentifier = [] - for n2 in range(deleteElementsCountAlong + 1): - for n3 in range(elementsCountThroughWall + 1): - for n1 in range(deleteElementsCountAcross + 1): - nodeIdx = deleteNodeIdxStart + n1 + elementsCountAround * n3 + \ - n2 * (elementsCountAround * (elementsCountThroughWall + 1) + - ((elementsCountAroundTC - 1) * tcCount if tcThickness > 0.0 else 0)) - deleteNodeIdentifier.append(nodeIdx) - - innerEndPoints_Id = [] - endProportions = [] - for n1 in range(ei1Centre - ei1Left + 1): - idx = nodeStart - n1 - innerEndPoints_Id.append(idx) - endProportions.append([(ei1Centre - n1)/elementsAroundTrackSurface, ei2Bottom/elementsAlongTrackSurface]) - for n2 in range(ei2Top - ei2Bottom + 1): - idx = idx + 2 * elementsCountAround + ((elementsCountAroundTC - 1) * tcCount if tcThickness > 0.0 else 0) - innerEndPoints_Id.append(idx) - endProportions.append([ei1Left/elementsAroundTrackSurface, (ei2Bottom + n2 + 1)/elementsAlongTrackSurface]) - for n1 in range(1, ei1Right - ei1Left + 2): - idx = idx + 1 - innerEndPoints_Id.append(idx) - endProportions.append([(ei1Left + n1) / elementsAroundTrackSurface, (ei2Top+1) / elementsAlongTrackSurface]) - for n2 in range(ei2Top - ei2Bottom + 1): - idx = idx - 2 * elementsCountAround - ((elementsCountAroundTC - 1) * tcCount if tcThickness > 0.0 else 0) - innerEndPoints_Id.append(idx) - endProportions.append( - [(ei1Right+1) / elementsAroundTrackSurface, (ei2Top - n2) / elementsAlongTrackSurface]) - for n1 in range(ei1Right - ei1Centre): - idx = idx - 1 - innerEndPoints_Id.append(idx) - endProportions.append([(ei1Right - n1) / elementsAroundTrackSurface, ei2Bottom / elementsAlongTrackSurface]) - - innerEndPoints_x = [] - innerEndPoints_d1 = [] - innerEndPoints_d2 = [] - - outerEndPoints_Id = [] - outerEndPoints_x = [] - outerEndPoints_d1 = [] - outerEndPoints_d2 = [] - - for i in range(len(innerEndPoints_Id)): - innerNode = innerEndPoints_Id[i] - innerEndPoints_x.append(xCecum[innerNode-1]) - innerEndPoints_d1.append(d1Cecum[innerNode - 1]) - innerEndPoints_d2.append(d2Cecum[innerNode - 1]) - - outerNode = innerNode + elementsCountAround - outerEndPoints_Id.append(outerNode) - outerEndPoints_x.append(xCecum[outerNode - 1]) - outerEndPoints_d1.append(d1Cecum[outerNode - 1]) - outerEndPoints_d2.append(d2Cecum[outerNode - 1]) - - endPoints_Id = [innerEndPoints_Id, outerEndPoints_Id] - endPoints_x = [innerEndPoints_x, outerEndPoints_x] - endPoints_d1 = [innerEndPoints_d1, outerEndPoints_d1] - endPoints_d2 = [innerEndPoints_d2, outerEndPoints_d2] - - endDerivativesMap = [[None] * len(innerEndPoints_Id), [None] * len(innerEndPoints_Id)] - count = 0 - for n1 in range(ei1Centre - ei1Left): - endDerivativesMap[0][count] = endDerivativesMap[1][count] = ((-1, 0, 0), (0, -1, 0), None) - count += 1 - - endDerivativesMap[0][count] = endDerivativesMap[1][count] = ((-1, 0, 0), (-1, -1, 0), None, (0, 1, 0)) - count += 1 - for n2 in range(ei2Top - ei2Bottom): - endDerivativesMap[0][count] = endDerivativesMap[1][count] = ((0, 1, 0), (-1, 0, 0), None) - count += 1 - endDerivativesMap[0][count] = endDerivativesMap[1][count] = ((0, 1, 0), (-1, 1, 0), None, (1, 0, 0)) - count += 1 - for n1 in range(1, ei1Right - ei1Left + 1): - endDerivativesMap[0][count] = endDerivativesMap[1][count] = ((1, 0, 0), (0, 1, 0), None) - count += 1 - endDerivativesMap[0][count] = endDerivativesMap[1][count] = ((1, 0, 0), (1, 1, 0), None, (0, -1, 0)) - count += 1 - for n2 in range(1, ei2Top - ei2Bottom + 1): - endDerivativesMap[0][count] = endDerivativesMap[1][count] = ((0, -1, 0), (1, 0, 0), None) - count += 1 - endDerivativesMap[0][count] = endDerivativesMap[1][count] = ((0, -1, 0), (1, -1, 0), None, (-1, 0, 0)) - count += 1 - for n1 in range(ei1Right - ei1Centre): - endDerivativesMap[0][count] = endDerivativesMap[1][count] = ((-1, 0, 0), (0, -1, 0), None) - count += 1 - - ostiumSettings['Number of elements around ostium'] = len(innerEndPoints_Id) - - fm = region.getFieldmodule() - mesh = fm.findMeshByDimension(3) - nodes = fm.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES) - - cecumMeshGroup = cecumGroup.getMeshGroup(mesh) - - nextNodeIdentifier, nextElementIdentifier, (o1_x, o1_d1, o1_d2, o1_d3, o1_NodeId, o1_Positions) = \ - generateOstiumMesh(region, ostiumSettings, trackSurfaceOstium, centrePosition, axis1, - nextNodeIdentifier, nextElementIdentifier, ostiumMeshGroups= [cecumMeshGroup] ) - - startProportions = [] - for n in range(len(innerEndPoints_Id)): - startProportions.append(trackSurfaceOstium.getProportion(o1_Positions[n])) - - nextNodeIdentifier, nextElementIdentifier = createAnnulusMesh3d( - nodes, mesh, nextNodeIdentifier, nextElementIdentifier, - o1_x, o1_d1, o1_d2, None, o1_NodeId, None, - endPoints_x, endPoints_d1, endPoints_d2, None, endPoints_Id, endDerivativesMap, - elementsCountRadial = 2, meshGroups = [cecumMeshGroup], tracksurface = trackSurfaceOstium, - startProportions = startProportions, endProportions = endProportions) - - # Delete elements under annulus mesh - mesh_destroy_elements_and_nodes_by_identifiers(mesh, deleteElementIdentifier) + nextNodeIdentifier = 1 + nextElementIdentifier = 1 + cls.updateSubScaffoldOptions(options) + geometricCentralPath = options['Central path'] + cecumTermsAlong = ['caecum', 'ileum'] + geometricCentralPath = CecumCentralPath(region, geometricCentralPath, cecumTermsAlong) + annotationGroups, nextNodeIdentifier, nextElementIdentifier = \ + createCecumMesh3d(region, options, geometricCentralPath, nextNodeIdentifier, + nextElementIdentifier) return annotationGroups, None @@ -1046,3 +732,1593 @@ def getElementIdxOfOstiumBoundary(centrePosition, trackSurfaceOstium, ostiumDiam return ei1Left, ei1Right, ei2Bottom, ei2Top +def findDerivativeBetweenPoints(v1, v2): + """ + Find vector difference between two points and rescale vector difference using cubic hermite arclength + between the points to derive the derivative between the points. + :param v1: start vector + :param v2: end vector + :return: derivative of between v1 and v2 + """ + d = [v2[c] - v1[c] for c in range(3)] + arcLengthAround = interp.computeCubicHermiteArcLength(v1, d, v2, d, True) + d = [c * arcLengthAround for c in vector.normalise(d)] + + return d + + +def findCurvatureAroundLoop(nx, nd, radialVectors): + """ + Calculate curvature for points lying along a loop. + :param nx: points on loop + :param nd: derivative of points on loop + :param radialVectors: radial direction, assumed normal to curve tangent at point + :return: curvatures along points on loop + """ + curvature = [] + for n in range(len(nx)): + prevIdx = n - 1 if n > 0 else -1 + nextIdx = n + 1 if n < len(nx) - 1 else 0 + kappam = interp.getCubicHermiteCurvature(nx[prevIdx], nd[prevIdx], nx[n], nd[n], radialVectors[n], 1.0) + kappap = interp.getCubicHermiteCurvature(nx[n], nd[n], nx[nextIdx], nd[nextIdx], radialVectors[n], 0.0) + curvature.append(0.5 * (kappam + kappap)) + + return curvature + +def findCurvatureAlongLine(nx, nd, radialVectors): + """ + Calculate curvature for points lying along a line. + :param nx: points on line + :param nd: derivative of points on line + :param radialVectors: radial direction, assumed normal to curve tangent at point + :return: curvatures along points on line + """ + curvature = [] + for n in range(len(nx)): + if n == 0: + curvature.append(interp.getCubicHermiteCurvature(nx[n], nd[n], nx[n + 1], nd[n + 1], radialVectors[n], 0.0)) + elif n == len(nx) - 1: + curvature.append(interp.getCubicHermiteCurvature(nx[n - 1], nd[n - 1], nx[n], nd[n], radialVectors[n], 1.0)) + else: + curvature.append(0.5 * ( + interp.getCubicHermiteCurvature(nx[n], nd[n], nx[n + 1], nd[n + 1], radialVectors[n], 0.0) + + interp.getCubicHermiteCurvature(nx[n - 1], nd[n - 1], nx[n], nd[n], radialVectors[n], 1.0))) + + return curvature + +def createCecumMesh3d(region, options, centralPath, nextNodeIdentifier, nextElementIdentifier): + """ + + """ + segmentCount = options['Number of segments'] + startPhase = 0.0 + elementsCountAroundTC = options['Number of elements around tenia coli'] + elementsCountAroundHaustrum = options['Number of elements around haustrum'] + elementsCountAlongSegment = options['Number of elements along segment'] + elementsCountThroughWall = options['Number of elements through wall'] + cornerInnerRadiusFactor = options['Corner inner radius factor'] + haustrumInnerRadiusFactor = options['Haustrum inner radius factor'] + segmentLengthEndDerivativeFactor = options['Segment length end derivative factor'] + segmentLengthMidDerivativeFactor = options['Segment length mid derivative factor'] + tcCount = options['Number of tenia coli'] + startTCWidth = options['Start tenia coli width'] + startTCWidthDerivative = options['Start tenia coli width derivative'] + endTCWidth = options['End tenia coli width'] + endTCWidthDerivative = options['End tenia coli width derivative'] + tcThickness = options['Tenia coli thickness'] + 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']) + elementsCountAlong = int(elementsCountAlongSegment * segmentCount) + elementsCountAround = (elementsCountAroundTC + elementsCountAroundHaustrum) * tcCount + + ostiumOptions = options['Ileocecal junction'] + ostiumSettings = ostiumOptions.getScaffoldSettings() + + zero = [0.0, 0.0, 0.0] + firstNodeIdentifier = nextNodeIdentifier + firstElementIdentifier = nextElementIdentifier + startNode = nextNodeIdentifier + startElement = nextElementIdentifier + + fm = region.getFieldmodule() + coordinates = findOrCreateFieldCoordinates(fm) + cache = fm.createFieldcache() + + nodes = fm.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES) + nodetemplate = nodes.createNodetemplate() + nodetemplate.defineField(coordinates) + nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_VALUE, 1) + nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D_DS1, 1) + nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D_DS2, 1) + if useCrossDerivatives: + nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D2_DS1DS2, 1) + if useCubicHermiteThroughWall: + nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D_DS3, 1) + if useCrossDerivatives: + nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D2_DS1DS3, 1) + nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D2_DS2DS3, 1) + nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D3_DS1DS2DS3, 1) + + if elementsCountThroughWall == 1: + relativeThicknessList = [1.0] + annotationGroupsThroughWall = [[]] + else: + relativeThicknessList = [mucosaRelThickness, submucosaRelThickness, + circularRelThickness, longitudinalRelThickness] + longitudinalMuscleGroup = AnnotationGroup(region, get_cecum_term("longitudinal muscle layer of cecum")) + circularMuscleGroup = AnnotationGroup(region, get_cecum_term("circular muscle layer of cecum")) + submucosaGroup = AnnotationGroup(region, get_cecum_term("submucosa of cecum")) + mucosaGroup = AnnotationGroup(region, get_cecum_term("cecum mucosa")) + annotationGroupsThroughWall = [[mucosaGroup], + [submucosaGroup], + [circularMuscleGroup], + [longitudinalMuscleGroup]] + + # Sample central path along cecum + # print(len(centralPath.cxGroups)) + cecumLength = centralPath.arcLengthOfGroupsAlong[0] + cx = centralPath.cxGroups[0] + cd1 = centralPath.cd1Groups[0] + cd2 = centralPath.cd2Groups[0] + cd12 = centralPath.cd12Groups[0] + + cxIleum = centralPath.cxGroups[1] + cd1Ileum = centralPath.cd1Groups[1] + cd2Ileum = centralPath.cd2Groups[1] + cd3Ileum = centralPath.cd3Groups[1] + cd12Ileum = centralPath.cd12Groups[1] + cd13Ileum = centralPath.cd13Groups[1] + + # xBranchPt = centralPath.xBranchPt + d2BranchPt = centralPath.d2BranchPt + + # smoothd1 = interp.smoothCubicHermiteDerivativesLine(cx, cd1, fixAllDirections=True, + # magnitudeScalingMode=interp.DerivativeScalingMode.HARMONIC_MEAN) + sxCecum, sd1Cecum, se, sxi, ssf = interp.sampleCubicHermiteCurves(cx, cd1, elementsCountAlong) + sd2Cecum, sd12Cecum = interp.interpolateSampleCubicHermite(cd2, cd12, se, sxi, ssf) + + # Calculate segment length + segmentLength = cecumLength / segmentCount + + # Generate variation of radius & tc width along length + innerRadiusAlongCecum = [] + dInnerRadiusAlongCecum = [] + tcWidthAlongCecum = [] + + closedProximalEnd = True + + innerRadiusListCP = [vector.magnitude(c) for c in cd2] + dInnerRadiusListCP = [] + for n in range(len(innerRadiusListCP) - 1): + dInnerRadiusListCP.append(innerRadiusListCP[n + 1] - innerRadiusListCP[n]) + dInnerRadiusListCP.append(innerRadiusListCP[-1] - innerRadiusListCP[-2]) + innerRadiusAlongElementList, dInnerRadiusAlongElementList = \ + interp.interpolateSampleCubicHermite(innerRadiusListCP, dInnerRadiusListCP, se, sxi, ssf) + + for n2 in range(elementsCountAlongSegment * segmentCount + 1): + xi = 1 / (elementsCountAlongSegment * segmentCount) * n2 + + radius = innerRadiusAlongElementList[n2] + innerRadiusAlongCecum.append(radius) + dRadius = dInnerRadiusAlongElementList[n2] + dInnerRadiusAlongCecum.append(dRadius) + tcWidth = interp.interpolateCubicHermite([startTCWidth], [startTCWidthDerivative], + [endTCWidth], [endTCWidthDerivative], xi)[0] + tcWidthAlongCecum.append(tcWidth) + + haustrumInnerRadiusFactorAlongCecum = [haustrumInnerRadiusFactor] * (elementsCountAlong + 1) + + xToSample = [] + d1ToSample = [] + d2ToSample = [] + + elementsCountAroundHalfHaustrum = int((elementsCountAroundTC + elementsCountAroundHaustrum) * 0.5) + + # Create object + colonSegmentTubeMeshInnerPoints = ColonSegmentTubeMeshInnerPoints( + region, elementsCountAroundTC, elementsCountAroundHaustrum, elementsCountAlongSegment, + tcCount, segmentLengthEndDerivativeFactor, segmentLengthMidDerivativeFactor, + segmentLength, wallThickness, cornerInnerRadiusFactor, haustrumInnerRadiusFactorAlongCecum, + innerRadiusAlongCecum, dInnerRadiusAlongCecum, tcWidthAlongCecum, startPhase) + + # Create annotation + cecumGroup = AnnotationGroup(region, get_cecum_term("caecum")) + annotationGroupsAlong = [] + for i in range(elementsCountAlong): + annotationGroupsAlong.append([cecumGroup]) + + for nSegment in range(segmentCount): + # Make regular segments + xInner, d1Inner, d2Inner, transitElementList, segmentAxis, annotationGroupsAround \ + = colonSegmentTubeMeshInnerPoints.getColonSegmentTubeMeshInnerPoints(nSegment) + + # Replace first half of first segment with apex and sample along apex and second half of segment + if nSegment == 0: + xFirstSegmentSampled, d1FirstSegmentSampled, d2FirstSegmentSampled, d1FirstDirectionVector = \ + getApexSegmentForCecum(xInner, d1Inner, d2Inner, elementsCountAroundHalfHaustrum, + elementsCountAroundTC, elementsCountAround, elementsCountAlongSegment, + tcCount) + + xToSample += xFirstSegmentSampled + d1ToSample += d1FirstSegmentSampled + d2ToSample += d2FirstSegmentSampled + else: + xInnerExtrude = [] + for n in range(len(xInner)): + xInnerExtrude.append([xInner[n][0], xInner[n][1], xInner[n][2] + segmentLength * nSegment]) + xToSample += xInnerExtrude[elementsCountAround:] + d1ToSample += d1Inner[elementsCountAround:] + d2ToSample += d2Inner[elementsCountAround:] + + # Sample along length + xToWarp, d1ToWarp, d2ToWarp = sampleCecumAlongLength(xToSample, d1ToSample, d2ToSample, d1FirstDirectionVector, + elementsCountAroundHalfHaustrum, elementsCountAroundTC, + elementsCountAround, elementsCountAlong, tcCount) + + # Ensure cecum starts at z = 0.0 + minZ = xToWarp[0][2] + for n2 in range(elementsCountAlong + 1): + zFirstNodeAlong = xToWarp[n2 * elementsCountAround][2] + if zFirstNodeAlong < minZ: + minZ = zFirstNodeAlong + + for n in range(len(xToWarp)): + xToWarp[n][2] = xToWarp[n][2] - minZ + + # Project reference point for warping onto central path + sxRefList, sd1RefList, sd2ProjectedListRef, zRefList = \ + tubemesh.getPlaneProjectionOnCentralPath(xToWarp, elementsCountAround, elementsCountAlong, + cecumLength, sxCecum, sd1Cecum, sd2Cecum, sd12Cecum) + + # Warp points + xWarpedList, d1WarpedList, d2WarpedList, d3WarpedUnitList = \ + tubemesh.warpSegmentPoints(xToWarp, d1ToWarp, d2ToWarp, segmentAxis, sxRefList, sd1RefList, + sd2ProjectedListRef, elementsCountAround, elementsCountAlong, zRefList) + + # Create coordinates and derivatives + wallThicknessList = [wallThickness] * (elementsCountAlong + 1) + + xList, d1List, d2List, d3List, curvatureList = \ + tubemesh.getCoordinatesFromInner(xWarpedList, d1WarpedList,d2WarpedList, d3WarpedUnitList, + wallThicknessList, relativeThicknessList, elementsCountAround, + elementsCountAlong, elementsCountThroughWall, transitElementList) + + # Deal with multiple nodes at end point for closed proximal end + xApexInner = xList[0] + # arclength between apex point and corresponding point on next face + mag = interp.getCubicHermiteArcLength(xList[0], d2List[0], + xList[elementsCountAround * (elementsCountThroughWall + 1)], + d2List[elementsCountAround * (elementsCountThroughWall + 1)]) + d2ApexInner = vector.setMagnitude(sd2Cecum[0], mag * 0.5) + d1ApexInner = vector.crossproduct3(sd1Cecum[0], d2ApexInner) + d1ApexInner = vector.setMagnitude(d1ApexInner, mag * 0.5) + d3ApexUnit = vector.normalise(vector.crossproduct3(vector.normalise(d1ApexInner), + vector.normalise(d2ApexInner))) + d3ApexInner = [d3ApexUnit[c] * wallThickness / elementsCountThroughWall for c in range(3)] + + xCecum = [] + d1Cecum = [] + d2Cecum = [] + d3Cecum = [] + + for n3 in range(elementsCountThroughWall + 1): + xApex = [xApexInner[c] + d3ApexUnit[c] * wallThickness / elementsCountThroughWall * n3 for c in range(3)] + xCecum.append(xApex) + d1Cecum.append(d1ApexInner) + d2Cecum.append(d2ApexInner) + d3Cecum.append(d3ApexInner) + + xCecum += xList[(elementsCountThroughWall + 1) * elementsCountAround:] + d1Cecum += d1List[(elementsCountThroughWall + 1) * elementsCountAround:] + d2Cecum += d2List[(elementsCountThroughWall + 1) * elementsCountAround:] + d3Cecum += d3List[(elementsCountThroughWall + 1) * elementsCountAround:] + + xFlat = d1Flat = d2Flat = [] + xOrgan = d1Organ = d2Organ = [] + + # Create nodes and elements + if tcThickness > 0: + tubeTCWidthList = colonSegmentTubeMeshInnerPoints.getTubeTCWidthList() + xCecum, d1Cecum, d2Cecum, d3Cecum, annotationArrayAround = getTeniaColi( + region, xCecum, d1Cecum, d2Cecum, d3Cecum, curvatureList, tcCount, elementsCountAroundTC, + elementsCountAroundHaustrum, elementsCountAlong, elementsCountThroughWall, + tubeTCWidthList, tcThickness, sxRefList, annotationGroupsAround, closedProximalEnd) + + nextNodeIdentifier, nextElementIdentifier, allAnnotationGroups = createNodesAndElementsTeniaColi( + region, xCecum, d1Cecum, d2Cecum, d3Cecum, xFlat, d1Flat, d2Flat, xOrgan, d1Organ, d2Organ, None, + elementsCountAroundTC, elementsCountAroundHaustrum, elementsCountAlong, elementsCountThroughWall, + tcCount, annotationGroupsAround, annotationGroupsAlong, annotationGroupsThroughWall, + firstNodeIdentifier, firstElementIdentifier, useCubicHermiteThroughWall, useCrossDerivatives, + closedProximalEnd) + + else: + nextNodeIdentifier, nextElementIdentifier, allAnnotationGroups = tubemesh.createNodesAndElements( + region, xCecum, d1Cecum, d2Cecum, d3Cecum, xFlat, d1Flat, d2Flat, xOrgan, d1Organ, d2Organ, None, + elementsCountAround, elementsCountAlong, elementsCountThroughWall, + annotationGroupsAround, annotationGroupsAlong, annotationGroupsThroughWall, + firstNodeIdentifier, firstElementIdentifier, useCubicHermiteThroughWall, useCrossDerivatives, + closedProximalEnd) + + nodeIdentifierCecum = nextNodeIdentifier + for n2 in range(len(cx)): + node = nodes.createNode(nextNodeIdentifier, nodetemplate) + cache.setNode(node) + coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, cx[n2]) + coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, cd1[n2]) + coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, cd2[n2]) + coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, [0.0, 0.0, 0.0]) + nextNodeIdentifier += 1 + + ################# + # Create elements + ################# + + mesh = fm.findMeshByDimension(1) + cubicHermiteBasis = fm.createElementbasis(1, Elementbasis.FUNCTION_TYPE_CUBIC_HERMITE) + eft = mesh.createElementfieldtemplate(cubicHermiteBasis) + elementtemplate = mesh.createElementtemplate() + elementtemplate.setElementShapeType(Element.SHAPE_TYPE_LINE) + result = elementtemplate.defineField(coordinates, -1, eft) + + elementIdentifier = nextElementIdentifier + for e in range(len(cx) - 1): + element = mesh.createElement(elementIdentifier, elementtemplate) + element.setNodesByIdentifier(eft, [nodeIdentifierCecum + e, nodeIdentifierCecum + 1 + e]) + elementIdentifier = elementIdentifier + 1 + + cx = centralPath.cxGroups[1] + cd1 = centralPath.cd1Groups[1] + cd2 = centralPath.cd2Groups[1] + + nodeIdentifierIleum = nextNodeIdentifier + for n2 in range(len(cx)): + node = nodes.createNode(nextNodeIdentifier, nodetemplate) + cache.setNode(node) + coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, cx[n2]) + coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, cd1[n2]) + coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, cd2[n2]) + coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, [0.0, 0.0, 0.0]) + nextNodeIdentifier += 1 + + for e in range(2): + element = mesh.createElement(elementIdentifier, elementtemplate) + element.setNodesByIdentifier(eft, [nodeIdentifierIleum + e, nodeIdentifierIleum + 1 + e]) + elementIdentifier = elementIdentifier + 1 + + # Add ostium on track surface + elementsAroundTrackSurface = elementsCountAroundHaustrum + elementsAlongTrackSurface = elementsCountAlongSegment + + # Find region where ostium sits + # angle between d2 of branch point and vector between branch point and 1st point on ileum + dV = [cxIleum[0][c] - cxIleum[-1][c] for c in range(3)] + ostiumPositionAngleAround = math.acos(vector.dotproduct(dV, d2BranchPt)/ + (vector.magnitude(dV) * vector.magnitude(d2BranchPt))) + sectorIdx = ostiumPositionAngleAround // (2 * math.pi / tcCount) + sectorStartAngle = sectorIdx * (2 * math.pi / tcCount) + + startIdxElementsAround = int((elementsCountAroundHaustrum + elementsCountAroundTC) * sectorIdx + + elementsCountAroundTC * 0.5) + + segmentIdx = int(centralPath.arcLengthToBranchPt // segmentLength) + + baseNodesIdx = (elementsCountThroughWall + 1) + \ + + (elementsCountAround * (elementsCountThroughWall + 1) + + ((elementsCountAroundTC - 1) * tcCount if tcThickness > 0.0 else 0)) * \ + (elementsCountAlongSegment * segmentIdx - 1) + elementsCountAround + + # Elements to delete + deleteElementIdentifier = [] + for n2 in range(elementsCountAlongSegment): + for n3 in range(elementsCountThroughWall): + for n1 in range(elementsCountAroundHaustrum): + elementIdx = \ + startIdxElementsAround + int(elementsCountAroundTC * (0.5 if tcThickness > 0.0 else 0)) + \ + n1 + (elementsCountAround * n3) + (elementsCountAround * elementsCountThroughWall + + elementsCountAroundTC * (tcCount if tcThickness > 0.0 else 0)) \ + * n2 + startElement - 1 + segmentIdx * ((elementsCountAround * n3) + + (elementsCountAround * elementsCountThroughWall + + elementsCountAroundTC * + (tcCount if tcThickness > 0.0 else 0)) * + elementsCountAlongSegment) + + deleteElementIdentifier.append(elementIdx) + + xTrackSurface = [] + d1TrackSurface = [] + d2TrackSurface = [] + nodesOnLHS = [] + nodesOnRHS = [] + nodesOnDistal = [] + nodesOnProximal = [] + + for n2 in range(elementsCountAlongSegment + 1): + for n1 in range(elementsCountAroundHaustrum + 1): + if n2 == 0 and segmentIdx == 0: + xTrackSurface.append(xApex) + d1TrackSurface.append(d1ApexInner) + d2TrackSurface.append(d2ApexInner) + else: + idx = baseNodesIdx + \ + (elementsCountAround * (elementsCountThroughWall + 1) + + ((elementsCountAroundTC - 1) * tcCount if tcThickness > 0.0 else 0)) * n2 + \ + startIdxElementsAround + n1 + (elementsCountAround * (elementsCountThroughWall - 1)) + xTrackSurface.append(xCecum[idx]) + d1TrackSurface.append(d1Cecum[idx]) + d2TrackSurface.append(d2Cecum[idx]) + + if n1 == 1: + nodeWall = [] + for n3 in range(elementsCountThroughWall, -1, -1): + nodeWall.append(idx - elementsCountAround * n3) + nodesOnLHS.append(nodeWall) + if n1 == elementsCountAroundHaustrum: + nodeWall = [] + for n3 in range(elementsCountThroughWall, -1, -1): + nodeWall.append(idx + 1 - elementsCountAround * n3) + nodesOnRHS.append(nodeWall) + if segmentIdx and n2 == 0 and n1 > 0 and n1 < elementsCountAroundHaustrum: + nodeWall = [] + for n3 in range(elementsCountThroughWall, -1, -1): + nodeWall.append(idx + 1 - elementsCountAround * n3) + nodesOnProximal.append(nodeWall) + if n2 == elementsCountAlongSegment and n1 > 0 and n1 < elementsCountAroundHaustrum: + nodeWall = [] + for n3 in range(elementsCountThroughWall, -1, -1): + nodeWall.append(idx + 1 - elementsCountAround * n3) + nodesOnDistal.append(nodeWall) + + sideNodes = [] + for n2 in range(elementsCountAlongSegment + 1): + for n3 in range(elementsCountThroughWall + 1): + if n2 == 0 and segmentIdx == 0: + sideNodes.append((n2 + 1) * (n3 + 1)) + elif segmentIdx and n2 == 0: + sideNodes.append(nodesOnLHS[n2][n3]) + for n in range(len(nodesOnProximal)): + sideNodes.append(nodesOnProximal[n][n3]) + sideNodes.append(nodesOnRHS[n2][n3]) + elif n2 == elementsCountAlongSegment: + sideNodes.append(nodesOnLHS[n2 + (0 if segmentIdx else -1)][n3]) + for n in range(len(nodesOnDistal)): + sideNodes.append(nodesOnDistal[n][n3]) + sideNodes.append(nodesOnRHS[n2 + (0 if segmentIdx else -1)][n3]) + else: + for n1 in range(2): + if n1 == 0: + sideNodes.append(nodesOnLHS[n2 + (0 if segmentIdx else -1)][n3]) + else: + sideNodes.append(nodesOnRHS[n2 + (0 if segmentIdx else -1)][n3]) + + # # Visualise track surface + # for n1 in range(len(xTrackSurface)): + # node = nodes.createNode(nextNodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xTrackSurface[n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d2TrackSurface[n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d1TrackSurface[n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, [0.0, 0.0, 0.0]) + # nextNodeIdentifier += 1 + + trackSurfaceOstium = TrackSurface(elementsAroundTrackSurface, elementsAlongTrackSurface, + xTrackSurface, d1TrackSurface, d2TrackSurface) + + # Find centre position + # track along ileum path and since cxIleum[1] could be above or below the track surface, we check both side to determine direction to track + # At each point, find the nearest position and take the diff between nearest point to the point in line, keep tracking till diff is close to zero. + xTol = 1.0E-6 + arcStart = 0.0 + arcEnd = centralPath.arcLengthOfGroupsAlong[1] + nearestPosition = trackSurfaceOstium.findNearestPosition(cxIleum[0]) + xNearestStart = trackSurfaceOstium.evaluateCoordinates(nearestPosition, derivatives=False) + distStart = vector.magnitude([cxIleum[0][c] - xNearestStart[c] for c in range(3)]) + nearestPosition = trackSurfaceOstium.findNearestPosition(cxIleum[-1]) + xNearestEnd = trackSurfaceOstium.evaluateCoordinates(nearestPosition, derivatives=False) + distEnd = vector.magnitude([cxIleum[-1][c] - xNearestEnd[c] for c in range(3)]) + + for iter in range(100): + arcDistance = (arcStart + arcEnd) * 0.5 + x, d1 = interp.getCubicHermiteCurvesPointAtArcDistance(cxIleum, cd1Ileum, arcDistance)[0:2] + nearestPosition = trackSurfaceOstium.findNearestPosition(x) + xNearest = trackSurfaceOstium.evaluateCoordinates(nearestPosition, derivatives=False) + dist = vector.magnitude([x[c] - xNearest[c] for c in range(3)]) + + if abs(distStart - distEnd) > xTol: + if distStart < distEnd: + arcEnd = arcDistance + distEnd = dist + else: + arcStart = arcDistance + distStart = dist + + else: + xCentre, d1Centre, d2Centre = trackSurfaceOstium.evaluateCoordinates(nearestPosition, derivatives=True) + normAxis = vector.normalise([-d for d in d1]) + eIdx = interp.getNearestPointIndex(cxIleum, xCentre) - 1 + arcLenghtSum = 0.0 + for e in range(eIdx): + arcLenghtSum += interp.getCubicHermiteArcLength(cxIleum[e], cd1Ileum[e], + cxIleum[e + 1], cd1Ileum[e + 1]) + xi = (arcDistance - arcLenghtSum)/\ + interp.getCubicHermiteArcLength(cxIleum[eIdx], cd1Ileum[eIdx], cxIleum[eIdx + 1], cd1Ileum[eIdx + 1]) + d2Centre = interp.interpolateCubicHermite(cd2Ileum[eIdx], cd12Ileum[eIdx], cd2Ileum[eIdx + 1], cd12Ileum[eIdx + 1], xi) + break + if iter > 98: + print('Search for ileum entry centre - Max iters reached:', iter) + + # node = nodes.createNode(nextNodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xNearest) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, [0.0, 0.0, 0.0]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, [0.0, 0.0, 0.0]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, [0.0, 0.0, 0.0]) + # print('x', nextNodeIdentifier) + # nextNodeIdentifier += 1 + + # node = nodes.createNode(nextNodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, cxIleum[eIdx]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, [0.0, 0.0, 0.0]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, cd2Ileum[eIdx]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, [0.0, 0.0, 0.0]) + # nextNodeIdentifier += 1 + # + # + # node = nodes.createNode(nextNodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, cxIleum[eIdx + 1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, [0.0, 0.0, 0.0]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, cd2Ileum[eIdx + 1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, [0.0, 0.0, 0.0]) + # nextNodeIdentifier += 1 + # + # node = nodes.createNode(nextNodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xCentre) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d1Centre) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d2Centre) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, normAxis) + # nextNodeIdentifier += 1 + + ostiumSettings['Number of elements around ostium'] = elementsCountAlongSegment + elementsCountAroundOstium = ostiumSettings['Number of elements around ostium'] + + fm = region.getFieldmodule() + mesh = fm.findMeshByDimension(3) + nodes = fm.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES) + + ileumGroup = AnnotationGroup(region, get_smallintestine_term("ileum")) + ileumMeshGroup = ileumGroup.getMeshGroup(mesh) + ileocecalJunctionGroup = AnnotationGroup(region, get_smallintestine_term("ileocecal junction")) + ileocecalJunctionMeshGroup = ileocecalJunctionGroup.getMeshGroup(mesh) + smallIntestineGroup = AnnotationGroup(region, get_smallintestine_term("small intestine")) + smallIntestineMeshGroup = smallIntestineGroup.getMeshGroup(mesh) + cecumMeshGroup = cecumGroup.getMeshGroup(mesh) + allAnnotationGroups += [ileumGroup, ileocecalJunctionGroup, smallIntestineGroup] + + ostiumWallAnnotationGroups = [] + if elementsCountThroughWall == 4: + ileumMucosaGroup = AnnotationGroup(region, get_smallintestine_term("mucosa of ileum")) + ileumSubmucosaGroup = AnnotationGroup(region, get_smallintestine_term("submucosa of ileum")) + ileumCircularGroup = AnnotationGroup(region, get_smallintestine_term("circular muscle layer of ileum")) + ileumLongitudinalGroup = AnnotationGroup(region, + get_smallintestine_term("longitudinal muscle layer of ileum")) + + ostiumWallAnnotationGroups = [[ileumMucosaGroup, mucosaGroup], + [ileumSubmucosaGroup, submucosaGroup], + [ileumCircularGroup, circularMuscleGroup], + [ileumLongitudinalGroup, longitudinalMuscleGroup]] + + allAnnotationGroups += [ileumMucosaGroup, ileumSubmucosaGroup, + ileumCircularGroup, ileumLongitudinalGroup] + + # Points from track surface and vessel end + xPath = [cxIleum[0], xCentre] + d1Path = [cd1Ileum[0], [-d for d in normAxis]] + d2Path = [cd2Ileum[0], d2Centre] + d3Path = [cd3Ileum[0], [-d for d in d1Centre]] + d12Path = [cd2Ileum[0], [0.0, 0.0, 0.0]] + d13Path = [cd3Ileum[0], [0.0, 0.0, 0.0]] + + centralPathIleum = CustomCentralPath(xPath, d1Path, d2Path, d3Path, d12Path, d13Path) + + # for n in range(2): + # node = nodes.createNode(nextNodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xPath[n]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d1Path[n]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d2Path[n]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, d3Path[n]) + # nextNodeIdentifier += 1 + + nextNodeIdentifier, nextElementIdentifier, (o1_x, o1_d1, o1_d2, o1_d3, o1_NodeId, o1_Positions) = \ + generateOstiumMesh(region, ostiumSettings, trackSurfaceOstium, centralPathIleum, + startNodeIdentifier=nextNodeIdentifier, startElementIdentifier=nextElementIdentifier, + vesselMeshGroups=[[cecumMeshGroup, smallIntestineMeshGroup, ileumMeshGroup]], + ostiumMeshGroups=[cecumMeshGroup, ileocecalJunctionMeshGroup], + wallAnnotationGroups=ostiumWallAnnotationGroups, coordinates=None) + + ostiumFaceStartNode = nextNodeIdentifier + ostiumFaceStartElement = nextElementIdentifier + + # Create location of annulus + xAnnulusOuter = [[] for x in range(elementsCountAroundOstium)] + xAnnulusOuterPosition = [[] for x in range(elementsCountAroundOstium)] + d1AnnulusNorm = [] + d1AnnulusOuter = [] + e1Left = elementsAroundTrackSurface + e1Right = 0 + e2Top = 0 + e2Bottom = elementsAlongTrackSurface + sf = vector.magnitude(centralPathIleum.cd2Path[-1]) * 0.25 + for n1 in range(elementsCountAroundOstium): + normD2 = vector.normalise(o1_d2[-1][n1]) + d1AnnulusNorm.append(normD2) + d1AnnulusOuter.append(vector.setMagnitude(o1_d2[-1][n1], sf)) + x = [o1_x[-1][n1][c] + sf * normD2[c] for c in range(3)] + nearestPosition = trackSurfaceOstium.findNearestPosition(x) + e1 = nearestPosition.e1 + e2 = nearestPosition.e2 + if e1 < e1Left: + e1Left = e1 + if e1 > e1Right: + e1Right = e1 + if e2 > e2Top: + e2Top = e2 + if e2 < e2Bottom: + e2Bottom = e2 + xAnnulusOuterPosition[n1] = nearestPosition + xAnnulusOuter[n1] = trackSurfaceOstium.evaluateCoordinates(nearestPosition) + + d2AnnulusOuter = [] + for n in range(elementsCountAlongSegment): + d = findDerivativeBetweenPoints(xAnnulusOuter[n], xAnnulusOuter[(n + 1) % elementsCountAroundOstium]) + d2AnnulusOuter.append(d) + d2AnnulusOuter = interp.smoothCubicHermiteDerivativesLoop(xAnnulusOuter, d2AnnulusOuter) + d3Annulus = [] + for n in range(elementsCountAroundOstium): + d3 = vector.normalise(vector.crossproduct3(vector.normalise(d2AnnulusOuter[n]), d1AnnulusNorm[n])) + d3Annulus.append(d3) + annulusD2Curvature = findCurvatureAroundLoop(xAnnulusOuter, d2AnnulusOuter, d3Annulus) + + # # Visualise annulus + # for n1 in range(len(xAnnulusOuter)): + # node = nodes.createNode(nextNodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xAnnulusOuter[n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d1AnnulusOuter[n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d2AnnulusOuter[n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, [0.0, 0.0, 0.0]) + # nextNodeIdentifier += 1 + + # base row counts with 8 elements around ostium + rowsIncrement = int((elementsCountAlongSegment - 8) / 4) + rowsAbove = 1 + rowsIncrement + rowsOstium = 4 + rowsIncrement * 2 + rowsBelow = 3 + rowsIncrement + + # # rowIdx along segment + startRowIdx = rowsBelow + 1 + endRowIdx = rowsBelow + rowsOstium - 1 + + # sample along the midline of ostium + rotAngle = math.pi + rotFrame = matrix.getRotationMatrixFromAxisAngle(d3ApexUnit, rotAngle) + d1A = [rotFrame[j][0] * d1Cecum[1][0] + rotFrame[j][1] * d1Cecum[1][1] + + rotFrame[j][2] * d1Cecum[1][2] for j in range(3)] + + rotAngle = math.pi + rotFrame = matrix.getRotationMatrixFromAxisAngle(vector.normalise(d3Annulus[0]), rotAngle) + d2B = [rotFrame[j][0] * d1AnnulusOuter[0][0] + rotFrame[j][1] * d1AnnulusOuter[0][1] + + rotFrame[j][2] * d1AnnulusOuter[0][2] for j in range(3)] + + # sample along from apex to annulus start + if segmentIdx == 0: + xStart = xCecum[1] + else: + idx = int(elementsAroundTrackSurface * 0.5) + xStart = xTrackSurface[idx] + + xPositionA = trackSurfaceOstium.findNearestPosition(xStart) + xProportionA = trackSurfaceOstium.getProportion(xPositionA) + derivativeA = trackSurfaceOstium.evaluateCoordinates(xPositionA, derivatives=True)[2] + + xPositionB = trackSurfaceOstium.findNearestPosition(xAnnulusOuter[0]) + xProportionB = trackSurfaceOstium.getProportion(xPositionB) + derivativeB = d2B + derivativeMagnitudeB = vector.magnitude(derivativeB) + + nx, nd1, nd2, nd3, proportions = \ + trackSurfaceOstium.createHermiteCurvePoints( + xProportionA[0], xProportionA[1], xProportionB[0], xProportionB[1], + rowsBelow + 1, derivativeStart=derivativeA, derivativeEnd=derivativeB) + + pxAlongMidLine, pd2AlongMidLine, pd1AlongMidLine = \ + trackSurfaceOstium.resampleHermiteCurvePointsSmooth( + nx, nd1, nd2, nd3, proportions, + derivativeMagnitudeEnd=derivativeMagnitudeB)[0:3] + + for n in range(len(pd1AlongMidLine)): + pd1AlongMidLine[n] = [-d for d in pd1AlongMidLine[n]] + + # for n1 in range(len(nx)): + # node = nodes.createNode(nextNodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, nx[n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, nd2[n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, [0.0, 0.0, 0.0]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, [0.0, 0.0, 0.0]) + # # print(n1, nextNodeIdentifier) + # nextNodeIdentifier += 1 + + # Apex half + # print(startRowIdx) + # pxAlongMidLine, pd2AlongMidLine = \ + # interp.sampleCubicHermiteCurvesSmooth( + # nx, nd2, rowsBelow + 1, + # # derivativeMagnitudeStart=vector.magnitude([nx[1][c] - nx[0][c] for c in range(3)]), + # derivativeMagnitudeEnd=vector.magnitude(d2B))[:2] + + # for n1 in range(len(pxAlongMidLine)): + # node = nodes.createNode(nextNodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, pxAlongMidLine[n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, pd2AlongMidLine[n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, pd1AlongMidLine[n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, [0.0, 0.0, 0.0]) + # nextNodeIdentifier += 1 + + # Next haustrum half + # nx = [xAnnulusOuter[int(elementsCountAlongSegment * 0.5)]] + # nd2 = [d1AnnulusOuter[int(elementsCountAlongSegment * 0.5)]] + # nd1 = [d2AnnulusOuter[int(elementsCountAlongSegment * 0.5)]] + # + # for n in range(elementsAlongTrackSurface - e2Top): + # n1 = e2Top + 1 + n + # idx = elementsCountAroundHalfHaustrum + n1 * (elementsCountAroundHaustrum + 1) - 1 + # nx.append(xTrackSurface[idx]) + # nd2.append(d2TrackSurface[idx]) + # nd1.append(d1TrackSurface[idx]) + # + # pxAlongMidLineBottom, pd2AlongMidLineBottom, pe, pxi, psf = \ + # interp.sampleCubicHermiteCurvesSmooth( + # nx, nd2, rowsAbove + 1, + # derivativeMagnitudeStart=vector.magnitude(nd2[0]), + # derivativeMagnitudeEnd=vector.magnitude(nd2[-1])) + # + # pd1AlongMidLineBottom = nd1 + + xPositionA = trackSurfaceOstium.findNearestPosition(xAnnulusOuter[int(elementsCountAlongSegment * 0.5)]) + xProportionA = trackSurfaceOstium.getProportion(xPositionA) + xA, derivative2A, derivativeA = trackSurfaceOstium.evaluateCoordinates(xPositionA, derivatives=True) + derivativeMagnitudeA = vector.magnitude(d2AnnulusOuter[int(elementsCountAlongSegment * 0.5)]) # derivativeA) + + xB = xTrackSurface[-elementsCountAroundHalfHaustrum] + xPositionB = trackSurfaceOstium.findNearestPosition(xB) + xProportionB = trackSurfaceOstium.getProportion(xPositionB) + derivativeB = d2TrackSurface[-elementsCountAroundHalfHaustrum] + + nx, nd1, nd2, nd3, proportions = \ + trackSurfaceOstium.createHermiteCurvePoints( + xProportionA[0], xProportionA[1], xProportionB[0], xProportionB[1], + rowsAbove + 1, derivativeStart=derivativeA, derivativeEnd=derivativeB) + + pxAlongMidLineBottom, pd2AlongMidLineBottom, pd1AlongMidLineBottom = \ + trackSurfaceOstium.resampleHermiteCurvePointsSmooth( + nx, nd1, nd2, nd3, proportions, derivativeMagnitudeStart=derivativeMagnitudeA, + derivativeMagnitudeEnd=derivativeMagnitudeA)[0:3] + + for n in range(len(pd1AlongMidLineBottom)): + pd1AlongMidLineBottom[n] = [-d for d in pd1AlongMidLineBottom[n]] + + # for n1 in range(len(pxAlongMidLineBottom)): + # node = nodes.createNode(nextNodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, pxAlongMidLineBottom[n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, pd2AlongMidLineBottom[n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, pd1AlongMidLineBottom[n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, [0.0, 0.0, 0.0]) + # nextNodeIdentifier += 1 + + # sample points around colon to ostium + annulusIdx = 1 + xAroundAlong = [] + d1AroundAlong = [] + + sideElements = int(elementsCountAroundHaustrum * 0.5) + for n2 in range(elementsCountAlongSegment): + xAround = [] + d1Around = [] + if n2 == 0 and segmentIdx == 0: + for n1 in range(elementsCountAroundHaustrum + 1): + xAround.append(xApex) + d1Around.append(d1A) + else: + for n in range(2): + # LHS + if n == 0: + xPositionA = trackSurfaceOstium.findNearestPosition( + xTrackSurface[n2 * (elementsCountAroundHaustrum + 1)]) + xProportionA = trackSurfaceOstium.getProportion(xPositionA) + derivativeA = d1TrackSurface[n2 * (elementsCountAroundHaustrum + 1)] + + if n2 < rowsBelow + 1: + xPositionB = trackSurfaceOstium.findNearestPosition(pxAlongMidLine[n2]) + derivativeB = None + + elif n2 >= rowsBelow + rowsOstium: + idx = n2 - (rowsBelow + rowsOstium) + 1 + xPositionB = trackSurfaceOstium.findNearestPosition(pxAlongMidLineBottom[idx]) + derivativeB = None + + else: + xPositionB = trackSurfaceOstium.findNearestPosition(xAnnulusOuter[annulusIdx]) + rotAngle = math.pi + rotFrame = matrix.getRotationMatrixFromAxisAngle(vector.normalise(d3Annulus[annulusIdx]), + rotAngle) + derivativeB = [rotFrame[j][0] * d1AnnulusOuter[annulusIdx][0] + + rotFrame[j][1] * d1AnnulusOuter[annulusIdx][1] + + rotFrame[j][2] * d1AnnulusOuter[annulusIdx][2] for j in range(3)] + + xProportionB = trackSurfaceOstium.getProportion(xPositionB) + + # node = nodes.createNode(nextNodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xTrackSurface[n2 * (elementsCountAroundHaustrum + 1)]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, [0.0, 0.0, 0.0]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, derivativeA) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, [0.0, 0.0, 0.0]) + # nextNodeIdentifier += 1 + # + # node = nodes.createNode(nextNodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xB) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, [0.0, 0.0, 0.0]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, derivativeB) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, [0.0, 0.0, 0.0]) + # nextNodeIdentifier += 1 + + else: # RHS + if n2 < rowsBelow + 1: + xPositionA = trackSurfaceOstium.findNearestPosition(pxAlongMidLine[n2]) + derivativeA = None + + elif n2 >= rowsBelow + rowsOstium: + idx = n2 - (rowsBelow + rowsOstium) + 1 + xPositionA = trackSurfaceOstium.findNearestPosition(pxAlongMidLineBottom[idx]) + derivativeA = None + + else: + xPositionA = trackSurfaceOstium.findNearestPosition(xAnnulusOuter[-annulusIdx]) + derivativeA = d1AnnulusOuter[-annulusIdx] + xProportionA = trackSurfaceOstium.getProportion(xPositionA) + + xPositionB = trackSurfaceOstium.findNearestPosition( + xTrackSurface[n2 * (elementsCountAroundHaustrum + 1) + elementsCountAroundHaustrum]) + xProportionB = trackSurfaceOstium.getProportion(xPositionB) + derivativeB = d1TrackSurface[n2 * (elementsCountAroundHaustrum + 1) + elementsCountAroundHaustrum] + + nx, nd1, nd2, nd3, proportions = \ + trackSurfaceOstium.createHermiteCurvePoints( + xProportionA[0], xProportionA[1], xProportionB[0], xProportionB[1], + sideElements +(0 if (n2 < rowsBelow + 1 or n2 >= rowsBelow + rowsOstium) else -1), + derivativeStart=derivativeA, derivativeEnd=derivativeB) + + nx, nd1 = \ + trackSurfaceOstium.resampleHermiteCurvePointsSmooth( + nx, nd1, nd2, nd3, proportions)[0:2] + + # for n in range(len(nx)): + # node = nodes.createNode(nextNodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, nx[n]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, nd1[n]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, [0.0, 0.0, 0.0]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, [0.0, 0.0, 0.0]) + # nextNodeIdentifier += 1 + + if n2 == rowsBelow + 1 or n2 == rowsBelow + rowsOstium - 1: + mag = 0.5 * (vector.magnitude(d1AnnulusOuter[0]) + vector.magnitude( + d2AnnulusOuter[0])) if n2 == startRowIdx else vector.magnitude(d1AnnulusOuter[0]) + if n == 0: + nd1[-1] = vector.setMagnitude(nd1[-1], mag) + else: + nd1[0] = vector.setMagnitude(nd1[0], mag) + if n == 0: + xAround += nx + d1Around += nd1 + else: + xAround += nx[(1 if (n2 < rowsBelow + 1 or n2 >= rowsBelow + rowsOstium) else 0):] + d1Around += nd1[(1 if (n2 < rowsBelow + 1 or n2 >= rowsBelow + rowsOstium) else 0):] + if n2 < rowsBelow + 1 or n2 >= rowsBelow + rowsOstium: + d1Around = interp.smoothCubicHermiteDerivativesLine(xAround, d1Around, fixStartDerivative=True, + fixEndDerivative=True) + + if n2 >= rowsBelow + 1 and n2 < rowsBelow + rowsOstium: + annulusIdx += 1 + + xAroundAlong.append(xAround) + d1AroundAlong.append(d1Around) + + xAround = [] + d1Around = [] + for n1 in range(elementsCountAroundHaustrum + 1): + xAround.append(xTrackSurface[n1 + (elementsCountAroundHaustrum + 1) * elementsCountAlongSegment]) + d1Around.append(d1TrackSurface[n1 + (elementsCountAroundHaustrum + 1) * elementsCountAlongSegment]) + xAroundAlong.append(xAround) + d1AroundAlong.append(d1Around) + + # Calculate d2 along segment + d2AroundAlong = [] + xAlongAll = [] + d2AlongAll = [] + + for n2 in range(len(xAroundAlong)): + d2Around = [] + for n1 in range(len(xAroundAlong[n2])): + d2Around.append([0.0, 0.0, 0.0]) + d2AroundAlong.append(d2Around) + + for n1 in range(elementsCountAroundHaustrum + 1): + nxAlong = [] + nd2Along = [] + if n1 < elementsCountAroundHalfHaustrum - 1: + for n2 in range(elementsCountAlongSegment): + nxAlong.append(xAroundAlong[n2][n1]) + nd2Along.append(findDerivativeBetweenPoints(xAroundAlong[n2][n1], xAroundAlong[n2 + 1][n1])) + nxAlong.append(xAroundAlong[n2 + 1][n1]) + nd2Along.append(d2TrackSurface[(elementsCountAroundHaustrum + 1) * elementsCountAlongSegment + n1]) + nd2Along = interp.smoothCubicHermiteDerivativesLine(nxAlong, nd2Along, fixStartDerivative=True, + fixEndDerivative=True) + + # Replace d2 on node along annulus LHS with d2Annulus + if n1 == elementsCountAroundHalfHaustrum - 2: + nd2Along[startRowIdx] = d2AnnulusOuter[1] + nd2Along[endRowIdx] = d2AnnulusOuter[int(elementsCountAroundOstium * 0.5) - 1] + + xAlongAll.append(nxAlong) + d2AlongAll.append(nd2Along) + + for n2 in range(len(nd2Along)): + d2AroundAlong[n2][n1] = nd2Along[n2] + + elif n1 == elementsCountAroundHalfHaustrum - 1: + for n2 in range(len(pxAlongMidLine)): + d2AroundAlong[n2][n1] = pd2AlongMidLine[n2] + for n in range(1, len(pxAlongMidLineBottom)): + d2AroundAlong[n + endRowIdx][n1] = pd2AlongMidLineBottom[n] + nxAlong = pxAlongMidLine + pxAlongMidLineBottom + xAlongAll.append(nxAlong) + d2AlongAll.append(pd2AlongMidLine + pd2AlongMidLineBottom) + + else: + for n2 in range(elementsCountAlongSegment): + nxAlong.append(xAroundAlong[n2][n1 + (0 if (n2 < startRowIdx or n2 > endRowIdx) else -1)]) + if n2 < startRowIdx - 1 or n2 > endRowIdx -1: + nxAlongNext = xAroundAlong[n2 + 1][n1] + else: + nxAlongNext = xAroundAlong[n2 + 1][n1 - 1] + nd2Along.append(findDerivativeBetweenPoints( + xAroundAlong[n2][n1 + (0 if (n2 < startRowIdx or n2 > endRowIdx) else -1)], nxAlongNext)) + + nxAlong.append(xAroundAlong[n2 + 1][n1]) + nd2Along.append(d2TrackSurface[(elementsCountAroundHaustrum + 1) * elementsCountAlongSegment + n1]) + nd2Along = interp.smoothCubicHermiteDerivativesLine(nxAlong, nd2Along, fixStartDerivative=True, + fixEndDirection=True) + + # Replace d2 on node along annulus RHS with d2Annulus + if n1 == elementsCountAroundHalfHaustrum: + nd2Along[startRowIdx] = [-d for d in d2AnnulusOuter[-1]] + nd2Along[endRowIdx] = [-d for d in d2AnnulusOuter[int(elementsCountAroundOstium * 0.5) + 1]] + + xAlongAll.append(nxAlong) + d2AlongAll.append(nd2Along) + + for n2 in range(len(nd2Along)): + if n2 < startRowIdx or n2 > endRowIdx: + n1Idx = n1 + else: + n1Idx = n1 - 1 + d2AroundAlong[n2][n1Idx] = nd2Along[n2] + + # Calculate d3 + d3UnitAroundAlong = [] + for n2 in range(len(xAroundAlong)): + d3Around = [] + for n1 in range(len(xAroundAlong[n2])): + d3Around.append(vector.normalise( + vector.crossproduct3(vector.normalise(d1AroundAlong[n2][n1]), + vector.normalise(d2AroundAlong[n2][n1])))) + d3UnitAroundAlong.append(d3Around) + + # for n2 in range(len(xAroundAlong)): + # for n1 in range(len(xAroundAlong[n2])): + # node = nodes.createNode(nextNodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xAroundAlong[n2][n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d1AroundAlong[n2][n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d2AroundAlong[n2][n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, d3UnitAroundAlong[n2][n1]) + # nextNodeIdentifier += 1 + + # Calculate curvatures + # Curvatures around + d1Curvature = [] + if segmentIdx == 0: + d1Curvature.append([0.0]) + + for n2 in range(1 if segmentIdx == 0 else 0, elementsCountAlongSegment + 1): + if n2 < startRowIdx or n2 == elementsCountAlongSegment: + d1Curvature.append(findCurvatureAlongLine(xAroundAlong[n2], d1AroundAlong[n2], d3UnitAroundAlong[n2])) + else: + d1CurvatureLeft = findCurvatureAlongLine(xAroundAlong[n2][:int(0.5 * len(xAroundAlong[n2]))], + d1AroundAlong[n2][:int(0.5 * len(xAroundAlong[n2]))], + d3UnitAroundAlong[n2][:int(0.5 * len(xAroundAlong[n2]))]) + + d1CurvatureRight = findCurvatureAlongLine(xAroundAlong[n2][int(0.5 * len(xAroundAlong[n2])):], + d1AroundAlong[n2][int(0.5 * len(xAroundAlong[n2])):], + d3UnitAroundAlong[n2][int(0.5 * len(xAroundAlong[n2])):]) + + d1Curvature.append(d1CurvatureLeft + d1CurvatureRight) + + # Curvatures along + d2Curvature = [] + for n2 in range(len(xAroundAlong)): + d2CurvatureAround = [] + for n1 in range(len(xAroundAlong[n2])): + d2CurvatureAround.append(0.0) + d2Curvature.append(d2CurvatureAround) + + for n1 in range(elementsCountAroundHaustrum + 1): + xAlong = xAlongAll[n1] + d2Along = d2AlongAll[n1] + d3UnitAlong = [] + + if n1 < elementsCountAroundHalfHaustrum - 1: + for n2 in range(elementsCountAlongSegment): + d3UnitAlong.append(d3UnitAroundAlong[n2][n1]) + d3UnitAlong.append(d3UnitAroundAlong[n2 + 1][n1]) + d2CurvatureAlong = findCurvatureAlongLine(xAlong, d2Along, d3UnitAlong) + # Adjust for corners + if n1 == elementsCountAroundHalfHaustrum - 2: + d2CurvatureAlong[endRowIdx] = annulusD2Curvature[int(elementsCountAlongSegment * 0.5) - 1] + + for n2 in range(len(d2CurvatureAlong)): + d2Curvature[n2][n1] = d2CurvatureAlong[n2] + + elif n1 == elementsCountAroundHalfHaustrum - 1: + xAlong = [] + d2Along = [] + d3UnitAlong = [] + for n2 in range(len(pd2AlongMidLine)): + xAlong.append(xAroundAlong[n2][n1]) + d2Along.append(d2AroundAlong[n2][n1]) + d3UnitAlong.append(d3UnitAroundAlong[n2][n1]) + d2CurvatureAlong = findCurvatureAlongLine(xAlong, d2Along, d3UnitAlong) + for n2 in range(len(pd2AlongMidLine)): + d2Curvature[n2][n1] = d2CurvatureAlong[n2] + + # Calculate curvature for node on edge + xAlong = [] + d2Along = [] + d3UnitAlong = [] + for n in range(1, len(pd2AlongMidLineBottom)): + nIdx = n + endRowIdx + xAlong.append(xAroundAlong[nIdx][n1]) + d2Along.append(d2AroundAlong[nIdx][n1]) + d3UnitAlong.append(d3UnitAroundAlong[nIdx][n1]) + d2CurvatureAlong = findCurvatureAlongLine(xAlong, d2Along, d3UnitAlong) + for n in range(len(pd2AlongMidLineBottom) - 1): + nIdx = n + endRowIdx + 1 + d2Curvature[nIdx][n1] = d2CurvatureAlong[n] + else: + for n2 in range(elementsCountAlongSegment): + d3UnitAlong.append(d3UnitAroundAlong[n2][n1 + (0 if (n2 < startRowIdx or n2 > endRowIdx) else -1)]) + d3UnitAlong.append(d3UnitAroundAlong[n2 + 1][n1]) + d2CurvatureAlong = findCurvatureAlongLine(xAlong, d2Along, d3UnitAlong) + + # Adjust for corners + if n1 == elementsCountAroundHalfHaustrum: + d2CurvatureAlong[endRowIdx] = annulusD2Curvature[int(elementsCountAlongSegment * 0.5) + 1] + + for n2 in range(len(d2CurvatureAlong)): + if n2 < startRowIdx or n2 > endRowIdx: + n1Idx = n1 + else: + n1Idx = n1 - 1 + d2Curvature[n2][n1Idx] = d2CurvatureAlong[n2] + + # Slot in annulus points along the midline + rotFrame = matrix.getRotationMatrixFromAxisAngle(d3Annulus[0], math.pi) + rotD2 = [rotFrame[j][0] * d2AnnulusOuter[0][0] + rotFrame[j][1] * d2AnnulusOuter[0][1] + + rotFrame[j][2] * d2AnnulusOuter[0][2] for j in range(3)] + xAroundAlong[startRowIdx].insert(int(elementsCountAroundHaustrum * 0.5), xAnnulusOuter[0]) + d1AroundAlong[startRowIdx].insert(int(elementsCountAroundHaustrum * 0.5), rotD2) + d2AroundAlong[startRowIdx].insert(int(elementsCountAroundHaustrum * 0.5), d1AnnulusOuter[0]) + d3UnitAroundAlong[startRowIdx].insert(int(elementsCountAroundHaustrum * 0.5), d3Annulus[0]) + d1Curvature[startRowIdx].insert(int(elementsCountAroundHaustrum * 0.5), annulusD2Curvature[0]) + d2Curvature[startRowIdx].insert(int(elementsCountAroundHaustrum * 0.5), annulusD2Curvature[0]) + + idx = int(elementsCountAlongSegment * 0.5) + xAroundAlong[endRowIdx].insert(int(elementsCountAroundHaustrum * 0.5), xAnnulusOuter[idx]) + d1AroundAlong[endRowIdx].insert(int(elementsCountAroundHaustrum * 0.5), d2AnnulusOuter[idx]) + d2AroundAlong[endRowIdx].insert(int(elementsCountAroundHaustrum * 0.5), d1AnnulusOuter[idx]) + d3UnitAroundAlong[endRowIdx].insert(int(elementsCountAroundHaustrum * 0.5), d3Annulus[idx]) + d1Curvature[endRowIdx].insert(int(elementsCountAroundHaustrum * 0.5), annulusD2Curvature[idx]) + d2Curvature[endRowIdx].insert(int(elementsCountAroundHaustrum * 0.5), annulusD2Curvature[idx]) + + # for n2 in range(len(xAroundAlong)): + # for n1 in range(len(xAroundAlong[n2])): + # node = nodes.createNode(nextNodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xAroundAlong[n2][n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d1AroundAlong[n2][n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d2AroundAlong[n2][n1]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, d3UnitAroundAlong[n2][n1]) + # nextNodeIdentifier += 1 + + # Create inner nodes + sideNodesToDelete = [] + xList = [] + d1List = [] + d2List = [] + d3List = [] + nodeIdx = ostiumFaceStartNode + idxMat = [] + + if elementsCountThroughWall > 1: + thicknessProportionsUI = [0.0, mucosaRelThickness, submucosaRelThickness, circularRelThickness, + longitudinalRelThickness, longitudinalRelThickness] + thicknessProportions = [thicknessProportion / sum(thicknessProportionsUI[:-1]) + for thicknessProportion in thicknessProportionsUI] + + xi3List = [] + xi3 = 0.0 + for i in range(len(thicknessProportions) - 1): + xi3 += thicknessProportions[i] + xi3List.append(xi3) + + count = 0 + for n2 in range(len(xAroundAlong)): + idxThroughWall = [] + for n3 in range(elementsCountThroughWall + 1): + xi3 = xi3List[n3] if elementsCountThroughWall > 1 else 1.0 / elementsCountThroughWall * n3 + idxAround = [] + + for n1 in range(1 if (n2 == 0 and segmentIdx == 0) else len(xAroundAlong[n2])): + if n1 == 0 or n1 == len(xAroundAlong[n2]) - 1: + sideNodesToDelete.append(nodeIdx) + newNodeIdx = sideNodes[count] + startNode - 1 + count += 1 + + elif n2 == 0 and segmentIdx and n1 > 0 and n1 < len(xAroundAlong[n2]) - 1: + sideNodesToDelete.append(nodeIdx) + newNodeIdx = sideNodes[count] + startNode - 1 + count += 1 + + elif n2 == len(xAroundAlong) - 1 and n1 > 0 and n1 < len(xAroundAlong[n2]) - 1: + sideNodesToDelete.append(nodeIdx) + newNodeIdx = sideNodes[count] + startNode - 1 + count += 1 + + else: + newNodeIdx = nodeIdx + + # Coordinates + norm = d3UnitAroundAlong[n2][n1] + xOut = xAroundAlong[n2][n1] + xIn = [xOut[i] - norm[i] * wallThickness for i in range(3)] + dWall = [wallThickness * c for c in norm] + x = interp.interpolateCubicHermite(xIn, dWall, xOut, dWall, xi3) + xList.append(x) + + # d1 + factor = 1.0 + wallThickness * (1.0 - xi3) * d1Curvature[n2][n1] + d1 = [factor * c for c in d1AroundAlong[n2][n1]] + d1List.append(d1) + + # d2 + factor = 1.0 + wallThickness * (1.0 - xi3) * d2Curvature[n2][n1] + d2 = [factor * c for c in d2AroundAlong[n2][n1]] + d2List.append(d2) + + # d3 + d3 = [c * wallThickness * (thicknessProportions[n3 + 1] if elementsCountThroughWall > 1 else 1.0) + for c in norm] + d3List.append(d3) + + idxAround.append(newNodeIdx) + nodeIdx += 1 + idxThroughWall.append(idxAround) + idxMat.append(idxThroughWall) + + for n in range(len(xList)): + if nextNodeIdentifier in sideNodesToDelete: + nextNodeIdentifier += 1 + continue + else: + node = nodes.createNode(nextNodeIdentifier, nodetemplate) + cache.setNode(node) + coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xList[n]) + coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d1List[n]) + coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d2List[n]) + coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, d3List[n]) + if useCrossDerivatives: + coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D2_DS1DS2, 1, zero) + coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D2_DS1DS3, 1, zero) + coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D2_DS2DS3, 1, zero) + coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D3_DS1DS2DS3, 1, zero) + nextNodeIdentifier += 1 + + # Create elements + elementIdxMat = [] + + if useCubicHermiteThroughWall: + eftfactory = eftfactory_tricubichermite(mesh, useCrossDerivatives) + else: + eftfactory = eftfactory_bicubichermitelinear(mesh, useCrossDerivatives) + eftStandard = eftfactory.createEftBasic() + + elementtemplateStandard = mesh.createElementtemplate() + elementtemplateStandard.setElementShapeType(Element.SHAPE_TYPE_CUBE) + elementtemplateStandard.defineField(coordinates, -1, eftStandard) + + elementtemplateX = mesh.createElementtemplate() + elementtemplateX.setElementShapeType(Element.SHAPE_TYPE_CUBE) + + radiansPerElementAround = math.pi * 2.0 / elementsCountAround + elementIdentifier = ostiumFaceStartElement + + for e2 in range(elementsCountAlongSegment): + elementIdxThroughWall = [] + if segmentIdx == 0 and e2 == 0: # pole + for e3 in range(elementsCountThroughWall): + elementIdxAround = [] + for e1 in range(elementsCountAroundHaustrum): + va = e1 + startIdxElementsAround + vb = (e1 + startIdxElementsAround + 1) + eft1 = eftfactory.createEftShellPoleBottom(va * 100, vb * 100) + elementtemplateX.defineField(coordinates, -1, eft1) + element = mesh.createElement(elementIdentifier, elementtemplateX) + bni1 = e3 + 1 + startNode - 1 + bni2 = idxMat[e2 + 1][e3][e1] + bni3 = idxMat[e2 + 1][e3][e1 + 1] + bni4 = bni1 + 1 + bni5 = idxMat[e2 + 1][e3 + 1][e1] + bni6 = idxMat[e2 + 1][e3 + 1][e1 + 1] + nodeIdentifiers = [bni1, bni2, bni3, bni4, bni5, bni6] + element.setNodesByIdentifier(eft1, nodeIdentifiers) + # set general linear map coefficients + radiansAround = (e1 + 1) * radiansPerElementAround + sectorStartAngle + radiansAroundNext = (e1 + 2) * radiansPerElementAround + sectorStartAngle + scalefactors = [ + -1.0, + math.sin(radiansAround), math.cos(radiansAround), radiansPerElementAround, + math.sin(radiansAroundNext), math.cos(radiansAroundNext), radiansPerElementAround, + math.sin(radiansAround), math.cos(radiansAround), radiansPerElementAround, + math.sin(radiansAroundNext), math.cos(radiansAroundNext), radiansPerElementAround] + element.setScaleFactors(eft1, scalefactors) + elementIdxAround.append(elementIdentifier) + elementIdentifier += 1 + annotationGroups = annotationGroupsAlong[e2] + annotationGroupsThroughWall[e3] + if annotationGroups: + allAnnotationGroups = mergeAnnotationGroups(allAnnotationGroups, annotationGroups) + for annotationGroup in annotationGroups: + meshGroup = annotationGroup.getMeshGroup(mesh) + meshGroup.addElement(element) + elementIdxThroughWall.append(elementIdxAround) + elementIdxMat.append(elementIdxThroughWall) + else: + for e3 in range(elementsCountThroughWall): + elementIdxAround = [] + for e1 in range(len(xAroundAlong[e2]) - 1): + offset = 0 + if endRowIdx - startRowIdx > 1: + if e2 == startRowIdx and e1 > int(0.5 * len(xAroundAlong[e2])): + offset = -1 + elif e2 == endRowIdx - 1 and e1 >= int(0.5 * len(xAroundAlong[e2])): + offset = 1 + + if (startRowIdx <= e2 <= endRowIdx - 1) and 0.5 * len(xAroundAlong[e2]) - 2 < e1 < 0.5 * len( + xAroundAlong[e2]): + continue + else: + eft1 = eftStandard + scaleFactors = [] + elementtemplate1 = elementtemplateStandard + bni111 = idxMat[e2][e3][e1] + bni211 = idxMat[e2][e3][e1 + 1] + bni121 = idxMat[e2 + 1][e3][e1 + offset] + bni221 = idxMat[e2 + 1][e3][e1 + 1 + offset] + bni112 = idxMat[e2][e3 + 1][e1] + bni212 = idxMat[e2][e3 + 1][e1 + 1] + bni122 = idxMat[e2 + 1][e3 + 1][e1 + offset] + bni222 = idxMat[e2 + 1][e3 + 1][e1 + 1 + offset] + nodeIdentifiers = [bni111, bni211, bni121, bni221, + bni112, bni212, bni122, bni222] + + if e2 == startRowIdx - 1 and e1 == elementsCountAroundHalfHaustrum - 2: # LHS bottom + scaleFactors = [-1.0] + eft1 = eftfactory.createEftNoCrossDerivatives() + setEftScaleFactorIds(eft1, [1], []) + remapEftNodeValueLabel(eft1, [3, 7], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS2, [1])]) + remapEftNodeValueLabel(eft1, [3, 7], Node.VALUE_LABEL_D_DS2, + [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [])]) + remapEftNodeValueLabel(eft1, [4, 8], Node.VALUE_LABEL_D_DS2, + [(Node.VALUE_LABEL_D_DS2, [1])]) + + elementtemplateX.defineField(coordinates, -1, eft1) + elementtemplate1 = elementtemplateX + + elif e2 == startRowIdx - 1 and e1 == elementsCountAroundHalfHaustrum - 1: # RHS bottom + scaleFactors = [-1.0] + eft1 = eftfactory.createEftNoCrossDerivatives() + setEftScaleFactorIds(eft1, [1], []) + remapEftNodeValueLabel(eft1, [3, 7], Node.VALUE_LABEL_D_DS2, + [(Node.VALUE_LABEL_D_DS2, [1])]) + remapEftNodeValueLabel(eft1, [4, 8], Node.VALUE_LABEL_D_DS2, + [(Node.VALUE_LABEL_D_DS1, [1]), (Node.VALUE_LABEL_D_DS2, [])]) + remapEftNodeValueLabel(eft1, [4, 8], Node.VALUE_LABEL_D_DS1, + [(Node.VALUE_LABEL_D_DS2, [])]) + elementtemplateX.defineField(coordinates, -1, eft1) + elementtemplate1 = elementtemplateX + + elif e2 == startRowIdx - 1 and e1 == elementsCountAroundHalfHaustrum: # RHS bottom + 1 + scaleFactors = [-1.0] + eft1 = eftfactory.createEftNoCrossDerivatives() + setEftScaleFactorIds(eft1, [1], []) + remapEftNodeValueLabel(eft1, [3, 7], Node.VALUE_LABEL_D_DS2, + [(Node.VALUE_LABEL_D_DS1, [1]), (Node.VALUE_LABEL_D_DS2, [])]) + elementtemplateX.defineField(coordinates, -1, eft1) + elementtemplate1 = elementtemplateX + + elif e2 == startRowIdx - 1 and e1 == elementsCountAroundHalfHaustrum - 3: # LHS Bottom Left - 1 + eft1 = eftfactory.createEftNoCrossDerivatives() + remapEftNodeValueLabel(eft1, [4, 8], Node.VALUE_LABEL_D_DS2, + [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [])]) + elementtemplateX.defineField(coordinates, -1, eft1) + elementtemplate1 = elementtemplateX + + elif e2 == endRowIdx and e1 == elementsCountAroundHalfHaustrum - 2: # end LHS + scaleFactors = [-1.0] + eft1 = eftfactory.createEftNoCrossDerivatives() + setEftScaleFactorIds(eft1, [1], []) + remapEftNodeValueLabel(eft1, [1, 5], Node.VALUE_LABEL_D_DS2, + [(Node.VALUE_LABEL_D_DS1, [1]), (Node.VALUE_LABEL_D_DS2, [])]) + remapEftNodeValueLabel(eft1, [1, 5], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS2, [])]) + elementtemplateX.defineField(coordinates, -1, eft1) + elementtemplate1 = elementtemplateX + + elif e2 == endRowIdx and e1 == elementsCountAroundHalfHaustrum - 3: # end LHS -1 + scaleFactors = [-1.0] + eft1 = eftfactory.createEftNoCrossDerivatives() + setEftScaleFactorIds(eft1, [1], []) + remapEftNodeValueLabel(eft1, [2, 6], Node.VALUE_LABEL_D_DS2, + [(Node.VALUE_LABEL_D_DS1, [1]), (Node.VALUE_LABEL_D_DS2, [])]) + elementtemplateX.defineField(coordinates, -1, eft1) + elementtemplate1 = elementtemplateX + + elif e2 == endRowIdx and e1 == elementsCountAroundHalfHaustrum - 1: # end RHS + scaleFactors = [-1.0] + eft1 = eftfactory.createEftNoCrossDerivatives() + setEftScaleFactorIds(eft1, [1], []) + remapEftNodeValueLabel(eft1, [2, 6], Node.VALUE_LABEL_D_DS1, + [(Node.VALUE_LABEL_D_DS2, [1])]) + remapEftNodeValueLabel(eft1, [2, 6], Node.VALUE_LABEL_D_DS2, + [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [])]) + + elementtemplateX.defineField(coordinates, -1, eft1) + elementtemplate1 = elementtemplateX + + elif e2 == endRowIdx and e1 == elementsCountAroundHalfHaustrum: # end RHS + 1 + eft1 = eftfactory.createEftNoCrossDerivatives() + remapEftNodeValueLabel(eft1, [1, 5], Node.VALUE_LABEL_D_DS2, + [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [])]) + elementtemplateX.defineField(coordinates, -1, eft1) + elementtemplate1 = elementtemplateX + + element = mesh.createElement(elementIdentifier, elementtemplate1) + element.setNodesByIdentifier(eft1, nodeIdentifiers) + if scaleFactors: + element.setScaleFactors(eft1, scaleFactors) + elementIdxAround.append(elementIdentifier) + elementIdentifier += 1 + annotationGroups = annotationGroupsAlong[e2] + annotationGroupsThroughWall[e3] + if annotationGroups: + allAnnotationGroups = mergeAnnotationGroups(allAnnotationGroups, annotationGroups) + for annotationGroup in annotationGroups: + meshGroup = annotationGroup.getMeshGroup(mesh) + meshGroup.addElement(element) + elementIdxThroughWall.append(elementIdxAround) + elementIdxMat.append(elementIdxThroughWall) + + # Annulus + # Assemble endPoints for annulus + endPoints_x = [[None] * elementsCountAroundOstium for n3 in range(elementsCountThroughWall + 1)] + endPoints_d1 = [[None] * elementsCountAroundOstium for n3 in range(elementsCountThroughWall + 1)] + endPoints_d2 = [[None] * elementsCountAroundOstium for n3 in range(elementsCountThroughWall + 1)] + endNode_Id = [[None] * elementsCountAroundOstium for n3 in range(elementsCountThroughWall + 1)] + endDerivativesMap = [[None] * elementsCountAroundOstium for n3 in range(elementsCountThroughWall + 1)] + endProportions = [] + + for n3 in range(elementsCountThroughWall + 1): + n1 = 0 + for nAround in range(elementsCountAroundOstium): + if nAround == 0: + idx = idxMat[startRowIdx][n3][elementsCountAroundHalfHaustrum - 1] + elif 0 < nAround < (elementsCountAroundOstium * 0.5): + idx = idxMat[startRowIdx + n1][n3][elementsCountAroundHalfHaustrum - 2] + n1 += 1 + elif nAround == int(elementsCountAroundOstium * 0.5): + n1 -= 1 + idx = idxMat[startRowIdx + n1][n3][elementsCountAroundHalfHaustrum - 1] + else: + idx = idxMat[startRowIdx + n1][n3][ + elementsCountAroundHalfHaustrum - 1 + ( + 1 if (n1 == int(elementsCountAroundOstium * 0.5) - 2 or n1 == 0) else 0)] + n1 -= 1 + + endPoints_x[n3][nAround] = xList[idx - ostiumFaceStartNode] + endPoints_d1[n3][nAround] = d1List[idx - ostiumFaceStartNode] + endPoints_d2[n3][nAround] = d2List[idx - ostiumFaceStartNode] + endNode_Id[n3][nAround] = idx + + if n3 == elementsCountThroughWall: # outer layer + endPosition = trackSurfaceOstium.findNearestPosition(endPoints_x[n3][nAround]) + endProportions.append(trackSurfaceOstium.getProportion(endPosition)) + + for n3 in range(elementsCountThroughWall + 1): + for nAround in range(elementsCountAroundOstium): + if nAround == 0: + endDerivativesMap[n3][nAround] = ((-1, 0, 0), (0, 1, 0), None) + elif 1 <= nAround < int(elementsCountAroundOstium * 0.5): + endDerivativesMap[n3][nAround] = ((0, 1, 0), (-1, 0, 0), None) + elif nAround == int(elementsCountAroundOstium * 0.5): + endDerivativesMap[n3][nAround] = (None, None, None) + else: + endDerivativesMap[n3][nAround] = ((0, -1, 0), (1, 0, 0), None) + + startProportions = [] + for n in range(elementsCountAroundOstium): + startProportions.append(trackSurfaceOstium.getProportion(o1_Positions[n])) + + cecumWallAnnotationGroups = [] + if elementsCountThroughWall == 4: + cecumWallAnnotationGroups = [[mucosaGroup], [submucosaGroup], [circularMuscleGroup], + [longitudinalMuscleGroup]] + + nextNodeIdentifier, nextElementIdentifier = createAnnulusMesh3d( + nodes, mesh, nextNodeIdentifier, elementIdentifier, + o1_x, o1_d1, o1_d2, None, o1_NodeId, None, + endPoints_x, endPoints_d1, endPoints_d2, None, endNode_Id, endDerivativesMap, + elementsCountRadial=1, meshGroups=[cecumMeshGroup], + wallAnnotationGroups=cecumWallAnnotationGroups, + tracksurface=trackSurfaceOstium, + startProportions=startProportions, endProportions=endProportions, + rescaleStartDerivatives=True, rescaleEndDerivatives=True, sampleBlend=0.0, fixMinimumStart=True, + coordinates=coordinates) + + # Delete elements in new haustrum + mesh_destroy_elements_and_nodes_by_identifiers(mesh, deleteElementIdentifier) + + return allAnnotationGroups, nextNodeIdentifier, nextElementIdentifier #, nodeIdDistal, xDistal, d1Distal, \ + # d2Distal, d3Distal + + +class CecumCentralPath: + """ + Generates sampled central path for cecum scaffold. + """ + def __init__(self, region, centralPath, termsAlong=[None]): + """ + :param region: Zinc region to define model in. + :param centralPath: Central path subscaffold from meshtype_1d_path1 + :param termsAlong: Annotation terms along length of central path + """ + # Extract length of each group along stomach from central path + arcLengthOfGroupsAlong = [] + cxGroups = [] + cd1Groups = [] + cd2Groups = [] + cd3Groups = [] + cd12Groups = [] + cd13Groups = [] + + tmpRegion = region.createRegion() + centralPath.generate(tmpRegion) + pathNetworkMesh = centralPath.getConstructionObject() + tmpFieldmodule = tmpRegion.getFieldmodule() + tmpNodes = tmpFieldmodule.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES) + tmpCoordinates = tmpFieldmodule.findFieldByName('coordinates') + networkSegments = pathNetworkMesh.getNetworkSegments() + + cxGroup = [] + cd1Group = [] + cd2Group = [] + cd3Group = [] + cd12Group = [] + cd13Group = [] + + for termName in termsAlong: + tmpGroup = tmpFieldmodule.findFieldByName(termName).castGroup() if termName else None + tmpNodeset = tmpGroup.getNodesetGroup(tmpNodes) if tmpGroup else tmpNodes + + if termName == "caecum": + for i in range(2): + cx, cd1, cd2, cd3, cd12, cd13 = get_nodeset_path_ordered_field_parameters( + tmpNodeset, tmpCoordinates, + [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], + networkSegments[i + 1].getNodeIdentifiers(), networkSegments[i + 1].getNodeVersions()) + + cxGroup += cx[(1 if i else 0):] + cd1Group += cd1[(1 if i else 0):] + cd2Group += cd2[(1 if i else 0):] + cd3Group += cd3[(1 if i else 0):] + cd12Group += cd12[(1 if i else 0):] + cd13Group += cd13[(1 if i else 0):] + + if i == 0: + xbranchpt = cx[-1] + d2branchpt = cd2[-1] + arcLengthToBranchPt = 0.0 + for n in range(len(cx) - 1): + arcLengthToBranchPt += interp.getCubicHermiteArcLength(cx[n], cd1[n], cx[n + 1], cd1[n + 1]) + + elif termName == "ileum": + cxGroup, cd1Group, cd2Group, cd3Group, cd12Group, cd13Group = get_nodeset_path_ordered_field_parameters( + tmpNodes, tmpCoordinates, + [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], + networkSegments[0].getNodeIdentifiers(), networkSegments[0].getNodeVersions()) + + 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) + cxGroups.append(cxGroup) + cd1Groups.append(cd1Group) + cd2Groups.append(cd2Group) + cd3Groups.append(cd3Group) + cd12Groups.append(cd12Group) + cd13Groups.append(cd13Group) + + del tmpNodeset + del tmpGroup + + del tmpCoordinates + del tmpNodes + del tmpFieldmodule + del tmpRegion + + self.arcLengthOfGroupsAlong = arcLengthOfGroupsAlong + self.cxGroups = cxGroups + self.cd1Groups = cd1Groups + self.cd2Groups = cd2Groups + self.cd3Groups = cd3Groups + self.cd12Groups = cd12Groups + self.cd13Groups = cd13Groups + self.xBranchPt = xbranchpt + self.d2BranchPt = d2branchpt + self.arcLengthToBranchPt = arcLengthToBranchPt + +class CustomCentralPath: + """ + Generates sampled central path for part of central path. + """ + def __init__(self, cx, cd1, cd2, cd3, cd12, cd13): + self.cxPath = cx + self.cd1Path = cd1 + self.cd2Path = cd2 + self.cd3Path = cd3 + self.cd12Path = cd12 + self.cd13Path = cd13 + \ No newline at end of file diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_cecum2.py b/src/scaffoldmaker/meshtypes/meshtype_3d_cecum2.py deleted file mode 100644 index 2eb174a0..00000000 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_cecum2.py +++ /dev/null @@ -1,2323 +0,0 @@ -""" -Generates a 3-D cecum mesh along the central line, with variable -numbers of elements around, along and through wall, with -variable radius and thickness along. -""" - -import copy -import math - -from cmlibs.maths.vectorops import add, sub -from cmlibs.utils.zinc.field import findOrCreateFieldCoordinates # KM -from cmlibs.zinc.element import Element, Elementbasis -from cmlibs.zinc.field import Field -from cmlibs.zinc.node import Node -from scaffoldmaker.annotation.annotationgroup import AnnotationGroup, mergeAnnotationGroups -from scaffoldmaker.annotation.cecum_terms import get_cecum_term -from scaffoldmaker.annotation.smallintestine_terms import get_smallintestine_term -from scaffoldmaker.meshtypes.meshtype_1d_network_layout1 import MeshType_1d_network_layout1 -from scaffoldmaker.meshtypes.meshtype_3d_colonsegment1 import ColonSegmentTubeMeshInnerPoints, \ - getFullProfileFromHalfHaustrum, getTeniaColi, createNodesAndElementsTeniaColi -from scaffoldmaker.meshtypes.meshtype_3d_ostium2 import MeshType_3d_ostium2, generateOstiumMesh -from scaffoldmaker.meshtypes.scaffold_base import Scaffold_base -from scaffoldmaker.scaffoldpackage import ScaffoldPackage -from scaffoldmaker.utils import interpolation as interp -from scaffoldmaker.utils import matrix -from scaffoldmaker.utils import tubemesh -from scaffoldmaker.utils import vector -from scaffoldmaker.utils.geometry import createEllipsePoints # KM -from scaffoldmaker.utils.annulusmesh import createAnnulusMesh3d -from scaffoldmaker.utils.eftfactory_bicubichermitelinear import eftfactory_bicubichermitelinear -from scaffoldmaker.utils.eftfactory_tricubichermite import eftfactory_tricubichermite -from scaffoldmaker.utils.eft_utils import setEftScaleFactorIds, remapEftNodeValueLabel, remapEftNodeValueLabelsVersion -from scaffoldmaker.utils.networkmesh import NetworkMesh, NetworkNode -from scaffoldmaker.utils.tracksurface import TrackSurface, TrackSurfacePosition -from scaffoldmaker.utils.zinc_utils import exnode_string_from_nodeset_field_parameters, \ - mesh_destroy_elements_and_nodes_by_identifiers, get_nodeset_path_field_parameters, \ - get_nodeset_path_ordered_field_parameters - - -class MeshType_3d_cecum2(Scaffold_base): - ''' - Generates a 3-D cecum mesh with variable numbers - of elements around, along the central line, and through wall. - The cecum is created by a function that generates a cecum - segment and uses tubemesh to map the segment along a central - line profile. The proximal end of the cecum is closed up with - an apex plate. An ostium is included to generate the - ileo-cecal junction. - ''' - - parameterSetStructureStrings = { - 'Human 1': ScaffoldPackage(MeshType_1d_network_layout1, { - 'scaffoldSettings': { - "Structure": "1-2-3.2, 4-3-5" - }, - 'meshEdits': exnode_string_from_nodeset_field_parameters( - [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ - (1, [[7.50,-20.00,0.00], [0.00,8.28,0.00], [-1.50,0.00,0.00], [0.00,0.00,0.00], [0.00,-0.00,1.50], [0.00,0.00,0.00]]), - (2, [[7.50,-10.86,0.00], [0.00,10.00,0.00], [-4.50,0.00,0.00], [0.00,0.00,0.00], [0.00,-0.00,4.50], [0.00,0.00,0.00]]), - (3, [[7.50,0.00,0.00], [[7.50,0.00,0.00],[0.00,11.72,0.00]], [[0.00,10.00,0.00],[-4.50,0.00,0.00]], [[1.02,6.79,0.00],[0.00,0.00,0.00]], [[0.00,0.00,10.00],[0.00,-0.00,4.50]], [[0.00,0.00,5.77],[0.00,0.00,0.00]]]), - (4, [[0.00,0.00,0.00], [7.50,0.00,0.00], [0.00,10.00,0.00], [0.00,0.00,0.00], [0.00,0.00,10.00], [0.00,0.00,0.00]]), - (5, [[15.00,0.00,0.00], [7.50,0.00,0.00], [0.00,10.00,0.00], [0.00,0.00,0.00], [0.00,0.00,10.00], [0.00,0.00,0.00]])]), - - 'userAnnotationGroups': [ - { - '_AnnotationGroup': True, - 'dimension': 1, - 'identifierRanges': '3-4', - 'name': get_cecum_term('caecum')[0], - 'ontId': get_cecum_term('caecum')[1] - }, - { - '_AnnotationGroup': True, - 'dimension': 1, - 'identifierRanges': '1-2', - 'name': get_smallintestine_term('ileum')[0], - 'ontId': get_smallintestine_term('ileum')[1] - }] - }), - 'Human 2': ScaffoldPackage(MeshType_1d_network_layout1, { - 'scaffoldSettings': { - "Structure": "1-2-3.2, 4-3-5" - }, - 'meshEdits': exnode_string_from_nodeset_field_parameters( - [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ - (1, [[9.21,-19.56,6.43], [-2.02,7.27,-6.55], [-1.46,-0.27,0.15], [0.00,0.00,0.00], [-0.06,0.99,1.12], [0.00,0.00,0.00]]), - (2, [[7.72,-10.79,1.37], [-0.90,10.04,-3.37], [-4.48,-0.36,0.11], [0.00,0.00,0.00], [-0.01,1.43,4.27], [0.00,0.00,0.00]]), - (3, [[7.50,0.00,0.00], [[7.50,0.00,0.00],[0.45,11.25,0.61]], [[0.00,10.00,0.00],[-4.50,0.18,0.01]], [[1.02,6.79,0.00],[0.00,0.00,0.00]], [[0.00,0.00,10.00],[0.00,-0.24,4.49]], [[0.00,0.00,5.77],[0.00,0.00,0.00]]]), - (4, [[0.00,0.00,0.00], [7.50,0.00,0.00], [0.00,10.00,0.00], [0.00,0.00,0.00], [0.00,0.00,10.00], [0.00,0.00,0.00]]), - (5, [[15.00,0.00,0.00], [7.50,0.00,0.00], [0.00,10.00,0.00], [0.00,0.00,0.00], [0.00,0.00,10.00], [0.00,0.00,0.00]])]), - - 'userAnnotationGroups': [ - { - '_AnnotationGroup': True, - 'dimension': 1, - 'identifierRanges': '3-4', - 'name': get_cecum_term('caecum')[0], - 'ontId': get_cecum_term('caecum')[1] - }, - { - '_AnnotationGroup': True, - 'dimension': 1, - 'identifierRanges': '1-2', - 'name': get_smallintestine_term('ileum')[0], - 'ontId': get_smallintestine_term('ileum')[1] - }] - }), - 'Pig 1': ScaffoldPackage(MeshType_1d_network_layout1, { - 'scaffoldSettings': { - "Structure": "1-2-3.2, 4-5-6-3-7" - }, - 'meshEdits': exnode_string_from_nodeset_field_parameters( - [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ - (1, [[167.00,29.75,51.53], [0.00,-9.63,-16.67], [-4.00,-0.00,0.00], [0.00,0.00,0.00], [0.00,6.64,-3.83], [0.00,0.00,0.00]]), - (2, [[167.00,17.50,30.31], [0.00,-14.87,-25.77], [-15.00,-0.00,0.00], [0.00,0.00,0.00], [0.00,10.49,-6.05], [0.00,0.00,0.00]]), - (3, [[167.00,0.00,0.00], [[30.00,0.00,0.00],[0.00,-20.13,-34.85]], [[0.00,35.00,0.00],[-15.00,0.00,0.00]], [[0.00,0.00,0.00],[0.00,0.00,0.00]], [[0.00,0.00,35.00],[0.00,8.49,-4.90]], [[0.00,0.00,0.00],[0.00,0.00,0.00]]]), - (4, [[0.00,0.00,0.00], [60.00,0.00,0.00], [0.00,35.00,0.00], [0.00,0.00,0.00], [0.00,0.00,35.00], [0.00,0.00,0.00]]), - (5, [[60.00,0.00,0.00], [60.00,0.00,0.00], [0.00,35.00,0.00], [0.00,0.00,0.00], [0.00,0.00,35.00], [0.00,0.00,0.00]]), - (6, [[120.00,0.00,0.00], [53.50,0.00,0.00], [0.00,35.00,0.00], [0.00,0.00,0.00], [0.00,0.00,35.00], [0.00,0.00,0.00]]), - (7, [[180.00,0.00,0.00], [4.00,-0.00,-0.00], [0.00,35.00,0.00], [0.00,0.00,0.00], [0.00,0.00,35.00], [0.00,0.00,0.00]])]), - - 'userAnnotationGroups': [ - { - '_AnnotationGroup': True, - 'dimension': 1, - 'identifierRanges': '3-6', - 'name': get_cecum_term('caecum')[0], - 'ontId': get_cecum_term('caecum')[1] - }, - { - '_AnnotationGroup': True, - 'dimension': 1, - 'identifierRanges': '1-2', - 'name': get_smallintestine_term('ileum')[0], - 'ontId': get_smallintestine_term('ileum')[1] - }] - }), - } - - ostiumDefaultScaffoldPackages = { - 'Human 1': ScaffoldPackage(MeshType_3d_ostium2, { - 'scaffoldSettings': { - 'Number of elements around ostium': 8, - 'Number of elements along': 2, - 'Number of elements through wall': 1, - 'Unit scale': 1.0, - 'Outlet': False, - 'Ostium wall thickness': 1.6, - 'Ostium wall relative thicknesses': [0.55, 0.15, 0.25, 0.05], - 'Use linear through ostium wall': True, - 'Vessel wall thickness': 0.45, - 'Vessel wall relative thicknesses': [0.55, 0.15, 0.25, 0.05], - 'Use linear through vessel wall': True, - 'Use cross derivatives': False, - 'Refine': False, - 'Refine number of elements around': 4, - 'Refine number of elements along': 4, - 'Refine number of elements through wall': 1 - }, - }), - 'Pig 1': ScaffoldPackage(MeshType_3d_ostium2, { - 'scaffoldSettings': { - 'Number of elements around ostium': 8, - 'Number of elements along': 2, - 'Number of elements through wall': 1, # not implemented for > 1 - 'Unit scale': 1.0, - 'Outlet': False, - 'Ostium wall thickness': 2.0, - 'Use linear through ostium wall': True, - 'Vessel wall thickness': 2.0, - 'Use linear through vessel wall': True, - 'Use cross derivatives': False, - 'Refine': False, - 'Refine number of elements around': 4, - 'Refine number of elements along': 4, - 'Refine number of elements through wall': 1 - }, - }) - } - - @staticmethod - def getName(): - return '3D Cecum 2' - - @staticmethod - def getParameterSetNames(): - return [ - 'Default', - 'Human 1', - 'Human 2', - 'Pig 1'] - - @classmethod - def getDefaultOptions(cls, parameterSetName='Default'): - if 'Human 2' in parameterSetName: - centralPathOption = cls.parameterSetStructureStrings['Human 2'] - ostiumOption = cls.ostiumDefaultScaffoldPackages['Human 1'] - elif 'Pig 1' in parameterSetName: - centralPathOption = cls.parameterSetStructureStrings['Pig 1'] - ostiumOption = cls.ostiumDefaultScaffoldPackages['Pig 1'] - else: - centralPathOption = cls.parameterSetStructureStrings['Human 1'] - ostiumOption = cls.ostiumDefaultScaffoldPackages['Human 1'] - - options = { - 'Central path': copy.deepcopy(centralPathOption), - 'Number of segments': 1, - 'Number of elements around tenia coli': 2, - 'Number of elements around haustrum': 8, - 'Number of elements along segment': 8, - 'Number of elements through wall': 1, # 4 later! - 'Corner inner radius factor': 0.5, - 'Haustrum inner radius factor': 0.4, - 'Segment length end derivative factor': 0.5, - 'Segment length mid derivative factor': 1.0, # 3.0, - 'Number of tenia coli': 3, - 'Start tenia coli width': 2.0, #10.0, - 'Start tenia coli width derivative': 2.0, #0.0, - 'End tenia coli width': 4.0, #10.0, - 'End tenia coli width derivative': 2.0, #0.0, - 'Tenia coli thickness': 0.5, #1.6, - 'Wall thickness': 1.6, - 'Mucosa relative thickness': 0.55, - 'Submucosa relative thickness': 0.15, - 'Circular muscle layer relative thickness': 0.25, - 'Longitudinal muscle layer relative thickness': 0.05, - 'Ileocecal junction': copy.deepcopy(ostiumOption), - 'Use cross derivatives': False, - 'Use linear through wall': True, - 'Refine': False, - 'Refine number of elements around': 1, - 'Refine number of elements along': 1, - 'Refine number of elements through wall': 1 - } - - if 'Pig 1' in parameterSetName: - options['Number of segments'] = 5 - options['Haustrum inner radius factor'] = 0.25 - options['Segment length end derivative factor'] = 1.0 - options['Segment length mid derivative factor'] = 4.0 - options['Start tenia coli width'] = 5.0 - options['Start tenia coli width derivative'] = 0.0 - options['End tenia coli width'] = 5.0 - options['End tenia coli width derivative'] = 0.0 - options['Wall thickness'] = 2.0 - - cls.updateSubScaffoldOptions(options) - return options - - @staticmethod - def getOrderedOptionNames(): - return [ - 'Central path', - 'Number of segments', - 'Number of elements around tenia coli', - 'Number of elements around haustrum', - 'Number of elements along segment', - 'Number of elements through wall', - 'Corner inner radius factor', - 'Haustrum inner radius factor', - 'Segment length end derivative factor', - 'Segment length mid derivative factor', - 'Number of tenia coli', - 'Start tenia coli width', - 'Start tenia coli width derivative', - 'End tenia coli width', - 'End tenia coli width derivative', - 'Tenia coli thickness', - 'Wall thickness', - 'Mucosa relative thickness', - 'Submucosa relative thickness', - 'Circular muscle layer relative thickness', - 'Longitudinal muscle layer relative thickness', - 'Ileocecal junction', - 'Use cross derivatives', - 'Use linear through wall', - 'Refine', - 'Refine number of elements around', - 'Refine number of elements along', - 'Refine number of elements through wall'] - - @classmethod - def getOptionValidScaffoldTypes(cls, optionName): - if optionName == 'Central path': - return [ MeshType_1d_network_layout1 ] - if optionName == 'Ileocecal junction': - return [ MeshType_3d_ostium2 ] - return [] - - @classmethod - def getOptionScaffoldTypeParameterSetNames(cls, optionName, scaffoldType): - if optionName == 'Central path': - return list(cls.parameterSetStructureStrings.keys()) - if optionName == 'Ileocecal junction': - return list(cls.ostiumDefaultScaffoldPackages.keys()) - assert scaffoldType in cls.getOptionValidScaffoldTypes(optionName), cls.__name__ + '.getOptionScaffoldTypeParameterSetNames. ' + \ - 'Invalid option \'' + optionName + '\' scaffold type ' + scaffoldType.getName() - return scaffoldType.getParameterSetNames() - - @classmethod - def getOptionScaffoldPackage(cls, optionName, scaffoldType, parameterSetName=None): - ''' - :param parameterSetName: Name of valid parameter set for option Scaffold, or None for default. - :return: ScaffoldPackage. - ''' - if parameterSetName: - assert parameterSetName in cls.getOptionScaffoldTypeParameterSetNames(optionName, scaffoldType), \ - 'Invalid parameter set ' + str(parameterSetName) + ' for scaffold ' + str(scaffoldType.getName()) + ' in option ' + str(optionName) + ' of scaffold ' + cls.getName() - if optionName == 'Central path': - if not parameterSetName: - parameterSetName = list(cls.parameterSetStructureStrings.keys())[0] - return copy.deepcopy(cls.parameterSetStructureStrings[parameterSetName]) - if optionName == 'Ileocecal junction': - if not parameterSetName: - parameterSetName = list(cls.ostiumDefaultScaffoldPackages.keys())[0] - return copy.deepcopy(cls.ostiumDefaultScaffoldPackages[parameterSetName]) - assert False, cls.__name__ + '.getOptionScaffoldPackage: Option ' + optionName + ' is not a scaffold' - - @classmethod - def checkOptions(cls, options): - if not options['Central path'].getScaffoldType() in cls.getOptionValidScaffoldTypes('Central path'): - options['Central path'] = cls.getOptionScaffoldPackage('Central path', MeshType_1d_network_layout1) - if not options['Ileocecal junction'].getScaffoldType() in cls.getOptionValidScaffoldTypes('Ileocecal junction'): - options['Ileocecal junction'] = cls.getOptionScaffoldPackage('Ileocecal junction', MeshType_3d_ostium2) - for key in [ - 'Number of segments', - 'Refine number of elements around', - 'Refine number of elements along', - 'Refine number of elements through wall']: - if options[key] < 1: - options[key] = 1 - for key in [ - 'Number of elements around tenia coli', - 'Number of elements around haustrum', - 'Number of elements along segment', - 'Corner inner radius factor', - 'Haustrum inner radius factor', - 'Segment length end derivative factor', - 'Segment length mid derivative factor', - 'Number of tenia coli', - 'Start tenia coli width', - 'Start tenia coli width derivative', - 'End tenia coli width', - 'End tenia coli width derivative', - 'Tenia coli thickness', - 'Wall thickness']: - if options[key] < 0.0: - options[key] = 0.0 - if options['Number of elements through wall'] != (1 or 4): - options['Number of elements through wall'] = 4 - cls.updateSubScaffoldOptions(options) - - @classmethod - def updateSubScaffoldOptions(cls, options): - ''' - Update ostium sub-scaffold options which depend on parent options. - ''' - wallThickness = options['Wall thickness'] - ostiumOptions = options['Ileocecal junction'] - ostiumSettings = ostiumOptions.getScaffoldSettings() - ostiumSettings['Ostium wall thickness'] = wallThickness - elementsCountThroughWall = options['Number of elements through wall'] - ostiumSettings['Number of elements through wall'] = elementsCountThroughWall - if elementsCountThroughWall == 1: - ostiumSettings['Ostium wall relative thicknesses'] = [1.0] - ostiumSettings['Vessel wall relative thicknesses'] = [1.0] - else: - mucosaRelThickness = options['Mucosa relative thickness'] - submucosaRelThickness = options['Submucosa relative thickness'] - circularRelThickness = options['Circular muscle layer relative thickness'] - longRelThickness = options['Longitudinal muscle layer relative thickness'] - relThicknesses = [mucosaRelThickness, submucosaRelThickness, circularRelThickness, longRelThickness] - ostiumSettings['Ostium wall relative thicknesses'] = relThicknesses - ostiumSettings['Vessel wall relative thicknesses'] = relThicknesses - - @classmethod - def generateBaseMesh(cls, region, options): - """ - Generate the base tricubic Hermite mesh. - :param region: Zinc region to define model in. Must be empty. - :param options: Dict containing options. See getDefaultOptions(). - :return: annotationGroups - """ - - nextNodeIdentifier = 1 - nextElementIdentifier = 1 - cls.updateSubScaffoldOptions(options) - geometricCentralPath = options['Central path'] - cecumTermsAlong = ['caecum', 'ileum'] - geometricCentralPath = CecumCentralPath(region, geometricCentralPath, cecumTermsAlong) - annotationGroups, nextNodeIdentifier, nextElementIdentifier = \ - createCecumMesh3d(region, options, geometricCentralPath, nextNodeIdentifier, - nextElementIdentifier) - - return annotationGroups, None - - @classmethod - def refineMesh(cls, meshrefinement, options): - """ - Refine source mesh into separate region, with change of basis. - :param meshrefinement: MeshRefinement, which knows source and target region. - :param options: Dict containing options. See getDefaultOptions(). - """ - refineElementsCountAround = options['Refine number of elements around'] - refineElementsCountAlong = options['Refine number of elements along'] - refineElementsCountThroughWall = options['Refine number of elements through wall'] - - meshrefinement.refineAllElementsCubeStandard3d(refineElementsCountAround, refineElementsCountAlong, - refineElementsCountThroughWall) - return - -def getApexSegmentForCecum(xInner, d1Inner, d2Inner, elementsCountAroundHalfHaustrum, - elementsCountAroundTC, elementsCountAround, elementsCountAlongSegment, tcCount): - """ - Generates the inner coordinates and derivatives for a cecum segment on the closed end. - The closed end is a single node and segment is created by sampling curves between the - point on closed end with nodes on the length along second half of a colon segment. - :param xInner: coordinates of a colon segment. - :param d1Inner: derivative around colon segment. - :param d2Inner: derivative along colon segment. - :param elementsCountAroundHalfHaustrum: half of total number of elements in haustrum and tenia coli. - :param elementsCountAroundTC: number of elements around a tenia coli. - :param elementsCountAround: number of elements around a cecum. - :param elementsCountAlongSegment: number of elements along a segment of cecum. - :param tcCount: number of tenia coli. - :return: coordinates and derivatives around and along closed segment of cecum, and directional derivative for node - on middle of tenia coli. - """ - - # Make apex cap - apex points like multiple points - xFirstSegment = [[0.0, 0.0, 0.0] for c in range(elementsCountAround)] - - # Compile nodes and d2 for sampling - xFirstSegment += xInner[elementsCountAround * int(elementsCountAlongSegment * 0.5):] # second half of first regular segment - d1FirstDirectionVector = vector.normalise(d1Inner[elementsCountAround]) # Store direction vector of first d1 intra-haustral for later - d2Vector = xInner[elementsCountAround * int(elementsCountAlongSegment * 0.5): - elementsCountAround * (int(elementsCountAlongSegment * 0.5) + 1)] # half face of segment - apex - d2FirstSegment = [] - for c in range(elementsCountAround): - d2 = [d2Vector[c][0], d2Vector[c][1], 0.0 ] # project onto x-y plane to get d2 pointing vertically - d2FirstSegment.append(d2) - d2FirstSegment += d2Inner[elementsCountAround * int(elementsCountAlongSegment*0.5):] - - # Sample along first segment - xFirstSegmentSampledRaw = [] - d2FirstSegmentSampledRaw = [] - xFirstSegmentSampled = [] - d1FirstSegmentSampled = [] - d2FirstSegmentSampled = [] - - for n1 in range(elementsCountAround): - xForSamplingAlong = [] - d2ForSamplingAlong = [] - for n2 in range(1 + elementsCountAlongSegment - int(elementsCountAlongSegment * 0.5) + 1): - idx = elementsCountAround * n2 + n1 - xForSamplingAlong.append(xFirstSegment[idx]) - d2ForSamplingAlong.append(d2FirstSegment[idx]) - xResampled, d1Resampled, se, sxi, _ = interp.sampleCubicHermiteCurves(xForSamplingAlong, d2ForSamplingAlong, - elementsCountAlongSegment, - arcLengthDerivatives = True) - - xFirstSegmentSampledRaw.append(xResampled) - d2FirstSegmentSampledRaw.append(d1Resampled) - - # Re-arrange sample order - for n2 in range(elementsCountAlongSegment + 1): - xAround = [] - for n1 in range(elementsCountAround): - x = xFirstSegmentSampledRaw[n1][n2] - d2 = d2FirstSegmentSampledRaw[n1][n2] - if n1 < elementsCountAroundHalfHaustrum + 1: - xAround.append(x) - xFirstSegmentSampled.append(x) - d2FirstSegmentSampled.append(d2) - if n2 == 0: - d1 = matrix.rotateAboutZAxis(d2, math.pi*0.5) - d1FirstSegmentSampled.append(d1) - - if n2 > 0: - d1Around = [] - for n1 in range(elementsCountAroundHalfHaustrum): - v1 = xAround[n1] - v2 = xAround[n1 + 1] - d1 = d1FirstDirectionVector if n1 == 0 else [v2[c] - v1[c] for c in range(3)] - 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) - # Account for d1 of node sitting on half haustrum - d1 = vector.normalise( - [xAround[elementsCountAroundHalfHaustrum][c] - xAround[elementsCountAroundHalfHaustrum - 1][c] - for c in range(3)]) - dx_ds1 = [c * arcLengthAround for c in d1] - d1Around.append(dx_ds1) - - d1Smoothed = interp.smoothCubicHermiteDerivativesLine(xAround, d1Around, fixStartDerivative=True) - d1TCEdge = vector.setMagnitude(d1Smoothed[int(elementsCountAroundTC * 0.5)], - vector.magnitude(d1Smoothed[int(elementsCountAroundTC * 0.5 - 1)])) - d1Transition = vector.setMagnitude(d1Smoothed[int(elementsCountAroundTC * 0.5 + 1)], - vector.magnitude(d1Smoothed[int(elementsCountAroundTC * 0.5 + 2)])) - d1Corrected = [] - d1Corrected = d1Corrected + d1Smoothed[:int(elementsCountAroundTC * 0.5)] - d1Corrected.append(d1TCEdge) - d1Corrected.append(d1Transition) - d1Corrected = d1Corrected + d1Smoothed[int(elementsCountAroundTC * 0.5 + 2):] - d1Full = getD1ForFullProfileFromHalfHaustrum(d1Corrected, tcCount) - d1FirstSegmentSampled += d1Full - - return xFirstSegmentSampled, d1FirstSegmentSampled, d2FirstSegmentSampled, d1FirstDirectionVector - -def getD1ForFullProfileFromHalfHaustrum(d1HaustrumHalfSet, tcCount): - """ - Get full profile from half haustrum - :param d1HaustrumHalfSet: - :param tcCount: - :return: - """ - d1HaustrumHalfSet2 = [] - d1Haustra = [] - - rotAng = 2 * math.pi / tcCount - for n in range(1, len(d1HaustrumHalfSet)): - idx = -n + len(d1HaustrumHalfSet) - 1 - d1 = d1HaustrumHalfSet[idx] - d1Reflect = [d1[0], -d1[1], d1[2]] - d1Rot = [-(d1Reflect[0] * math.cos(rotAng) - d1Reflect[1] * math.sin(rotAng)), - -(d1Reflect[0] * math.sin(rotAng) + d1Reflect[1] * math.cos(rotAng)), - -d1Reflect[2]] - d1HaustrumHalfSet2.append(d1Rot) - - d1Haustrum = d1HaustrumHalfSet + d1HaustrumHalfSet2 - - # Rotate to get all 3 sectors - d1Haustra = d1Haustra + d1Haustrum[:-1] - ang = [2 / 3 * math.pi, -2 / 3 * math.pi] if tcCount == 3 else [math.pi] - for i in range(tcCount - 1): - rotAng = ang[i] - cosRotAng = math.cos(rotAng) - sinRotAng = math.sin(rotAng) - for n in range(len(d1Haustrum) - 1): - d1 = d1Haustrum[n] - dx_ds1 = [d1[0] * cosRotAng - d1[1] * sinRotAng, d1[0] * sinRotAng + d1[1] * cosRotAng, d1[2]] - d1Haustra.append(dx_ds1) - - return d1Haustra - -def sampleCecumAlongLength(xToSample, d1ToSample, d2ToSample, d1FirstDirectionVector, elementsCountAroundHalfHaustrum, - elementsCountAroundTC, elementsCountAround, elementsCountAlong, tcCount): - """ - Get systematically spaced points and derivatives over cubic Hermite interpolated curves along the - length of the cecum. - :param xToSample: coordinates of nodes. - :param d1ToSample: derivative around elements. - :param d2ToSample: derivative along cecum length. - :param d1FirstDirectionVector: directional vector of derivative around for node on the middle of the tenia coli. - :param elementsCountAroundHalfHaustrum:half the total number of elements around tenia coli and haustrum. - :param elementsCountAroundTC: number of elements around tenia coli. - :param elementsCountAround: number of elements around cecum. - :param elementsCountAlong: number of elements along cecum length. - :param tcCount: number of tenia coli. - :return: nodes and derivatives for equally spaced points. - """ - - xInnerRaw = [] - d2InnerRaw = [] - xSampledAlongLength = [] - d1SampledAlongLength = [] - d2SampledAlongLength = [] - - for n1 in range(elementsCountAroundHalfHaustrum + 1): - xForSamplingAlong = [] - d2ForSamplingAlong = [] - for n2 in range(elementsCountAlong + 1): - idx = n2 * elementsCountAround + n1 - xForSamplingAlong.append(xToSample[idx]) - d2ForSamplingAlong.append(d2ToSample[idx]) - xSampled, d2Sampled, se, sxi, _ = interp.sampleCubicHermiteCurves(xForSamplingAlong, d2ForSamplingAlong, - elementsCountAlong, - arcLengthDerivatives=True) - 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(elementsCountAroundHalfHaustrum + 1): - x = xInnerRaw[n1][n2] - d2 = d2InnerRaw[n1][n2] - xAround.append(x) - d2Around.append(d2) - - d1InnerAroundList = [] - if n2 == 0: - d1Corrected = d1ToSample[:elementsCountAroundHalfHaustrum + 1] - - else: - for n1 in range(elementsCountAroundHalfHaustrum): - v1 = xAround[n1] - v2 = xAround[n1 + 1] - d1 = d1FirstDirectionVector if n1 == 0 else [v2[c] - v1[c] for c in range(3)] - 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)] - d1InnerAroundList.append(dx_ds1) - # Account for d1 of node sitting on half haustrum - d1 = vector.normalise([xAround[elementsCountAroundHalfHaustrum][c] - - xAround[elementsCountAroundHalfHaustrum - 1][c] for c in range(3)]) - dx_ds1 = [c * arcLengthAround for c in d1] - d1InnerAroundList.append(dx_ds1) - - if d1InnerAroundList: - d1Smoothed = interp.smoothCubicHermiteDerivativesLine(xAround, d1InnerAroundList, fixStartDerivative=True) - d1TCEdge = vector.setMagnitude(d1Smoothed[int(elementsCountAroundTC * 0.5)], - vector.magnitude(d1Smoothed[int(elementsCountAroundTC * 0.5 - 1)])) - d1Transition = vector.setMagnitude(d1Smoothed[int(elementsCountAroundTC * 0.5 + 1)], - vector.magnitude(d1Smoothed[int(elementsCountAroundTC * 0.5 + 2)])) - d1Corrected = [] - d1Corrected = d1Corrected + d1Smoothed[:int(elementsCountAroundTC * 0.5)] - d1Corrected.append(d1TCEdge) - d1Corrected.append(d1Transition) - d1Corrected = d1Corrected + d1Smoothed[int(elementsCountAroundTC * 0.5 + 2):] - - xAlongList, d1AlongList, d2AlongList = getFullProfileFromHalfHaustrum(xAround, d1Corrected, d2Around, tcCount) - - xSampledAlongLength += xAlongList - d1SampledAlongLength += d1AlongList - d2SampledAlongLength += d2AlongList - - return xSampledAlongLength, d1SampledAlongLength, d2SampledAlongLength - -def getElementIdxOfOstiumBoundary(centrePosition, trackSurfaceOstium, ostiumDiameter): - """ - Finds the element indices of the boundaries of elements on tracksurface that surround - the ostium. Indices based on numbering for elements around and along tracksurface. - Boundary lies on xi=0 of elements on left and bottom boundaries and xi = 1 for right and - top boundaries. - :param centrePosition: surface description for centre of ostium. - :param trackSurfaceOstium: surface description for tracksurface. - :param ostiumDiameter: Diameter of ostium. - :return: element indices on the left, right, bottom and top boundaries around tracksurface. - """ - - elementsAroundTrackSurface = trackSurfaceOstium.elementsCount1 - elementsAlongTrackSurface = trackSurfaceOstium.elementsCount2 - ei1 = centrePosition.e1 - ei2 = centrePosition.e2 - xi1 = centrePosition.xi1 - xi2 = centrePosition.xi2 - xCentre, d1Centre, d2Centre = trackSurfaceOstium.evaluateCoordinates(centrePosition, derivatives=True) - - # Left boundary - leftPositionOfCentreElement = TrackSurfacePosition(ei1, ei2, 0, xi2) - xLeft, d1Left, _ = trackSurfaceOstium.evaluateCoordinates(leftPositionOfCentreElement, derivatives=True) - distxLeftToxCentre = interp.computeCubicHermiteArcLength(xLeft, d1Left, xCentre, d1Centre, False) - remainingLength = ostiumDiameter * 0.5 - distxLeftToxCentre - xCurrent = xLeft - d1Current = d1Left - - for n1 in range(ei1, -1, -1): - if remainingLength > 0.0: - prevPosition = TrackSurfacePosition(n1-1, ei2, 0, xi2) - xPrev, d1Prev, _ = trackSurfaceOstium.evaluateCoordinates(prevPosition, derivatives=True) - distPrevToxCurrent = interp.computeCubicHermiteArcLength(xPrev, d1Prev, xCurrent, d1Current, False) - remainingLength -= distPrevToxCurrent - xCurrent = xPrev - d1Current = d1Prev - else: - ei1Left = n1 - break - - # Right boundary - rightPositionOfCentreElement = TrackSurfacePosition(ei1, ei2, 1.0, xi2) - xRight, d1Right, _ = trackSurfaceOstium.evaluateCoordinates(rightPositionOfCentreElement, derivatives=True) - distxCentreToxRight = interp.computeCubicHermiteArcLength(xCentre, d1Centre, xRight, d1Right, False) - remainingLength = ostiumDiameter * 0.5 - distxCentreToxRight - xCurrent = xRight - d1Current = d1Right - - for n1 in range(ei1, elementsAroundTrackSurface): - if remainingLength > 0.0: - nextPosition = TrackSurfacePosition(n1+1, ei2, 1.0, xi2) - xNext, d1Next, _ = trackSurfaceOstium.evaluateCoordinates(nextPosition, derivatives=True) - distxCurrentToxNext = interp.computeCubicHermiteArcLength(xCurrent, d1Current, xNext, d1Next, False) - remainingLength -= distxCurrentToxNext - xCurrent = xNext - d1Current = d1Next - else: - ei1Right = n1 - break - - # Bottom boundary - bottomPositionOfCentreElement = TrackSurfacePosition(ei1, ei2, xi1, 0) - xBottom, _, d2Bottom = trackSurfaceOstium.evaluateCoordinates(bottomPositionOfCentreElement, derivatives=True) - distxBottomToxCentre = interp.computeCubicHermiteArcLength(xBottom, d2Bottom, xCentre, d2Centre, False) - remainingLength = ostiumDiameter * 0.5 - distxBottomToxCentre - xCurrent = xBottom - d2Current = d2Bottom - - for n2 in range(ei2, -1, -1): - if remainingLength > 0.0: - prevPosition = TrackSurfacePosition(ei1, n2 - 1, xi1, 0) - xPrev, _, d2Prev = trackSurfaceOstium.evaluateCoordinates(prevPosition, derivatives=True) - distPrevToxCurrent = interp.computeCubicHermiteArcLength(xPrev, d2Prev, xCurrent, d2Current, False) - remainingLength -= distPrevToxCurrent - xCurrent = xPrev - d2Current = d2Prev - else: - ei2Bottom = n2 - break - - # Top boundary - topPositionOfCentreElement = TrackSurfacePosition(ei1, ei2, xi1, 1.0) - xTop, _, d2Top = trackSurfaceOstium.evaluateCoordinates(topPositionOfCentreElement, derivatives=True) - distxCentreToxTop = interp.computeCubicHermiteArcLength(xCentre, d2Centre, xTop, d2Top, False) - remainingLength = ostiumDiameter * 0.5 - distxCentreToxTop - xCurrent = xTop - d2Current = d2Top - - for n2 in range(ei2, elementsAlongTrackSurface): - if remainingLength > 0.0: - nextPosition = TrackSurfacePosition(ei1, n2+1, xi1, 1.0) - xNext, _, d2Next = trackSurfaceOstium.evaluateCoordinates(nextPosition, derivatives=True) - distxCurrentToxNext = interp.computeCubicHermiteArcLength(xCurrent, d2Current, xNext, d2Next, False) - remainingLength -= distxCurrentToxNext - xCurrent = xNext - d2Current = d2Next - else: - ei2Top = n2 - break - - return ei1Left, ei1Right, ei2Bottom, ei2Top - -def findDerivativeBetweenPoints(v1, v2): - """ - Find vector difference between two points and rescale vector difference using cubic hermite arclength - between the points to derive the derivative between the points. - :param v1: start vector - :param v2: end vector - :return: derivative of between v1 and v2 - """ - d = [v2[c] - v1[c] for c in range(3)] - arcLengthAround = interp.computeCubicHermiteArcLength(v1, d, v2, d, True) - d = [c * arcLengthAround for c in vector.normalise(d)] - - return d - - -def findCurvatureAroundLoop(nx, nd, radialVectors): - """ - Calculate curvature for points lying along a loop. - :param nx: points on loop - :param nd: derivative of points on loop - :param radialVectors: radial direction, assumed normal to curve tangent at point - :return: curvatures along points on loop - """ - curvature = [] - for n in range(len(nx)): - prevIdx = n - 1 if n > 0 else -1 - nextIdx = n + 1 if n < len(nx) - 1 else 0 - kappam = interp.getCubicHermiteCurvature(nx[prevIdx], nd[prevIdx], nx[n], nd[n], radialVectors[n], 1.0) - kappap = interp.getCubicHermiteCurvature(nx[n], nd[n], nx[nextIdx], nd[nextIdx], radialVectors[n], 0.0) - curvature.append(0.5 * (kappam + kappap)) - - return curvature - -def findCurvatureAlongLine(nx, nd, radialVectors): - """ - Calculate curvature for points lying along a line. - :param nx: points on line - :param nd: derivative of points on line - :param radialVectors: radial direction, assumed normal to curve tangent at point - :return: curvatures along points on line - """ - curvature = [] - for n in range(len(nx)): - if n == 0: - curvature.append(interp.getCubicHermiteCurvature(nx[n], nd[n], nx[n + 1], nd[n + 1], radialVectors[n], 0.0)) - elif n == len(nx) - 1: - curvature.append(interp.getCubicHermiteCurvature(nx[n - 1], nd[n - 1], nx[n], nd[n], radialVectors[n], 1.0)) - else: - curvature.append(0.5 * ( - interp.getCubicHermiteCurvature(nx[n], nd[n], nx[n + 1], nd[n + 1], radialVectors[n], 0.0) + - interp.getCubicHermiteCurvature(nx[n - 1], nd[n - 1], nx[n], nd[n], radialVectors[n], 1.0))) - - return curvature - -def createCecumMesh3d(region, options, centralPath, nextNodeIdentifier, nextElementIdentifier): - """ - - """ - segmentCount = options['Number of segments'] - startPhase = 0.0 - elementsCountAroundTC = options['Number of elements around tenia coli'] - elementsCountAroundHaustrum = options['Number of elements around haustrum'] - elementsCountAlongSegment = options['Number of elements along segment'] - elementsCountThroughWall = options['Number of elements through wall'] - cornerInnerRadiusFactor = options['Corner inner radius factor'] - haustrumInnerRadiusFactor = options['Haustrum inner radius factor'] - segmentLengthEndDerivativeFactor = options['Segment length end derivative factor'] - segmentLengthMidDerivativeFactor = options['Segment length mid derivative factor'] - tcCount = options['Number of tenia coli'] - startTCWidth = options['Start tenia coli width'] - startTCWidthDerivative = options['Start tenia coli width derivative'] - endTCWidth = options['End tenia coli width'] - endTCWidthDerivative = options['End tenia coli width derivative'] - tcThickness = options['Tenia coli thickness'] - 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']) - elementsCountAlong = int(elementsCountAlongSegment * segmentCount) - elementsCountAround = (elementsCountAroundTC + elementsCountAroundHaustrum) * tcCount - - ostiumOptions = options['Ileocecal junction'] - ostiumSettings = ostiumOptions.getScaffoldSettings() - - zero = [0.0, 0.0, 0.0] - firstNodeIdentifier = nextNodeIdentifier - firstElementIdentifier = nextElementIdentifier - startNode = nextNodeIdentifier - startElement = nextElementIdentifier - - fm = region.getFieldmodule() - coordinates = findOrCreateFieldCoordinates(fm) - cache = fm.createFieldcache() - - nodes = fm.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES) - nodetemplate = nodes.createNodetemplate() - nodetemplate.defineField(coordinates) - nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_VALUE, 1) - nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D_DS1, 1) - nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D_DS2, 1) - if useCrossDerivatives: - nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D2_DS1DS2, 1) - if useCubicHermiteThroughWall: - nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D_DS3, 1) - if useCrossDerivatives: - nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D2_DS1DS3, 1) - nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D2_DS2DS3, 1) - nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D3_DS1DS2DS3, 1) - - if elementsCountThroughWall == 1: - relativeThicknessList = [1.0] - annotationGroupsThroughWall = [[]] - else: - relativeThicknessList = [mucosaRelThickness, submucosaRelThickness, - circularRelThickness, longitudinalRelThickness] - longitudinalMuscleGroup = AnnotationGroup(region, get_cecum_term("longitudinal muscle layer of cecum")) - circularMuscleGroup = AnnotationGroup(region, get_cecum_term("circular muscle layer of cecum")) - submucosaGroup = AnnotationGroup(region, get_cecum_term("submucosa of cecum")) - mucosaGroup = AnnotationGroup(region, get_cecum_term("cecum mucosa")) - annotationGroupsThroughWall = [[mucosaGroup], - [submucosaGroup], - [circularMuscleGroup], - [longitudinalMuscleGroup]] - - # Sample central path along cecum - # print(len(centralPath.cxGroups)) - cecumLength = centralPath.arcLengthOfGroupsAlong[0] - cx = centralPath.cxGroups[0] - cd1 = centralPath.cd1Groups[0] - cd2 = centralPath.cd2Groups[0] - cd12 = centralPath.cd12Groups[0] - - cxIleum = centralPath.cxGroups[1] - cd1Ileum = centralPath.cd1Groups[1] - cd2Ileum = centralPath.cd2Groups[1] - cd3Ileum = centralPath.cd3Groups[1] - cd12Ileum = centralPath.cd12Groups[1] - cd13Ileum = centralPath.cd13Groups[1] - - # xBranchPt = centralPath.xBranchPt - d2BranchPt = centralPath.d2BranchPt - - # smoothd1 = interp.smoothCubicHermiteDerivativesLine(cx, cd1, fixAllDirections=True, - # magnitudeScalingMode=interp.DerivativeScalingMode.HARMONIC_MEAN) - sxCecum, sd1Cecum, se, sxi, ssf = interp.sampleCubicHermiteCurves(cx, cd1, elementsCountAlong) - sd2Cecum, sd12Cecum = interp.interpolateSampleCubicHermite(cd2, cd12, se, sxi, ssf) - - # Calculate segment length - segmentLength = cecumLength / segmentCount - - # Generate variation of radius & tc width along length - innerRadiusAlongCecum = [] - dInnerRadiusAlongCecum = [] - tcWidthAlongCecum = [] - - closedProximalEnd = True - - innerRadiusListCP = [vector.magnitude(c) for c in cd2] - dInnerRadiusListCP = [] - for n in range(len(innerRadiusListCP) - 1): - dInnerRadiusListCP.append(innerRadiusListCP[n + 1] - innerRadiusListCP[n]) - dInnerRadiusListCP.append(innerRadiusListCP[-1] - innerRadiusListCP[-2]) - innerRadiusAlongElementList, dInnerRadiusAlongElementList = \ - interp.interpolateSampleCubicHermite(innerRadiusListCP, dInnerRadiusListCP, se, sxi, ssf) - - for n2 in range(elementsCountAlongSegment * segmentCount + 1): - xi = 1 / (elementsCountAlongSegment * segmentCount) * n2 - - radius = innerRadiusAlongElementList[n2] - innerRadiusAlongCecum.append(radius) - dRadius = dInnerRadiusAlongElementList[n2] - dInnerRadiusAlongCecum.append(dRadius) - tcWidth = interp.interpolateCubicHermite([startTCWidth], [startTCWidthDerivative], - [endTCWidth], [endTCWidthDerivative], xi)[0] - tcWidthAlongCecum.append(tcWidth) - - haustrumInnerRadiusFactorAlongCecum = [haustrumInnerRadiusFactor] * (elementsCountAlong + 1) - - xToSample = [] - d1ToSample = [] - d2ToSample = [] - - elementsCountAroundHalfHaustrum = int((elementsCountAroundTC + elementsCountAroundHaustrum) * 0.5) - - # Create object - colonSegmentTubeMeshInnerPoints = ColonSegmentTubeMeshInnerPoints( - region, elementsCountAroundTC, elementsCountAroundHaustrum, elementsCountAlongSegment, - tcCount, segmentLengthEndDerivativeFactor, segmentLengthMidDerivativeFactor, - segmentLength, wallThickness, cornerInnerRadiusFactor, haustrumInnerRadiusFactorAlongCecum, - innerRadiusAlongCecum, dInnerRadiusAlongCecum, tcWidthAlongCecum, startPhase) - - # Create annotation - cecumGroup = AnnotationGroup(region, get_cecum_term("caecum")) - annotationGroupsAlong = [] - for i in range(elementsCountAlong): - annotationGroupsAlong.append([cecumGroup]) - - for nSegment in range(segmentCount): - # Make regular segments - xInner, d1Inner, d2Inner, transitElementList, segmentAxis, annotationGroupsAround \ - = colonSegmentTubeMeshInnerPoints.getColonSegmentTubeMeshInnerPoints(nSegment) - - # Replace first half of first segment with apex and sample along apex and second half of segment - if nSegment == 0: - xFirstSegmentSampled, d1FirstSegmentSampled, d2FirstSegmentSampled, d1FirstDirectionVector = \ - getApexSegmentForCecum(xInner, d1Inner, d2Inner, elementsCountAroundHalfHaustrum, - elementsCountAroundTC, elementsCountAround, elementsCountAlongSegment, - tcCount) - - xToSample += xFirstSegmentSampled - d1ToSample += d1FirstSegmentSampled - d2ToSample += d2FirstSegmentSampled - else: - xInnerExtrude = [] - for n in range(len(xInner)): - xInnerExtrude.append([xInner[n][0], xInner[n][1], xInner[n][2] + segmentLength * nSegment]) - xToSample += xInnerExtrude[elementsCountAround:] - d1ToSample += d1Inner[elementsCountAround:] - d2ToSample += d2Inner[elementsCountAround:] - - # Sample along length - xToWarp, d1ToWarp, d2ToWarp = sampleCecumAlongLength(xToSample, d1ToSample, d2ToSample, d1FirstDirectionVector, - elementsCountAroundHalfHaustrum, elementsCountAroundTC, - elementsCountAround, elementsCountAlong, tcCount) - - # Ensure cecum starts at z = 0.0 - minZ = xToWarp[0][2] - for n2 in range(elementsCountAlong + 1): - zFirstNodeAlong = xToWarp[n2 * elementsCountAround][2] - if zFirstNodeAlong < minZ: - minZ = zFirstNodeAlong - - for n in range(len(xToWarp)): - xToWarp[n][2] = xToWarp[n][2] - minZ - - # Project reference point for warping onto central path - sxRefList, sd1RefList, sd2ProjectedListRef, zRefList = \ - tubemesh.getPlaneProjectionOnCentralPath(xToWarp, elementsCountAround, elementsCountAlong, - cecumLength, sxCecum, sd1Cecum, sd2Cecum, sd12Cecum) - - # Warp points - xWarpedList, d1WarpedList, d2WarpedList, d3WarpedUnitList = \ - tubemesh.warpSegmentPoints(xToWarp, d1ToWarp, d2ToWarp, segmentAxis, sxRefList, sd1RefList, - sd2ProjectedListRef, elementsCountAround, elementsCountAlong, zRefList) - - # Create coordinates and derivatives - wallThicknessList = [wallThickness] * (elementsCountAlong + 1) - - xList, d1List, d2List, d3List, curvatureList = \ - tubemesh.getCoordinatesFromInner(xWarpedList, d1WarpedList,d2WarpedList, d3WarpedUnitList, - wallThicknessList, relativeThicknessList, elementsCountAround, - elementsCountAlong, elementsCountThroughWall, transitElementList) - - # Deal with multiple nodes at end point for closed proximal end - xApexInner = xList[0] - # arclength between apex point and corresponding point on next face - mag = interp.getCubicHermiteArcLength(xList[0], d2List[0], - xList[elementsCountAround * (elementsCountThroughWall + 1)], - d2List[elementsCountAround * (elementsCountThroughWall + 1)]) - d2ApexInner = vector.setMagnitude(sd2Cecum[0], mag * 0.5) - d1ApexInner = vector.crossproduct3(sd1Cecum[0], d2ApexInner) - d1ApexInner = vector.setMagnitude(d1ApexInner, mag * 0.5) - d3ApexUnit = vector.normalise(vector.crossproduct3(vector.normalise(d1ApexInner), - vector.normalise(d2ApexInner))) - d3ApexInner = [d3ApexUnit[c] * wallThickness / elementsCountThroughWall for c in range(3)] - - xCecum = [] - d1Cecum = [] - d2Cecum = [] - d3Cecum = [] - - for n3 in range(elementsCountThroughWall + 1): - xApex = [xApexInner[c] + d3ApexUnit[c] * wallThickness / elementsCountThroughWall * n3 for c in range(3)] - xCecum.append(xApex) - d1Cecum.append(d1ApexInner) - d2Cecum.append(d2ApexInner) - d3Cecum.append(d3ApexInner) - - xCecum += xList[(elementsCountThroughWall + 1) * elementsCountAround:] - d1Cecum += d1List[(elementsCountThroughWall + 1) * elementsCountAround:] - d2Cecum += d2List[(elementsCountThroughWall + 1) * elementsCountAround:] - d3Cecum += d3List[(elementsCountThroughWall + 1) * elementsCountAround:] - - xFlat = d1Flat = d2Flat = [] - xOrgan = d1Organ = d2Organ = [] - - # Create nodes and elements - if tcThickness > 0: - tubeTCWidthList = colonSegmentTubeMeshInnerPoints.getTubeTCWidthList() - xCecum, d1Cecum, d2Cecum, d3Cecum, annotationArrayAround = getTeniaColi( - region, xCecum, d1Cecum, d2Cecum, d3Cecum, curvatureList, tcCount, elementsCountAroundTC, - elementsCountAroundHaustrum, elementsCountAlong, elementsCountThroughWall, - tubeTCWidthList, tcThickness, sxRefList, annotationGroupsAround, closedProximalEnd) - - nextNodeIdentifier, nextElementIdentifier, allAnnotationGroups = createNodesAndElementsTeniaColi( - region, xCecum, d1Cecum, d2Cecum, d3Cecum, xFlat, d1Flat, d2Flat, xOrgan, d1Organ, d2Organ, None, - elementsCountAroundTC, elementsCountAroundHaustrum, elementsCountAlong, elementsCountThroughWall, - tcCount, annotationGroupsAround, annotationGroupsAlong, annotationGroupsThroughWall, - firstNodeIdentifier, firstElementIdentifier, useCubicHermiteThroughWall, useCrossDerivatives, - closedProximalEnd) - - else: - nextNodeIdentifier, nextElementIdentifier, allAnnotationGroups = tubemesh.createNodesAndElements( - region, xCecum, d1Cecum, d2Cecum, d3Cecum, xFlat, d1Flat, d2Flat, xOrgan, d1Organ, d2Organ, None, - elementsCountAround, elementsCountAlong, elementsCountThroughWall, - annotationGroupsAround, annotationGroupsAlong, annotationGroupsThroughWall, - firstNodeIdentifier, firstElementIdentifier, useCubicHermiteThroughWall, useCrossDerivatives, - closedProximalEnd) - - nodeIdentifierCecum = nextNodeIdentifier - for n2 in range(len(cx)): - node = nodes.createNode(nextNodeIdentifier, nodetemplate) - cache.setNode(node) - coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, cx[n2]) - coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, cd1[n2]) - coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, cd2[n2]) - coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, [0.0, 0.0, 0.0]) - nextNodeIdentifier += 1 - - ################# - # Create elements - ################# - - mesh = fm.findMeshByDimension(1) - cubicHermiteBasis = fm.createElementbasis(1, Elementbasis.FUNCTION_TYPE_CUBIC_HERMITE) - eft = mesh.createElementfieldtemplate(cubicHermiteBasis) - elementtemplate = mesh.createElementtemplate() - elementtemplate.setElementShapeType(Element.SHAPE_TYPE_LINE) - result = elementtemplate.defineField(coordinates, -1, eft) - - elementIdentifier = nextElementIdentifier - for e in range(len(cx) - 1): - element = mesh.createElement(elementIdentifier, elementtemplate) - element.setNodesByIdentifier(eft, [nodeIdentifierCecum + e, nodeIdentifierCecum + 1 + e]) - elementIdentifier = elementIdentifier + 1 - - cx = centralPath.cxGroups[1] - cd1 = centralPath.cd1Groups[1] - cd2 = centralPath.cd2Groups[1] - - nodeIdentifierIleum = nextNodeIdentifier - for n2 in range(len(cx)): - node = nodes.createNode(nextNodeIdentifier, nodetemplate) - cache.setNode(node) - coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, cx[n2]) - coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, cd1[n2]) - coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, cd2[n2]) - coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, [0.0, 0.0, 0.0]) - nextNodeIdentifier += 1 - - for e in range(2): - element = mesh.createElement(elementIdentifier, elementtemplate) - element.setNodesByIdentifier(eft, [nodeIdentifierIleum + e, nodeIdentifierIleum + 1 + e]) - elementIdentifier = elementIdentifier + 1 - - # Add ostium on track surface - elementsAroundTrackSurface = elementsCountAroundHaustrum - elementsAlongTrackSurface = elementsCountAlongSegment - - # Find region where ostium sits - # angle between d2 of branch point and vector between branch point and 1st point on ileum - dV = [cxIleum[0][c] - cxIleum[-1][c] for c in range(3)] - ostiumPositionAngleAround = math.acos(vector.dotproduct(dV, d2BranchPt)/ - (vector.magnitude(dV) * vector.magnitude(d2BranchPt))) - sectorIdx = ostiumPositionAngleAround // (2 * math.pi / tcCount) - sectorStartAngle = sectorIdx * (2 * math.pi / tcCount) - - startIdxElementsAround = int((elementsCountAroundHaustrum + elementsCountAroundTC) * sectorIdx + - elementsCountAroundTC * 0.5) - - segmentIdx = int(centralPath.arcLengthToBranchPt // segmentLength) - - baseNodesIdx = (elementsCountThroughWall + 1) + \ - + (elementsCountAround * (elementsCountThroughWall + 1) + - ((elementsCountAroundTC - 1) * tcCount if tcThickness > 0.0 else 0)) * \ - (elementsCountAlongSegment * segmentIdx - 1) + elementsCountAround - - # Elements to delete - deleteElementIdentifier = [] - for n2 in range(elementsCountAlongSegment): - for n3 in range(elementsCountThroughWall): - for n1 in range(elementsCountAroundHaustrum): - elementIdx = \ - startIdxElementsAround + int(elementsCountAroundTC * (0.5 if tcThickness > 0.0 else 0)) + \ - n1 + (elementsCountAround * n3) + (elementsCountAround * elementsCountThroughWall + - elementsCountAroundTC * (tcCount if tcThickness > 0.0 else 0)) \ - * n2 + startElement - 1 + segmentIdx * ((elementsCountAround * n3) + - (elementsCountAround * elementsCountThroughWall + - elementsCountAroundTC * - (tcCount if tcThickness > 0.0 else 0)) * - elementsCountAlongSegment) - - deleteElementIdentifier.append(elementIdx) - - xTrackSurface = [] - d1TrackSurface = [] - d2TrackSurface = [] - nodesOnLHS = [] - nodesOnRHS = [] - nodesOnDistal = [] - nodesOnProximal = [] - - for n2 in range(elementsCountAlongSegment + 1): - for n1 in range(elementsCountAroundHaustrum + 1): - if n2 == 0 and segmentIdx == 0: - xTrackSurface.append(xApex) - d1TrackSurface.append(d1ApexInner) - d2TrackSurface.append(d2ApexInner) - else: - idx = baseNodesIdx + \ - (elementsCountAround * (elementsCountThroughWall + 1) + - ((elementsCountAroundTC - 1) * tcCount if tcThickness > 0.0 else 0)) * n2 + \ - startIdxElementsAround + n1 + (elementsCountAround * (elementsCountThroughWall - 1)) - xTrackSurface.append(xCecum[idx]) - d1TrackSurface.append(d1Cecum[idx]) - d2TrackSurface.append(d2Cecum[idx]) - - if n1 == 1: - nodeWall = [] - for n3 in range(elementsCountThroughWall, -1, -1): - nodeWall.append(idx - elementsCountAround * n3) - nodesOnLHS.append(nodeWall) - if n1 == elementsCountAroundHaustrum: - nodeWall = [] - for n3 in range(elementsCountThroughWall, -1, -1): - nodeWall.append(idx + 1 - elementsCountAround * n3) - nodesOnRHS.append(nodeWall) - if segmentIdx and n2 == 0 and n1 > 0 and n1 < elementsCountAroundHaustrum: - nodeWall = [] - for n3 in range(elementsCountThroughWall, -1, -1): - nodeWall.append(idx + 1 - elementsCountAround * n3) - nodesOnProximal.append(nodeWall) - if n2 == elementsCountAlongSegment and n1 > 0 and n1 < elementsCountAroundHaustrum: - nodeWall = [] - for n3 in range(elementsCountThroughWall, -1, -1): - nodeWall.append(idx + 1 - elementsCountAround * n3) - nodesOnDistal.append(nodeWall) - - sideNodes = [] - for n2 in range(elementsCountAlongSegment + 1): - for n3 in range(elementsCountThroughWall + 1): - if n2 == 0 and segmentIdx == 0: - sideNodes.append((n2 + 1) * (n3 + 1)) - elif segmentIdx and n2 == 0: - sideNodes.append(nodesOnLHS[n2][n3]) - for n in range(len(nodesOnProximal)): - sideNodes.append(nodesOnProximal[n][n3]) - sideNodes.append(nodesOnRHS[n2][n3]) - elif n2 == elementsCountAlongSegment: - sideNodes.append(nodesOnLHS[n2 + (0 if segmentIdx else -1)][n3]) - for n in range(len(nodesOnDistal)): - sideNodes.append(nodesOnDistal[n][n3]) - sideNodes.append(nodesOnRHS[n2 + (0 if segmentIdx else -1)][n3]) - else: - for n1 in range(2): - if n1 == 0: - sideNodes.append(nodesOnLHS[n2 + (0 if segmentIdx else -1)][n3]) - else: - sideNodes.append(nodesOnRHS[n2 + (0 if segmentIdx else -1)][n3]) - - # # Visualise track surface - # for n1 in range(len(xTrackSurface)): - # node = nodes.createNode(nextNodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xTrackSurface[n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d2TrackSurface[n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d1TrackSurface[n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, [0.0, 0.0, 0.0]) - # nextNodeIdentifier += 1 - - trackSurfaceOstium = TrackSurface(elementsAroundTrackSurface, elementsAlongTrackSurface, - xTrackSurface, d1TrackSurface, d2TrackSurface) - - # Find centre position - # track along ileum path and since cxIleum[1] could be above or below the track surface, we check both side to determine direction to track - # At each point, find the nearest position and take the diff between nearest point to the point in line, keep tracking till diff is close to zero. - xTol = 1.0E-6 - arcStart = 0.0 - arcEnd = centralPath.arcLengthOfGroupsAlong[1] - nearestPosition = trackSurfaceOstium.findNearestPosition(cxIleum[0]) - xNearestStart = trackSurfaceOstium.evaluateCoordinates(nearestPosition, derivatives=False) - distStart = vector.magnitude([cxIleum[0][c] - xNearestStart[c] for c in range(3)]) - nearestPosition = trackSurfaceOstium.findNearestPosition(cxIleum[-1]) - xNearestEnd = trackSurfaceOstium.evaluateCoordinates(nearestPosition, derivatives=False) - distEnd = vector.magnitude([cxIleum[-1][c] - xNearestEnd[c] for c in range(3)]) - - for iter in range(100): - arcDistance = (arcStart + arcEnd) * 0.5 - x, d1 = interp.getCubicHermiteCurvesPointAtArcDistance(cxIleum, cd1Ileum, arcDistance)[0:2] - nearestPosition = trackSurfaceOstium.findNearestPosition(x) - xNearest = trackSurfaceOstium.evaluateCoordinates(nearestPosition, derivatives=False) - dist = vector.magnitude([x[c] - xNearest[c] for c in range(3)]) - - if abs(distStart - distEnd) > xTol: - if distStart < distEnd: - arcEnd = arcDistance - distEnd = dist - else: - arcStart = arcDistance - distStart = dist - - else: - xCentre, d1Centre, d2Centre = trackSurfaceOstium.evaluateCoordinates(nearestPosition, derivatives=True) - normAxis = vector.normalise([-d for d in d1]) - eIdx = interp.getNearestPointIndex(cxIleum, xCentre) - 1 - arcLenghtSum = 0.0 - for e in range(eIdx): - arcLenghtSum += interp.getCubicHermiteArcLength(cxIleum[e], cd1Ileum[e], - cxIleum[e + 1], cd1Ileum[e + 1]) - xi = (arcDistance - arcLenghtSum)/\ - interp.getCubicHermiteArcLength(cxIleum[eIdx], cd1Ileum[eIdx], cxIleum[eIdx + 1], cd1Ileum[eIdx + 1]) - d2Centre = interp.interpolateCubicHermite(cd2Ileum[eIdx], cd12Ileum[eIdx], cd2Ileum[eIdx + 1], cd12Ileum[eIdx + 1], xi) - break - if iter > 98: - print('Search for ileum entry centre - Max iters reached:', iter) - - # node = nodes.createNode(nextNodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xNearest) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, [0.0, 0.0, 0.0]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, [0.0, 0.0, 0.0]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, [0.0, 0.0, 0.0]) - # print('x', nextNodeIdentifier) - # nextNodeIdentifier += 1 - - # node = nodes.createNode(nextNodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, cxIleum[eIdx]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, [0.0, 0.0, 0.0]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, cd2Ileum[eIdx]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, [0.0, 0.0, 0.0]) - # nextNodeIdentifier += 1 - # - # - # node = nodes.createNode(nextNodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, cxIleum[eIdx + 1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, [0.0, 0.0, 0.0]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, cd2Ileum[eIdx + 1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, [0.0, 0.0, 0.0]) - # nextNodeIdentifier += 1 - # - # node = nodes.createNode(nextNodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xCentre) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d1Centre) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d2Centre) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, normAxis) - # nextNodeIdentifier += 1 - - ostiumSettings['Number of elements around ostium'] = elementsCountAlongSegment - elementsCountAroundOstium = ostiumSettings['Number of elements around ostium'] - - fm = region.getFieldmodule() - mesh = fm.findMeshByDimension(3) - nodes = fm.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES) - - ileumGroup = AnnotationGroup(region, get_smallintestine_term("ileum")) - ileumMeshGroup = ileumGroup.getMeshGroup(mesh) - ileocecalJunctionGroup = AnnotationGroup(region, get_smallintestine_term("ileocecal junction")) - ileocecalJunctionMeshGroup = ileocecalJunctionGroup.getMeshGroup(mesh) - smallIntestineGroup = AnnotationGroup(region, get_smallintestine_term("small intestine")) - smallIntestineMeshGroup = smallIntestineGroup.getMeshGroup(mesh) - cecumMeshGroup = cecumGroup.getMeshGroup(mesh) - allAnnotationGroups += [ileumGroup, ileocecalJunctionGroup, smallIntestineGroup] - - ostiumWallAnnotationGroups = [] - if elementsCountThroughWall == 4: - ileumMucosaGroup = AnnotationGroup(region, get_smallintestine_term("mucosa of ileum")) - ileumSubmucosaGroup = AnnotationGroup(region, get_smallintestine_term("submucosa of ileum")) - ileumCircularGroup = AnnotationGroup(region, get_smallintestine_term("circular muscle layer of ileum")) - ileumLongitudinalGroup = AnnotationGroup(region, - get_smallintestine_term("longitudinal muscle layer of ileum")) - - ostiumWallAnnotationGroups = [[ileumMucosaGroup, mucosaGroup], - [ileumSubmucosaGroup, submucosaGroup], - [ileumCircularGroup, circularMuscleGroup], - [ileumLongitudinalGroup, longitudinalMuscleGroup]] - - allAnnotationGroups += [ileumMucosaGroup, ileumSubmucosaGroup, - ileumCircularGroup, ileumLongitudinalGroup] - - # Points from track surface and vessel end - xPath = [cxIleum[0], xCentre] - d1Path = [cd1Ileum[0], [-d for d in normAxis]] - d2Path = [cd2Ileum[0], d2Centre] - d3Path = [cd3Ileum[0], [-d for d in d1Centre]] - d12Path = [cd2Ileum[0], [0.0, 0.0, 0.0]] - d13Path = [cd3Ileum[0], [0.0, 0.0, 0.0]] - - centralPathIleum = CustomCentralPath(xPath, d1Path, d2Path, d3Path, d12Path, d13Path) - - # for n in range(2): - # node = nodes.createNode(nextNodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xPath[n]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d1Path[n]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d2Path[n]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, d3Path[n]) - # nextNodeIdentifier += 1 - - nextNodeIdentifier, nextElementIdentifier, (o1_x, o1_d1, o1_d2, o1_d3, o1_NodeId, o1_Positions) = \ - generateOstiumMesh(region, ostiumSettings, trackSurfaceOstium, centralPathIleum, - startNodeIdentifier=nextNodeIdentifier, startElementIdentifier=nextElementIdentifier, - vesselMeshGroups=[[cecumMeshGroup, smallIntestineMeshGroup, ileumMeshGroup]], - ostiumMeshGroups=[cecumMeshGroup, ileocecalJunctionMeshGroup], - wallAnnotationGroups=ostiumWallAnnotationGroups, coordinates=None) - - ostiumFaceStartNode = nextNodeIdentifier - ostiumFaceStartElement = nextElementIdentifier - - # Create location of annulus - xAnnulusOuter = [[] for x in range(elementsCountAroundOstium)] - xAnnulusOuterPosition = [[] for x in range(elementsCountAroundOstium)] - d1AnnulusNorm = [] - d1AnnulusOuter = [] - e1Left = elementsAroundTrackSurface - e1Right = 0 - e2Top = 0 - e2Bottom = elementsAlongTrackSurface - sf = vector.magnitude(centralPathIleum.cd2Path[-1]) * 0.25 - for n1 in range(elementsCountAroundOstium): - normD2 = vector.normalise(o1_d2[-1][n1]) - d1AnnulusNorm.append(normD2) - d1AnnulusOuter.append(vector.setMagnitude(o1_d2[-1][n1], sf)) - x = [o1_x[-1][n1][c] + sf * normD2[c] for c in range(3)] - nearestPosition = trackSurfaceOstium.findNearestPosition(x) - e1 = nearestPosition.e1 - e2 = nearestPosition.e2 - if e1 < e1Left: - e1Left = e1 - if e1 > e1Right: - e1Right = e1 - if e2 > e2Top: - e2Top = e2 - if e2 < e2Bottom: - e2Bottom = e2 - xAnnulusOuterPosition[n1] = nearestPosition - xAnnulusOuter[n1] = trackSurfaceOstium.evaluateCoordinates(nearestPosition) - - d2AnnulusOuter = [] - for n in range(elementsCountAlongSegment): - d = findDerivativeBetweenPoints(xAnnulusOuter[n], xAnnulusOuter[(n + 1) % elementsCountAroundOstium]) - d2AnnulusOuter.append(d) - d2AnnulusOuter = interp.smoothCubicHermiteDerivativesLoop(xAnnulusOuter, d2AnnulusOuter) - d3Annulus = [] - for n in range(elementsCountAroundOstium): - d3 = vector.normalise(vector.crossproduct3(vector.normalise(d2AnnulusOuter[n]), d1AnnulusNorm[n])) - d3Annulus.append(d3) - annulusD2Curvature = findCurvatureAroundLoop(xAnnulusOuter, d2AnnulusOuter, d3Annulus) - - # # Visualise annulus - # for n1 in range(len(xAnnulusOuter)): - # node = nodes.createNode(nextNodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xAnnulusOuter[n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d1AnnulusOuter[n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d2AnnulusOuter[n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, [0.0, 0.0, 0.0]) - # nextNodeIdentifier += 1 - - # base row counts with 8 elements around ostium - rowsIncrement = int((elementsCountAlongSegment - 8) / 4) - rowsAbove = 1 + rowsIncrement - rowsOstium = 4 + rowsIncrement * 2 - rowsBelow = 3 + rowsIncrement - - # # rowIdx along segment - startRowIdx = rowsBelow + 1 - endRowIdx = rowsBelow + rowsOstium - 1 - - # sample along the midline of ostium - rotAngle = math.pi - rotFrame = matrix.getRotationMatrixFromAxisAngle(d3ApexUnit, rotAngle) - d1A = [rotFrame[j][0] * d1Cecum[1][0] + rotFrame[j][1] * d1Cecum[1][1] + - rotFrame[j][2] * d1Cecum[1][2] for j in range(3)] - - rotAngle = math.pi - rotFrame = matrix.getRotationMatrixFromAxisAngle(vector.normalise(d3Annulus[0]), rotAngle) - d2B = [rotFrame[j][0] * d1AnnulusOuter[0][0] + rotFrame[j][1] * d1AnnulusOuter[0][1] + - rotFrame[j][2] * d1AnnulusOuter[0][2] for j in range(3)] - - # sample along from apex to annulus start - if segmentIdx == 0: - xStart = xCecum[1] - else: - idx = int(elementsAroundTrackSurface * 0.5) - xStart = xTrackSurface[idx] - - xPositionA = trackSurfaceOstium.findNearestPosition(xStart) - xProportionA = trackSurfaceOstium.getProportion(xPositionA) - derivativeA = trackSurfaceOstium.evaluateCoordinates(xPositionA, derivatives=True)[2] - - xPositionB = trackSurfaceOstium.findNearestPosition(xAnnulusOuter[0]) - xProportionB = trackSurfaceOstium.getProportion(xPositionB) - derivativeB = d2B - derivativeMagnitudeB = vector.magnitude(derivativeB) - - nx, nd1, nd2, nd3, proportions = \ - trackSurfaceOstium.createHermiteCurvePoints( - xProportionA[0], xProportionA[1], xProportionB[0], xProportionB[1], - rowsBelow + 1, derivativeStart=derivativeA, derivativeEnd=derivativeB) - - pxAlongMidLine, pd2AlongMidLine, pd1AlongMidLine = \ - trackSurfaceOstium.resampleHermiteCurvePointsSmooth( - nx, nd1, nd2, nd3, proportions, - derivativeMagnitudeEnd=derivativeMagnitudeB)[0:3] - - for n in range(len(pd1AlongMidLine)): - pd1AlongMidLine[n] = [-d for d in pd1AlongMidLine[n]] - - # for n1 in range(len(nx)): - # node = nodes.createNode(nextNodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, nx[n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, nd2[n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, [0.0, 0.0, 0.0]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, [0.0, 0.0, 0.0]) - # # print(n1, nextNodeIdentifier) - # nextNodeIdentifier += 1 - - # Apex half - # print(startRowIdx) - # pxAlongMidLine, pd2AlongMidLine = \ - # interp.sampleCubicHermiteCurvesSmooth( - # nx, nd2, rowsBelow + 1, - # # derivativeMagnitudeStart=vector.magnitude([nx[1][c] - nx[0][c] for c in range(3)]), - # derivativeMagnitudeEnd=vector.magnitude(d2B))[:2] - - # for n1 in range(len(pxAlongMidLine)): - # node = nodes.createNode(nextNodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, pxAlongMidLine[n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, pd2AlongMidLine[n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, pd1AlongMidLine[n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, [0.0, 0.0, 0.0]) - # nextNodeIdentifier += 1 - - # Next haustrum half - # nx = [xAnnulusOuter[int(elementsCountAlongSegment * 0.5)]] - # nd2 = [d1AnnulusOuter[int(elementsCountAlongSegment * 0.5)]] - # nd1 = [d2AnnulusOuter[int(elementsCountAlongSegment * 0.5)]] - # - # for n in range(elementsAlongTrackSurface - e2Top): - # n1 = e2Top + 1 + n - # idx = elementsCountAroundHalfHaustrum + n1 * (elementsCountAroundHaustrum + 1) - 1 - # nx.append(xTrackSurface[idx]) - # nd2.append(d2TrackSurface[idx]) - # nd1.append(d1TrackSurface[idx]) - # - # pxAlongMidLineBottom, pd2AlongMidLineBottom, pe, pxi, psf = \ - # interp.sampleCubicHermiteCurvesSmooth( - # nx, nd2, rowsAbove + 1, - # derivativeMagnitudeStart=vector.magnitude(nd2[0]), - # derivativeMagnitudeEnd=vector.magnitude(nd2[-1])) - # - # pd1AlongMidLineBottom = nd1 - - xPositionA = trackSurfaceOstium.findNearestPosition(xAnnulusOuter[int(elementsCountAlongSegment * 0.5)]) - xProportionA = trackSurfaceOstium.getProportion(xPositionA) - xA, derivative2A, derivativeA = trackSurfaceOstium.evaluateCoordinates(xPositionA, derivatives=True) - derivativeMagnitudeA = vector.magnitude(d2AnnulusOuter[int(elementsCountAlongSegment * 0.5)]) # derivativeA) - - xB = xTrackSurface[-elementsCountAroundHalfHaustrum] - xPositionB = trackSurfaceOstium.findNearestPosition(xB) - xProportionB = trackSurfaceOstium.getProportion(xPositionB) - derivativeB = d2TrackSurface[-elementsCountAroundHalfHaustrum] - - nx, nd1, nd2, nd3, proportions = \ - trackSurfaceOstium.createHermiteCurvePoints( - xProportionA[0], xProportionA[1], xProportionB[0], xProportionB[1], - rowsAbove + 1, derivativeStart=derivativeA, derivativeEnd=derivativeB) - - pxAlongMidLineBottom, pd2AlongMidLineBottom, pd1AlongMidLineBottom = \ - trackSurfaceOstium.resampleHermiteCurvePointsSmooth( - nx, nd1, nd2, nd3, proportions, derivativeMagnitudeStart=derivativeMagnitudeA, - derivativeMagnitudeEnd=derivativeMagnitudeA)[0:3] - - for n in range(len(pd1AlongMidLineBottom)): - pd1AlongMidLineBottom[n] = [-d for d in pd1AlongMidLineBottom[n]] - - # for n1 in range(len(pxAlongMidLineBottom)): - # node = nodes.createNode(nextNodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, pxAlongMidLineBottom[n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, pd2AlongMidLineBottom[n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, pd1AlongMidLineBottom[n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, [0.0, 0.0, 0.0]) - # nextNodeIdentifier += 1 - - # sample points around colon to ostium - annulusIdx = 1 - xAroundAlong = [] - d1AroundAlong = [] - - sideElements = int(elementsCountAroundHaustrum * 0.5) - for n2 in range(elementsCountAlongSegment): - xAround = [] - d1Around = [] - if n2 == 0 and segmentIdx == 0: - for n1 in range(elementsCountAroundHaustrum + 1): - xAround.append(xApex) - d1Around.append(d1A) - else: - for n in range(2): - # LHS - if n == 0: - xPositionA = trackSurfaceOstium.findNearestPosition( - xTrackSurface[n2 * (elementsCountAroundHaustrum + 1)]) - xProportionA = trackSurfaceOstium.getProportion(xPositionA) - derivativeA = d1TrackSurface[n2 * (elementsCountAroundHaustrum + 1)] - - if n2 < rowsBelow + 1: - xPositionB = trackSurfaceOstium.findNearestPosition(pxAlongMidLine[n2]) - derivativeB = None - - elif n2 >= rowsBelow + rowsOstium: - idx = n2 - (rowsBelow + rowsOstium) + 1 - xPositionB = trackSurfaceOstium.findNearestPosition(pxAlongMidLineBottom[idx]) - derivativeB = None - - else: - xPositionB = trackSurfaceOstium.findNearestPosition(xAnnulusOuter[annulusIdx]) - rotAngle = math.pi - rotFrame = matrix.getRotationMatrixFromAxisAngle(vector.normalise(d3Annulus[annulusIdx]), - rotAngle) - derivativeB = [rotFrame[j][0] * d1AnnulusOuter[annulusIdx][0] + - rotFrame[j][1] * d1AnnulusOuter[annulusIdx][1] + - rotFrame[j][2] * d1AnnulusOuter[annulusIdx][2] for j in range(3)] - - xProportionB = trackSurfaceOstium.getProportion(xPositionB) - - # node = nodes.createNode(nextNodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xTrackSurface[n2 * (elementsCountAroundHaustrum + 1)]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, [0.0, 0.0, 0.0]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, derivativeA) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, [0.0, 0.0, 0.0]) - # nextNodeIdentifier += 1 - # - # node = nodes.createNode(nextNodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xB) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, [0.0, 0.0, 0.0]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, derivativeB) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, [0.0, 0.0, 0.0]) - # nextNodeIdentifier += 1 - - else: # RHS - if n2 < rowsBelow + 1: - xPositionA = trackSurfaceOstium.findNearestPosition(pxAlongMidLine[n2]) - derivativeA = None - - elif n2 >= rowsBelow + rowsOstium: - idx = n2 - (rowsBelow + rowsOstium) + 1 - xPositionA = trackSurfaceOstium.findNearestPosition(pxAlongMidLineBottom[idx]) - derivativeA = None - - else: - xPositionA = trackSurfaceOstium.findNearestPosition(xAnnulusOuter[-annulusIdx]) - derivativeA = d1AnnulusOuter[-annulusIdx] - xProportionA = trackSurfaceOstium.getProportion(xPositionA) - - xPositionB = trackSurfaceOstium.findNearestPosition( - xTrackSurface[n2 * (elementsCountAroundHaustrum + 1) + elementsCountAroundHaustrum]) - xProportionB = trackSurfaceOstium.getProportion(xPositionB) - derivativeB = d1TrackSurface[n2 * (elementsCountAroundHaustrum + 1) + elementsCountAroundHaustrum] - - nx, nd1, nd2, nd3, proportions = \ - trackSurfaceOstium.createHermiteCurvePoints( - xProportionA[0], xProportionA[1], xProportionB[0], xProportionB[1], - sideElements +(0 if (n2 < rowsBelow + 1 or n2 >= rowsBelow + rowsOstium) else -1), - derivativeStart=derivativeA, derivativeEnd=derivativeB) - - nx, nd1 = \ - trackSurfaceOstium.resampleHermiteCurvePointsSmooth( - nx, nd1, nd2, nd3, proportions)[0:2] - - # for n in range(len(nx)): - # node = nodes.createNode(nextNodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, nx[n]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, nd1[n]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, [0.0, 0.0, 0.0]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, [0.0, 0.0, 0.0]) - # nextNodeIdentifier += 1 - - if n2 == rowsBelow + 1 or n2 == rowsBelow + rowsOstium - 1: - mag = 0.5 * (vector.magnitude(d1AnnulusOuter[0]) + vector.magnitude( - d2AnnulusOuter[0])) if n2 == startRowIdx else vector.magnitude(d1AnnulusOuter[0]) - if n == 0: - nd1[-1] = vector.setMagnitude(nd1[-1], mag) - else: - nd1[0] = vector.setMagnitude(nd1[0], mag) - if n == 0: - xAround += nx - d1Around += nd1 - else: - xAround += nx[(1 if (n2 < rowsBelow + 1 or n2 >= rowsBelow + rowsOstium) else 0):] - d1Around += nd1[(1 if (n2 < rowsBelow + 1 or n2 >= rowsBelow + rowsOstium) else 0):] - if n2 < rowsBelow + 1 or n2 >= rowsBelow + rowsOstium: - d1Around = interp.smoothCubicHermiteDerivativesLine(xAround, d1Around, fixStartDerivative=True, - fixEndDerivative=True) - - if n2 >= rowsBelow + 1 and n2 < rowsBelow + rowsOstium: - annulusIdx += 1 - - xAroundAlong.append(xAround) - d1AroundAlong.append(d1Around) - - xAround = [] - d1Around = [] - for n1 in range(elementsCountAroundHaustrum + 1): - xAround.append(xTrackSurface[n1 + (elementsCountAroundHaustrum + 1) * elementsCountAlongSegment]) - d1Around.append(d1TrackSurface[n1 + (elementsCountAroundHaustrum + 1) * elementsCountAlongSegment]) - xAroundAlong.append(xAround) - d1AroundAlong.append(d1Around) - - # Calculate d2 along segment - d2AroundAlong = [] - xAlongAll = [] - d2AlongAll = [] - - for n2 in range(len(xAroundAlong)): - d2Around = [] - for n1 in range(len(xAroundAlong[n2])): - d2Around.append([0.0, 0.0, 0.0]) - d2AroundAlong.append(d2Around) - - for n1 in range(elementsCountAroundHaustrum + 1): - nxAlong = [] - nd2Along = [] - if n1 < elementsCountAroundHalfHaustrum - 1: - for n2 in range(elementsCountAlongSegment): - nxAlong.append(xAroundAlong[n2][n1]) - nd2Along.append(findDerivativeBetweenPoints(xAroundAlong[n2][n1], xAroundAlong[n2 + 1][n1])) - nxAlong.append(xAroundAlong[n2 + 1][n1]) - nd2Along.append(d2TrackSurface[(elementsCountAroundHaustrum + 1) * elementsCountAlongSegment + n1]) - nd2Along = interp.smoothCubicHermiteDerivativesLine(nxAlong, nd2Along, fixStartDerivative=True, - fixEndDerivative=True) - - # Replace d2 on node along annulus LHS with d2Annulus - if n1 == elementsCountAroundHalfHaustrum - 2: - nd2Along[startRowIdx] = d2AnnulusOuter[1] - nd2Along[endRowIdx] = d2AnnulusOuter[int(elementsCountAroundOstium * 0.5) - 1] - - xAlongAll.append(nxAlong) - d2AlongAll.append(nd2Along) - - for n2 in range(len(nd2Along)): - d2AroundAlong[n2][n1] = nd2Along[n2] - - elif n1 == elementsCountAroundHalfHaustrum - 1: - for n2 in range(len(pxAlongMidLine)): - d2AroundAlong[n2][n1] = pd2AlongMidLine[n2] - for n in range(1, len(pxAlongMidLineBottom)): - d2AroundAlong[n + endRowIdx][n1] = pd2AlongMidLineBottom[n] - nxAlong = pxAlongMidLine + pxAlongMidLineBottom - xAlongAll.append(nxAlong) - d2AlongAll.append(pd2AlongMidLine + pd2AlongMidLineBottom) - - else: - for n2 in range(elementsCountAlongSegment): - nxAlong.append(xAroundAlong[n2][n1 + (0 if (n2 < startRowIdx or n2 > endRowIdx) else -1)]) - if n2 < startRowIdx - 1 or n2 > endRowIdx -1: - nxAlongNext = xAroundAlong[n2 + 1][n1] - else: - nxAlongNext = xAroundAlong[n2 + 1][n1 - 1] - nd2Along.append(findDerivativeBetweenPoints( - xAroundAlong[n2][n1 + (0 if (n2 < startRowIdx or n2 > endRowIdx) else -1)], nxAlongNext)) - - nxAlong.append(xAroundAlong[n2 + 1][n1]) - nd2Along.append(d2TrackSurface[(elementsCountAroundHaustrum + 1) * elementsCountAlongSegment + n1]) - nd2Along = interp.smoothCubicHermiteDerivativesLine(nxAlong, nd2Along, fixStartDerivative=True, - fixEndDirection=True) - - # Replace d2 on node along annulus RHS with d2Annulus - if n1 == elementsCountAroundHalfHaustrum: - nd2Along[startRowIdx] = [-d for d in d2AnnulusOuter[-1]] - nd2Along[endRowIdx] = [-d for d in d2AnnulusOuter[int(elementsCountAroundOstium * 0.5) + 1]] - - xAlongAll.append(nxAlong) - d2AlongAll.append(nd2Along) - - for n2 in range(len(nd2Along)): - if n2 < startRowIdx or n2 > endRowIdx: - n1Idx = n1 - else: - n1Idx = n1 - 1 - d2AroundAlong[n2][n1Idx] = nd2Along[n2] - - # Calculate d3 - d3UnitAroundAlong = [] - for n2 in range(len(xAroundAlong)): - d3Around = [] - for n1 in range(len(xAroundAlong[n2])): - d3Around.append(vector.normalise( - vector.crossproduct3(vector.normalise(d1AroundAlong[n2][n1]), - vector.normalise(d2AroundAlong[n2][n1])))) - d3UnitAroundAlong.append(d3Around) - - # for n2 in range(len(xAroundAlong)): - # for n1 in range(len(xAroundAlong[n2])): - # node = nodes.createNode(nextNodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xAroundAlong[n2][n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d1AroundAlong[n2][n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d2AroundAlong[n2][n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, d3UnitAroundAlong[n2][n1]) - # nextNodeIdentifier += 1 - - # Calculate curvatures - # Curvatures around - d1Curvature = [] - if segmentIdx == 0: - d1Curvature.append([0.0]) - - for n2 in range(1 if segmentIdx == 0 else 0, elementsCountAlongSegment + 1): - if n2 < startRowIdx or n2 == elementsCountAlongSegment: - d1Curvature.append(findCurvatureAlongLine(xAroundAlong[n2], d1AroundAlong[n2], d3UnitAroundAlong[n2])) - else: - d1CurvatureLeft = findCurvatureAlongLine(xAroundAlong[n2][:int(0.5 * len(xAroundAlong[n2]))], - d1AroundAlong[n2][:int(0.5 * len(xAroundAlong[n2]))], - d3UnitAroundAlong[n2][:int(0.5 * len(xAroundAlong[n2]))]) - - d1CurvatureRight = findCurvatureAlongLine(xAroundAlong[n2][int(0.5 * len(xAroundAlong[n2])):], - d1AroundAlong[n2][int(0.5 * len(xAroundAlong[n2])):], - d3UnitAroundAlong[n2][int(0.5 * len(xAroundAlong[n2])):]) - - d1Curvature.append(d1CurvatureLeft + d1CurvatureRight) - - # Curvatures along - d2Curvature = [] - for n2 in range(len(xAroundAlong)): - d2CurvatureAround = [] - for n1 in range(len(xAroundAlong[n2])): - d2CurvatureAround.append(0.0) - d2Curvature.append(d2CurvatureAround) - - for n1 in range(elementsCountAroundHaustrum + 1): - xAlong = xAlongAll[n1] - d2Along = d2AlongAll[n1] - d3UnitAlong = [] - - if n1 < elementsCountAroundHalfHaustrum - 1: - for n2 in range(elementsCountAlongSegment): - d3UnitAlong.append(d3UnitAroundAlong[n2][n1]) - d3UnitAlong.append(d3UnitAroundAlong[n2 + 1][n1]) - d2CurvatureAlong = findCurvatureAlongLine(xAlong, d2Along, d3UnitAlong) - # Adjust for corners - if n1 == elementsCountAroundHalfHaustrum - 2: - d2CurvatureAlong[endRowIdx] = annulusD2Curvature[int(elementsCountAlongSegment * 0.5) - 1] - - for n2 in range(len(d2CurvatureAlong)): - d2Curvature[n2][n1] = d2CurvatureAlong[n2] - - elif n1 == elementsCountAroundHalfHaustrum - 1: - xAlong = [] - d2Along = [] - d3UnitAlong = [] - for n2 in range(len(pd2AlongMidLine)): - xAlong.append(xAroundAlong[n2][n1]) - d2Along.append(d2AroundAlong[n2][n1]) - d3UnitAlong.append(d3UnitAroundAlong[n2][n1]) - d2CurvatureAlong = findCurvatureAlongLine(xAlong, d2Along, d3UnitAlong) - for n2 in range(len(pd2AlongMidLine)): - d2Curvature[n2][n1] = d2CurvatureAlong[n2] - - # Calculate curvature for node on edge - xAlong = [] - d2Along = [] - d3UnitAlong = [] - for n in range(1, len(pd2AlongMidLineBottom)): - nIdx = n + endRowIdx - xAlong.append(xAroundAlong[nIdx][n1]) - d2Along.append(d2AroundAlong[nIdx][n1]) - d3UnitAlong.append(d3UnitAroundAlong[nIdx][n1]) - d2CurvatureAlong = findCurvatureAlongLine(xAlong, d2Along, d3UnitAlong) - for n in range(len(pd2AlongMidLineBottom) - 1): - nIdx = n + endRowIdx + 1 - d2Curvature[nIdx][n1] = d2CurvatureAlong[n] - else: - for n2 in range(elementsCountAlongSegment): - d3UnitAlong.append(d3UnitAroundAlong[n2][n1 + (0 if (n2 < startRowIdx or n2 > endRowIdx) else -1)]) - d3UnitAlong.append(d3UnitAroundAlong[n2 + 1][n1]) - d2CurvatureAlong = findCurvatureAlongLine(xAlong, d2Along, d3UnitAlong) - - # Adjust for corners - if n1 == elementsCountAroundHalfHaustrum: - d2CurvatureAlong[endRowIdx] = annulusD2Curvature[int(elementsCountAlongSegment * 0.5) + 1] - - for n2 in range(len(d2CurvatureAlong)): - if n2 < startRowIdx or n2 > endRowIdx: - n1Idx = n1 - else: - n1Idx = n1 - 1 - d2Curvature[n2][n1Idx] = d2CurvatureAlong[n2] - - # Slot in annulus points along the midline - rotFrame = matrix.getRotationMatrixFromAxisAngle(d3Annulus[0], math.pi) - rotD2 = [rotFrame[j][0] * d2AnnulusOuter[0][0] + rotFrame[j][1] * d2AnnulusOuter[0][1] + - rotFrame[j][2] * d2AnnulusOuter[0][2] for j in range(3)] - xAroundAlong[startRowIdx].insert(int(elementsCountAroundHaustrum * 0.5), xAnnulusOuter[0]) - d1AroundAlong[startRowIdx].insert(int(elementsCountAroundHaustrum * 0.5), rotD2) - d2AroundAlong[startRowIdx].insert(int(elementsCountAroundHaustrum * 0.5), d1AnnulusOuter[0]) - d3UnitAroundAlong[startRowIdx].insert(int(elementsCountAroundHaustrum * 0.5), d3Annulus[0]) - d1Curvature[startRowIdx].insert(int(elementsCountAroundHaustrum * 0.5), annulusD2Curvature[0]) - d2Curvature[startRowIdx].insert(int(elementsCountAroundHaustrum * 0.5), annulusD2Curvature[0]) - - idx = int(elementsCountAlongSegment * 0.5) - xAroundAlong[endRowIdx].insert(int(elementsCountAroundHaustrum * 0.5), xAnnulusOuter[idx]) - d1AroundAlong[endRowIdx].insert(int(elementsCountAroundHaustrum * 0.5), d2AnnulusOuter[idx]) - d2AroundAlong[endRowIdx].insert(int(elementsCountAroundHaustrum * 0.5), d1AnnulusOuter[idx]) - d3UnitAroundAlong[endRowIdx].insert(int(elementsCountAroundHaustrum * 0.5), d3Annulus[idx]) - d1Curvature[endRowIdx].insert(int(elementsCountAroundHaustrum * 0.5), annulusD2Curvature[idx]) - d2Curvature[endRowIdx].insert(int(elementsCountAroundHaustrum * 0.5), annulusD2Curvature[idx]) - - # for n2 in range(len(xAroundAlong)): - # for n1 in range(len(xAroundAlong[n2])): - # node = nodes.createNode(nextNodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xAroundAlong[n2][n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d1AroundAlong[n2][n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d2AroundAlong[n2][n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, d3UnitAroundAlong[n2][n1]) - # nextNodeIdentifier += 1 - - # Create inner nodes - sideNodesToDelete = [] - xList = [] - d1List = [] - d2List = [] - d3List = [] - nodeIdx = ostiumFaceStartNode - idxMat = [] - - if elementsCountThroughWall > 1: - thicknessProportionsUI = [0.0, mucosaRelThickness, submucosaRelThickness, circularRelThickness, - longitudinalRelThickness, longitudinalRelThickness] - thicknessProportions = [thicknessProportion / sum(thicknessProportionsUI[:-1]) - for thicknessProportion in thicknessProportionsUI] - - xi3List = [] - xi3 = 0.0 - for i in range(len(thicknessProportions) - 1): - xi3 += thicknessProportions[i] - xi3List.append(xi3) - - count = 0 - for n2 in range(len(xAroundAlong)): - idxThroughWall = [] - for n3 in range(elementsCountThroughWall + 1): - xi3 = xi3List[n3] if elementsCountThroughWall > 1 else 1.0 / elementsCountThroughWall * n3 - idxAround = [] - - for n1 in range(1 if (n2 == 0 and segmentIdx == 0) else len(xAroundAlong[n2])): - if n1 == 0 or n1 == len(xAroundAlong[n2]) - 1: - sideNodesToDelete.append(nodeIdx) - newNodeIdx = sideNodes[count] + startNode - 1 - count += 1 - - elif n2 == 0 and segmentIdx and n1 > 0 and n1 < len(xAroundAlong[n2]) - 1: - sideNodesToDelete.append(nodeIdx) - newNodeIdx = sideNodes[count] + startNode - 1 - count += 1 - - elif n2 == len(xAroundAlong) - 1 and n1 > 0 and n1 < len(xAroundAlong[n2]) - 1: - sideNodesToDelete.append(nodeIdx) - newNodeIdx = sideNodes[count] + startNode - 1 - count += 1 - - else: - newNodeIdx = nodeIdx - - # Coordinates - norm = d3UnitAroundAlong[n2][n1] - xOut = xAroundAlong[n2][n1] - xIn = [xOut[i] - norm[i] * wallThickness for i in range(3)] - dWall = [wallThickness * c for c in norm] - x = interp.interpolateCubicHermite(xIn, dWall, xOut, dWall, xi3) - xList.append(x) - - # d1 - factor = 1.0 + wallThickness * (1.0 - xi3) * d1Curvature[n2][n1] - d1 = [factor * c for c in d1AroundAlong[n2][n1]] - d1List.append(d1) - - # d2 - factor = 1.0 + wallThickness * (1.0 - xi3) * d2Curvature[n2][n1] - d2 = [factor * c for c in d2AroundAlong[n2][n1]] - d2List.append(d2) - - # d3 - d3 = [c * wallThickness * (thicknessProportions[n3 + 1] if elementsCountThroughWall > 1 else 1.0) - for c in norm] - d3List.append(d3) - - idxAround.append(newNodeIdx) - nodeIdx += 1 - idxThroughWall.append(idxAround) - idxMat.append(idxThroughWall) - - for n in range(len(xList)): - if nextNodeIdentifier in sideNodesToDelete: - nextNodeIdentifier += 1 - continue - else: - node = nodes.createNode(nextNodeIdentifier, nodetemplate) - cache.setNode(node) - coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xList[n]) - coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d1List[n]) - coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d2List[n]) - coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, d3List[n]) - if useCrossDerivatives: - coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D2_DS1DS2, 1, zero) - coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D2_DS1DS3, 1, zero) - coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D2_DS2DS3, 1, zero) - coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D3_DS1DS2DS3, 1, zero) - nextNodeIdentifier += 1 - - # Create elements - elementIdxMat = [] - - if useCubicHermiteThroughWall: - eftfactory = eftfactory_tricubichermite(mesh, useCrossDerivatives) - else: - eftfactory = eftfactory_bicubichermitelinear(mesh, useCrossDerivatives) - eftStandard = eftfactory.createEftBasic() - - elementtemplateStandard = mesh.createElementtemplate() - elementtemplateStandard.setElementShapeType(Element.SHAPE_TYPE_CUBE) - elementtemplateStandard.defineField(coordinates, -1, eftStandard) - - elementtemplateX = mesh.createElementtemplate() - elementtemplateX.setElementShapeType(Element.SHAPE_TYPE_CUBE) - - radiansPerElementAround = math.pi * 2.0 / elementsCountAround - elementIdentifier = ostiumFaceStartElement - - for e2 in range(elementsCountAlongSegment): - elementIdxThroughWall = [] - if segmentIdx == 0 and e2 == 0: # pole - for e3 in range(elementsCountThroughWall): - elementIdxAround = [] - for e1 in range(elementsCountAroundHaustrum): - va = e1 + startIdxElementsAround - vb = (e1 + startIdxElementsAround + 1) - eft1 = eftfactory.createEftShellPoleBottom(va * 100, vb * 100) - elementtemplateX.defineField(coordinates, -1, eft1) - element = mesh.createElement(elementIdentifier, elementtemplateX) - bni1 = e3 + 1 + startNode - 1 - bni2 = idxMat[e2 + 1][e3][e1] - bni3 = idxMat[e2 + 1][e3][e1 + 1] - bni4 = bni1 + 1 - bni5 = idxMat[e2 + 1][e3 + 1][e1] - bni6 = idxMat[e2 + 1][e3 + 1][e1 + 1] - nodeIdentifiers = [bni1, bni2, bni3, bni4, bni5, bni6] - element.setNodesByIdentifier(eft1, nodeIdentifiers) - # set general linear map coefficients - radiansAround = (e1 + 1) * radiansPerElementAround + sectorStartAngle - radiansAroundNext = (e1 + 2) * radiansPerElementAround + sectorStartAngle - scalefactors = [ - -1.0, - math.sin(radiansAround), math.cos(radiansAround), radiansPerElementAround, - math.sin(radiansAroundNext), math.cos(radiansAroundNext), radiansPerElementAround, - math.sin(radiansAround), math.cos(radiansAround), radiansPerElementAround, - math.sin(radiansAroundNext), math.cos(radiansAroundNext), radiansPerElementAround] - element.setScaleFactors(eft1, scalefactors) - elementIdxAround.append(elementIdentifier) - elementIdentifier += 1 - annotationGroups = annotationGroupsAlong[e2] + annotationGroupsThroughWall[e3] - if annotationGroups: - allAnnotationGroups = mergeAnnotationGroups(allAnnotationGroups, annotationGroups) - for annotationGroup in annotationGroups: - meshGroup = annotationGroup.getMeshGroup(mesh) - meshGroup.addElement(element) - elementIdxThroughWall.append(elementIdxAround) - elementIdxMat.append(elementIdxThroughWall) - else: - for e3 in range(elementsCountThroughWall): - elementIdxAround = [] - for e1 in range(len(xAroundAlong[e2]) - 1): - offset = 0 - if endRowIdx - startRowIdx > 1: - if e2 == startRowIdx and e1 > int(0.5 * len(xAroundAlong[e2])): - offset = -1 - elif e2 == endRowIdx - 1 and e1 >= int(0.5 * len(xAroundAlong[e2])): - offset = 1 - - if (startRowIdx <= e2 <= endRowIdx - 1) and 0.5 * len(xAroundAlong[e2]) - 2 < e1 < 0.5 * len( - xAroundAlong[e2]): - continue - else: - eft1 = eftStandard - scaleFactors = [] - elementtemplate1 = elementtemplateStandard - bni111 = idxMat[e2][e3][e1] - bni211 = idxMat[e2][e3][e1 + 1] - bni121 = idxMat[e2 + 1][e3][e1 + offset] - bni221 = idxMat[e2 + 1][e3][e1 + 1 + offset] - bni112 = idxMat[e2][e3 + 1][e1] - bni212 = idxMat[e2][e3 + 1][e1 + 1] - bni122 = idxMat[e2 + 1][e3 + 1][e1 + offset] - bni222 = idxMat[e2 + 1][e3 + 1][e1 + 1 + offset] - nodeIdentifiers = [bni111, bni211, bni121, bni221, - bni112, bni212, bni122, bni222] - - if e2 == startRowIdx - 1 and e1 == elementsCountAroundHalfHaustrum - 2: # LHS bottom - scaleFactors = [-1.0] - eft1 = eftfactory.createEftNoCrossDerivatives() - setEftScaleFactorIds(eft1, [1], []) - remapEftNodeValueLabel(eft1, [3, 7], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS2, [1])]) - remapEftNodeValueLabel(eft1, [3, 7], Node.VALUE_LABEL_D_DS2, - [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [])]) - remapEftNodeValueLabel(eft1, [4, 8], Node.VALUE_LABEL_D_DS2, - [(Node.VALUE_LABEL_D_DS2, [1])]) - - elementtemplateX.defineField(coordinates, -1, eft1) - elementtemplate1 = elementtemplateX - - elif e2 == startRowIdx - 1 and e1 == elementsCountAroundHalfHaustrum - 1: # RHS bottom - scaleFactors = [-1.0] - eft1 = eftfactory.createEftNoCrossDerivatives() - setEftScaleFactorIds(eft1, [1], []) - remapEftNodeValueLabel(eft1, [3, 7], Node.VALUE_LABEL_D_DS2, - [(Node.VALUE_LABEL_D_DS2, [1])]) - remapEftNodeValueLabel(eft1, [4, 8], Node.VALUE_LABEL_D_DS2, - [(Node.VALUE_LABEL_D_DS1, [1]), (Node.VALUE_LABEL_D_DS2, [])]) - remapEftNodeValueLabel(eft1, [4, 8], Node.VALUE_LABEL_D_DS1, - [(Node.VALUE_LABEL_D_DS2, [])]) - elementtemplateX.defineField(coordinates, -1, eft1) - elementtemplate1 = elementtemplateX - - elif e2 == startRowIdx - 1 and e1 == elementsCountAroundHalfHaustrum: # RHS bottom + 1 - scaleFactors = [-1.0] - eft1 = eftfactory.createEftNoCrossDerivatives() - setEftScaleFactorIds(eft1, [1], []) - remapEftNodeValueLabel(eft1, [3, 7], Node.VALUE_LABEL_D_DS2, - [(Node.VALUE_LABEL_D_DS1, [1]), (Node.VALUE_LABEL_D_DS2, [])]) - elementtemplateX.defineField(coordinates, -1, eft1) - elementtemplate1 = elementtemplateX - - elif e2 == startRowIdx - 1 and e1 == elementsCountAroundHalfHaustrum - 3: # LHS Bottom Left - 1 - eft1 = eftfactory.createEftNoCrossDerivatives() - remapEftNodeValueLabel(eft1, [4, 8], Node.VALUE_LABEL_D_DS2, - [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [])]) - elementtemplateX.defineField(coordinates, -1, eft1) - elementtemplate1 = elementtemplateX - - elif e2 == endRowIdx and e1 == elementsCountAroundHalfHaustrum - 2: # end LHS - scaleFactors = [-1.0] - eft1 = eftfactory.createEftNoCrossDerivatives() - setEftScaleFactorIds(eft1, [1], []) - remapEftNodeValueLabel(eft1, [1, 5], Node.VALUE_LABEL_D_DS2, - [(Node.VALUE_LABEL_D_DS1, [1]), (Node.VALUE_LABEL_D_DS2, [])]) - remapEftNodeValueLabel(eft1, [1, 5], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS2, [])]) - elementtemplateX.defineField(coordinates, -1, eft1) - elementtemplate1 = elementtemplateX - - elif e2 == endRowIdx and e1 == elementsCountAroundHalfHaustrum - 3: # end LHS -1 - scaleFactors = [-1.0] - eft1 = eftfactory.createEftNoCrossDerivatives() - setEftScaleFactorIds(eft1, [1], []) - remapEftNodeValueLabel(eft1, [2, 6], Node.VALUE_LABEL_D_DS2, - [(Node.VALUE_LABEL_D_DS1, [1]), (Node.VALUE_LABEL_D_DS2, [])]) - elementtemplateX.defineField(coordinates, -1, eft1) - elementtemplate1 = elementtemplateX - - elif e2 == endRowIdx and e1 == elementsCountAroundHalfHaustrum - 1: # end RHS - scaleFactors = [-1.0] - eft1 = eftfactory.createEftNoCrossDerivatives() - setEftScaleFactorIds(eft1, [1], []) - remapEftNodeValueLabel(eft1, [2, 6], Node.VALUE_LABEL_D_DS1, - [(Node.VALUE_LABEL_D_DS2, [1])]) - remapEftNodeValueLabel(eft1, [2, 6], Node.VALUE_LABEL_D_DS2, - [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [])]) - - elementtemplateX.defineField(coordinates, -1, eft1) - elementtemplate1 = elementtemplateX - - elif e2 == endRowIdx and e1 == elementsCountAroundHalfHaustrum: # end RHS + 1 - eft1 = eftfactory.createEftNoCrossDerivatives() - remapEftNodeValueLabel(eft1, [1, 5], Node.VALUE_LABEL_D_DS2, - [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [])]) - elementtemplateX.defineField(coordinates, -1, eft1) - elementtemplate1 = elementtemplateX - - element = mesh.createElement(elementIdentifier, elementtemplate1) - element.setNodesByIdentifier(eft1, nodeIdentifiers) - if scaleFactors: - element.setScaleFactors(eft1, scaleFactors) - elementIdxAround.append(elementIdentifier) - elementIdentifier += 1 - annotationGroups = annotationGroupsAlong[e2] + annotationGroupsThroughWall[e3] - if annotationGroups: - allAnnotationGroups = mergeAnnotationGroups(allAnnotationGroups, annotationGroups) - for annotationGroup in annotationGroups: - meshGroup = annotationGroup.getMeshGroup(mesh) - meshGroup.addElement(element) - elementIdxThroughWall.append(elementIdxAround) - elementIdxMat.append(elementIdxThroughWall) - - # Annulus - # Assemble endPoints for annulus - endPoints_x = [[None] * elementsCountAroundOstium for n3 in range(elementsCountThroughWall + 1)] - endPoints_d1 = [[None] * elementsCountAroundOstium for n3 in range(elementsCountThroughWall + 1)] - endPoints_d2 = [[None] * elementsCountAroundOstium for n3 in range(elementsCountThroughWall + 1)] - endNode_Id = [[None] * elementsCountAroundOstium for n3 in range(elementsCountThroughWall + 1)] - endDerivativesMap = [[None] * elementsCountAroundOstium for n3 in range(elementsCountThroughWall + 1)] - endProportions = [] - - for n3 in range(elementsCountThroughWall + 1): - n1 = 0 - for nAround in range(elementsCountAroundOstium): - if nAround == 0: - idx = idxMat[startRowIdx][n3][elementsCountAroundHalfHaustrum - 1] - elif 0 < nAround < (elementsCountAroundOstium * 0.5): - idx = idxMat[startRowIdx + n1][n3][elementsCountAroundHalfHaustrum - 2] - n1 += 1 - elif nAround == int(elementsCountAroundOstium * 0.5): - n1 -= 1 - idx = idxMat[startRowIdx + n1][n3][elementsCountAroundHalfHaustrum - 1] - else: - idx = idxMat[startRowIdx + n1][n3][ - elementsCountAroundHalfHaustrum - 1 + ( - 1 if (n1 == int(elementsCountAroundOstium * 0.5) - 2 or n1 == 0) else 0)] - n1 -= 1 - - endPoints_x[n3][nAround] = xList[idx - ostiumFaceStartNode] - endPoints_d1[n3][nAround] = d1List[idx - ostiumFaceStartNode] - endPoints_d2[n3][nAround] = d2List[idx - ostiumFaceStartNode] - endNode_Id[n3][nAround] = idx - - if n3 == elementsCountThroughWall: # outer layer - endPosition = trackSurfaceOstium.findNearestPosition(endPoints_x[n3][nAround]) - endProportions.append(trackSurfaceOstium.getProportion(endPosition)) - - for n3 in range(elementsCountThroughWall + 1): - for nAround in range(elementsCountAroundOstium): - if nAround == 0: - endDerivativesMap[n3][nAround] = ((-1, 0, 0), (0, 1, 0), None) - elif 1 <= nAround < int(elementsCountAroundOstium * 0.5): - endDerivativesMap[n3][nAround] = ((0, 1, 0), (-1, 0, 0), None) - elif nAround == int(elementsCountAroundOstium * 0.5): - endDerivativesMap[n3][nAround] = (None, None, None) - else: - endDerivativesMap[n3][nAround] = ((0, -1, 0), (1, 0, 0), None) - - startProportions = [] - for n in range(elementsCountAroundOstium): - startProportions.append(trackSurfaceOstium.getProportion(o1_Positions[n])) - - cecumWallAnnotationGroups = [] - if elementsCountThroughWall == 4: - cecumWallAnnotationGroups = [[mucosaGroup], [submucosaGroup], [circularMuscleGroup], - [longitudinalMuscleGroup]] - - nextNodeIdentifier, nextElementIdentifier = createAnnulusMesh3d( - nodes, mesh, nextNodeIdentifier, elementIdentifier, - o1_x, o1_d1, o1_d2, None, o1_NodeId, None, - endPoints_x, endPoints_d1, endPoints_d2, None, endNode_Id, endDerivativesMap, - elementsCountRadial=1, meshGroups=[cecumMeshGroup], - wallAnnotationGroups=cecumWallAnnotationGroups, - tracksurface=trackSurfaceOstium, - startProportions=startProportions, endProportions=endProportions, - rescaleStartDerivatives=True, rescaleEndDerivatives=True, sampleBlend=0.0, fixMinimumStart=True, - coordinates=coordinates) - - # Delete elements in new haustrum - mesh_destroy_elements_and_nodes_by_identifiers(mesh, deleteElementIdentifier) - - return allAnnotationGroups, nextNodeIdentifier, nextElementIdentifier #, nodeIdDistal, xDistal, d1Distal, \ - # d2Distal, d3Distal - - -class CecumCentralPath: - """ - Generates sampled central path for cecum scaffold. - """ - def __init__(self, region, centralPath, termsAlong=[None]): - """ - :param region: Zinc region to define model in. - :param centralPath: Central path subscaffold from meshtype_1d_path1 - :param termsAlong: Annotation terms along length of central path - """ - # Extract length of each group along stomach from central path - arcLengthOfGroupsAlong = [] - cxGroups = [] - cd1Groups = [] - cd2Groups = [] - cd3Groups = [] - cd12Groups = [] - cd13Groups = [] - - tmpRegion = region.createRegion() - centralPath.generate(tmpRegion) - pathNetworkMesh = centralPath.getConstructionObject() - tmpFieldmodule = tmpRegion.getFieldmodule() - tmpNodes = tmpFieldmodule.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES) - tmpCoordinates = tmpFieldmodule.findFieldByName('coordinates') - networkSegments = pathNetworkMesh.getNetworkSegments() - - cxGroup = [] - cd1Group = [] - cd2Group = [] - cd3Group = [] - cd12Group = [] - cd13Group = [] - - for termName in termsAlong: - tmpGroup = tmpFieldmodule.findFieldByName(termName).castGroup() if termName else None - tmpNodeset = tmpGroup.getNodesetGroup(tmpNodes) if tmpGroup else tmpNodes - - if termName == "caecum": - for i in range(2): - cx, cd1, cd2, cd3, cd12, cd13 = get_nodeset_path_ordered_field_parameters( - tmpNodeset, tmpCoordinates, - [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], - networkSegments[i + 1].getNodeIdentifiers(), networkSegments[i + 1].getNodeVersions()) - - cxGroup += cx[(1 if i else 0):] - cd1Group += cd1[(1 if i else 0):] - cd2Group += cd2[(1 if i else 0):] - cd3Group += cd3[(1 if i else 0):] - cd12Group += cd12[(1 if i else 0):] - cd13Group += cd13[(1 if i else 0):] - - if i == 0: - xbranchpt = cx[-1] - d2branchpt = cd2[-1] - arcLengthToBranchPt = 0.0 - for n in range(len(cx) - 1): - arcLengthToBranchPt += interp.getCubicHermiteArcLength(cx[n], cd1[n], cx[n + 1], cd1[n + 1]) - - elif termName == "ileum": - cxGroup, cd1Group, cd2Group, cd3Group, cd12Group, cd13Group = get_nodeset_path_ordered_field_parameters( - tmpNodes, tmpCoordinates, - [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], - networkSegments[0].getNodeIdentifiers(), networkSegments[0].getNodeVersions()) - - 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) - cxGroups.append(cxGroup) - cd1Groups.append(cd1Group) - cd2Groups.append(cd2Group) - cd3Groups.append(cd3Group) - cd12Groups.append(cd12Group) - cd13Groups.append(cd13Group) - - del tmpNodeset - del tmpGroup - - del tmpCoordinates - del tmpNodes - del tmpFieldmodule - del tmpRegion - - self.arcLengthOfGroupsAlong = arcLengthOfGroupsAlong - self.cxGroups = cxGroups - self.cd1Groups = cd1Groups - self.cd2Groups = cd2Groups - self.cd3Groups = cd3Groups - self.cd12Groups = cd12Groups - self.cd13Groups = cd13Groups - self.xBranchPt = xbranchpt - self.d2BranchPt = d2branchpt - self.arcLengthToBranchPt = arcLengthToBranchPt - -class CustomCentralPath: - """ - Generates sampled central path for part of central path. - """ - def __init__(self, cx, cd1, cd2, cd3, cd12, cd13): - self.cxPath = cx - self.cd1Path = cd1 - self.cd2Path = cd2 - self.cd3Path = cd3 - self.cd12Path = cd12 - self.cd13Path = cd13 \ No newline at end of file diff --git a/src/scaffoldmaker/scaffolds.py b/src/scaffoldmaker/scaffolds.py index a03d751a..52971183 100644 --- a/src/scaffoldmaker/scaffolds.py +++ b/src/scaffoldmaker/scaffolds.py @@ -19,7 +19,6 @@ from scaffoldmaker.meshtypes.meshtype_3d_boxnetwork1 import MeshType_3d_boxnetwork1 from scaffoldmaker.meshtypes.meshtype_3d_brainstem import MeshType_3d_brainstem1 from scaffoldmaker.meshtypes.meshtype_3d_cecum1 import MeshType_3d_cecum1 -from scaffoldmaker.meshtypes.meshtype_3d_cecum2 import MeshType_3d_cecum2 from scaffoldmaker.meshtypes.meshtype_3d_colon1 import MeshType_3d_colon1 from scaffoldmaker.meshtypes.meshtype_3d_colonsegment1 import MeshType_3d_colonsegment1 from scaffoldmaker.meshtypes.meshtype_3d_esophagus1 import MeshType_3d_esophagus1 @@ -75,7 +74,6 @@ def __init__(self): MeshType_3d_boxnetwork1, MeshType_3d_brainstem1, MeshType_3d_cecum1, - MeshType_3d_cecum2, MeshType_3d_colon1, MeshType_3d_colonsegment1, MeshType_3d_esophagus1, From d8d839a085b754ec99bcae4b4284c499baff0d3c Mon Sep 17 00:00:00 2001 From: mlin865 Date: Thu, 13 Jul 2023 13:23:16 +1200 Subject: [PATCH 06/24] Add human3 for GI tract --- .../meshtypes/meshtype_3d_cecum1.py | 55 ++++++++++++++++--- 1 file changed, 47 insertions(+), 8 deletions(-) diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_cecum1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_cecum1.py index 81e7e28f..45cff999 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_cecum1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_cecum1.py @@ -105,6 +105,34 @@ class MeshType_3d_cecum1(Scaffold_base): 'ontId': get_smallintestine_term('ileum')[1] }] }), + 'Human 3': ScaffoldPackage(MeshType_1d_network_layout1, { + 'scaffoldSettings': { + "Structure": "1-2-3.2, 4-3-5" + }, + 'meshEdits': exnode_string_from_nodeset_field_parameters( + [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ + (1, [[-60.63,-80.53,895.25], [-6.17,-10.10,-5.87], [2.66,0.73,-4.05], [2.38,0.99,-1.14], [3.31,-2.97,1.64], [2.38,0.99,-1.14]]), + (2, [[-68.64,-93.29,888.06], [-9.85,-15.42,-8.51], [3.88,1.20,-6.66], [2.38,0.99,-1.14], [2.82,-2.46,1.20], [2.38,0.99,-1.14]]), + (3, [[-80.39,-111.37,878.29], [[-7.24,-1.01,11.64],[-13.65,-20.74,-11.03]], [[19.37,-3.78,11.72],[5.59,1.31,-9.38]], [[2.38,0.99,-1.14],[2.38,0.99,-1.14]], [[2.31,22.26,3.37],[1.51,-1.37,0.71]], [[2.38,0.99,-1.14],[2.38,0.99,-1.14]]]), + (4, [[-72.87,-109.11,867.41], [-7.88,-3.47,10.51], [16.11,-4.49,10.60], [3.73,0.68,4.20], [0.76,18.44,6.66], [3.74,0.69,4.20]]), + (5, [[-87.21,-111.06,890.54], [-4.75,0.41,12.39], [20.72,-2.80,8.04], [2.46,-0.39,-2.95], [2.85,22.11,0.36], [1.83,0.46,-4.31]])]), + + 'userAnnotationGroups': [ + { + '_AnnotationGroup': True, + 'dimension': 1, + 'identifierRanges': '3-4', + 'name': get_cecum_term('caecum')[0], + 'ontId': get_cecum_term('caecum')[1] + }, + { + '_AnnotationGroup': True, + 'dimension': 1, + 'identifierRanges': '1-2', + 'name': get_smallintestine_term('ileum')[0], + 'ontId': get_smallintestine_term('ileum')[1] + }] + }), 'Pig 1': ScaffoldPackage(MeshType_1d_network_layout1, { 'scaffoldSettings': { "Structure": "1-2-3.2, 4-5-6-3-7" @@ -188,6 +216,7 @@ def getParameterSetNames(): 'Default', 'Human 1', 'Human 2', + 'Human 3', 'Pig 1'] @classmethod @@ -195,6 +224,9 @@ def getDefaultOptions(cls, parameterSetName='Default'): if 'Human 2' in parameterSetName: centralPathOption = cls.parameterSetStructureStrings['Human 2'] ostiumOption = cls.ostiumDefaultScaffoldPackages['Human 1'] + if 'Human 3' in parameterSetName: + centralPathOption = cls.parameterSetStructureStrings['Human 3'] + ostiumOption = cls.ostiumDefaultScaffoldPackages['Human 1'] elif 'Pig 1' in parameterSetName: centralPathOption = cls.parameterSetStructureStrings['Pig 1'] ostiumOption = cls.ostiumDefaultScaffoldPackages['Pig 1'] @@ -212,13 +244,13 @@ def getDefaultOptions(cls, parameterSetName='Default'): 'Corner inner radius factor': 0.5, 'Haustrum inner radius factor': 0.4, 'Segment length end derivative factor': 0.5, - 'Segment length mid derivative factor': 1.0, # 3.0, + 'Segment length mid derivative factor': 1.0, 'Number of tenia coli': 3, - 'Start tenia coli width': 2.0, #10.0, - 'Start tenia coli width derivative': 2.0, #0.0, - 'End tenia coli width': 4.0, #10.0, - 'End tenia coli width derivative': 2.0, #0.0, - 'Tenia coli thickness': 0.5, #1.6, + 'Start tenia coli width': 2.0, + 'Start tenia coli width derivative': 2.0, + 'End tenia coli width': 4.0, + 'End tenia coli width derivative': 2.0, + 'Tenia coli thickness': 0.5, 'Wall thickness': 1.6, 'Mucosa relative thickness': 0.55, 'Submucosa relative thickness': 0.15, @@ -233,7 +265,15 @@ def getDefaultOptions(cls, parameterSetName='Default'): 'Refine number of elements through wall': 1 } - if 'Pig 1' in parameterSetName: + if 'Human 3' in parameterSetName: + options['Segment length mid derivative factor'] = 3.0 + options['Start tenia coli width'] = 10.0 + options['Start tenia coli width derivative'] = 0.0 + options['End tenia coli width'] = 10.0 + options['End tenia coli width derivative'] = 0.0 + options[ 'Tenia coli thickness'] = 1.6 + + elif 'Pig 1' in parameterSetName: options['Number of segments'] = 5 options['Haustrum inner radius factor'] = 0.25 options['Segment length end derivative factor'] = 1.0 @@ -2321,4 +2361,3 @@ def __init__(self, cx, cd1, cd2, cd3, cd12, cd13): self.cd3Path = cd3 self.cd12Path = cd12 self.cd13Path = cd13 - \ No newline at end of file From 9e15b67855b7dccbede36d524317093f224da1d5 Mon Sep 17 00:00:00 2001 From: mlin865 Date: Thu, 13 Jul 2023 13:46:30 +1200 Subject: [PATCH 07/24] Update unit test for cecum --- tests/test_cecum.py | 67 +++++++++++++++++++++++++++------------------ 1 file changed, 41 insertions(+), 26 deletions(-) diff --git a/tests/test_cecum.py b/tests/test_cecum.py index 527ea9b2..ccc06d8d 100644 --- a/tests/test_cecum.py +++ b/tests/test_cecum.py @@ -6,6 +6,9 @@ from cmlibs.zinc.element import Element from cmlibs.zinc.field import Field from cmlibs.zinc.result import RESULT_OK +from scaffoldmaker.annotation.annotationgroup import getAnnotationGroupForTerm +from scaffoldmaker.annotation.cecum_terms import get_cecum_term +from scaffoldmaker.annotation.smallintestine_terms import get_smallintestine_term from scaffoldmaker.meshtypes.meshtype_3d_cecum1 import MeshType_3d_cecum1 from scaffoldmaker.utils.zinc_utils import createFaceMeshGroupExteriorOnFace @@ -19,58 +22,54 @@ def test_cecum1(self): Test creation of cecum scaffold. """ parameterSetNames = MeshType_3d_cecum1.getParameterSetNames() - self.assertEqual(parameterSetNames, ["Default", "Pig 1"]) - options = MeshType_3d_cecum1.getDefaultOptions("Pig 1") - self.assertEqual(30, len(options)) - self.assertEqual(5, options.get("Number of segments")) + self.assertEqual(parameterSetNames, ["Default", "Human 1", "Human 2", "Human 3", "Pig 1"]) + options = MeshType_3d_cecum1.getDefaultOptions("Human 3") + + centralPath = options.get("Central path") + centralPathSettings = centralPath.getScaffoldSettings() + self.assertEqual("1-2-3.2, 4-3-5", centralPathSettings["Structure"]) + + self.assertEqual(28, len(options)) + self.assertEqual(1, options.get("Number of segments")) self.assertEqual(2, options.get("Number of elements around tenia coli")) self.assertEqual(8, options.get("Number of elements along segment")) self.assertEqual(1, options.get("Number of elements through wall")) - self.assertEqual(35.0, options.get("Start inner radius")) - self.assertEqual(3.0, options.get("Start inner radius derivative")) - self.assertEqual(38.0, options.get("End inner radius")) - self.assertEqual(3.0, options.get("End inner radius derivative")) self.assertEqual(0.5, options.get("Corner inner radius factor")) - self.assertEqual(0.25, options.get("Haustrum inner radius factor")) - self.assertEqual(4.0, options.get("Segment length mid derivative factor")) + self.assertEqual(0.4, options.get("Haustrum inner radius factor")) + self.assertEqual(3.0, options.get("Segment length mid derivative factor")) self.assertEqual(3, options.get("Number of tenia coli")) - self.assertEqual(5.0, options.get("Start tenia coli width")) + self.assertEqual(10.0, options.get("Start tenia coli width")) self.assertEqual(0.0, options.get("End tenia coli width derivative")) - self.assertEqual(2.0, options.get("Wall thickness")) + self.assertEqual(1.6, options.get("Wall thickness")) ostiumOptions = options['Ileocecal junction'] ostiumSettings = ostiumOptions.getScaffoldSettings() - self.assertEqual(1, ostiumSettings.get("Number of vessels")) self.assertEqual(8, ostiumSettings.get("Number of elements around ostium")) self.assertEqual(1, ostiumSettings.get("Number of elements through wall")) - self.assertEqual(20.0, ostiumSettings.get("Ostium diameter")) - self.assertEqual(10.0, ostiumSettings.get("Vessel inner diameter")) - self.assertEqual(60, options.get("Ileocecal junction angular position degrees")) - self.assertEqual(0.5, options.get("Ileocecal junction position along factor")) context = Context("Test") region = context.getDefaultRegion() self.assertTrue(region.isValid()) annotationGroups = MeshType_3d_cecum1.generateBaseMesh(region, options)[0] - self.assertEqual(2, len(annotationGroups)) + self.assertEqual(5, len(annotationGroups)) fieldmodule = region.getFieldmodule() self.assertEqual(RESULT_OK, fieldmodule.defineAllFaces()) mesh3d = fieldmodule.findMeshByDimension(3) - self.assertEqual(1492, mesh3d.getSize()) + self.assertEqual(308, mesh3d.getSize()) mesh2d = fieldmodule.findMeshByDimension(2) - self.assertEqual(5617, mesh2d.getSize()) + self.assertEqual(1164, mesh2d.getSize()) mesh1d = fieldmodule.findMeshByDimension(1) - self.assertEqual(6767, mesh1d.getSize()) + self.assertEqual(1412, mesh1d.getSize()) nodes = fieldmodule.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES) - self.assertEqual(2642, nodes.getSize()) + self.assertEqual(558, nodes.getSize()) datapoints = fieldmodule.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_DATAPOINTS) self.assertEqual(0, datapoints.getSize()) coordinates = fieldmodule.findFieldByName("coordinates").castFiniteElement() self.assertTrue(coordinates.isValid()) minimums, maximums = evaluateFieldNodesetRange(coordinates, nodes) - assertAlmostEqualList(self, minimums, [-49.01658984455258, -46.89686037622053, -2.343256155753525], 1.0E-6) - assertAlmostEqualList(self, maximums, [42.18085849205387, 54.902119877312636, 180.0], 1.0E-6) + assertAlmostEqualList(self, minimums, [-110.98815807992678, -144.1649444946355, 854.4533092097239], 1.0E-6) + assertAlmostEqualList(self, maximums, [-55.3885994876074, -77.17764626881537, 900.1398770921413], 1.0E-6) with ChangeManager(fieldmodule): one = fieldmodule.createFieldConstant(1.0) @@ -82,10 +81,26 @@ def test_cecum1(self): fieldcache = fieldmodule.createFieldcache() result, surfaceArea = surfaceAreaField.evaluateReal(fieldcache, 1) self.assertEqual(result, RESULT_OK) - self.assertAlmostEqual(surfaceArea, 65960.86557108756, delta=1.0E-6) + self.assertAlmostEqual(surfaceArea, 8014.802826468518, delta=1.0E-6) result, volume = volumeField.evaluateReal(fieldcache, 1) self.assertEqual(result, RESULT_OK) - self.assertAlmostEqual(volume, 127907.08806524028, delta=1.0E-6) + self.assertAlmostEqual(volume, 12562.715396659782, delta=1.0E-6) + + # check some annotationGroups: + expectedSizes3d = { + "caecum": 308, + "ileum": 16, + "ileocecal junction": 8 + } + + for name in expectedSizes3d: + if name == "caecum": + term = get_cecum_term(name) + else: + term = get_smallintestine_term(name) + group = getAnnotationGroupForTerm(annotationGroups, term) + size = group.getMeshGroup(mesh3d).getSize() + self.assertEqual(expectedSizes3d[name], size, name) if __name__ == "__main__": From d6b514edc5add9868fa8a5133bde972a3eed6082 Mon Sep 17 00:00:00 2001 From: mlin865 Date: Mon, 17 Jul 2023 11:09:32 +1200 Subject: [PATCH 08/24] Clean up and remove redundant code --- src/scaffoldmaker/annotation/cecum_terms.py | 7 +- .../annotation/smallintestine_terms.py | 5 + .../meshtypes/meshtype_3d_cecum1.py | 552 ++++-------------- .../meshtypes/meshtype_3d_colonsegment1.py | 8 +- .../meshtypes/meshtype_3d_stomach1.py | 60 +- src/scaffoldmaker/utils/interpolation.py | 39 ++ 6 files changed, 182 insertions(+), 489 deletions(-) diff --git a/src/scaffoldmaker/annotation/cecum_terms.py b/src/scaffoldmaker/annotation/cecum_terms.py index 15df6025..8a9533d5 100644 --- a/src/scaffoldmaker/annotation/cecum_terms.py +++ b/src/scaffoldmaker/annotation/cecum_terms.py @@ -4,7 +4,12 @@ # convention: preferred name, preferred id, followed by any other ids and alternative names cecum_terms = [ - ("caecum", "UBERON:0001153", "FMA:14541", "ILX:0732270") + ("caecum", "UBERON:0001153", "FMA:14541", "ILX:0732270"), + ("cecum mucosa", "UBERON:0000314", "FMA:14998", "ILX:0723957"), + ("circular muscle layer of cecum", "ILX:0774843"), + ("longitudinal muscle layer of cecum", "ILX:0776047"), + ("serosa of cecum", "ILX:0773223"), + ("submucosa of cecum", "UBERON:0004927", "FMA:14999", "ILX:0725500") ] diff --git a/src/scaffoldmaker/annotation/smallintestine_terms.py b/src/scaffoldmaker/annotation/smallintestine_terms.py index c2ac7e03..ea591783 100644 --- a/src/scaffoldmaker/annotation/smallintestine_terms.py +++ b/src/scaffoldmaker/annotation/smallintestine_terms.py @@ -5,17 +5,22 @@ # convention: preferred name, preferred id, followed by any other ids and alternative names smallintestine_terms = [ ("circular-longitudinal muscle interface of first segment of the duodenum along the gastric-omentum attachment", "ILX:0793090"), + ("circular muscle layer of ileum", "ILX:0776561"), ("circular muscle layer of small intestine", "ILX:0772669"), ("duodenum", "UBERON:0002114", "FMA:7206", "ILX:0726125"), ("ileocecal junction", "UBERON:0001073", "FMA:11338", "ILX:0730012"), ("ileum", "UBERON:0002116", "FMA:7208", "ILX:0728151"), ("jejunum", "UBERON:0002115", "FMA:7207", "ILX:0724224"), + ("longitudinal muscle layer of ileum", "ILX:0770304"), ("longitudinal muscle layer of small intestine", "ILX:0772125"), ("luminal surface of duodenum", "ILX:0793121"), + ("mucosa of ileum", "ILX:0770578"), ("mucosa of small intestine", "UBERON:0001204", "FMA:14933", "ILX:0770578"), ("serosa of duodenum", "UBERON:0003336", "FMA:14948", "ILX:0732373"), + ("serosa of ileum", "ILX:0774472"), ("serosa of small intestine", "UBERON:0001206", "FMA:14938", "ILX:0727465"), ("small intestine", "UBERON:0002108", "FMA:7200", "ILX:0726770"), + ("submucosa of ileum", "UBERON:0004946", "FMA:14957", "ILX:0734297"), ("submucosa of small intestine", "UBERON:0001205", "FMA:14934", "ILX:0735609") ] diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_cecum1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_cecum1.py index 45cff999..f0763a48 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_cecum1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_cecum1.py @@ -7,9 +7,8 @@ import copy import math -from cmlibs.maths.vectorops import add, sub -from cmlibs.utils.zinc.field import findOrCreateFieldCoordinates # KM -from cmlibs.zinc.element import Element, Elementbasis +from cmlibs.utils.zinc.field import findOrCreateFieldCoordinates +from cmlibs.zinc.element import Element from cmlibs.zinc.field import Field from cmlibs.zinc.node import Node from scaffoldmaker.annotation.annotationgroup import AnnotationGroup, mergeAnnotationGroups @@ -25,26 +24,20 @@ from scaffoldmaker.utils import matrix from scaffoldmaker.utils import tubemesh from scaffoldmaker.utils import vector -from scaffoldmaker.utils.geometry import createEllipsePoints # KM from scaffoldmaker.utils.annulusmesh import createAnnulusMesh3d from scaffoldmaker.utils.eftfactory_bicubichermitelinear import eftfactory_bicubichermitelinear from scaffoldmaker.utils.eftfactory_tricubichermite import eftfactory_tricubichermite -from scaffoldmaker.utils.eft_utils import setEftScaleFactorIds, remapEftNodeValueLabel, remapEftNodeValueLabelsVersion -from scaffoldmaker.utils.networkmesh import NetworkMesh, NetworkNode -from scaffoldmaker.utils.tracksurface import TrackSurface, TrackSurfacePosition +from scaffoldmaker.utils.eft_utils import setEftScaleFactorIds, remapEftNodeValueLabel +from scaffoldmaker.utils.tracksurface import TrackSurface from scaffoldmaker.utils.zinc_utils import exnode_string_from_nodeset_field_parameters, \ - mesh_destroy_elements_and_nodes_by_identifiers, get_nodeset_path_field_parameters, \ - get_nodeset_path_ordered_field_parameters + mesh_destroy_elements_and_nodes_by_identifiers, get_nodeset_path_ordered_field_parameters class MeshType_3d_cecum1(Scaffold_base): ''' - Generates a 3-D cecum mesh with variable numbers - of elements around, along the central line, and through wall. - The cecum is created by a function that generates a cecum - segment and uses tubemesh to map the segment along a central - line profile. The proximal end of the cecum is closed up with - an apex plate. An ostium is included to generate the + Generates a 3-D cecum mesh with variable numbers of elements around, along the central line, and through wall. The + cecum is created by a function that generates a cecum segment and uses tubemesh to map the segment along a network + layout. The proximal end of the cecum is closed up with an apex plate. An ostium is included to generate the ileo-cecal junction. ''' @@ -78,34 +71,6 @@ class MeshType_3d_cecum1(Scaffold_base): }] }), 'Human 2': ScaffoldPackage(MeshType_1d_network_layout1, { - 'scaffoldSettings': { - "Structure": "1-2-3.2, 4-3-5" - }, - 'meshEdits': exnode_string_from_nodeset_field_parameters( - [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ - (1, [[9.21,-19.56,6.43], [-2.02,7.27,-6.55], [-1.46,-0.27,0.15], [0.00,0.00,0.00], [-0.06,0.99,1.12], [0.00,0.00,0.00]]), - (2, [[7.72,-10.79,1.37], [-0.90,10.04,-3.37], [-4.48,-0.36,0.11], [0.00,0.00,0.00], [-0.01,1.43,4.27], [0.00,0.00,0.00]]), - (3, [[7.50,0.00,0.00], [[7.50,0.00,0.00],[0.45,11.25,0.61]], [[0.00,10.00,0.00],[-4.50,0.18,0.01]], [[1.02,6.79,0.00],[0.00,0.00,0.00]], [[0.00,0.00,10.00],[0.00,-0.24,4.49]], [[0.00,0.00,5.77],[0.00,0.00,0.00]]]), - (4, [[0.00,0.00,0.00], [7.50,0.00,0.00], [0.00,10.00,0.00], [0.00,0.00,0.00], [0.00,0.00,10.00], [0.00,0.00,0.00]]), - (5, [[15.00,0.00,0.00], [7.50,0.00,0.00], [0.00,10.00,0.00], [0.00,0.00,0.00], [0.00,0.00,10.00], [0.00,0.00,0.00]])]), - - 'userAnnotationGroups': [ - { - '_AnnotationGroup': True, - 'dimension': 1, - 'identifierRanges': '3-4', - 'name': get_cecum_term('caecum')[0], - 'ontId': get_cecum_term('caecum')[1] - }, - { - '_AnnotationGroup': True, - 'dimension': 1, - 'identifierRanges': '1-2', - 'name': get_smallintestine_term('ileum')[0], - 'ontId': get_smallintestine_term('ileum')[1] - }] - }), - 'Human 3': ScaffoldPackage(MeshType_1d_network_layout1, { 'scaffoldSettings': { "Structure": "1-2-3.2, 4-3-5" }, @@ -190,7 +155,7 @@ class MeshType_3d_cecum1(Scaffold_base): 'scaffoldSettings': { 'Number of elements around ostium': 8, 'Number of elements along': 2, - 'Number of elements through wall': 1, # not implemented for > 1 + 'Number of elements through wall': 1, 'Unit scale': 1.0, 'Outlet': False, 'Ostium wall thickness': 2.0, @@ -216,7 +181,6 @@ def getParameterSetNames(): 'Default', 'Human 1', 'Human 2', - 'Human 3', 'Pig 1'] @classmethod @@ -224,9 +188,6 @@ def getDefaultOptions(cls, parameterSetName='Default'): if 'Human 2' in parameterSetName: centralPathOption = cls.parameterSetStructureStrings['Human 2'] ostiumOption = cls.ostiumDefaultScaffoldPackages['Human 1'] - if 'Human 3' in parameterSetName: - centralPathOption = cls.parameterSetStructureStrings['Human 3'] - ostiumOption = cls.ostiumDefaultScaffoldPackages['Human 1'] elif 'Pig 1' in parameterSetName: centralPathOption = cls.parameterSetStructureStrings['Pig 1'] ostiumOption = cls.ostiumDefaultScaffoldPackages['Pig 1'] @@ -240,7 +201,7 @@ def getDefaultOptions(cls, parameterSetName='Default'): 'Number of elements around tenia coli': 2, 'Number of elements around haustrum': 8, 'Number of elements along segment': 8, - 'Number of elements through wall': 1, # 4 later! + 'Number of elements through wall': 1, 'Corner inner radius factor': 0.5, 'Haustrum inner radius factor': 0.4, 'Segment length end derivative factor': 0.5, @@ -265,7 +226,7 @@ def getDefaultOptions(cls, parameterSetName='Default'): 'Refine number of elements through wall': 1 } - if 'Human 3' in parameterSetName: + if 'Human 2' in parameterSetName: options['Segment length mid derivative factor'] = 3.0 options['Start tenia coli width'] = 10.0 options['Start tenia coli width derivative'] = 0.0 @@ -372,7 +333,6 @@ def checkOptions(cls, options): for key in [ 'Number of elements around tenia coli', 'Number of elements around haustrum', - 'Number of elements along segment', 'Corner inner radius factor', 'Haustrum inner radius factor', 'Segment length end derivative factor', @@ -386,6 +346,10 @@ def checkOptions(cls, options): 'Wall thickness']: if options[key] < 0.0: options[key] = 0.0 + if options['Number of elements along segment'] < 8: + options['Number of elements along segment'] = 8 + if options['Number of elements along segment'] % 4 > 0: + options['Number of elements along segment'] = options['Number of elements along segment'] // 4 * 4 if options['Number of elements through wall'] != (1 or 4): options['Number of elements through wall'] = 4 cls.updateSubScaffoldOptions(options) @@ -551,9 +515,9 @@ def getApexSegmentForCecum(xInner, d1Inner, d2Inner, elementsCountAroundHalfHaus def getD1ForFullProfileFromHalfHaustrum(d1HaustrumHalfSet, tcCount): """ Get full profile from half haustrum - :param d1HaustrumHalfSet: - :param tcCount: - :return: + :param d1HaustrumHalfSet: d1 for first half of haustrum + :param tcCount: Number of tenia coli + :return: d1 for nodes around the entire haustrum """ d1HaustrumHalfSet2 = [] d1Haustra = [] @@ -670,108 +634,6 @@ def sampleCecumAlongLength(xToSample, d1ToSample, d2ToSample, d1FirstDirectionVe return xSampledAlongLength, d1SampledAlongLength, d2SampledAlongLength -def getElementIdxOfOstiumBoundary(centrePosition, trackSurfaceOstium, ostiumDiameter): - """ - Finds the element indices of the boundaries of elements on tracksurface that surround - the ostium. Indices based on numbering for elements around and along tracksurface. - Boundary lies on xi=0 of elements on left and bottom boundaries and xi = 1 for right and - top boundaries. - :param centrePosition: surface description for centre of ostium. - :param trackSurfaceOstium: surface description for tracksurface. - :param ostiumDiameter: Diameter of ostium. - :return: element indices on the left, right, bottom and top boundaries around tracksurface. - """ - - elementsAroundTrackSurface = trackSurfaceOstium.elementsCount1 - elementsAlongTrackSurface = trackSurfaceOstium.elementsCount2 - ei1 = centrePosition.e1 - ei2 = centrePosition.e2 - xi1 = centrePosition.xi1 - xi2 = centrePosition.xi2 - xCentre, d1Centre, d2Centre = trackSurfaceOstium.evaluateCoordinates(centrePosition, derivatives=True) - - # Left boundary - leftPositionOfCentreElement = TrackSurfacePosition(ei1, ei2, 0, xi2) - xLeft, d1Left, _ = trackSurfaceOstium.evaluateCoordinates(leftPositionOfCentreElement, derivatives=True) - distxLeftToxCentre = interp.computeCubicHermiteArcLength(xLeft, d1Left, xCentre, d1Centre, False) - remainingLength = ostiumDiameter * 0.5 - distxLeftToxCentre - xCurrent = xLeft - d1Current = d1Left - - for n1 in range(ei1, -1, -1): - if remainingLength > 0.0: - prevPosition = TrackSurfacePosition(n1-1, ei2, 0, xi2) - xPrev, d1Prev, _ = trackSurfaceOstium.evaluateCoordinates(prevPosition, derivatives=True) - distPrevToxCurrent = interp.computeCubicHermiteArcLength(xPrev, d1Prev, xCurrent, d1Current, False) - remainingLength -= distPrevToxCurrent - xCurrent = xPrev - d1Current = d1Prev - else: - ei1Left = n1 - break - - # Right boundary - rightPositionOfCentreElement = TrackSurfacePosition(ei1, ei2, 1.0, xi2) - xRight, d1Right, _ = trackSurfaceOstium.evaluateCoordinates(rightPositionOfCentreElement, derivatives=True) - distxCentreToxRight = interp.computeCubicHermiteArcLength(xCentre, d1Centre, xRight, d1Right, False) - remainingLength = ostiumDiameter * 0.5 - distxCentreToxRight - xCurrent = xRight - d1Current = d1Right - - for n1 in range(ei1, elementsAroundTrackSurface): - if remainingLength > 0.0: - nextPosition = TrackSurfacePosition(n1+1, ei2, 1.0, xi2) - xNext, d1Next, _ = trackSurfaceOstium.evaluateCoordinates(nextPosition, derivatives=True) - distxCurrentToxNext = interp.computeCubicHermiteArcLength(xCurrent, d1Current, xNext, d1Next, False) - remainingLength -= distxCurrentToxNext - xCurrent = xNext - d1Current = d1Next - else: - ei1Right = n1 - break - - # Bottom boundary - bottomPositionOfCentreElement = TrackSurfacePosition(ei1, ei2, xi1, 0) - xBottom, _, d2Bottom = trackSurfaceOstium.evaluateCoordinates(bottomPositionOfCentreElement, derivatives=True) - distxBottomToxCentre = interp.computeCubicHermiteArcLength(xBottom, d2Bottom, xCentre, d2Centre, False) - remainingLength = ostiumDiameter * 0.5 - distxBottomToxCentre - xCurrent = xBottom - d2Current = d2Bottom - - for n2 in range(ei2, -1, -1): - if remainingLength > 0.0: - prevPosition = TrackSurfacePosition(ei1, n2 - 1, xi1, 0) - xPrev, _, d2Prev = trackSurfaceOstium.evaluateCoordinates(prevPosition, derivatives=True) - distPrevToxCurrent = interp.computeCubicHermiteArcLength(xPrev, d2Prev, xCurrent, d2Current, False) - remainingLength -= distPrevToxCurrent - xCurrent = xPrev - d2Current = d2Prev - else: - ei2Bottom = n2 - break - - # Top boundary - topPositionOfCentreElement = TrackSurfacePosition(ei1, ei2, xi1, 1.0) - xTop, _, d2Top = trackSurfaceOstium.evaluateCoordinates(topPositionOfCentreElement, derivatives=True) - distxCentreToxTop = interp.computeCubicHermiteArcLength(xCentre, d2Centre, xTop, d2Top, False) - remainingLength = ostiumDiameter * 0.5 - distxCentreToxTop - xCurrent = xTop - d2Current = d2Top - - for n2 in range(ei2, elementsAlongTrackSurface): - if remainingLength > 0.0: - nextPosition = TrackSurfacePosition(ei1, n2+1, xi1, 1.0) - xNext, _, d2Next = trackSurfaceOstium.evaluateCoordinates(nextPosition, derivatives=True) - distxCurrentToxNext = interp.computeCubicHermiteArcLength(xCurrent, d2Current, xNext, d2Next, False) - remainingLength -= distxCurrentToxNext - xCurrent = xNext - d2Current = d2Next - else: - ei2Top = n2 - break - - return ei1Left, ei1Right, ei2Bottom, ei2Top - def findDerivativeBetweenPoints(v1, v2): """ Find vector difference between two points and rescale vector difference using cubic hermite arclength @@ -786,49 +648,15 @@ def findDerivativeBetweenPoints(v1, v2): return d - -def findCurvatureAroundLoop(nx, nd, radialVectors): - """ - Calculate curvature for points lying along a loop. - :param nx: points on loop - :param nd: derivative of points on loop - :param radialVectors: radial direction, assumed normal to curve tangent at point - :return: curvatures along points on loop - """ - curvature = [] - for n in range(len(nx)): - prevIdx = n - 1 if n > 0 else -1 - nextIdx = n + 1 if n < len(nx) - 1 else 0 - kappam = interp.getCubicHermiteCurvature(nx[prevIdx], nd[prevIdx], nx[n], nd[n], radialVectors[n], 1.0) - kappap = interp.getCubicHermiteCurvature(nx[n], nd[n], nx[nextIdx], nd[nextIdx], radialVectors[n], 0.0) - curvature.append(0.5 * (kappam + kappap)) - - return curvature - -def findCurvatureAlongLine(nx, nd, radialVectors): - """ - Calculate curvature for points lying along a line. - :param nx: points on line - :param nd: derivative of points on line - :param radialVectors: radial direction, assumed normal to curve tangent at point - :return: curvatures along points on line - """ - curvature = [] - for n in range(len(nx)): - if n == 0: - curvature.append(interp.getCubicHermiteCurvature(nx[n], nd[n], nx[n + 1], nd[n + 1], radialVectors[n], 0.0)) - elif n == len(nx) - 1: - curvature.append(interp.getCubicHermiteCurvature(nx[n - 1], nd[n - 1], nx[n], nd[n], radialVectors[n], 1.0)) - else: - curvature.append(0.5 * ( - interp.getCubicHermiteCurvature(nx[n], nd[n], nx[n + 1], nd[n + 1], radialVectors[n], 0.0) + - interp.getCubicHermiteCurvature(nx[n - 1], nd[n - 1], nx[n], nd[n], radialVectors[n], 1.0))) - - return curvature - -def createCecumMesh3d(region, options, centralPath, nextNodeIdentifier, nextElementIdentifier): +def createCecumMesh3d(region, options, centralPath, nodeIdentifier, elementIdentifier): """ - + Generates a cecum scaffold in the region using a network layout and parameter options. + :param region: Region to create elements in. + :param options: Parameter options for scaffold. + :param centralPath: Central path through the axis of the cecum scaffold. + :param nodeIdentifier: First node identifier. + :param elementIdentifier: First element identifier. + :return allAnnotationGroups, nextNodeIdentifier, nextElementIdentifier. """ segmentCount = options['Number of segments'] startPhase = 0.0 @@ -860,14 +688,15 @@ def createCecumMesh3d(region, options, centralPath, nextNodeIdentifier, nextElem ostiumSettings = ostiumOptions.getScaffoldSettings() zero = [0.0, 0.0, 0.0] - firstNodeIdentifier = nextNodeIdentifier - firstElementIdentifier = nextElementIdentifier - startNode = nextNodeIdentifier - startElement = nextElementIdentifier + firstNodeIdentifier = nodeIdentifier + firstElementIdentifier = elementIdentifier + startNode = nodeIdentifier + startElement = elementIdentifier fm = region.getFieldmodule() coordinates = findOrCreateFieldCoordinates(fm) cache = fm.createFieldcache() + mesh = fm.findMeshByDimension(3) nodes = fm.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES) nodetemplate = nodes.createNodetemplate() @@ -894,9 +723,7 @@ def createCecumMesh3d(region, options, centralPath, nextNodeIdentifier, nextElem circularMuscleGroup = AnnotationGroup(region, get_cecum_term("circular muscle layer of cecum")) submucosaGroup = AnnotationGroup(region, get_cecum_term("submucosa of cecum")) mucosaGroup = AnnotationGroup(region, get_cecum_term("cecum mucosa")) - annotationGroupsThroughWall = [[mucosaGroup], - [submucosaGroup], - [circularMuscleGroup], + annotationGroupsThroughWall = [[mucosaGroup], [submucosaGroup], [circularMuscleGroup], [longitudinalMuscleGroup]] # Sample central path along cecum @@ -912,13 +739,10 @@ def createCecumMesh3d(region, options, centralPath, nextNodeIdentifier, nextElem cd2Ileum = centralPath.cd2Groups[1] cd3Ileum = centralPath.cd3Groups[1] cd12Ileum = centralPath.cd12Groups[1] - cd13Ileum = centralPath.cd13Groups[1] - # xBranchPt = centralPath.xBranchPt d2BranchPt = centralPath.d2BranchPt + d3BranchPt = centralPath.d3BranchPt - # smoothd1 = interp.smoothCubicHermiteDerivativesLine(cx, cd1, fixAllDirections=True, - # magnitudeScalingMode=interp.DerivativeScalingMode.HARMONIC_MEAN) sxCecum, sd1Cecum, se, sxi, ssf = interp.sampleCubicHermiteCurves(cx, cd1, elementsCountAlong) sd2Cecum, sd12Cecum = interp.interpolateSampleCubicHermite(cd2, cd12, se, sxi, ssf) @@ -931,7 +755,6 @@ def createCecumMesh3d(region, options, centralPath, nextNodeIdentifier, nextElem tcWidthAlongCecum = [] closedProximalEnd = True - innerRadiusListCP = [vector.magnitude(c) for c in cd2] dInnerRadiusListCP = [] for n in range(len(innerRadiusListCP) - 1): @@ -1084,51 +907,51 @@ def createCecumMesh3d(region, options, centralPath, nextNodeIdentifier, nextElem firstNodeIdentifier, firstElementIdentifier, useCubicHermiteThroughWall, useCrossDerivatives, closedProximalEnd) - nodeIdentifierCecum = nextNodeIdentifier - for n2 in range(len(cx)): - node = nodes.createNode(nextNodeIdentifier, nodetemplate) - cache.setNode(node) - coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, cx[n2]) - coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, cd1[n2]) - coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, cd2[n2]) - coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, [0.0, 0.0, 0.0]) - nextNodeIdentifier += 1 - - ################# - # Create elements - ################# - - mesh = fm.findMeshByDimension(1) - cubicHermiteBasis = fm.createElementbasis(1, Elementbasis.FUNCTION_TYPE_CUBIC_HERMITE) - eft = mesh.createElementfieldtemplate(cubicHermiteBasis) - elementtemplate = mesh.createElementtemplate() - elementtemplate.setElementShapeType(Element.SHAPE_TYPE_LINE) - result = elementtemplate.defineField(coordinates, -1, eft) - - elementIdentifier = nextElementIdentifier - for e in range(len(cx) - 1): - element = mesh.createElement(elementIdentifier, elementtemplate) - element.setNodesByIdentifier(eft, [nodeIdentifierCecum + e, nodeIdentifierCecum + 1 + e]) - elementIdentifier = elementIdentifier + 1 - - cx = centralPath.cxGroups[1] - cd1 = centralPath.cd1Groups[1] - cd2 = centralPath.cd2Groups[1] - - nodeIdentifierIleum = nextNodeIdentifier - for n2 in range(len(cx)): - node = nodes.createNode(nextNodeIdentifier, nodetemplate) - cache.setNode(node) - coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, cx[n2]) - coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, cd1[n2]) - coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, cd2[n2]) - coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, [0.0, 0.0, 0.0]) - nextNodeIdentifier += 1 - - for e in range(2): - element = mesh.createElement(elementIdentifier, elementtemplate) - element.setNodesByIdentifier(eft, [nodeIdentifierIleum + e, nodeIdentifierIleum + 1 + e]) - elementIdentifier = elementIdentifier + 1 + # nodeIdentifierCecum = nextNodeIdentifier + # for n2 in range(len(cx)): + # node = nodes.createNode(nextNodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, cx[n2]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, cd1[n2]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, cd2[n2]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, [0.0, 0.0, 0.0]) + # nextNodeIdentifier += 1 + # + # ################# + # # Create elements + # ################# + # + # mesh = fm.findMeshByDimension(1) + # cubicHermiteBasis = fm.createElementbasis(1, Elementbasis.FUNCTION_TYPE_CUBIC_HERMITE) + # eft = mesh.createElementfieldtemplate(cubicHermiteBasis) + # elementtemplate = mesh.createElementtemplate() + # elementtemplate.setElementShapeType(Element.SHAPE_TYPE_LINE) + # result = elementtemplate.defineField(coordinates, -1, eft) + # + # elementIdentifier = nextElementIdentifier + # for e in range(len(cx) - 1): + # element = mesh.createElement(elementIdentifier, elementtemplate) + # element.setNodesByIdentifier(eft, [nodeIdentifierCecum + e, nodeIdentifierCecum + 1 + e]) + # elementIdentifier = elementIdentifier + 1 + # + # cx = centralPath.cxGroups[1] + # cd1 = centralPath.cd1Groups[1] + # cd2 = centralPath.cd2Groups[1] + # + # nodeIdentifierIleum = nextNodeIdentifier + # for n2 in range(len(cx)): + # node = nodes.createNode(nextNodeIdentifier, nodetemplate) + # cache.setNode(node) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, cx[n2]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, cd1[n2]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, cd2[n2]) + # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, [0.0, 0.0, 0.0]) + # nextNodeIdentifier += 1 + # + # for e in range(2): + # element = mesh.createElement(elementIdentifier, elementtemplate) + # element.setNodesByIdentifier(eft, [nodeIdentifierIleum + e, nodeIdentifierIleum + 1 + e]) + # elementIdentifier = elementIdentifier + 1 # Add ostium on track surface elementsAroundTrackSurface = elementsCountAroundHaustrum @@ -1139,6 +962,10 @@ def createCecumMesh3d(region, options, centralPath, nextNodeIdentifier, nextElem dV = [cxIleum[0][c] - cxIleum[-1][c] for c in range(3)] ostiumPositionAngleAround = math.acos(vector.dotproduct(dV, d2BranchPt)/ (vector.magnitude(dV) * vector.magnitude(d2BranchPt))) + if vector.dotproduct(dV,d3BranchPt) != 0: + sign = vector.dotproduct(dV, d3BranchPt)/abs(vector.dotproduct(dV, d3BranchPt)) + if sign < 0: + ostiumPositionAngleAround = math.pi * 2.0 - ostiumPositionAngleAround sectorIdx = ostiumPositionAngleAround // (2 * math.pi / tcCount) sectorStartAngle = sectorIdx * (2 * math.pi / tcCount) @@ -1158,15 +985,12 @@ def createCecumMesh3d(region, options, centralPath, nextNodeIdentifier, nextElem for n3 in range(elementsCountThroughWall): for n1 in range(elementsCountAroundHaustrum): elementIdx = \ - startIdxElementsAround + int(elementsCountAroundTC * (0.5 if tcThickness > 0.0 else 0)) + \ - n1 + (elementsCountAround * n3) + (elementsCountAround * elementsCountThroughWall + - elementsCountAroundTC * (tcCount if tcThickness > 0.0 else 0)) \ - * n2 + startElement - 1 + segmentIdx * ((elementsCountAround * n3) + - (elementsCountAround * elementsCountThroughWall + - elementsCountAroundTC * - (tcCount if tcThickness > 0.0 else 0)) * - elementsCountAlongSegment) - + startIdxElementsAround + int(elementsCountAroundTC * (0.5 if tcThickness > 0.0 else 0)) + n1 + \ + (elementsCountAround * n3) + n2 * (elementsCountAround * elementsCountThroughWall + + elementsCountAroundTC * (tcCount if tcThickness > 0.0 else 0))\ + + startElement - 1 + segmentIdx * (elementsCountAlongSegment * + (elementsCountAround * elementsCountThroughWall + + elementsCountAroundTC * (tcCount if tcThickness > 0.0 else 0))) deleteElementIdentifier.append(elementIdx) xTrackSurface = [] @@ -1249,8 +1073,10 @@ def createCecumMesh3d(region, options, centralPath, nextNodeIdentifier, nextElem xTrackSurface, d1TrackSurface, d2TrackSurface) # Find centre position - # track along ileum path and since cxIleum[1] could be above or below the track surface, we check both side to determine direction to track - # At each point, find the nearest position and take the diff between nearest point to the point in line, keep tracking till diff is close to zero. + # track along ileum path and since cxIleum[1] could be above or below the track surface, we check both side to + # determine direction to track. At each point, find the nearest position and take the diff between nearest point + # to the point in line, keep tracking till diff is close to zero. + xTol = 1.0E-6 arcStart = 0.0 arcEnd = centralPath.arcLengthOfGroupsAlong[1] @@ -1286,52 +1112,15 @@ def createCecumMesh3d(region, options, centralPath, nextNodeIdentifier, nextElem cxIleum[e + 1], cd1Ileum[e + 1]) xi = (arcDistance - arcLenghtSum)/\ interp.getCubicHermiteArcLength(cxIleum[eIdx], cd1Ileum[eIdx], cxIleum[eIdx + 1], cd1Ileum[eIdx + 1]) - d2Centre = interp.interpolateCubicHermite(cd2Ileum[eIdx], cd12Ileum[eIdx], cd2Ileum[eIdx + 1], cd12Ileum[eIdx + 1], xi) + d2Centre = interp.interpolateCubicHermite(cd2Ileum[eIdx], cd12Ileum[eIdx], cd2Ileum[eIdx + 1], + cd12Ileum[eIdx + 1], xi) break if iter > 98: print('Search for ileum entry centre - Max iters reached:', iter) - # node = nodes.createNode(nextNodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xNearest) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, [0.0, 0.0, 0.0]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, [0.0, 0.0, 0.0]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, [0.0, 0.0, 0.0]) - # print('x', nextNodeIdentifier) - # nextNodeIdentifier += 1 - - # node = nodes.createNode(nextNodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, cxIleum[eIdx]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, [0.0, 0.0, 0.0]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, cd2Ileum[eIdx]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, [0.0, 0.0, 0.0]) - # nextNodeIdentifier += 1 - # - # - # node = nodes.createNode(nextNodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, cxIleum[eIdx + 1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, [0.0, 0.0, 0.0]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, cd2Ileum[eIdx + 1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, [0.0, 0.0, 0.0]) - # nextNodeIdentifier += 1 - # - # node = nodes.createNode(nextNodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xCentre) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d1Centre) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d2Centre) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, normAxis) - # nextNodeIdentifier += 1 - ostiumSettings['Number of elements around ostium'] = elementsCountAlongSegment elementsCountAroundOstium = ostiumSettings['Number of elements around ostium'] - fm = region.getFieldmodule() - mesh = fm.findMeshByDimension(3) - nodes = fm.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES) - ileumGroup = AnnotationGroup(region, get_smallintestine_term("ileum")) ileumMeshGroup = ileumGroup.getMeshGroup(mesh) ileocecalJunctionGroup = AnnotationGroup(region, get_smallintestine_term("ileocecal junction")) @@ -1367,15 +1156,6 @@ def createCecumMesh3d(region, options, centralPath, nextNodeIdentifier, nextElem centralPathIleum = CustomCentralPath(xPath, d1Path, d2Path, d3Path, d12Path, d13Path) - # for n in range(2): - # node = nodes.createNode(nextNodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xPath[n]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d1Path[n]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d2Path[n]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, d3Path[n]) - # nextNodeIdentifier += 1 - nextNodeIdentifier, nextElementIdentifier, (o1_x, o1_d1, o1_d2, o1_d3, o1_NodeId, o1_Positions) = \ generateOstiumMesh(region, ostiumSettings, trackSurfaceOstium, centralPathIleum, startNodeIdentifier=nextNodeIdentifier, startElementIdentifier=nextElementIdentifier, @@ -1424,7 +1204,7 @@ def createCecumMesh3d(region, options, centralPath, nextNodeIdentifier, nextElem for n in range(elementsCountAroundOstium): d3 = vector.normalise(vector.crossproduct3(vector.normalise(d2AnnulusOuter[n]), d1AnnulusNorm[n])) d3Annulus.append(d3) - annulusD2Curvature = findCurvatureAroundLoop(xAnnulusOuter, d2AnnulusOuter, d3Annulus) + annulusD2Curvature = interp.findCurvatureAroundLoop(xAnnulusOuter, d2AnnulusOuter, d3Annulus) # # Visualise annulus # for n1 in range(len(xAnnulusOuter)): @@ -1486,57 +1266,10 @@ def createCecumMesh3d(region, options, centralPath, nextNodeIdentifier, nextElem for n in range(len(pd1AlongMidLine)): pd1AlongMidLine[n] = [-d for d in pd1AlongMidLine[n]] - # for n1 in range(len(nx)): - # node = nodes.createNode(nextNodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, nx[n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, nd2[n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, [0.0, 0.0, 0.0]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, [0.0, 0.0, 0.0]) - # # print(n1, nextNodeIdentifier) - # nextNodeIdentifier += 1 - - # Apex half - # print(startRowIdx) - # pxAlongMidLine, pd2AlongMidLine = \ - # interp.sampleCubicHermiteCurvesSmooth( - # nx, nd2, rowsBelow + 1, - # # derivativeMagnitudeStart=vector.magnitude([nx[1][c] - nx[0][c] for c in range(3)]), - # derivativeMagnitudeEnd=vector.magnitude(d2B))[:2] - - # for n1 in range(len(pxAlongMidLine)): - # node = nodes.createNode(nextNodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, pxAlongMidLine[n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, pd2AlongMidLine[n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, pd1AlongMidLine[n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, [0.0, 0.0, 0.0]) - # nextNodeIdentifier += 1 - - # Next haustrum half - # nx = [xAnnulusOuter[int(elementsCountAlongSegment * 0.5)]] - # nd2 = [d1AnnulusOuter[int(elementsCountAlongSegment * 0.5)]] - # nd1 = [d2AnnulusOuter[int(elementsCountAlongSegment * 0.5)]] - # - # for n in range(elementsAlongTrackSurface - e2Top): - # n1 = e2Top + 1 + n - # idx = elementsCountAroundHalfHaustrum + n1 * (elementsCountAroundHaustrum + 1) - 1 - # nx.append(xTrackSurface[idx]) - # nd2.append(d2TrackSurface[idx]) - # nd1.append(d1TrackSurface[idx]) - # - # pxAlongMidLineBottom, pd2AlongMidLineBottom, pe, pxi, psf = \ - # interp.sampleCubicHermiteCurvesSmooth( - # nx, nd2, rowsAbove + 1, - # derivativeMagnitudeStart=vector.magnitude(nd2[0]), - # derivativeMagnitudeEnd=vector.magnitude(nd2[-1])) - # - # pd1AlongMidLineBottom = nd1 - xPositionA = trackSurfaceOstium.findNearestPosition(xAnnulusOuter[int(elementsCountAlongSegment * 0.5)]) xProportionA = trackSurfaceOstium.getProportion(xPositionA) xA, derivative2A, derivativeA = trackSurfaceOstium.evaluateCoordinates(xPositionA, derivatives=True) - derivativeMagnitudeA = vector.magnitude(d2AnnulusOuter[int(elementsCountAlongSegment * 0.5)]) # derivativeA) + derivativeMagnitudeA = vector.magnitude(d2AnnulusOuter[int(elementsCountAlongSegment * 0.5)]) xB = xTrackSurface[-elementsCountAroundHalfHaustrum] xPositionB = trackSurfaceOstium.findNearestPosition(xB) @@ -1556,15 +1289,6 @@ def createCecumMesh3d(region, options, centralPath, nextNodeIdentifier, nextElem for n in range(len(pd1AlongMidLineBottom)): pd1AlongMidLineBottom[n] = [-d for d in pd1AlongMidLineBottom[n]] - # for n1 in range(len(pxAlongMidLineBottom)): - # node = nodes.createNode(nextNodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, pxAlongMidLineBottom[n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, pd2AlongMidLineBottom[n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, pd1AlongMidLineBottom[n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, [0.0, 0.0, 0.0]) - # nextNodeIdentifier += 1 - # sample points around colon to ostium annulusIdx = 1 xAroundAlong = [] @@ -1607,22 +1331,6 @@ def createCecumMesh3d(region, options, centralPath, nextNodeIdentifier, nextElem xProportionB = trackSurfaceOstium.getProportion(xPositionB) - # node = nodes.createNode(nextNodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xTrackSurface[n2 * (elementsCountAroundHaustrum + 1)]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, [0.0, 0.0, 0.0]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, derivativeA) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, [0.0, 0.0, 0.0]) - # nextNodeIdentifier += 1 - # - # node = nodes.createNode(nextNodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xB) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, [0.0, 0.0, 0.0]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, derivativeB) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, [0.0, 0.0, 0.0]) - # nextNodeIdentifier += 1 - else: # RHS if n2 < rowsBelow + 1: xPositionA = trackSurfaceOstium.findNearestPosition(pxAlongMidLine[n2]) @@ -1653,15 +1361,6 @@ def createCecumMesh3d(region, options, centralPath, nextNodeIdentifier, nextElem trackSurfaceOstium.resampleHermiteCurvePointsSmooth( nx, nd1, nd2, nd3, proportions)[0:2] - # for n in range(len(nx)): - # node = nodes.createNode(nextNodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, nx[n]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, nd1[n]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, [0.0, 0.0, 0.0]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, [0.0, 0.0, 0.0]) - # nextNodeIdentifier += 1 - if n2 == rowsBelow + 1 or n2 == rowsBelow + rowsOstium - 1: mag = 0.5 * (vector.magnitude(d1AnnulusOuter[0]) + vector.magnitude( d2AnnulusOuter[0])) if n2 == startRowIdx else vector.magnitude(d1AnnulusOuter[0]) @@ -1772,20 +1471,9 @@ def createCecumMesh3d(region, options, centralPath, nextNodeIdentifier, nextElem d3Around = [] for n1 in range(len(xAroundAlong[n2])): d3Around.append(vector.normalise( - vector.crossproduct3(vector.normalise(d1AroundAlong[n2][n1]), - vector.normalise(d2AroundAlong[n2][n1])))) + vector.crossproduct3(vector.normalise(d1AroundAlong[n2][n1]), vector.normalise(d2AroundAlong[n2][n1])))) d3UnitAroundAlong.append(d3Around) - # for n2 in range(len(xAroundAlong)): - # for n1 in range(len(xAroundAlong[n2])): - # node = nodes.createNode(nextNodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xAroundAlong[n2][n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d1AroundAlong[n2][n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d2AroundAlong[n2][n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, d3UnitAroundAlong[n2][n1]) - # nextNodeIdentifier += 1 - # Calculate curvatures # Curvatures around d1Curvature = [] @@ -1794,13 +1482,14 @@ def createCecumMesh3d(region, options, centralPath, nextNodeIdentifier, nextElem for n2 in range(1 if segmentIdx == 0 else 0, elementsCountAlongSegment + 1): if n2 < startRowIdx or n2 == elementsCountAlongSegment: - d1Curvature.append(findCurvatureAlongLine(xAroundAlong[n2], d1AroundAlong[n2], d3UnitAroundAlong[n2])) + d1Curvature.append(interp.findCurvatureAlongLine(xAroundAlong[n2], d1AroundAlong[n2], + d3UnitAroundAlong[n2])) else: - d1CurvatureLeft = findCurvatureAlongLine(xAroundAlong[n2][:int(0.5 * len(xAroundAlong[n2]))], + d1CurvatureLeft = interp.findCurvatureAlongLine(xAroundAlong[n2][:int(0.5 * len(xAroundAlong[n2]))], d1AroundAlong[n2][:int(0.5 * len(xAroundAlong[n2]))], d3UnitAroundAlong[n2][:int(0.5 * len(xAroundAlong[n2]))]) - d1CurvatureRight = findCurvatureAlongLine(xAroundAlong[n2][int(0.5 * len(xAroundAlong[n2])):], + d1CurvatureRight = interp.findCurvatureAlongLine(xAroundAlong[n2][int(0.5 * len(xAroundAlong[n2])):], d1AroundAlong[n2][int(0.5 * len(xAroundAlong[n2])):], d3UnitAroundAlong[n2][int(0.5 * len(xAroundAlong[n2])):]) @@ -1823,11 +1512,10 @@ def createCecumMesh3d(region, options, centralPath, nextNodeIdentifier, nextElem for n2 in range(elementsCountAlongSegment): d3UnitAlong.append(d3UnitAroundAlong[n2][n1]) d3UnitAlong.append(d3UnitAroundAlong[n2 + 1][n1]) - d2CurvatureAlong = findCurvatureAlongLine(xAlong, d2Along, d3UnitAlong) + d2CurvatureAlong = interp.findCurvatureAlongLine(xAlong, d2Along, d3UnitAlong) # Adjust for corners if n1 == elementsCountAroundHalfHaustrum - 2: d2CurvatureAlong[endRowIdx] = annulusD2Curvature[int(elementsCountAlongSegment * 0.5) - 1] - for n2 in range(len(d2CurvatureAlong)): d2Curvature[n2][n1] = d2CurvatureAlong[n2] @@ -1839,7 +1527,7 @@ def createCecumMesh3d(region, options, centralPath, nextNodeIdentifier, nextElem xAlong.append(xAroundAlong[n2][n1]) d2Along.append(d2AroundAlong[n2][n1]) d3UnitAlong.append(d3UnitAroundAlong[n2][n1]) - d2CurvatureAlong = findCurvatureAlongLine(xAlong, d2Along, d3UnitAlong) + d2CurvatureAlong = interp.findCurvatureAlongLine(xAlong, d2Along, d3UnitAlong) for n2 in range(len(pd2AlongMidLine)): d2Curvature[n2][n1] = d2CurvatureAlong[n2] @@ -1852,7 +1540,7 @@ def createCecumMesh3d(region, options, centralPath, nextNodeIdentifier, nextElem xAlong.append(xAroundAlong[nIdx][n1]) d2Along.append(d2AroundAlong[nIdx][n1]) d3UnitAlong.append(d3UnitAroundAlong[nIdx][n1]) - d2CurvatureAlong = findCurvatureAlongLine(xAlong, d2Along, d3UnitAlong) + d2CurvatureAlong = interp.findCurvatureAlongLine(xAlong, d2Along, d3UnitAlong) for n in range(len(pd2AlongMidLineBottom) - 1): nIdx = n + endRowIdx + 1 d2Curvature[nIdx][n1] = d2CurvatureAlong[n] @@ -1860,7 +1548,7 @@ def createCecumMesh3d(region, options, centralPath, nextNodeIdentifier, nextElem for n2 in range(elementsCountAlongSegment): d3UnitAlong.append(d3UnitAroundAlong[n2][n1 + (0 if (n2 < startRowIdx or n2 > endRowIdx) else -1)]) d3UnitAlong.append(d3UnitAroundAlong[n2 + 1][n1]) - d2CurvatureAlong = findCurvatureAlongLine(xAlong, d2Along, d3UnitAlong) + d2CurvatureAlong = interp.findCurvatureAlongLine(xAlong, d2Along, d3UnitAlong) # Adjust for corners if n1 == elementsCountAroundHalfHaustrum: @@ -1892,16 +1580,6 @@ def createCecumMesh3d(region, options, centralPath, nextNodeIdentifier, nextElem d1Curvature[endRowIdx].insert(int(elementsCountAroundHaustrum * 0.5), annulusD2Curvature[idx]) d2Curvature[endRowIdx].insert(int(elementsCountAroundHaustrum * 0.5), annulusD2Curvature[idx]) - # for n2 in range(len(xAroundAlong)): - # for n1 in range(len(xAroundAlong[n2])): - # node = nodes.createNode(nextNodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xAroundAlong[n2][n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d1AroundAlong[n2][n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d2AroundAlong[n2][n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, d3UnitAroundAlong[n2][n1]) - # nextNodeIdentifier += 1 - # Create inner nodes sideNodesToDelete = [] xList = [] @@ -1994,7 +1672,7 @@ def createCecumMesh3d(region, options, centralPath, nextNodeIdentifier, nextElem coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D2_DS2DS3, 1, zero) coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D3_DS1DS2DS3, 1, zero) nextNodeIdentifier += 1 - + # Create elements elementIdxMat = [] @@ -2086,7 +1764,8 @@ def createCecumMesh3d(region, options, centralPath, nextNodeIdentifier, nextElem scaleFactors = [-1.0] eft1 = eftfactory.createEftNoCrossDerivatives() setEftScaleFactorIds(eft1, [1], []) - remapEftNodeValueLabel(eft1, [3, 7], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS2, [1])]) + remapEftNodeValueLabel(eft1, [3, 7], Node.VALUE_LABEL_D_DS1, + [(Node.VALUE_LABEL_D_DS2, [1])]) remapEftNodeValueLabel(eft1, [3, 7], Node.VALUE_LABEL_D_DS2, [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [])]) remapEftNodeValueLabel(eft1, [4, 8], Node.VALUE_LABEL_D_DS2, @@ -2307,17 +1986,19 @@ def __init__(self, region, centralPath, termsAlong=[None]): if i == 0: xbranchpt = cx[-1] d2branchpt = cd2[-1] + d3branchpt = cd3[-1] arcLengthToBranchPt = 0.0 for n in range(len(cx) - 1): arcLengthToBranchPt += interp.getCubicHermiteArcLength(cx[n], cd1[n], cx[n + 1], cd1[n + 1]) elif termName == "ileum": - cxGroup, cd1Group, cd2Group, cd3Group, cd12Group, cd13Group = get_nodeset_path_ordered_field_parameters( - tmpNodes, tmpCoordinates, - [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], - networkSegments[0].getNodeIdentifiers(), networkSegments[0].getNodeVersions()) + cxGroup, cd1Group, cd2Group, cd3Group, cd12Group, cd13Group = \ + get_nodeset_path_ordered_field_parameters(tmpNodes, tmpCoordinates, + [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], + networkSegments[0].getNodeIdentifiers(), + networkSegments[0].getNodeVersions()) arcLength = 0.0 for e in range(len(cxGroup) - 1): @@ -2348,6 +2029,7 @@ def __init__(self, region, centralPath, termsAlong=[None]): self.cd13Groups = cd13Groups self.xBranchPt = xbranchpt self.d2BranchPt = d2branchpt + self.d3BranchPt = d3branchpt self.arcLengthToBranchPt = arcLengthToBranchPt class CustomCentralPath: diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_colonsegment1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_colonsegment1.py index ccd27b9b..acb5161f 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_colonsegment1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_colonsegment1.py @@ -15,6 +15,7 @@ from scaffoldmaker.annotation.annotationgroup import AnnotationGroup, mergeAnnotationGroups, \ findOrCreateAnnotationGroupForTerm, findAnnotationGroupByName, getAnnotationGroupForTerm from scaffoldmaker.annotation.colon_terms import get_colon_term +from scaffoldmaker.annotation.cecum_terms import get_cecum_term from scaffoldmaker.meshtypes.scaffold_base import Scaffold_base from scaffoldmaker.utils import interpolation as interp from scaffoldmaker.utils import matrix @@ -1922,10 +1923,13 @@ def createNodesAndElementsTeniaColi(region, allAnnotationGroups = [] for group in annotationGroupsThroughWall: - longitudinalMuscle = findAnnotationGroupByName(group, "longitudinal muscle layer of colon") + longitudinalMuscle = findAnnotationGroupByName(group, ("longitudinal muscle layer of cecum" if closedProximalEnd + else "longitudinal muscle layer of colon")) if longitudinalMuscle: - longitudinalMuscleGroup = AnnotationGroup(region, get_colon_term("longitudinal muscle layer of colon")) + longitudinalMuscleGroup = \ + AnnotationGroup(region, (get_cecum_term("longitudinal muscle layer of cecum") if closedProximalEnd + else get_colon_term("longitudinal muscle layer of colon"))) if closedProximalEnd: elementtemplate3 = mesh.createElementtemplate() diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py index 900c2394..41be71f0 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py @@ -1241,7 +1241,7 @@ def findD1CurvatureAround(xAround, d1Around, normsAround): xLoop = xAround[int(len(xAround) * 0.5 + 1):] + xAround[: int(len(xAround) * 0.5 + 1)] d1Loop = d1Around[int(len(d1Around) * 0.5 + 1):] + d1Around[: int(len(d1Around) * 0.5 + 1)] normsLoop = normsAround[int(len(d1Around) * 0.5 + 1):] + normsAround[: int(len(d1Around) * 0.5 + 1)] - curvature = findCurvatureAlongLine(xLoop, d1Loop, normsLoop) + curvature = interp.findCurvatureAlongLine(xLoop, d1Loop, normsLoop) # Rearrange to correct order d1CurvatureAround = curvature[int(len(xAround) * 0.5):] + curvature[: int(len(xAround) * 0.5):] @@ -1262,48 +1262,6 @@ def findDerivativeBetweenPoints(v1, v2): return d - -def findCurvatureAroundLoop(nx, nd, radialVectors): - """ - Calculate curvature for points lying along a loop. - :param nx: points on loop - :param nd: derivative of points on loop - :param radialVectors: radial direction, assumed normal to curve tangent at point - :return: curvatures along points on loop - """ - curvature = [] - for n in range(len(nx)): - prevIdx = n - 1 if n > 0 else -1 - nextIdx = n + 1 if n < len(nx) - 1 else 0 - kappam = interp.getCubicHermiteCurvature(nx[prevIdx], nd[prevIdx], nx[n], nd[n], radialVectors[n], 1.0) - kappap = interp.getCubicHermiteCurvature(nx[n], nd[n], nx[nextIdx], nd[nextIdx], radialVectors[n], 0.0) - curvature.append(0.5 * (kappam + kappap)) - - return curvature - - -def findCurvatureAlongLine(nx, nd, radialVectors): - """ - Calculate curvature for points lying along a line. - :param nx: points on line - :param nd: derivative of points on line - :param radialVectors: radial direction, assumed normal to curve tangent at point - :return: curvatures along points on line - """ - curvature = [] - for n in range(len(nx)): - if n == 0: - curvature.append(interp.getCubicHermiteCurvature(nx[n], nd[n], nx[n + 1], nd[n + 1], radialVectors[n], 0.0)) - elif n == len(nx) - 1: - curvature.append(interp.getCubicHermiteCurvature(nx[n - 1], nd[n - 1], nx[n], nd[n], radialVectors[n], 1.0)) - else: - curvature.append(0.5 * ( - interp.getCubicHermiteCurvature(nx[n], nd[n], nx[n + 1], nd[n + 1], radialVectors[n], 0.0) + - interp.getCubicHermiteCurvature(nx[n - 1], nd[n - 1], nx[n], nd[n], radialVectors[n], 1.0))) - - return curvature - - def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotationGroups, elementCountGroupList, centralPath, options, nodeIdentifier, elementIdentifier, splitCoordinates, materialCoordinates=False): @@ -1933,7 +1891,7 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio for n in range(elementsCountAroundEso): d3 = vector.normalise(vector.crossproduct3(vector.normalise(d2AnnulusOuter[n]), d1AnnulusNorm[n])) d3Annulus.append(d3) - annulusD2Curvature = findCurvatureAroundLoop(xAnnulusOuter, d2AnnulusOuter, d3Annulus) + annulusD2Curvature = interp.findCurvatureAroundLoop(xAnnulusOuter, d2AnnulusOuter, d3Annulus) # Adjust annulus derivatives # Make d2 on second half of eso point towards duodenum @@ -2433,7 +2391,7 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio vector.normalise(o1_d2[-1][esoCount]))) rotFrame = matrix.getRotationMatrixFromAxisAngle(rotAxis, math.pi) d2Rot = [rotFrame[j][0] * d2[0] + rotFrame[j][1] * d2[1] + rotFrame[j][2] * d2[2] for j in range(3)] - d1CurvatureFirstHalf = findCurvatureAlongLine(xOuter[n2][:elementsAroundHalfDuod] + [o1_x[-1][esoCount]], + d1CurvatureFirstHalf = interp.findCurvatureAlongLine(xOuter[n2][:elementsAroundHalfDuod] + [o1_x[-1][esoCount]], d1Outer[n2][:elementsAroundHalfDuod] + [d2Rot], d3UnitOuter[n2][:elementsAroundHalfDuod] + [rotAxis]) curvature = interp.getCubicHermiteCurvature(xAnnulusOuter[esoCount], d1AnnulusOuter[esoCount], @@ -2443,7 +2401,7 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio d3 = vector.normalise(vector.crossproduct3(vector.normalise(o1_d1[-1][-esoCount]), vector.normalise(o1_d2[-1][-esoCount]))) - d1CurvatureSecondHalf = findCurvatureAlongLine([o1_x[-1][-esoCount]] + + d1CurvatureSecondHalf = interp.findCurvatureAlongLine([o1_x[-1][-esoCount]] + xOuter[n2][elementsAroundHalfDuod:] + [xOuter[n2][0]], [o1_d2[-1][-esoCount]] + d1Outer[n2][elementsAroundHalfDuod:] + [d1Outer[n2][0]], @@ -2458,11 +2416,11 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio esoCount += 1 elif completeRingsOnCardia: - d1CurvatureFirstHalf = findCurvatureAlongLine(xOuter[n2][:elementsAroundHalfDuod], + d1CurvatureFirstHalf = interp.findCurvatureAlongLine(xOuter[n2][:elementsAroundHalfDuod], d1Outer[n2][:elementsAroundHalfDuod], d3UnitOuter[n2][:elementsAroundHalfDuod]) - d1CurvatureSecondHalf = findCurvatureAlongLine(xOuter[n2][elementsAroundHalfDuod + 1:] + [xOuter[n2][0]], + d1CurvatureSecondHalf = interp.findCurvatureAlongLine(xOuter[n2][elementsAroundHalfDuod + 1:] + [xOuter[n2][0]], d1Outer[n2][elementsAroundHalfDuod + 1:] + [d1Outer[n2][0]], d3UnitOuter[n2][elementsAroundHalfDuod + 1:] + [d3UnitOuter[n2][0]])[:-1] @@ -2518,13 +2476,13 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio for n1 in range(len(xAlongAll)): if n1 == elementsAroundHalfDuod: # Process LC and GC # GC - d2CurvatureAlongGCHalfDuod = findCurvatureAlongLine(xAlongGCHalfDuod, d2AlongGCHalfDuod, d3AlongGCHalfDuod) + d2CurvatureAlongGCHalfDuod = interp.findCurvatureAlongLine(xAlongGCHalfDuod, d2AlongGCHalfDuod, d3AlongGCHalfDuod) # LC - d2CurvatureAlongLCHalfDuod = findCurvatureAlongLine(xAlongLCHalfDuod, d2AlongLCHalfDuod, d3AlongLCHalfDuod) + d2CurvatureAlongLCHalfDuod = interp.findCurvatureAlongLine(xAlongLCHalfDuod, d2AlongLCHalfDuod, d3AlongLCHalfDuod) d2CurvaturesAlongCurvature = d2CurvatureAlongGCHalfDuod + d2CurvatureAlongLCHalfDuod d2CurvatureAlong.append(d2CurvaturesAlongCurvature) else: - curvature = findCurvatureAlongLine(xAlongAll[n1], d2AlongAll[n1], d3UnitAlongAll[n1]) + curvature = interp.findCurvatureAlongLine(xAlongAll[n1], d2AlongAll[n1], d3UnitAlongAll[n1]) # replace with curvature from annulus if n1 == elementsAroundHalfDuod - 1 or n1 == elementsAroundHalfDuod + 1: for n2 in range(2, elementsAroundHalfEso - 1): diff --git a/src/scaffoldmaker/utils/interpolation.py b/src/scaffoldmaker/utils/interpolation.py index 3ae637e7..6a0114e0 100644 --- a/src/scaffoldmaker/utils/interpolation.py +++ b/src/scaffoldmaker/utils/interpolation.py @@ -973,3 +973,42 @@ def sampleParameterAlongLine(lengthList, paramList, elementsCountOut): sdP.append(dpdx*lengthPerElementOut) return sP, sdP + +def findCurvatureAroundLoop(nx, nd, radialVectors): + """ + Calculate curvature for points lying along a loop. + :param nx: points on loop + :param nd: derivative of points on loop + :param radialVectors: radial direction, assumed normal to curve tangent at point + :return: curvatures along points on loop + """ + curvature = [] + for n in range(len(nx)): + prevIdx = n - 1 if n > 0 else -1 + nextIdx = n + 1 if n < len(nx) - 1 else 0 + kappam = getCubicHermiteCurvature(nx[prevIdx], nd[prevIdx], nx[n], nd[n], radialVectors[n], 1.0) + kappap = getCubicHermiteCurvature(nx[n], nd[n], nx[nextIdx], nd[nextIdx], radialVectors[n], 0.0) + curvature.append(0.5 * (kappam + kappap)) + + return curvature + +def findCurvatureAlongLine(nx, nd, radialVectors): + """ + Calculate curvature for points lying along a line. + :param nx: points on line + :param nd: derivative of points on line + :param radialVectors: radial direction, assumed normal to curve tangent at point + :return: curvatures along points on line + """ + curvature = [] + for n in range(len(nx)): + if n == 0: + curvature.append(getCubicHermiteCurvature(nx[n], nd[n], nx[n + 1], nd[n + 1], radialVectors[n], 0.0)) + elif n == len(nx) - 1: + curvature.append(getCubicHermiteCurvature(nx[n - 1], nd[n - 1], nx[n], nd[n], radialVectors[n], 1.0)) + else: + curvature.append(0.5 * ( + getCubicHermiteCurvature(nx[n], nd[n], nx[n + 1], nd[n + 1], radialVectors[n], 0.0) + + getCubicHermiteCurvature(nx[n - 1], nd[n - 1], nx[n], nd[n], radialVectors[n], 1.0))) + + return curvature From 17a3b4f5137d70d7f923076613c6398119d03af4 Mon Sep 17 00:00:00 2001 From: mlin865 Date: Mon, 17 Jul 2023 15:18:06 +1200 Subject: [PATCH 09/24] Use 1D network layout as central path for esophagus and intestines --- .../meshtypes/meshtype_3d_colon1.py | 87 +++++++------------ .../meshtypes/meshtype_3d_esophagus1.py | 30 +++---- .../meshtypes/meshtype_3d_smallintestine1.py | 85 ++++++++++-------- tests/test_cecum.py | 8 +- tests/test_colon.py | 14 ++- tests/test_smallintestine.py | 14 ++- 6 files changed, 110 insertions(+), 128 deletions(-) diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_colon1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_colon1.py index 8ea87931..c4d46816 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_colon1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_colon1.py @@ -12,7 +12,7 @@ from scaffoldmaker.annotation.annotationgroup import AnnotationGroup, findOrCreateAnnotationGroupForTerm, \ getAnnotationGroupForTerm from scaffoldmaker.annotation.colon_terms import get_colon_term -from scaffoldmaker.meshtypes.meshtype_1d_path1 import MeshType_1d_path1 +from scaffoldmaker.meshtypes.meshtype_1d_network_layout1 import MeshType_1d_network_layout1 from scaffoldmaker.meshtypes.meshtype_3d_colonsegment1 import MeshType_3d_colonsegment1, \ ColonSegmentTubeMeshInnerPoints, getTeniaColi, createFlatCoordinatesTeniaColi, createColonCoordinatesTeniaColi, \ createNodesAndElementsTeniaColi @@ -34,14 +34,11 @@ class MeshType_3d_colon1(Scaffold_base): line profile. ''' - centralPathDefaultScaffoldPackages = { - 'Cattle 1': ScaffoldPackage(MeshType_1d_path1, { + parameterSetStructureStrings = { + 'Cattle 1': ScaffoldPackage(MeshType_1d_network_layout1, { 'scaffoldSettings': { - 'Coordinate dimensions': 3, - 'D2 derivatives': True, - 'D3 derivatives': True, - 'Length': 1.0, - 'Number of elements': 52 + "Structure": "1-2-3-4-5-6-7-8-9-10-11-12-13-14-15-16-17-18-19-20-21-22-23-24-25-26-27-28-29-30-31-32-" + "33-34-35-36-37-38-39-40-41-42-43-44-45-46-47-48-49-50-51-52-53" }, 'meshEdits': exnode_string_from_nodeset_field_parameters( [ Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3 ], [ @@ -122,13 +119,9 @@ class MeshType_3d_colon1(Scaffold_base): 'ontId': get_colon_term('left colon')[1] }] }), - 'Human 1': ScaffoldPackage(MeshType_1d_path1, { + 'Human 1': ScaffoldPackage(MeshType_1d_network_layout1, { 'scaffoldSettings': { - 'Coordinate dimensions': 3, - 'D2 derivatives': True, - 'D3 derivatives': True, - 'Length': 1.0, - 'Number of elements': 8 + "Structure": "1-2-3-4-5-6-7-8-9" }, 'meshEdits': exnode_string_from_nodeset_field_parameters( [ Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ @@ -165,13 +158,9 @@ class MeshType_3d_colon1(Scaffold_base): 'ontId': get_colon_term('descending colon')[1] }] }), - 'Human 2': ScaffoldPackage(MeshType_1d_path1, { + 'Human 2': ScaffoldPackage(MeshType_1d_network_layout1, { 'scaffoldSettings': { - 'Coordinate dimensions': 3, - 'D2 derivatives': True, - 'D3 derivatives': True, - 'Length': 1.0, - 'Number of elements': 8 + "Structure": "1-2-3-4-5-6-7-8-9" }, 'meshEdits': exnode_string_from_nodeset_field_parameters( [ Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ @@ -208,13 +197,10 @@ class MeshType_3d_colon1(Scaffold_base): 'ontId': get_colon_term('descending colon')[1] }] }), - 'Human 3': ScaffoldPackage(MeshType_1d_path1, { + 'Human 3': ScaffoldPackage(MeshType_1d_network_layout1, { 'scaffoldSettings': { - 'Coordinate dimensions': 3, - 'D2 derivatives': True, - 'D3 derivatives': True, - 'Length': 1.0, - 'Number of elements': 48 + "Structure": "1-2-3-4-5-6-7-8-9-10-11-12-13-14-15-16-17-18-19-20-21-22-23-24-25-26-27-28-29-30-31-32-" + "33-34-35-36-37-38-39-40-41-42-43-44-45-46-47-48-49" }, 'meshEdits': exnode_string_from_nodeset_field_parameters( [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ @@ -298,13 +284,9 @@ class MeshType_3d_colon1(Scaffold_base): 'ontId': get_colon_term('descending colon')[1] }] }), - 'Mouse 1': ScaffoldPackage(MeshType_1d_path1, { + 'Mouse 1': ScaffoldPackage(MeshType_1d_network_layout1, { 'scaffoldSettings': { - 'Coordinate dimensions': 3, - 'D2 derivatives': True, - 'D3 derivatives': True, - 'Length': 1.0, - 'Number of elements': 7 + "Structure": "1-2-3-4-5-6-7-8" }, 'meshEdits': exnode_string_from_nodeset_field_parameters( [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ @@ -340,13 +322,9 @@ class MeshType_3d_colon1(Scaffold_base): 'ontId': get_colon_term('left colon')[1] }] }), - 'Mouse 2': ScaffoldPackage(MeshType_1d_path1, { + 'Mouse 2': ScaffoldPackage(MeshType_1d_network_layout1, { 'scaffoldSettings': { - 'Coordinate dimensions': 3, - 'D2 derivatives': True, - 'D3 derivatives': True, - 'Length': 1.0, - 'Number of elements': 4 + "Structure": "1-2-3-4-5" }, 'meshEdits': exnode_string_from_nodeset_field_parameters( [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ @@ -379,13 +357,10 @@ class MeshType_3d_colon1(Scaffold_base): 'ontId': get_colon_term('left colon')[1] }] }), - 'Pig 1': ScaffoldPackage(MeshType_1d_path1, { + 'Pig 1': ScaffoldPackage(MeshType_1d_network_layout1, { 'scaffoldSettings': { - 'Coordinate dimensions': 3, - 'D2 derivatives': True, - 'D3 derivatives': True, - 'Length': 1.0, - 'Number of elements': 39 + "Structure": "1-2-3-4-5-6-7-8-9-10-11-12-13-14-15-16-17-18-19-20-21-22-23-24-25-26-27-28-29-30-31-32-" + "33-34-35-36-37-38-39-40" }, 'meshEdits': exnode_string_from_nodeset_field_parameters( [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ @@ -474,19 +449,19 @@ def getParameterSetNames(): @classmethod def getDefaultOptions(cls, parameterSetName='Default'): if 'Human 2' in parameterSetName: - centralPathOption = cls.centralPathDefaultScaffoldPackages['Human 2'] + centralPathOption = cls.parameterSetStructureStrings['Human 2'] elif 'Human 3' in parameterSetName: - centralPathOption = cls.centralPathDefaultScaffoldPackages['Human 3'] + centralPathOption = cls.parameterSetStructureStrings['Human 3'] elif 'Cattle 1' in parameterSetName: - centralPathOption = cls.centralPathDefaultScaffoldPackages['Cattle 1'] + centralPathOption = cls.parameterSetStructureStrings['Cattle 1'] elif 'Mouse 1' in parameterSetName: - centralPathOption = cls.centralPathDefaultScaffoldPackages['Mouse 1'] + centralPathOption = cls.parameterSetStructureStrings['Mouse 1'] elif 'Mouse 2' in parameterSetName: - centralPathOption = cls.centralPathDefaultScaffoldPackages['Mouse 2'] + centralPathOption = cls.parameterSetStructureStrings['Mouse 2'] elif 'Pig 1' in parameterSetName: - centralPathOption = cls.centralPathDefaultScaffoldPackages['Pig 1'] + centralPathOption = cls.parameterSetStructureStrings['Pig 1'] else: - centralPathOption = cls.centralPathDefaultScaffoldPackages['Human 1'] + centralPathOption = cls.parameterSetStructureStrings['Human 1'] if 'Human 3' in parameterSetName: segmentProfileOption = ScaffoldPackage(MeshType_3d_colonsegment1, defaultParameterSetName='Human 2') @@ -553,7 +528,7 @@ def getOrderedOptionNames(): @classmethod def getOptionValidScaffoldTypes(cls, optionName): if optionName == 'Central path': - return [MeshType_1d_path1] + return [MeshType_1d_network_layout1] if optionName == 'Segment profile': return [MeshType_3d_colonsegment1] return [] @@ -561,7 +536,7 @@ def getOptionValidScaffoldTypes(cls, optionName): @classmethod def getOptionScaffoldTypeParameterSetNames(cls, optionName, scaffoldType): if optionName == 'Central path': - return list(cls.centralPathDefaultScaffoldPackages.keys()) + return list(cls.parameterSetStructureStrings.keys()) assert scaffoldType in cls.getOptionValidScaffoldTypes(optionName), \ cls.__name__ + '.getOptionScaffoldTypeParameterSetNames. ' + \ 'Invalid option \'' + optionName + '\' scaffold type ' + scaffoldType.getName() @@ -579,8 +554,8 @@ def getOptionScaffoldPackage(cls, optionName, scaffoldType, parameterSetName=Non ' in option ' + str(optionName) + ' of scaffold ' + cls.getName() if optionName == 'Central path': if not parameterSetName: - parameterSetName = list(cls.centralPathDefaultScaffoldPackages.keys())[0] - return copy.deepcopy(cls.centralPathDefaultScaffoldPackages[parameterSetName]) + parameterSetName = list(cls.parameterSetStructureStrings.keys())[0] + return copy.deepcopy(cls.parameterSetStructureStrings[parameterSetName]) if optionName == 'Segment profile': if not parameterSetName: parameterSetName = scaffoldType.getParameterSetNames()[0] @@ -590,7 +565,7 @@ def getOptionScaffoldPackage(cls, optionName, scaffoldType, parameterSetName=Non @classmethod def checkOptions(cls, options): if not options['Central path'].getScaffoldType() in cls.getOptionValidScaffoldTypes('Central path'): - options['Central path'] = cls.getOptionScaffoldPackage('Central path', MeshType_1d_path1) + options['Central path'] = cls.getOptionScaffoldPackage('Central path', MeshType_1d_network_layout1) if not options['Segment profile'].getScaffoldType() in cls.getOptionValidScaffoldTypes('Segment profile'): options['Segment profile'] = cls.getOptionScaffoldPackage('Segment profile', MeshType_3d_colonsegment1) for key in [ diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_esophagus1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_esophagus1.py index b187d359..0b9bbb75 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_esophagus1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_esophagus1.py @@ -6,6 +6,7 @@ import copy import math + from cmlibs.utils.zinc.field import findOrCreateFieldGroup, findOrCreateFieldStoredString, \ findOrCreateFieldStoredMeshLocation from cmlibs.zinc.element import Element @@ -14,14 +15,14 @@ from scaffoldmaker.annotation.annotationgroup import AnnotationGroup, getAnnotationGroupForTerm, \ findOrCreateAnnotationGroupForTerm from scaffoldmaker.annotation.esophagus_terms import get_esophagus_term -from scaffoldmaker.meshtypes.meshtype_1d_path1 import MeshType_1d_path1 +from scaffoldmaker.meshtypes.meshtype_1d_network_layout1 import MeshType_1d_network_layout1 from scaffoldmaker.meshtypes.scaffold_base import Scaffold_base from scaffoldmaker.scaffoldpackage import ScaffoldPackage from scaffoldmaker.utils import geometry from scaffoldmaker.utils import interpolation as interp from scaffoldmaker.utils import tubemesh from scaffoldmaker.utils import vector -from scaffoldmaker.utils.zinc_utils import exnode_string_from_nodeset_field_parameters, \ +from scaffoldmaker.utils.zinc_utils import exnode_string_from_nodeset_field_parameters,\ get_nodeset_path_field_parameters @@ -32,15 +33,11 @@ class MeshType_3d_esophagus1(Scaffold_base): segment along a central path profile. """ - centralPathDefaultScaffoldPackages = { - 'Human 1': ScaffoldPackage(MeshType_1d_path1, { + parameterSetStructureStrings = { + 'Human 1': ScaffoldPackage(MeshType_1d_network_layout1, { 'scaffoldSettings': { - 'Coordinate dimensions': 3, - 'D2 derivatives': True, - 'D3 derivatives': True, - 'Length': 1.0, - 'Number of elements': 4 - }, + "Structure": "1-2-3-4-5" + }, 'meshEdits': exnode_string_from_nodeset_field_parameters( [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ (1, [ [ -0.42, -100.50, 1401.88 ], [ 0.74, 14.22, -46.12 ], [ 7.85, -0.56, -0.05 ], [ 0.69, 0.03, 0.02 ], [ -0.22, -2.98, -0.92 ], [ 0.19, 1.51, 0.43 ] ] ), @@ -86,7 +83,7 @@ def getParameterSetNames(): @classmethod def getDefaultOptions(cls, parameterSetName='Default'): - centralPathOption = cls.centralPathDefaultScaffoldPackages['Human 1'] + centralPathOption = cls.parameterSetStructureStrings['Human 1'] options = { 'Central path': copy.deepcopy(centralPathOption), 'Number of elements around': 8, @@ -128,13 +125,13 @@ def getOrderedOptionNames(): @classmethod def getOptionValidScaffoldTypes(cls, optionName): if optionName == 'Central path': - return [MeshType_1d_path1] + return [MeshType_1d_network_layout1] return [] @classmethod def getOptionScaffoldTypeParameterSetNames(cls, optionName, scaffoldType): if optionName == 'Central path': - return list(cls.centralPathDefaultScaffoldPackages.keys()) + return list(cls.parameterSetStructureStrings.keys()) assert scaffoldType in cls.getOptionValidScaffoldTypes(optionName), \ cls.__name__ + '.getOptionScaffoldTypeParameterSetNames. ' + \ 'Invalid option \'' + optionName + '\' scaffold type ' + scaffoldType.getName() @@ -152,14 +149,14 @@ def getOptionScaffoldPackage(cls, optionName, scaffoldType, parameterSetName=Non ' in option ' + str(optionName) + ' of scaffold ' + cls.getName() if optionName == 'Central path': if not parameterSetName: - parameterSetName = list(cls.centralPathDefaultScaffoldPackages.keys())[0] - return copy.deepcopy(cls.centralPathDefaultScaffoldPackages[parameterSetName]) + parameterSetName = list(cls.parameterSetStructureStrings.keys())[0] + return copy.deepcopy(cls.parameterSetStructureStrings[parameterSetName]) assert False, cls.__name__ + '.getOptionScaffoldPackage: Option ' + optionName + ' is not a scaffold' @classmethod def checkOptions(cls, options): if not options['Central path'].getScaffoldType() in cls.getOptionValidScaffoldTypes('Central path'): - options['Central path'] = cls.getOptionScaffoldPackage('Central path', MeshType_1d_path1) + options['Central path'] = cls.getOptionScaffoldPackage('Central path', MeshType_1d_network_layout1) if options['Number of elements through wall'] != (1 or 4): options['Number of elements through wall'] = 4 for key in [ @@ -208,6 +205,7 @@ def generateBaseMesh(cls, region, options): tmpFieldmodule = tmpRegion.getFieldmodule() tmpNodes = tmpFieldmodule.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES) tmpCoordinates = tmpFieldmodule.findFieldByName('coordinates') + esophagusTermsAlong =\ [None, 'cervical part of esophagus', 'thoracic part of esophagus', 'abdominal part of esophagus'] arcLengthOfGroupsAlong = [] diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_smallintestine1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_smallintestine1.py index 767c5f6c..ca5cfbb6 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_smallintestine1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_smallintestine1.py @@ -12,7 +12,7 @@ from scaffoldmaker.annotation.annotationgroup import AnnotationGroup, findOrCreateAnnotationGroupForTerm, \ getAnnotationGroupForTerm from scaffoldmaker.annotation.smallintestine_terms import get_smallintestine_term -from scaffoldmaker.meshtypes.meshtype_1d_path1 import MeshType_1d_path1 +from scaffoldmaker.meshtypes.meshtype_1d_network_layout1 import MeshType_1d_network_layout1 from scaffoldmaker.meshtypes.scaffold_base import Scaffold_base from scaffoldmaker.scaffoldpackage import ScaffoldPackage from scaffoldmaker.utils import interpolation as interp @@ -32,16 +32,35 @@ class MeshType_3d_smallintestine1(Scaffold_base): along a central line profile. ''' - centralPathDefaultScaffoldPackages = { - 'Cattle 1' : ScaffoldPackage(MeshType_1d_path1, { - 'scaffoldSettings' : { - 'D2 derivatives': True, - 'D3 derivatives': True, - 'Coordinate dimensions' : 3, - 'Length' : 1.0, - 'Number of elements' : 536 - }, - 'meshEdits' : exnode_string_from_nodeset_field_parameters( + parameterSetStructureStrings = { + 'Cattle 1': ScaffoldPackage(MeshType_1d_network_layout1, { + 'scaffoldSettings': { + "Structure": "1-2-3-4-5-6-7-8-9-10-11-12-13-14-15-16-17-18-19-20-21-22-23-24-25-26-27-28-29-30-31-32-" + "33-34-35-36-37-38-39-40-41-42-43-44-45-46-47-48-49-50-51-52-53-54-55-56-57-58-59-60-61-" + "62-63-64-65-66-67-68-69-70-71-72-73-74-75-76-77-78-79-80-81-82-83-84-85-86-87-88-89-90-" + "91-92-93-94-95-96-97-98-99-100-101-102-103-104-105-106-107-108-109-110-111-112-113-114-" + "115-116-117-118-119-120-121-122-123-124-125-126-127-128-129-130-131-132-133-134-135-136-" + "137-138-139-140-141-142-143-144-145-146-147-148-149-150-151-152-153-154-155-156-157-158-" + "159-160-161-162-163-164-165-166-167-168-169-170-171-172-173-174-175-176-177-178-179-180-" + "181-182-183-184-185-186-187-188-189-190-191-192-193-194-195-196-197-198-199-200-201-202-" + "203-204-205-206-207-208-209-210-211-212-213-214-215-216-217-218-219-220-221-222-223-224-" + "225-226-227-228-229-230-231-232-233-234-235-236-237-238-239-240-241-242-243-244-245-246-" + "247-248-249-250-251-252-253-254-255-256-257-258-259-260-261-262-263-264-265-266-267-268-" + "269-270-271-272-273-274-275-276-277-278-279-280-281-282-283-284-285-286-287-288-289-290-" + "291-292-293-294-295-296-297-298-299-300-301-302-303-304-305-306-307-308-309-310-311-312-" + "313-314-315-316-317-318-319-320-321-322-323-324-325-326-327-328-329-330-331-332-333-334-" + "335-336-337-338-339-340-341-342-343-344-345-346-347-348-349-350-351-352-353-354-355-356-" + "357-358-359-360-361-362-363-364-365-366-367-368-369-370-371-372-373-374-375-376-377-378-" + "379-380-381-382-383-384-385-386-387-388-389-390-391-392-393-394-395-396-397-398-399-400-" + "401-402-403-404-405-406-407-408-409-410-411-412-413-414-415-416-417-418-419-420-421-422-" + "423-424-425-426-427-428-429-430-431-432-433-434-435-436-437-438-439-440-441-442-443-444-" + "445-446-447-448-449-450-451-452-453-454-455-456-457-458-459-460-461-462-463-464-465-466-" + "467-468-469-470-471-472-473-474-475-476-477-478-479-480-481-482-483-484-485-486-487-488-" + "489-490-491-492-493-494-495-496-497-498-499-500-501-502-503-504-505-506-507-508-509-510-" + "511-512-513-514-515-516-517-518-519-520-521-522-523-524-525-526-527-528-529-530-531-532-" + "533-534-535-536-537" + }, + 'meshEdits': exnode_string_from_nodeset_field_parameters( [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ (1, [ [ -502.30, 732.10, 92.00 ], [ -49.80, -90.70, 0.00 ], [ 0.00, 0.00, 10.00 ], [ 0.00, 0.00, 0.00 ], [ -8.77, 4.81, 0.00 ], [ 0.00, 0.00, 0.00 ] ] ), (2, [ [ -543.10, 654.80, 92.00 ], [ -31.70, -64.00, 0.00 ], [ 0.00, 0.00, 10.00 ], [ 0.00, 0.00, 0.00 ], [ -8.96, 4.44, 0.00 ], [ 0.00, 0.00, 0.00 ] ] ), @@ -604,13 +623,14 @@ class MeshType_3d_smallintestine1(Scaffold_base): 'ontId': get_smallintestine_term('ileum')[1] }] }), - 'Human 1': ScaffoldPackage(MeshType_1d_path1, { + 'Human 1': ScaffoldPackage(MeshType_1d_network_layout1, { 'scaffoldSettings': { - 'D2 derivatives': True, - 'D3 derivatives': True, - 'Coordinate dimensions': 3, - 'Length': 1.0, - 'Number of elements': 150 + "Structure": "1-2-3-4-5-6-7-8-9-10-11-12-13-14-15-16-17-18-19-20-21-22-23-24-25-26-27-28-29-30-31-32-" + "33-34-35-36-37-38-39-40-41-42-43-44-45-46-47-48-49-50-51-52-53-54-55-56-57-58-59-60-61-" + "62-63-64-65-66-67-68-69-70-71-72-73-74-75-76-77-78-79-80-81-82-83-84-85-86-87-88-89-90-" + "91-92-93-94-95-96-97-98-99-100-101-102-103-104-105-106-107-108-109-110-111-112-113-114-" + "115-116-117-118-119-120-121-122-123-124-125-126-127-128-129-130-131-132-133-134-135-136-" + "137-138-139-140-141-142-143-144-145-146-147-148-149-150-151" }, 'meshEdits': exnode_string_from_nodeset_field_parameters( [ Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3 ], [ @@ -790,15 +810,12 @@ class MeshType_3d_smallintestine1(Scaffold_base): }] }), - 'Mouse 1' : ScaffoldPackage(MeshType_1d_path1, { - 'scaffoldSettings' : { - 'D2 derivatives': True, - 'D3 derivatives': True, - 'Coordinate dimensions' : 3, - 'Length' : 1.0, - 'Number of elements' : 45 - }, - 'meshEdits' : exnode_string_from_nodeset_field_parameters( + 'Mouse 1': ScaffoldPackage(MeshType_1d_network_layout1, { + 'scaffoldSettings': { + "Structure": "1-2-3-4-5-6-7-8-9-10-11-12-13-14-15-16-17-18-19-20-21-22-23-24-25-26-27-28-29-30-31-32-" + "33-34-35-36-37-38-39-40-41-42-43-44-45-46" + }, + 'meshEdits': exnode_string_from_nodeset_field_parameters( [ Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3 ], [ (1, [ [ -2.30, 18.50, -4.40 ], [ -4.20, -0.80, 3.70 ], [ 0.00, 0.60, 0.00 ], [ 0.00, 0.11, 0.00 ], [ -0.33, 0.01, -0.50 ], [ 0.00, 0.00, 0.50 ] ] ), (2, [ [ -8.60, 16.30, -0.40 ], [ -7.10, -2.70, 1.60 ], [ 0.00, 0.73, 0.00 ], [ 0.00, 0.14, 0.00 ], [ 0.08, 0.09, -0.72 ], [ 0.00, 0.00, 0.50 ] ] ), @@ -887,11 +904,11 @@ def getParameterSetNames(): @classmethod def getDefaultOptions(cls, parameterSetName='Default'): if 'Cattle 1' in parameterSetName: - centralPathOption = cls.centralPathDefaultScaffoldPackages['Cattle 1'] + centralPathOption = cls.parameterSetStructureStrings['Cattle 1'] elif 'Mouse 1' in parameterSetName: - centralPathOption = cls.centralPathDefaultScaffoldPackages['Mouse 1'] + centralPathOption = cls.parameterSetStructureStrings['Mouse 1'] else: - centralPathOption = cls.centralPathDefaultScaffoldPackages['Human 1'] + centralPathOption = cls.parameterSetStructureStrings['Human 1'] options = { 'Central path': copy.deepcopy(centralPathOption), 'Number of segments': 80, @@ -942,13 +959,13 @@ def getOrderedOptionNames(): @classmethod def getOptionValidScaffoldTypes(cls, optionName): if optionName == 'Central path': - return [ MeshType_1d_path1 ] + return [ MeshType_1d_network_layout1 ] return [] @classmethod def getOptionScaffoldTypeParameterSetNames(cls, optionName, scaffoldType): if optionName == 'Central path': - return list(cls.centralPathDefaultScaffoldPackages.keys()) + return list(cls.parameterSetStructureStrings.keys()) assert scaffoldType in cls.getOptionValidScaffoldTypes(optionName), \ cls.__name__ + '.getOptionScaffoldTypeParameterSetNames. ' + \ 'Invalid option \'' + optionName + '\' scaffold type ' + scaffoldType.getName() @@ -966,14 +983,14 @@ def getOptionScaffoldPackage(cls, optionName, scaffoldType, parameterSetName=Non ' in option ' + str(optionName) + ' of scaffold ' + cls.getName() if optionName == 'Central path': if not parameterSetName: - parameterSetName = list(cls.centralPathDefaultScaffoldPackages.keys())[0] - return copy.deepcopy(cls.centralPathDefaultScaffoldPackages[parameterSetName]) + parameterSetName = list(cls.parameterSetStructureStrings.keys())[0] + return copy.deepcopy(cls.parameterSetStructureStrings[parameterSetName]) assert False, cls.__name__ + '.getOptionScaffoldPackage: Option ' + optionName + ' is not a scaffold' @classmethod def checkOptions(cls, options): if not options['Central path'].getScaffoldType() in cls.getOptionValidScaffoldTypes('Central path'): - options['Central path'] = cls.getOptionScaffoldPackage('Central path', MeshType_1d_path1) + options['Central path'] = cls.getOptionScaffoldPackage('Central path', MeshType_1d_network_layout1) for key in [ 'Number of segments', 'Number of elements around', diff --git a/tests/test_cecum.py b/tests/test_cecum.py index ccc06d8d..aed9c5dc 100644 --- a/tests/test_cecum.py +++ b/tests/test_cecum.py @@ -22,8 +22,8 @@ def test_cecum1(self): Test creation of cecum scaffold. """ parameterSetNames = MeshType_3d_cecum1.getParameterSetNames() - self.assertEqual(parameterSetNames, ["Default", "Human 1", "Human 2", "Human 3", "Pig 1"]) - options = MeshType_3d_cecum1.getDefaultOptions("Human 3") + self.assertEqual(parameterSetNames, ["Default", "Human 1", "Human 2", "Pig 1"]) + options = MeshType_3d_cecum1.getDefaultOptions("Human 2") centralPath = options.get("Central path") centralPathSettings = centralPath.getScaffoldSettings() @@ -59,9 +59,9 @@ def test_cecum1(self): mesh2d = fieldmodule.findMeshByDimension(2) self.assertEqual(1164, mesh2d.getSize()) mesh1d = fieldmodule.findMeshByDimension(1) - self.assertEqual(1412, mesh1d.getSize()) + self.assertEqual(1408, mesh1d.getSize()) nodes = fieldmodule.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES) - self.assertEqual(558, nodes.getSize()) + self.assertEqual(552, nodes.getSize()) datapoints = fieldmodule.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_DATAPOINTS) self.assertEqual(0, datapoints.getSize()) diff --git a/tests/test_colon.py b/tests/test_colon.py index 969a4d03..7afdfa75 100644 --- a/tests/test_colon.py +++ b/tests/test_colon.py @@ -9,7 +9,7 @@ from cmlibs.zinc.node import Node from cmlibs.zinc.result import RESULT_OK from scaffoldmaker.annotation.colon_terms import get_colon_term -from scaffoldmaker.meshtypes.meshtype_1d_path1 import MeshType_1d_path1 +from scaffoldmaker.meshtypes.meshtype_1d_network_layout1 import MeshType_1d_network_layout1 from scaffoldmaker.meshtypes.meshtype_3d_colon1 import MeshType_3d_colon1 from scaffoldmaker.meshtypes.meshtype_3d_colonsegment1 import MeshType_3d_colonsegment1 from scaffoldmaker.scaffoldpackage import ScaffoldPackage @@ -29,14 +29,10 @@ def test_colon1(self): self.assertEqual(parameterSetNames, ["Default", "Cattle 1", "Human 1", "Human 2", "Human 3", "Mouse 1", "Mouse 2", "Pig 1"]) - centralPathDefaultScaffoldPackages = { - 'Test line': ScaffoldPackage(MeshType_1d_path1, { + parameterSetStructureStrings = { + 'Test line': ScaffoldPackage(MeshType_1d_network_layout1, { 'scaffoldSettings': { - 'Coordinate dimensions': 3, - 'D2 derivatives': True, - 'D3 derivatives': True, - 'Length': 1.0, - 'Number of elements': 3 + "Structure": "1-2-3-4" }, 'meshEdits': exnode_string_from_nodeset_field_parameters( [ Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ @@ -69,7 +65,7 @@ def test_colon1(self): }] }) } - centralPathOption = centralPathDefaultScaffoldPackages['Test line'] + centralPathOption = parameterSetStructureStrings['Test line'] segmentProfileOption = ScaffoldPackage(MeshType_3d_colonsegment1, defaultParameterSetName='Human 1') options = { 'Central path': copy.deepcopy(centralPathOption), diff --git a/tests/test_smallintestine.py b/tests/test_smallintestine.py index 9320fe22..300ef542 100644 --- a/tests/test_smallintestine.py +++ b/tests/test_smallintestine.py @@ -9,7 +9,7 @@ from cmlibs.zinc.node import Node from cmlibs.zinc.result import RESULT_OK from scaffoldmaker.annotation.smallintestine_terms import get_smallintestine_term -from scaffoldmaker.meshtypes.meshtype_1d_path1 import MeshType_1d_path1 +from scaffoldmaker.meshtypes.meshtype_1d_network_layout1 import MeshType_1d_network_layout1 from scaffoldmaker.meshtypes.meshtype_3d_smallintestine1 import MeshType_3d_smallintestine1 from scaffoldmaker.scaffoldpackage import ScaffoldPackage from scaffoldmaker.utils.zinc_utils import createFaceMeshGroupExteriorOnFace, \ @@ -25,14 +25,10 @@ def test_smallintestine1(self): """ parameterSetNames = MeshType_3d_smallintestine1.getParameterSetNames() self.assertEqual(parameterSetNames, ["Default", "Cattle 1", "Human 1", "Mouse 1"]) - centralPathDefaultScaffoldPackages = { - 'Test line': ScaffoldPackage(MeshType_1d_path1, { + parameterSetStructureStrings = { + 'Test line': ScaffoldPackage(MeshType_1d_network_layout1, { 'scaffoldSettings': { - 'D2 derivatives': True, - 'D3 derivatives': True, - 'Coordinate dimensions': 3, - 'Length': 1.0, - 'Number of elements': 3 + "Structure": "1-2-3-4" }, 'meshEdits': exnode_string_from_nodeset_field_parameters( [ Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3 ], [ @@ -65,7 +61,7 @@ def test_smallintestine1(self): }] }) } - centralPathOption = centralPathDefaultScaffoldPackages['Test line'] + centralPathOption = parameterSetStructureStrings['Test line'] options = MeshType_3d_smallintestine1.getDefaultOptions("Mouse 1") options['Central path'] = copy.deepcopy(centralPathOption) options['Number of segments'] = 3 From 132823d6b30caabd42efdaab220c93f84f3fe288 Mon Sep 17 00:00:00 2001 From: mlin865 Date: Tue, 18 Jul 2023 17:36:33 +1200 Subject: [PATCH 10/24] Update stomach to use 1D network layout --- .../meshtypes/meshtype_3d_cecum1.py | 2 +- .../meshtypes/meshtype_3d_stomach1.py | 106 ++++++++---------- 2 files changed, 47 insertions(+), 61 deletions(-) diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_cecum1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_cecum1.py index f0763a48..ea5c5a40 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_cecum1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_cecum1.py @@ -1939,7 +1939,7 @@ def __init__(self, region, centralPath, termsAlong=[None]): :param centralPath: Central path subscaffold from meshtype_1d_path1 :param termsAlong: Annotation terms along length of central path """ - # Extract length of each group along stomach from central path + # Extract length of each group along cecum from central path arcLengthOfGroupsAlong = [] cxGroups = [] cd1Groups = [] diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py index 41be71f0..d314a5df 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py @@ -20,7 +20,7 @@ from scaffoldmaker.annotation.esophagus_terms import get_esophagus_term from scaffoldmaker.annotation.smallintestine_terms import get_smallintestine_term from scaffoldmaker.annotation.stomach_terms import get_stomach_term -from scaffoldmaker.meshtypes.meshtype_1d_path1 import MeshType_1d_path1 +from scaffoldmaker.meshtypes.meshtype_1d_network_layout1 import MeshType_1d_network_layout1 from scaffoldmaker.meshtypes.meshtype_3d_ostium1 import MeshType_3d_ostium1, generateOstiumMesh from scaffoldmaker.meshtypes.scaffold_base import Scaffold_base from scaffoldmaker.scaffoldpackage import ScaffoldPackage @@ -34,7 +34,8 @@ from scaffoldmaker.utils.geometry import sampleEllipsePoints from scaffoldmaker.utils.tracksurface import TrackSurface from scaffoldmaker.utils.zinc_utils import exnode_string_from_nodeset_field_parameters, \ - mesh_destroy_elements_and_nodes_by_identifiers, get_nodeset_path_field_parameters + mesh_destroy_elements_and_nodes_by_identifiers, get_nodeset_path_field_parameters, \ + get_nodeset_path_ordered_field_parameters class MeshType_3d_stomach1(Scaffold_base): @@ -44,14 +45,10 @@ class MeshType_3d_stomach1(Scaffold_base): of the stomach. D2 of the central path points to the greater curvature of the stomach and magnitude of D2 and D3 are the radii of the stomach in the respective direction. """ - centralPathDefaultScaffoldPackages = { - 'Human 1': ScaffoldPackage(MeshType_1d_path1, { + parameterSetStructureStrings = { + 'Human 1': ScaffoldPackage(MeshType_1d_network_layout1, { 'scaffoldSettings': { - 'Coordinate dimensions': 3, - 'D2 derivatives': True, - 'D3 derivatives': True, - 'Length': 1.0, - 'Number of elements': 7 + "Structure": "1-2-3-4-5-6-7-8" }, 'meshEdits': exnode_string_from_nodeset_field_parameters( [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ @@ -102,24 +99,23 @@ class MeshType_3d_stomach1(Scaffold_base): 'ontId': get_smallintestine_term('duodenum')[1] }] }), - 'Human 2': ScaffoldPackage(MeshType_1d_path1, { + + 'Human 2': ScaffoldPackage(MeshType_1d_network_layout1, { 'scaffoldSettings': { - 'Coordinate dimensions': 3, - 'D2 derivatives': True, - 'D3 derivatives': True, - 'Length': 1.0, - 'Number of elements': 7 + "Structure": "1-2-3.2, 4-3-5-6-7-8-9-10" }, 'meshEdits': exnode_string_from_nodeset_field_parameters( [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ - (1, [ [ 61.47, -101.30, 1152.18 ], [ 1.92, -17.01, -22.36 ], [ 15.88, -0.53, 2.00 ], [ -1.47, -0.53, -7.23 ], [ -4.20, -32.38, 24.81 ], [ 1.62, -4.46, 0.00 ] ] ), - (2, [ [ 61.43, -121.54, 1122.53 ], [ -2.01, -23.41, -36.85 ], [ 39.29, -6.83, 2.36 ], [ -7.43, -2.71, -11.05 ], [ -7.56, -35.47, 23.07 ], [ 0.31, -0.85, 0.00 ] ] ), - (3, [ [ 56.78, -147.38, 1078.66 ], [ -18.57, -19.78, -33.63 ], [ 37.34, -13.52, -12.67 ], [ -13.50, -4.91, -7.49 ], [ -4.91, -35.87, 23.81 ], [ -1.83, 5.03, 0.00 ] ] ), - (4, [ [ 32.14, -159.44, 1058.12 ], [ -25.49, -7.02, -11.18 ], [ 12.92, -15.68, -19.60 ], [ -13.60, -4.95, -0.11 ], [ -1.59, -27.21, 20.72 ], [ -3.42, 9.40, 0.00 ] ] ), - (5, [ [ 10.36, -162.05, 1054.83 ], [ -21.12, 0.81, -0.05 ], [ -0.49, -14.00, -17.23 ], [ -8.70, -3.17, 5.66 ], [ -0.74, -18.17, 14.78 ], [ -2.45, 6.74, 0.00 ] ] ), - (6, [ [ -8.74, -158.28, 1057.63 ], [ -14.76, 6.59, 2.22 ], [ -6.11, -10.23, -10.22 ], [ -2.39, 4.12, 5.11 ], [ -3.26, -12.00, 13.95 ], [ -1.56, 6.63, -3.36 ] ] ), - (7, [ [ -18.83, -150.69, 1059.20 ], [ -11.47, 11.36, 1.06 ], [ -6.41, -5.88, -6.34 ], [ -0.18, 2.75, 2.61 ], [ -4.20, -5.07, 8.95 ], [ -1.21, 4.57, -2.38 ] ] ), - (8, [ [ -30.74, -135.24, 1059.32 ], [ -10.69, 13.10, -0.80 ], [ -6.40, -5.57, -5.67 ], [ 1.20, -0.04, -0.56 ], [ -5.80, -4.09, 10.56 ], [ 0.50, 1.74, -3.24 ] ] ) ] ), + (1, [[8.00,-110.19,1129.24], [5.59,-4.49,-11.63], [3.50,-0.38,1.83], [-7.43,-2.71,-11.05], [-1.20,-4.84,1.29], [0.31,-0.85,0.00]]), + (2, [[25.31,-116.23,1119.25], [27.85,-6.64,-5.89], [3.77,6.09,10.97], [-7.43,-2.71,-11.05], [-1.34,-11.88,7.06], [0.31,-0.85,0.00]]), + (3, [[61.43,-121.54,1122.53], [[-2.01,-23.40,-36.85],[42.96,-3.86,12.04]], [[39.28,-6.90,2.24],[-2.29,6.36,10.19]], [[-7.43,-2.71,-11.05],[0.00,0.00,0.00]], [[-7.56,-35.53,22.98],[-2.98,-11.98,6.81]], [[0.31,-0.85,0.00],[0.00,0.00,0.00]]]), + (4, [ [ 61.47, -101.30, 1152.18 ], [ 1.92, -17.01, -22.36 ], [ 15.88, -0.53, 2.00 ], [ -1.47, -0.53, -7.23 ], [ -4.20, -32.38, 24.81 ], [ 1.62, -4.46, 0.00 ] ] ), + (5, [ [ 56.78, -147.38, 1078.66 ], [ -18.57, -19.78, -33.63 ], [ 37.34, -13.52, -12.67 ], [ -13.50, -4.91, -7.49 ], [ -4.91, -35.87, 23.81 ], [ -1.83, 5.03, 0.00 ] ] ), + (6, [ [ 32.14, -159.44, 1058.12 ], [ -25.49, -7.02, -11.18 ], [ 12.92, -15.68, -19.60 ], [ -13.60, -4.95, -0.11 ], [ -1.59, -27.21, 20.72 ], [ -3.42, 9.40, 0.00 ] ] ), + (7, [ [ 10.36, -162.05, 1054.83 ], [ -21.12, 0.81, -0.05 ], [ -0.49, -14.00, -17.23 ], [ -8.70, -3.17, 5.66 ], [ -0.74, -18.17, 14.78 ], [ -2.45, 6.74, 0.00 ] ] ), + (8, [ [ -8.74, -158.28, 1057.63 ], [ -14.76, 6.59, 2.22 ], [ -6.11, -10.23, -10.22 ], [ -2.39, 4.12, 5.11 ], [ -3.26, -12.00, 13.95 ], [ -1.56, 6.63, -3.36 ] ] ), + (9, [ [ -18.83, -150.69, 1059.20 ], [ -11.47, 11.36, 1.06 ], [ -6.41, -5.88, -6.34 ], [ -0.18, 2.75, 2.61 ], [ -4.20, -5.07, 8.95 ], [ -1.21, 4.57, -2.38 ] ] ), + (10, [ [ -30.74, -135.24, 1059.32 ], [ -10.69, 13.10, -0.80 ], [ -6.40, -5.57, -5.67 ], [ 1.20, -0.04, -0.56 ], [ -5.80, -4.09, 10.56 ], [ 0.50, 1.74, -3.24 ] ] ) ] ), 'userAnnotationGroups': [ { @@ -158,13 +154,10 @@ class MeshType_3d_stomach1(Scaffold_base): 'ontId': get_smallintestine_term('duodenum')[1] }] }), - 'Mouse 1': ScaffoldPackage(MeshType_1d_path1, { + + 'Mouse 1': ScaffoldPackage(MeshType_1d_network_layout1, { 'scaffoldSettings': { - 'Coordinate dimensions': 3, - 'D2 derivatives': True, - 'D3 derivatives': True, - 'Length': 1.0, - 'Number of elements': 8 + "Structure": "1-2-3-4-5-6-7-8-9" }, 'meshEdits': exnode_string_from_nodeset_field_parameters( [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, @@ -217,13 +210,10 @@ class MeshType_3d_stomach1(Scaffold_base): 'ontId': get_smallintestine_term('duodenum')[1] }] }), - 'Pig 1': ScaffoldPackage(MeshType_1d_path1, { + + 'Pig 1': ScaffoldPackage(MeshType_1d_network_layout1, { 'scaffoldSettings': { - 'Coordinate dimensions': 3, - 'D2 derivatives': True, - 'D3 derivatives': True, - 'Length': 1.0, - 'Number of elements': 7 + "Structure": "1-2-3-4-5-6-7-8" }, 'meshEdits': exnode_string_from_nodeset_field_parameters( [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ @@ -274,13 +264,10 @@ class MeshType_3d_stomach1(Scaffold_base): 'ontId': get_smallintestine_term('duodenum')[1] }] }), - 'Rat 1': ScaffoldPackage(MeshType_1d_path1, { + + 'Rat 1': ScaffoldPackage(MeshType_1d_network_layout1, { 'scaffoldSettings': { - 'Coordinate dimensions': 3, - 'D2 derivatives': True, - 'D3 derivatives': True, - 'Length': 1.0, - 'Number of elements': 8 + "Structure": "1-2-3-4-5-6-7-8-9" }, 'meshEdits': exnode_string_from_nodeset_field_parameters( [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ @@ -332,13 +319,10 @@ class MeshType_3d_stomach1(Scaffold_base): 'ontId': get_smallintestine_term('duodenum')[1] }] }), - 'Material': ScaffoldPackage(MeshType_1d_path1, { + + 'Material': ScaffoldPackage(MeshType_1d_network_layout1, { 'scaffoldSettings': { - 'Coordinate dimensions': 3, - 'D2 derivatives': True, - 'D3 derivatives': True, - 'Length': 1.0, - 'Number of elements': 7 + "Structure": "1-2-3-4-5-6-7-8" }, 'meshEdits': exnode_string_from_nodeset_field_parameters( [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ @@ -598,22 +582,22 @@ def getParameterSetNames(): @classmethod def getDefaultOptions(cls, parameterSetName='Default'): if 'Human 2' in parameterSetName: - centralPathOption = cls.centralPathDefaultScaffoldPackages['Human 2'] + centralPathOption = cls.parameterSetStructureStrings['Human 2'] ostiumOption = cls.ostiumDefaultScaffoldPackages['Human 2'] elif 'Mouse 1' in parameterSetName: - centralPathOption = cls.centralPathDefaultScaffoldPackages['Mouse 1'] + centralPathOption = cls.parameterSetStructureStrings['Mouse 1'] ostiumOption = cls.ostiumDefaultScaffoldPackages['Mouse 1'] elif 'Pig 1' in parameterSetName: - centralPathOption = cls.centralPathDefaultScaffoldPackages['Pig 1'] + centralPathOption = cls.parameterSetStructureStrings['Pig 1'] ostiumOption = cls.ostiumDefaultScaffoldPackages['Pig 1'] elif 'Rat 1' in parameterSetName: - centralPathOption = cls.centralPathDefaultScaffoldPackages['Rat 1'] + centralPathOption = cls.parameterSetStructureStrings['Rat 1'] ostiumOption = cls.ostiumDefaultScaffoldPackages['Rat 1'] elif 'Material' in parameterSetName: - centralPathOption = cls.centralPathDefaultScaffoldPackages['Material'] + centralPathOption = cls.parameterSetStructureStrings['Material'] ostiumOption = cls.ostiumDefaultScaffoldPackages['Material'] else: - centralPathOption = cls.centralPathDefaultScaffoldPackages['Human 1'] + centralPathOption = cls.parameterSetStructureStrings['Human 1'] ostiumOption = cls.ostiumDefaultScaffoldPackages['Human 1'] options = { @@ -704,7 +688,7 @@ def getOrderedOptionNames(): @classmethod def getOptionValidScaffoldTypes(cls, optionName): if optionName == 'Central path': - return [MeshType_1d_path1] + return [MeshType_1d_network_layout1] if optionName == 'Gastro-esophagal junction': return [MeshType_3d_ostium1] return [] @@ -712,7 +696,7 @@ def getOptionValidScaffoldTypes(cls, optionName): @classmethod def getOptionScaffoldTypeParameterSetNames(cls, optionName, scaffoldType): if optionName == 'Central path': - return list(cls.centralPathDefaultScaffoldPackages.keys()) + return list(cls.parameterSetStructureStrings.keys()) if optionName == 'Gastro-esophagal junction': return list(cls.ostiumDefaultScaffoldPackages.keys()) assert scaffoldType in cls.getOptionValidScaffoldTypes(optionName), \ @@ -732,8 +716,8 @@ def getOptionScaffoldPackage(cls, optionName, scaffoldType, parameterSetName=Non ' in option ' + str(optionName) + ' of scaffold ' + cls.getName() if optionName == 'Central path': if not parameterSetName: - parameterSetName = list(cls.centralPathDefaultScaffoldPackages.keys())[0] - return copy.deepcopy(cls.centralPathDefaultScaffoldPackages[parameterSetName]) + parameterSetName = list(cls.parameterSetStructureStrings.keys())[0] + return copy.deepcopy(cls.parameterSetStructureStrings[parameterSetName]) if optionName == 'Gastro-esophagal junction': if not parameterSetName: parameterSetName = list(cls.ostiumDefaultScaffoldPackages.keys())[0] @@ -743,7 +727,7 @@ def getOptionScaffoldPackage(cls, optionName, scaffoldType, parameterSetName=Non @classmethod def checkOptions(cls, options): if not options['Central path'].getScaffoldType() in cls.getOptionValidScaffoldTypes('Central path'): - options['Central path'] = cls.getOptionScaffoldPackage('Central path', MeshType_1d_path1) + options['Central path'] = cls.getOptionScaffoldPackage('Central path', MeshType_1d_network_layout1) if not options['Gastro-esophagal junction'].getScaffoldType() in cls.getOptionValidScaffoldTypes( 'Gastro-esophagal junction'): options['Gastro-esophagal junction'] = cls.getOptionScaffoldPackage('Gastro-esophagal junction', @@ -799,7 +783,7 @@ def generateBaseMesh(cls, region, options): """ cls.updateSubScaffoldOptions(options) geometricCentralPath = options['Central path'] - materialCentralPath = cls.centralPathDefaultScaffoldPackages['Material'] + materialCentralPath = cls.parameterSetStructureStrings['Material'] limitingRidge = options['Limiting ridge'] elementsCountThroughWall = options['Number of elements through wall'] allAnnotationGroups = [] @@ -1170,7 +1154,7 @@ class StomachCentralPath: def __init__(self, region, centralPath, stomachTermsAlong=[None]): """ :param region: Zinc region to define model in. - :param centralPath: Central path subscaffold from meshtype_1d_path1 + :param centralPath: Central path subscaffold from meshtype_1d_network_layout1 :param stomachTermsAlong: Annotation terms along length of stomach """ # Extract length of each group along stomach from central path @@ -1187,6 +1171,8 @@ def __init__(self, region, centralPath, stomachTermsAlong=[None]): tmpFieldmodule = tmpRegion.getFieldmodule() tmpNodes = tmpFieldmodule.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES) tmpCoordinates = tmpFieldmodule.findFieldByName('coordinates') + pathNetworkMesh = centralPath.getConstructionObject() + networkSegments = pathNetworkMesh.getNetworkSegments() for termName in stomachTermsAlong: tmpGroup = tmpFieldmodule.findFieldByName(termName).castGroup() if termName else None From 9ad2d0c1baa9c65cd2e60958ec2de2e1c1207166 Mon Sep 17 00:00:00 2001 From: mlin865 Date: Fri, 21 Jul 2023 16:25:40 +1200 Subject: [PATCH 11/24] Use network layout for ostium central path --- .../meshtypes/meshtype_3d_ostium2.py | 154 ++++++------------ 1 file changed, 54 insertions(+), 100 deletions(-) diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_ostium2.py b/src/scaffoldmaker/meshtypes/meshtype_3d_ostium2.py index c9c98f16..bc155589 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_ostium2.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_ostium2.py @@ -11,17 +11,18 @@ from cmlibs.zinc.element import Element, Elementbasis from cmlibs.zinc.field import Field from cmlibs.zinc.node import Node -from scaffoldmaker.meshtypes.meshtype_1d_path1 import MeshType_1d_path1 +from scaffoldmaker.meshtypes.meshtype_1d_network_layout1 import MeshType_1d_network_layout1 from scaffoldmaker.meshtypes.scaffold_base import Scaffold_base from scaffoldmaker.scaffoldpackage import ScaffoldPackage from scaffoldmaker.utils import interpolation as interp from scaffoldmaker.utils import vector from scaffoldmaker.utils.annulusmesh import createAnnulusMesh3d from scaffoldmaker.utils.eftfactory_tricubichermite import eftfactory_tricubichermite -from scaffoldmaker.utils.geometry import createCirclePoints, getCircleProjectionAxes +from scaffoldmaker.utils.geometry import createCirclePoints from scaffoldmaker.utils.meshrefinement import MeshRefinement -from scaffoldmaker.utils.tracksurface import TrackSurface, TrackSurfacePosition, calculate_surface_axes -from scaffoldmaker.utils.zinc_utils import exnode_string_from_nodeset_field_parameters, get_nodeset_path_field_parameters +from scaffoldmaker.utils.tracksurface import TrackSurface, calculate_surface_axes +from scaffoldmaker.utils.zinc_utils import exnode_string_from_nodeset_field_parameters, \ + get_nodeset_path_field_parameters @@ -29,14 +30,10 @@ class MeshType_3d_ostium2(Scaffold_base): """ Generates a 3-D single or double/common ostium inlet or outlet. """ - centralPathDefaultScaffoldPackages = { - 'Default': ScaffoldPackage(MeshType_1d_path1, { + parameterSetStructureStrings = { + 'Default': ScaffoldPackage(MeshType_1d_network_layout1, { 'scaffoldSettings': { - 'Coordinate dimensions': 3, - 'D2 derivatives': True, - 'D3 derivatives': True, - 'Length': 1.0, - 'Number of elements': 2 + "Structure": "1-2-3" }, 'meshEdits': exnode_string_from_nodeset_field_parameters( [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ @@ -52,30 +49,23 @@ def getName(): @classmethod def getDefaultOptions(cls, parameterSetName='Default'): - centralPathOption = cls.centralPathDefaultScaffoldPackages['Default'] + centralPathOption = cls.parameterSetStructureStrings['Default'] options = { 'Central path': copy.deepcopy(centralPathOption), # 'Number of vessels': 1, # 'Number of elements across common': 2, 'Number of elements around ostium': 8, - 'Number of elements along': 2, #1, + 'Number of elements along': 2, 'Number of elements through wall': 1, 'Unit scale': 1.0, 'Outlet': False, - # 'Ostium diameter': 1.0, - # 'Ostium length': 0.4, 'Ostium wall thickness': 0.08, 'Ostium wall relative thicknesses': [1.0], # 'Ostium inter-vessel distance': 0.8, # 'Ostium inter-vessel height': 0.0, 'Use linear through ostium wall': False, - # 'Vessel end length factor': 1.0, - # 'Vessel inner diameter': 0.6, 'Vessel wall thickness': 0.04, 'Vessel wall relative thicknesses': [1.0], - # 'Vessel angle 1 degrees': 0.0, - # 'Vessel angle 1 spread degrees': 0.0, - # 'Vessel angle 2 degrees': 0.0, 'Use linear through vessel wall': True, # 'Use cross derivatives': False, 'Refine': False, @@ -97,20 +87,13 @@ def getOrderedOptionNames(): 'Number of elements through wall', 'Unit scale', 'Outlet', - # 'Ostium diameter', - # 'Ostium length', 'Ostium wall thickness', 'Ostium wall relative thicknesses', # 'Ostium inter-vessel distance', # 'Ostium inter-vessel height', 'Use linear through ostium wall', - # 'Vessel end length factor', - # 'Vessel inner diameter', 'Vessel wall thickness', 'Vessel wall relative thicknesses', - # 'Vessel angle 1 degrees', - # 'Vessel angle 1 spread degrees', - # 'Vessel angle 2 degrees', 'Use linear through vessel wall', # 'Use cross derivatives', # not implemented 'Refine', @@ -122,12 +105,12 @@ def getOrderedOptionNames(): @classmethod def getOptionValidScaffoldTypes(cls, optionName): if optionName == 'Central path': - return [MeshType_1d_path1] + return [MeshType_1d_network_layout1] @classmethod def getOptionScaffoldTypeParameterSetNames(cls, optionName, scaffoldType): if optionName == 'Central path': - return list(cls.centralPathDefaultScaffoldPackages.keys()) + return list(cls.parameterSetStructureStrings.keys()) assert scaffoldType in cls.getOptionValidScaffoldTypes(optionName), \ cls.__name__ + '.getOptionScaffoldTypeParameterSetNames. ' + \ 'Invalid option \'' + optionName + '\' scaffold type ' + scaffoldType.getName() @@ -145,15 +128,15 @@ def getOptionScaffoldPackage(cls, optionName, scaffoldType, parameterSetName=Non ' in option ' + str(optionName) + ' of scaffold ' + cls.getName() if optionName == 'Central path': if not parameterSetName: - parameterSetName = list(cls.centralPathDefaultScaffoldPackages.keys())[0] - return copy.deepcopy(cls.centralPathDefaultScaffoldPackages[parameterSetName]) + parameterSetName = list(cls.parameterSetStructureStrings.keys())[0] + return copy.deepcopy(cls.parameterSetStructureStrings[parameterSetName]) assert False, cls.__name__ + '.getOptionScaffoldPackage: Option ' + optionName + ' is not a scaffold' @classmethod def checkOptions(cls, options): dependentChanges = False if not options['Central path'].getScaffoldType() in cls.getOptionValidScaffoldTypes('Central path'): - options['Central path'] = cls.getOptionScaffoldPackage('Central path', MeshType_1d_path1) + options['Central path'] = cls.getOptionScaffoldPackage('Central path', MeshType_1d_network_layout1) # vesselsCount = options['Number of vessels'] # if vesselsCount != 1: # vesselsCount = options['Number of vessels'] = 1 @@ -175,15 +158,11 @@ def checkOptions(cls, options): # dependentChanges = True # because can happen by changing number of vessels for key in [ 'Unit scale', - # 'Ostium length', 'Ostium wall thickness', # 'Ostium inter-vessel distance', - # 'Vessel inner diameter', 'Vessel wall thickness']: if options[key] < 0.0: options[key] = 0.0 - # if options['Ostium diameter'] <= 0.0: - # options['Ostium diameter'] = 0.000001 # avoid division by zero elementsThroughWall = options['Number of elements through wall'] ostiumThicknessProportionsCountKey = 'Ostium wall relative thicknesses' vesselThicknessProportionsCountKey = 'Vessel wall relative thicknesses' @@ -221,7 +200,6 @@ def generateBaseMesh(cls, region, options): centralPath = options['Central path'] centralPath = CentralPath(region, centralPath, unitScale) - # ostiumRadius = 0.5 * unitScale * options['Ostium diameter'] # interVesselDistance = unitScale * options['Ostium inter-vessel distance'] ox = centralPath.cxPath[-1] od2 = centralPath.cd2Path[-1] @@ -240,40 +218,8 @@ def generateBaseMesh(cls, region, options): nd1 = [vector.setMagnitude(od3, 2.0 * scale)] * 4 nd2 = [vector.setMagnitude(od2, 2.0 * scale)] * 4 - # fm = region.getFieldmodule() - # fm.beginChange() - # cache = fm.createFieldcache() - # coordinates = findOrCreateFieldCoordinates(fm) - # - # nodes = fm.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES) - # nodeIdentifier = 1000 - # - # nodetemplate = nodes.createNodetemplate() - # nodetemplate.defineField(coordinates) - # nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_VALUE, 1) - # nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D_DS1, 1) - # nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D_DS2, 1) - # nodetemplate.setValueNumberOfVersions(coordinates, -1, Node.VALUE_LABEL_D_DS3, 1) - # - # for n1 in range(len(nx)): - # node = nodes.createNode(nodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, nx[n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, nd1[n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, nd2[n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, [0.0, 0.0, 0.0]) - # nodeIdentifier += 1 - - # # curve track surface: - # zf = 2.0 - # nd1 = [ [ 2.0 * scale, 0.0, zf * scale ], [ 2.0 * scale, 0.0, -zf * scale ], - # [ 2.0 * scale, 0.0, zf * scale ], [ 2.0 * scale, 0.0, -zf * scale ] ] - # nd2 = [ [ 0.0, 2.0 * scale, zf * scale ], [ 0.0, 2.0 * scale, zf * scale ], - # [ 0.0, 2.0 * scale, -zf * scale ], [ 0.0, 2.0 * scale, -zf * scale ] ] trackSurface = TrackSurface(1, 1, nx, nd1, nd2) - # centrePosition = TrackSurfacePosition(0, 0, 0.5, 0.5) - # axis1 = [1.0, 0.0, 0.0] - generateOstiumMesh(region, options, trackSurface, centralPath) #centrePosition, axis1) + generateOstiumMesh(region, options, trackSurface, centralPath) return [], None @classmethod @@ -324,9 +270,8 @@ def getOstiumElementsCountsAroundVessels(elementsCountAroundOstium, elementsCoun return [countOuter, countInner, countOuter], elementsCountAroundMid -def generateOstiumMesh(region, options, trackSurface, centralPath, startNodeIdentifier=1, - startElementIdentifier=1, vesselMeshGroups=None, ostiumMeshGroups=None, - wallAnnotationGroups=None, coordinates=None): +def generateOstiumMesh(region, options, trackSurface, centralPath, startNodeIdentifier=1, startElementIdentifier=1, + vesselMeshGroups=None, ostiumMeshGroups=None, wallAnnotationGroups=None, coordinates=None): """ :param vesselMeshGroups: List (over number of vessels) of list of mesh groups to add vessel elements to. :param ostiumMeshGroups: List of mesh groups to add only row of elements at ostium end to. @@ -351,27 +296,17 @@ def generateOstiumMesh(region, options, trackSurface, centralPath, startNodeIden unitScale = options['Unit scale'] isOutlet = options['Outlet'] - # ostiumRadius = 0.5 * unitScale * options['Ostium diameter'] - # ostiumLength = unitScale * options['Ostium length'] ostiumWallThickness = unitScale * options['Ostium wall thickness'] ostiumWallThicknessProportionsUI = copy.deepcopy(options['Ostium wall relative thicknesses']) # interVesselHeight = unitScale * options['Ostium inter-vessel height'] # interVesselDistance = unitScale * options['Ostium inter-vessel distance'] if (vesselsCount > 1) else 0.0 # halfInterVesselDistance = 0.5 * interVesselDistance useCubicHermiteThroughOstiumWall = not(options['Use linear through ostium wall']) - # vesselEndDerivative = ostiumLength * options['Vessel end length factor'] / elementsCountAlong - # vesselInnerRadius = 0.5 * unitScale * options['Vessel inner diameter'] vesselWallThickness = unitScale * options['Vessel wall thickness'] vesselWallThicknessProportionsUI = copy.deepcopy(options['Vessel wall relative thicknesses']) - # vesselOuterRadius = vesselInnerRadius + vesselWallThickness - # vesselAngle1Radians = math.radians(options['Vessel angle 1 degrees']) - # vesselAngle1SpreadRadians = math.radians(options['Vessel angle 1 spread degrees']) - # vesselAngle2Radians = math.radians(options['Vessel angle 2 degrees']) useCubicHermiteThroughVesselWall = not(options['Use linear through vessel wall']) useCrossDerivatives = False # options['Use cross derivatives'] # not implemented - ostiumRadius = vector.magnitude(centralPath.cd2Path[-1]) - # ostiumD3Radius = vector.magnitude(cd3Path[0]) * unitScale arcLength = 0.0 for e in range(len(centralPath.cxPath) - 1): @@ -407,7 +342,6 @@ def generateOstiumMesh(region, options, trackSurface, centralPath, startNodeIden centrePosition = trackSurface.findNearestPosition(centralPath.cxPath[-1]) cx, cd1, cd2 = trackSurface.evaluateCoordinates(centrePosition, True) trackDirection1, trackDirection2, centreNormal = calculate_surface_axes(cd1, cd2, cd1) - # trackDirection2reverse = [-d for d in trackDirection2] halfCircumference = math.pi * ostiumRadius circumference = 2.0 * halfCircumference @@ -504,7 +438,6 @@ def generateOstiumMesh(region, options, trackSurface, centralPath, startNodeIden # print('5') position = trackSurface.findNearestPosition(xOstiumInner[n1]) - # position = trackSurface.trackVector(position, sideDirection, ostiumRadius) oPositions.append(position) px, d1, d2 = trackSurface.evaluateCoordinates(position, True) angleRadians = 2.0 * math.pi / elementsCountAroundOstium * n1 @@ -1046,7 +979,8 @@ def generateOstiumMesh(region, options, trackSurface, centralPath, startNodeIden maxStartThickness=vesselWallThickness, maxEndThickness=vesselWallThickness, elementsCountRadial=elementsCountAlong, meshGroups=rowMeshGroups, wallAnnotationGroups=wallAnnotationGroups, coordinates=coordinates) - # + + # To visualise central path # nodeIdentifierLine = nodeIdentifier # for n1 in range(len(centralPath.cxPath)): # node = nodes.createNode(nodeIdentifier, nodetemplate ) @@ -1080,21 +1014,41 @@ def __init__(self, region, centralPath, unitScale, termsAlong=[None]): """ :param region: Zinc region to define model in. :param centralPath: Central path subscaffold from meshtype_1d_path1 - :param unitScale: + :param unitScale: Unit scale of ostium :param termsAlong: Annotation terms along length of central path """ - # Extract length of each group along stomach from central path + tmpRegion = region.createRegion() centralPath.generate(tmpRegion) tmpFieldmodule = tmpRegion.getFieldmodule() tmpNodes = tmpFieldmodule.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES) tmpCoordinates = tmpFieldmodule.findFieldByName('coordinates') - cxPath, cd1Path, cd2Path, cd3Path, cd12Path, cd13Path = \ - get_nodeset_path_field_parameters(tmpNodes, tmpCoordinates, - [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]) + for termName in termsAlong: + tmpGroup = tmpFieldmodule.findFieldByName(termName).castGroup() if termName else None + tmpNodeset = tmpGroup.getNodesetGroup(tmpNodes) if tmpGroup else tmpNodes + + cxGroup, cd1Group, cd2Group, cd3Group, cd12Group, cd13Group = get_nodeset_path_field_parameters( + tmpNodeset, tmpCoordinates, + [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]) + + if not termName: + cx = cxGroup + cd1 = cd1Group + cd2 = cd2Group + cd3 = cd3Group + cd12 = cd12Group + cd13 = cd13Group + + del tmpNodeset + del tmpGroup + + del tmpCoordinates + del tmpNodes + del tmpFieldmodule + del tmpRegion self.cxPath = [] self.cd1Path = [] @@ -1103,10 +1057,10 @@ def __init__(self, region, centralPath, unitScale, termsAlong=[None]): self.cd12Path = [] self.cd13Path = [] - for i in range(len(cxPath)): - self.cxPath.append([unitScale * x for x in cxPath[i]]) - self.cd1Path.append([unitScale * cd1 for cd1 in cd1Path[i]]) - self.cd2Path.append([unitScale * cd2 for cd2 in cd2Path[i]]) - self.cd3Path.append([unitScale * cd3 for cd3 in cd3Path[i]]) - self.cd12Path.append([unitScale * cd12 for cd12 in cd12Path[i]]) - self.cd13Path.append([unitScale * cd13 for cd13 in cd13Path[i]]) + for i in range(len(cx)): + self.cxPath.append([unitScale * x for x in cx[i]]) + self.cd1Path.append([unitScale * cd1 for cd1 in cd1[i]]) + self.cd2Path.append([unitScale * cd2 for cd2 in cd2[i]]) + self.cd3Path.append([unitScale * cd3 for cd3 in cd3[i]]) + self.cd12Path.append([unitScale * cd12 for cd12 in cd12[i]]) + self.cd13Path.append([unitScale * cd13 for cd13 in cd13[i]]) From 42140f6c5e62aee4194a7cdd8774fd1d080ff2e7 Mon Sep 17 00:00:00 2001 From: mlin865 Date: Mon, 28 Aug 2023 15:12:13 +1200 Subject: [PATCH 12/24] Use d3 on central path to control radius of elliptical ostium --- .../meshtypes/meshtype_3d_ostium2.py | 38 +++++++++++-------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_ostium2.py b/src/scaffoldmaker/meshtypes/meshtype_3d_ostium2.py index bc155589..e1cab127 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_ostium2.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_ostium2.py @@ -18,7 +18,7 @@ from scaffoldmaker.utils import vector from scaffoldmaker.utils.annulusmesh import createAnnulusMesh3d from scaffoldmaker.utils.eftfactory_tricubichermite import eftfactory_tricubichermite -from scaffoldmaker.utils.geometry import createCirclePoints +from scaffoldmaker.utils.geometry import sampleEllipsePoints, getApproximateEllipsePerimeter from scaffoldmaker.utils.meshrefinement import MeshRefinement from scaffoldmaker.utils.tracksurface import TrackSurface, calculate_surface_axes from scaffoldmaker.utils.zinc_utils import exnode_string_from_nodeset_field_parameters, \ @@ -39,7 +39,7 @@ class MeshType_3d_ostium2(Scaffold_base): [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ (1, [[0.00,0.00,1.00], [0.00,0.00,-0.50], [0.00,0.50,0.00], [0.00,0.00,0.00], [1.00,0.00,0.00], [0.00,0.00,0.00]]), (2, [[0.00,0.00,0.50], [0.00,0.00,-0.50], [0.00,1.00,0.00], [0.00,0.00,0.00], [1.00,0.00,0.00], [0.00,0.00,0.00]]), - (3, [[0.00,0.00,0.00], [0.00,0.00,-0.50], [0.00,1.00,0.00], [0.00,0.00,0.00], [1.00,0.00,0.00], [0.00,0.00,0.00]])]) + (3, [[0.00,0.00,0.00], [0.00,0.00,-0.50], [0.00,1.00,0.00], [0.00,0.00,0.00], [2.00,0.00,0.00], [0.00,0.00,0.00]])]) }) } @@ -204,7 +204,7 @@ def generateBaseMesh(cls, region, options): ox = centralPath.cxPath[-1] od2 = centralPath.cd2Path[-1] od3 = centralPath.cd3Path[-1] - scale = 2.0 * vector.magnitude([od2[c] + od3[c] for c in range(3)]) + scale = 4.0 * vector.magnitude([od2[c] + od3[c] for c in range(3)]) nxOffset = [vector.setMagnitude([-od3[c] - od2[c] for c in range(3)], scale), vector.setMagnitude([od3[c] - od2[c] for c in range(3)], scale), @@ -220,6 +220,7 @@ def generateBaseMesh(cls, region, options): trackSurface = TrackSurface(1, 1, nx, nd1, nd2) generateOstiumMesh(region, options, trackSurface, centralPath) + return [], None @classmethod @@ -306,7 +307,7 @@ def generateOstiumMesh(region, options, trackSurface, centralPath, startNodeIden vesselWallThicknessProportionsUI = copy.deepcopy(options['Vessel wall relative thicknesses']) useCubicHermiteThroughVesselWall = not(options['Use linear through vessel wall']) useCrossDerivatives = False # options['Use cross derivatives'] # not implemented - ostiumRadius = vector.magnitude(centralPath.cd2Path[-1]) + # ostiumRadius = vector.magnitude(centralPath.cd2Path[-1]) arcLength = 0.0 for e in range(len(centralPath.cxPath) - 1): @@ -343,14 +344,16 @@ def generateOstiumMesh(region, options, trackSurface, centralPath, startNodeIden cx, cd1, cd2 = trackSurface.evaluateCoordinates(centrePosition, True) trackDirection1, trackDirection2, centreNormal = calculate_surface_axes(cd1, cd2, cd1) - halfCircumference = math.pi * ostiumRadius - circumference = 2.0 * halfCircumference + ellipsePerimeter = getApproximateEllipsePerimeter(vector.magnitude(centralPath.cd2Path[-1]), + vector.magnitude(centralPath.cd3Path[-1])) + # halfCircumference = math.pi * ostiumRadius + # circumference = 2.0 * halfCircumference distance = 0.0 # elementLengthAroundOstiumMid = 0.0 # vesselsSpanAll = interVesselDistance * (vesselsCount - 1) # vesselsSpanMid = interVesselDistance * (vesselsCount - 2) - elementLengthAroundOstiumEnd = circumference / elementsCountAroundOstium + elementLengthAroundOstiumEnd = ellipsePerimeter / elementsCountAroundOstium # if vesselsCount == 1: # elementLengthAroundOstiumEnd = circumference / elementsCountAroundOstium @@ -394,10 +397,10 @@ def generateOstiumMesh(region, options, trackSurface, centralPath, startNodeIden ostiumWallThicknessProportions.append(ostiumWallThicknessProportions[-1]) vesselWallThicknessProportions.append(vesselWallThicknessProportions[-1]) - xOstiumInner, d1OstiumInner = createCirclePoints(centralPath.cxPath[-1], - vector.setMagnitude(centralPath.cd2Path[-1], ostiumRadius), - vector.setMagnitude(centralPath.cd3Path[-1], ostiumRadius), - elementsCountAroundOstium) + xOstiumInner, d1OstiumInner = sampleEllipsePoints(centralPath.cxPath[-1], centralPath.cd2Path[-1], + centralPath.cd3Path[-1], 0.0, 2.0*math.pi, + elementsCountAroundOstium) + del xOstiumInner[-1], d1OstiumInner[-1] for n1 in range(elementsCountAroundOstium): elementLength = elementLengthAroundOstiumEnd @@ -489,7 +492,7 @@ def generateOstiumMesh(region, options, trackSurface, centralPath, startNodeIden od3[n3].append([opd3[c] * ostiumWallThicknessProportions[n3] for c in range(3)]) distance += elementLength for n3 in range(elementsCountThroughWall + 1): - od1[n3] = interp.smoothCubicHermiteDerivativesLoop(ox[n3], od1[n3], fixAllDirections=True) + od1[n3] = interp.smoothCubicHermiteDerivativesLoop(ox[n3], od1[n3]) # for n3 in range(len(ox)): # for n1 in range(len(ox[n3])): @@ -608,9 +611,10 @@ def generateOstiumMesh(region, options, trackSurface, centralPath, startNodeIden vod2.append([]) vod3.append([]) for n3 in range(elementsCountThroughWall + 1): - radius = vector.magnitude(centralPath.cd2Path[0]) + vesselWallThicknessXi3List[n3] * vesselWallThickness - vAxis1 = vector.setMagnitude(centralPath.cd2Path[0], radius) - vAxis2 = vector.setMagnitude(centralPath.cd3Path[0], radius) + radius1 = vector.magnitude(centralPath.cd2Path[0]) + vesselWallThicknessXi3List[n3] * vesselWallThickness + radius2 = vector.magnitude(centralPath.cd3Path[0]) + vesselWallThicknessXi3List[n3] * vesselWallThickness + vAxis1 = vector.setMagnitude(centralPath.cd2Path[0], radius1) + vAxis2 = vector.setMagnitude(centralPath.cd3Path[0], radius2) # print(centralPath.cd2Path[0], centralPath.cd3Path[0]) # if vesselsCount == 1: startRadians = 0.0 # 0.5 * math.pi @@ -618,7 +622,9 @@ def generateOstiumMesh(region, options, trackSurface, centralPath, startNodeIden # startRadians = 0.5 * radiansPerElementVessel * elementsCountAcross # if v == (vesselsCount - 1): # startRadians -= math.pi - px, pd1 = createCirclePoints(centralPath.cxPath[0], vAxis1, vAxis2, elementsCountAroundVessel, startRadians) + px, pd1 = sampleEllipsePoints(centralPath.cxPath[0], vAxis1, vAxis2, 0.0, 2.0 * math.pi, elementsCountAroundVessel) + del px[-1], pd1[-1] + vox[-1].append(px) vod1[-1].append(pd1) vesselEndDerivative = vector.setMagnitude(centralPath.cd1Path[0], arcLength/elementsCountAlong) From 5e8c274e2b5054c8cb372e4b84893a7c4574b48e Mon Sep 17 00:00:00 2001 From: mlin865 Date: Mon, 28 Aug 2023 17:10:46 +1200 Subject: [PATCH 13/24] Make d2 and d3 to outer surface of ostium2 --- src/scaffoldmaker/meshtypes/meshtype_3d_ostium2.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_ostium2.py b/src/scaffoldmaker/meshtypes/meshtype_3d_ostium2.py index e1cab127..22928a38 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_ostium2.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_ostium2.py @@ -397,10 +397,10 @@ def generateOstiumMesh(region, options, trackSurface, centralPath, startNodeIden ostiumWallThicknessProportions.append(ostiumWallThicknessProportions[-1]) vesselWallThicknessProportions.append(vesselWallThicknessProportions[-1]) - xOstiumInner, d1OstiumInner = sampleEllipsePoints(centralPath.cxPath[-1], centralPath.cd2Path[-1], + xOstiumOuter, d1OstiumOuter = sampleEllipsePoints(centralPath.cxPath[-1], centralPath.cd2Path[-1], centralPath.cd3Path[-1], 0.0, 2.0*math.pi, elementsCountAroundOstium) - del xOstiumInner[-1], d1OstiumInner[-1] + del xOstiumOuter[-1], d1OstiumOuter[-1] for n1 in range(elementsCountAroundOstium): elementLength = elementLengthAroundOstiumEnd @@ -440,7 +440,7 @@ def generateOstiumMesh(region, options, trackSurface, centralPath, startNodeIden # sideDirection = trackDirection2reverse # print('5') - position = trackSurface.findNearestPosition(xOstiumInner[n1]) + position = trackSurface.findNearestPosition(xOstiumOuter[n1]) oPositions.append(position) px, d1, d2 = trackSurface.evaluateCoordinates(position, True) angleRadians = 2.0 * math.pi / elementsCountAroundOstium * n1 @@ -457,7 +457,7 @@ def generateOstiumMesh(region, options, trackSurface, centralPath, startNodeIden sideDirection = [(w1 * trackDirection1[c] + w2 * trackDirection2[c]) for c in range(3)] pd2, pd1, pd3 = calculate_surface_axes(d1, d2, sideDirection) - # get outer coordinates + # get inner coordinates opx = px opd1 = vector.setMagnitude([-d for d in pd1], elementLengthAroundOstiumEnd) opd2 = vector.setMagnitude(pd2, vector.magnitude(centralPath.cd2Path[0])) # smoothed later @@ -610,9 +610,10 @@ def generateOstiumMesh(region, options, trackSurface, centralPath, startNodeIden vod1.append([]) vod2.append([]) vod3.append([]) + for n3 in range(elementsCountThroughWall + 1): - radius1 = vector.magnitude(centralPath.cd2Path[0]) + vesselWallThicknessXi3List[n3] * vesselWallThickness - radius2 = vector.magnitude(centralPath.cd3Path[0]) + vesselWallThicknessXi3List[n3] * vesselWallThickness + radius1 = vector.magnitude(centralPath.cd2Path[0]) - (1.0 - vesselWallThicknessXi3List[n3]) * vesselWallThickness + radius2 = vector.magnitude(centralPath.cd3Path[0]) - (1.0 - vesselWallThicknessXi3List[n3]) * vesselWallThickness vAxis1 = vector.setMagnitude(centralPath.cd2Path[0], radius1) vAxis2 = vector.setMagnitude(centralPath.cd3Path[0], radius2) # print(centralPath.cd2Path[0], centralPath.cd3Path[0]) From dd25f8191e04ce3ae86ed16e1a5ed076afd462ca Mon Sep 17 00:00:00 2001 From: mlin865 Date: Thu, 31 Aug 2023 12:40:25 +1200 Subject: [PATCH 14/24] Update scaffolds so d2 and d3 of central path point to outer surface --- .../meshtypes/meshtype_3d_cecum1.py | 148 +- .../meshtypes/meshtype_3d_colon1.py | 420 ++--- .../meshtypes/meshtype_3d_colonsegment1.py | 288 ++-- .../meshtypes/meshtype_3d_esophagus1.py | 15 +- .../meshtypes/meshtype_3d_smallintestine1.py | 1475 +++++++++-------- 5 files changed, 1163 insertions(+), 1183 deletions(-) diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_cecum1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_cecum1.py index 5b5b4ffb..96c3d0f4 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_cecum1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_cecum1.py @@ -15,7 +15,7 @@ from scaffoldmaker.annotation.cecum_terms import get_cecum_term from scaffoldmaker.annotation.smallintestine_terms import get_smallintestine_term from scaffoldmaker.meshtypes.meshtype_1d_network_layout1 import MeshType_1d_network_layout1 -from scaffoldmaker.meshtypes.meshtype_3d_colonsegment1 import ColonSegmentTubeMeshInnerPoints, \ +from scaffoldmaker.meshtypes.meshtype_3d_colonsegment1 import ColonSegmentTubeMeshOuterPoints, \ getFullProfileFromHalfHaustrum, getTeniaColi, createNodesAndElementsTeniaColi from scaffoldmaker.meshtypes.meshtype_3d_ostium2 import MeshType_3d_ostium2, generateOstiumMesh from scaffoldmaker.meshtypes.scaffold_base import Scaffold_base @@ -50,9 +50,10 @@ class MeshType_3d_cecum1(Scaffold_base): [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ (1, [[7.50,-20.00,0.00], [0.00,8.28,0.00], [-1.50,0.00,0.00], [0.00,0.00,0.00], [0.00,-0.00,1.50], [0.00,0.00,0.00]]), (2, [[7.50,-10.86,0.00], [0.00,10.00,0.00], [-4.50,0.00,0.00], [0.00,0.00,0.00], [0.00,-0.00,4.50], [0.00,0.00,0.00]]), - (3, [[7.50,0.00,0.00], [[7.50,0.00,0.00],[0.00,11.72,0.00]], [[0.00,10.00,0.00],[-4.50,0.00,0.00]], [[1.02,6.79,0.00],[0.00,0.00,0.00]], [[0.00,0.00,10.00],[0.00,-0.00,4.50]], [[0.00,0.00,5.77],[0.00,0.00,0.00]]]), - (4, [[0.00,0.00,0.00], [7.50,0.00,0.00], [0.00,10.00,0.00], [0.00,0.00,0.00], [0.00,0.00,10.00], [0.00,0.00,0.00]]), - (5, [[15.00,0.00,0.00], [7.50,0.00,0.00], [0.00,10.00,0.00], [0.00,0.00,0.00], [0.00,0.00,10.00], [0.00,0.00,0.00]])]), + (3, [[7.50,0.00,0.00], [[8.44,0.00,0.04],[0.00,11.72,0.00]], [[0.00,11.60,0.00],[-4.50,0.00,0.00]], [[1.02,6.79,0.00],[0.00,0.00,0.00]], [[0.00,0.00,11.60],[0.00,-0.00,4.50]], [[0.00,0.00,5.77],[0.00,0.00,0.00]]]), + (4, [[-1.88,0.00,-0.08], [10.32,0.00,0.12], [0.00,11.60,0.00], [0.00,0.00,0.00], [0.00,0.00,11.60], [0.00,0.00,0.00]]), + (5, [[15.00,0.00,0.00], [6.56,0.00,-0.04], [0.00,11.60,0.00], [0.00,0.00,0.00], [0.00,0.00,11.60], [0.00,0.00,0.00]]) + ]), 'userAnnotationGroups': [ { @@ -78,10 +79,10 @@ class MeshType_3d_cecum1(Scaffold_base): [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ (1, [[-60.63,-80.53,895.25], [-6.17,-10.10,-5.87], [2.66,0.73,-4.05], [2.38,0.99,-1.14], [3.31,-2.97,1.64], [2.38,0.99,-1.14]]), (2, [[-68.64,-93.29,888.06], [-9.85,-15.42,-8.51], [3.88,1.20,-6.66], [2.38,0.99,-1.14], [2.82,-2.46,1.20], [2.38,0.99,-1.14]]), - (3, [[-80.39,-111.37,878.29], [[-7.24,-1.01,11.64],[-13.65,-20.74,-11.03]], [[19.37,-3.78,11.72],[5.59,1.31,-9.38]], [[2.38,0.99,-1.14],[2.38,0.99,-1.14]], [[2.31,22.26,3.37],[1.51,-1.37,0.71]], [[2.38,0.99,-1.14],[2.38,0.99,-1.14]]]), - (4, [[-72.87,-109.11,867.41], [-7.88,-3.47,10.51], [16.11,-4.49,10.60], [3.73,0.68,4.20], [0.76,18.44,6.66], [3.74,0.69,4.20]]), - (5, [[-87.21,-111.06,890.54], [-4.75,0.41,12.39], [20.72,-2.80,8.04], [2.46,-0.39,-2.95], [2.85,22.11,0.36], [1.83,0.46,-4.31]])]), - + (3, [[-80.39,-111.37,878.29], [[-7.79,-0.98,12.36],[-13.65,-20.74,-11.03]], [[20.72,-4.04,12.54],[5.59,1.31,-9.38]], [[2.38,0.99,-1.14],[2.38,0.99,-1.14]], [[2.47,23.83,3.61],[1.51,-1.37,0.71]], [[2.38,0.99,-1.14],[2.38,0.99,-1.14]]]), + (4, [[-71.69,-109.00,866.04], [-9.55,-3.73,12.06], [17.41,-4.85,11.46], [3.73,0.68,4.20], [0.82,19.94,7.20], [3.74,0.69,4.20]]), + (5, [[-87.21,-111.06,890.54], [-5.80,1.59,12.04], [22.20,-3.00,8.61], [2.46,-0.39,-2.95], [3.05,23.70,0.39], [1.83,0.46,-4.31]]) + ]), 'userAnnotationGroups': [ { '_AnnotationGroup': True, @@ -104,13 +105,14 @@ class MeshType_3d_cecum1(Scaffold_base): }, 'meshEdits': exnode_string_from_nodeset_field_parameters( [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ - (1, [[167.00,29.75,51.53], [0.00,-9.63,-16.67], [-4.00,-0.00,0.00], [0.00,0.00,0.00], [0.00,6.64,-3.83], [0.00,0.00,0.00]]), - (2, [[167.00,17.50,30.31], [0.00,-14.87,-25.77], [-15.00,-0.00,0.00], [0.00,0.00,0.00], [0.00,10.49,-6.05], [0.00,0.00,0.00]]), - (3, [[167.00,0.00,0.00], [[30.00,0.00,0.00],[0.00,-20.13,-34.85]], [[0.00,35.00,0.00],[-15.00,0.00,0.00]], [[0.00,0.00,0.00],[0.00,0.00,0.00]], [[0.00,0.00,35.00],[0.00,8.49,-4.90]], [[0.00,0.00,0.00],[0.00,0.00,0.00]]]), - (4, [[0.00,0.00,0.00], [60.00,0.00,0.00], [0.00,35.00,0.00], [0.00,0.00,0.00], [0.00,0.00,35.00], [0.00,0.00,0.00]]), - (5, [[60.00,0.00,0.00], [60.00,0.00,0.00], [0.00,35.00,0.00], [0.00,0.00,0.00], [0.00,0.00,35.00], [0.00,0.00,0.00]]), - (6, [[120.00,0.00,0.00], [53.50,0.00,0.00], [0.00,35.00,0.00], [0.00,0.00,0.00], [0.00,0.00,35.00], [0.00,0.00,0.00]]), - (7, [[180.00,0.00,0.00], [4.00,-0.00,-0.00], [0.00,35.00,0.00], [0.00,0.00,0.00], [0.00,0.00,35.00], [0.00,0.00,0.00]])]), + (1, [[164.00,29.75,51.53], [0.00,-9.63,-16.67], [-6.00,0.00,0.00], [0.00,0.00,0.00], [0.00,5.20,-3.00], [0.00,0.00,0.00]]), + (2, [[164.00,17.50,30.31], [0.00,-14.87,-25.77], [-12.00,0.00,0.00], [0.00,0.00,0.00], [0.00,10.39,-6.00], [0.00,0.00,0.00]]), + (3, [[164.00,0.00,0.00], [[30.00,0.00,0.00],[0.00,-20.13,-34.85]], [[0.00,37.00,0.00],[-12.00,0.00,0.00]], [[0.00,0.00,0.00],[0.00,0.00,0.00]], [[0.00,0.00,37.00],[0.00,10.39,-6.00]], [[0.00,0.00,0.00],[0.00,0.00,0.00]]]), + (4, [[0.00,0.00,0.00], [60.00,0.00,0.00], [0.00,37.00,0.00], [0.00,0.00,0.00], [0.00,0.00,37.00], [0.00,0.00,0.00]]), + (5, [[60.00,0.00,0.00], [60.00,0.00,0.00], [0.00,37.00,0.00], [0.00,0.00,0.00], [0.00,0.00,37.00], [0.00,0.00,0.00]]), + (6, [[120.00,0.00,0.00], [52.00,0.00,0.00], [0.00,37.00,0.00], [0.00,0.00,0.00], [0.00,0.00,37.00], [0.00,0.00,0.00]]), + (7, [[180.00,0.00,0.00], [2.00,0.00,0.00], [0.00,37.00,0.00], [0.00,0.00,0.00], [0.00,0.00,37.00], [0.00,0.00,0.00]]) + ]), 'userAnnotationGroups': [ { @@ -202,15 +204,15 @@ def getDefaultOptions(cls, parameterSetName='Default'): 'Number of elements around haustrum': 8, 'Number of elements along segment': 8, 'Number of elements through wall': 1, - 'Corner inner radius factor': 0.5, - 'Haustrum inner radius factor': 0.4, + 'Corner outer radius factor': 0.536, + 'Haustrum outer radius factor': 0.464, 'Segment length end derivative factor': 0.5, 'Segment length mid derivative factor': 1.0, 'Number of tenia coli': 3, 'Start tenia coli width': 2.0, - 'Start tenia coli width derivative': 2.0, - 'End tenia coli width': 4.0, - 'End tenia coli width derivative': 2.0, + 'Start tenia coli width derivative': 3.3, + 'End tenia coli width': 5.3, + 'End tenia coli width derivative': 3.3, 'Tenia coli thickness': 0.5, 'Wall thickness': 1.6, 'Mucosa relative thickness': 0.55, @@ -236,8 +238,8 @@ def getDefaultOptions(cls, parameterSetName='Default'): elif 'Pig 1' in parameterSetName: options['Number of segments'] = 5 - options['Haustrum inner radius factor'] = 0.25 - options['Segment length end derivative factor'] = 1.0 + options['Haustrum outer radius factor'] = 0.25 + options['Segment length end derivative factor'] = 0.5 options['Segment length mid derivative factor'] = 4.0 options['Start tenia coli width'] = 5.0 options['Start tenia coli width derivative'] = 0.0 @@ -257,8 +259,8 @@ def getOrderedOptionNames(): 'Number of elements around haustrum', 'Number of elements along segment', 'Number of elements through wall', - 'Corner inner radius factor', - 'Haustrum inner radius factor', + 'Corner outer radius factor', + 'Haustrum outer radius factor', 'Segment length end derivative factor', 'Segment length mid derivative factor', 'Number of tenia coli', @@ -333,8 +335,8 @@ def checkOptions(cls, options): for key in [ 'Number of elements around tenia coli', 'Number of elements around haustrum', - 'Corner inner radius factor', - 'Haustrum inner radius factor', + 'Corner outer radius factor', + 'Haustrum outer radius factor', 'Segment length end derivative factor', 'Segment length mid derivative factor', 'Number of tenia coli', @@ -413,10 +415,10 @@ def refineMesh(cls, meshrefinement, options): refineElementsCountThroughWall) return -def getApexSegmentForCecum(xInner, d1Inner, d2Inner, elementsCountAroundHalfHaustrum, +def getApexSegmentForCecum(xOuter, d1Outer, d2Outer, elementsCountAroundHalfHaustrum, elementsCountAroundTC, elementsCountAround, elementsCountAlongSegment, tcCount): """ - Generates the inner coordinates and derivatives for a cecum segment on the closed end. + Generates the outer coordinates and derivatives for a cecum segment on the closed end. The closed end is a single node and segment is created by sampling curves between the point on closed end with nodes on the length along second half of a colon segment. :param xInner: coordinates of a colon segment. @@ -435,15 +437,15 @@ def getApexSegmentForCecum(xInner, d1Inner, d2Inner, elementsCountAroundHalfHaus xFirstSegment = [[0.0, 0.0, 0.0] for c in range(elementsCountAround)] # Compile nodes and d2 for sampling - xFirstSegment += xInner[elementsCountAround * int(elementsCountAlongSegment * 0.5):] # second half of first regular segment - d1FirstDirectionVector = vector.normalise(d1Inner[elementsCountAround]) # Store direction vector of first d1 intra-haustral for later - d2Vector = xInner[elementsCountAround * int(elementsCountAlongSegment * 0.5): + xFirstSegment += xOuter[elementsCountAround * int(elementsCountAlongSegment * 0.5):] # second half of first regular segment + d1FirstDirectionVector = vector.normalise(d1Outer[elementsCountAround]) # Store direction vector of first d1 intra-haustral for later + d2Vector = xOuter[elementsCountAround * int(elementsCountAlongSegment * 0.5): elementsCountAround * (int(elementsCountAlongSegment * 0.5) + 1)] # half face of segment - apex d2FirstSegment = [] for c in range(elementsCountAround): d2 = [d2Vector[c][0], d2Vector[c][1], 0.0 ] # project onto x-y plane to get d2 pointing vertically d2FirstSegment.append(d2) - d2FirstSegment += d2Inner[elementsCountAround * int(elementsCountAlongSegment*0.5):] + d2FirstSegment += d2Outer[elementsCountAround * int(elementsCountAlongSegment*0.5):] # Sample along first segment xFirstSegmentSampledRaw = [] @@ -565,8 +567,8 @@ def sampleCecumAlongLength(xToSample, d1ToSample, d2ToSample, d1FirstDirectionVe :return: nodes and derivatives for equally spaced points. """ - xInnerRaw = [] - d2InnerRaw = [] + xOuterRaw = [] + d2OuterRaw = [] xSampledAlongLength = [] d1SampledAlongLength = [] d2SampledAlongLength = [] @@ -581,8 +583,8 @@ def sampleCecumAlongLength(xToSample, d1ToSample, d2ToSample, d1FirstDirectionVe xSampled, d2Sampled, se, sxi, _ = interp.sampleCubicHermiteCurves(xForSamplingAlong, d2ForSamplingAlong, elementsCountAlong, arcLengthDerivatives=True) - xInnerRaw.append(xSampled) - d2InnerRaw.append(d2Sampled) + xOuterRaw.append(xSampled) + d2OuterRaw.append(d2Sampled) # Re-arrange sample order & calculate dx_ds1 and dx_ds3 from dx_ds2 for n2 in range(elementsCountAlong + 1): @@ -590,12 +592,12 @@ def sampleCecumAlongLength(xToSample, d1ToSample, d2ToSample, d1FirstDirectionVe d2Around = [] for n1 in range(elementsCountAroundHalfHaustrum + 1): - x = xInnerRaw[n1][n2] - d2 = d2InnerRaw[n1][n2] + x = xOuterRaw[n1][n2] + d2 = d2OuterRaw[n1][n2] xAround.append(x) d2Around.append(d2) - d1InnerAroundList = [] + d1OuterAroundList = [] if n2 == 0: d1Corrected = d1ToSample[:elementsCountAroundHalfHaustrum + 1] @@ -607,15 +609,15 @@ def sampleCecumAlongLength(xToSample, d1ToSample, d2ToSample, d1FirstDirectionVe 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)] - d1InnerAroundList.append(dx_ds1) + d1OuterAroundList.append(dx_ds1) # Account for d1 of node sitting on half haustrum d1 = vector.normalise([xAround[elementsCountAroundHalfHaustrum][c] - xAround[elementsCountAroundHalfHaustrum - 1][c] for c in range(3)]) dx_ds1 = [c * arcLengthAround for c in d1] - d1InnerAroundList.append(dx_ds1) + d1OuterAroundList.append(dx_ds1) - if d1InnerAroundList: - d1Smoothed = interp.smoothCubicHermiteDerivativesLine(xAround, d1InnerAroundList, fixStartDerivative=True) + if d1OuterAroundList: + d1Smoothed = interp.smoothCubicHermiteDerivativesLine(xAround, d1OuterAroundList, fixStartDerivative=True) d1TCEdge = vector.setMagnitude(d1Smoothed[int(elementsCountAroundTC * 0.5)], vector.magnitude(d1Smoothed[int(elementsCountAroundTC * 0.5 - 1)])) d1Transition = vector.setMagnitude(d1Smoothed[int(elementsCountAroundTC * 0.5 + 1)], @@ -664,8 +666,8 @@ def createCecumMesh3d(region, options, centralPath, nodeIdentifier, elementIdent elementsCountAroundHaustrum = options['Number of elements around haustrum'] elementsCountAlongSegment = options['Number of elements along segment'] elementsCountThroughWall = options['Number of elements through wall'] - cornerInnerRadiusFactor = options['Corner inner radius factor'] - haustrumInnerRadiusFactor = options['Haustrum inner radius factor'] + cornerOuterRadiusFactor = options['Corner outer radius factor'] + haustrumOuterRadiusFactor = options['Haustrum outer radius factor'] segmentLengthEndDerivativeFactor = options['Segment length end derivative factor'] segmentLengthMidDerivativeFactor = options['Segment length mid derivative factor'] tcCount = options['Number of tenia coli'] @@ -750,31 +752,31 @@ def createCecumMesh3d(region, options, centralPath, nodeIdentifier, elementIdent segmentLength = cecumLength / segmentCount # Generate variation of radius & tc width along length - innerRadiusAlongCecum = [] - dInnerRadiusAlongCecum = [] + outerRadiusAlongCecum = [] + dOuterRadiusAlongCecum = [] tcWidthAlongCecum = [] closedProximalEnd = True - innerRadiusListCP = [vector.magnitude(c) for c in cd2] - dInnerRadiusListCP = [] - for n in range(len(innerRadiusListCP) - 1): - dInnerRadiusListCP.append(innerRadiusListCP[n + 1] - innerRadiusListCP[n]) - dInnerRadiusListCP.append(innerRadiusListCP[-1] - innerRadiusListCP[-2]) - innerRadiusAlongElementList, dInnerRadiusAlongElementList = \ - interp.interpolateSampleCubicHermite(innerRadiusListCP, dInnerRadiusListCP, se, sxi, ssf) + outerRadiusListCP = [vector.magnitude(c) for c in cd2] + dOuterRadiusListCP = [] + for n in range(len(outerRadiusListCP) - 1): + dOuterRadiusListCP.append(outerRadiusListCP[n + 1] - outerRadiusListCP[n]) + dOuterRadiusListCP.append(outerRadiusListCP[-1] - outerRadiusListCP[-2]) + outerRadiusAlongElementList, dOuterRadiusAlongElementList = \ + interp.interpolateSampleCubicHermite(outerRadiusListCP, dOuterRadiusListCP, se, sxi, ssf) for n2 in range(elementsCountAlongSegment * segmentCount + 1): xi = 1 / (elementsCountAlongSegment * segmentCount) * n2 - radius = innerRadiusAlongElementList[n2] - innerRadiusAlongCecum.append(radius) - dRadius = dInnerRadiusAlongElementList[n2] - dInnerRadiusAlongCecum.append(dRadius) + radius = outerRadiusAlongElementList[n2] + outerRadiusAlongCecum.append(radius) + dRadius = dOuterRadiusAlongElementList[n2] + dOuterRadiusAlongCecum.append(dRadius) tcWidth = interp.interpolateCubicHermite([startTCWidth], [startTCWidthDerivative], [endTCWidth], [endTCWidthDerivative], xi)[0] tcWidthAlongCecum.append(tcWidth) - haustrumInnerRadiusFactorAlongCecum = [haustrumInnerRadiusFactor] * (elementsCountAlong + 1) + haustrumOuterRadiusFactorAlongCecum = [haustrumOuterRadiusFactor] * (elementsCountAlong + 1) xToSample = [] d1ToSample = [] @@ -783,11 +785,11 @@ def createCecumMesh3d(region, options, centralPath, nodeIdentifier, elementIdent elementsCountAroundHalfHaustrum = int((elementsCountAroundTC + elementsCountAroundHaustrum) * 0.5) # Create object - colonSegmentTubeMeshInnerPoints = ColonSegmentTubeMeshInnerPoints( + colonSegmentTubeMeshOuterPoints = ColonSegmentTubeMeshOuterPoints( region, elementsCountAroundTC, elementsCountAroundHaustrum, elementsCountAlongSegment, tcCount, segmentLengthEndDerivativeFactor, segmentLengthMidDerivativeFactor, - segmentLength, wallThickness, cornerInnerRadiusFactor, haustrumInnerRadiusFactorAlongCecum, - innerRadiusAlongCecum, dInnerRadiusAlongCecum, tcWidthAlongCecum, startPhase) + segmentLength, wallThickness, cornerOuterRadiusFactor, haustrumOuterRadiusFactorAlongCecum, + outerRadiusAlongCecum, dOuterRadiusAlongCecum, tcWidthAlongCecum, startPhase) # Create annotation cecumGroup = AnnotationGroup(region, get_cecum_term("caecum")) @@ -797,13 +799,13 @@ def createCecumMesh3d(region, options, centralPath, nodeIdentifier, elementIdent for nSegment in range(segmentCount): # Make regular segments - xInner, d1Inner, d2Inner, transitElementList, segmentAxis, annotationGroupsAround \ - = colonSegmentTubeMeshInnerPoints.getColonSegmentTubeMeshInnerPoints(nSegment) + xOuter, d1Outer, d2Outer, transitElementList, segmentAxis, annotationGroupsAround \ + = colonSegmentTubeMeshOuterPoints.getColonSegmentTubeMeshOuterPoints(nSegment) # Replace first half of first segment with apex and sample along apex and second half of segment if nSegment == 0: xFirstSegmentSampled, d1FirstSegmentSampled, d2FirstSegmentSampled, d1FirstDirectionVector = \ - getApexSegmentForCecum(xInner, d1Inner, d2Inner, elementsCountAroundHalfHaustrum, + getApexSegmentForCecum(xOuter, d1Outer, d2Outer, elementsCountAroundHalfHaustrum, elementsCountAroundTC, elementsCountAround, elementsCountAlongSegment, tcCount) @@ -811,12 +813,12 @@ def createCecumMesh3d(region, options, centralPath, nodeIdentifier, elementIdent d1ToSample += d1FirstSegmentSampled d2ToSample += d2FirstSegmentSampled else: - xInnerExtrude = [] - for n in range(len(xInner)): - xInnerExtrude.append([xInner[n][0], xInner[n][1], xInner[n][2] + segmentLength * nSegment]) - xToSample += xInnerExtrude[elementsCountAround:] - d1ToSample += d1Inner[elementsCountAround:] - d2ToSample += d2Inner[elementsCountAround:] + xOuterExtrude = [] + for n in range(len(xOuter)): + xOuterExtrude.append([xOuter[n][0], xOuter[n][1], xOuter[n][2] + segmentLength * nSegment]) + xToSample += xOuterExtrude[elementsCountAround:] + d1ToSample += d1Outer[elementsCountAround:] + d2ToSample += d2Outer[elementsCountAround:] # Sample along length xToWarp, d1ToWarp, d2ToWarp = sampleCecumAlongLength(xToSample, d1ToSample, d2ToSample, d1FirstDirectionVector, @@ -850,7 +852,7 @@ def createCecumMesh3d(region, options, centralPath, nodeIdentifier, elementIdent tubemesh.extrudeSurfaceCoordinates(xWarpedList, d1WarpedList,d2WarpedList, d3WarpedUnitList, wallThicknessList, relativeThicknessList, elementsCountAround, elementsCountAlong, elementsCountThroughWall, transitElementList, - outward=True) + outward=False) # Deal with multiple nodes at end point for closed proximal end xApexInner = xList[0] @@ -887,7 +889,7 @@ def createCecumMesh3d(region, options, centralPath, nodeIdentifier, elementIdent # Create nodes and elements if tcThickness > 0: - tubeTCWidthList = colonSegmentTubeMeshInnerPoints.getTubeTCWidthList() + tubeTCWidthList = colonSegmentTubeMeshOuterPoints.getTubeTCWidthList() xCecum, d1Cecum, d2Cecum, d3Cecum, annotationArrayAround = getTeniaColi( region, xCecum, d1Cecum, d2Cecum, d3Cecum, curvatureList, tcCount, elementsCountAroundTC, elementsCountAroundHaustrum, elementsCountAlong, elementsCountThroughWall, diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_colon1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_colon1.py index 3cf59417..dadf1076 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_colon1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_colon1.py @@ -14,7 +14,7 @@ from scaffoldmaker.annotation.colon_terms import get_colon_term from scaffoldmaker.meshtypes.meshtype_1d_network_layout1 import MeshType_1d_network_layout1 from scaffoldmaker.meshtypes.meshtype_3d_colonsegment1 import MeshType_3d_colonsegment1, \ - ColonSegmentTubeMeshInnerPoints, getTeniaColi, createFlatCoordinatesTeniaColi, createColonCoordinatesTeniaColi, \ + ColonSegmentTubeMeshOuterPoints, getTeniaColi, createFlatCoordinatesTeniaColi, createColonCoordinatesTeniaColi, \ createNodesAndElementsTeniaColi from scaffoldmaker.meshtypes.scaffold_base import Scaffold_base from scaffoldmaker.scaffoldpackage import ScaffoldPackage @@ -42,59 +42,60 @@ class MeshType_3d_colon1(Scaffold_base): }, 'meshEdits': exnode_string_from_nodeset_field_parameters( [ Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3 ], [ - (1, [ [ -245.30, 444.60, -49.10 ], [ -267.70, -53.10, -20.20 ], [ 0.00, 0.00, 35.00 ], [ 0.00, 0.00, -4.41 ], [ -6.81, 34.33, 0.00 ], [ 0.00, 0.00, -4.41] ] ), - (2, [ [ -380.30, 484.80, -45.00 ], [ 24.50, 102.70, 15.70 ], [ 0.00, 0.00, 31.47 ], [ 0.00, 0.00, -2.65 ], [ 30.61, -7.30, 0.00 ], [ 0.00, 0.00, -2.65] ] ), - (3, [ [ -298.10, 510.40, -36.80 ], [ 73.60, 9.90, -16.40 ], [ 0.00, 0.00, 29.34 ], [ -12.52, -3.10, -14.34 ], [ 3.91, -29.08, 0.00 ], [ -12.52, -3.10, -14.34] ] ), - (4, [ [ -213.10, 527.90, -22.50 ], [ -1.00, -10.80, 125.60 ], [ -26.23, -6.50, 1.62 ], [ -4.10, -6.11, -25.37 ], [ 6.36, -26.22, -2.20 ], [ -4.10, -6.11, -25.37] ] ), - (5, [ [ -315.50, 570.20, 18.90 ], [ -107.90, 9.30, 21.90 ], [ -2.62, -12.12, -20.82 ], [ 14.35, 4.82, -10.40 ], [ 0.65, -20.97, 12.13 ], [ 14.35, 4.82, -10.40] ] ), - (6, [ [ -417.40, 555.00, 14.60 ], [ -83.00, -41.30, -0.80 ], [ 4.22, 1.17, -21.45 ], [ 0.54, 4.88, 0.73 ], [ 9.74, -19.59, 0.85 ], [ 0.54, 4.88, 0.73] ] ), - (7, [ [ -497.30, 488.90, 13.60 ], [ -44.60, -81.60, 10.00 ], [ -1.56, -2.39, -19.34 ], [ -2.12, -0.60, 2.13 ], [ 17.14, -9.40, -0.22 ], [ -2.12, -0.60, 2.13] ] ), - (8, [ [ -527.00, 392.50, 2.70 ], [ 47.40, -82.00, -7.90 ], [ 0.00, 0.00, -17.20 ], [ 0.68, 1.04, 1.96 ], [ 14.89, 8.61, 0.00 ], [ 0.68, 1.04, 1.96] ] ), - (9, [ [ -461.20, 345.90, -0.80 ], [ 56.90, -44.50, 2.40 ], [ 0.00, 0.00, -15.38 ], [ 0.00, 0.00, 1.09 ], [ 9.47, 12.11, 0.00 ], [ 0.00, 0.00, 1.09] ] ), - (10, [ [ -415.60, 293.80, 3.90 ], [ 93.20, -62.60, 3.10 ], [ 0.00, 0.00, -14.91 ], [ 0.00, 0.00, 0.43 ], [ 8.31, 12.38, 0.00 ], [ 0.00, 0.00, 0.43] ] ), - (11, [ [ -232.20, 264.90, 0.20 ], [ 140.10, 58.20, -1.00 ], [ 0.00, 0.00, -14.58 ], [ 0.00, 0.00, 0.25 ], [ -5.59, 13.46, 0.00 ], [ 0.00, 0.00, 0.25] ] ), - (12, [ [ -168.40, 357.20, 1.30 ], [ 10.10, 78.60, -3.20 ], [ 0.00, 0.00, -14.38 ], [ 0.00, 0.00, 0.15 ], [ -14.26, 1.83, 0.00 ], [ 0.00, 0.00, 0.15] ] ), - (13, [ [ -185.30, 419.10, -0.70 ], [ -45.10, 57.10, -0.90 ], [ 0.00, 0.00, -14.27 ], [ 0.00, 0.00, 0.13 ], [ -11.20, -8.84, 0.00 ], [ 0.00, 0.00, 0.13] ] ), - (14, [ [ -253.20, 466.70, -0.30 ], [ -63.40, 24.70, 0.20 ], [ 0.00, 0.00, -14.13 ], [ 0.00, 0.00, 0.13 ], [ -5.13, -13.17, 0.00 ], [ 0.00, 0.00, 0.13] ] ), - (15, [ [ -323.80, 482.50, 0.10 ], [ -68.20, 2.90, -1.20 ], [ 0.00, 0.00, -14.00 ], [ 0.00, 0.00, 0.12 ], [ -0.59, -13.99, 0.00 ], [ 0.00, 0.00, 0.12] ] ), - (16, [ [ -387.50, 485.40, -0.20 ], [ -44.20, -17.10, -1.00 ], [ 0.00, 0.00, -13.89 ], [ 0.00, 0.00, 0.12 ], [ 5.01, -12.95, 0.00 ], [ 0.00, 0.00, 0.12] ] ), - (17, [ [ -435.60, 433.50, 3.30 ], [ 3.40, -109.50, 1.40 ], [ 0.00, 0.00, -13.76 ], [ 0.00, 0.00, 0.14 ], [ 13.75, 0.43, 0.00 ], [ 0.00, 0.00, 0.14] ] ), - (18, [ [ -370.60, 376.30, -1.10 ], [ 66.90, -29.20, -0.90 ], [ 0.00, 0.00, -13.60 ], [ 0.00, 0.00, 0.12 ], [ 5.44, 12.46, 0.00 ], [ 0.00, 0.00, 0.12] ] ), - (19, [ [ -313.00, 357.90, -0.10 ], [ 40.00, -33.50, 9.60 ], [ 0.00, 0.00, -13.50 ], [ 0.00, 0.00, 0.10 ], [ 8.67, 10.35, 0.00 ], [ 0.00, 0.00, 0.10] ] ), - (20, [ [ -259.20, 340.70, 2.10 ], [ 48.90, 6.40, 1.40 ], [ 0.00, 0.00, -13.40 ], [ 0.00, 0.00, 0.09 ], [ -1.74, 13.29, 0.00 ], [ 0.00, 0.00, 0.09] ] ), - (21, [ [ -246.50, 380.30, -0.80 ], [ -29.70, 33.60, -0.70 ], [ 0.00, 0.00, -13.31 ], [ 0.00, 0.00, 0.09 ], [ -9.97, -8.82, 0.00 ], [ 0.00, 0.00, 0.09] ] ), - (22, [ [ -297.30, 387.10, 0.60 ], [ -59.70, 12.60, -0.00 ], [ 0.00, 0.00, -13.22 ], [ 0.00, 0.00, 0.09 ], [ -2.73, -12.94, 0.00 ], [ 0.00, 0.00, 0.09] ] ), - (23, [ [ -340.20, 415.60, -1.00 ], [ -86.20, 28.90, -2.90 ], [ 0.00, 0.00, -13.13 ], [ 0.00, 0.00, 0.10 ], [ -4.17, -12.45, 0.00 ], [ 0.00, 0.00, 0.10] ] ), - (24, [ [ -398.30, 443.10, -0.10 ], [ 10.60, 82.10, -2.60 ], [ 0.00, 0.00, -13.01 ], [ 0.00, 0.00, 0.12 ], [ -12.90, 1.67, 0.00 ], [ 0.00, 0.00, 0.12] ] ), - (25, [ [ -329.80, 449.10, -2.10 ], [ 53.20, 14.00, -0.50 ], [ 0.00, 0.00, -12.88 ], [ 0.00, 0.00, 0.14 ], [ -3.28, 12.46, 0.00 ], [ 0.00, 0.00, 0.14] ] ), - (26, [ [ -251.30, 425.90, -0.30 ], [ 43.90, -19.30, 0.00 ], [ 0.00, 0.00, -12.74 ], [ 0.00, 0.00, 0.11 ], [ 5.13, 11.66, 0.00 ], [ 0.00, 0.00, 0.11] ] ), - (27, [ [ -209.10, 390.60, 0.00 ], [ 26.00, -38.80, 0.90 ], [ 0.00, 0.00, -12.65 ], [ 0.00, 0.00, 0.08 ], [ 10.51, 7.04, 0.00 ], [ 0.00, 0.00, 0.08] ] ), - (28, [ [ -207.80, 350.80, 1.40 ], [ -9.40, -43.60, 1.80 ], [ 0.00, 0.00, -12.57 ], [ 0.00, 0.00, 0.09 ], [ 12.29, -2.65, 0.00 ], [ 0.00, 0.00, 0.09] ] ), - (29, [ [ -245.80, 299.40, 7.60 ], [ -70.30, -36.00, 1.40 ], [ 0.00, 0.00, -12.46 ], [ 0.00, 0.00, 0.14 ], [ 5.68, -11.09, 0.00 ], [ 0.00, 0.00, 0.14] ] ), - (30, [ [ -345.30, 304.10, 3.10 ], [ -100.20, 27.90, -1.90 ], [ 0.00, 0.00, -12.29 ], [ 0.00, 0.00, 0.17 ], [ -3.30, -11.84, 0.00 ], [ 0.00, 0.00, 0.17] ] ), - (31, [ [ -418.40, 361.10, -0.20 ], [ -57.80, 55.80, -1.70 ], [ 0.00, 0.00, -12.13 ], [ 0.00, 0.00, 0.15 ], [ -8.42, -8.73, 0.00 ], [ 0.00, 0.00, 0.15] ] ), - (32, [ [ -479.20, 415.60, 2.20 ], [ -8.80, 73.10, -1.60 ], [ 0.00, 0.00, -11.98 ], [ 0.00, 0.00, 0.15 ], [ -11.89, -1.43, 0.00 ], [ 0.00, 0.00, 0.15] ] ), - (33, [ [ -439.60, 495.70, -2.10 ], [ 61.10, 57.10, -1.30 ], [ 0.00, 0.00, -11.82 ], [ 0.00, 0.00, 0.15 ], [ -8.07, 8.64, 0.00 ], [ 0.00, 0.00, 0.15] ] ), - (34, [ [ -361.60, 522.60, -3.00 ], [ 78.60, 9.90, 0.20 ], [ 0.00, 0.00, -11.68 ], [ 0.00, 0.00, 0.15 ], [ -1.46, 11.59, 0.00 ], [ 0.00, 0.00, 0.15] ] ), - (35, [ [ -270.10, 506.50, -3.80 ], [ 103.60, -33.30, 1.00 ], [ 0.00, 0.00, -11.52 ], [ 0.00, 0.00, 0.19 ], [ 3.53, 10.97, 0.00 ], [ 0.00, 0.00, 0.19] ] ), - (36, [ [ -148.90, 441.40, -2.10 ], [ 79.70, -91.50, 2.80 ], [ 0.00, 0.00, -11.28 ], [ 0.00, 0.00, 0.23 ], [ 8.51, 7.41, 0.00 ], [ 0.00, 0.00, 0.23] ] ), - (37, [ [ -130.90, 313.30, 4.00 ], [ -4.00, -107.20, 3.10 ], [ 0.00, 0.00, -11.05 ], [ 0.00, 0.00, 0.18 ], [ 11.04, -0.41, 0.00 ], [ 0.00, 0.00, 0.18] ] ), - (38, [ [ -183.90, 251.00, 3.80 ], [ -65.50, -60.20, 3.60 ], [ 0.00, 0.00, -10.90 ], [ 0.00, 0.00, 0.16 ], [ 7.38, -8.03, 0.00 ], [ 0.00, 0.00, 0.16] ] ), - (39, [ [ -280.30, 213.00, 3.40 ], [ -165.10, -18.60, 0.10 ], [ 0.00, 0.00, -10.72 ], [ 0.00, 0.00, 0.20 ], [ 1.20, -10.65, 0.00 ], [ 0.00, 0.00, 0.20] ] ), - (40, [ [ -400.80, 247.50, 6.80 ], [ -127.10, 36.80, 1.30 ], [ 0.00, 0.00, -10.51 ], [ 0.00, 0.00, 0.23 ], [ -2.92, -10.10, 0.00 ], [ 0.00, 0.00, 0.23] ] ), - (41, [ [ -530.50, 290.70, 5.20 ], [ -89.00, 86.50, 0.30 ], [ 0.00, 0.00, -10.27 ], [ 0.00, 0.00, 0.21 ], [ -7.16, -7.36, 0.00 ], [ 0.00, 0.00, 0.21] ] ), - (42, [ [ -568.80, 392.30, 6.90 ], [ -77.40, 67.70, -5.50 ], [ 0.00, 0.00, -10.08 ], [ 0.00, 0.00, 0.23 ], [ -6.64, -7.59, 0.00 ], [ 0.00, 0.00, 0.23] ] ), - (43, [ [ -511.20, 535.10, 2.50 ], [ 86.20, 111.40, -1.00 ], [ 0.00, 0.00, -9.80 ], [ 0.00, 0.00, 0.25 ], [ -7.75, 6.00, 0.00 ], [ 0.00, 0.00, 0.25] ] ), - (44, [ [ -405.00, 601.70, 6.40 ], [ 143.60, 52.20, 2.60 ], [ 0.00, 0.00, -9.58 ], [ 1.49, -1.44, 0.82 ], [ -3.27, 9.00, 0.00 ], [ 1.49, -1.44, 0.82] ] ), - (45, [ [ -238.80, 615.90, 16.60 ], [ 63.30, -9.10, 19.10 ], [ 3.45, -3.33, -7.95 ], [ -5.13, 0.21, 1.79 ], [ 2.06, 8.63, -2.72 ], [ -5.13, 0.21, 1.79] ] ), - (46, [ [ -146.20, 605.90, 36.50 ], [ 49.30, -9.90, -50.60 ], [ -6.72, -1.05, -6.07 ], [ -3.12, 3.94, 7.67 ], [ 0.10, 8.96, -1.66 ], [ -3.12, 3.94, 7.67] ] ), - (47, [ [ -218.40, 585.30, -2.00 ], [ -124.00, 0.40, -37.50 ], [ -3.04, 4.50, 7.19 ], [ 2.76, 2.30, 8.98 ], [ 1.33, 7.80, -4.32 ], [ 2.76, 2.30, 8.98] ] ), - (48, [ [ -376.30, 579.60, -40.80 ], [ -189.20, -50.70, -8.80 ], [ -1.85, 1.22, 8.78 ], [ 4.16, 0.49, -2.60 ], [ -2.23, 8.62, -1.67 ], [ 4.16, 0.49, -2.60] ] ), - (49, [ [ -557.90, 493.90, -24.90 ], [ -30.30, 24.10, 152.80 ], [ 6.19, 6.65, 0.69 ], [ 1.49, -2.48, -8.73 ], [ -6.35, 6.14, -2.23 ], [ 1.49, -2.48, -8.73] ] ), - (50, [ [ -484.80, 594.40, 0.70 ], [ 132.70, 97.00, 3.50 ], [ 3.25, -1.18, -8.47 ], [ -2.78, -5.06, -5.12 ], [ -5.07, 7.03, -2.92 ], [ -2.78, -5.06, -5.12] ] ), - (51, [ [ -318.10, 641.90, -8.50 ], [ 166.70, 17.60, 5.50 ], [ 0.67, -2.88, -8.72 ], [ -2.15, -0.82, -0.11 ], [ -0.82, 8.69, -2.93 ], [ -2.15, -0.82, -0.11] ] ), - (52, [ [ -158.30, 634.70, -1.90 ], [ 176.50, -14.00, 10.80 ], [ -1.08, -2.89, -8.71 ], [ -0.81, 0.27, -0.12 ], [ 0.87, 8.70, -2.99 ], [ -0.81, 0.27, -0.12] ] ), - (53, [ [ 32.70, 611.70, 13.60 ], [ 205.50, -32.20, 20.00 ], [ -0.76, -2.28, -8.98 ], [ 1.46, 0.96, -0.42 ], [ 1.62, 8.84, -2.38 ], [ 1.46, 0.96, -0.42] ] ) ] ), + (1, [[-245.30,444.60,-49.10], [-267.70,-53.10,-20.20], [0.00,0.00,38.02], [0.00,0.00,-4.41], [-7.40,37.29,0.00], [0.00,0.00,-4.41]]), + (2, [[-380.30,484.80,-45.00], [24.50,102.70,15.70], [0.00,0.00,34.49], [0.00,0.00,-2.65], [33.55,-8.00,0.00], [0.00,0.00,-2.65]]), + (3, [[-298.10,510.40,-36.80], [73.60,9.90,-16.40], [0.00,0.00,32.36], [-12.52,-3.10,-14.34], [4.31,-32.07,0.00], [-12.52,-3.10,-14.34]]), + (4, [[-213.10,527.90,-22.50], [-1.00,-10.80,125.60], [-29.16,-7.23,1.80], [-4.10,-6.11,-25.37], [7.07,-29.15,-2.45], [-4.10,-6.11,-25.37]]), + (5, [[-315.50,570.20,18.90], [-107.90,9.30,21.90], [-2.95,-13.63,-23.41], [14.35,4.82,-10.40], [0.73,-23.58,13.64], [14.35,4.82,-10.40]]), + (6, [[-417.40,555.00,14.60], [-83.00,-41.30,-0.80], [4.80,1.33,-24.41], [0.54,4.88,0.73], [11.08,-22.29,0.97], [0.54,4.88,0.73]]), + (7, [[-497.30,488.90,13.60], [-44.60,-81.60,10.00], [-1.80,-2.76,-22.33], [-2.12,-0.60,2.13], [19.79,-10.85,-0.25], [-2.12,-0.60,2.13]]), + (8, [[-527.00,392.50,2.70], [47.40,-82.00,-7.90], [0.00,0.00,-20.22], [0.68,1.04,1.96], [17.50,10.12,0.00], [0.68,1.04,1.96]]), + (9, [[-461.20,345.90,-0.80], [56.90,-44.50,2.40], [0.00,0.00,-18.40], [0.00,0.00,1.09], [11.33,14.49,0.00], [0.00,0.00,1.09]]), + (10, [[-415.60,293.80,3.90], [93.20,-62.60,3.10], [0.00,0.00,-17.93], [0.00,0.00,0.43], [9.99,14.89,0.00], [0.00,0.00,0.43]]), + (11, [[-232.20,264.90,0.20], [140.10,58.20,-1.00], [0.00,0.00,-17.60], [0.00,0.00,0.25], [-6.75,16.25,0.00], [0.00,0.00,0.25]]), + (12, [[-168.40,357.20,1.30], [10.10,78.60,-3.20], [0.00,0.00,-17.40], [0.00,0.00,0.15], [-17.26,2.21,0.00], [0.00,0.00,0.15]]), + (13, [[-185.30,419.10,-0.70], [-45.10,57.10,-0.90], [0.00,0.00,-17.29], [0.00,0.00,0.13], [-13.57,-10.71,0.00], [0.00,0.00,0.13]]), + (14, [[-253.20,466.70,-0.30], [-63.40,24.70,0.20], [0.00,0.00,-17.15], [0.00,0.00,0.13], [-6.23,-15.98,0.00], [0.00,0.00,0.13]]), + (15, [[-323.80,482.50,0.10], [-68.20,2.90,-1.20], [0.00,0.00,-17.02], [0.00,0.00,0.12], [-0.72,-17.01,0.00], [0.00,0.00,0.12]]), + (16, [[-387.50,485.40,-0.20], [-44.20,-17.10,-1.00], [0.00,0.00,-16.91], [0.00,0.00,0.12], [6.10,-15.77,0.00], [0.00,0.00,0.12]]), + (17, [[-435.60,433.50,3.30], [3.40,-109.50,1.40], [0.00,0.00,-16.78], [0.00,0.00,0.14], [16.77,0.52,0.00], [0.00,0.00,0.14]]), + (18, [[-370.60,376.30,-1.10], [66.90,-29.20,-0.90], [0.00,0.00,-16.62], [0.00,0.00,0.12], [6.65,15.23,0.00], [0.00,0.00,0.12]]), + (19, [[-313.00,357.90,-0.10], [40.00,-33.50,9.60], [0.00,0.00,-16.52], [0.00,0.00,0.10], [10.61,12.67,0.00], [0.00,0.00,0.10]]), + (20, [[-259.20,340.70,2.10], [48.90,6.40,1.40], [0.00,0.00,-16.42], [0.00,0.00,0.09], [-2.13,16.28,0.00], [0.00,0.00,0.09]]), + (21, [[-246.50,380.30,-0.80], [-29.70,33.60,-0.70], [0.00,0.00,-16.33], [0.00,0.00,0.09], [-12.23,-10.82,0.00], [0.00,0.00,0.09]]), + (22, [[-297.30,387.10,0.60], [-59.70,12.60,-0.00], [0.00,0.00,-16.24], [0.00,0.00,0.09], [-3.35,-15.89,0.00], [0.00,0.00,0.09]]), + (23, [[-340.20,415.60,-1.00], [-86.20,28.90,-2.90], [0.00,0.00,-16.15], [0.00,0.00,0.10], [-5.13,-15.31,0.00], [0.00,0.00,0.10]]), + (24, [[-398.30,443.10,-0.10], [10.60,82.10,-2.60], [0.00,0.00,-16.03], [0.00,0.00,0.12], [-15.90,2.06,0.00], [0.00,0.00,0.12]]), + (25, [[-329.80,449.10,-2.10], [53.20,14.00,-0.50], [0.00,0.00,-15.90], [0.00,0.00,0.14], [-4.05,15.38,0.00], [0.00,0.00,0.14]]), + (26, [[-251.30,425.90,-0.30], [43.90,-19.30,0.00], [0.00,0.00,-15.76], [0.00,0.00,0.11], [6.35,14.42,0.00], [0.00,0.00,0.11]]), + (27, [[-209.10,390.60,0.00], [26.00,-38.80,0.90], [0.00,0.00,-15.67], [0.00,0.00,0.08], [13.02,8.72,0.00], [0.00,0.00,0.08]]), + (28, [[-207.80,350.80,1.40], [-9.40,-43.60,1.80], [0.00,0.00,-15.59], [0.00,0.00,0.09], [15.24,-3.29,0.00], [0.00,0.00,0.09]]), + (29, [[-245.80,299.40,7.60], [-70.30,-36.00,1.40], [0.00,0.00,-15.48], [0.00,0.00,0.14], [7.06,-13.78,0.00], [0.00,0.00,0.14]]), + (30, [[-345.30,304.10,3.10], [-100.20,27.90,-1.90], [0.00,0.00,-15.31], [0.00,0.00,0.17], [-4.11,-14.75,0.00], [0.00,0.00,0.17]]), + (31, [[-418.40,361.10,-0.20], [-57.80,55.80,-1.70], [0.00,0.00,-15.15], [0.00,0.00,0.15], [-10.52,-10.90,0.00], [0.00,0.00,0.15]]), + (32, [[-479.20,415.60,2.20], [-8.80,73.10,-1.60], [0.00,0.00,-15.00], [0.00,0.00,0.15], [-14.89,-1.79,0.00], [0.00,0.00,0.15]]), + (33, [[-439.60,495.70,-2.10], [61.10,57.10,-1.30], [0.00,0.00,-14.84], [0.00,0.00,0.15], [-10.13,10.85,0.00], [0.00,0.00,0.15]]), + (34, [[-361.60,522.60,-3.00], [78.60,9.90,0.20], [0.00,0.00,-14.70], [0.00,0.00,0.15], [-1.84,14.59,0.00], [0.00,0.00,0.15]]), + (35, [[-270.10,506.50,-3.80], [103.60,-33.30,1.00], [0.00,0.00,-14.54], [0.00,0.00,0.19], [4.46,13.84,0.00], [0.00,0.00,0.19]]), + (36, [[-148.90,441.40,-2.10], [79.70,-91.50,2.80], [0.00,0.00,-14.30], [0.00,0.00,0.23], [10.79,9.39,0.00], [0.00,0.00,0.23]]), + (37, [[-130.90,313.30,4.00], [-4.00,-107.20,3.10], [0.00,0.00,-14.07], [0.00,0.00,0.18], [14.06,-0.52,0.00], [0.00,0.00,0.18]]), + (38, [[-183.90,251.00,3.80], [-65.50,-60.20,3.60], [0.00,0.00,-13.92], [0.00,0.00,0.16], [9.42,-10.25,0.00], [0.00,0.00,0.16]]), + (39, [[-280.30,213.00,3.40], [-165.10,-18.60,0.10], [0.00,0.00,-13.74], [0.00,0.00,0.20], [1.54,-13.65,0.00], [0.00,0.00,0.20]]), + (40, [[-400.80,247.50,6.80], [-127.10,36.80,1.30], [0.00,0.00,-13.53], [0.00,0.00,0.23], [-3.76,-13.00,0.00], [0.00,0.00,0.23]]), + (41, [[-530.50,290.70,5.20], [-89.00,86.50,0.30], [0.00,0.00,-13.29], [0.00,0.00,0.21], [-9.27,-9.52,0.00], [0.00,0.00,0.21]]), + (42, [[-568.80,392.30,6.90], [-77.40,67.70,-5.50], [0.00,0.00,-13.10], [0.00,0.00,0.23], [-8.63,-9.86,0.00], [0.00,0.00,0.23]]), + (43, [[-511.20,535.10,2.50], [86.20,111.40,-1.00], [0.00,0.00,-12.82], [0.00,0.00,0.25], [-10.14,7.85,0.00], [0.00,0.00,0.25]]), + (44, [[-405.00,601.70,6.40], [143.60,52.20,2.60], [0.00,0.00,-12.60], [1.49,-1.44,0.82], [-4.30,11.84,0.00], [1.49,-1.44,0.82]]), + (45, [[-238.80,615.90,16.60], [63.30,-9.10,19.10], [4.57,-4.41,-10.54], [-5.13,0.21,1.79], [2.73,11.44,-3.61], [-5.13,0.21,1.79]]), + (46, [[-146.20,605.90,36.50], [49.30,-9.90,-50.60], [-8.95,-1.40,-8.08], [-3.12,3.94,7.67], [0.13,11.93,-2.21], [-3.12,3.94,7.67]]), + (47, [[-218.40,585.30,-2.00], [-124.00,0.40,-37.50], [-4.06,6.01,9.60], [2.76,2.30,8.98], [1.78,10.41,-5.77], [2.76,2.30,8.98]]), + (48, [[-376.30,579.60,-40.80], [-189.20,-50.70,-8.80], [-2.47,1.63,11.71], [4.16,0.49,-2.60], [-2.97,11.49,-2.23], [4.16,0.49,-2.60]]), + (49, [[-557.90,493.90,-24.90], [-30.30,24.10,152.80], [8.24,8.85,0.92], [1.49,-2.48,-8.73], [-8.46,8.18,-2.97], [1.49,-2.48,-8.73]]), + (50, [[-484.80,594.40,0.70], [132.70,97.00,3.50], [4.32,-1.57,-11.27], [-2.78,-5.06,-5.12], [-6.74,9.35,-3.88], [-2.78,-5.06,-5.12]]), + (51, [[-318.10,641.90,-8.50], [166.70,17.60,5.50], [0.89,-3.82,-11.58], [-2.15,-0.82,-0.11], [-1.09,11.54,-3.89], [-2.15,-0.82,-0.11]]), + (52, [[-158.30,634.70,-1.90], [176.50,-14.00,10.80], [-1.43,-3.83,-11.56], [-0.81,0.27,-0.12], [1.15,11.54,-3.97], [-0.81,0.27,-0.12]]), + (53, [[32.70,611.70,13.60], [205.50,-32.20,20.00], [-1.01,-3.02,-11.90], [1.46,0.96,-0.42], [2.15,11.71,-3.15], [1.46,0.96,-0.42]]) + ] ), 'userAnnotationGroups': [ { @@ -125,15 +126,16 @@ class MeshType_3d_colon1(Scaffold_base): }, 'meshEdits': exnode_string_from_nodeset_field_parameters( [ Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ - (1, [ [ 0.00, 0.00, 0.00 ], [ -50.70, 178.20, 0.00 ], [ -37.97, -9.49, -18.98 ], [ -6.86, -11.39, -2.36 ], [ -18.61, -3.98, 39.12 ], [ -14.00, -1.00, -12.00] ] ), - (2, [ [ -47.40, 188.60, 0.00 ], [ -19.30, 177.10, 0.00 ], [ -35.79, -6.51, -13.01 ], [ 11.23, 17.36, 14.31 ], [ -12.66, -3.99, 36.28 ], [ -4.00, 19.00, 22.00] ] ), - (3, [ [ -4.40, 396.50, 0.00 ], [ 206.00, 40.10, 0.00 ], [ -13.89, 27.78, 11.11 ], [ 13.54, -1.87, 21.51 ], [ -6.05, -12.50, 29.93 ], [ -6.00, 0.00, 51.00] ] ), - (4, [ [ 130.00, 384.10, 0.00 ], [ 130.80, -40.50, 0.00 ], [ -5.35, 4.28, 31.06 ], [ 5.83, -8.41, 8.86 ], [ -15.28, -27.78, 2.51 ], [ 0.00, 1.00, 24.00] ] ), - (5, [ [ 279.40, 383.00, 0.00 ], [ 118.00, 48.70, 0.00 ], [ -2.51, 12.57, 27.65 ], [ 9.30, 9.73, -10.83 ], [ 12.83, -24.62, 12.58 ], [ 5.00, 25.00, -20.00] ] ), - (6, [ [ 443.90, 390.80, 0.00 ], [ 111.30, -97.00, 0.00 ], [ 14.07, 23.92, 8.44 ], [ 12.36, -3.74, -23.50 ], [ -9.40, -3.01, 27.28 ], [ 1.00, -6.00, -35.00] ] ), - (7, [ [ 475.20, 168.00, 0.00 ], [ -0.80, -112.40, 0.00 ], [ 20.78, 0.00, -20.78 ], [ -2.41, -19.32, -15.36 ], [ 20.78, -0.00, 20.78 ], [ 15.00, -1.00, -10.00] ] ), - (8, [ [ 432.60, -32.30, 0.00 ], [ -90.50, -59.00, 0.00 ], [ 10.09, -15.13, -23.54 ], [ -9.58, -7.07, -2.37 ], [ 13.01, -19.62, 18.19 ], [ 8.00, -11.00, -13.00] ] ), - (9, [ [ 272.40, 7.50, 0.00 ], [ -79.00, 47.40, 0.00 ], [ 1.42, -15.65, -25.60 ], [ -7.76, 6.05, -1.75 ], [ -5.22, -26.72, 12.68 ], [ 4.00, -12.00, -12.00] ] ) ] ), + (1, [[0.00,0.00,0.00], [-50.70,178.20,0.00], [-40.03,-10.00,-20.01], [-6.86,-11.39,-2.36], [-19.62,-4.20,41.24], [-14.00,-1.00,-12.00]]), + (2, [[-47.40,188.60,0.00], [-19.30,177.10,0.00], [-37.98,-6.91,-13.80], [11.23,17.36,14.31], [-13.43,-4.23,38.50], [-4.00,19.00,22.00]]), + (3, [[-4.40,396.50,0.00], [206.00,40.10,0.00], [-14.88,29.77,11.90], [13.54,-1.87,21.51], [-6.48,-13.39,32.07], [-6.00,0.00,51.00]]), + (4, [[130.00,384.10,0.00], [130.80,-40.50,0.00], [-5.75,4.60,33.36], [5.83,-8.41,8.86], [-16.41,-29.84,2.70], [0.00,1.00,24.00]]), + (5, [[279.40,383.00,0.00], [118.00,48.70,0.00], [-2.70,13.54,29.79], [9.30,9.73,-10.83], [13.82,-26.53,13.55], [5.00,25.00,-20.00]]), + (6, [[443.90,390.80,0.00], [111.30,-97.00,0.00], [15.21,25.87,9.13], [12.36,-3.74,-23.50], [-10.16,-3.25,29.50], [1.00,-6.00,-35.00]]), + (7, [[475.20,168.00,0.00], [-0.80,-112.40,0.00], [22.45,0.00,-22.45], [-2.41,-19.32,-15.36], [22.45,-0.00,22.45], [15.00,-1.00,-10.00]]), + (8, [[432.60,-32.30,0.00], [-90.50,-59.00,0.00], [10.89,-16.33,-25.41], [-9.58,-7.07,-2.37], [14.04,-21.18,19.63], [8.00,-11.00,-13.00]]), + (9, [[272.40,7.50,0.00], [-79.00,47.40,0.00], [1.53,-16.88,-27.61], [-7.76,6.05,-1.75], [-5.63,-28.82,13.68], [4.00,-12.00,-12.00]]) + ]), 'userAnnotationGroups': [ { @@ -164,15 +166,16 @@ class MeshType_3d_colon1(Scaffold_base): }, 'meshEdits': exnode_string_from_nodeset_field_parameters( [ Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ - (1, [ [ 0.00, 0.00, 0.00 ], [ -56.81, 105.14, -38.05 ], [ -37.97, -9.49, -18.98 ], [ -3.67, -11.77, -1.56 ], [ -21.20, 5.92, 37.52 ], [ -14.00, -1.00, -12.00 ] ] ), - (2, [ [ -34.50, 114.00, -18.10 ], [ -9.51, 117.91, 3.65 ], [ -33.74, -6.13, -12.27 ], [ 12.13, 18.49, 14.99 ], [ -12.58, -4.62, 33.86 ], [ -4.00, 19.00, 22.00 ] ] ), - (3, [ [ -19.10, 218.50, 5.50 ], [ 79.23, 66.40, 77.49 ], [ -13.72, 27.44, 10.98 ], [ 14.61, 7.18, 21.72 ], [ -22.92, -17.43, 15.26 ], [ -6.00, 0.00, 51.00 ] ] ), - (4, [ [ 82.50, 189.10, 94.20 ], [ 140.70, -1.06, 48.14 ], [ -5.34, 4.27, 30.95 ], [ 5.75, -8.29, 9.07 ], [ 11.54, -25.97, 14.03 ], [ 0.00, 1.00, 24.00 ] ] ), - (5, [ [ 226.60, 218.70, 85.70 ], [ 164.08, 101.90, -75.52 ], [ -2.53, 12.64, 27.81 ], [ 8.00, 9.47, -9.25 ], [ 19.49, -20.43, 11.94 ], [ 5.00, 25.00, -20.00 ] ] ), - (6, [ [ 325.50, 381.70, -57.90 ], [ 187.36, -116.61, -173.53 ], [ 14.07, 23.92, 8.44 ], [ 12.05, -5.07, -23.99 ], [ 5.51, -10.97, 26.28 ], [ 1.00, -6.00, -35.00 ] ] ), - (7, [ [ 354.00, 105.30, -24.40 ], [ -20.59, -269.54, 30.48 ], [ 20.87, 0.00, -20.87 ], [ -2.92, -19.10, -14.61 ], [ 20.81, 5.79, 20.11 ], [ 15.00, -1.00, -10.00 ] ] ), - (8, [ [ 296.50, -121.20, -0.60 ], [ -170.98, -102.19, -18.39 ], [ 10.15, -15.22, -23.67 ], [ -9.48, -6.06, -2.33 ], [ 13.09, -19.73, 18.29 ], [ 8.00, -11.00, -13.00 ] ] ), - (9, [ [ 169.80, -73.40, -33.50 ], [ -42.47, 101.91, -24.43 ], [ 1.43, -15.71, -25.71 ], [ -7.96, 5.07, -1.75 ], [ -16.72, -21.84, 12.39 ], [ 4.00, -12.00, -12.00 ] ] ) ] ), + (1, [[0.00,0.00,0.00], [-56.81,105.14,-38.05], [-40.03,-10.00,-20.01], [-3.67,-11.77,-1.56], [-22.35,6.24,39.56], [-14.00,-1.00,-12.00]]), + (2, [[-34.50,114.00,-18.10], [-9.51,117.91,3.65], [-35.93,-6.53,-13.07], [12.13,18.49,14.99], [-13.40,-4.92,36.05], [-4.00,19.00,22.00]]), + (3, [[-19.10,218.50,5.50], [79.23,66.40,77.49], [-14.71,29.43,11.78], [14.61,7.18,21.72], [-24.58,-18.69,16.37], [-6.00,0.00,51.00]]), + (4, [[82.50,189.10,94.20], [140.70,-1.06,48.14], [-5.74,4.59,33.25], [5.75,-8.29,9.07], [12.40,-27.90,15.07], [0.00,1.00,24.00]]), + (5, [[226.60,218.70,85.70], [164.08,101.90,-75.52], [-2.72,13.61,29.95], [8.00,9.47,-9.25], [20.99,-22.00,12.86], [5.00,25.00,-20.00]]), + (6, [[325.50,381.70,-57.90], [187.36,-116.61,-173.53], [15.21,25.87,9.13], [12.05,-5.07,-23.99], [5.96,-11.86,28.42], [1.00,-6.00,-35.00]]), + (7, [[354.00,105.30,-24.40], [-20.59,-269.54,30.48], [22.54,0.00,-22.54], [-2.92,-19.10,-14.61], [22.47,6.25,21.72], [15.00,-1.00,-10.00]]), + (8, [[296.50,-121.20,-0.60], [-170.98,-102.19,-18.39], [10.95,-16.42,-25.54], [-9.48,-6.06,-2.33], [14.12,-21.29,19.73], [8.00,-11.00,-13.00]]), + (9, [[169.80,-73.40,-33.50], [-42.47,101.91,-24.43], [1.54,-16.94,-27.72], [-7.96,5.07,-1.75], [-18.03,-23.55,13.36], [4.00,-12.00,-12.00]]) + ] ), 'userAnnotationGroups': [ { @@ -204,55 +207,56 @@ class MeshType_3d_colon1(Scaffold_base): }, 'meshEdits': exnode_string_from_nodeset_field_parameters( [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ - (1, [ [ -87.21, -111.06, 890.54 ], [ -4.75, 0.41, 12.39 ], [ 21.05, -2.83, 7.13 ], [ 2.46, -0.39, -2.95 ], [ 2.79, 22.12, 0.41 ], [ 1.83, 0.46, -4.31 ] ] ), - (2, [ [ -89.99, -110.57, 902.65 ], [ -2.05, 0.53, 12.72 ], [ 22.40, -2.97, 3.74 ], [ 0.07, 0.14, -2.81 ], [ 3.10, 22.66, -0.58 ], [ 0.43, 0.10, -3.97 ] ] ), - (3, [ [ -91.25, -110.01, 915.92 ], [ -0.55, 0.53, 13.39 ], [ 21.27, -2.54, 0.97 ], [ -1.46, 0.55, -1.92 ], [ 2.57, 21.27, -0.82 ], [ -1.42, 0.54, -2.13 ] ] ), - (4, [ [ -91.08, -109.52, 929.39 ], [ 0.13, 0.65, 13.47 ], [ 19.48, -1.87, -0.09 ], [ -0.53, 0.22, -1.06 ], [ 1.86, 19.46, -1.05 ], [ -0.53, 0.21, -1.17 ] ] ), - (5, [ [ -91.00, -108.72, 942.85 ], [ 0.83, 0.67, 13.37 ], [ 20.22, -2.11, -1.15 ], [ -0.88, 0.27, -1.85 ], [ 2.05, 20.22, -1.27 ], [ -0.92, 0.27, -2.03 ] ] ), - (6, [ [ -89.43, -108.18, 956.08 ], [ 2.81, 0.32, 13.11 ], [ 17.75, -1.34, -3.78 ], [ -1.96, 0.62, -1.35 ], [ 1.22, 18.09, -0.76 ], [ -2.00, 0.62, -1.49 ] ] ), - (7, [ [ -85.39, -108.09, 968.92 ], [ 3.10, 0.44, 13.08 ], [ 16.31, -0.87, -3.84 ], [ -0.76, 0.32, 0.66 ], [ 0.72, 16.68, -0.80 ], [ -0.73, 0.31, 0.71 ] ] ), - (8, [ [ -83.24, -107.30, 982.14 ], [ 2.05, 0.85, 13.23 ], [ 16.22, -0.70, -2.47 ], [ -0.24, 0.09, 0.57 ], [ 0.54, 16.36, -1.26 ], [ -0.21, 0.08, 0.63 ] ] ), - (9, [ [ -81.29, -106.40, 995.37 ], [ 2.32, 1.34, 13.29 ], [ 15.83, -0.69, -2.70 ], [ 0.14, 0.24, -0.11 ], [ 0.41, 15.95, -1.86 ], [ 0.05, 0.31, -0.57 ] ] ), - (10, [ [ -78.60, -104.62, 1008.65 ], [ 2.14, -1.50, 13.27 ], [ 16.51, -0.22, -2.69 ], [ -0.91, 1.85, -0.22 ], [ 0.74, 16.43, 3.01 ], [ -0.95, 1.98, -0.15 ] ] ), - (11, [ [ -77.17, -109.18, 1020.82 ], [ 4.07, -9.07, 9.68 ], [ 14.05, 2.96, -3.13 ], [ -2.15, 4.06, 0.80 ], [ -0.01, 10.40, 10.89 ], [ -1.97, 3.89, 1.43 ] ] ), - (12, [ [ -71.19, -121.03, 1025.58 ], [ 7.48, -11.42, 0.49 ], [ 12.23, 7.97, -0.98 ], [ -1.27, 2.69, 3.17 ], [ 0.00, 1.72, 15.29 ], [ -1.27, 2.72, 3.23 ] ] ), - (13, [ [ -63.35, -130.56, 1022.18 ], [ 7.99, -9.44, -3.40 ], [ 11.46, 8.59, 3.10 ], [ -0.81, 0.70, 2.42 ], [ 0.00, -4.74, 14.55 ], [ -0.91, 0.85, 2.43 ] ] ), - (14, [ [ -55.27, -139.84, 1018.80 ], [ 8.88, -8.59, -3.55 ], [ 10.61, 9.36, 3.87 ], [ -1.07, 0.87, 0.81 ], [ 0.00, -5.35, 14.33 ], [ -1.09, 0.87, 0.81 ] ] ), - (15, [ [ -45.66, -147.66, 1015.10 ], [ 9.90, -7.39, -3.36 ], [ 9.31, 10.33, 4.71 ], [ -1.63, 1.38, 0.03 ], [ -0.01, -5.79, 14.11 ], [ -1.62, 1.36, 0.02 ] ] ), - (16, [ [ -35.52, -154.60, 1012.08 ], [ 11.08, -6.08, -1.98 ], [ 7.36, 12.12, 3.95 ], [ -1.99, 1.15, 0.25 ], [ -0.01, -4.33, 14.74 ], [ -1.97, 1.13, 0.24 ] ] ), - (17, [ [ -23.71, -159.68, 1011.20 ], [ 11.97, -4.32, -1.79 ], [ 5.34, 12.62, 5.23 ], [ -1.74, -0.44, 2.51 ], [ 0.01, -5.34, 14.28 ], [ -1.79, -0.44, 2.52 ] ] ), - (18, [ [ -11.72, -163.20, 1008.53 ], [ 12.26, -2.58, -2.06 ], [ 3.87, 11.25, 8.97 ], [ -2.16, -0.11, 1.44 ], [ -0.01, -8.84, 12.28 ], [ -2.14, -0.12, 1.43 ] ] ), - (19, [ [ 0.67, -164.82, 1007.10 ], [ 12.71, -0.73, -0.48 ], [ 1.02, 12.38, 8.14 ], [ -2.67, 0.76, -0.81 ], [ -0.01, -7.75, 13.06 ], [ -2.58, 0.75, -0.81 ] ] ), - (20, [ [ 13.53, -164.63, 1007.59 ], [ 12.75, 0.98, 0.85 ], [ -1.47, 12.77, 7.36 ], [ -1.75, 0.42, -1.04 ], [ -0.28, -7.05, 13.49 ], [ -1.71, 0.43, -1.04 ] ] ), - (21, [ [ 26.09, -162.88, 1008.79 ], [ 12.63, 1.81, 1.23 ], [ -2.49, 13.21, 6.05 ], [ -2.26, -0.16, -1.14 ], [ -0.39, -5.90, 14.09 ], [ -2.23, -0.14, -1.14 ] ] ), - (22, [ [ 38.73, -161.01, 1010.04 ], [ 11.76, 4.53, 2.77 ], [ -6.00, 12.45, 5.07 ], [ -3.08, -0.42, -3.34 ], [ -0.85, -5.62, 14.19 ], [ -3.12, -0.44, -3.35 ] ] ), - (23, [ [ 48.79, -154.12, 1014.15 ], [ 9.86, 7.10, 4.16 ], [ -8.65, 12.37, -0.62 ], [ -1.93, -0.52, -2.09 ], [ -4.15, -2.21, 15.11 ], [ -1.97, -0.53, -2.09 ] ] ), - (24, [ [ 58.41, -146.84, 1018.34 ], [ 9.34, 7.75, 4.35 ], [ -9.86, 11.41, 0.85 ], [ -1.82, -1.10, 1.29 ], [ -3.19, -3.77, 15.02 ], [ -1.80, -1.06, 1.30 ] ] ), - (25, [ [ 67.43, -138.64, 1022.84 ], [ 7.99, 8.77, 4.67 ], [ -12.30, 10.17, 1.95 ], [ -2.50, -1.97, -0.34 ], [ -2.29, -5.48, 15.73 ], [ -2.59, -2.16, -0.41 ] ] ), - (26, [ [ 74.34, -129.42, 1027.61 ], [ 5.08, 9.97, 3.83 ], [ -14.87, 7.50, 0.22 ], [ 0.03, -2.06, 0.33 ], [ -2.33, -5.10, 16.50 ], [ -1.53, -1.17, 0.49 ] ] ), - (27, [ [ 77.56, -119.25, 1030.43 ], [ 5.04, 10.78, -0.51 ], [ -12.53, 5.98, 2.38 ], [ 0.10, 1.23, -1.77 ], [ 3.79, 1.01, 17.93 ], [ 0.40, 1.97, -2.97 ] ] ), - (28, [ [ 83.86, -109.53, 1026.21 ], [ 6.93, 6.51, -9.45 ], [ -14.97, 10.33, -3.86 ], [ -2.81, 1.30, -3.77 ], [ 6.42, 13.14, 12.02 ], [ -1.24, 0.30, -4.60 ] ] ), - (29, [ [ 89.55, -108.42, 1013.56 ], [ 3.91, 0.86, -13.16 ], [ -18.20, 8.23, -4.87 ], [ -1.85, -1.68, 0.87 ], [ 7.52, 18.71, 3.84 ], [ -2.14, -1.95, 1.17 ] ] ), - (30, [ [ 91.64, -107.83, 1000.37 ], [ 1.78, 0.55, -13.27 ], [ -18.73, 6.95, -2.22 ], [ -0.80, -1.12, 1.76 ], [ 6.79, 18.82, 1.85 ], [ -0.86, -1.12, 1.92 ] ] ), - (31, [ [ 93.10, -107.33, 987.04 ], [ 1.01, 0.30, -13.42 ], [ -19.80, 6.00, -1.36 ], [ -0.56, -0.65, 1.35 ], [ 5.95, 19.84, 0.98 ], [ -0.58, -0.66, 1.49 ] ] ), - (32, [ [ 93.66, -107.24, 973.55 ], [ -0.02, 1.05, -13.41 ], [ -19.85, 5.64, 0.47 ], [ 0.93, -2.25, 1.33 ], [ 5.66, 19.79, 1.71 ], [ 0.92, -2.27, 1.47 ] ] ), - (33, [ [ 93.06, -105.25, 960.32 ], [ -0.77, 2.25, -13.20 ], [ -17.96, 1.50, 1.30 ], [ 0.92, -2.34, 0.15 ], [ 1.70, 17.72, 3.23 ], [ 0.93, -2.36, 0.17 ] ] ), - (34, [ [ 92.12, -102.74, 947.16 ], [ -0.42, 2.82, -13.16 ], [ -18.00, 0.97, 0.78 ], [ 0.74, -0.11, -0.85 ], [ 1.11, 17.57, 4.15 ], [ 0.73, -0.09, -0.94 ] ] ), - (35, [ [ 92.23, -99.62, 934.04 ], [ 0.47, 1.78, -13.24 ], [ -16.47, 1.28, -0.41 ], [ 1.01, 0.01, -1.14 ], [ 1.22, 16.31, 2.49 ], [ 1.03, 0.02, -1.27 ] ] ), - (36, [ [ 93.04, -99.17, 920.86 ], [ 1.21, -0.74, -13.33 ], [ -15.97, 1.00, -1.51 ], [ 0.28, -0.61, 0.54 ], [ 1.07, 16.00, -0.87 ], [ 0.28, -0.69, -0.02 ] ] ), - (37, [ [ 94.65, -101.12, 907.56 ], [ -0.61, -1.62, -13.47 ], [ -15.91, 0.05, 0.71 ], [ -0.21, -1.55, 3.28 ], [ -0.04, 15.82, -2.00 ], [ -0.49, -1.71, 2.07 ] ] ), - (38, [ [ 91.84, -102.35, 894.35 ], [ -3.47, -1.64, -11.95 ], [ -16.38, -2.10, 5.05 ], [ 0.91, -2.20, 3.65 ], [ -2.64, 16.98, -1.59 ], [ -0.73, -2.58, 3.87 ] ] ), - (39, [ [ 87.88, -104.31, 883.75 ], [ -5.21, -2.13, -10.32 ], [ -14.30, -4.34, 8.12 ], [ 2.73, -2.87, 2.50 ], [ -5.97, 18.48, -0.99 ], [ 0.46, -3.19, 4.53 ] ] ), - (40, [ [ 81.45, -106.59, 873.90 ], [ -6.99, -2.14, -9.27 ], [ -10.90, -7.86, 10.04 ], [ 0.33, -3.15, 2.69 ], [ -9.26, 19.09, 1.96 ], [ 2.23, -2.67, 3.37 ] ] ), - (41, [ [ 73.98, -108.57, 865.27 ], [ -8.31, -0.22, -8.52 ], [ -13.53, -10.65, 13.47 ], [ -1.28, -1.76, 1.51 ], [ -8.01, 18.53, 7.34 ], [ 3.18, -1.46, 2.05 ] ] ), - (42, [ [ 65.06, -106.92, 857.15 ], [ -8.97, 1.81, -7.69 ], [ -13.39, -11.32, 12.96 ], [ 1.28, 0.43, -0.09 ], [ -4.01, 17.55, 11.89 ], [ 2.48, 0.16, 0.52 ] ] ), - (43, [ [ 56.07, -104.97, 849.91 ], [ -10.00, 1.92, -6.88 ], [ -11.02, -9.85, 13.27 ], [ 2.49, 5.00, 1.79 ], [ -2.03, 16.12, 10.97 ], [ 2.28, 4.69, 1.10 ] ] ), - (44, [ [ 45.11, -103.12, 843.53 ], [ -11.00, 4.81, -5.26 ], [ -8.40, -0.98, 16.68 ], [ 2.56, 4.66, 2.88 ], [ 6.12, 16.27, 4.28 ], [ 2.42, 4.35, 0.87 ] ] ), - (45, [ [ 34.86, -95.59, 839.81 ], [ -9.59, 8.68, -2.67 ], [ -5.91, -0.68, 19.02 ], [ 0.94, -0.41, 0.56 ], [ 11.03, 11.58, 3.43 ], [ 0.00, 0.16, -0.54 ] ] ), - (46, [ [ 26.14, -85.99, 838.23 ], [ -8.26, 10.16, -2.00 ], [ -6.49, -1.78, 17.83 ], [ -0.32, -0.12, -0.85 ], [ 12.91, 9.40, 5.55 ], [ -1.05, -0.47, 0.41 ] ] ), - (47, [ [ 18.39, -75.31, 835.82 ], [ -8.42, 10.08, -2.66 ], [ -6.54, -0.88, 17.32 ], [ -0.56, 0.61, 0.80 ], [ 14.15, 8.98, 5.99 ], [ -0.36, -0.28, 1.59 ] ] ), - (48, [ [ 9.35, -65.88, 832.92 ], [ -11.90, 13.24, -4.28 ], [ -7.61, -0.56, 19.43 ], [ -0.85, 0.48, 1.28 ], [ 15.89, 10.29, 6.56 ], [ -1.39, -0.78, 1.04 ] ] ), - (49, [ [ -5.12, -48.68, 827.11 ], [ -17.03, 21.16, -7.34 ], [ -8.07, 0.18, 19.25 ], [ -0.08, 1.01, -1.64 ], [ 15.89, 10.29, 6.56 ], [ -1.39, -0.78, 1.04 ] ] ) ] ), + (1, [[-87.21,-111.06,890.54], [-4.75,0.41,12.39], [23.27,-3.13,7.88], [2.46,-0.39,-2.95], [3.09,24.46,0.45], [1.83,0.46,-4.31]]), + (2, [[-89.99,-110.57,902.65], [-2.05,0.53,12.72], [24.71,-3.28,4.13], [0.07,0.14,-2.81], [3.42,25.00,-0.64], [0.43,0.10,-3.97]]), + (3, [[-91.25,-110.01,915.92], [-0.55,0.53,13.39], [23.61,-2.82,1.08], [-1.46,0.55,-1.92], [2.85,23.61,-0.91], [-1.42,0.54,-2.13]]), + (4, [[-91.08,-109.52,929.39], [0.13,0.65,13.47], [21.83,-2.10,-0.10], [-0.53,0.22,-1.06], [2.08,21.81,-1.18], [-0.53,0.21,-1.17]]), + (5, [[-91.00,-108.72,942.85], [0.83,0.67,13.37], [22.56,-2.35,-1.28], [-0.88,0.27,-1.85], [2.29,22.56,-1.42], [-0.92,0.27,-2.03]]), + (6, [[-89.43,-108.18,956.08], [2.81,0.32,13.11], [20.05,-1.51,-4.27], [-1.96,0.62,-1.35], [1.38,20.44,-0.86], [-2.00,0.62,-1.49]]), + (7, [[-85.39,-108.09,968.92], [3.10,0.44,13.08], [18.60,-0.99,-4.38], [-0.76,0.32,0.66], [0.82,19.04,-0.91], [-0.73,0.31,0.71]]), + (8, [[-83.24,-107.30,982.14], [2.05,0.85,13.23], [18.55,-0.80,-2.82], [-0.24,0.09,0.57], [0.62,18.71,-1.44], [-0.21,0.08,0.63]]), + (9, [[-81.29,-106.40,995.37], [2.32,1.34,13.29], [18.15,-0.79,-3.10], [0.14,0.24,-0.11], [0.47,18.29,-2.13], [0.05,0.31,-0.57]]), + (10, [[-78.60,-104.62,1008.65], [2.14,-1.50,13.27], [18.84,-0.25,-3.07], [-0.91,1.85,-0.22], [0.84,18.75,3.43], [-0.95,1.98,-0.15]]), + (11, [[-77.17,-109.18,1020.82], [4.07,-9.07,9.68], [16.31,3.44,-3.63], [-2.15,4.06,0.80], [-0.01,12.03,12.60], [-1.97,3.89,1.43]]), + (12, [[-71.19,-121.03,1025.58], [7.48,-11.42,0.49], [14.20,9.26,-1.14], [-1.27,2.69,3.17], [0.00,1.98,17.64], [-1.27,2.72,3.23]]), + (13, [[-63.35,-130.56,1022.18], [7.99,-9.44,-3.40], [13.31,9.97,3.60], [-0.81,0.70,2.42], [0.00,-5.47,16.79], [-0.91,0.85,2.43]]), + (14, [[-55.27,-139.84,1018.80], [8.88,-8.59,-3.55], [12.32,10.87,4.49], [-1.07,0.87,0.81], [0.00,-6.18,16.54], [-1.09,0.87,0.81]]), + (15, [[-45.66,-147.66,1015.10], [9.90,-7.39,-3.36], [10.81,11.99,5.47], [-1.63,1.38,0.03], [-0.01,-6.69,16.29], [-1.62,1.36,0.02]]), + (16, [[-35.52,-154.60,1012.08], [11.08,-6.08,-1.98], [8.54,14.06,4.58], [-1.99,1.15,0.25], [-0.01,-5.00,17.00], [-1.97,1.13,0.24]]), + (17, [[-23.71,-159.68,1011.20], [11.97,-4.32,-1.79], [6.20,14.65,6.07], [-1.74,-0.44,2.51], [0.01,-6.17,16.49], [-1.79,-0.44,2.52]]), + (18, [[-11.72,-163.20,1008.53], [12.26,-2.58,-2.06], [4.48,13.03,10.39], [-2.16,-0.11,1.44], [-0.01,-10.22,14.20], [-2.14,-0.12,1.43]]), + (19, [[0.67,-164.82,1007.10], [12.71,-0.73,-0.48], [1.18,14.35,9.43], [-2.67,0.76,-0.81], [-0.01,-8.95,15.09], [-2.58,0.75,-0.81]]), + (20, [[13.53,-164.63,1007.59], [12.75,0.98,0.85], [-1.70,14.80,8.53], [-1.75,0.42,-1.04], [-0.32,-8.14,15.58], [-1.71,0.43,-1.04]]), + (21, [[26.09,-162.88,1008.79], [12.63,1.81,1.23], [-2.89,15.32,7.02], [-2.26,-0.16,-1.14], [-0.45,-6.81,16.27], [-2.23,-0.14,-1.14]]), + (22, [[38.73,-161.01,1010.04], [11.76,4.53,2.77], [-6.96,14.45,5.88], [-3.08,-0.42,-3.34], [-0.98,-6.49,16.38], [-3.12,-0.44,-3.35]]), + (23, [[48.79,-154.12,1014.15], [9.86,7.10,4.16], [-10.00,14.30,-0.72], [-1.93,-0.52,-2.09], [-4.77,-2.54,17.36], [-1.97,-0.53,-2.09]]), + (24, [[58.41,-146.84,1018.34], [9.34,7.75,4.35], [-11.40,13.19,0.98], [-1.82,-1.10,1.29], [-3.67,-4.33,17.26], [-1.80,-1.06,1.30]]), + (25, [[67.43,-138.64,1022.84], [7.99,8.77,4.67], [-14.11,11.66,2.24], [-2.50,-1.97,-0.34], [-2.61,-6.25,17.94], [-2.59,-2.16,-0.41]]), + (26, [[74.34,-129.42,1027.61], [5.08,9.97,3.83], [-16.98,8.56,0.25], [0.03,-2.06,0.33], [-2.65,-5.79,18.73], [-1.53,-1.17,0.49]]), + (27, [[77.56,-119.25,1030.43], [5.04,10.78,-0.51], [-14.63,6.98,2.78], [0.10,1.23,-1.77], [4.28,1.14,20.24], [0.40,1.97,-2.97]]), + (28, [[83.86,-109.53,1026.21], [6.93,6.51,-9.45], [-16.87,11.64,-4.35], [-2.81,1.30,-3.77], [7.22,14.78,13.52], [-1.24,0.30,-4.60]]), + (29, [[89.55,-108.42,1013.56], [3.91,0.86,-13.16], [-20.29,9.17,-5.43], [-1.85,-1.68,0.87], [8.38,20.86,4.28], [-2.14,-1.95,1.17]]), + (30, [[91.64,-107.83,1000.37], [1.78,0.55,-13.27], [-20.93,7.77,-2.48], [-0.80,-1.12,1.76], [7.59,21.03,2.07], [-0.86,-1.12,1.92]]), + (31, [[93.10,-107.33,987.04], [1.01,0.30,-13.42], [-22.05,6.68,-1.51], [-0.56,-0.65,1.35], [6.63,22.10,1.09], [-0.58,-0.66,1.49]]), + (32, [[93.66,-107.24,973.55], [-0.02,1.05,-13.41], [-22.12,6.28,0.52], [0.93,-2.25,1.33], [6.31,22.05,1.91], [0.92,-2.27,1.47]]), + (33, [[93.06,-105.25,960.32], [-0.77,2.25,-13.20], [-20.31,1.70,1.47], [0.92,-2.34,0.15], [1.92,20.03,3.65], [0.93,-2.36,0.17]]), + (34, [[92.12,-102.74,947.16], [-0.42,2.82,-13.16], [-20.35,1.10,0.88], [0.74,-0.11,-0.85], [1.25,19.86,4.69], [0.73,-0.09,-0.94]]), + (35, [[92.23,-99.62,934.04], [0.47,1.78,-13.24], [-18.82,1.46,-0.47], [1.01,0.01,-1.14], [1.39,18.64,2.85], [1.03,0.02,-1.27]]), + (36, [[93.04,-99.17,920.86], [1.21,-0.74,-13.33], [-18.31,1.15,-1.73], [0.28,-0.61,0.54], [1.23,18.35,-1.00], [0.28,-0.69,-0.02]]), + (37, [[94.65,-101.12,907.56], [-0.61,-1.62,-13.47], [-18.27,0.06,0.82], [-0.21,-1.55,3.28], [-0.05,18.16,-2.30], [-0.49,-1.71,2.07]]), + (38, [[91.84,-102.35,894.35], [-3.47,-1.64,-11.95], [-18.62,-2.39,5.74], [0.91,-2.20,3.65], [-3.00,19.30,-1.81], [-0.73,-2.58,3.87]]), + (39, [[87.88,-104.31,883.75], [-5.21,-2.13,-10.32], [-16.28,-4.94,9.25], [2.73,-2.87,2.50], [-6.69,20.72,-1.11], [0.46,-3.19,4.53]]), + (40, [[81.45,-106.59,873.90], [-6.99,-2.14,-9.27], [-12.43,-8.97,11.45], [0.33,-3.15,2.69], [-10.29,21.20,2.18], [2.23,-2.67,3.37]]), + (41, [[73.98,-108.57,865.27], [-8.31,-0.22,-8.52], [-14.99,-11.80,14.92], [-1.28,-1.76,1.51], [-8.89,20.57,8.15], [3.18,-1.46,2.05]]), + (42, [[65.06,-106.92,857.15], [-8.97,1.81,-7.69], [-14.84,-12.55,14.36], [1.28,0.43,-0.09], [-4.45,19.47,13.19], [2.48,0.16,0.52]]), + (43, [[56.07,-104.97,849.91], [-10.00,1.92,-6.88], [-12.33,-11.02,14.85], [2.49,5.00,1.79], [-2.27,18.06,12.29], [2.28,4.69,1.10]]), + (44, [[45.11,-103.12,843.53], [-11.00,4.81,-5.26], [-9.46,-1.10,18.78], [2.56,4.66,2.88], [6.93,18.41,4.84], [2.42,4.35,0.87]]), + (45, [[34.86,-95.59,839.81], [-9.59,8.68,-2.67], [-6.61,-0.76,21.27], [0.94,-0.41,0.56], [12.62,13.25,3.92], [0.00,0.16,-0.54]]), + (46, [[26.14,-85.99,838.23], [-8.26,10.16,-2.00], [-7.29,-2.00,20.04], [-0.32,-0.12,-0.85], [14.71,10.71,6.32], [-1.05,-0.47,0.41]]), + (47, [[18.39,-75.31,835.82], [-8.42,10.08,-2.66], [-7.37,-0.99,19.53], [-0.56,0.61,0.80], [16.03,10.17,6.78], [-0.36,-0.28,1.59]]), + (48, [[9.35,-65.88,832.92], [-11.90,13.24,-4.28], [-8.47,-0.62,21.63], [-0.85,0.48,1.28], [17.76,11.50,7.33], [-1.39,-0.78,1.04]]), + (49, [[-5.12,-48.68,827.11], [-17.03,21.16,-7.34], [-8.98,0.20,21.43], [-0.08,1.01,-1.64], [17.76,11.50,7.33], [-1.39,-0.78,1.04]]) + ] ), 'userAnnotationGroups': [ { @@ -290,14 +294,15 @@ class MeshType_3d_colon1(Scaffold_base): }, 'meshEdits': exnode_string_from_nodeset_field_parameters( [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ - (1, [ [ 0.00, 0.00, 0.00 ], [ 6.00, 12.00, -2.00 ], [ 0.67, 0.33, 0.67 ], [ -0.03, 0.95, -0.68 ], [ 0.86, 0.04, -0.51 ], [ 6.00, 0.00, 3.00 ] ] ), - (2, [ [ -2.00, 11.00, -3.00 ], [ -8.00, 4.00, 9.00 ], [ 0.64, 0.64, 0.32 ], [ -0.03, -0.34, -0.02 ], [ -0.37, 0.66, -0.58 ], [ 0.00, 1.00, 2.00 ] ] ), - (3, [ [ -3.00, 2.00, 3.00 ], [ -4.00, -8.00, 0.00 ], [ 0.61, -0.30, 0.61 ], [ -0.15, -0.65, 0.01 ], [ -0.55, 0.27, 0.68 ], [ 1.00, 0.00, 2.00 ] ] ), - (4, [ [ -11.00, -3.00, -4.00 ], [ -8.00, -3.00, -7.00 ], [ 0.33, -0.67, 0.33 ], [ -0.18, -0.18, -0.31 ], [ -0.32, 0.10, 0.75 ], [ 0.00, 0.00, 0.50 ] ] ), - (5, [ [ -16.00, -4.00, 0.00 ], [ 4.00, -3.00, 14.00 ], [ 0.23, -0.70, 0.00 ], [ -0.16, -0.02, -0.19 ], [ 0.71, 0.18, 0.05 ], [ 0.00, 0.00, 0.50 ] ] ), - (6, [ [ -7.00, -8.00, 0.00 ], [ 5.00, -1.00, -14.00 ], [ 0.00, -0.70, 0.00 ], [ 0.03, 0.04, -0.12 ], [ -0.64, -0.00, -0.28 ], [ 0.00, 0.00, 0.50 ] ] ), - (7, [ [ -1.00, -6.00, -1.00 ], [ 2.00, -2.00, 9.00 ], [ 0.21, -0.63, -0.21 ], [ 0.12, 0.11, -0.23 ], [ 0.64, 0.25, -0.11 ], [ 0.00, 0.00, 0.50 ] ] ), - (8, [ [ -2.00, -14.00, 5.00 ], [ -2.00, -4.00, 2.00 ], [ 0.23, -0.47, -0.47 ], [ -0.08, 0.22, -0.28 ], [ 0.53, -0.17, 0.42 ], [ 0.00, 0.00, 0.50 ] ] ) ] ), + (1, [[0.00,0.00,0.00], [6.00,12.00,-2.00], [1.04,0.51,1.04], [-0.03,0.95,-0.68], [1.33,0.06,-0.79], [6.00,0.00,3.00]]), + (2, [[-2.00,11.00,-3.00], [-8.00,4.00,9.00], [1.01,1.01,0.50], [-0.03,-0.34,-0.02], [-0.58,1.04,-0.91], [0.00,1.00,2.00]]), + (3, [[-3.00,2.00,3.00], [-4.00,-8.00,0.00], [0.98,-0.48,0.98], [-0.15,-0.65,0.01], [-0.88,0.43,1.09], [1.00,0.00,2.00]]), + (4, [[-11.00,-3.00,-4.00], [-8.00,-3.00,-7.00], [0.55,-1.12,0.55], [-0.18,-0.18,-0.31], [-0.53,0.17,1.25], [0.00,0.00,0.50]]), + (5, [[-16.00,-4.00,0.00], [4.00,-3.00,14.00], [0.40,-1.22,0.00], [-0.16,-0.02,-0.19], [1.24,0.31,0.09], [0.00,0.00,0.50]]), + (6, [[-7.00,-8.00,0.00], [5.00,-1.00,-14.00], [0.00,-1.25,0.00], [0.03,0.04,-0.12], [-1.14,-0.00,-0.50], [0.00,0.00,0.50]]), + (7, [[-1.00,-6.00,-1.00], [2.00,-2.00,9.00], [0.38,-1.13,-0.38], [0.12,0.11,-0.23], [1.15,0.45,-0.20], [0.00,0.00,0.50]]), + (8, [[-2.00,-14.00,5.00], [-2.00,-4.00,2.00], [0.41,-0.84,-0.84], [-0.08,0.22,-0.28], [0.95,-0.30,0.75], [0.00,0.00,0.50]]) + ] ), 'userAnnotationGroups': [ { @@ -328,11 +333,12 @@ class MeshType_3d_colon1(Scaffold_base): }, 'meshEdits': exnode_string_from_nodeset_field_parameters( [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ - (1, [ [ 0.00, 0.00, 0.00 ], [ 0.00, 0.00, 13.00 ], [ 0.00, -1.00, 0.00 ], [ 0.00, 0.03, 0.00 ], [ 1.00, -0.00, 0.00 ], [ 0.00, 0.00, 0.50 ] ] ), - (2, [ [ 0.00, 0.00, 13.00 ], [ 0.00, 2.00, 28.00 ], [ 0.00, -0.96, 0.00 ], [ 0.00, 0.05, 0.00 ], [ 0.95, -0.00, -0.07 ], [ 0.00, 0.00, 0.50 ] ] ), - (3, [ [ -14.00, -2.00, 13.00 ], [ 0.00, -3.00, -19.00 ], [ 0.00, -0.88, 0.00 ], [ 0.00, 0.13, 0.00 ], [ -0.87, -0.02, -0.14 ], [ 0.00, 0.00, 0.50 ] ] ), - (4, [ [ -14.00, -1.00, -10.00 ], [ 1.00, 1.00, -17.00 ], [ 0.00, -0.70, 0.00 ], [ 0.00, 0.08, 0.00 ], [ -0.70, -0.00, -0.00 ], [ 0.00, 0.00, 0.50 ] ] ), - (5, [ [ -14.00, 0.00, -28.00 ], [ 0.00, 0.00, -11.00 ], [ 0.00, -0.70, 0.00 ], [ 0.00, -0.08, 0.00 ], [ -0.70, -0.00, 0.00 ], [ 0.00, 0.00, 0.50 ] ] ) ] ), + (1, [[0.00,0.00,0.00], [0.00,0.00,13.00], [0.00,-1.55,0.00], [0.00,0.03,0.00], [1.55,-0.00,0.00], [0.00,0.00,0.50]]), + (2, [[0.00,0.00,13.00], [0.00,2.00,28.00], [0.00,-1.51,0.00], [0.00,0.05,0.00], [1.50,-0.00,-0.11], [0.00,0.00,0.50]]), + (3, [[-14.00,-2.00,13.00], [0.00,-3.00,-19.00], [0.00,-1.43,0.00], [0.00,0.13,0.00], [-1.41,-0.03,-0.23], [0.00,0.00,0.50]]), + (4, [[-14.00,-1.00,-10.00], [1.00,1.00,-17.00], [0.00,-1.25,0.00], [0.00,0.08,0.00], [-1.25,-0.00,-0.00], [0.00,0.00,0.50]]), + (5, [[-14.00,0.00,-28.00], [0.00,0.00,-11.00], [0.00,-1.25,0.00], [0.00,-0.08,0.00], [-1.25,-0.00,0.00], [0.00,0.00,0.50]]) + ] ), 'userAnnotationGroups': [ { @@ -364,46 +370,47 @@ class MeshType_3d_colon1(Scaffold_base): }, 'meshEdits': exnode_string_from_nodeset_field_parameters( [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ - (1, [ [ -7.20, 83.30, -20.70 ], [ -65.20, -8.10, 7.60 ], [ 0.00, 0.00, 36.00 ], [ 0.00, 0.00, -0.50 ], [ -8.49, 34.98, 0.48 ], [ 0.00, 0.00, -0.50 ] ] ), - (2, [ [ -68.50, 52.80, -9.60 ], [ -40.10, -36.10, 10.70 ], [ 0.00, 0.00, 35.44 ], [ 0.00, 0.00, -0.63 ], [ -28.28, 21.31, 1.34 ], [ 0.00, 0.00, -0.63 ] ] ), - (3, [ [ -97.40, -26.30, 5.70 ], [ 18.00, -93.20, 13.70 ], [ 0.00, 0.00, 34.73 ], [ 0.00, 0.00, -0.67 ], [ -32.82, -11.34, 0.71 ], [ 0.00, 0.00, -0.67 ] ] ), - (4, [ [ -56.80, -90.50, 14.10 ], [ 65.50, -41.40, 7.30 ], [ 0.00, 0.00, 34.10 ], [ 0.00, 0.00, -0.74 ], [ -15.44, -30.39, 0.30 ], [ 0.00, 0.00, -0.74 ] ] ), - (5, [ [ 48.90, -100.80, 24.00 ], [ 112.20, 40.10, 19.00 ], [ 0.00, 0.00, 33.22 ], [ 0.00, 0.00, -0.91 ], [ 15.90, -29.15, 0.82 ], [ 0.00, 0.00, -0.91 ] ] ), - (6, [ [ 114.80, -12.60, 38.70 ], [ 8.20, 96.10, 14.20 ], [ 0.00, 0.00, 32.28 ], [ 0.00, 0.00, -0.93 ], [ 32.22, 1.92, 0.68 ], [ 0.00, 0.00, -0.93 ] ] ), - (7, [ [ 60.30, 83.50, 43.70 ], [ -108.70, 54.10, 22.40 ], [ 0.00, 0.00, 31.35 ], [ 0.00, 0.00, -0.89 ], [ 8.73, 30.09, 1.03 ], [ 0.00, 0.00, -0.89 ] ] ), - (8, [ [ -41.20, 90.70, 56.30 ], [ -89.00, -32.40, 14.40 ], [ 0.00, 0.00, 30.50 ], [ 0.00, 0.00, -0.93 ], [ -14.57, 26.79, 0.69 ], [ 0.00, 0.00, -0.93 ] ] ), - (9, [ [ -107.90, -9.70, 76.60 ], [ 11.10, -94.40, 11.30 ], [ 0.00, 0.00, 29.47 ], [ 0.00, 0.00, -0.91 ], [ -28.66, -6.85, 0.41 ], [ 0.00, 0.00, -0.91 ] ] ), - (10, [ [ -57.30, -91.90, 81.30 ], [ 71.20, -31.20, 5.70 ], [ 0.00, 0.00, 28.65 ], [ 0.00, 0.00, -0.86 ], [ -9.56, -27.01, 0.15 ], [ 0.00, 0.00, -0.86 ] ] ), - (11, [ [ 51.20, -89.40, 97.20 ], [ 99.10, 55.40, 12.90 ], [ 0.00, 0.00, 27.75 ], [ 0.00, 0.00, -0.90 ], [ 16.17, -22.55, 0.35 ], [ 0.00, 0.00, -0.90 ] ] ), - (12, [ [ 91.60, 9.30, 103.60 ], [ 4.70, 51.20, 3.40 ], [ 0.00, 0.00, 26.86 ], [ 0.00, 0.00, -0.90 ], [ 26.85, -0.69, 0.12 ], [ 0.00, 0.00, -0.90 ] ] ), - (13, [ [ 61.60, 111.80, 109.60 ], [ -85.20, 46.10, 2.60 ], [ 0.00, 0.00, 25.95 ], [ 0.00, 0.00, -0.95 ], [ 11.73, 23.14, 0.02 ], [ 0.00, 0.00, -0.95 ] ] ), - (14, [ [ -54.60, 91.90, 129.40 ], [ -92.70, -55.00, 14.50 ], [ 0.00, 0.00, 24.95 ], [ 0.00, 0.00, -0.94 ], [ -15.45, 19.58, 0.44 ], [ 0.00, 0.00, -0.94 ] ] ), - (15, [ [ -109.00, 5.60, 156.90 ], [ 23.60, -108.20, 27.70 ], [ 0.00, 0.00, 24.05 ], [ 0.00, 0.00, -0.80 ], [ -21.59, -10.51, 1.42 ], [ 0.00, 0.00, -0.80 ] ] ), - (16, [ [ -59.10, -62.50, 170.80 ], [ 74.00, -20.10, 14.40 ], [ 0.00, 0.00, 23.34 ], [ 0.00, 0.00, -0.70 ], [ -1.93, -23.24, 0.79 ], [ 0.00, 0.00, -0.70 ] ] ), - (17, [ [ 23.50, -53.20, 179.70 ], [ 84.60, 47.00, 6.90 ], [ 0.00, 0.00, 22.65 ], [ 0.00, 0.00, -0.73 ], [ 12.38, -18.97, 0.11 ], [ 0.00, 0.00, -0.73 ] ] ), - (18, [ [ 62.30, 30.10, 187.50 ], [ -12.80, 58.00, 0.80 ], [ 0.00, 0.00, 21.88 ], [ 0.00, 0.00, -0.55 ], [ 21.30, 5.00, 0.00 ], [ 0.00, 0.00, -0.55 ] ] ), - (19, [ [ 22.40, 45.20, 181.10 ], [ -23.60, -34.50, -7.40 ], [ 0.00, 0.00, 21.44 ], [ 0.00, 0.00, -0.41 ], [ -15.35, 14.96, 0.65 ], [ 0.00, 0.00, -0.41 ] ] ), - (20, [ [ -1.90, 4.90, 180.50 ], [ -41.30, -30.90, 7.50 ], [ 0.00, 0.00, 21.06 ], [ 0.00, 0.00, -0.39 ], [ -14.89, 14.89, 0.44 ], [ 0.00, 0.00, -0.39 ] ] ), - (21, [ [ -45.10, -12.60, 194.40 ], [ -40.50, -4.60, 6.90 ], [ 0.00, 0.00, 20.67 ], [ 0.00, 0.00, -0.30 ], [ -5.68, 19.87, 0.58 ], [ 0.00, 0.00, -0.30 ] ] ), - (22, [ [ -71.70, -2.20, 197.20 ], [ -25.20, 35.80, -6.80 ], [ 0.00, 0.00, 20.42 ], [ 0.00, 0.00, -0.30 ], [ 18.28, 9.08, 0.48 ], [ 0.00, 0.00, -0.30 ] ] ), - (23, [ [ -65.80, 42.10, 182.30 ], [ 26.60, 37.60, -15.60 ], [ 0.00, 0.00, 20.03 ], [ 0.00, 0.00, -0.46 ], [ 11.97, -15.92, 2.06 ], [ 0.00, 0.00, -0.46 ] ] ), - (24, [ [ -14.10, 81.20, 163.50 ], [ 41.00, 10.30, -9.50 ], [ 0.00, 0.00, 19.48 ], [ 0.00, 0.00, -0.59 ], [ 0.59, -19.44, 0.94 ], [ 0.00, 0.00, -0.59 ] ] ), - (25, [ [ 61.70, 86.10, 156.40 ], [ 77.90, -40.70, 8.90 ], [ 0.00, 0.00, 18.85 ], [ 0.00, 0.00, -0.62 ], [ -7.01, -17.50, 0.19 ], [ 0.00, 0.00, -0.62 ] ] ), - (26, [ [ 92.90, 20.50, 150.30 ], [ 0.00, -73.30, -5.20 ], [ 0.00, 0.00, 18.23 ], [ 0.00, 0.00, -0.69 ], [ -18.19, 1.29, 0.09 ], [ 0.00, 0.00, -0.69 ] ] ), - (27, [ [ 48.90, -65.00, 142.80 ], [ -82.80, -80.00, -1.90 ], [ 0.00, 0.00, 17.44 ], [ 0.00, 0.00, -0.84 ], [ -11.91, 12.74, 0.00 ], [ 0.00, 0.00, -0.84 ] ] ), - (28, [ [ -54.30, -90.80, 134.00 ], [ -60.10, 26.40, -8.20 ], [ 0.00, 0.00, 16.54 ], [ 0.00, 0.00, -0.92 ], [ 8.46, 14.21, 0.25 ], [ 0.00, 0.00, -0.92 ] ] ), - (29, [ [ -89.90, 11.20, 115.00 ], [ 34.90, 125.10, -27.90 ], [ 0.00, 0.00, 15.59 ], [ 0.00, 0.00, -0.88 ], [ 13.83, -7.18, 0.69 ], [ 0.00, 0.00, -0.88 ] ] ), - (30, [ [ -17.40, 74.20, 91.10 ], [ 78.80, 19.10, -15.40 ], [ 0.00, 0.00, 14.77 ], [ 0.00, 0.00, -0.67 ], [ 0.79, -14.74, 0.51 ], [ 0.00, 0.00, -0.67 ] ] ), - (31, [ [ 43.40, 50.20, 73.30 ], [ 30.20, -36.00, -9.90 ], [ 0.00, 0.00, 14.20 ], [ 0.00, 0.00, -0.52 ], [ -12.48, -6.73, 0.60 ], [ 0.00, 0.00, -0.52 ] ] ), - (32, [ [ 62.40, -5.10, 63.50 ], [ 10.90, -54.20, -2.70 ], [ 0.00, 0.00, 13.72 ], [ 0.00, 0.00, -0.48 ], [ -13.56, -2.05, 0.03 ], [ 0.00, 0.00, -0.48 ] ] ), - (33, [ [ 32.70, -51.70, 56.10 ], [ -38.60, -29.80, -8.10 ], [ 0.00, 0.00, 13.24 ], [ 1.37, 2.33, -1.30 ], [ -6.29, 11.65, 0.36 ], [ 1.59, 2.70, -1.41 ] ] ), - (34, [ [ -38.10, -28.60, 46.80 ], [ -62.50, 82.60, -19.20 ], [ 3.28, 5.57, 10.81 ], [ 1.59, -2.89, -2.75 ], [ 9.22, 6.17, -5.96 ], [ 1.85, -3.40, -3.08 ] ] ), - (35, [ [ 5.70, 40.40, 22.40 ], [ 144.80, 18.60, -20.50 ], [ 2.68, -8.27, 7.65 ], [ -4.75, -6.37, -4.66 ], [ 0.33, -7.82, -8.54 ], [ -5.62, -7.55, -5.37 ] ] ), - (36, [ [ 53.00, -14.70, -4.10 ], [ -6.00, -25.70, -46.70 ], [ -5.67, -8.15, 1.68 ], [ -3.78, 1.55, -1.86 ], [ -8.24, 3.65, -4.49 ], [ -4.60, 1.69, -2.12 ] ] ), - (37, [ [ 24.80, -0.40, -48.80 ], [ -13.40, 23.90, -30.60 ], [ -6.57, -5.70, 2.41 ], [ 4.46, 2.06, 2.31 ], [ -1.87, 3.95, 7.90 ], [ 5.41, 2.39, 2.88 ] ] ), - (38, [ [ -20.90, 15.30, -77.90 ], [ -51.20, -30.60, 21.10 ], [ 3.74, -4.06, 6.43 ], [ -1.12, 2.71, -1.85 ], [ -2.63, 5.93, 5.46 ], [ -1.44, 3.31, -2.27 ] ] ), - (39, [ [ -47.60, 33.90, -112.20 ], [ 32.60, 30.70, -27.80 ], [ -8.36, -0.32, -1.04 ], [ -7.25, 2.76, -6.03 ], [ -3.75, 2.25, 7.20 ], [ -8.97, 3.42, -7.45 ] ] ), - (40, [ [ 19.60, 96.00, -167.50 ], [ 19.90, 19.10, -18.40 ], [ -6.99, 0.72, -4.50 ], [ 9.97, -0.68, -0.89 ], [ -2.97, 5.84, 5.17 ], [ 12.30, -0.82, -1.11 ] ] ) ] ), + (1, [[-7.20,83.30,-20.70], [-65.20,-8.10,7.60], [0.00,0.00,38.25], [0.00,0.00,-0.50], [-9.02,37.17,0.51], [0.00,0.00,-0.50]]), + (2, [[-68.50,52.80,-9.60], [-40.10,-36.10,10.70], [0.00,0.00,37.69], [0.00,0.00,-0.63], [-30.08,22.66,1.43], [0.00,0.00,-0.63]]), + (3, [[-97.40,-26.30,5.70], [18.00,-93.20,13.70], [0.00,0.00,36.98], [0.00,0.00,-0.67], [-34.95,-12.07,0.76], [0.00,0.00,-0.67]]), + (4, [[-56.80,-90.50,14.10], [65.50,-41.40,7.30], [0.00,0.00,36.35], [0.00,0.00,-0.74], [-16.46,-32.40,0.32], [0.00,0.00,-0.74]]), + (5, [[48.90,-100.80,24.00], [112.20,40.10,19.00], [0.00,0.00,35.47], [0.00,0.00,-0.91], [16.98,-31.12,0.88], [0.00,0.00,-0.91]]), + (6, [[114.80,-12.60,38.70], [8.20,96.10,14.20], [0.00,0.00,34.53], [0.00,0.00,-0.93], [34.47,2.05,0.73], [0.00,0.00,-0.93]]), + (7, [[60.30,83.50,43.70], [-108.70,54.10,22.40], [0.00,0.00,33.60], [0.00,0.00,-0.89], [9.36,32.25,1.10], [0.00,0.00,-0.89]]), + (8, [[-41.20,90.70,56.30], [-89.00,-32.40,14.40], [0.00,0.00,32.75], [0.00,0.00,-0.93], [-15.64,28.77,0.74], [0.00,0.00,-0.93]]), + (9, [[-107.90,-9.70,76.60], [11.10,-94.40,11.30], [0.00,0.00,31.72], [0.00,0.00,-0.91], [-30.85,-7.37,0.44], [0.00,0.00,-0.91]]), + (10, [[-57.30,-91.90,81.30], [71.20,-31.20,5.70], [0.00,0.00,30.90], [0.00,0.00,-0.86], [-10.31,-29.13,0.16], [0.00,0.00,-0.86]]), + (11, [[51.20,-89.40,97.20], [99.10,55.40,12.90], [0.00,0.00,30.00], [0.00,0.00,-0.90], [17.48,-24.38,0.38], [0.00,0.00,-0.90]]), + (12, [[91.60,9.30,103.60], [4.70,51.20,3.40], [0.00,0.00,29.11], [0.00,0.00,-0.90], [29.10,-0.75,0.13], [0.00,0.00,-0.90]]), + (13, [[61.60,111.80,109.60], [-85.20,46.10,2.60], [0.00,0.00,28.20], [0.00,0.00,-0.95], [12.75,25.15,0.02], [0.00,0.00,-0.95]]), + (14, [[-54.60,91.90,129.40], [-92.70,-55.00,14.50], [0.00,0.00,27.20], [0.00,0.00,-0.94], [-16.84,21.35,0.48], [0.00,0.00,-0.94]]), + (15, [[-109.00,5.60,156.90], [23.60,-108.20,27.70], [0.00,0.00,26.30], [0.00,0.00,-0.80], [-23.61,-11.49,1.55], [0.00,0.00,-0.80]]), + (16, [[-59.10,-62.50,170.80], [74.00,-20.10,14.40], [0.00,0.00,25.59], [0.00,0.00,-0.70], [-2.12,-25.48,0.87], [0.00,0.00,-0.70]]), + (17, [[23.50,-53.20,179.70], [84.60,47.00,6.90], [0.00,0.00,24.90], [0.00,0.00,-0.73], [13.61,-20.85,0.12], [0.00,0.00,-0.73]]), + (18, [[62.30,30.10,187.50], [-12.80,58.00,0.80], [0.00,0.00,24.13], [0.00,0.00,-0.55], [23.49,5.51,0.00], [0.00,0.00,-0.55]]), + (19, [[22.40,45.20,181.10], [-23.60,-34.50,-7.40], [0.00,0.00,23.69], [0.00,0.00,-0.41], [-16.96,16.53,0.72], [0.00,0.00,-0.41]]), + (20, [[-1.90,4.90,180.50], [-41.30,-30.90,7.50], [0.00,0.00,23.31], [0.00,0.00,-0.39], [-16.48,16.48,0.49], [0.00,0.00,-0.39]]), + (21, [[-45.10,-12.60,194.40], [-40.50,-4.60,6.90], [0.00,0.00,22.92], [0.00,0.00,-0.30], [-6.30,22.03,0.64], [0.00,0.00,-0.30]]), + (22, [[-71.70,-2.20,197.20], [-25.20,35.80,-6.80], [0.00,0.00,22.67], [0.00,0.00,-0.30], [20.29,10.08,0.53], [0.00,0.00,-0.30]]), + (23, [[-65.80,42.10,182.30], [26.60,37.60,-15.60], [0.00,0.00,22.28], [0.00,0.00,-0.46], [13.31,-17.71,2.29], [0.00,0.00,-0.46]]), + (24, [[-14.10,81.20,163.50], [41.00,10.30,-9.50], [0.00,0.00,21.73], [0.00,0.00,-0.59], [0.66,-21.69,1.05], [0.00,0.00,-0.59]]), + (25, [[61.70,86.10,156.40], [77.90,-40.70,8.90], [0.00,0.00,21.10], [0.00,0.00,-0.62], [-7.85,-19.59,0.21], [0.00,0.00,-0.62]]), + (26, [[92.90,20.50,150.30], [0.00,-73.30,-5.20], [0.00,0.00,20.48], [0.00,0.00,-0.69], [-20.43,1.45,0.10], [0.00,0.00,-0.69]]), + (27, [[48.90,-65.00,142.80], [-82.80,-80.00,-1.90], [0.00,0.00,19.69], [0.00,0.00,-0.84], [-13.45,14.38,0.00], [0.00,0.00,-0.84]]), + (28, [[-54.30,-90.80,134.00], [-60.10,26.40,-8.20], [0.00,0.00,18.79], [0.00,0.00,-0.92], [9.61,16.14,0.28], [0.00,0.00,-0.92]]), + (29, [[-89.90,11.20,115.00], [34.90,125.10,-27.90], [0.00,0.00,17.84], [0.00,0.00,-0.88], [15.82,-8.22,0.79], [0.00,0.00,-0.88]]), + (30, [[-17.40,74.20,91.10], [78.80,19.10,-15.40], [0.00,0.00,17.02], [0.00,0.00,-0.67], [0.91,-16.99,0.59], [0.00,0.00,-0.67]]), + (31, [[43.40,50.20,73.30], [30.20,-36.00,-9.90], [0.00,0.00,16.45], [0.00,0.00,-0.52], [-14.46,-7.80,0.70], [0.00,0.00,-0.52]]), + (32, [[62.40,-5.10,63.50], [10.90,-54.20,-2.70], [0.00,0.00,15.97], [0.00,0.00,-0.48], [-15.78,-2.39,0.03], [0.00,0.00,-0.48]]), + (33, [[32.70,-51.70,56.10], [-38.60,-29.80,-8.10], [0.00,0.00,15.49], [1.37,2.33,-1.30], [-7.36,13.63,0.42], [1.59,2.70,-1.41]]), + (34, [[-38.10,-28.60,46.80], [-62.50,82.60,-19.20], [3.87,6.57,12.74], [1.59,-2.89,-2.75], [10.87,7.27,-7.02], [1.85,-3.40,-3.08]]), + (35, [[5.70,40.40,22.40], [144.80,18.60,-20.50], [3.20,-9.88,9.14], [-4.75,-6.37,-4.66], [0.39,-9.34,-10.20], [-5.62,-7.55,-5.37]]), + (36, [[53.00,-14.70,-4.10], [-6.00,-25.70,-46.70], [-6.94,-9.97,2.06], [-3.78,1.55,-1.86], [-10.08,4.47,-5.49], [-4.60,1.69,-2.12]]), + (37, [[24.80,-0.40,-48.80], [-13.40,23.90,-30.60], [-8.21,-7.12,3.01], [4.46,2.06,2.31], [-2.34,4.93,9.87], [5.41,2.39,2.88]]), + (38, [[-20.90,15.30,-77.90], [-51.20,-30.60,21.10], [4.73,-5.14,8.14], [-1.12,2.71,-1.85], [-3.33,7.50,6.91], [-1.44,3.31,-2.27]]), + (39, [[-47.60,33.90,-112.20], [32.60,30.70,-27.80], [-10.59,-0.41,-1.32], [-7.25,2.76,-6.03], [-4.75,2.85,9.12], [-8.97,3.42,-7.45]]), + (40, [[19.60,96.00,-167.50], [19.90,19.10,-18.40], [-8.87,0.91,-5.71], [9.97,-0.68,-0.89], [-3.77,7.41,6.56], [12.30,-0.82,-1.11]]) + ] ), 'userAnnotationGroups': [ { @@ -497,10 +504,10 @@ def getDefaultOptions(cls, parameterSetName='Default'): options['Number of segments'] = 33 elif 'Mouse' in parameterSetName: options['Number of segments'] = 10 - options['Proximal tenia coli width'] = 0.5 - options['Proximal-transverse tenia coli width'] = 0.5 - options['Transverse-distal tenia coli width'] = 0.5 - options['Distal tenia coli width'] = 0.5 + options['Proximal tenia coli width'] = 0.77 + options['Proximal-transverse tenia coli width'] = 0.8 + options['Transverse-distal tenia coli width'] = 0.9 + options['Distal tenia coli width'] = 0.9 elif 'Pig 1' in parameterSetName: options['Number of segments'] = 120 options['Proximal tenia coli width'] = 5.0 @@ -603,8 +610,8 @@ def generateBaseMesh(cls, region, options): 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'] + cornerOuterRadiusFactor = segmentSettings['Corner outer radius factor'] + haustrumOuterRadiusFactor = segmentSettings['Haustrum outer radius factor'] segmentLengthEndDerivativeFactor = segmentSettings['Segment length end derivative factor'] segmentLengthMidDerivativeFactor = segmentSettings['Segment length mid derivative factor'] tcCount = segmentSettings['Number of tenia coli'] @@ -727,13 +734,13 @@ def generateBaseMesh(cls, region, options): lengthList = [0.0, arcLengthOfGroupsAlong[1], arcLengthOfGroupsAlong[1] + arcLengthOfGroupsAlong[2], arcLengthOfGroupsAlong[0]] - innerRadiusListCP = [vector.magnitude(c) for c in cd2] - dInnerRadiusListCP = [] - for n in range(len(innerRadiusListCP) - 1): - dInnerRadiusListCP.append(innerRadiusListCP[n + 1] - innerRadiusListCP[n]) - dInnerRadiusListCP.append(innerRadiusListCP[-1] - innerRadiusListCP[-2]) - innerRadiusAlongElementList, dInnerRadiusAlongElementList = interp.interpolateSampleCubicHermite( - innerRadiusListCP, dInnerRadiusListCP, se, sxi, ssf) + outerRadiusListCP = [vector.magnitude(c) for c in cd2] + dOuterRadiusListCP = [] + for n in range(len(outerRadiusListCP) - 1): + dOuterRadiusListCP.append(outerRadiusListCP[n + 1] - outerRadiusListCP[n]) + dOuterRadiusListCP.append(outerRadiusListCP[-1] - outerRadiusListCP[-2]) + outerRadiusAlongElementList, dOuterRadiusAlongElementList = interp.interpolateSampleCubicHermite( + outerRadiusListCP, dOuterRadiusListCP, se, sxi, ssf) tcWidthList = [proximalTCWidth, proximalTransverseTCWidth, transverseDistalTCWidth, distalTCWidth] tcWidthAlongElementList, dTCWidthAlongElementList = interp.sampleParameterAlongLine(lengthList, @@ -742,12 +749,12 @@ def generateBaseMesh(cls, region, options): # 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] + haustrumOuterRadiusFactorList = [haustrumOuterRadiusFactor, haustrumOuterRadiusFactor * 0.75, + haustrumOuterRadiusFactor * 0.5, haustrumOuterRadiusFactor * 0.2] + haustrumOuterRadiusFactorAlongElementList = \ + interp.sampleParameterAlongLine(lengthList, haustrumOuterRadiusFactorList, elementsCountAlong)[0] else: - haustrumInnerRadiusFactorAlongElementList = [haustrumInnerRadiusFactor] * (elementsCountAlong + 1) + haustrumOuterRadiusFactorAlongElementList = [haustrumOuterRadiusFactor] * (elementsCountAlong + 1) # Create annotation groups for colon sections colonGroup = AnnotationGroup(region, get_colon_term("colon")) @@ -802,29 +809,29 @@ def generateBaseMesh(cls, region, options): [circularMuscleGroup], [longitudinalMuscleGroup]] # Create object - colonSegmentTubeMeshInnerPoints = ColonSegmentTubeMeshInnerPoints( + colonSegmentTubeMeshOuterPoints = ColonSegmentTubeMeshOuterPoints( region, elementsCountAroundTC, elementsCountAroundHaustrum, elementsCountAlongSegment, tcCount, segmentLengthEndDerivativeFactor, segmentLengthMidDerivativeFactor, - segmentLength, wallThickness, cornerInnerRadiusFactor, haustrumInnerRadiusFactorAlongElementList, - innerRadiusAlongElementList, dInnerRadiusAlongElementList, tcWidthAlongElementList, + segmentLength, wallThickness, cornerOuterRadiusFactor, haustrumOuterRadiusFactorAlongElementList, + outerRadiusAlongElementList, dOuterRadiusAlongElementList, tcWidthAlongElementList, startPhase) for nSegment in range(segmentCount): # Create inner points - xInner, d1Inner, d2Inner, transitElementList, segmentAxis, annotationGroupsAround \ - = colonSegmentTubeMeshInnerPoints.getColonSegmentTubeMeshInnerPoints(nSegment) + xOuter, d1Outer, d2Outer, transitElementList, segmentAxis, annotationGroupsAround \ + = colonSegmentTubeMeshOuterPoints.getColonSegmentTubeMeshOuterPoints(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, + tubemesh.getPlaneProjectionOnCentralPath(xOuter, 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, + xOuter, d1Outer, d2Outer, segmentAxis, sxRefList, sd1RefList, sd2ProjectedListRef, elementsCountAround, elementsCountAlongSegment, zRefList) # Store points along length @@ -834,20 +841,21 @@ def generateBaseMesh(cls, region, options): d3UnitExtrude += d3WarpedUnitList if nSegment == 0 else d3WarpedUnitList[elementsCountAround:] sxRefExtrudeList += sxRefList if nSegment == 0 else sxRefList[elementsCountAround:] - contractedWallThicknessList = colonSegmentTubeMeshInnerPoints.getContractedWallThicknessList() + contractedWallThicknessList = colonSegmentTubeMeshOuterPoints.getContractedWallThicknessList() # Create coordinates and derivatives - xList, d1List, d2List, d3List, curvatureList = tubemesh.extrudeSurfaceCoordinates(xExtrude, d1Extrude, - d2Extrude, d3UnitExtrude, contractedWallThicknessList, relativeThicknessList, - elementsCountAround, elementsCountAlong, elementsCountThroughWall, transitElementList, - outward=True) + xList, d1List, d2List, d3List, curvatureList = \ + tubemesh.extrudeSurfaceCoordinates(xExtrude, d1Extrude, d2Extrude, d3UnitExtrude, + contractedWallThicknessList, relativeThicknessList, + elementsCountAround, elementsCountAlong, elementsCountThroughWall, + transitElementList, outward=False) - relaxedLengthList, xiList = colonSegmentTubeMeshInnerPoints.getRelaxedLengthAndXiList() + relaxedLengthList, xiList = colonSegmentTubeMeshOuterPoints.getRelaxedLengthAndXiList() closedProximalEnd = False if tcThickness > 0: - tubeTCWidthList = colonSegmentTubeMeshInnerPoints.getTubeTCWidthList() + tubeTCWidthList = colonSegmentTubeMeshOuterPoints.getTubeTCWidthList() xList, d1List, d2List, d3List, annotationArrayAround = getTeniaColi( region, xList, d1List, d2List, d3List, curvatureList, tcCount, elementsCountAroundTC, elementsCountAroundHaustrum, elementsCountAlong, elementsCountThroughWall, diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_colonsegment1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_colonsegment1.py index 2e5279b7..1d19ac47 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_colonsegment1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_colonsegment1.py @@ -62,20 +62,20 @@ def getDefaultOptions(parameterSetName='Default'): 'Number of elements along segment': 4, 'Number of elements through wall': 4, 'Start phase': 0.0, - 'Start inner radius': 43.5, - 'Start inner radius derivative': 0.0, - 'End inner radius': 33.0, - 'End inner radius derivative': 0.0, - 'Corner inner radius factor': 0.5, - 'Haustrum inner radius factor': 0.5, + 'Start outer radius': 45.4, + 'Start outer radius derivative': 0.0, + 'End outer radius': 35.3, + 'End outer radius derivative': 0.0, + 'Corner outer radius factor': 0.536, + 'Haustrum outer radius factor': 0.464, 'Segment length end derivative factor': 0.5, 'Segment length mid derivative factor': 3.0, 'Segment length': 50.0, 'Number of tenia coli': 3, - 'Start tenia coli width': 10.0, - 'Start tenia coli width derivative': 0.0, - 'End tenia coli width': 10.0, - 'End tenia coli width derivative': 0.0, + 'Start tenia coli width': 11.1, + 'Start tenia coli width derivative': 0.4, + 'End tenia coli width': 11.5, + 'End tenia coli width derivative': 0.4, 'Tenia coli thickness': 0.6, 'Wall thickness': 1.6, 'Mucosa relative thickness': 0.18, @@ -90,30 +90,30 @@ def getDefaultOptions(parameterSetName='Default'): 'Refine number of elements through wall': 1 } if 'Cattle' in parameterSetName: - options['Start inner radius'] = 10.5 - options['End inner radius'] = 10.5 - options['Corner inner radius factor'] = 0.0 - options['Haustrum inner radius factor'] = 0.0 + options['Start outer radius'] = 13.52 + options['End outer radius'] = 13.52 + options['Corner outer radius factor'] = 0.0 + options['Haustrum outer radius factor'] = 0.0 options['Segment length end derivative factor'] = 0.0 options['Segment length mid derivative factor'] = 0.0 options['Number of tenia coli'] = 1 - options['Start tenia coli width'] = 3.0 - options['End tenia coli width'] = 3.0 + options['Start tenia coli width'] = 3.85 + options['End tenia coli width'] = 3.85 options['Tenia coli thickness'] = 0.0 options['Wall thickness'] = 3.02 elif 'Human 2' in parameterSetName: - options['Haustrum inner radius factor'] = 0.4 + options['Haustrum outer radius factor'] = 0.364 options['Tenia coli thickness'] = 1.6 elif 'Mouse' in parameterSetName: - options['Start inner radius'] = 0.94 - options['End inner radius'] = 0.94 - options['Corner inner radius factor'] = 0.0 - options['Haustrum inner radius factor'] = 0.0 + options['Start outer radius'] = 1.49 + options['End outer radius'] = 1.49 + options['Corner outer radius factor'] = 0.0 + options['Haustrum outer radius factor'] = 0.0 options['Segment length end derivative factor'] = 0.0 options['Segment length mid derivative factor'] = 0.0 options['Number of tenia coli'] = 1 - options['Start tenia coli width'] = 0.8 - options['End tenia coli width'] = 0.8 + options['Start tenia coli width'] = 1.29 + options['End tenia coli width'] = 1.29 options['Tenia coli thickness'] = 0.0 options['Wall thickness'] = 0.55 options['Mucosa relative thickness'] = 0.4 @@ -121,16 +121,16 @@ def getDefaultOptions(parameterSetName='Default'): options['Circular muscle layer relative thickness'] = 0.3 options['Longitudinal muscle layer relative thickness'] = 0.2 elif 'Pig' in parameterSetName: - options['Start inner radius'] = 20.0 - options['End inner radius'] = 20.0 - options['Corner inner radius factor'] = 0.0 - options['Haustrum inner radius factor'] = 0.2 + options['Start outer radius'] = 22.23 + options['End outer radius'] = 22.23 + options['Corner outer radius factor'] = 0.0 + options['Haustrum outer radius factor'] = 0.17 options['Segment length end derivative factor'] = 0.8 options['Segment length mid derivative factor'] = 2.0 options['Segment length'] = 25.0 options['Number of tenia coli'] = 2 - options['Start tenia coli width'] = 5.0 - options['End tenia coli width'] = 5.0 + options['Start tenia coli width'] = 5.5 + options['End tenia coli width'] = 5.5 options['Tenia coli thickness'] = 0.5 options['Wall thickness'] = 2.0 options['Mucosa relative thickness'] = 0.34 @@ -148,12 +148,12 @@ def getOrderedOptionNames(): 'Number of elements along segment', 'Number of elements through wall', 'Start phase', - 'Start inner radius', - 'Start inner radius derivative', - 'End inner radius', - 'End inner radius derivative', - 'Corner inner radius factor', - 'Haustrum inner radius factor', + 'Start outer radius', + 'Start outer radius derivative', + 'End outer radius', + 'End outer radius derivative', + 'Corner outer radius factor', + 'Haustrum outer radius factor', 'Segment length end derivative factor', 'Segment length mid derivative factor', 'Segment length', @@ -199,9 +199,9 @@ def checkOptions(options): if options[key] % 2 > 0: options[key] = options[key] + 1 for key in [ - 'Start inner radius', - 'End inner radius', - 'Haustrum inner radius factor', + 'Start outer radius', + 'End outer radius', + 'Haustrum outer radius factor', 'Segment length end derivative factor', 'Segment length mid derivative factor', 'Segment length', @@ -213,10 +213,10 @@ def checkOptions(options): 'Longitudinal muscle layer relative thickness']: if options[key] < 0.0: options[key] = 0.0 - if options['Corner inner radius factor'] < 0.1: - options['Corner inner radius factor'] = 0.1 + if options['Corner outer radius factor'] < 0.1: + options['Corner outer radius factor'] = 0.1 for key in [ - 'Corner inner radius factor', + 'Corner outer radius factor', 'Segment length end derivative factor']: if options[key] > 1.0: options[key] = 1.0 @@ -227,12 +227,12 @@ def checkOptions(options): for key in [ 'Start tenia coli width', 'End tenia coli width']: - if options[key] < 0.2 * min(options['Start inner radius'], options['End inner radius']): - options[key] = round(0.2 * min(options['Start inner radius'], options['End inner radius']), 2) - if options['Start tenia coli width'] > round(math.sqrt(3) * 0.5 * options['Start inner radius'], 2): - options['Start tenia coli width'] = round(math.sqrt(3) * 0.5 * options['Start inner radius'], 2) - if options['End tenia coli width'] > round(math.sqrt(3) * 0.5 * options['End inner radius'], 2): - options['End tenia coli width'] = round(math.sqrt(3) * 0.5 * options['End inner radius'], 2) + if options[key] < 0.2 * min(options['Start outer radius'], options['End outer radius']): + options[key] = round(0.2 * min(options['Start outer radius'], options['End outer radius']), 2) + if options['Start tenia coli width'] > round(math.sqrt(3) * 0.5 * options['Start outer radius'], 2): + options['Start tenia coli width'] = round(math.sqrt(3) * 0.5 * options['Start outer radius'], 2) + if options['End tenia coli width'] > round(math.sqrt(3) * 0.5 * options['End outer radius'], 2): + options['End tenia coli width'] = round(math.sqrt(3) * 0.5 * options['End outer radius'], 2) @classmethod def generateBaseMesh(cls, region, options): @@ -247,12 +247,12 @@ def generateBaseMesh(cls, region, options): elementsCountAlongSegment = options['Number of elements along segment'] elementsCountThroughWall = options['Number of elements through wall'] startPhase = options['Start phase'] % 360.0 - startRadius = options['Start inner radius'] - startRadiusDerivative = options['Start inner radius derivative'] - endRadius = options['End inner radius'] - endRadiusDerivative = options['End inner radius derivative'] - cornerInnerRadiusFactor = options['Corner inner radius factor'] - haustrumInnerRadiusFactor = options['Haustrum inner radius factor'] + startRadius = options['Start outer radius'] + startRadiusDerivative = options['Start outer radius derivative'] + endRadius = options['End outer radius'] + endRadiusDerivative = options['End outer radius derivative'] + cornerOuterRadiusFactor = options['Corner outer radius factor'] + haustrumOuterRadiusFactor = options['Haustrum outer radius factor'] segmentLengthEndDerivativeFactor = options['Segment length end derivative factor'] segmentLengthMidDerivativeFactor = options['Segment length mid derivative factor'] segmentLength = options['Segment length'] @@ -300,12 +300,12 @@ def generateBaseMesh(cls, region, options): [endTCWidth], [endTCWidthDerivative], xi)[0] tcWidthAlongSegment.append(tcWidth) - haustrumInnerRadiusFactorAlongSegment = [haustrumInnerRadiusFactor] * (elementsCountAlongSegment + 1) + haustrumOuterRadiusFactorAlongSegment = [haustrumOuterRadiusFactor] * (elementsCountAlongSegment + 1) - colonSegmentTubeMeshInnerPoints = ColonSegmentTubeMeshInnerPoints( + colonSegmentTubeMeshOuterPoints = ColonSegmentTubeMeshOuterPoints( region, elementsCountAroundTC, elementsCountAroundHaustrum, elementsCountAlongSegment, tcCount, segmentLengthEndDerivativeFactor, segmentLengthMidDerivativeFactor, - segmentLength, wallThickness, cornerInnerRadiusFactor, haustrumInnerRadiusFactorAlongSegment, + segmentLength, wallThickness, cornerOuterRadiusFactor, haustrumOuterRadiusFactorAlongSegment, radiusAlongSegment, dRadiusAlongSegment, tcWidthAlongSegment, startPhase) # Create annotation @@ -314,24 +314,24 @@ def generateBaseMesh(cls, region, options): for i in range(elementsCountAlongSegment): annotationGroupsAlong.append([colonGroup]) - # Create inner points + # Create outer points nSegment = 0 closedProximalEnd = False - xInner, d1Inner, d2Inner, transitElementList, segmentAxis, annotationGroupsAround = \ - colonSegmentTubeMeshInnerPoints.getColonSegmentTubeMeshInnerPoints(nSegment) + xOuter, d1Outer, d2Outer, transitElementList, segmentAxis, annotationGroupsAround = \ + colonSegmentTubeMeshOuterPoints.getColonSegmentTubeMeshOuterPoints(nSegment) # Project reference point for warping onto central path sxRefList, sd1RefList, sd2ProjectedListRef, zRefList = \ - tubemesh.getPlaneProjectionOnCentralPath(xInner, elementsCountAround, elementsCountAlongSegment, + tubemesh.getPlaneProjectionOnCentralPath(xOuter, elementsCountAround, elementsCountAlongSegment, segmentLength, sx, sd1, sd2, sd12) # Warp segment points xWarpedList, d1WarpedList, d2WarpedList, d3WarpedUnitList = tubemesh.warpSegmentPoints( - xInner, d1Inner, d2Inner, segmentAxis, sxRefList, sd1RefList, sd2ProjectedListRef, + xOuter, d1Outer, d2Outer, segmentAxis, sxRefList, sd1RefList, sd2ProjectedListRef, elementsCountAround, elementsCountAlongSegment, zRefList) - contractedWallThicknessList = colonSegmentTubeMeshInnerPoints.getContractedWallThicknessList() + contractedWallThicknessList = colonSegmentTubeMeshOuterPoints.getContractedWallThicknessList() if elementsCountThroughWall == 1: relativeThicknessList = [1.0] @@ -351,14 +351,14 @@ def generateBaseMesh(cls, region, options): tubemesh.extrudeSurfaceCoordinates(xWarpedList, d1WarpedList, d2WarpedList, d3WarpedUnitList, contractedWallThicknessList, relativeThicknessList, elementsCountAround, elementsCountAlongSegment, elementsCountThroughWall, transitElementList, - outward=True) + outward=False) xColonSegment = d1ColonSegment = d2ColonSegment = [] - relaxedLengthList, xiList = colonSegmentTubeMeshInnerPoints.getRelaxedLengthAndXiList() + relaxedLengthList, xiList = colonSegmentTubeMeshOuterPoints.getRelaxedLengthAndXiList() if tcThickness > 0: - tubeTCWidthList = colonSegmentTubeMeshInnerPoints.getTubeTCWidthList() + tubeTCWidthList = colonSegmentTubeMeshOuterPoints.getTubeTCWidthList() xList, d1List, d2List, d3List, annotationGroupsAround = getTeniaColi( region, xList, d1List, d2List, d3List, curvatureList, tcCount, elementsCountAroundTC, elementsCountAroundHaustrum, elementsCountAlongSegment, elementsCountThroughWall, @@ -436,16 +436,16 @@ def defineFaceAnnotations(cls, region, options, annotationGroups): mucosaInnerSurface.getMeshGroup(mesh2d).addElementsConditional(is_mucosaInnerSurface) -class ColonSegmentTubeMeshInnerPoints: +class ColonSegmentTubeMeshOuterPoints: """ - Generates inner profile of a colon segment for use by tubemesh. + Generates outer profile of a colon segment for use by tubemesh. """ def __init__(self, region, elementsCountAroundTC, elementsCountAroundHaustrum, elementsCountAlongSegment, tcCount, segmentLengthEndDerivativeFactor, segmentLengthMidDerivativeFactor, segmentLength, wallThickness, - cornerInnerRadiusFactor, haustrumInnerRadiusFactorAlongElementList, innerRadiusAlongElementList, - dInnerRadiusAlongElementList, tcWidthAlongElementList, startPhase): + cornerOuterRadiusFactor, haustrumOuterRadiusFactorAlongElementList, outerRadiusAlongElementList, + dOuterRadiusAlongElementList, tcWidthAlongElementList, startPhase): self._region = region self._elementsCountAroundTC = elementsCountAroundTC self._elementsCountAroundHaustrum = elementsCountAroundHaustrum @@ -455,10 +455,10 @@ def __init__(self, region, elementsCountAroundTC, elementsCountAroundHaustrum, self._segmentLengthMidDerivativeFactor = segmentLengthMidDerivativeFactor self._segmentLength = segmentLength self._wallThickness = wallThickness - self._cornerInnerRadiusFactor = cornerInnerRadiusFactor - self._haustrumInnerRadiusFactorAlongElementList = haustrumInnerRadiusFactorAlongElementList - self._innerRadiusAlongElementList = innerRadiusAlongElementList - self._dInnerRadiusAlongElementList = dInnerRadiusAlongElementList + self._cornerOuterRadiusFactor = cornerOuterRadiusFactor + self._haustrumOuterRadiusFactorAlongElementList = haustrumOuterRadiusFactorAlongElementList + self._outerRadiusAlongElementList = outerRadiusAlongElementList + self._dOuterRadiusAlongElementList = dOuterRadiusAlongElementList self._tcWidthAlongElementList = tcWidthAlongElementList self._tubeTCWidthList = [] self._xiList = [] @@ -466,27 +466,27 @@ def __init__(self, region, elementsCountAroundTC, elementsCountAroundHaustrum, self._contractedWallThicknessList = [] self._startPhase = startPhase - def getColonSegmentTubeMeshInnerPoints(self, nSegment): + def getColonSegmentTubeMeshOuterPoints(self, nSegment): # Unpack parameter variation along elements - radiusSegmentList = self._innerRadiusAlongElementList[nSegment * self._elementsCountAlongSegment: + radiusSegmentList = self._outerRadiusAlongElementList[nSegment * self._elementsCountAlongSegment: (nSegment + 1) * self._elementsCountAlongSegment + 1] - dRadiusSegmentList = self._dInnerRadiusAlongElementList[nSegment * self._elementsCountAlongSegment: + dRadiusSegmentList = self._dOuterRadiusAlongElementList[nSegment * self._elementsCountAlongSegment: (nSegment + 1) * self._elementsCountAlongSegment + 1] tcWidthSegmentList = self._tcWidthAlongElementList[nSegment * self._elementsCountAlongSegment: (nSegment + 1) * self._elementsCountAlongSegment + 1] - haustrumInnerRadiusFactorSegmentList = self._haustrumInnerRadiusFactorAlongElementList[ + haustrumOuterRadiusFactorSegmentList = self._haustrumOuterRadiusFactorAlongElementList[ nSegment * self._elementsCountAlongSegment: (nSegment + 1) * self._elementsCountAlongSegment + 1] - xInner, d1Inner, d2Inner, transitElementList, xiSegment, relaxedLengthSegment, contractedWallThicknessSegment, \ + xOuter, d1Outer, d2Outer, transitElementList, xiSegment, relaxedLengthSegment, contractedWallThicknessSegment, \ segmentAxis, annotationGroupsAround = \ - getColonSegmentInnerPoints(self._region, + getColonSegmentOuterPoints(self._region, self._elementsCountAroundTC, self._elementsCountAroundHaustrum, self._elementsCountAlongSegment, self._tcCount, self._segmentLengthEndDerivativeFactor, self._segmentLengthMidDerivativeFactor, self._segmentLength, self._wallThickness, - self._cornerInnerRadiusFactor, haustrumInnerRadiusFactorSegmentList, + self._cornerOuterRadiusFactor, haustrumOuterRadiusFactorSegmentList, radiusSegmentList, dRadiusSegmentList, tcWidthSegmentList, self._startPhase) @@ -503,7 +503,7 @@ def getColonSegmentTubeMeshInnerPoints(self, nSegment): contractedWallThickness = contractedWallThicknessSegment[startIdx:self._elementsCountAlongSegment + 1] self._contractedWallThicknessList += contractedWallThickness - return xInner, d1Inner, d2Inner, transitElementList, segmentAxis, annotationGroupsAround + return xOuter, d1Outer, d2Outer, transitElementList, segmentAxis, annotationGroupsAround def getTubeTCWidthList(self): return self._tubeTCWidthList @@ -515,10 +515,10 @@ def getContractedWallThicknessList(self): return self._contractedWallThicknessList -def getColonSegmentInnerPoints(region, elementsCountAroundTC, elementsCountAroundHaustrum, elementsCountAlongSegment, +def getColonSegmentOuterPoints(region, elementsCountAroundTC, elementsCountAroundHaustrum, elementsCountAlongSegment, tcCount, segmentLengthEndDerivativeFactor, segmentLengthMidDerivativeFactor, - segmentLength, wallThickness, cornerInnerRadiusFactor, - haustrumInnerRadiusFactorSegmentList, radiusSegmentList, dRadiusSegmentList, + segmentLength, wallThickness, cornerOuterRadiusFactor, + haustrumOuterRadiusFactorSegmentList, radiusSegmentList, dRadiusSegmentList, tcWidthSegmentList, startPhase): """ Generates a 3-D colon segment mesh with variable numbers of tenia coli, @@ -539,22 +539,22 @@ def getColonSegmentInnerPoints(region, elementsCountAroundTC, elementsCountAroun length to scale derivative along the mid length of the segment. :param segmentLength: Length of a colon segment. :param wallThickness: Thickness of wall. - :param cornerInnerRadiusFactor: Roundness of triangular corners of - inter-haustral septa. Factor is multiplied by inner radius + :param cornerOuterRadiusFactor: Roundness of triangular corners of + inter-haustral septa. Factor is multiplied by outer radius to get a radius of curvature at the corners. Only applicable for three tenia coli. Set to zero for two tenia coli. - :param haustrumInnerRadiusFactorSegmentList: Factor is multiplied by inner + :param haustrumOuterRadiusFactorSegmentList: Factor is multiplied by inner radius to obtain radius of intersecting circles in the middle cross-section along a haustra segment. :param radiusSegmentList: List of inner radius defined from center of triangular profile to vertex of the triangle at proximal end of the colon segment for each element along. - :param dRadiusSegmentList: List of rate of change of inner radius at proximal end + :param dRadiusSegmentList: List of rate of change of outer radius at proximal end for each element along. :param tcWidthSegmentList: List of tenia coli width at proximal end of the colon segment for each element along. :param startPhase: Phase at start. - :return coordinates, derivatives on inner surface of a colon segment. + :return coordinates, derivatives on outer surface of a colon segment. :return transitElementList: stores true if element around is an element that transits from tenia coli / mesenteric zone to haustrum / non-mesenteric zone. :return xiList: List of xi for each node around. xi refers to node position @@ -580,8 +580,8 @@ def getColonSegmentInnerPoints(region, elementsCountAroundTC, elementsCountAroun d2HalfSet = [] d2Raw = [] - xInnerRaw = [] - dx_ds2InnerRaw = [] + xOuterRaw = [] + dx_ds2OuterRaw = [] xFinal = [] d1Final = [] d2Final = [] @@ -600,7 +600,7 @@ def getColonSegmentInnerPoints(region, elementsCountAroundTC, elementsCountAroun xHalfSet, d1HalfSet = \ createHalfSetInterHaustralSegment(elementsCountAroundTC, elementsCountAroundHaustrum, tcCount, tcWidth, - radius, cornerInnerRadiusFactor, sampleElementOut) + radius, cornerOuterRadiusFactor, sampleElementOut) for i in range(len(xHalfSet)): d2HalfSet.append([0.0, 0.0, 0.0]) @@ -611,8 +611,7 @@ def getColonSegmentInnerPoints(region, elementsCountAroundTC, elementsCountAroun for n1 in range(elementsCountAroundTC + elementsCountAroundHaustrum): xFinal.append([x[n1][0], x[n1][1], z]) xFace.append([x[n1][0], x[n1][1], z]) - xiFace, lengthAroundFace = getXiListFromOuterLengthProfile(xFace, d1, segmentAxis, - wallThickness, transitElementList) + xiFace, lengthAroundFace = getXiListFromOuterLengthProfile(xFace, d1) xiList.append(xiFace) relaxedLengthList.append(lengthAroundFace) contractedWallThicknessList.append(wallThickness) @@ -658,13 +657,13 @@ def getColonSegmentInnerPoints(region, elementsCountAroundTC, elementsCountAroun radius = radiusSegmentList[n2] sdRadius = dRadiusSegmentList[n2] tcWidth = tcWidthSegmentList[n2] - haustrumInnerRadiusFactor = haustrumInnerRadiusFactorSegmentList[n2] + haustrumOuterRadiusFactor = haustrumOuterRadiusFactorSegmentList[n2] # Create segment of inner radius # Calculate x and d1 at the start, mid, and end faces xHalfSetStart, d1HalfSetStart = createHalfSetInterHaustralSegment( elementsCountAroundTC, elementsCountAroundHaustrum, tcCount, tcWidth, radius, - cornerInnerRadiusFactor, sampleElementOut) + cornerOuterRadiusFactor, sampleElementOut) if startPhase == 0.0: if n2 == 0: @@ -678,7 +677,7 @@ def getColonSegmentInnerPoints(region, elementsCountAroundTC, elementsCountAroun xHalfSetMid, d1HalfSetMid = createHalfSetIntraHaustralSegment( elementsCountAroundTC, elementsCountAroundHaustrum, tcCount, tcWidth, radius, - cornerInnerRadiusFactor, sampleElementOut, haustrumInnerRadiusFactor) + cornerOuterRadiusFactor, sampleElementOut, haustrumOuterRadiusFactor) d1AtStartOfEachMidFace.append(d1HalfSetMid[0]) @@ -760,8 +759,8 @@ def getColonSegmentInnerPoints(region, elementsCountAroundTC, elementsCountAroun xResampled, d1Resampled, se, sxi, _ = interp.sampleCubicHermiteCurves(xForSamplingAlong, d1ForSamplingAlong, elementsCountAlongSegment, arcLengthDerivatives=True) - xInnerRaw.append(xResampled) - dx_ds2InnerRaw.append(d1Resampled) + xOuterRaw.append(xResampled) + dx_ds2OuterRaw.append(d1Resampled) # Re-arrange sample order & calculate dx_ds1 and dx_ds3 from dx_ds2 for n2 in range(elementsCountAlongSegment + 1): @@ -771,26 +770,26 @@ def getColonSegmentInnerPoints(region, elementsCountAroundTC, elementsCountAroun d2Around = [] for n1 in range(elementsCountAroundHalfHaustrum + 1): - x = xInnerRaw[n1][n2] + x = xOuterRaw[n1][n2] # Bring first face back to origin x = [x[0], x[1], x[2] - lengthToFirstPhase] - dx_ds2 = dx_ds2InnerRaw[n1][n2] + dx_ds2 = dx_ds2OuterRaw[n1][n2] xAround.append(x) d2Around.append(dx_ds2) - dx_ds1InnerAroundList = [] + dx_ds1OuterAroundList = [] if startPhase == 0.0 and n2 == 0: d1Corrected = d1Phase0FirstFace elif startPhase == 0.0 and elementsCountAlongSegment % 2 == 0 and \ n2 == int(elementsCountAlongSegment * 0.5): - dx_ds1InnerAroundList = dx_ds1InnerAroundList + d1Phase0MidFace + dx_ds1OuterAroundList = dx_ds1OuterAroundList + d1Phase0MidFace elif startPhase == 0.0 and n2 > elementsCountAlongSegment - 1: d1Corrected = d1Phase0LastFace elif startPhase == 180.0 and n2 == 0: - dx_ds1InnerAroundList = dx_ds1InnerAroundList + d1180FirstFace + dx_ds1OuterAroundList = dx_ds1OuterAroundList + d1180FirstFace elif startPhase == 180.0 and n2 > elementsCountAlongSegment - 1: - dx_ds1InnerAroundList = dx_ds1InnerAroundList + d1180LastFace + dx_ds1OuterAroundList = dx_ds1OuterAroundList + d1180LastFace elif startPhase == 180.0 and elementsCountAlongSegment % 2 == 0 and \ n2 == int(elementsCountAlongSegment * 0.5): d1Corrected = d1180MidFace @@ -803,15 +802,15 @@ def getColonSegmentInnerPoints(region, elementsCountAroundTC, elementsCountAroun 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)] - dx_ds1InnerAroundList.append(dx_ds1) + dx_ds1OuterAroundList.append(dx_ds1) # Account for d1 of node sitting on half haustrum d1 = vector.normalise([xAround[elementsCountAroundHalfHaustrum][c] - xAround[elementsCountAroundHalfHaustrum - 1][c] for c in range(3)]) dx_ds1 = [c * arcLengthAround for c in d1] - dx_ds1InnerAroundList.append(dx_ds1) + dx_ds1OuterAroundList.append(dx_ds1) - if dx_ds1InnerAroundList: - d1Smoothed = interp.smoothCubicHermiteDerivativesLine(xAround, dx_ds1InnerAroundList, + if dx_ds1OuterAroundList: + d1Smoothed = interp.smoothCubicHermiteDerivativesLine(xAround, dx_ds1OuterAroundList, fixStartDerivative=True) d1TCEdge = vector.setMagnitude(d1Smoothed[int(elementsCountAroundTC * 0.5)], vector.magnitude(d1Smoothed[int(elementsCountAroundTC * 0.5 - 1)])) @@ -830,16 +829,14 @@ def getColonSegmentInnerPoints(region, elementsCountAroundTC, elementsCountAroun xHalfSetRelaxed, d1HalfSetRelaxed = \ createHalfSetIntraHaustralSegment(elementsCountAroundTC, elementsCountAroundHaustrum, tcCount, tcWidthSegmentList[n2], radiusSegmentList[n2], - cornerInnerRadiusFactor, sampleElementOut, haustrumInnerRadiusFactor) + cornerOuterRadiusFactor, sampleElementOut, haustrumOuterRadiusFactor) xRelaxed, d1Relaxed, _ = getFullProfileFromHalfHaustrum(xHalfSetRelaxed, d1HalfSetRelaxed, d2Around, tcCount) - xiFace, relaxedLengthAroundFace = getXiListFromOuterLengthProfile(xRelaxed, d1Relaxed, segmentAxis, - wallThickness, transitElementList) + xiFace, relaxedLengthAroundFace = getXiListFromOuterLengthProfile(xRelaxed, d1Relaxed) xiList.append(xiFace) relaxedLengthList.append(relaxedLengthAroundFace) - contractedLengthAroundFace = getXiListFromOuterLengthProfile(xAlongList, d1AlongList, segmentAxis, - wallThickness, transitElementList)[1] + contractedLengthAroundFace = getXiListFromOuterLengthProfile(xAlongList, d1AlongList)[1] contractedWallThickness = relaxedLengthAroundFace * wallThickness / contractedLengthAroundFace contractedWallThicknessList.append(contractedWallThickness) @@ -857,7 +854,7 @@ def getColonSegmentInnerPoints(region, elementsCountAroundTC, elementsCountAroun def createHalfSetInterHaustralSegment(elementsCountAroundTC, elementsCountAroundHaustrum, - tcCount, tcWidth, radius, cornerInnerRadiusFactor, sampleElementOut): + tcCount, tcWidth, radius, cornerOuterRadiusFactor, sampleElementOut): """ Find locations and derivative of nodes in half of an inter-haustral segment. Circular profile for segment @@ -867,10 +864,10 @@ def createHalfSetInterHaustralSegment(elementsCountAroundTC, elementsCountAround :param elementsCountAroundHaustrum: Number of elements around haustrum. :param tcCount: Number of tenia coli. :param tcWidth: Width of tenia coli. - :param radius: Inner radius of circular profile with two tenia coli, + :param radius: Outer radius of circular profile with two tenia coli, radius of circle enclosing triangle for profile with three tenia coli. - :param cornerInnerRadiusFactor: Roundness of triangular corners of - inter-haustral septa. Factor is multiplied by inner radius + :param cornerOuterRadiusFactor: Roundness of triangular corners of + inter-haustral septa. Factor is multiplied by outer radius to get a radius of curvature at the corners. Only applicable for three tenia coli. Set to zero for two tenia coli. :param sampleElementOut: Number of sample points used to set up profile @@ -888,7 +885,7 @@ def createHalfSetInterHaustralSegment(elementsCountAroundTC, elementsCountAround sampleElementOut, startRadians=0.0) else: # tcCount == 3, Triangular profile - cornerRC = cornerInnerRadiusFactor * radius + cornerRC = cornerOuterRadiusFactor * radius radiansRangeRC = [7 * math.pi / 4, 0.0, math.pi / 4] for n1 in range(3): @@ -937,8 +934,8 @@ def createHalfSetInterHaustralSegment(elementsCountAroundTC, elementsCountAround def createHalfSetIntraHaustralSegment(elementsCountAroundTC, elementsCountAroundHaustrum, - tcCount, tcWidth, radius, cornerInnerRadiusFactor, sampleElementOut, - haustrumInnerRadiusFactor): + tcCount, tcWidth, radius, cornerOuterRadiusFactor, sampleElementOut, + haustrumOuterRadiusFactor): """ Find locations and derivative of nodes in half of an intra-haustral segment. Bow-tie profile for segment with two tenia coli and @@ -947,15 +944,15 @@ def createHalfSetIntraHaustralSegment(elementsCountAroundTC, elementsCountAround :param elementsCountAroundHaustrum: Number of elements around haustrum. :param tcCount: Number of tenia coli. :param tcWidth: Width of tenia coli. - :param radius: Inner radius of circular inter-haustral profile with two + :param radius: Outer radius of circular inter-haustral profile with two tenia coli, radius of circle enclosing triangle for inter-haustral profile with three tenia coli. - :param cornerInnerRadiusFactor: Roundness of triangular corners of - inter-haustral septa. Factor is multiplied by inner radius + :param cornerOuterRadiusFactor: Roundness of triangular corners of + inter-haustral septa. Factor is multiplied by outer radius to get a radius of curvature at the corners. Only applicable for three tenia coli. Set to zero for two tenia coli. :param sampleElementOut: Number of sample points used to set up profile - :param haustrumInnerRadiusFactor: Factor is multiplied by inner + :param haustrumOuterRadiusFactor: Factor is multiplied by outer radius to obtain radius of intersecting circles in the middle cross-section along a haustra segment. :return: Node location and derivative on half of a haustrum segment. @@ -967,8 +964,8 @@ def createHalfSetIntraHaustralSegment(elementsCountAroundTC, elementsCountAround d1HalfSetIntraHaustra = [] # Set up profile - cornerRC = cornerInnerRadiusFactor * radius - haustrumRadius = (haustrumInnerRadiusFactor + 1) * radius + cornerRC = cornerOuterRadiusFactor * radius + haustrumRadius = (haustrumOuterRadiusFactor + 1) * radius if tcCount == 2: # Bow-tie profile originRC = (radius * radius - haustrumRadius * haustrumRadius) / (-2.0 * haustrumRadius) RC = haustrumRadius - originRC @@ -1253,13 +1250,12 @@ def getFullProfileFromHalfHaustrum(xHaustrumHalfSet, d1HaustrumHalfSet, return xHaustra, d1Haustra, d2Haustra -def getXiListFromOuterLengthProfile(xInner, d1Inner, segmentAxis, - wallThickness, transitElementList): +def getXiListFromOuterLengthProfile(xOuter, d1Outer): """ Gets a list of xi for flat coordinates calculated from outer arclength of elements around a segment (most relaxed state). - :param xInner: Coordinates of points on inner surface around segment. - :param d1Inner: Derivatives of points on inner surface around segment. + :param xOuter: Coordinates of points on outer surface around segment. + :param d1Outer: Derivatives of points on outer surface around segment. :param segmentAxis: Axis of segment. :param wallThickness: Thickness of wall. :param transitElementList: stores true if element around is an element that @@ -1268,36 +1264,6 @@ def getXiListFromOuterLengthProfile(xInner, d1Inner, segmentAxis, wall thickness from inner points. :return totalArcLengthOuter: Total arclength around outer surface of elements. """ - unitNormList = [] - xOuter = [] - curvatureInner = [] - d1Outer = [] - - for n in range(len(xInner)): - unitNormList.append(vector.normalise(vector.crossproduct3(d1Inner[n], segmentAxis))) - - for n in range(len(xInner)): - norm = unitNormList[n] - # Calculate outer coordinates - x = [xInner[n][i] + norm[i] * wallThickness for i in range(3)] - xOuter.append(x) - # Calculate curvature along elements around - prevIdx = n - 1 if (n != 0) else len(xInner) - 1 - nextIdx = n + 1 if (n < (len(xInner) - 1)) else 0 - kappam = interp.getCubicHermiteCurvatureSimple(xInner[prevIdx], d1Inner[prevIdx], xInner[n], d1Inner[n], 1.0) - kappap = interp.getCubicHermiteCurvatureSimple(xInner[n], d1Inner[n], xInner[nextIdx], d1Inner[nextIdx], 0.0) - if not transitElementList[n] and not transitElementList[(n - 1) % (len(xInner))]: - curvatureAround = 0.5 * (kappam + kappap) - elif transitElementList[n]: - curvatureAround = kappam - elif transitElementList[(n - 1) % (len(xInner))]: - curvatureAround = kappap - curvatureInner.append(curvatureAround) - - for n in range(len(xOuter)): - factor = 1.0 + wallThickness * curvatureInner[n] - dx_ds1 = [factor * c for c in d1Inner[n]] - d1Outer.append(dx_ds1) arcLengthList = [] for n1 in range(len(xOuter)): diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_esophagus1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_esophagus1.py index 19d2ea22..17e0f066 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_esophagus1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_esophagus1.py @@ -40,11 +40,12 @@ class MeshType_3d_esophagus1(Scaffold_base): }, 'meshEdits': exnode_string_from_nodeset_field_parameters( [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ - (1, [ [ -0.42, -100.50, 1401.88 ], [ 0.74, 14.22, -46.12 ], [ 7.85, -0.56, -0.05 ], [ 0.69, 0.03, 0.02 ], [ -0.22, -2.98, -0.92 ], [ 0.19, 1.51, 0.43 ] ] ), - (2, [ [ 0.52, -84.95, 1340.25 ], [ 1.15, 16.87, -77.08 ], [ 7.08, -0.66, -0.04 ], [ -0.25, -0.13, 0.05 ], [ -0.19, -2.04, -0.45 ], [ -0.03, 0.34, 0.51 ] ] ), - (3, [ [ 1.85, -67.80, 1247.93 ], [ -0.05, -4.17, -89.62 ], [ 6.13, -0.92, 0.04 ], [ -0.56, 0.20, 0.44 ], [ -0.38, -2.56, 0.12 ], [ 0.00, 0.08, 0.61 ] ] ), - (4, [ [ 0.55, -90.99, 1166.45 ], [ 6.95, -24.56, -60.26 ], [ 4.15, 1.65, -0.20 ], [ -1.22, 1.08, 1.18 ], [ 0.88, -2.09, 0.95 ], [ -0.02, 0.46, 0.61 ] ] ), - (5, [ [ 9.34, -111.30, 1127.62 ], [ 3.74, -1.54, -6.85 ], [ 1.93, 1.69, 0.67 ], [ -2.29, 1.59, 1.62 ], [ 1.32, -1.98, 1.17 ], [ -0.24, 0.29, 0.57 ] ] )] ), + (1, [[0.394,-100.872,1402.818], [-0.035,12.367,-48.020], [8.730,-0.526,-0.142], [0.613,-0.153,-0.037], [-0.272,-4.224,-1.088], [-0.169,-1.491,-0.564]]), + (2, [[0.520,-86.043,1340.066], [0.501,16.682,-77.602], [9.142,-0.799,-0.113], [0.212,-0.392,0.096], [-0.465,-5.159,-1.112], [-0.215,-0.377,0.515]]), + (3, [[1.368,-67.733,1247.932], [0.235,-3.685,-89.672], [9.061,-1.366,0.080], [-0.833,-0.231,0.187], [-0.714,-4.722,0.192], [-0.167,0.445,1.659]]), + (4, [[0.361,-91.057,1165.531], [-2.499,-24.560,-49.102], [7.540,-1.290,0.261], [-0.809,1.514,2.095], [-0.806,-4.269,2.176], [0.001,0.896,0.910]]), + (5, [[11.471,-112.192,1126.439], [9.994,-15.550,-16.424], [7.114,0.998,3.385], [-0.043,3.060,4.152], [-0.754,-3.134,2.509], [0.102,1.373,-0.245]]) + ]), 'userAnnotationGroups': [ { @@ -89,7 +90,7 @@ def getDefaultOptions(cls, parameterSetName='Default'): 'Number of elements around': 8, 'Number of elements along': 20, 'Number of elements through wall': 4, - 'Wall thickness': 3.2, + 'Wall thickness': 1.2, 'Mucosa relative thickness': 0.35, 'Submucosa relative thickness': 0.15, 'Circular muscle layer relative thickness': 0.25, @@ -421,7 +422,7 @@ def generateBaseMesh(cls, region, options): tubemesh.extrudeSurfaceCoordinates(xWarpedList, d1WarpedList, d2WarpedList, d3WarpedUnitList, [wallThickness]*(elementsCountAlong+1), relativeThicknessList, elementsCountAround, elementsCountAlong, elementsCountThroughWall, - transitElementList, outward=True) + transitElementList, outward=False) # Create flat coordinates xFlat, d1Flat, d2Flat = tubemesh.createFlatCoordinates(xiList, flatWidthList, length, wallThickness, diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_smallintestine1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_smallintestine1.py index b96cf54a..7ecb1f95 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_smallintestine1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_smallintestine1.py @@ -62,543 +62,544 @@ class MeshType_3d_smallintestine1(Scaffold_base): }, 'meshEdits': exnode_string_from_nodeset_field_parameters( [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ - (1, [ [ -502.30, 732.10, 92.00 ], [ -49.80, -90.70, 0.00 ], [ 0.00, 0.00, 10.00 ], [ 0.00, 0.00, 0.00 ], [ -8.77, 4.81, 0.00 ], [ 0.00, 0.00, 0.00 ] ] ), - (2, [ [ -543.10, 654.80, 92.00 ], [ -31.70, -64.00, 0.00 ], [ 0.00, 0.00, 10.00 ], [ 0.00, 0.00, 0.00 ], [ -8.96, 4.44, 0.00 ], [ 0.00, 0.00, 0.00 ] ] ), - (3, [ [ -566.20, 605.00, 92.00 ], [ -43.40, -40.20, 0.00 ], [ 0.00, 0.00, 10.00 ], [ 0.00, 0.00, 0.00 ], [ -6.80, 7.34, 0.00 ], [ 0.00, 0.00, 0.00 ] ] ), - (4, [ [ -623.90, 583.60, 92.00 ], [ -58.90, 0.00, 0.00 ], [ 0.00, 0.00, 10.00 ], [ 0.00, 0.00, 0.00 ], [ 0.00, 10.00, 0.00 ], [ 0.00, 0.00, 0.00 ] ] ), - (5, [ [ -674.40, 602.30, 92.00 ], [ -25.80, 24.90, 0.00 ], [ 0.00, 0.00, 10.00 ], [ 1.57, 1.24, -0.27 ], [ 6.94, 7.20, 0.00 ], [ 1.57, 1.24, -0.27 ] ] ), - (6, [ [ -676.30, 613.40, 92.00 ], [ 21.70, 17.10, -7.50 ], [ 2.05, 1.62, 9.65 ], [ 1.52, 0.69, -0.22 ], [ 6.19, -7.86, 0.01 ], [ 1.52, 0.69, -0.22 ] ] ), - (7, [ [ -638.20, 613.20, 80.50 ], [ 47.90, 1.90, -11.30 ], [ 2.29, 0.09, 9.73 ], [ -0.55, 2.15, -1.26 ], [ 0.39, -9.99, -0.00 ], [ -0.55, 2.15, -1.25 ] ] ), - (8, [ [ -586.80, 617.60, 72.10 ], [ 3.30, 41.00, -47.10 ], [ 0.61, 7.52, 6.56 ], [ -1.76, 0.56, -0.15 ], [ 9.97, -0.79, -0.02 ], [ -1.77, 0.56, -0.14 ] ] ), - (9, [ [ -644.60, 633.70, 57.50 ], [ -52.20, 4.60, -6.70 ], [ -1.25, 0.12, 9.92 ], [ 0.12, -4.47, 1.05 ], [ 0.89, 9.96, -0.01 ], [ 0.12, -4.47, 1.05 ] ] ), - (10, [ [ -677.20, 630.20, 57.50 ], [ 0.10, -43.70, -12.10 ], [ -0.00, -2.66, 9.64 ], [ 1.58, -0.74, -0.11 ], [ -10.00, -0.01, -0.00 ], [ 1.58, -0.74, -0.10 ] ] ), - (11, [ [ -632.90, 609.90, 50.60 ], [ 51.90, -16.20, -11.70 ], [ 2.02, -0.63, 9.77 ], [ 0.39, -1.35, -0.70 ], [ -2.97, -9.55, -0.00 ], [ 0.39, -1.35, -0.70 ] ] ), - (12, [ [ -581.30, 601.00, 35.40 ], [ 4.90, -48.00, -34.50 ], [ 0.57, -5.79, 8.13 ], [ -1.42, 0.41, 0.08 ], [ -9.95, -1.01, -0.02 ], [ -1.42, 0.40, 0.08 ] ] ), - (13, [ [ -631.70, 589.30, 35.90 ], [ -57.50, 19.90, -5.30 ], [ -0.82, 0.28, 9.96 ], [ -2.13, 7.48, -3.39 ], [ 3.27, 9.45, 0.00 ], [ -2.13, 7.47, -3.39 ] ] ), - (14, [ [ -667.40, 632.00, 27.30 ], [ -60.00, -18.80, -39.10 ], [ -3.71, 9.21, 1.15 ], [ -1.20, -0.91, -9.00 ], [ 4.52, 2.88, -8.44 ], [ -1.20, -0.91, -9.00 ] ] ), - (15, [ [ -666.40, 558.00, 7.70 ], [ -33.70, -54.60, 46.30 ], [ -2.57, -5.27, -8.10 ], [ -1.72, -4.99, -3.68 ], [ 8.68, -4.95, 0.47 ], [ -1.72, -4.99, -3.68 ] ] ), - (16, [ [ -698.00, 570.70, 66.50 ], [ -52.90, 5.40, 48.50 ], [ -6.71, -2.24, -7.06 ], [ -2.86, -0.08, 4.78 ], [ 0.98, -9.72, 2.16 ], [ -2.87, -0.08, 4.78 ] ] ), - (17, [ [ -760.20, 567.80, 94.30 ], [ -13.60, 33.40, 46.80 ], [ -8.32, -5.37, 1.39 ], [ 4.50, 1.96, 8.55 ], [ 5.04, -6.28, 5.92 ], [ 4.51, 1.96, 8.55 ] ] ), - (18, [ [ -724.50, 582.10, 93.50 ], [ 45.90, 1.10, -0.90 ], [ 0.19, -0.07, 10.00 ], [ 4.20, 2.65, 4.23 ], [ 0.23, -10.00, -0.07 ], [ 4.20, 2.65, 4.24 ] ] ), - (19, [ [ -681.80, 570.00, 92.80 ], [ 28.80, -21.00, -0.70 ], [ 0.24, 0.02, 10.02 ], [ -0.11, -0.21, 0.02 ], [ -5.91, -8.09, 0.16 ], [ -0.11, -0.21, 0.02 ] ] ), - (20, [ [ -667.90, 548.90, 92.30 ], [ 3.90, -28.50, -1.00 ], [ 0.03, -0.37, 10.03 ], [ -0.05, -0.00, 0.02 ], [ -9.94, -1.38, -0.02 ], [ -0.05, -0.00, 0.02 ] ] ), - (21, [ [ -677.10, 520.90, 91.00 ], [ -27.30, -11.70, 0.60 ], [ 0.17, 0.09, 10.06 ], [ -0.32, 0.01, 0.01 ], [ -3.97, 9.24, -0.02 ], [ -0.32, 0.01, 0.01 ] ] ), - (22, [ [ -700.50, 532.40, 92.90 ], [ -14.40, 20.00, -0.20 ], [ -0.56, -0.30, 10.06 ], [ -0.35, 0.31, 0.00 ], [ 8.16, 5.88, 0.63 ], [ -0.36, 0.32, 0.00 ] ] ), - (23, [ [ -703.50, 552.30, 91.10 ], [ -16.60, 15.00, -1.80 ], [ -0.63, 0.54, 10.06 ], [ -0.38, 0.11, -0.02 ], [ 6.75, 7.50, 0.02 ], [ -0.39, 0.11, -0.02 ] ] ), - (24, [ [ -726.50, 553.80, 90.20 ], [ -21.70, -2.90, -3.00 ], [ -1.37, -0.18, 10.02 ], [ -1.63, -5.16, -4.21 ], [ -1.35, 10.02, -0.00 ], [ -1.63, -5.16, -4.21 ] ] ), - (25, [ [ -739.60, 548.10, 86.40 ], [ 15.30, -13.20, -28.20 ], [ -3.76, -9.13, 2.25 ], [ -1.48, -2.79, -8.86 ], [ -8.28, 2.07, -5.44 ], [ -1.48, -2.79, -8.86 ] ] ), - (26, [ [ -694.50, 550.10, 70.60 ], [ 44.70, -4.70, -16.30 ], [ -3.06, 2.92, -9.23 ], [ 1.47, 4.72, -6.06 ], [ 1.90, 9.68, 2.43 ], [ 1.47, 4.71, -6.06 ] ] ), - (27, [ [ -652.70, 539.30, 54.70 ], [ 26.40, -22.50, -3.70 ], [ -0.85, 0.66, -10.13 ], [ 0.77, -2.83, -0.13 ], [ 6.61, 7.75, -0.05 ], [ 0.77, -2.82, -0.13 ] ] ), - (28, [ [ -644.90, 520.20, 58.60 ], [ -8.40, -26.00, 7.10 ], [ -0.80, -2.45, -9.87 ], [ -0.33, -0.93, 0.06 ], [ 9.70, -3.15, -0.00 ], [ -0.33, -0.92, 0.06 ] ] ), - (29, [ [ -670.50, 503.30, 65.20 ], [ -49.20, -7.40, 8.40 ], [ -1.67, -0.25, -10.09 ], [ -0.69, -1.22, 1.36 ], [ 1.54, -10.11, -0.00 ], [ -0.69, -1.22, 1.37 ] ] ), - (30, [ [ -723.20, 522.10, 69.80 ], [ 13.50, 42.00, -69.30 ], [ -1.98, -8.44, -5.51 ], [ -0.28, -0.80, 0.83 ], [ -9.93, 2.58, -0.38 ], [ -0.28, -0.80, 0.83 ] ] ), - (31, [ [ -641.70, 515.00, 30.80 ], [ 50.00, -30.40, -15.00 ], [ -2.21, 1.29, -10.01 ], [ 1.71, -0.27, -1.09 ], [ 5.37, 8.83, -0.05 ], [ 1.71, -0.28, -1.09 ] ] ), - (32, [ [ -631.40, 498.10, 31.40 ], [ -4.50, -28.10, 4.10 ], [ -0.02, -1.49, -10.24 ], [ 0.71, -0.99, -0.15 ], [ 10.22, -1.61, 0.21 ], [ 0.71, -0.99, -0.15 ] ] ), - (33, [ [ -652.60, 477.30, 37.00 ], [ -50.00, -6.30, 6.60 ], [ -1.34, -0.02, -10.29 ], [ -1.33, 1.31, 0.06 ], [ 1.29, -10.29, -0.15 ], [ -1.33, 1.31, 0.06 ] ] ), - (34, [ [ -711.30, 508.40, 47.40 ], [ -65.20, 35.30, 20.70 ], [ -2.68, 0.96, -10.02 ], [ -4.19, 0.21, 3.24 ], [ -4.87, -9.20, 0.42 ], [ -4.19, 0.21, 3.24 ] ] ), - (35, [ [ -756.90, 547.90, 71.40 ], [ -13.40, -32.80, 30.60 ], [ -9.76, 0.39, -3.77 ], [ -0.16, -0.33, -0.99 ], [ 2.37, -7.50, -6.91 ], [ -0.16, -0.33, -0.99 ] ] ), - (36, [ [ -764.20, 524.80, 82.70 ], [ 2.40, -34.00, -3.00 ], [ -7.09, 0.16, -7.72 ], [ 1.12, 1.17, 2.11 ], [ 7.69, 1.14, -7.04 ], [ 1.12, 1.17, 2.11 ] ] ), - (37, [ [ -733.10, 495.70, 71.40 ], [ -9.60, -50.80, 23.30 ], [ -8.61, 3.72, 4.77 ], [ 3.16, -1.87, 8.64 ], [ -5.81, -2.81, -8.30 ], [ 3.17, -1.87, 8.64 ] ] ), - (38, [ [ -714.70, 462.80, 83.00 ], [ 19.70, -9.40, 0.00 ], [ -1.38, -2.86, 10.06 ], [ -2.27, 2.74, -8.49 ], [ -4.34, -9.07, -3.17 ], [ -2.27, 2.74, -8.49 ] ] ), - (39, [ [ -703.00, 463.20, 92.20 ], [ -6.90, 19.30, 27.80 ], [ -8.20, 4.34, -5.03 ], [ -0.98, 2.71, -11.42 ], [ -6.31, -7.60, 3.73 ], [ -0.98, 2.71, -11.43 ] ] ), - (40, [ [ -722.30, 486.20, 90.20 ], [ -30.40, 26.10, -0.90 ], [ 0.20, -0.15, -10.58 ], [ 4.54, -2.26, -3.13 ], [ -6.88, -8.04, -0.02 ], [ 4.54, -2.26, -3.13 ] ] ), - (41, [ [ -745.10, 520.90, 90.70 ], [ -10.10, 19.90, 1.10 ], [ -0.24, 0.48, -10.60 ], [ 0.25, -0.06, -0.02 ], [ -9.47, -4.79, -0.00 ], [ 0.25, -0.06, -0.02 ] ] ), - (42, [ [ -724.50, 528.30, 92.00 ], [ 61.80, -0.90, 2.80 ], [ 0.46, -0.02, -10.62 ], [ -0.36, -0.13, 0.04 ], [ 0.13, 10.63, -0.01 ], [ -0.36, -0.13, 0.04 ] ] ), - (43, [ [ -691.00, 492.20, 92.50 ], [ 65.60, -18.50, -13.50 ], [ -1.98, 0.57, -10.46 ], [ -1.69, 0.78, 0.19 ], [ 2.91, 10.26, 0.01 ], [ -1.70, 0.78, 0.19 ] ] ), - (44, [ [ -640.00, 474.10, 57.50 ], [ 42.10, -24.20, -15.10 ], [ -2.75, 1.58, -10.23 ], [ 1.45, -0.62, -0.23 ], [ 5.34, 9.28, -0.00 ], [ 1.45, -0.63, -0.23 ] ] ), - (45, [ [ -611.10, 454.00, 57.30 ], [ -5.20, -35.60, 0.00 ], [ 0.00, 0.00, -10.73 ], [ 1.27, -0.75, -0.25 ], [ 10.62, -1.55, -0.00 ], [ 1.28, -0.75, -0.25 ] ] ), - (46, [ [ -640.70, 443.80, 57.50 ], [ -30.10, -5.20, 0.10 ], [ -0.04, -0.02, -10.76 ], [ 0.00, 0.00, -0.02 ], [ 1.82, -10.60, 0.01 ], [ 0.00, 0.00, -0.02 ] ] ), - (47, [ [ -667.60, 443.10, 57.50 ], [ -25.60, 5.80, 0.00 ], [ 0.00, 0.00, -10.77 ], [ 0.86, -0.09, 0.06 ], [ -2.38, -10.51, -0.00 ], [ 0.85, -0.09, 0.06 ] ] ), - (48, [ [ -702.10, 461.20, 42.90 ], [ -35.10, 4.20, -7.10 ], [ 2.12, -0.26, -10.59 ], [ -2.58, -3.51, 4.12 ], [ -1.28, -10.73, 0.01 ], [ -2.58, -3.51, 4.12 ] ] ), - (49, [ [ -751.10, 480.00, 41.40 ], [ -2.70, -4.20, 52.00 ], [ -6.95, -8.26, -1.02 ], [ 0.95, -1.86, -0.23 ], [ 8.30, -6.97, -0.12 ], [ 0.95, -1.86, -0.23 ] ] ), - (50, [ [ -740.70, 460.80, 81.10 ], [ 28.50, -35.40, 18.50 ], [ 2.29, -5.05, -9.35 ], [ 0.35, 3.93, -4.00 ], [ 9.49, 5.25, -0.74 ], [ 0.34, 3.93, -4.00 ] ] ), - (51, [ [ -715.80, 438.10, 60.60 ], [ 47.50, 3.90, -28.60 ], [ -5.59, -0.46, -9.35 ], [ -2.22, 3.02, -0.69 ], [ -0.89, 10.87, -0.00 ], [ -2.22, 3.03, -0.69 ] ] ), - (52, [ [ -690.60, 420.70, 23.60 ], [ 72.60, -48.00, -9.80 ], [ -1.03, 0.68, -10.87 ], [ 3.33, -0.90, -0.75 ], [ 6.02, 9.13, 0.00 ], [ 3.33, -0.90, -0.75 ] ] ), - (53, [ [ -634.40, 437.80, 2.60 ], [ -11.70, 62.00, -18.70 ], [ 0.57, -3.08, -10.53 ], [ 0.70, -0.09, -0.11 ], [ -10.80, -2.04, 0.01 ], [ 0.70, -0.10, -0.11 ] ] ), - (54, [ [ -685.40, 456.30, 14.80 ], [ -80.30, 28.90, -4.40 ], [ 0.54, -0.19, -11.01 ], [ -0.87, 2.09, -0.22 ], [ -3.73, -10.38, -0.00 ], [ -0.87, 2.09, -0.22 ] ] ), - (55, [ [ -713.80, 509.70, 13.10 ], [ -37.40, 33.30, 7.40 ], [ -1.21, 1.06, -10.95 ], [ -3.03, -3.15, 1.90 ], [ -7.35, -8.28, 0.01 ], [ -3.03, -3.15, 1.91 ] ] ), - (56, [ [ -762.90, 511.80, 46.30 ], [ -17.40, -20.30, 31.30 ], [ -5.49, -6.40, -7.24 ], [ -0.62, -3.81, 1.50 ], [ 8.45, -7.22, -0.02 ], [ -0.62, -3.81, 1.50 ] ] ), - (57, [ [ -778.20, 487.30, 79.10 ], [ -7.60, -16.30, 20.80 ], [ -3.55, -7.65, -7.29 ], [ 6.65, 7.15, 6.52 ], [ 10.11, -4.70, 0.01 ], [ 6.65, 7.16, 6.52 ] ] ), - (58, [ [ -800.50, 488.70, 56.50 ], [ -2.60, 28.50, -35.30 ], [ 7.23, 6.89, 5.01 ], [ 6.13, 4.32, 8.27 ], [ 8.49, -5.32, -4.94 ], [ 6.13, 4.32, 8.26 ] ] ), - (59, [ [ -767.60, 546.30, 28.50 ], [ 27.50, 29.90, 28.50 ], [ 4.20, -8.95, 5.32 ], [ -7.20, -5.78, -5.89 ], [ 8.34, -0.54, -7.50 ], [ -7.20, -5.78, -5.89 ] ] ), - (60, [ [ -730.30, 549.50, 39.80 ], [ 38.00, -16.90, -12.30 ], [ -5.37, -9.00, -4.10 ], [ 0.16, 0.75, -3.25 ], [ -0.99, 5.13, -9.97 ], [ 0.16, 0.75, -3.25 ] ] ), - (61, [ [ -695.50, 539.60, -1.80 ], [ -25.60, -41.70, -52.60 ], [ 8.66, -7.11, 1.44 ], [ 5.87, 1.82, -1.72 ], [ -6.04, -5.82, 7.57 ], [ 5.87, 1.82, -1.71 ] ] ), - (62, [ [ -753.60, 538.10, 17.50 ], [ -40.40, -47.50, 4.70 ], [ 5.33, -5.37, -8.46 ], [ -2.66, -0.56, -4.61 ], [ 6.83, -5.06, 7.52 ], [ -2.66, -0.56, -4.61 ] ] ), - (63, [ [ -716.70, 466.20, -1.60 ], [ -40.40, -47.80, 46.20 ], [ 3.56, -8.94, -6.13 ], [ -1.22, -1.90, 1.22 ], [ 9.07, -1.07, 6.83 ], [ -1.22, -1.90, 1.22 ] ] ), - (64, [ [ -774.90, 492.50, 14.30 ], [ 4.60, -28.40, 48.20 ], [ 2.79, -9.47, -5.82 ], [ -2.63, -0.59, 0.48 ], [ 11.08, 2.86, 0.65 ], [ -2.63, -0.59, 0.47 ] ] ), - (65, [ [ -755.00, 488.60, 92.30 ], [ -28.50, 3.50, 3.80 ], [ -1.91, -10.12, -5.16 ], [ -0.86, -0.12, -0.18 ], [ 0.72, -5.33, 10.19 ], [ -0.86, -0.12, -0.18 ] ] ), - (66, [ [ -793.80, 484.40, 104.20 ], [ -32.90, 3.60, -1.30 ], [ -0.86, -9.98, -5.76 ], [ 6.84, 4.46, 2.66 ], [ -1.01, -5.69, 10.00 ], [ 6.84, 4.46, 2.66 ] ] ), - (67, [ [ -790.70, 455.50, 85.30 ], [ -2.30, -19.40, -39.70 ], [ 11.49, -1.41, 0.00 ], [ 7.31, 8.14, 4.70 ], [ -1.27, -10.32, 5.09 ], [ 7.31, 8.13, 4.70 ] ] ), - (68, [ [ -801.70, 464.20, 17.70 ], [ 26.10, -25.90, -35.60 ], [ 9.60, 5.94, 2.78 ], [ -7.03, 6.33, -0.90 ], [ 2.70, -8.07, 7.92 ], [ -7.03, 6.33, -0.90 ] ] ), - (69, [ [ -762.40, 459.90, 21.70 ], [ 25.40, 2.00, 17.80 ], [ -0.61, 11.64, -0.39 ], [ -1.65, 0.95, -2.28 ], [ -6.67, -0.03, 9.56 ], [ -1.65, 0.96, -2.28 ] ] ), - (70, [ [ -762.80, 454.40, 83.50 ], [ -1.60, 18.90, 65.10 ], [ 10.10, 5.74, -1.38 ], [ -0.60, -1.49, 6.17 ], [ -5.90, 9.68, -2.92 ], [ -0.60, -1.49, 6.16 ] ] ), - (71, [ [ -767.20, 479.00, 107.60 ], [ -24.80, -1.90, 8.70 ], [ 2.70, 6.90, 9.09 ], [ -9.96, -2.61, 4.05 ], [ -2.90, 9.45, -6.31 ], [ -9.96, -2.61, 4.05 ] ] ), - (72, [ [ -795.10, 432.40, 92.80 ], [ -9.10, -19.70, -41.40 ], [ -11.22, -1.54, 3.22 ], [ -2.62, -8.20, -1.68 ], [ -2.72, 10.57, -4.41 ], [ -2.62, -8.20, -1.68 ] ] ), - (73, [ [ -769.20, 411.90, 25.90 ], [ 68.40, -16.90, -33.00 ], [ 1.09, -9.41, 7.07 ], [ 5.91, 1.76, 3.98 ], [ -5.53, -6.68, -8.04 ], [ 5.92, 1.76, 3.98 ] ] ), - (74, [ [ -679.40, 419.00, 45.00 ], [ 55.50, 10.70, -0.20 ], [ -0.68, 3.92, 11.21 ], [ 1.23, 4.77, 1.54 ], [ 2.17, -10.99, 3.98 ], [ 1.23, 4.77, 1.54 ] ] ), - (75, [ [ -624.80, 428.10, 30.90 ], [ 37.00, 1.10, -8.30 ], [ 2.38, 3.47, 11.16 ], [ 0.65, -3.43, 0.31 ], [ 1.06, -11.41, 3.32 ], [ 0.65, -3.43, 0.31 ] ] ), - (76, [ [ -596.10, 415.90, 17.90 ], [ 13.70, -50.50, -10.30 ], [ 1.44, -1.92, 11.71 ], [ -2.26, -0.16, -0.25 ], [ -11.48, -3.22, 0.88 ], [ -2.26, -0.16, -0.25 ] ] ), - (77, [ [ -633.70, 383.40, 10.50 ], [ -53.90, -32.70, 2.90 ], [ -2.73, 5.47, 10.32 ], [ -3.48, 1.84, -0.84 ], [ -5.57, 8.70, -6.09 ], [ -3.48, 1.84, -0.84 ] ] ), - (78, [ [ -721.00, 400.40, -2.40 ], [ -84.80, 146.00, 5.60 ], [ -4.89, -3.24, 10.54 ], [ 0.98, -2.25, 0.71 ], [ 9.21, 5.13, 5.85 ], [ 0.98, -2.25, 0.71 ] ] ), - (79, [ [ -838.90, 413.20, 12.20 ], [ -5.80, 0.00, 0.00 ], [ -0.00, 2.57, 11.87 ], [ -4.26, -1.08, -0.91 ], [ 0.00, 11.87, -2.57 ], [ -4.26, -1.08, -0.91 ] ] ), - (80, [ [ -841.90, 390.30, 9.10 ], [ 23.70, -40.80, 14.10 ], [ -6.15, 0.07, 10.50 ], [ -3.54, -1.63, -0.61 ], [ -8.72, -6.80, -5.06 ], [ -3.54, -1.63, -0.61 ] ] ), - (81, [ [ -785.00, 366.40, 25.00 ], [ 68.10, -25.40, 20.50 ], [ -3.33, 0.56, 11.73 ], [ 2.70, 1.81, 0.59 ], [ -4.10, -11.48, -0.62 ], [ 2.70, 1.81, 0.59 ] ] ), - (82, [ [ -715.10, 372.10, 29.90 ], [ 45.50, 7.30, 0.60 ], [ -0.77, 3.83, 11.62 ], [ 1.10, 0.20, 0.24 ], [ 1.79, -11.48, 3.90 ], [ 1.10, 0.20, 0.25 ] ] ), - (83, [ [ -676.70, 381.70, 46.00 ], [ 33.50, -1.60, 1.70 ], [ -0.56, 2.17, 12.08 ], [ -2.24, 0.19, -0.76 ], [ -0.74, -12.08, 2.14 ], [ -2.25, 0.19, -0.76 ] ] ), - (84, [ [ -624.70, 387.70, 43.50 ], [ 20.20, 30.90, -2.50 ], [ -5.85, 4.65, 9.80 ], [ 0.24, -5.21, -0.06 ], [ 8.51, -4.93, 7.42 ], [ 0.24, -5.21, -0.06 ] ] ), - (85, [ [ -620.00, 414.70, 50.80 ], [ -23.20, 24.50, 6.10 ], [ -2.40, -5.02, 11.02 ], [ 3.51, -2.77, 1.11 ], [ 8.77, 7.03, 5.11 ], [ 3.51, -2.77, 1.11 ] ] ), - (86, [ [ -667.60, 418.50, 51.40 ], [ -25.90, -0.20, 2.60 ], [ 1.20, 2.97, 11.96 ], [ 0.14, 4.53, 0.11 ], [ -0.37, 12.02, -2.95 ], [ 0.14, 4.53, 0.11 ] ] ), - (87, [ [ -705.40, 416.80, 61.80 ], [ -55.10, -17.10, 0.00 ], [ -1.49, 4.67, 11.40 ], [ -3.64, 0.65, -0.93 ], [ -3.42, 10.87, -4.90 ], [ -3.64, 0.65, -0.93 ] ] ), - (88, [ [ -749.80, 368.90, 72.20 ], [ -21.40, -38.20, -0.90 ], [ -6.74, 3.55, 9.85 ], [ 2.52, 2.85, -1.54 ], [ -8.52, 4.96, -7.61 ], [ 2.52, 2.84, -1.54 ] ] ), - (89, [ [ -794.90, 366.10, 65.90 ], [ -29.10, -4.30, 9.30 ], [ 1.33, 9.22, 8.31 ], [ 4.72, 2.23, -0.88 ], [ -3.91, 8.25, -8.52 ], [ 4.71, 2.23, -0.88 ] ] ), - (90, [ [ -808.20, 363.30, 93.30 ], [ 18.80, -10.20, 29.80 ], [ 3.64, 8.98, 7.91 ], [ 1.12, -0.05, -0.24 ], [ -6.53, -2.71, 10.32 ], [ 1.12, -0.05, -0.24 ] ] ), - (91, [ [ -772.30, 355.10, 95.70 ], [ 43.70, -4.20, -0.20 ], [ 3.42, 9.15, 7.86 ], [ -2.39, -0.32, 0.63 ], [ 1.77, -8.08, 9.42 ], [ -2.39, -0.32, 0.63 ] ] ), - (92, [ [ -723.70, 356.50, 92.00 ], [ 34.80, 14.40, -6.20 ], [ -1.72, 8.22, 9.35 ], [ 2.61, -4.95, 1.60 ], [ 4.88, -8.24, 8.14 ], [ 2.61, -4.94, 1.59 ] ] ), - (93, [ [ -704.10, 380.20, 92.30 ], [ -4.50, 25.20, 1.10 ], [ 6.07, 0.59, 11.02 ], [ -0.50, 1.17, -0.66 ], [ 10.81, 2.18, -6.07 ], [ -0.50, 1.17, -0.66 ] ] ), - (94, [ [ -724.40, 396.00, 92.70 ], [ -30.00, -4.70, -0.50 ], [ -1.56, 9.32, 8.35 ], [ -4.52, 4.97, -1.53 ], [ -1.10, 8.28, -9.45 ], [ -4.52, 4.97, -1.53 ] ] ), - (95, [ [ -761.40, 390.00, 92.00 ], [ -26.80, -4.40, -1.30 ], [ -1.95, 9.30, 8.33 ], [ 3.52, -0.78, 0.05 ], [ -0.92, 8.30, -9.48 ], [ 3.52, -0.78, 0.05 ] ] ), - (96, [ [ -796.40, 394.20, 92.00 ], [ -19.90, 14.60, -1.10 ], [ 5.31, 7.80, 8.45 ], [ 2.73, 0.40, -0.79 ], [ 5.37, 6.54, -9.42 ], [ 2.73, 0.40, -0.79 ] ] ), - (97, [ [ -808.00, 419.20, 92.00 ], [ 22.20, 4.70, -19.80 ], [ 4.02, 9.89, 6.85 ], [ -2.50, 1.30, -0.56 ], [ 7.57, -7.69, 6.66 ], [ -2.50, 1.30, -0.56 ] ] ), - (98, [ [ -772.40, 406.20, 98.30 ], [ 40.50, -7.10, 9.50 ], [ -0.00, 10.20, 7.59 ], [ -5.63, 0.13, -2.26 ], [ -3.58, -7.28, 9.79 ], [ -5.64, 0.13, -2.26 ] ] ), - (99, [ [ -743.70, 434.90, 88.30 ], [ -18.90, -10.80, -19.80 ], [ -7.56, 10.12, 1.74 ], [ -5.23, -2.29, -1.22 ], [ 6.19, 6.22, -9.25 ], [ -5.24, -2.29, -1.23 ] ] ), - (100, [ [ -799.10, 394.00, 52.00 ], [ -21.00, -22.00, -12.00 ], [ -9.00, 4.23, 8.07 ], [ 7.99, -2.65, 4.28 ], [ -3.86, 8.50, -8.76 ], [ 7.99, -2.64, 4.28 ] ] ), - (101, [ [ -804.50, 342.90, 51.10 ], [ 18.40, -46.20, 24.50 ], [ 5.55, 3.84, 10.93 ], [ 5.00, 2.57, 0.35 ], [ -9.65, -4.07, 7.43 ], [ 5.00, 2.57, 0.35 ] ] ), - (102, [ [ -779.40, 314.90, 94.50 ], [ 43.80, -11.60, 23.20 ], [ 0.11, 9.64, 8.54 ], [ -2.57, 2.84, -1.17 ], [ -4.80, -7.71, 9.14 ], [ -2.57, 2.84, -1.17 ] ] ), - (103, [ [ -725.70, 321.90, 94.80 ], [ 50.50, 2.40, -4.10 ], [ 0.22, 9.72, 8.51 ], [ 2.24, -0.48, -0.06 ], [ 1.18, -8.49, 9.67 ], [ 2.24, -0.48, -0.06 ] ] ), - (104, [ [ -673.60, 342.20, 84.90 ], [ 40.10, -23.10, 1.40 ], [ 4.71, 8.65, 8.43 ], [ 2.31, -3.92, 1.73 ], [ -4.45, -7.17, 9.84 ], [ 2.31, -3.92, 1.73 ] ] ), - (105, [ [ -654.80, 296.30, 92.00 ], [ 7.30, -43.20, 5.10 ], [ 5.10, 2.22, 11.75 ], [ -3.45, -3.20, 1.92 ], [ -11.76, -1.38, 5.36 ], [ -3.45, -3.19, 1.92 ] ] ), - (106, [ [ -638.40, 213.80, 96.30 ], [ -29.60, -31.80, 0.00 ], [ -4.73, 4.39, 11.35 ], [ 4.65, 2.69, -1.87 ], [ -8.31, 7.73, -6.45 ], [ 4.65, 2.69, -1.87 ] ] ), - (107, [ [ -671.50, 206.00, 94.00 ], [ -29.50, 25.20, 0.10 ], [ 6.31, 7.31, 8.82 ], [ 7.00, -1.55, -0.71 ], [ 5.73, 6.71, -9.66 ], [ 7.00, -1.56, -0.71 ] ] ), - (108, [ [ -693.10, 254.60, 92.00 ], [ -5.80, 31.80, 6.00 ], [ 7.56, -0.62, 10.70 ], [ 0.22, -0.48, 0.58 ], [ 10.46, 3.29, -7.20 ], [ 0.22, -0.48, 0.58 ] ] ), - (109, [ [ -692.70, 282.10, 99.60 ], [ -11.70, 28.50, 0.00 ], [ 7.22, 2.91, 10.58 ], [ -4.53, 4.59, -0.52 ], [ 9.81, 3.97, -7.79 ], [ -4.53, 4.59, -0.52 ] ] ), - (110, [ [ -714.50, 303.80, 105.30 ], [ -27.80, -10.40, 3.10 ], [ -2.20, 8.74, 9.59 ], [ -5.61, -1.93, 0.96 ], [ -4.25, 8.71, -8.91 ], [ -5.61, -1.93, 0.96 ] ] ), - (111, [ [ -732.90, 276.20, 100.40 ], [ -10.50, -24.20, -5.40 ], [ -3.94, -1.07, 12.54 ], [ 1.14, -6.02, 1.63 ], [ -11.48, 5.69, -3.12 ], [ 1.15, -6.02, 1.63 ] ] ), - (112, [ [ -739.60, 242.40, 94.90 ], [ 6.20, -21.60, 0.00 ], [ 0.16, -3.20, 12.82 ], [ 1.60, 0.58, 0.34 ], [ -11.46, -6.54, -0.73 ], [ 1.60, 0.58, 0.33 ] ] ), - (113, [ [ -729.90, 208.40, 92.90 ], [ 31.10, -37.00, 1.30 ], [ -0.79, 0.16, 13.21 ], [ -0.08, 2.62, 0.24 ], [ -10.29, -8.31, -0.51 ], [ -0.08, 2.62, 0.25 ] ] ), - (114, [ [ -671.40, 183.60, 95.20 ], [ 26.20, 4.60, -18.30 ], [ 0.71, 1.43, 13.18 ], [ 0.74, 0.62, 0.01 ], [ -2.74, -12.05, 4.85 ], [ 0.74, 0.62, 0.01 ] ] ), - (115, [ [ -676.50, 223.40, 56.90 ], [ -64.00, 41.80, -9.80 ], [ 0.72, 1.43, 13.23 ], [ 0.01, 0.00, 0.05 ], [ 8.61, 10.08, -1.39 ], [ 0.00, 0.01, 0.05 ] ] ), - (116, [ [ -680.80, 291.90, 29.60 ], [ 125.60, 70.80, -6.60 ], [ 0.72, 1.44, 13.29 ], [ -0.00, 0.00, 0.05 ], [ 7.21, -11.24, 0.87 ], [ 0.00, 0.01, 0.05 ] ] ), - (117, [ [ -714.10, 347.30, 15.30 ], [ -19.50, 82.90, -38.40 ], [ 0.72, 1.44, 13.34 ], [ 0.00, 0.00, 0.06 ], [ 13.34, -1.38, 0.85 ], [ 0.00, 0.01, 0.06 ] ] ), - (118, [ [ -801.90, 404.60, -7.10 ], [ -58.90, -30.30, 2.30 ], [ 0.73, 1.45, 13.41 ], [ 0.00, 0.00, 0.05 ], [ -5.43, 12.33, -0.98 ], [ 0.00, 0.01, 0.05 ] ] ), - (119, [ [ -808.70, 365.80, -13.70 ], [ 44.60, -53.00, -15.80 ], [ 0.73, 1.45, 13.45 ], [ -0.00, 0.00, 0.05 ], [ -11.98, -5.91, 2.26 ], [ 0.00, 0.01, 0.05 ] ] ), - (120, [ [ -688.00, 338.40, -11.70 ], [ 63.80, -48.80, 8.70 ], [ 0.73, 1.46, 13.53 ], [ 0.00, 0.01, 0.07 ], [ -7.42, -11.30, 1.72 ], [ 0.00, 0.01, 0.07 ] ] ), - (121, [ [ -673.00, 259.50, -3.20 ], [ 81.00, -7.10, 7.50 ], [ 0.73, 1.47, 13.59 ], [ 0.00, 0.01, 0.06 ], [ 0.51, -13.58, 1.69 ], [ 0.00, 0.01, 0.06 ] ] ), - (122, [ [ -674.40, 198.70, 27.60 ], [ -166.70, -5.50, 78.50 ], [ 0.74, 1.48, 13.66 ], [ 0.01, 0.01, 0.08 ], [ -5.65, 12.51, 0.86 ], [ 0.00, 0.01, 0.08 ] ] ), - (123, [ [ -751.20, 330.40, 5.60 ], [ -146.40, -62.90, 102.70 ], [ 0.74, 1.49, 13.77 ], [ 0.01, 0.01, 0.10 ], [ -10.32, 8.91, 2.56 ], [ 0.01, 0.01, 0.10 ] ] ), - (124, [ [ -771.40, 224.30, -0.50 ], [ -206.60, 3.00, -5.40 ], [ 0.75, 1.50, 13.86 ], [ 0.01, 0.01, 0.09 ], [ 1.33, 13.82, -1.48 ], [ 0.00, 0.01, 0.09 ] ] ), - (125, [ [ -809.20, 353.00, 16.20 ], [ -189.70, 36.40, -2.10 ], [ 0.75, 1.51, 13.96 ], [ 0.01, 0.00, 0.06 ], [ 3.24, 13.58, -1.62 ], [ 0.00, 0.01, 0.06 ] ] ), - (126, [ [ -838.20, 311.90, 41.30 ], [ 13.30, -30.30, 21.40 ], [ 0.76, 1.51, 14.00 ], [ 0.00, 0.01, 0.03 ], [ -9.33, -9.46, 4.73 ], [ 0.00, 0.00, 0.03 ] ] ), - (127, [ [ -817.10, 288.00, 42.40 ], [ 34.40, -12.20, 0.70 ], [ 0.76, 1.52, 14.02 ], [ -0.00, 0.01, 0.03 ], [ -4.27, -13.36, 1.69 ], [ 0.00, 0.00, 0.03 ] ] ), - (128, [ [ -752.40, 294.00, 78.80 ], [ 68.30, 9.10, 2.00 ], [ 0.76, 1.52, 14.08 ], [ 0.00, 0.01, 0.05 ], [ 3.16, -13.75, 1.44 ], [ 0.00, 0.01, 0.05 ] ] ), - (129, [ [ -741.40, 241.80, 54.90 ], [ -60.00, -10.60, -17.50 ], [ 0.76, 1.53, 14.13 ], [ 0.01, 0.01, 0.05 ], [ 2.67, 13.98, 0.02 ], [ 0.00, 0.01, 0.05 ] ] ), - (130, [ [ -802.80, 226.00, 43.40 ], [ -39.00, 36.40, 14.80 ], [ 0.77, 1.53, 14.17 ], [ 0.00, 0.01, 0.04 ], [ 5.91, 12.99, -0.45 ], [ 0.00, 0.00, 0.04 ] ] ), - (131, [ [ -833.10, 266.00, 68.30 ], [ -22.10, 29.70, 29.30 ], [ 0.77, 1.54, 14.21 ], [ 0.00, 0.00, 0.03 ], [ 3.57, 13.06, 4.65 ], [ 0.00, 0.00, 0.03 ] ] ), - (132, [ [ -822.70, 279.50, 92.00 ], [ 26.60, 9.70, 0.30 ], [ 0.77, 1.54, 14.23 ], [ -0.00, -0.00, 0.02 ], [ 6.18, -12.88, 1.20 ], [ 0.00, 0.00, 0.02 ] ] ), - (133, [ [ -799.30, 280.50, 92.00 ], [ 19.60, -7.30, 0.00 ], [ 0.77, 1.54, 14.25 ], [ -0.00, -0.00, 0.02 ], [ -4.80, -13.42, 1.71 ], [ 0.00, 0.00, 0.02 ] ] ), - (134, [ [ -788.60, 264.40, 92.00 ], [ -4.80, -26.50, 0.00 ], [ 0.77, 1.54, 14.27 ], [ -0.00, -0.00, 0.02 ], [ -13.74, 4.17, 0.48 ], [ 0.00, 0.00, 0.02 ] ] ), - (135, [ [ -814.90, 246.10, 92.00 ], [ -26.10, -9.00, 1.30 ], [ 0.77, 1.54, 14.29 ], [ 0.00, 0.01, 0.02 ], [ -4.20, 13.71, -1.23 ], [ 0.00, 0.00, 0.02 ] ] ), - (136, [ [ -826.20, 223.00, 92.00 ], [ 12.30, -25.30, 0.00 ], [ 0.77, 1.55, 14.31 ], [ 0.00, 0.01, 0.02 ], [ -13.33, -5.30, 1.37 ], [ 0.00, 0.00, 0.02 ] ] ), - (137, [ [ -802.80, 203.40, 92.00 ], [ 45.00, 8.60, 0.00 ], [ 0.77, 1.55, 14.33 ], [ 0.00, 0.00, 0.03 ], [ 3.72, -13.88, 1.38 ], [ 0.00, 0.00, 0.03 ] ] ), - (138, [ [ -783.70, 237.40, 92.10 ], [ 32.00, -1.80, -16.20 ], [ 0.78, 1.55, 14.36 ], [ 0.01, 0.00, 0.03 ], [ -5.24, -12.85, 4.06 ], [ 0.00, 0.00, 0.03 ] ] ), - (139, [ [ -754.40, 192.40, 70.50 ], [ 45.00, -18.70, -9.80 ], [ 0.78, 1.56, 14.40 ], [ 5.40, -1.59, -6.72 ], [ -7.57, -12.17, 2.24 ], [ 5.40, -1.59, -6.72 ] ] ), - (140, [ [ -680.80, 179.60, 31.60 ], [ 3.90, -10.60, -67.30 ], [ 14.18, -2.40, -2.32 ], [ -5.09, -0.39, -13.72 ], [ -1.81, -14.39, -1.36 ], [ -5.09, -0.39, -13.72 ] ] ), - (141, [ [ -737.10, 190.00, 35.60 ], [ -37.20, 15.70, 15.30 ], [ -4.87, -0.09, -13.78 ], [ -6.37, 1.87, -5.13 ], [ -4.36, -13.86, 1.59 ], [ -6.37, 1.87, -5.13 ] ] ), - (142, [ [ -781.90, 194.00, 48.10 ], [ -20.90, -6.20, -4.10 ], [ -2.21, 1.47, -14.40 ], [ -2.28, 2.28, 1.31 ], [ 0.21, -14.37, -2.80 ], [ -2.28, 2.28, 1.31 ] ] ), - (143, [ [ -802.30, 178.10, 41.90 ], [ -11.30, -27.20, 3.00 ], [ -7.37, 4.17, -11.97 ], [ -3.69, -0.20, 1.59 ], [ 11.43, -3.27, -8.59 ], [ -3.69, -0.20, 1.59 ] ] ), - (144, [ [ -799.10, 145.80, 39.00 ], [ 22.40, -22.60, -18.40 ], [ -9.21, 0.32, -11.44 ], [ -1.30, -2.70, 0.36 ], [ 7.14, 11.63, -5.43 ], [ -1.30, -2.69, 0.36 ] ] ), - (145, [ [ -731.20, 157.30, 2.00 ], [ 50.10, -43.00, -3.70 ], [ -9.25, 0.32, -11.48 ], [ -0.04, -0.00, -0.04 ], [ 2.50, 13.49, -5.40 ], [ -0.04, 0.00, -0.05 ] ] ), - (146, [ [ -669.40, 112.80, 4.40 ], [ 136.30, 170.20, -47.50 ], [ -9.29, 0.32, -11.53 ], [ -0.05, 0.00, -0.06 ], [ -10.54, 6.75, 7.91 ], [ -0.04, 0.00, -0.06 ] ] ), - (147, [ [ -750.70, 184.10, 17.70 ], [ -76.40, -20.30, -34.70 ], [ -9.34, 0.32, -11.59 ], [ -0.04, 0.00, -0.06 ], [ -8.52, -9.53, -7.65 ], [ -0.05, 0.00, -0.06 ] ] ), - (148, [ [ -840.70, 197.30, -8.00 ], [ -65.70, -54.00, -27.90 ], [ -9.38, 0.32, -11.65 ], [ -0.04, 0.00, -0.05 ], [ -0.45, -11.86, -9.11 ], [ -0.04, 0.00, -0.05 ] ] ), - (149, [ [ -770.00, 153.90, -18.30 ], [ 146.60, 96.20, 29.90 ], [ -9.43, 0.33, -11.70 ], [ 9.19, 1.65, -0.79 ], [ -14.26, 2.89, 3.77 ], [ 9.19, 1.65, -0.79 ] ] ), - (150, [ [ -687.80, 179.20, -17.80 ], [ 93.00, 6.90, 16.70 ], [ 6.85, 3.24, -13.05 ], [ 9.87, 3.45, 8.75 ], [ 3.05, 14.36, 3.50 ], [ 9.86, 3.45, 8.75 ] ] ), - (151, [ [ -660.00, 168.80, 104.60 ], [ -61.10, -12.30, 52.70 ], [ 6.81, 7.53, 11.29 ], [ -10.02, -0.74, 9.08 ], [ -7.36, 12.69, -3.93 ], [ -10.02, -0.74, 9.08 ] ] ), - (152, [ [ -732.50, 164.50, 92.40 ], [ -75.70, -13.60, -3.40 ], [ -8.83, 3.96, 11.77 ], [ -7.28, -3.78, 0.66 ], [ -9.24, 10.65, -5.78 ], [ -7.28, -3.78, 0.66 ] ] ), - (153, [ [ -785.80, 124.60, 91.40 ], [ -10.20, -35.80, -2.20 ], [ -8.66, -0.00, 12.60 ], [ 6.65, -4.80, 1.10 ], [ -12.54, 2.40, -8.41 ], [ 6.65, -4.79, 1.10 ] ] ), - (154, [ [ -759.00, 91.20, 83.60 ], [ 119.50, -1.50, 4.30 ], [ 3.31, -5.48, 13.92 ], [ 5.90, -3.29, 1.00 ], [ 3.90, -13.84, -5.30 ], [ 5.90, -3.29, 1.00 ] ] ), - (155, [ [ -640.80, 136.60, 98.60 ], [ 46.60, 50.10, 7.60 ], [ -4.70, -3.76, 14.19 ], [ -2.83, 0.60, 0.12 ], [ 7.80, -13.29, 0.39 ], [ -2.82, 0.60, 0.12 ] ] ), - (156, [ [ -579.70, 151.60, 100.30 ], [ 19.20, -49.70, 4.50 ], [ -4.72, -3.77, 14.23 ], [ -0.02, -0.02, 0.05 ], [ -11.83, -8.30, -5.49 ], [ -0.02, -0.01, 0.05 ] ] ), - (157, [ [ -626.30, 99.70, 102.90 ], [ -45.20, -3.50, 0.20 ], [ -4.73, -3.79, 14.28 ], [ 0.63, 2.69, 0.49 ], [ -6.14, 13.83, 3.44 ], [ 0.63, 2.69, 0.49 ] ] ), - (158, [ [ -677.50, 87.90, 102.10 ], [ -1.10, -44.00, 15.60 ], [ -3.61, 0.95, 15.10 ], [ -0.22, -0.88, -0.12 ], [ -14.64, -4.84, -2.01 ], [ -0.22, -0.88, -0.12 ] ] ), - (159, [ [ -658.60, 70.80, 123.20 ], [ 64.50, -18.30, 7.60 ], [ -4.75, -3.80, 14.34 ], [ -0.57, -2.37, -0.37 ], [ -5.27, -13.73, -5.13 ], [ -0.57, -2.36, -0.37 ] ] ), - (160, [ [ -663.80, 52.80, 121.60 ], [ -54.40, -14.30, -27.10 ], [ -4.76, -3.81, 14.36 ], [ -0.01, -0.01, 0.03 ], [ -3.89, 14.85, 2.76 ], [ -0.01, -0.01, 0.03 ] ] ), - (161, [ [ -714.90, 78.70, 84.40 ], [ -26.00, -24.40, -65.40 ], [ -4.77, -3.82, 14.40 ], [ -0.02, -0.01, 0.05 ], [ -4.68, 12.40, 8.31 ], [ -0.02, -0.01, 0.05 ] ] ), - (162, [ [ -658.40, 32.50, 83.90 ], [ 2.10, 116.00, -7.20 ], [ -4.79, -3.83, 14.47 ], [ -0.02, -0.01, 0.06 ], [ 14.11, -4.76, 5.01 ], [ -0.02, -0.02, 0.06 ] ] ), - (163, [ [ -604.60, 113.30, 63.50 ], [ -28.80, 78.00, -53.10 ], [ -4.81, -3.85, 14.53 ], [ -0.02, -0.02, 0.06 ], [ 12.18, -0.65, 10.02 ], [ -0.02, -0.02, 0.06 ] ] ), - (164, [ [ -692.90, 147.10, 50.50 ], [ -30.70, 48.10, -22.50 ], [ -4.84, -3.87, 14.59 ], [ -0.02, -0.01, 0.06 ], [ 13.01, 4.40, 7.92 ], [ -0.02, -0.02, 0.06 ] ] ), - (165, [ [ -760.40, 156.30, 47.10 ], [ 12.40, -68.30, 10.10 ], [ -4.85, -3.88, 14.65 ], [ -0.01, -0.01, 0.05 ], [ -12.81, -8.18, -4.68 ], [ -0.02, -0.01, 0.05 ] ] ), - (166, [ [ -714.60, 117.30, 46.30 ], [ 59.10, -31.90, -3.20 ], [ -4.87, -3.89, 14.69 ], [ 3.35, -1.81, -0.44 ], [ -9.91, -11.19, -5.58 ], [ 3.35, -1.81, -0.44 ] ] ), - (167, [ [ -642.10, 94.70, 41.50 ], [ 86.40, 3.30, -36.50 ], [ 2.64, -7.93, 13.65 ], [ 8.28, 8.12, -9.98 ], [ -5.51, -13.70, -6.17 ], [ 8.28, 8.12, -9.98 ] ] ), - (168, [ [ -636.10, 134.80, 16.40 ], [ 117.50, 19.20, -27.50 ], [ 11.57, 10.42, -3.86 ], [ 5.09, 10.44, -9.95 ], [ 14.85, 3.25, 5.13 ], [ 5.09, 10.44, -9.94 ] ] ), - (169, [ [ -578.20, 88.00, 25.20 ], [ 2.50, -59.30, 17.40 ], [ 11.61, 10.46, -3.87 ], [ 0.54, -10.37, 3.35 ], [ 0.34, 13.63, 8.56 ], [ 0.54, -10.38, 3.35 ] ] ), - (170, [ [ -631.30, 39.10, 34.60 ], [ -128.70, -21.40, -13.20 ], [ 12.62, -9.73, 2.64 ], [ -7.55, -13.18, 3.33 ], [ 9.45, 3.13, 12.72 ], [ -7.54, -13.18, 3.33 ] ] ), - (171, [ [ -704.70, 57.70, 8.40 ], [ -125.70, -34.50, 10.50 ], [ -3.96, -15.50, 2.62 ], [ -13.98, 6.42, -1.88 ], [ -7.24, 0.06, 14.50 ], [ -13.98, 6.42, -1.88 ] ] ), - (172, [ [ -784.50, 117.60, 16.90 ], [ 39.80, 42.00, -36.30 ], [ -14.44, 7.33, -1.76 ], [ 1.81, 11.47, -8.58 ], [ 1.08, 6.87, 14.73 ], [ 1.81, 11.48, -8.57 ] ] ), - (173, [ [ -699.80, 123.10, -24.30 ], [ 55.40, -153.80, -40.30 ], [ -0.55, 7.65, -14.46 ], [ 7.44, 0.19, -6.84 ], [ 13.82, 8.28, 2.90 ], [ 7.45, 0.19, -6.84 ] ] ), - (174, [ [ -800.50, 108.10, -31.70 ], [ -87.40, 47.70, 13.70 ], [ -0.55, 7.69, -14.53 ], [ -0.00, 0.03, -0.05 ], [ -9.81, -11.69, -6.13 ], [ 0.00, 0.03, -0.05 ] ] ), - (175, [ [ -802.60, 73.80, -45.80 ], [ 60.70, -32.10, -7.20 ], [ -0.55, 7.71, -14.56 ], [ -0.00, 0.02, -0.05 ], [ 5.33, 14.05, 6.79 ], [ 0.00, 0.02, -0.05 ] ] ), - (176, [ [ -700.50, 58.60, -44.70 ], [ 56.40, 29.00, 19.90 ], [ -0.55, 7.74, -14.63 ], [ 0.00, 0.03, -0.05 ], [ -9.95, 11.61, 6.37 ], [ 0.00, 0.03, -0.05 ] ] ), - (177, [ [ -650.80, 100.60, -19.70 ], [ 52.40, 82.20, 48.00 ], [ -0.55, 7.77, -14.67 ], [ -2.79, -2.28, -0.32 ], [ -14.95, 6.17, 3.78 ], [ -2.78, -2.28, -0.33 ] ] ), - (178, [ [ -659.10, 149.90, -29.60 ], [ 34.00, 79.40, 15.20 ], [ -5.71, 3.52, -15.24 ], [ -0.18, -0.13, -0.05 ], [ -15.05, 3.41, 6.24 ], [ -0.18, -0.13, -0.05 ] ] ), - (179, [ [ -609.50, 156.90, -23.70 ], [ 15.60, -53.60, -14.70 ], [ -0.56, 7.80, -14.74 ], [ 2.21, 1.85, 0.20 ], [ 14.69, 7.51, 2.51 ], [ 2.21, 1.85, 0.20 ] ] ), - (180, [ [ -609.70, 110.70, -23.20 ], [ 40.80, -48.10, -0.90 ], [ -0.56, 7.82, -14.77 ], [ -2.04, -1.11, 0.02 ], [ 7.42, 14.22, 4.72 ], [ -2.04, -1.11, 0.02 ] ] ), - (181, [ [ -646.50, 26.10, -11.20 ], [ -162.60, -77.40, 15.80 ], [ -7.08, 4.22, -14.63 ], [ -2.07, 0.47, 11.78 ], [ 2.94, -15.18, -6.54 ], [ -2.07, 0.47, 11.79 ] ] ), - (182, [ [ -611.30, 41.40, 96.10 ], [ 57.30, 45.80, -2.40 ], [ -3.08, 10.25, 13.06 ], [ -0.50, -9.06, 9.07 ], [ 11.26, -7.87, 9.80 ], [ -0.50, -9.06, 9.07 ] ] ), - (183, [ [ -577.60, 74.90, 90.60 ], [ 55.80, -10.00, 15.40 ], [ -5.16, -4.13, 15.57 ], [ -1.04, -7.16, 1.27 ], [ -1.68, -16.12, -4.83 ], [ -1.04, -7.15, 1.27 ] ] ), - (184, [ [ -584.90, 34.80, 107.90 ], [ -13.40, -36.10, 14.60 ], [ -5.17, -4.14, 15.60 ], [ -0.01, -0.00, 0.03 ], [ -15.74, -6.26, 0.66 ], [ -0.01, -0.01, 0.03 ] ] ), - (185, [ [ -599.80, -4.20, 106.40 ], [ -10.50, -58.00, -59.30 ], [ -5.18, -4.14, 15.63 ], [ -0.01, -0.00, 0.03 ], [ -12.83, 10.88, 2.29 ], [ -0.01, -0.01, 0.03 ] ] ), - (186, [ [ -560.70, -5.80, 103.50 ], [ 22.80, 77.00, 53.00 ], [ -5.19, -4.15, 15.66 ], [ -0.01, -0.01, 0.04 ], [ 15.79, -3.31, 5.42 ], [ -0.01, -0.01, 0.04 ] ] ), - (187, [ [ -539.50, 62.70, 103.50 ], [ 25.80, 91.30, 0.00 ], [ -5.20, -4.16, 15.71 ], [ -0.01, -0.01, 0.04 ], [ 13.65, -9.49, 3.87 ], [ -0.01, -0.01, 0.04 ] ] ), - (188, [ [ -509.90, 125.70, 103.50 ], [ 40.90, 31.10, 0.00 ], [ -5.22, -4.18, 15.75 ], [ -0.01, -0.01, 0.03 ], [ 4.21, -16.58, -0.17 ], [ -0.01, -0.01, 0.03 ] ] ), - (189, [ [ -480.30, 136.30, 103.50 ], [ 27.90, -1.50, 0.00 ], [ -5.23, -4.18, 15.77 ], [ -0.00, 0.00, 0.02 ], [ -5.84, -15.48, -4.46 ], [ -0.01, -0.00, 0.02 ] ] ), - (190, [ [ -463.80, 126.60, 103.50 ], [ 2.20, -41.60, 0.00 ], [ -5.23, -4.18, 15.79 ], [ -0.00, -0.00, 0.02 ], [ -15.56, -4.73, -5.44 ], [ -0.01, -0.01, 0.02 ] ] ), - (191, [ [ -502.40, 82.30, 103.50 ], [ -23.60, -27.20, 0.00 ], [ -5.24, -4.19, 15.83 ], [ -0.01, -0.01, 0.02 ], [ -16.28, 5.39, -1.21 ], [ -0.01, -0.01, 0.02 ] ] ), - (192, [ [ -509.30, 56.80, 103.50 ], [ 23.00, -22.90, 0.00 ], [ -5.25, -4.20, 15.84 ], [ -0.01, -0.01, 0.02 ], [ -11.71, -10.69, -6.68 ], [ -0.01, -0.01, 0.02 ] ] ), - (193, [ [ -475.50, 64.70, 103.50 ], [ 44.10, -1.90, 0.00 ], [ -5.26, -4.21, 15.86 ], [ -0.01, -0.01, 0.03 ], [ -5.75, -15.63, -4.43 ], [ -0.01, -0.01, 0.03 ] ] ), - (194, [ [ -430.20, 49.30, 103.50 ], [ 14.50, -56.10, 1.00 ], [ -5.27, -4.21, 15.90 ], [ -0.01, -0.01, 0.04 ], [ -14.56, -7.00, -6.10 ], [ -0.01, -0.01, 0.04 ] ] ), - (195, [ [ -469.90, 5.30, 104.60 ], [ -58.90, -25.60, -18.20 ], [ -5.28, -4.22, 15.94 ], [ -0.01, -0.01, 0.04 ], [ -8.97, 14.76, 1.17 ], [ -0.01, -0.01, 0.04 ] ] ), - (196, [ [ -530.20, 8.80, 71.20 ], [ -89.40, 9.00, -28.70 ], [ -5.30, -4.24, 15.98 ], [ -0.01, -0.01, 0.04 ], [ 0.47, 16.73, 4.60 ], [ -0.01, -0.01, 0.04 ] ] ), - (197, [ [ -549.80, 51.30, 74.50 ], [ 56.60, 60.50, 38.30 ], [ -5.31, -4.25, 16.02 ], [ -0.01, -0.01, 0.04 ], [ 12.78, -11.75, 1.14 ], [ -0.01, -0.01, 0.04 ] ] ), - (198, [ [ -531.30, 109.40, 71.30 ], [ 86.60, 49.60, 3.50 ], [ -5.32, -4.26, 16.06 ], [ -0.02, -0.01, 0.05 ], [ 2.78, -17.18, -1.27 ], [ -0.02, -0.01, 0.05 ] ] ), - (199, [ [ -456.50, 140.50, 51.60 ], [ 45.40, 11.90, -8.30 ], [ -5.34, -4.27, 16.11 ], [ -0.02, -0.01, 0.05 ], [ -5.25, -16.65, -1.17 ], [ -0.02, -0.01, 0.05 ] ] ), - (200, [ [ -423.00, 81.00, 50.80 ], [ -44.50, -103.30, -0.20 ], [ -5.36, -4.28, 16.16 ], [ -0.02, -0.02, 0.07 ], [ -17.24, 0.87, -3.24 ], [ -0.02, -0.02, 0.07 ] ] ), - (201, [ [ -549.80, 34.30, 52.00 ], [ -12.30, -134.80, -12.90 ], [ -5.39, -4.31, 16.25 ], [ -0.02, -0.02, 0.08 ], [ -16.81, -1.21, -5.26 ], [ -0.03, -0.02, 0.08 ] ] ), - (202, [ [ -465.30, -17.50, 49.30 ], [ -46.30, -108.10, -19.60 ], [ -5.41, -4.33, 16.33 ], [ 2.96, 6.02, -0.20 ], [ -16.81, 4.20, -3.77 ], [ 2.95, 6.02, -0.20 ] ] ), - (203, [ [ -578.60, -16.50, 42.30 ], [ -82.70, 25.50, -15.40 ], [ 0.72, 8.13, 15.84 ], [ -3.24, 8.71, -6.08 ], [ 7.05, 14.46, -7.67 ], [ -3.24, 8.71, -6.08 ] ] ), - (204, [ [ -536.60, 25.20, 15.60 ], [ 37.70, 57.90, -21.80 ], [ -8.45, 14.47, 6.22 ], [ -2.87, -6.71, 0.69 ], [ 12.08, 3.54, 12.69 ], [ -2.87, -6.71, 0.69 ] ] ), - (205, [ [ -529.00, 93.90, 11.80 ], [ 61.50, 67.50, -4.90 ], [ -5.47, -4.37, 16.50 ], [ 1.52, -9.66, 5.29 ], [ 6.71, -16.55, 1.52 ], [ 1.52, -9.66, 5.29 ] ] ), - (206, [ [ -468.20, 137.50, 16.60 ], [ 50.60, 13.70, -2.50 ], [ -5.48, -4.39, 16.55 ], [ -0.02, -0.01, 0.05 ], [ -2.85, -17.58, -2.46 ], [ -0.02, -0.01, 0.05 ] ] ), - (207, [ [ -398.80, 135.90, 16.10 ], [ 54.50, -33.90, -12.10 ], [ -5.50, -4.40, 16.59 ], [ -0.02, -0.01, 0.04 ], [ -13.91, -10.03, -5.53 ], [ -0.01, -0.01, 0.04 ] ] ), - (208, [ [ -378.80, 78.80, 14.50 ], [ -8.10, -48.90, 36.10 ], [ -5.51, -4.41, 16.63 ], [ -0.01, -0.01, 0.04 ], [ -12.52, -12.24, 4.45 ], [ -0.01, -0.01, 0.04 ] ] ), - (209, [ [ -398.00, 36.20, 45.80 ], [ -34.00, -45.80, 24.00 ], [ -5.52, -4.42, 16.67 ], [ -0.01, -0.01, 0.04 ], [ -17.64, -2.43, 3.29 ], [ -0.01, -0.01, 0.04 ] ] ), - (210, [ [ -442.20, -17.60, 57.50 ], [ -86.50, -40.80, 33.20 ], [ -5.54, -4.43, 16.71 ], [ -0.02, -0.01, 0.05 ], [ -15.53, 7.63, 5.49 ], [ -0.02, -0.01, 0.05 ] ] ), - (211, [ [ -533.50, -18.10, 72.80 ], [ -62.70, -13.50, 25.80 ], [ -5.56, -4.45, 16.77 ], [ -0.01, -0.01, 0.05 ], [ -12.65, 10.76, 7.49 ], [ -0.01, -0.01, 0.04 ] ] ), - (212, [ [ -559.10, -59.00, 75.10 ], [ 21.70, -55.50, 8.30 ], [ -5.57, -4.45, 16.81 ], [ -0.01, -0.01, 0.04 ], [ -13.30, -10.90, -6.13 ], [ -0.01, -0.01, 0.04 ] ] ), - (213, [ [ -500.70, -84.90, 81.00 ], [ 63.70, 28.70, 0.20 ], [ -5.58, -4.47, 16.85 ], [ -0.02, -0.02, 0.05 ], [ 0.67, -18.20, -1.80 ], [ -0.02, -0.01, 0.05 ] ] ), - (214, [ [ -421.10, -26.60, 49.00 ], [ 38.30, 45.90, -36.30 ], [ -5.61, -4.48, 16.92 ], [ -0.02, -0.02, 0.05 ], [ 0.68, -16.06, 8.91 ], [ -0.02, -0.01, 0.05 ] ] ), - (215, [ [ -382.00, 4.70, 3.40 ], [ 8.90, 68.80, -40.90 ], [ -5.62, -4.50, 16.96 ], [ -0.01, -0.01, 0.04 ], [ 10.76, -10.19, 10.95 ], [ -0.01, -0.01, 0.04 ] ] ), - (216, [ [ -389.10, 52.20, -22.10 ], [ -29.80, 81.20, -22.40 ], [ -5.63, -4.50, 17.00 ], [ -0.01, -0.01, 0.04 ], [ 16.48, 1.20, 8.24 ], [ -0.01, -0.01, 0.04 ] ] ), - (217, [ [ -412.00, 118.00, -36.80 ], [ -99.40, 115.40, 42.30 ], [ -5.65, -4.52, 17.04 ], [ -0.02, -0.02, 0.05 ], [ 10.62, 12.72, 8.25 ], [ -0.02, -0.01, 0.05 ] ] ), - (218, [ [ -500.70, 120.50, -22.30 ], [ -52.50, -122.90, 19.40 ], [ -5.67, -4.53, 17.11 ], [ -0.02, -0.02, 0.08 ], [ -18.33, -2.16, -2.14 ], [ -0.03, -0.02, 0.08 ] ] ), - (219, [ [ -430.50, 6.20, -21.60 ], [ -110.00, -102.90, 20.20 ], [ -5.70, -4.56, 17.20 ], [ -0.04, -0.03, 0.10 ], [ -17.92, 5.26, 0.70 ], [ -0.03, -0.03, 0.10 ] ] ), - (220, [ [ -561.60, 93.90, -37.50 ], [ -136.90, -93.80, 13.70 ], [ -5.74, -4.59, 17.31 ], [ -0.03, -0.02, 0.10 ], [ -16.55, 8.84, 1.26 ], [ -0.03, -0.03, 0.10 ] ] ), - (221, [ [ -478.90, -3.90, -57.80 ], [ 64.00, -137.50, 21.40 ], [ -5.77, -4.61, 17.41 ], [ 6.63, 6.39, -0.25 ], [ -13.24, -11.81, -6.52 ], [ 6.62, 6.39, -0.25 ] ] ), - (222, [ [ -431.20, -73.10, -4.70 ], [ -33.20, -2.10, 83.80 ], [ 5.72, 6.46, 16.91 ], [ -1.05, -1.02, 0.11 ], [ -11.35, 11.23, 10.26 ], [ -1.05, -1.01, 0.11 ] ] ), - (223, [ [ -498.10, -26.50, 1.10 ], [ -106.30, 89.80, -35.30 ], [ -5.81, -4.65, 17.53 ], [ -6.98, -6.72, 0.41 ], [ 11.98, 12.58, 7.79 ], [ -6.98, -6.72, 0.41 ] ] ), - (224, [ [ -612.20, 36.10, 28.20 ], [ -42.00, -52.50, 15.50 ], [ -5.84, -4.67, 17.62 ], [ -0.02, -0.01, 0.06 ], [ -19.10, 0.99, 0.89 ], [ -0.02, -0.02, 0.06 ] ] ), - (225, [ [ -599.60, -31.30, 28.40 ], [ 13.40, -54.20, -7.20 ], [ -5.85, -4.68, 17.67 ], [ -0.02, -0.01, 0.04 ], [ -17.41, -4.28, -6.86 ], [ -0.01, -0.01, 0.04 ] ] ), - (226, [ [ -551.10, -68.30, 48.80 ], [ 70.00, -22.30, 2.00 ], [ -5.87, -4.69, 17.71 ], [ -0.02, -0.01, 0.04 ], [ -8.76, -15.91, -6.35 ], [ -0.01, -0.01, 0.04 ] ] ), - (227, [ [ -489.30, -77.50, 38.10 ], [ 74.30, 17.00, -23.00 ], [ -5.88, -4.70, 17.75 ], [ -0.01, -0.01, 0.04 ], [ -8.41, -17.35, 0.23 ], [ -0.01, -0.01, 0.04 ] ] ), - (228, [ [ -463.60, -26.20, 12.80 ], [ -33.30, 65.70, 20.70 ], [ -5.90, -4.72, 17.80 ], [ -0.02, -0.02, 0.06 ], [ 15.11, 9.01, 8.02 ], [ -0.02, -0.02, 0.06 ] ] ), - (229, [ [ -582.60, 39.80, -15.30 ], [ -97.00, -93.30, -56.80 ], [ -5.93, -4.74, 17.89 ], [ -0.03, -0.02, 0.09 ], [ -13.28, 14.18, -0.64 ], [ -0.03, -0.02, 0.09 ] ] ), - (230, [ [ -535.10, -48.00, -7.60 ], [ 163.70, -58.30, -145.00 ], [ -5.95, -4.76, 17.97 ], [ -0.02, -0.02, 0.08 ], [ -18.23, -5.43, 4.37 ], [ -0.03, -0.02, 0.08 ] ] ), - (231, [ [ -451.00, -130.20, 37.30 ], [ -10.40, 16.50, 63.10 ], [ -5.98, -4.79, 18.06 ], [ -0.02, -0.02, 0.06 ], [ 6.41, 1.38, 18.49 ], [ -0.02, -0.02, 0.06 ] ] ), - (232, [ [ -404.70, -90.30, 45.30 ], [ 28.50, 23.80, -5.20 ], [ -6.00, -4.80, 18.11 ], [ -0.02, -0.01, 0.04 ], [ 3.14, -19.36, 1.56 ], [ -0.01, -0.01, 0.04 ] ] ), - (233, [ [ -373.40, -43.10, 39.40 ], [ 5.90, 71.90, -6.80 ], [ -6.01, -4.81, 18.14 ], [ 0.41, 8.07, -8.50 ], [ 16.98, -7.83, 6.23 ], [ 0.41, 8.07, -8.50 ] ] ), - (234, [ [ -350.70, 43.10, -5.50 ], [ 0.30, -23.00, -85.30 ], [ -4.83, 18.19, -6.12 ], [ 3.76, 0.99, -18.90 ], [ 19.16, 4.38, -2.31 ], [ 3.76, 0.98, -18.90 ] ] ), - (235, [ [ -326.20, -52.10, 3.90 ], [ 120.10, -136.40, 45.10 ], [ 1.61, -3.65, -19.46 ], [ 8.00, -8.11, -5.57 ], [ 14.41, 13.59, -1.41 ], [ 8.00, -8.11, -5.57 ] ] ), - (236, [ [ -415.40, -151.90, 68.80 ], [ -13.60, -50.50, -41.70 ], [ 11.95, 8.73, -13.42 ], [ -5.91, 8.77, 17.85 ], [ 15.71, -9.68, 7.65 ], [ -5.91, 8.77, 17.85 ] ] ), - (237, [ [ -353.60, -118.40, -8.30 ], [ 36.00, 49.60, -67.80 ], [ -4.64, 15.12, 12.19 ], [ -6.76, -0.33, 14.51 ], [ 16.78, -2.81, 10.45 ], [ -6.76, -0.33, 14.52 ] ] ), - (238, [ [ -394.00, -54.90, -43.90 ], [ -58.50, 62.10, 18.60 ], [ -3.17, 9.16, 17.42 ], [ -2.87, -4.30, 1.63 ], [ 2.17, 19.78, -1.25 ], [ -2.88, -4.30, 1.64 ] ] ), - (239, [ [ -374.20, 70.30, -64.10 ], [ -51.80, 111.20, -42.80 ], [ -12.32, 7.26, 13.82 ], [ -4.29, -2.14, -1.16 ], [ 11.60, 15.19, 5.49 ], [ -4.31, -2.13, -1.15 ] ] ), - (240, [ [ -480.40, 88.90, -81.20 ], [ -77.00, -72.50, -24.50 ], [ -12.13, 4.91, 14.92 ], [ 4.11, -0.54, 2.38 ], [ -10.25, 12.01, -12.03 ], [ 4.12, -0.54, 2.40 ] ] ), - (241, [ [ -447.70, 23.20, -62.70 ], [ 98.20, -53.90, -35.40 ], [ -5.03, 5.74, 18.28 ], [ 6.87, 3.25, 0.83 ], [ -16.98, -8.10, 6.21 ], [ 6.89, 3.27, 0.84 ] ] ), - (242, [ [ -382.90, -144.70, -29.60 ], [ -142.90, -41.30, 110.60 ], [ 1.32, 14.36, 13.47 ], [ 2.82, 3.81, -2.16 ], [ -14.51, 10.33, -8.50 ], [ 2.83, 3.84, -2.15 ] ] ), - (243, [ [ -481.80, -39.40, -48.90 ], [ -146.60, -39.20, 12.20 ], [ 1.32, 14.32, 13.43 ], [ -0.00, -0.05, -0.04 ], [ -0.87, 14.04, -13.76 ], [ 0.00, -0.03, -0.03 ] ] ), - (244, [ [ -453.60, -166.50, -38.80 ], [ 150.00, -6.00, -58.50 ], [ 1.32, 14.27, 13.39 ], [ -0.01, -0.05, -0.05 ], [ 0.80, -12.79, 14.84 ], [ 0.00, -0.03, -0.03 ] ] ), - (245, [ [ -534.60, 2.00, -60.70 ], [ -321.90, 11.50, 28.90 ], [ 1.31, 14.21, 13.34 ], [ -0.01, -0.04, -0.04 ], [ -1.19, 13.41, -14.16 ], [ 0.00, -0.03, -0.03 ] ] ), - (246, [ [ -620.80, 88.60, -65.80 ], [ -173.30, -112.90, -24.50 ], [ 1.31, 14.17, 13.30 ], [ -0.00, -0.04, -0.04 ], [ 3.06, 16.52, -9.87 ], [ 0.00, -0.03, -0.02 ] ] ), - (247, [ [ -601.00, -61.20, -12.30 ], [ 87.00, -77.00, 21.40 ], [ 1.31, 14.13, 13.26 ], [ 9.17, -14.24, -6.83 ], [ -15.51, -5.72, 10.20 ], [ 9.27, -14.39, -6.89 ] ] ), - (248, [ [ -524.30, -72.50, -58.30 ], [ -55.40, -200.40, -26.20 ], [ 16.67, -9.71, 1.85 ], [ 5.34, -1.84, -3.12 ], [ -4.21, -6.04, 17.93 ], [ 5.41, -1.85, -3.14 ] ] ), - (249, [ [ -516.70, -125.70, 44.60 ], [ 99.10, -71.00, 10.10 ], [ 10.37, 14.01, 8.37 ], [ 1.88, 3.64, -8.37 ], [ -5.23, -6.48, 17.45 ], [ 1.91, 3.68, -8.47 ] ] ), - (250, [ [ -511.50, -154.20, 13.70 ], [ -22.70, 29.20, -59.80 ], [ 15.95, 8.57, -6.73 ], [ -3.65, -0.47, 0.86 ], [ 3.16, -14.02, -12.90 ], [ -3.69, -0.47, 0.87 ] ] ), - (251, [ [ -507.90, -150.60, -52.20 ], [ 77.80, 65.80, -26.70 ], [ 1.29, 14.04, 13.17 ], [ -8.54, 3.17, 11.58 ], [ 16.50, -6.06, 7.94 ], [ -8.65, 3.22, 11.73 ] ] ), - (252, [ [ -501.90, -69.20, -84.50 ], [ 124.80, -47.20, -52.70 ], [ 1.29, 14.00, 13.15 ], [ -0.00, -0.03, -0.03 ], [ -6.41, -9.18, 15.66 ], [ -0.00, -0.02, -0.02 ] ] ), - (253, [ [ -435.40, -182.40, -85.30 ], [ 133.20, -88.90, 11.70 ], [ 1.29, 13.97, 13.11 ], [ -6.83, -0.95, -2.07 ], [ -13.01, -7.62, 11.89 ], [ -6.94, -0.95, -2.09 ] ] ), - (254, [ [ -364.90, -190.70, -12.50 ], [ -54.90, -42.00, 69.00 ], [ -11.49, 12.22, 9.26 ], [ -5.25, 1.16, -5.56 ], [ -16.97, -6.24, -6.34 ], [ -5.33, 1.18, -5.63 ] ] ), - (255, [ [ -340.30, -163.80, 48.10 ], [ 128.90, 72.90, -11.00 ], [ -10.62, 15.74, 2.32 ], [ 1.45, 0.79, 0.19 ], [ 0.86, -2.05, 19.00 ], [ 1.47, 0.81, 0.20 ] ] ), - (256, [ [ -317.00, -143.90, -26.80 ], [ -88.40, -30.90, -19.80 ], [ -8.52, 13.49, 10.49 ], [ 6.33, -0.81, 5.07 ], [ -1.83, 11.02, -15.49 ], [ 6.43, -0.81, 5.16 ] ] ), - (257, [ [ -358.50, -142.30, -98.10 ], [ -66.10, 25.40, -1.30 ], [ 1.28, 13.87, 13.01 ], [ 6.65, 0.24, 1.70 ], [ 1.62, 13.39, -13.47 ], [ 6.77, 0.26, 1.74 ] ] ), - (258, [ [ -360.30, 29.80, -104.30 ], [ 133.20, -2.90, 37.90 ], [ 1.28, 13.82, 12.96 ], [ -6.70, -8.71, 0.72 ], [ 0.26, -12.21, 14.54 ], [ -6.84, -8.87, 0.75 ] ] ), - (259, [ [ -315.60, -96.60, -32.70 ], [ 59.80, 120.90, 165.90 ], [ -11.84, -3.18, 14.42 ], [ 4.77, -4.90, 1.16 ], [ 12.32, -9.78, 10.52 ], [ 4.87, -4.98, 1.20 ] ] ), - (260, [ [ -314.20, 51.50, -89.10 ], [ 14.30, 127.70, -5.60 ], [ 10.40, 3.75, 15.28 ], [ -1.05, -1.37, -0.07 ], [ 15.80, 2.03, -10.10 ], [ -1.08, -1.40, -0.05 ] ] ), - (261, [ [ -333.70, 97.10, 47.00 ], [ 52.00, 38.50, 28.60 ], [ -11.07, -4.90, 14.39 ], [ -3.38, 4.27, -19.59 ], [ 6.15, -17.76, 0.41 ], [ -3.45, 4.37, -20.04 ] ] ), - (262, [ [ -304.70, 120.30, -32.00 ], [ 62.80, -40.80, -60.10 ], [ -3.09, 7.47, -16.93 ], [ 3.93, 2.96, -20.26 ], [ 15.41, 10.71, 0.20 ], [ 4.01, 3.02, -20.74 ] ] ), - (263, [ [ -235.30, -46.60, 17.40 ], [ 156.60, -68.60, 59.20 ], [ -7.31, -8.51, -14.95 ], [ 11.87, -4.32, 3.21 ], [ 1.54, 13.58, -12.75 ], [ 12.18, -4.43, 3.27 ] ] ), - (264, [ [ -160.60, 8.90, 41.90 ], [ 96.20, 60.70, -14.40 ], [ 13.67, -6.24, -11.05 ], [ 7.32, 9.43, 12.02 ], [ 1.39, 12.62, -13.67 ], [ 7.50, 9.68, 12.33 ] ] ), - (265, [ [ -233.60, 108.70, 14.10 ], [ -196.10, -54.60, -35.60 ], [ 1.25, 13.53, 12.70 ], [ -6.34, 10.06, 12.10 ], [ 5.57, 13.67, -11.32 ], [ -6.50, 10.34, 12.42 ] ] ), - (266, [ [ -327.10, -7.90, -1.40 ], [ 30.20, -91.10, 80.60 ], [ 1.24, 13.49, 12.66 ], [ -1.77, -3.98, 2.52 ], [ -18.20, -1.26, 3.28 ], [ -1.82, -4.08, 2.60 ] ] ), - (267, [ [ -223.10, 8.60, 56.80 ], [ 64.40, 127.00, 90.60 ], [ -1.99, 6.25, 17.29 ], [ 5.46, -14.42, -3.87 ], [ 14.70, 2.28, 10.98 ], [ 5.63, -14.85, -3.98 ] ] ), - (268, [ [ -253.90, 87.40, 105.10 ], [ -5.80, 39.60, 111.40 ], [ 10.24, -13.76, 6.80 ], [ -1.00, 9.40, -0.35 ], [ 15.17, 10.40, -1.53 ], [ -1.03, 9.68, -0.35 ] ] ), - (269, [ [ -243.10, 128.50, 112.80 ], [ 95.00, 13.80, 1.40 ], [ 1.24, 13.41, 12.59 ], [ -4.00, 12.07, 2.56 ], [ 4.92, -11.96, 13.14 ], [ -4.12, 12.44, 2.65 ] ] ), - (270, [ [ -198.40, 111.30, 103.50 ], [ 29.70, -22.50, 0.00 ], [ 1.24, 13.40, 12.58 ], [ -0.01, -0.01, -0.01 ], [ -13.25, -5.74, 11.43 ], [ 0.00, -0.01, -0.01 ] ] ), - (271, [ [ -179.80, 86.80, 103.50 ], [ 15.50, -40.20, -2.20 ], [ 1.23, 13.39, 12.57 ], [ -0.01, -0.01, -0.01 ], [ -15.58, 7.24, 6.61 ], [ 0.00, -0.01, -0.01 ] ] ), - (272, [ [ -181.00, 44.30, 103.40 ], [ -23.30, -31.20, 0.00 ], [ 1.23, 13.38, 12.56 ], [ -0.00, -0.01, -0.01 ], [ -3.20, 16.69, -7.02 ], [ 0.00, -0.01, -0.01 ] ] ), - (273, [ [ -212.60, 28.50, 103.50 ], [ -45.50, -9.50, 0.00 ], [ 1.23, 13.37, 12.55 ], [ -0.00, -0.01, -0.01 ], [ 1.29, 13.09, -12.83 ], [ 0.00, -0.01, -0.01 ] ] ), - (274, [ [ -268.30, 32.40, 103.80 ], [ -47.70, 23.20, -5.70 ], [ 1.23, 13.35, 12.54 ], [ -0.00, -0.01, -0.02 ], [ 3.87, 12.54, -12.83 ], [ 0.00, -0.01, -0.01 ] ] ), - (275, [ [ -303.20, 68.70, 92.20 ], [ -16.00, 43.30, -4.00 ], [ 1.23, 13.34, 12.52 ], [ -0.00, -0.01, -0.02 ], [ 9.07, 14.46, -6.70 ], [ 0.00, -0.01, -0.01 ] ] ), - (276, [ [ -264.40, 113.10, 92.20 ], [ 96.40, 13.40, -16.30 ], [ 1.23, 13.32, 12.51 ], [ -0.00, -0.02, -0.02 ], [ 4.82, -12.29, 12.69 ], [ 0.00, -0.01, -0.01 ] ] ), - (277, [ [ -194.80, 79.90, 66.60 ], [ 66.40, 101.30, -2.50 ], [ 1.23, 13.30, 12.48 ], [ -0.00, -0.02, -0.02 ], [ 17.04, 2.78, 6.03 ], [ 0.00, -0.02, -0.02 ] ] ), - (278, [ [ -259.90, 145.40, 69.10 ], [ -50.20, 11.70, 0.70 ], [ 1.23, 13.27, 12.46 ], [ -0.00, -0.02, -0.02 ], [ 0.71, 12.60, -13.18 ], [ 0.00, -0.01, -0.01 ] ] ), - (279, [ [ -332.40, 128.50, 76.00 ], [ -49.00, -52.40, -1.30 ], [ 1.23, 13.25, 12.44 ], [ -0.00, -0.02, -0.02 ], [ -1.51, 16.32, -7.96 ], [ 0.00, -0.01, -0.01 ] ] ), - (280, [ [ -350.80, 61.90, 80.80 ], [ -2.80, -49.40, 0.50 ], [ 1.23, 13.24, 12.42 ], [ -0.00, -0.02, -0.02 ], [ -11.79, 13.85, 0.34 ], [ 0.00, -0.01, -0.01 ] ] ), - (281, [ [ -310.50, 4.10, 73.40 ], [ 145.80, -25.20, -6.40 ], [ 1.22, 13.22, 12.40 ], [ -0.01, -0.02, -0.02 ], [ -3.10, -11.99, 13.29 ], [ 0.00, -0.01, -0.01 ] ] ), - (282, [ [ -271.10, -43.80, 94.40 ], [ 16.10, -48.30, 3.80 ], [ 1.22, 13.20, 12.39 ], [ -0.00, -0.01, -0.01 ], [ -16.23, 6.76, 4.48 ], [ 0.00, -0.01, -0.01 ] ] ), - (283, [ [ -270.90, -77.40, 103.40 ], [ 39.70, -14.80, 1.00 ], [ 1.21, 13.19, 12.38 ], [ -0.00, -0.01, -0.01 ], [ -7.61, -10.46, 12.70 ], [ 0.00, -0.01, -0.01 ] ] ), - (284, [ [ -220.70, -87.80, 97.40 ], [ 44.90, 15.00, 0.00 ], [ 1.21, 13.17, 12.36 ], [ -0.00, -0.01, -0.01 ], [ 8.97, -10.04, 12.11 ], [ 0.00, -0.01, -0.01 ] ] ), - (285, [ [ -173.40, -67.30, 82.30 ], [ -11.80, 54.90, -11.40 ], [ 1.21, 13.16, 12.35 ], [ -0.00, -0.02, -0.02 ], [ 12.41, 11.79, -5.84 ], [ 0.00, -0.01, -0.01 ] ] ), - (286, [ [ -229.90, -30.60, 62.70 ], [ -49.80, 8.30, -5.90 ], [ 1.21, 13.14, 12.33 ], [ -0.00, -0.02, -0.01 ], [ 4.00, 11.86, -13.02 ], [ 0.00, -0.01, -0.01 ] ] ), - (287, [ [ -291.70, -26.70, 39.10 ], [ -43.90, 3.80, 0.00 ], [ 1.21, 13.12, 12.32 ], [ -0.00, -0.01, -0.01 ], [ 1.14, 12.27, -13.17 ], [ 0.00, -0.01, -0.01 ] ] ), - (288, [ [ -323.60, -28.80, 45.90 ], [ -29.10, -6.00, 15.70 ], [ 1.21, 13.11, 12.31 ], [ -0.00, -0.01, -0.01 ], [ -10.37, 10.80, -10.04 ], [ 0.00, -0.01, -0.00 ] ] ), - (289, [ [ -340.40, -46.90, 56.00 ], [ -7.70, -28.60, -0.30 ], [ 1.21, 13.10, 12.30 ], [ -0.00, -0.01, -0.01 ], [ -8.34, 15.83, -2.10 ], [ 0.00, -0.01, -0.01 ] ] ), - (290, [ [ -341.70, -83.90, 64.30 ], [ 5.20, -25.30, 4.60 ], [ 1.21, 13.10, 12.29 ], [ -0.00, -0.01, -0.02 ], [ -16.18, 7.65, 1.97 ], [ 0.00, -0.01, -0.01 ] ] ), - (291, [ [ -327.60, -149.50, 76.40 ], [ 26.30, -22.60, 3.30 ], [ 1.21, 13.08, 12.27 ], [ -0.01, -0.02, -0.02 ], [ -14.04, -4.99, 10.05 ], [ 0.00, -0.01, -0.01 ] ] ), - (292, [ [ -277.60, -101.40, 42.90 ], [ 45.10, -4.20, 0.00 ], [ 1.20, 13.05, 12.26 ], [ -0.00, -0.02, -0.01 ], [ -1.15, -12.20, 13.11 ], [ 0.00, -0.01, -0.01 ] ] ), - (293, [ [ -231.00, -108.20, 27.80 ], [ 42.40, 14.10, 0.00 ], [ 1.20, 13.04, 12.24 ], [ -0.00, -0.01, -0.02 ], [ 8.85, -9.96, 12.00 ], [ 0.00, -0.01, -0.01 ] ] ), - (294, [ [ -180.10, -109.90, 40.70 ], [ 59.10, -19.40, 39.60 ], [ 1.20, 13.03, 12.23 ], [ -0.00, -0.01, -0.02 ], [ -6.93, -10.23, 12.96 ], [ 0.00, -0.01, -0.01 ] ] ), - (295, [ [ -174.70, -116.60, 80.30 ], [ -37.40, 27.50, 45.00 ], [ 1.20, 13.02, 12.21 ], [ -0.00, -0.02, -0.02 ], [ -11.59, 13.58, 1.25 ], [ 0.00, -0.01, -0.01 ] ] ), - (296, [ [ -300.70, -86.10, 54.30 ], [ -63.80, -23.10, 55.90 ], [ 1.20, 12.98, 12.18 ], [ -0.00, -0.03, -0.03 ], [ -13.97, 8.69, -6.90 ], [ 0.00, -0.02, -0.02 ] ] ), - (297, [ [ -289.00, -163.30, 110.50 ], [ -99.30, -43.30, 98.20 ], [ 1.20, 12.96, 12.15 ], [ -0.00, -0.03, -0.04 ], [ -14.68, 8.02, -6.09 ], [ 0.00, -0.02, -0.02 ] ] ), - (298, [ [ -323.00, -11.30, 56.10 ], [ 39.10, 49.20, -8.90 ], [ 1.20, 12.91, 12.11 ], [ -0.01, -0.02, -0.02 ], [ 16.77, -0.61, 5.76 ], [ 0.00, -0.01, -0.01 ] ] ), - (299, [ [ -277.50, 6.40, 49.70 ], [ 95.70, -13.00, 0.00 ], [ 1.18, 12.89, 12.10 ], [ -0.01, -0.02, -0.01 ], [ -2.18, -11.91, 12.93 ], [ 0.00, -0.01, -0.01 ] ] ), - (300, [ [ -191.40, -10.90, 80.50 ], [ 62.80, -7.70, 9.50 ], [ 1.18, 12.87, 12.07 ], [ -0.00, -0.02, -0.02 ], [ -1.98, -11.85, 12.98 ], [ 0.00, -0.01, -0.01 ] ] ), - (301, [ [ -133.30, 24.30, 81.00 ], [ 42.20, 67.00, 0.00 ], [ 1.18, 12.85, 12.06 ], [ -0.00, -0.02, -0.01 ], [ 16.33, 3.31, 5.85 ], [ 0.00, -0.01, -0.01 ] ] ), - (302, [ [ -125.40, 67.10, 93.50 ], [ -20.50, 21.20, -1.40 ], [ 1.18, 12.84, 12.04 ], [ -0.00, -0.01, -0.01 ], [ 3.82, 13.92, -10.13 ], [ 0.00, -0.01, -0.01 ] ] ), - (303, [ [ -181.30, 58.00, 64.50 ], [ -62.10, -31.80, -29.80 ], [ 1.18, 12.82, 12.03 ], [ -0.00, -0.02, -0.02 ], [ 9.05, 14.02, -5.65 ], [ 0.00, -0.01, -0.01 ] ] ), - (304, [ [ -295.90, 96.80, 39.60 ], [ -106.30, -114.70, -51.10 ], [ 1.18, 12.78, 11.99 ], [ -0.00, -0.04, -0.03 ], [ 4.27, 16.73, -3.27 ], [ 0.00, -0.02, -0.02 ] ] ), - (305, [ [ -170.50, 62.70, -13.20 ], [ -26.90, -123.60, 24.00 ], [ 1.18, 12.74, 11.96 ], [ -0.01, -0.04, -0.04 ], [ -11.71, 12.55, -3.44 ], [ 0.00, -0.02, -0.02 ] ] ), - (306, [ [ -274.30, 42.90, 28.40 ], [ -12.60, -108.50, -11.40 ], [ 1.17, 12.71, 11.92 ], [ -0.01, -0.04, -0.04 ], [ -8.86, 15.01, 1.14 ], [ 0.00, -0.02, -0.02 ] ] ), - (307, [ [ -142.90, -22.50, 18.30 ], [ 11.70, 9.50, 57.30 ], [ 1.17, 12.66, 11.88 ], [ 1.17, -1.58, 1.19 ], [ -7.62, 0.99, 15.61 ], [ 1.23, -1.65, 1.27 ] ] ), - (308, [ [ -150.90, -36.10, 84.20 ], [ -5.30, -48.90, 32.20 ], [ 2.86, 10.39, 13.63 ], [ 0.04, -0.08, 0.03 ], [ -16.90, 3.99, 0.66 ], [ 0.05, -0.07, 0.04 ] ] ), - (309, [ [ -135.30, -105.30, 94.80 ], [ -3.20, -32.60, 55.90 ], [ 1.17, 12.62, 11.85 ], [ 5.63, -11.05, 0.16 ], [ -17.04, -0.33, 3.25 ], [ 5.94, -11.65, 0.17 ] ] ), - (310, [ [ -138.40, -135.90, 107.80 ], [ 4.80, -33.70, -0.70 ], [ 10.40, -4.95, 12.96 ], [ 5.06, -12.37, -7.66 ], [ -12.07, -8.08, 9.47 ], [ 5.34, -13.05, -8.09 ] ] ), - (311, [ [ -150.80, -112.60, 40.60 ], [ 1.40, 115.30, 8.10 ], [ 5.48, -4.87, -15.68 ], [ -8.73, -1.10, -16.85 ], [ -15.37, -5.30, -5.93 ], [ -9.22, -1.17, -17.79 ] ] ), - (312, [ [ -176.80, 19.30, -24.60 ], [ 67.20, 241.30, -20.60 ], [ -10.06, -8.08, -11.46 ], [ -5.04, -2.23, 0.97 ], [ -14.20, -5.24, 8.27 ], [ -5.32, -2.36, 1.00 ] ] ), - (313, [ [ -276.70, 70.90, -69.10 ], [ -51.90, -162.20, 10.10 ], [ -3.19, -9.19, -14.18 ], [ 2.84, -0.45, -1.11 ], [ 11.33, -12.94, 0.29 ], [ 3.00, -0.48, -1.18 ] ] ), - (314, [ [ -221.20, 2.30, -47.30 ], [ -165.70, -117.10, -0.90 ], [ -3.19, -9.17, -14.15 ], [ 0.01, 0.02, 0.03 ], [ 1.62, -16.13, 5.61 ], [ 0.00, 0.01, 0.02 ] ] ), - (315, [ [ -283.70, -70.80, -59.10 ], [ 66.20, -75.00, 17.60 ], [ -3.18, -9.15, -14.11 ], [ 0.01, 0.02, 0.03 ], [ 13.47, 6.99, -7.92 ], [ 0.00, 0.01, 0.02 ] ] ), - (316, [ [ -200.90, -32.00, -51.70 ], [ 94.90, 36.10, 50.70 ], [ -3.18, -9.13, -14.09 ], [ 7.54, 1.13, 2.34 ], [ -10.31, 6.59, -11.92 ], [ 8.01, 1.20, 2.48 ] ] ), - (317, [ [ -114.90, 21.00, -43.50 ], [ 88.80, 141.00, 123.30 ], [ 12.65, -6.78, -9.20 ], [ 10.12, 6.89, 4.80 ], [ -4.22, 8.30, -14.28 ], [ 10.75, 7.32, 5.08 ] ] ), - (318, [ [ -154.40, 135.80, -62.60 ], [ -78.30, -1.00, -2.30 ], [ 15.19, 6.14, -4.52 ], [ -4.73, 11.66, 5.50 ], [ 15.36, -4.77, -5.50 ], [ -5.02, 12.40, 5.84 ] ] ), - (319, [ [ -274.80, 136.50, 7.90 ], [ 22.10, 45.90, 70.80 ], [ 3.20, 16.54, 1.79 ], [ -5.93, 5.11, 3.12 ], [ -9.70, 7.92, 11.41 ], [ -6.30, 5.46, 3.32 ] ] ), - (320, [ [ -141.60, 114.90, 31.30 ], [ 60.30, 66.50, 26.50 ], [ 3.20, 16.48, 1.79 ], [ -0.01, -0.03, -0.00 ], [ 5.81, 9.90, 12.39 ], [ 0.00, -0.02, 0.00 ] ] ), - (321, [ [ -108.40, 101.20, 30.10 ], [ 11.30, -64.60, -17.80 ], [ 3.19, 16.47, 1.79 ], [ 5.73, -9.33, 0.72 ], [ 0.02, 13.69, 9.85 ], [ 6.12, -9.95, 0.76 ] ] ), - (322, [ [ -117.50, 36.30, 28.10 ], [ -11.80, -88.50, 4.40 ], [ 15.95, -4.24, 3.38 ], [ 7.09, -9.12, -1.91 ], [ -3.44, -1.01, 16.46 ], [ 7.57, -9.72, -2.04 ] ] ), - (323, [ [ -123.00, -16.90, 76.90 ], [ -5.40, -40.50, 20.40 ], [ 16.63, -0.25, -2.49 ], [ -0.21, 4.61, -0.38 ], [ 2.66, 9.67, 13.50 ], [ -0.21, 4.92, -0.40 ] ] ), - (324, [ [ -83.50, -94.80, 124.40 ], [ -5.30, -37.10, -69.10 ], [ 15.15, 5.23, 4.96 ], [ -0.96, 3.46, 4.71 ], [ 2.79, -9.28, 13.70 ], [ -1.00, 3.70, 5.04 ] ] ), - (325, [ [ -114.60, -3.80, -22.00 ], [ -48.40, -89.30, -74.40 ], [ 15.09, 5.21, 4.94 ], [ 0.13, -7.07, -4.33 ], [ 4.35, 1.79, 16.03 ], [ 0.15, -7.57, -4.63 ] ] ), - (326, [ [ -106.10, -89.80, 24.00 ], [ -40.70, -98.90, -72.10 ], [ 15.33, -6.21, -2.04 ], [ 0.23, -2.61, -5.35 ], [ -2.24, -10.03, 13.12 ], [ 0.26, -2.79, -5.73 ] ] ), - (327, [ [ -134.60, -44.80, -44.70 ], [ -45.50, -59.20, -129.40 ], [ 15.55, -0.63, -5.87 ], [ -4.55, 4.11, -6.56 ], [ 1.59, -15.49, 5.83 ], [ -4.87, 4.41, -7.04 ] ] ), - (328, [ [ -152.20, -122.40, -0.90 ], [ -138.70, -24.00, -10.70 ], [ 5.62, 1.83, -15.50 ], [ -2.19, -5.54, 0.63 ], [ 7.35, -14.87, -0.48 ], [ -2.34, -5.95, 0.67 ] ] ), - (329, [ [ -215.00, -66.50, -51.90 ], [ -95.40, -77.80, 7.50 ], [ 10.89, -11.43, -4.96 ], [ 4.44, -4.77, 7.49 ], [ 5.00, -2.22, 15.63 ], [ 4.78, -5.13, 8.04 ] ] ), - (330, [ [ -281.50, -141.60, -97.10 ], [ -33.10, -74.40, -0.80 ], [ 14.52, -7.85, -0.46 ], [ 2.14, 2.15, 2.68 ], [ -0.17, -1.50, 16.44 ], [ 2.32, 2.30, 2.88 ] ] ), - (331, [ [ -142.90, -169.80, -24.70 ], [ 57.10, 22.50, 62.40 ], [ 14.46, -7.83, -0.46 ], [ -0.05, 0.02, 0.00 ], [ 10.09, 12.44, -3.77 ], [ -0.03, 0.02, 0.00 ] ] ), - (332, [ [ -114.90, -94.60, 56.00 ], [ -22.70, -27.90, 103.30 ], [ 14.42, -7.80, -0.46 ], [ -0.04, 0.02, 0.00 ], [ 7.79, 13.89, 3.94 ], [ -0.03, 0.01, 0.00 ] ] ), - (333, [ [ -165.80, -210.20, 55.70 ], [ -82.80, 8.90, -63.60 ], [ 14.38, -7.78, -0.46 ], [ -0.04, 0.02, 0.00 ], [ 4.52, -10.09, 12.05 ], [ -0.03, 0.01, 0.00 ] ] ), - (334, [ [ -221.80, -171.30, -25.00 ], [ -110.60, -77.10, -27.50 ], [ 14.34, -7.76, -0.46 ], [ -7.05, 1.07, -6.62 ], [ 4.40, 0.73, 15.69 ], [ -7.61, 1.16, -7.17 ] ] ), - (335, [ [ -212.40, -201.20, 82.90 ], [ 136.90, 5.40, 26.70 ], [ -1.40, -5.38, -15.28 ], [ 1.17, -0.16, 1.14 ], [ -3.98, 14.55, -6.08 ], [ 1.28, -0.18, 1.23 ] ] ), - (336, [ [ -187.10, -132.60, 25.20 ], [ -87.20, 10.40, -111.30 ], [ 14.26, -7.71, -0.46 ], [ 9.16, 4.06, 10.76 ], [ -0.57, -12.13, 10.74 ], [ 9.93, 4.39, 11.65 ] ] ), - (337, [ [ -324.00, -192.70, -37.00 ], [ -25.10, -36.30, 21.20 ], [ 14.59, 5.03, 4.77 ], [ 0.10, 4.80, 1.97 ], [ -1.03, 15.54, 4.28 ], [ 0.13, 5.20, 2.14 ] ] ), - (338, [ [ -280.20, -208.50, 37.40 ], [ -89.00, -10.60, 119.10 ], [ 14.55, 5.03, 4.77 ], [ -10.49, 2.92, -7.65 ], [ -1.23, 14.85, -6.15 ], [ -11.39, 3.18, -8.31 ] ] ), - (339, [ [ -271.90, -187.90, 119.40 ], [ 42.70, 34.80, 6.60 ], [ -6.06, 10.79, -10.27 ], [ -5.42, 1.49, -5.96 ], [ -7.05, 7.74, 12.21 ], [ -5.88, 1.63, -6.48 ] ] ), - (340, [ [ -252.20, -147.10, 107.10 ], [ 22.70, 45.10, -4.00 ], [ -4.00, 10.18, -11.77 ], [ 2.55, 1.22, 0.64 ], [ -6.00, 12.89, 7.48 ], [ 2.78, 1.34, 0.69 ] ] ), - (341, [ [ -216.60, -117.80, 95.70 ], [ 40.30, -19.20, -0.50 ], [ -0.92, 13.36, -8.84 ], [ 9.63, -2.95, 8.59 ], [ -1.90, 10.78, 11.74 ], [ 10.48, -3.21, 9.35 ] ] ), - (342, [ [ -210.30, -154.50, 112.40 ], [ -20.60, -33.90, 26.20 ], [ 14.48, 5.00, 4.74 ], [ 9.65, -5.25, 8.52 ], [ -3.00, 15.18, 4.18 ], [ 10.51, -5.71, 9.27 ] ] ), - (343, [ [ -241.10, -217.80, 103.30 ], [ -99.30, -50.40, -38.80 ], [ 14.45, 4.98, 4.74 ], [ -2.89, 1.23, -6.88 ], [ 12.97, 6.01, 7.20 ], [ -3.14, 1.34, -7.50 ] ] ), - (344, [ [ -262.00, -235.10, 20.00 ], [ 83.30, -4.40, -126.20 ], [ 7.63, 7.92, -11.58 ], [ -0.53, 0.21, -1.21 ], [ 14.45, -0.38, -6.79 ], [ -0.57, 0.23, -1.31 ] ] ), - (345, [ [ -341.30, -228.90, -31.50 ], [ 21.90, 106.10, -95.20 ], [ 14.39, 4.97, 4.71 ], [ 3.58, -1.58, 8.69 ], [ 7.16, -8.20, -11.63 ], [ 3.93, -1.72, 9.48 ] ] ), - (346, [ [ -223.00, -253.50, -46.00 ], [ 3.40, 60.90, -83.80 ], [ 14.34, 4.95, 4.69 ], [ 0.66, -1.98, -3.36 ], [ 6.75, -11.99, -7.93 ], [ 0.74, -2.16, -3.66 ] ] ), - (347, [ [ -309.60, -169.80, -81.10 ], [ 21.90, 106.10, -95.20 ], [ 15.68, 1.07, -1.89 ], [ -7.72, -0.17, -9.71 ], [ -0.02, -6.82, -14.29 ], [ -8.44, -0.18, -10.64 ] ] ), - (348, [ [ -209.50, -219.10, -37.80 ], [ 53.10, -46.50, -77.10 ], [ -1.67, 4.84, -14.93 ], [ -6.57, 1.42, -4.92 ], [ 14.28, 5.25, -4.20 ], [ -7.20, 1.56, -5.40 ] ] ), - (349, [ [ -173.60, -172.20, -85.40 ], [ -26.90, 37.00, -15.30 ], [ -1.67, 4.82, -14.90 ], [ 3.86, -5.85, 4.16 ], [ -15.11, -0.60, -4.38 ], [ 4.24, -6.42, 4.55 ] ] ), - (350, [ [ -291.30, -84.30, -106.00 ], [ 97.00, 135.70, 42.80 ], [ 9.54, -12.11, -2.88 ], [ 6.72, -8.15, 5.15 ], [ -2.01, 0.14, -15.56 ], [ 7.39, -8.96, 5.63 ] ] ), - (351, [ [ -120.90, -148.90, -48.40 ], [ 39.70, 69.50, -18.40 ], [ 10.75, -9.49, -6.16 ], [ 0.44, 1.01, -1.23 ], [ -8.04, -0.66, -13.36 ], [ 0.50, 1.10, -1.36 ] ] ), - (352, [ [ -144.10, -35.10, -76.70 ], [ -46.20, 4.30, -3.90 ], [ 10.72, -9.46, -6.13 ], [ -0.03, 0.02, 0.02 ], [ 9.56, -8.00, 9.32 ], [ -0.02, 0.02, 0.01 ] ] ), - (353, [ [ -190.90, -106.20, -108.70 ], [ -85.30, 10.90, -25.60 ], [ 10.69, -9.44, -6.13 ], [ -0.03, 0.02, 0.01 ], [ 5.65, -10.04, 10.41 ], [ -0.02, 0.01, 0.01 ] ] ), - (354, [ [ -285.70, -73.50, -145.80 ], [ -88.80, -66.70, -0.90 ], [ 10.67, -9.42, -6.10 ], [ -0.03, 0.03, 0.02 ], [ 5.85, -3.27, 13.96 ], [ -0.02, 0.02, 0.01 ] ] ), - (355, [ [ -321.80, -178.80, -111.70 ], [ -31.80, -89.20, 89.10 ], [ 10.64, -9.39, -6.09 ], [ -0.02, 0.02, 0.01 ], [ 10.69, 6.03, 9.37 ], [ -0.02, 0.01, 0.01 ] ] ), - (356, [ [ -371.60, -176.40, -124.40 ], [ 19.20, 94.50, -4.50 ], [ 10.62, -9.37, -6.08 ], [ -1.15, 5.43, -2.83 ], [ -7.74, -5.92, -11.94 ], [ -1.26, 6.01, -3.14 ] ] ), - (357, [ [ -321.80, -83.50, -118.80 ], [ -75.90, 112.20, -24.80 ], [ 7.94, 3.35, -12.73 ], [ -7.87, 9.63, -2.48 ], [ -10.12, -7.92, -8.43 ], [ -8.72, 10.67, -2.75 ] ] ), - (358, [ [ -395.50, -163.20, -123.30 ], [ -53.40, -89.20, 1.10 ], [ -5.72, 9.53, -10.56 ], [ 1.54, 4.94, 6.19 ], [ 11.70, -0.90, -9.86 ], [ 1.72, 5.48, 6.85 ] ] ), - (359, [ [ -473.40, -148.90, -123.50 ], [ -56.10, 65.20, -46.90 ], [ 6.94, 13.55, -1.43 ], [ 8.17, -9.27, 2.34 ], [ 2.25, -0.33, -15.12 ], [ 9.07, -10.30, 2.58 ] ] ), - (360, [ [ -429.70, -106.40, -120.50 ], [ 163.60, -61.70, -10.20 ], [ 10.52, -9.29, -6.02 ], [ -2.78, -9.61, -6.54 ], [ 14.14, 0.27, -5.75 ], [ -3.09, -10.68, -7.28 ] ] ), - (361, [ [ -402.50, -38.30, -145.20 ], [ -67.70, 81.20, 4.50 ], [ 0.22, -3.27, -14.88 ], [ -6.38, 6.43, -3.19 ], [ -9.17, -12.03, 1.78 ], [ -7.10, 7.14, -3.56 ] ] ), - (362, [ [ -461.90, -56.90, -150.00 ], [ -80.10, -50.60, 3.70 ], [ -3.60, 3.42, -14.37 ], [ -5.47, 3.23, 2.15 ], [ 6.98, -12.63, -4.79 ], [ -6.09, 3.59, 2.38 ] ] ), - (363, [ [ -522.70, -134.30, -113.60 ], [ -48.30, 6.50, 89.20 ], [ -11.56, 1.39, -9.73 ], [ -0.45, 2.83, 1.70 ], [ -0.44, -14.95, -2.51 ], [ -0.50, 3.16, 1.88 ] ] ), - (364, [ [ -492.60, -30.90, -110.50 ], [ -4.70, 62.60, 70.10 ], [ -4.04, 9.38, -11.16 ], [ 3.44, 3.64, -0.64 ], [ -14.31, -4.82, 0.82 ], [ 3.83, 4.07, -0.73 ] ] ), - (365, [ [ -562.40, -79.20, -83.10 ], [ -57.30, 18.40, 43.90 ], [ -4.03, 9.36, -11.13 ], [ 0.01, -0.02, 0.03 ], [ -7.38, -11.22, -6.88 ], [ 0.01, -0.02, 0.02 ] ] ), - (366, [ [ -607.00, 13.50, -78.80 ], [ 37.30, 101.70, -7.80 ], [ -4.02, 9.33, -11.10 ], [ 0.01, -0.03, 0.03 ], [ -6.92, 11.73, 6.39 ], [ 0.01, -0.02, 0.02 ] ] ), - (367, [ [ -511.10, 40.20, -112.70 ], [ 103.50, -93.30, -48.20 ], [ -4.01, 9.30, -11.07 ], [ 0.11, -3.57, -1.75 ], [ 6.48, 12.30, 5.65 ], [ 0.12, -3.99, -1.97 ] ] ), - (368, [ [ -523.20, -9.50, -122.50 ], [ -147.00, 5.30, 22.40 ], [ -3.83, 3.08, -14.15 ], [ -0.01, -3.23, -1.48 ], [ -2.71, -14.50, -2.64 ], [ -0.01, -3.61, -1.67 ] ] ), - (369, [ [ -588.70, -24.10, -95.80 ], [ 34.00, -42.60, 1.70 ], [ -4.00, 2.57, -14.17 ], [ 0.65, 0.95, 0.15 ], [ 7.91, 12.58, -1.68 ], [ 0.72, 1.07, 0.16 ] ] ), - (370, [ [ -532.30, -72.30, -120.30 ], [ 111.50, -25.50, -41.10 ], [ -2.56, 4.94, -13.85 ], [ 1.57, 2.29, 0.53 ], [ 5.77, 13.30, 3.55 ], [ 1.76, 2.57, 0.59 ] ] ), - (371, [ [ -460.90, -12.40, -123.40 ], [ 176.70, 55.60, 45.00 ], [ -0.83, 7.12, -13.05 ], [ 0.80, 1.00, 0.37 ], [ -7.13, 11.38, 6.42 ], [ 0.90, 1.13, 0.40 ] ] ), - (372, [ [ -427.40, 65.30, -95.70 ], [ -43.60, 32.50, -16.00 ], [ -0.99, 6.89, -13.12 ], [ 0.27, 0.90, 0.56 ], [ -12.05, -4.99, -7.11 ], [ 0.30, 1.02, 0.62 ] ] ), - (373, [ [ -471.40, 54.70, -118.00 ], [ -79.10, -33.90, 8.90 ], [ -0.50, 8.37, -12.23 ], [ -0.62, 1.29, 1.01 ], [ 7.66, -9.63, -8.27 ], [ -0.70, 1.46, 1.13 ] ] ), - (374, [ [ -580.40, 127.50, -99.50 ], [ 11.00, 31.00, 79.80 ], [ -3.95, 9.17, -10.90 ], [ 1.47, 0.43, 0.17 ], [ -13.32, -4.88, -4.15 ], [ 1.66, 0.50, 0.18 ] ] ), - (375, [ [ -556.80, 144.60, -36.30 ], [ 82.20, -21.40, 6.30 ], [ 0.21, 9.40, -11.37 ], [ 0.42, 0.00, -0.03 ], [ -0.73, 11.74, 8.90 ], [ 0.47, 0.02, -0.04 ] ] ), - (376, [ [ -519.60, 126.70, -112.70 ], [ 103.30, -10.80, -25.10 ], [ -3.93, 9.13, -10.86 ], [ -2.19, -0.16, 0.28 ], [ 1.14, 11.64, 8.94 ], [ -2.48, -0.17, 0.31 ] ] ), - (377, [ [ -425.90, 145.30, -95.20 ], [ 0.10, 5.40, 86.10 ], [ -3.92, 9.10, -10.83 ], [ 0.01, -0.03, 0.03 ], [ -9.77, -4.54, -9.97 ], [ 0.01, -0.02, 0.02 ] ] ), - (378, [ [ -512.40, 124.30, -46.70 ], [ -26.40, -6.80, -45.50 ], [ -3.91, 9.07, -10.80 ], [ 0.01, -0.02, 0.03 ], [ 4.17, -3.30, -13.64 ], [ 0.01, -0.01, 0.02 ] ] ), - (379, [ [ -476.90, 99.10, -97.70 ], [ 61.40, -4.20, -24.70 ], [ -3.90, 9.06, -10.77 ], [ 0.01, -0.02, 0.03 ], [ 3.89, 11.44, 8.21 ], [ 0.01, -0.01, 0.02 ] ] ), - (380, [ [ -371.40, 119.00, -116.30 ], [ 47.50, 67.00, 21.40 ], [ -3.89, 9.03, -10.74 ], [ 3.72, 1.74, 2.21 ], [ -9.50, 6.80, 8.69 ], [ 4.22, 1.99, 2.49 ] ] ), - (381, [ [ -341.60, 157.90, -39.40 ], [ -130.40, -15.20, -17.30 ], [ 3.62, 12.58, -6.31 ], [ 0.70, 2.51, 4.56 ], [ 6.49, -6.21, -11.42 ], [ 0.79, 2.87, 5.16 ] ] ), - (382, [ [ -401.40, 155.50, -49.20 ], [ -44.00, 17.80, 118.30 ], [ -0.22, 14.41, -1.67 ], [ -2.23, 0.58, 5.83 ], [ -13.79, -0.71, -4.45 ], [ -2.54, 0.67, 6.62 ] ] ), - (383, [ [ -326.70, 144.80, -18.40 ], [ 68.80, -24.00, -65.20 ], [ -0.21, 13.25, 5.81 ], [ 0.05, -0.90, -4.01 ], [ 2.29, -2.16, 14.12 ], [ 0.06, -1.01, -4.56 ] ] ), - (384, [ [ -264.80, 135.60, -54.60 ], [ 15.70, 44.40, 54.40 ], [ -0.12, 12.55, -7.14 ], [ 3.05, -0.30, -4.66 ], [ -13.39, 2.90, 4.57 ], [ 3.48, -0.33, -5.31 ] ] ), - (385, [ [ -311.00, 161.60, 22.30 ], [ 30.30, -19.60, 79.00 ], [ 6.48, 12.73, -1.86 ], [ 2.95, 0.10, 1.93 ], [ -11.96, 7.06, 3.81 ], [ 3.37, 0.13, 2.19 ] ] ), - (386, [ [ -216.70, 146.00, 34.60 ], [ 48.10, -13.40, 2.20 ], [ 5.72, 12.74, -3.34 ], [ -0.36, -0.13, -1.13 ], [ 2.21, 2.94, 13.89 ], [ -0.41, -0.13, -1.29 ] ] ), - (387, [ [ -127.20, 99.80, 74.20 ], [ 48.10, -23.70, 1.30 ], [ 5.78, 12.45, -4.09 ], [ 3.97, -5.53, 2.44 ], [ 1.13, 3.99, 13.71 ], [ 4.55, -6.30, 2.78 ] ] ), - (388, [ [ -31.50, 35.80, 58.00 ], [ 9.60, -94.20, 34.00 ], [ 14.11, 1.08, 1.91 ], [ -4.96, -6.31, 9.74 ], [ -2.06, 3.67, 13.65 ], [ -5.67, -7.21, 11.15 ] ] ), - (389, [ [ -93.20, 47.90, 78.70 ], [ -40.40, 4.30, -4.70 ], [ 0.38, -1.89, 14.12 ], [ -13.30, 3.09, -2.34 ], [ 3.43, 13.68, 2.08 ], [ -15.22, 3.54, -2.68 ] ] ), - (390, [ [ -83.60, 41.80, 21.70 ], [ -25.40, 95.30, -36.30 ], [ -12.54, 6.62, -1.22 ], [ 1.19, 7.30, -7.96 ], [ -1.11, 12.61, 6.50 ], [ 1.37, 8.37, -9.11 ] ] ), - (391, [ [ -94.90, 120.00, -16.70 ], [ 54.70, 18.00, -1.30 ], [ 6.95, 12.37, 0.40 ], [ 13.15, -4.37, 2.41 ], [ 10.33, 2.73, 9.34 ], [ 15.08, -5.02, 2.76 ] ] ), - (392, [ [ -6.00, 8.70, 44.40 ], [ -86.70, -73.70, -3.60 ], [ 8.62, -10.35, 4.25 ], [ 1.39, -7.11, -5.37 ], [ -3.08, 2.96, 13.47 ], [ 1.61, -8.16, -6.18 ] ] ), - (393, [ [ -69.50, 67.10, -5.30 ], [ -28.20, -6.40, -92.20 ], [ 9.82, -6.91, -7.36 ], [ -1.75, 10.80, -4.15 ], [ -7.45, -11.82, -1.74 ], [ -2.01, 12.43, -4.77 ] ] ), - (394, [ [ -80.80, -39.40, -67.40 ], [ 124.60, -54.30, 39.80 ], [ 4.34, 13.18, -2.10 ], [ -6.39, 8.82, 4.76 ], [ -4.51, 3.77, 12.74 ], [ -7.36, 10.17, 5.48 ] ] ), - (395, [ [ -47.50, 28.90, -23.70 ], [ 59.80, -55.90, 69.30 ], [ -2.73, 13.54, 2.28 ], [ 6.16, -4.72, 4.76 ], [ -13.90, 0.67, 1.53 ], [ 7.12, -5.43, 5.49 ] ] ), - (396, [ [ -37.50, -11.90, -20.60 ], [ -26.30, -38.40, 68.20 ], [ 10.22, 6.22, 7.23 ], [ 7.91, -7.09, -3.25 ], [ -8.44, 10.83, 2.63 ], [ 9.13, -8.18, -3.75 ] ] ), - (397, [ [ -36.80, -10.90, 27.50 ], [ -1.60, 7.40, 38.00 ], [ 13.48, -0.66, -3.58 ], [ 1.34, -2.85, -4.47 ], [ 0.14, 12.27, -6.66 ], [ 1.56, -3.28, -5.16 ] ] ), - (398, [ [ -42.70, -8.00, 62.70 ], [ -6.50, 1.70, 7.10 ], [ 13.47, -0.66, -3.57 ], [ -0.01, 0.00, 0.01 ], [ 7.61, 5.38, -10.38 ], [ -0.01, 0.00, 0.00 ] ] ), - (399, [ [ -63.30, 1.20, 96.30 ], [ -26.00, 27.20, 0.00 ], [ 13.46, -0.65, -3.56 ], [ -0.01, 0.00, 0.00 ], [ 4.17, -9.52, -9.28 ], [ -0.01, 0.00, 0.00 ] ] ), - (400, [ [ -78.00, 27.60, 100.90 ], [ 37.30, 13.80, 0.20 ], [ 13.44, -0.65, -3.56 ], [ -8.40, -4.20, 4.36 ], [ 10.36, 7.70, -5.21 ], [ -9.71, -4.86, 5.05 ] ] ), - (401, [ [ -31.50, 35.20, 105.20 ], [ 15.60, -22.20, 3.00 ], [ -6.21, -10.50, 6.66 ], [ -11.72, -1.75, 3.45 ], [ -1.00, -9.14, -10.43 ], [ -13.57, -2.02, 3.99 ] ] ), - (402, [ [ -34.50, -1.20, 104.80 ], [ -10.90, -26.50, -24.40 ], [ -11.67, -5.84, 4.76 ], [ 4.66, -0.01, -4.41 ], [ -8.41, 5.84, -9.38 ], [ 5.39, -0.02, -5.10 ] ] ), - (403, [ [ -5.70, 4.10, 69.80 ], [ 22.60, 26.50, -0.50 ], [ 6.31, -12.00, -2.94 ], [ 11.49, 4.26, -3.48 ], [ -5.65, -1.98, -12.51 ], [ 13.31, 4.94, -4.03 ] ] ), - (404, [ [ -8.00, 34.90, 79.80 ], [ -9.00, 30.20, 23.80 ], [ 13.38, -0.65, -3.55 ], [ 3.58, 5.76, -0.31 ], [ -1.03, 2.91, -13.51 ], [ 4.16, 6.67, -0.35 ] ] ), - (405, [ [ -24.40, 59.80, 98.70 ], [ -18.30, 17.30, 14.10 ], [ 13.37, -0.65, -3.54 ], [ -1.58, 4.17, -0.52 ], [ 4.91, -2.07, -12.78 ], [ -1.83, 4.84, -0.61 ] ] ), - (406, [ [ -52.80, 83.20, 117.00 ], [ -19.40, 32.60, 10.00 ], [ 9.96, 8.38, -4.68 ], [ -1.64, -2.45, 7.05 ], [ -6.44, 0.93, -12.20 ], [ -1.90, -2.84, 8.18 ] ] ), - (407, [ [ -33.10, 94.80, 102.90 ], [ 22.10, -6.20, -30.40 ], [ 9.77, -3.52, 9.11 ], [ 0.95, -7.69, 3.13 ], [ -4.89, -12.92, 0.37 ], [ 1.10, -8.91, 3.63 ] ] ), - (408, [ [ -19.60, 67.80, 71.00 ], [ -12.00, 23.60, -71.10 ], [ 12.39, -5.00, -3.48 ], [ -0.41, 5.00, -8.19 ], [ -5.72, -12.24, -2.83 ], [ -0.47, 5.81, -9.51 ] ] ), - (409, [ [ -69.80, 126.80, 91.50 ], [ -61.80, 12.70, 9.10 ], [ 6.67, 11.38, -3.94 ], [ 1.21, 0.41, 0.04 ], [ 2.20, -3.82, -13.04 ], [ 1.42, 0.48, 0.04 ] ] ), - (410, [ [ -121.30, 169.50, 92.00 ], [ -11.10, 37.00, 0.00 ], [ 13.27, -0.64, -3.52 ], [ 1.04, -10.30, 0.16 ], [ -2.09, -5.25, -12.53 ], [ 1.22, -11.98, 0.19 ] ] ), - (411, [ [ -114.50, 225.50, 92.00 ], [ 69.10, 44.90, 0.00 ], [ 9.34, -9.39, -3.58 ], [ -8.87, -5.78, -0.28 ], [ 0.32, 4.48, -12.97 ], [ -10.32, -6.73, -0.33 ] ] ), - (412, [ [ -65.20, 213.40, 92.00 ], [ 33.20, -32.20, 0.00 ], [ -4.05, -12.45, -4.05 ], [ -9.41, 1.68, -1.87 ], [ 6.95, -1.10, -11.76 ], [ -10.96, 1.95, -2.18 ] ] ), - (413, [ [ -41.70, 168.20, 81.00 ], [ 8.20, -39.50, -1.80 ], [ -9.73, -6.34, -7.24 ], [ -1.36, 1.33, -1.36 ], [ 7.72, -2.55, -11.01 ], [ -1.58, 1.55, -1.59 ] ] ), - (414, [ [ -32.20, 130.30, 62.30 ], [ 24.30, -54.00, -19.60 ], [ -7.50, -8.97, -7.08 ], [ 1.34, -1.11, -0.38 ], [ 6.07, -1.01, -12.21 ], [ 1.56, -1.30, -0.45 ] ] ), - (415, [ [ 13.30, 68.90, 25.90 ], [ 74.40, 51.70, -56.50 ], [ -8.09, -6.79, -8.63 ], [ 6.57, -0.10, 0.78 ], [ -10.81, 8.18, 1.49 ], [ 7.67, -0.13, 0.90 ] ] ), - (416, [ [ -52.20, 119.90, -39.10 ], [ -64.10, -49.60, 36.30 ], [ 7.97, -9.91, -4.78 ], [ 7.36, 2.12, -1.37 ], [ 8.29, 1.02, 10.72 ], [ 8.61, 2.47, -1.62 ] ] ), - (417, [ [ 0.60, 40.90, -6.30 ], [ -35.10, -73.30, -52.20 ], [ 7.52, -3.08, -10.84 ], [ -8.63, 0.31, 2.35 ], [ 4.57, -12.15, 3.87 ], [ -10.11, 0.35, 2.75 ] ] ), - (418, [ [ -93.60, 68.70, -44.60 ], [ -75.00, 91.80, -77.60 ], [ -9.58, -9.51, 0.20 ], [ -8.60, -3.22, 5.56 ], [ -4.44, 4.58, 11.90 ], [ -10.08, -3.79, 6.52 ] ] ), - (419, [ [ -10.30, 30.20, -41.90 ], [ 25.00, -66.20, -30.80 ], [ -9.55, -9.48, 0.20 ], [ 8.19, 6.85, 5.89 ], [ -2.35, -0.51, -13.24 ], [ 9.62, 8.03, 6.92 ] ] ), - (420, [ [ -50.40, -34.50, -84.60 ], [ -46.00, 102.90, -35.50 ], [ 6.06, 3.56, 11.44 ], [ 6.94, 5.55, 5.15 ], [ 12.08, 0.28, -5.85 ], [ 8.16, 6.52, 6.07 ] ] ), - (421, [ [ -41.40, 32.40, -58.90 ], [ -91.30, 85.20, -56.10 ], [ 5.92, 2.99, 11.63 ], [ -2.72, 1.28, 0.04 ], [ 13.04, 1.06, -2.87 ], [ -3.20, 1.52, 0.06 ] ] ), - (422, [ [ -114.30, -19.20, -124.30 ], [ -81.00, 8.40, 9.10 ], [ -0.41, 6.85, 11.45 ], [ 0.59, -0.71, 0.09 ], [ -1.94, 11.52, -6.46 ], [ 0.71, -0.83, 0.13 ] ] ), - (423, [ [ -129.50, 59.30, -86.40 ], [ -83.60, 13.00, 50.80 ], [ 5.70, 2.51, 11.77 ], [ 2.54, -3.98, 0.65 ], [ -1.06, 13.11, -2.07 ], [ 3.00, -4.70, 0.79 ] ] ), - (424, [ [ -193.40, -50.20, -121.30 ], [ -158.00, 10.70, 45.10 ], [ 2.87, -0.94, 12.92 ], [ -2.63, 2.52, -0.11 ], [ 0.40, 13.23, 0.91 ], [ -3.10, 2.98, -0.11 ] ] ), - (425, [ [ -260.70, 9.90, -99.50 ], [ -72.10, -15.50, -24.10 ], [ 0.38, 5.69, 11.94 ], [ -1.24, 1.76, -0.01 ], [ 4.21, 12.01, -3.59 ], [ -1.46, 2.09, 0.01 ] ] ), - (426, [ [ -339.40, -58.30, -138.90 ], [ -98.20, 0.40, -23.00 ], [ 0.56, 1.96, 13.03 ], [ -1.75, 1.21, -0.89 ], [ 3.91, 12.54, -1.11 ], [ -2.08, 1.44, -1.04 ] ] ), - (427, [ [ -392.70, 8.10, -127.60 ], [ 58.00, 12.90, -44.30 ], [ -2.91, 7.53, 10.38 ], [ -0.09, 0.88, -0.16 ], [ 0.70, -7.63, 10.68 ], [ -0.11, 1.05, -0.17 ] ] ), - (428, [ [ -318.60, -12.70, -117.30 ], [ 82.30, 72.00, 33.30 ], [ -0.08, 4.36, 12.37 ], [ 0.82, -1.67, 0.99 ], [ 11.05, -4.97, 5.02 ], [ 0.97, -1.97, 1.19 ] ] ), - (429, [ [ -400.20, 75.30, -134.70 ], [ 185.90, 159.10, 45.20 ], [ -2.86, 5.38, 11.56 ], [ -0.07, 1.98, -1.16 ], [ 8.95, -6.98, 6.47 ], [ -0.09, 2.36, -1.36 ] ] ), - (430, [ [ -297.10, 32.20, -114.40 ], [ 170.70, 159.00, 13.00 ], [ -0.38, 8.26, 10.06 ], [ -1.28, 1.68, -1.81 ], [ 10.70, -3.35, 6.62 ], [ -1.53, 2.01, -2.14 ] ] ), - (431, [ [ -183.70, 12.90, -89.70 ], [ 13.00, 150.40, -5.30 ], [ -5.33, 8.76, 7.95 ], [ -3.94, -4.23, -0.25 ], [ 8.91, 7.45, 5.78 ], [ -4.71, -5.05, -0.28 ] ] ), - (432, [ [ -336.80, 87.50, -103.70 ], [ -17.50, 86.10, 36.10 ], [ -8.00, -1.41, 10.03 ], [ 4.82, 0.55, 1.73 ], [ 8.89, 2.44, 9.03 ], [ 5.77, 0.68, 2.09 ] ] ), - (433, [ [ -251.90, 87.50, -90.80 ], [ 85.40, -108.30, 36.10 ], [ 1.28, 5.52, 11.55 ], [ 2.95, -0.08, 1.37 ], [ -10.47, -6.21, 4.16 ], [ 3.53, -0.09, 1.66 ] ] ), - (434, [ [ -181.50, 101.00, -68.40 ], [ 88.50, -70.20, 49.50 ], [ -0.99, -0.33, 12.80 ], [ -1.06, -4.88, 0.18 ], [ -3.84, -12.21, 1.05 ], [ -1.27, -5.85, 0.23 ] ] ), - (435, [ [ -170.30, 54.60, -111.80 ], [ 73.70, -24.10, -48.10 ], [ -0.96, -4.33, 12.02 ], [ -2.34, 5.28, -2.64 ], [ -10.28, -7.63, -0.60 ], [ -2.81, 6.35, -3.16 ] ] ), - (436, [ [ -123.20, 76.70, -98.70 ], [ 73.80, 14.70, 83.70 ], [ -5.26, 8.63, 7.84 ], [ -4.11, 1.60, -5.47 ], [ -3.10, -8.59, 8.96 ], [ -4.95, 1.91, -6.57 ] ] ), - (437, [ [ -53.70, 112.30, -68.10 ], [ -112.20, 97.90, 113.50 ], [ -9.05, -8.99, 0.20 ], [ -1.90, -8.86, -3.85 ], [ 5.04, -4.93, 10.63 ], [ -2.30, -10.67, -4.63 ] ] ), - (438, [ [ -42.10, 136.80, 15.40 ], [ 139.60, -1.80, 110.30 ], [ -9.03, -8.96, 0.19 ], [ 2.10, -1.42, -0.53 ], [ 0.16, -5.68, -11.38 ], [ 2.52, -1.73, -0.64 ] ] ), - (439, [ [ 8.20, 95.10, 34.30 ], [ -24.80, -1.90, 92.70 ], [ -5.35, -11.49, -0.74 ], [ 0.32, 0.74, 3.30 ], [ 10.88, -5.37, 3.73 ], [ 0.37, 0.88, 3.99 ] ] ), - (440, [ [ 16.90, 122.10, 92.60 ], [ 26.30, 5.60, 42.10 ], [ -7.67, -8.20, 5.88 ], [ -1.66, 0.65, -1.50 ], [ 7.57, -9.56, -3.46 ], [ -2.01, 0.77, -1.81 ] ] ), - (441, [ [ 25.30, 149.50, 92.30 ], [ -11.10, 35.90, 0.00 ], [ -8.98, -8.92, 0.19 ], [ -0.75, -0.41, -3.28 ], [ 1.91, -5.55, 11.22 ], [ -0.91, -0.50, -3.96 ] ] ), - (442, [ [ -9.30, 181.40, 93.40 ], [ -17.10, 39.40, 0.00 ], [ -8.97, -8.90, 0.19 ], [ 0.35, 9.47, -2.05 ], [ 2.00, -4.14, 11.77 ], [ 0.42, 11.45, -2.48 ] ] ), - (443, [ [ -3.30, 218.30, 94.20 ], [ 39.10, 16.20, 0.00 ], [ -8.33, 8.77, -3.63 ], [ 8.92, 8.72, -0.98 ], [ -5.40, 1.69, 11.29 ], [ 10.79, 10.55, -1.19 ] ] ), - (444, [ [ 33.30, 192.20, 83.10 ], [ 42.50, -69.90, -17.10 ], [ 10.72, 6.53, -1.13 ], [ 12.06, -2.03, 2.94 ], [ 2.40, -1.80, 12.25 ], [ 14.60, -2.45, 3.56 ] ] ), - (445, [ [ 29.00, 113.80, 73.30 ], [ 13.20, -7.90, -43.20 ], [ 11.33, 4.84, 2.53 ], [ 0.73, -5.94, -0.50 ], [ 4.14, -11.41, 3.31 ], [ 0.89, -7.19, -0.61 ] ] ), - (446, [ [ 53.50, 137.40, 54.40 ], [ 22.90, 17.80, 6.30 ], [ 12.12, -3.29, -0.12 ], [ 0.39, -1.17, -2.28 ], [ 6.30, 7.07, -8.25 ], [ 0.48, -1.41, -2.77 ] ] ), - (447, [ [ 57.60, 178.10, 62.90 ], [ -9.40, 32.20, -3.10 ], [ 12.11, 2.57, -2.03 ], [ -0.01, 2.18, -0.71 ], [ -1.50, -2.38, -12.23 ], [ -0.01, 2.65, -0.87 ] ] ), - (448, [ [ 40.10, 195.20, 59.60 ], [ -3.40, 25.80, -0.90 ], [ 12.10, 2.57, -2.03 ], [ -0.01, -0.00, 0.00 ], [ -2.05, 0.34, -12.36 ], [ -0.01, 0.00, 0.00 ] ] ), - (449, [ [ 57.30, 231.00, 78.90 ], [ -15.50, 11.50, 19.40 ], [ 12.09, 2.57, -2.03 ], [ -0.01, -0.00, 0.00 ], [ 1.41, 4.39, -11.64 ], [ -0.01, 0.00, 0.00 ] ] ), - (450, [ [ 34.30, 245.80, 93.80 ], [ -46.90, 3.20, 0.00 ], [ 12.07, 2.57, -2.02 ], [ -0.01, -0.00, 0.00 ], [ 11.71, -2.83, -3.38 ], [ -0.01, 0.00, 0.00 ] ] ), - (451, [ [ 5.80, 255.40, 92.60 ], [ 2.30, 2.40, 34.80 ], [ 12.06, 2.57, -2.02 ], [ -4.14, -6.59, -1.04 ], [ -2.76, 12.07, -1.70 ], [ -5.03, -8.01, -1.27 ] ] ), - (452, [ [ 37.80, 263.40, 105.50 ], [ 25.30, 1.40, 0.00 ], [ 3.38, -11.25, -4.21 ], [ -9.58, -6.24, -0.76 ], [ 2.52, 4.36, -11.42 ], [ -11.64, -7.58, -0.92 ] ] ), - (453, [ [ 72.90, 262.00, 95.30 ], [ 27.10, -36.00, -29.30 ], [ -7.12, -9.62, -3.48 ], [ -3.75, 0.11, 0.48 ], [ -0.52, 2.46, -12.21 ], [ -4.56, 0.13, 0.57 ] ] ), - (454, [ [ 74.30, 240.00, 41.90 ], [ 65.30, -11.40, -10.10 ], [ 0.06, -11.97, -3.42 ], [ 7.15, -0.12, 0.45 ], [ 1.32, 2.88, -12.04 ], [ 8.71, -0.16, 0.54 ] ] ), - (455, [ [ 104.20, 247.50, 91.20 ], [ 23.80, 44.00, 5.50 ], [ 7.18, -9.81, -2.58 ], [ 2.79, 12.36, 2.88 ], [ -3.76, -2.77, -11.51 ], [ 3.41, 15.07, 3.51 ] ] ), - (456, [ [ 105.20, 286.30, 78.80 ], [ -59.10, 14.70, 15.40 ], [ 6.69, 10.28, 1.84 ], [ -4.20, 11.14, 0.08 ], [ 1.14, 2.57, -12.08 ], [ -5.12, 13.58, 0.10 ] ] ), - (457, [ [ 79.00, 257.00, 53.90 ], [ -35.60, -5.00, -14.30 ], [ -1.41, 12.02, -2.63 ], [ -5.03, 0.93, -0.98 ], [ 4.13, -1.99, -11.51 ], [ -6.14, 1.14, -1.19 ] ] ), - (458, [ [ 20.00, 252.70, 43.90 ], [ -73.70, -16.00, -8.60 ], [ -2.90, 12.01, 0.43 ], [ -4.01, -3.06, -0.71 ], [ 1.04, 0.70, -12.30 ], [ -4.90, -3.72, -0.87 ] ] ), - (459, [ [ -18.80, 195.30, 54.90 ], [ -24.50, -54.20, -37.40 ], [ -10.04, 5.15, -4.98 ], [ -3.78, -3.64, -2.86 ], [ 5.83, 1.93, -10.71 ], [ -4.63, -4.44, -3.50 ] ] ), - (460, [ [ -85.50, 167.30, 15.40 ], [ -18.50, -23.90, -52.20 ], [ -10.02, 5.14, -4.96 ], [ 5.22, -1.93, -3.52 ], [ 4.78, 5.04, -10.16 ], [ 6.38, -2.36, -4.33 ] ] ), - (461, [ [ -9.90, 178.40, 10.90 ], [ 70.50, -60.80, 38.30 ], [ 0.64, 1.20, -12.20 ], [ 3.58, -3.04, -3.48 ], [ 3.47, 11.76, -0.64 ], [ 4.38, -3.72, -4.28 ] ] ), - (462, [ [ 40.80, 131.00, 22.30 ], [ 93.00, 82.10, -75.60 ], [ -3.07, -0.91, -11.82 ], [ -0.17, -2.60, 0.37 ], [ -4.81, 11.24, -0.76 ], [ -0.21, -3.20, 0.44 ] ] ), - (463, [ [ 15.50, 223.00, 15.30 ], [ 66.30, 73.50, -18.10 ], [ 0.99, -4.10, -11.46 ], [ 5.85, -2.68, 3.02 ], [ -9.29, 7.17, -3.38 ], [ 7.19, -3.30, 3.69 ] ] ), - (464, [ [ 84.50, 187.60, 6.70 ], [ 63.20, -22.90, 74.10 ], [ 8.35, -6.35, -6.19 ], [ 1.95, 3.39, 0.57 ], [ 7.47, 9.60, -0.52 ], [ 2.40, 4.17, 0.68 ] ] ), - (465, [ [ 81.80, 195.00, 99.00 ], [ 85.20, -17.50, -8.30 ], [ 4.26, 3.34, -10.87 ], [ -5.95, 3.42, -2.24 ], [ 6.90, 9.29, 3.68 ], [ -7.33, 4.21, -2.77 ] ] ), - (466, [ [ 144.30, 215.80, 88.40 ], [ 56.60, 35.60, -14.80 ], [ -2.94, 2.55, -11.47 ], [ -6.00, -0.83, 0.66 ], [ -4.28, 10.83, 3.34 ], [ -7.40, -1.02, 0.80 ] ] ), - (467, [ [ 178.40, 287.40, 86.20 ], [ 6.50, 74.90, -2.80 ], [ -7.52, 1.67, -9.31 ], [ -2.09, -5.60, 3.23 ], [ -9.09, 2.44, 7.58 ], [ -2.58, -6.92, 3.98 ] ] ), - (468, [ [ 160.50, 350.90, 83.50 ], [ -55.40, 54.50, 2.60 ], [ -7.51, -7.89, -5.18 ], [ 4.12, -6.89, 3.11 ], [ -3.11, -4.19, 10.88 ], [ 5.08, -8.53, 3.83 ] ] ), - (469, [ [ 79.50, 372.50, 92.00 ], [ -94.70, -10.00, 12.80 ], [ 1.80, -11.41, -3.37 ], [ 8.18, 5.30, -0.77 ], [ 2.89, -2.97, 11.29 ], [ 10.12, 6.55, -0.96 ] ] ), - (470, [ [ 56.20, 296.40, 44.30 ], [ 5.10, -77.10, -40.60 ], [ 8.64, 4.24, -7.16 ], [ -0.89, 8.18, -2.63 ], [ 8.30, -3.68, 7.84 ], [ -1.10, 10.13, -3.27 ] ] ), - (471, [ [ 86.50, 241.90, 24.50 ], [ 53.00, -52.30, 0.20 ], [ 2.60, 7.44, -9.01 ], [ -3.05, -2.57, -2.05 ], [ 3.89, 8.81, 7.11 ], [ -3.77, -3.18, -2.56 ] ] ), - (472, [ [ 152.10, 205.80, 56.00 ], [ 63.60, -8.30, 10.00 ], [ 3.21, -2.16, -11.30 ], [ -0.12, -2.70, -1.03 ], [ 3.42, 11.35, -1.45 ], [ -0.15, -3.35, -1.29 ] ] ), - (473, [ [ 198.40, 215.10, 56.00 ], [ 38.20, 22.50, -1.40 ], [ 2.66, -0.84, -11.59 ], [ -0.74, 1.84, -0.19 ], [ -3.99, 11.03, -2.14 ], [ -0.92, 2.29, -0.25 ] ] ), - (474, [ [ 231.60, 243.60, 55.70 ], [ 23.70, 41.90, -1.20 ], [ 1.74, 1.49, -11.69 ], [ -0.06, 0.95, 0.02 ], [ -8.93, 7.83, -0.84 ], [ -0.08, 1.18, 0.02 ] ] ), - (475, [ [ 254.20, 308.60, 53.70 ], [ -36.30, 58.90, 0.00 ], [ 3.07, 0.19, -11.48 ], [ 1.44, -1.14, 0.41 ], [ -9.01, -7.25, -2.71 ], [ 1.80, -1.42, 0.49 ] ] ), - (476, [ [ 201.60, 339.10, 45.30 ], [ -53.50, 14.40, -12.40 ], [ 4.61, -0.82, -10.90 ], [ 1.75, -3.67, 9.37 ], [ -0.90, -11.83, 0.08 ], [ 2.19, -4.57, 11.67 ] ] ), - (477, [ [ 225.60, 364.90, 17.70 ], [ 84.00, -17.10, -36.30 ], [ 6.57, -7.03, 6.90 ], [ -1.74, -1.93, 11.58 ], [ 0.08, -9.62, -6.91 ], [ -2.17, -2.41, 14.45 ] ] ), - (478, [ [ 262.20, 310.80, 24.60 ], [ 19.90, -60.50, 3.10 ], [ 0.45, -3.90, 11.14 ], [ -3.49, 2.51, 2.39 ], [ -9.02, -7.61, -0.58 ], [ -4.35, 3.12, 3.00 ] ] ), - (479, [ [ 266.70, 240.60, 17.50 ], [ -54.80, -92.30, 1.00 ], [ -0.30, -2.05, 11.61 ], [ -0.74, 1.97, 0.30 ], [ -10.99, 4.18, 0.80 ], [ -0.93, 2.46, 0.39 ] ] ), - (480, [ [ 191.50, 210.20, 17.50 ], [ -54.20, -18.80, 19.40 ], [ -1.03, 0.06, 11.71 ], [ 0.91, 2.69, -0.23 ], [ -7.82, 8.71, 1.12 ], [ 1.14, 3.36, -0.27 ] ] ), - (481, [ [ 126.50, 239.40, 20.10 ], [ -85.50, -4.10, -17.80 ], [ 1.33, 3.26, 11.19 ], [ 1.41, 1.92, -0.33 ], [ 3.78, 10.85, -2.36 ], [ 1.77, 2.40, -0.39 ] ] ), - (482, [ [ 27.70, 256.90, -12.00 ], [ 25.60, 34.70, 43.20 ], [ 1.31, 3.24, 11.15 ], [ -0.00, -0.01, -0.03 ], [ 8.36, 2.10, 7.89 ], [ 0.00, -0.01, -0.02 ] ] ), - (483, [ [ 83.20, 288.30, -1.00 ], [ 33.20, -4.80, -3.70 ], [ 1.31, 3.23, 11.13 ], [ -0.00, -0.01, -0.03 ], [ -1.61, -11.04, 3.41 ], [ 0.00, -0.01, -0.02 ] ] ), - (484, [ [ 213.40, 266.00, 3.10 ], [ 68.30, 112.60, 23.20 ], [ 1.31, 3.23, 11.08 ], [ -0.00, -0.01, -0.03 ], [ 11.48, -0.96, 1.46 ], [ 0.00, -0.01, -0.02 ] ] ), - (485, [ [ 188.20, 299.90, 26.40 ], [ -48.40, -18.80, 4.40 ], [ 1.31, 3.21, 11.06 ], [ -0.00, -0.01, -0.02 ], [ -2.92, 10.90, -2.63 ], [ 0.00, -0.00, -0.01 ] ] ), - (486, [ [ 130.20, 290.80, 30.50 ], [ -44.60, 71.50, 28.90 ], [ 1.31, 3.21, 11.04 ], [ -0.01, -0.01, -0.02 ], [ 5.06, 10.37, -0.87 ], [ 0.00, -0.00, -0.01 ] ] ), - (487, [ [ 136.70, 339.40, 47.80 ], [ -100.80, 75.50, 26.60 ], [ 1.30, 3.20, 11.02 ], [ -0.01, -0.01, -0.03 ], [ 3.35, 10.74, -2.62 ], [ 0.00, -0.01, -0.02 ] ] ), - (488, [ [ 47.80, 248.50, 21.60 ], [ -98.10, 56.50, 2.30 ], [ 1.30, 3.19, 10.97 ], [ -0.00, -0.01, -0.04 ], [ 4.81, 9.88, -3.40 ], [ 0.00, -0.01, -0.02 ] ] ), - (489, [ [ 59.30, 327.60, 28.10 ], [ 34.80, 103.20, -11.30 ], [ 1.29, 3.18, 10.94 ], [ -0.00, -0.01, -0.03 ], [ 11.37, -1.46, -0.44 ], [ 0.00, -0.01, -0.02 ] ] ), - (490, [ [ 158.50, 381.30, 13.00 ], [ 145.50, -5.80, -42.40 ], [ 1.29, 3.17, 10.90 ], [ -0.01, -0.01, -0.04 ], [ -1.38, -10.74, 3.63 ], [ 0.00, -0.01, -0.03 ] ] ), - (491, [ [ 240.70, 304.70, -6.30 ], [ 49.30, -67.70, -27.10 ], [ 1.28, 3.15, 10.86 ], [ -0.01, -0.01, -0.03 ], [ -10.21, -2.59, 4.31 ], [ 0.00, -0.01, -0.02 ] ] ), - (492, [ [ 240.40, 234.90, -17.20 ], [ -74.10, -88.50, 16.10 ], [ 1.28, 3.15, 10.83 ], [ -0.00, -0.01, -0.03 ], [ -7.57, 8.36, -1.27 ], [ 0.00, -0.01, -0.02 ] ] ), - (493, [ [ 173.00, 289.90, -12.50 ], [ 56.50, 158.10, 0.10 ], [ 1.28, 3.14, 10.80 ], [ -0.00, -0.01, -0.04 ], [ 11.31, -0.44, -0.15 ], [ 0.00, -0.01, -0.02 ] ] ), - (494, [ [ 109.50, 348.10, -9.70 ], [ -74.10, -88.50, 16.10 ], [ 1.28, 3.13, 10.76 ], [ -0.01, -0.01, -0.02 ], [ -7.52, 8.31, -1.26 ], [ 0.00, -0.00, -0.01 ] ] ), - (495, [ [ 88.40, 320.90, -6.10 ], [ -71.10, -68.40, 21.40 ], [ 1.27, 3.12, 10.75 ], [ -0.01, -0.01, -0.01 ], [ -7.43, 8.34, -1.49 ], [ 0.00, -0.00, -0.01 ] ] ), - (496, [ [ 61.80, 280.20, -37.60 ], [ 69.10, -114.80, -49.00 ], [ 1.27, 3.12, 10.73 ], [ -0.00, -0.01, -0.03 ], [ -10.27, -1.14, 4.45 ], [ 0.00, -0.00, -0.02 ] ] ), - (497, [ [ 132.90, 264.70, -28.90 ], [ -44.70, -165.90, -57.30 ], [ 1.26, 3.11, 10.70 ], [ -0.00, -0.01, -0.04 ], [ -7.20, 8.23, 2.46 ], [ 0.00, -0.01, -0.02 ] ] ), - (498, [ [ 147.20, 179.70, 61.30 ], [ 91.20, -36.60, 30.40 ], [ 1.26, 3.10, 10.65 ], [ -0.01, -0.01, -0.04 ], [ -1.90, -10.20, 4.13 ], [ 0.00, -0.01, -0.02 ] ] ), - (499, [ [ 238.20, 177.20, 65.00 ], [ 18.30, -82.80, -18.10 ], [ 1.25, 3.09, 10.62 ], [ -6.46, -1.97, -8.08 ], [ -10.53, 2.18, 2.87 ], [ -8.32, -2.53, -10.38 ] ] ), - (500, [ [ 197.80, 161.40, 50.30 ], [ 67.60, 35.60, -126.70 ], [ -10.39, -0.45, -3.92 ], [ 0.94, -2.52, -10.53 ], [ -2.01, 10.32, 3.58 ], [ 1.21, -3.24, -13.56 ] ] ), - (501, [ [ 254.20, 183.80, 49.30 ], [ -11.80, 23.50, 62.10 ], [ 3.91, -1.89, -10.20 ], [ 10.29, -1.14, 3.54 ], [ 0.06, -1.92, -10.91 ], [ 13.26, -1.47, 4.56 ] ] ), - (502, [ [ 277.70, 254.80, 52.00 ], [ -1.10, 48.50, -21.40 ], [ 10.34, -2.74, 2.80 ], [ 0.61, 0.19, -0.28 ], [ 1.53, -7.63, -7.85 ], [ 0.80, 0.24, -0.38 ] ] ), - (503, [ [ 291.40, 209.50, 13.10 ], [ -39.30, -47.20, -6.60 ], [ 5.80, -1.63, -9.23 ], [ -3.43, 0.14, -6.40 ], [ 7.81, -5.38, 5.63 ], [ -4.42, 0.18, -8.27 ] ] ), - (504, [ [ 227.20, 207.90, 6.30 ], [ -93.70, -69.70, -8.90 ], [ 3.44, -2.43, -10.16 ], [ 0.12, 0.05, 0.07 ], [ 6.29, -8.07, 4.03 ], [ 0.16, 0.06, 0.08 ] ] ), - (505, [ [ 186.40, 164.40, 16.90 ], [ -71.70, -61.20, -10.00 ], [ 5.78, -1.62, -9.19 ], [ 1.27, 0.44, 0.54 ], [ 7.54, -6.04, 5.21 ], [ 1.65, 0.57, 0.68 ] ] ), - (506, [ [ 118.40, 159.70, 1.30 ], [ -74.40, 26.40, -38.50 ], [ 5.76, -1.62, -9.17 ], [ -0.02, 0.00, 0.03 ], [ -2.33, -10.70, 0.23 ], [ -0.01, 0.00, 0.02 ] ] ), - (507, [ [ 42.70, 245.00, -45.30 ], [ 77.70, 116.50, 19.30 ], [ 5.74, -1.62, -9.13 ], [ -0.03, 0.01, 0.04 ], [ -6.98, 6.28, -5.54 ], [ -0.02, 0.00, 0.03 ] ] ), - (508, [ [ 159.90, 180.50, -31.40 ], [ 106.20, 76.60, 20.20 ], [ 5.71, -1.60, -9.08 ], [ -0.03, 0.01, 0.04 ], [ -3.19, 9.46, -4.24 ], [ -0.02, 0.00, 0.03 ] ] ), - (509, [ [ 134.10, 292.30, -47.10 ], [ 34.50, 97.60, 13.80 ], [ 5.68, -1.60, -9.05 ], [ -0.02, 0.01, 0.03 ], [ -8.51, 2.98, -5.95 ], [ -0.01, 0.00, 0.02 ] ] ), - (510, [ [ 193.30, 275.10, -46.30 ], [ 23.80, -61.70, 26.10 ], [ 5.67, -1.59, -9.02 ], [ -3.56, 1.74, -0.59 ], [ 8.40, 5.13, 4.38 ], [ -4.64, 2.27, -0.79 ] ] ), - (511, [ [ 190.90, 187.00, -52.20 ], [ 66.50, -39.30, 3.60 ], [ -2.01, 2.15, -10.33 ], [ -3.82, 1.31, -0.79 ], [ 2.31, 10.47, 0.68 ], [ -5.00, 1.72, -1.05 ] ] ), - (512, [ [ 254.20, 247.30, -47.60 ], [ -23.50, 92.50, 19.80 ], [ -1.63, 0.82, -10.55 ], [ 0.99, -1.69, -0.13 ], [ -9.94, -3.80, 1.15 ], [ 1.29, -2.21, -0.20 ] ] ), - (513, [ [ 228.40, 321.30, -41.20 ], [ 52.70, 188.20, -7.70 ], [ -0.11, -1.17, -10.61 ], [ 3.62, -1.19, 0.81 ], [ -10.46, 2.15, -0.18 ], [ 4.76, -1.57, 1.05 ] ] ), - (514, [ [ 176.60, 339.50, -38.20 ], [ -78.70, 16.00, 21.50 ], [ 5.61, -1.57, -8.92 ], [ 2.47, -0.17, 0.74 ], [ 6.18, -8.52, -1.64 ], [ 3.25, -0.23, 0.96 ] ] ), - (515, [ [ 119.00, 367.30, -29.70 ], [ -127.00, 18.70, 4.70 ], [ 5.59, -1.57, -8.90 ], [ -0.02, 0.00, 0.03 ], [ 4.78, -9.48, 0.52 ], [ -0.01, 0.00, 0.02 ] ] ), - (516, [ [ 91.40, 252.30, -63.20 ], [ 23.10, -112.20, 118.60 ], [ 5.57, -1.57, -8.86 ], [ -0.03, 0.01, 0.04 ], [ 6.52, 8.32, 0.32 ], [ -0.02, 0.00, 0.03 ] ] ), - (517, [ [ 175.10, 162.40, -53.90 ], [ -54.80, -66.80, 32.70 ], [ 5.54, -1.56, -8.82 ], [ -0.03, 0.01, 0.04 ], [ 10.06, 0.55, 3.06 ], [ -0.02, 0.00, 0.03 ] ] ), - (518, [ [ 70.80, 203.50, -65.80 ], [ -102.40, -41.90, -13.50 ], [ 5.52, -1.55, -8.78 ], [ -0.02, 0.01, 0.03 ], [ 6.25, -7.45, 3.92 ], [ -0.01, 0.00, 0.02 ] ] ), - (519, [ [ 52.30, 140.20, -39.60 ], [ -180.50, -24.10, 75.00 ], [ 5.51, -1.54, -8.75 ], [ -0.01, 0.01, 0.02 ], [ 9.17, -4.92, -1.03 ], [ -0.01, 0.00, 0.01 ] ] ), - (520, [ [ 6.80, 106.50, -47.40 ], [ -171.30, 31.80, -4.10 ], [ 5.49, -1.54, -8.74 ], [ -0.02, 0.00, 0.02 ], [ 3.75, -9.72, 0.64 ], [ -0.01, 0.00, 0.02 ] ] ), - (521, [ [ 27.90, 191.60, -30.80 ], [ -96.90, 52.70, -49.30 ], [ 5.48, -1.54, -8.71 ], [ -0.02, 0.00, 0.03 ], [ -3.21, -9.88, -0.54 ], [ -0.01, 0.00, 0.02 ] ] ), - (522, [ [ -17.90, 115.60, -73.10 ], [ -104.10, 42.30, 14.10 ], [ 5.45, -1.54, -8.67 ], [ -0.02, 0.01, 0.04 ], [ 3.08, -9.78, -1.45 ], [ -0.01, 0.00, 0.02 ] ] ), - (523, [ [ 1.90, 223.30, -37.40 ], [ 44.00, 82.00, -9.10 ], [ 5.43, -1.53, -8.63 ], [ -0.02, 0.01, 0.03 ], [ -6.75, 5.34, -5.68 ], [ -0.01, 0.00, 0.02 ] ] ), - (524, [ [ 33.20, 282.60, -58.50 ], [ -23.00, 67.10, -26.70 ], [ 5.41, -1.52, -8.61 ], [ 0.79, 3.52, 4.91 ], [ -8.17, -4.48, -4.35 ], [ 1.08, 4.71, 6.57 ] ] ), - (525, [ [ 67.80, 358.20, -24.30 ], [ -2.30, 0.30, 54.60 ], [ 7.28, 6.66, 2.78 ], [ 1.46, 2.72, 1.91 ], [ -6.74, 7.41, 2.19 ], [ 1.97, 3.65, 2.54 ] ] ), - (526, [ [ 40.70, 358.70, 43.40 ], [ -22.60, 47.20, 59.80 ], [ 8.42, 5.16, -2.63 ], [ -2.81, 1.16, 1.68 ], [ -5.07, 4.81, -7.46 ], [ -3.76, 1.57, 2.26 ] ] ), - (527, [ [ 29.20, 413.00, 41.50 ], [ -60.50, 10.90, 19.00 ], [ 2.27, 8.57, 5.05 ], [ -2.85, 2.07, 3.48 ], [ -2.44, 5.56, -8.20 ], [ -3.83, 2.79, 4.68 ] ] ), - (528, [ [ -26.50, 361.80, 43.10 ], [ -56.30, 17.20, 1.60 ], [ 3.56, 8.95, 3.27 ], [ 2.65, -1.03, -4.10 ], [ 1.38, 3.02, -9.62 ], [ 3.58, -1.38, -5.52 ] ] ), - (529, [ [ -23.40, 393.00, 43.00 ], [ -7.70, 31.40, -0.90 ], [ 6.85, 7.25, -1.93 ], [ -0.97, 0.74, -1.25 ], [ -2.97, 4.65, -8.53 ], [ -1.31, 1.01, -1.68 ] ] ), - (530, [ [ -36.60, 415.60, 41.80 ], [ -25.50, 17.70, 1.00 ], [ 2.83, 9.74, -0.36 ], [ -4.02, 1.55, 1.19 ], [ -3.16, 1.63, -9.51 ], [ -5.42, 2.09, 1.60 ] ] ), - (531, [ [ -70.00, 421.50, 45.40 ], [ -30.80, -9.50, 1.40 ], [ -1.19, 10.06, 0.33 ], [ -5.91, -4.42, 2.80 ], [ 1.19, 0.79, -10.03 ], [ -7.98, -5.96, 3.78 ] ] ), - (532, [ [ -90.30, 401.60, 44.50 ], [ -15.10, -33.40, -0.70 ], [ -8.70, 1.66, 4.91 ], [ -2.95, -8.68, 2.68 ], [ -5.26, 0.39, -8.65 ], [ -3.98, -11.72, 3.63 ] ] ), - (533, [ [ -91.80, 361.20, 44.50 ], [ 35.10, -38.10, -18.40 ], [ -4.90, -7.44, 4.78 ], [ 6.01, -6.11, -1.81 ], [ -5.53, -1.71, -8.29 ], [ 8.12, -8.26, -2.44 ] ] ), - (534, [ [ -38.80, 367.10, 17.80 ], [ 33.30, 56.60, -27.60 ], [ 4.46, -9.04, 0.44 ], [ 6.11, 6.76, -2.78 ], [ -5.61, -6.12, -5.73 ], [ 8.27, 9.14, -3.76 ] ] ), - (535, [ [ -55.20, 436.50, 11.50 ], [ -50.10, 54.50, -0.10 ], [ 6.83, 7.37, -0.54 ], [ 0.24, 8.59, -0.86 ], [ -0.93, 0.22, -10.01 ], [ 0.34, 11.63, -1.17 ] ] ), - (536, [ [ -121.40, 460.30, 17.10 ], [ -86.80, 60.90, -1.80 ], [ 5.06, 8.57, -1.28 ], [ 0.90, -2.49, -1.08 ], [ -1.24, -0.68, -9.93 ], [ 1.24, -3.38, -1.46 ] ] ), - (537, [ [ -164.50, 536.10, -17.30 ], [ -9.90, 55.20, -8.50 ], [ 9.53, 1.13, -2.81 ], [ 8.03, -12.39, -1.98 ], [ -2.54, -2.06, -9.45 ], [ 10.93, -16.81, -2.68 ] ] ) ] ), + (1, [[-502.30,732.10,92.00], [-49.80,-90.70,0.00], [0.00,0.00,12.00], [0.00,0.00,0.00], [-10.52,5.77,0.00], [0.00,0.00,0.00]]), + (2, [[-543.10,654.80,92.00], [-31.70,-64.00,0.00], [0.00,0.00,12.00], [0.00,0.00,0.00], [-10.75,5.33,0.00], [0.00,0.00,0.00]]), + (3, [[-566.20,605.00,92.00], [-43.40,-40.20,0.00], [0.00,0.00,12.00], [0.00,0.00,0.00], [-8.16,8.81,0.00], [0.00,0.00,0.00]]), + (4, [[-623.90,583.60,92.00], [-58.90,0.00,0.00], [0.00,0.00,12.00], [0.00,0.00,0.00], [0.00,12.00,0.00], [0.00,0.00,0.00]]), + (5, [[-674.40,602.30,92.00], [-25.80,24.90,0.00], [0.00,0.00,12.00], [1.57,1.24,-0.27], [8.33,8.64,0.00], [1.57,1.24,-0.27]]), + (6, [[-676.30,613.40,92.00], [21.70,17.10,-7.50], [2.46,1.94,11.58], [1.52,0.69,-0.22], [7.43,-9.43,0.01], [1.52,0.69,-0.22]]), + (7, [[-638.20,613.20,80.50], [47.90,1.90,-11.30], [2.75,0.11,11.68], [-0.55,2.15,-1.26], [0.47,-11.99,-0.00], [-0.55,2.15,-1.25]]), + (8, [[-586.80,617.60,72.10], [3.30,41.00,-47.10], [0.73,9.02,7.87], [-1.76,0.56,-0.15], [11.96,-0.95,-0.02], [-1.77,0.56,-0.14]]), + (9, [[-644.60,633.70,57.50], [-52.20,4.60,-6.70], [-1.50,0.14,11.90], [0.12,-4.47,1.05], [1.07,11.95,-0.01], [0.12,-4.47,1.05]]), + (10, [[-677.20,630.20,57.50], [0.10,-43.70,-12.10], [-0.00,-3.19,11.57], [1.58,-0.74,-0.11], [-12.00,-0.01,-0.00], [1.58,-0.74,-0.10]]), + (11, [[-632.90,609.90,50.60], [51.90,-16.20,-11.70], [2.42,-0.76,11.72], [0.39,-1.35,-0.70], [-3.56,-11.46,-0.00], [0.39,-1.35,-0.70]]), + (12, [[-581.30,601.00,35.40], [4.90,-48.00,-34.50], [0.68,-6.95,9.76], [-1.42,0.41,0.08], [-11.94,-1.21,-0.02], [-1.42,0.40,0.08]]), + (13, [[-631.70,589.30,35.90], [-57.50,19.90,-5.30], [-0.98,0.34,11.95], [-2.13,7.48,-3.39], [3.92,11.34,0.00], [-2.13,7.47,-3.39]]), + (14, [[-667.40,632.00,27.30], [-60.00,-18.80,-39.10], [-4.45,11.05,1.38], [-1.20,-0.91,-9.00], [5.42,3.46,-10.13], [-1.20,-0.91,-9.00]]), + (15, [[-666.40,558.00,7.70], [-33.70,-54.60,46.30], [-3.08,-6.32,-9.72], [-1.72,-4.99,-3.68], [10.42,-5.94,0.56], [-1.72,-4.99,-3.68]]), + (16, [[-698.00,570.70,66.50], [-52.90,5.40,48.50], [-8.05,-2.69,-8.47], [-2.86,-0.08,4.78], [1.18,-11.66,2.59], [-2.87,-0.08,4.78]]), + (17, [[-760.20,567.80,94.30], [-13.60,33.40,46.80], [-9.98,-6.44,1.67], [4.50,1.96,8.55], [6.05,-7.54,7.10], [4.51,1.96,8.55]]), + (18, [[-724.50,582.10,93.50], [45.90,1.10,-0.90], [0.23,-0.08,12.00], [4.20,2.65,4.23], [0.28,-12.00,-0.08], [4.20,2.65,4.24]]), + (19, [[-681.80,570.00,92.80], [28.80,-21.00,-0.70], [0.29,0.02,12.02], [-0.11,-0.21,0.02], [-7.09,-9.70,0.19], [-0.11,-0.21,0.02]]), + (20, [[-667.90,548.90,92.30], [3.90,-28.50,-1.00], [0.04,-0.44,12.03], [-0.05,-0.00,0.02], [-11.92,-1.66,-0.02], [-0.05,-0.00,0.02]]), + (21, [[-677.10,520.90,91.00], [-27.30,-11.70,0.60], [0.20,0.11,12.06], [-0.32,0.01,0.01], [-4.76,11.08,-0.02], [-0.32,0.01,0.01]]), + (22, [[-700.50,532.40,92.90], [-14.40,20.00,-0.20], [-0.67,-0.36,12.06], [-0.35,0.31,0.00], [9.78,7.05,0.76], [-0.36,0.32,0.00]]), + (23, [[-703.50,552.30,91.10], [-16.60,15.00,-1.80], [-0.75,0.65,12.05], [-0.38,0.11,-0.02], [8.09,8.99,0.02], [-0.39,0.11,-0.02]]), + (24, [[-726.50,553.80,90.20], [-21.70,-2.90,-3.00], [-1.64,-0.22,12.00], [-1.63,-5.16,-4.21], [-1.62,12.00,-0.00], [-1.63,-5.16,-4.21]]), + (25, [[-739.60,548.10,86.40], [15.30,-13.20,-28.20], [-4.50,-10.93,2.69], [-1.48,-2.79,-8.86], [-9.92,2.48,-6.51], [-1.48,-2.79,-8.86]]), + (26, [[-694.50,550.10,70.60], [44.70,-4.70,-16.30], [-3.66,3.50,-11.05], [1.47,4.72,-6.06], [2.27,11.59,2.91], [1.47,4.71,-6.06]]), + (27, [[-652.70,539.30,54.70], [26.40,-22.50,-3.70], [-1.02,0.79,-12.12], [0.77,-2.83,-0.13], [7.91,9.27,-0.06], [0.77,-2.82,-0.13]]), + (28, [[-644.90,520.20,58.60], [-8.40,-26.00,7.10], [-0.96,-2.93,-11.81], [-0.33,-0.93,0.06], [11.60,-3.77,-0.00], [-0.33,-0.92,0.06]]), + (29, [[-670.50,503.30,65.20], [-49.20,-7.40,8.40], [-2.00,-0.30,-12.06], [-0.69,-1.22,1.36], [1.84,-12.09,-0.00], [-0.69,-1.22,1.37]]), + (30, [[-723.20,522.10,69.80], [13.50,42.00,-69.30], [-2.37,-10.08,-6.58], [-0.28,-0.80,0.83], [-11.86,3.08,-0.45], [-0.28,-0.80,0.83]]), + (31, [[-641.70,515.00,30.80], [50.00,-30.40,-15.00], [-2.64,1.54,-11.95], [1.71,-0.27,-1.09], [6.41,10.54,-0.06], [1.71,-0.28,-1.09]]), + (32, [[-631.40,498.10,31.40], [-4.50,-28.10,4.10], [-0.02,-1.78,-12.22], [0.71,-0.99,-0.15], [12.20,-1.92,0.25], [0.71,-0.99,-0.15]]), + (33, [[-652.60,477.30,37.00], [-50.00,-6.30,6.60], [-1.60,-0.02,-12.27], [-1.33,1.31,0.06], [1.54,-12.27,-0.18], [-1.33,1.31,0.06]]), + (34, [[-711.30,508.40,47.40], [-65.20,35.30,20.70], [-3.19,1.14,-11.94], [-4.19,0.21,3.24], [-5.80,-10.97,0.50], [-4.19,0.21,3.24]]), + (35, [[-756.90,547.90,71.40], [-13.40,-32.80,30.60], [-11.62,0.46,-4.49], [-0.16,-0.33,-0.99], [2.82,-8.93,-8.23], [-0.16,-0.33,-0.99]]), + (36, [[-764.20,524.80,82.70], [2.40,-34.00,-3.00], [-8.44,0.19,-9.19], [1.12,1.17,2.11], [9.16,1.36,-8.38], [1.12,1.17,2.11]]), + (37, [[-733.10,495.70,71.40], [-9.60,-50.80,23.30], [-10.25,4.43,5.68], [3.16,-1.87,8.64], [-6.92,-3.34,-9.88], [3.17,-1.87,8.64]]), + (38, [[-714.70,462.80,83.00], [19.70,-9.40,0.00], [-1.64,-3.40,11.97], [-2.27,2.74,-8.49], [-5.16,-10.79,-3.77], [-2.27,2.74,-8.49]]), + (39, [[-703.00,463.20,92.20], [-6.90,19.30,27.80], [-9.75,5.16,-5.98], [-0.98,2.71,-11.42], [-7.51,-9.04,4.44], [-0.98,2.71,-11.43]]), + (40, [[-722.30,486.20,90.20], [-30.40,26.10,-0.90], [0.24,-0.18,-12.58], [4.54,-2.26,-3.13], [-8.18,-9.56,-0.02], [4.54,-2.26,-3.13]]), + (41, [[-745.10,520.90,90.70], [-10.10,19.90,1.10], [-0.29,0.57,-12.60], [0.25,-0.06,-0.02], [-11.25,-5.69,-0.00], [0.25,-0.06,-0.02]]), + (42, [[-724.50,528.30,92.00], [61.80,-0.90,2.80], [0.55,-0.02,-12.62], [-0.36,-0.13,0.04], [0.15,12.63,-0.01], [-0.36,-0.13,0.04]]), + (43, [[-691.00,492.20,92.50], [65.60,-18.50,-13.50], [-2.35,0.68,-12.42], [-1.69,0.78,0.19], [3.46,12.18,0.01], [-1.70,0.78,0.19]]), + (44, [[-640.00,474.10,57.50], [42.10,-24.20,-15.10], [-3.26,1.88,-12.14], [1.45,-0.62,-0.23], [6.34,11.01,-0.00], [1.45,-0.63,-0.23]]), + (45, [[-611.10,454.00,57.30], [-5.20,-35.60,0.00], [0.00,0.00,-12.73], [1.27,-0.75,-0.25], [12.60,-1.84,-0.00], [1.28,-0.75,-0.25]]), + (46, [[-640.70,443.80,57.50], [-30.10,-5.20,0.10], [-0.05,-0.02,-12.76], [0.00,0.00,-0.02], [2.16,-12.57,0.01], [0.00,0.00,-0.02]]), + (47, [[-667.60,443.10,57.50], [-25.60,5.80,0.00], [0.00,0.00,-12.77], [0.86,-0.09,0.06], [-2.82,-12.46,-0.00], [0.85,-0.09,0.06]]), + (48, [[-702.10,461.20,42.90], [-35.10,4.20,-7.10], [2.51,-0.31,-12.55], [-2.58,-3.51,4.12], [-1.52,-12.72,0.01], [-2.58,-3.51,4.12]]), + (49, [[-751.10,480.00,41.40], [-2.70,-4.20,52.00], [-8.23,-9.78,-1.21], [0.95,-1.86,-0.23], [9.83,-8.26,-0.14], [0.95,-1.86,-0.23]]), + (50, [[-740.70,460.80,81.10], [28.50,-35.40,18.50], [2.71,-5.98,-11.07], [0.35,3.93,-4.00], [11.24,6.22,-0.88], [0.34,3.93,-4.00]]), + (51, [[-715.80,438.10,60.60], [47.50,3.90,-28.60], [-6.62,-0.54,-11.07], [-2.22,3.02,-0.69], [-1.05,12.86,-0.00], [-2.22,3.03,-0.69]]), + (52, [[-690.60,420.70,23.60], [72.60,-48.00,-9.80], [-1.22,0.80,-12.86], [3.33,-0.90,-0.75], [7.12,10.80,0.00], [3.33,-0.90,-0.75]]), + (53, [[-634.40,437.80,2.60], [-11.70,62.00,-18.70], [0.67,-3.64,-12.45], [0.70,-0.09,-0.11], [-12.77,-2.41,0.01], [0.70,-0.10,-0.11]]), + (54, [[-685.40,456.30,14.80], [-80.30,28.90,-4.40], [0.64,-0.22,-13.01], [-0.87,2.09,-0.22], [-4.41,-12.26,-0.00], [-0.87,2.09,-0.22]]), + (55, [[-713.80,509.70,13.10], [-37.40,33.30,7.40], [-1.43,1.25,-12.93], [-3.03,-3.15,1.90], [-8.68,-9.78,0.01], [-3.03,-3.15,1.91]]), + (56, [[-762.90,511.80,46.30], [-17.40,-20.30,31.30], [-6.48,-7.55,-8.54], [-0.62,-3.81,1.50], [9.97,-8.52,-0.02], [-0.62,-3.81,1.50]]), + (57, [[-778.20,487.30,79.10], [-7.60,-16.30,20.80], [-4.19,-9.02,-8.60], [6.65,7.15,6.52], [11.92,-5.54,0.01], [6.65,7.16,6.52]]), + (58, [[-800.50,488.70,56.50], [-2.60,28.50,-35.30], [8.52,8.12,5.91], [6.13,4.32,8.27], [10.01,-6.27,-5.82], [6.13,4.32,8.26]]), + (59, [[-767.60,546.30,28.50], [27.50,29.90,28.50], [4.95,-10.54,6.27], [-7.20,-5.78,-5.89], [9.83,-0.64,-8.84], [-7.20,-5.78,-5.89]]), + (60, [[-730.30,549.50,39.80], [38.00,-16.90,-12.30], [-6.32,-10.60,-4.83], [0.16,0.75,-3.25], [-1.17,6.04,-11.74], [0.16,0.75,-3.25]]), + (61, [[-695.50,539.60,-1.80], [-25.60,-41.70,-52.60], [10.19,-8.37,1.69], [5.87,1.82,-1.72], [-7.11,-6.85,8.91], [5.87,1.82,-1.71]]), + (62, [[-753.60,538.10,17.50], [-40.40,-47.50,4.70], [6.27,-6.32,-9.95], [-2.66,-0.56,-4.61], [8.03,-5.95,8.85], [-2.66,-0.56,-4.61]]), + (63, [[-716.70,466.20,-1.60], [-40.40,-47.80,46.20], [4.18,-10.51,-7.20], [-1.22,-1.90,1.22], [10.66,-1.26,8.03], [-1.22,-1.90,1.22]]), + (64, [[-774.90,492.50,14.30], [4.60,-28.40,48.20], [3.28,-11.12,-6.84], [-2.63,-0.59,0.48], [13.01,3.36,0.76], [-2.63,-0.59,0.47]]), + (65, [[-755.00,488.60,92.30], [-28.50,3.50,3.80], [-2.24,-11.88,-6.06], [-0.86,-0.12,-0.18], [0.84,-6.26,11.96], [-0.86,-0.12,-0.18]]), + (66, [[-793.80,484.40,104.20], [-32.90,3.60,-1.30], [-1.01,-11.71,-6.76], [6.84,4.46,2.66], [-1.18,-6.68,11.73], [6.84,4.46,2.66]]), + (67, [[-790.70,455.50,85.30], [-2.30,-19.40,-39.70], [13.48,-1.65,0.00], [7.31,8.14,4.70], [-1.49,-12.10,5.97], [7.31,8.13,4.70]]), + (68, [[-801.70,464.20,17.70], [26.10,-25.90,-35.60], [11.25,6.96,3.26], [-7.03,6.33,-0.90], [3.16,-9.46,9.28], [-7.03,6.33,-0.90]]), + (69, [[-762.40,459.90,21.70], [25.40,2.00,17.80], [-0.71,13.64,-0.46], [-1.65,0.95,-2.28], [-7.81,-0.04,11.20], [-1.65,0.96,-2.28]]), + (70, [[-762.80,454.40,83.50], [-1.60,18.90,65.10], [11.83,6.72,-1.62], [-0.60,-1.49,6.17], [-6.91,11.33,-3.42], [-0.60,-1.49,6.16]]), + (71, [[-767.20,479.00,107.60], [-24.80,-1.90,8.70], [3.16,8.08,10.64], [-9.96,-2.61,4.05], [-3.39,11.06,-7.39], [-9.96,-2.61,4.05]]), + (72, [[-795.10,432.40,92.80], [-9.10,-19.70,-41.40], [-13.13,-1.80,3.77], [-2.62,-8.20,-1.68], [-3.18,12.37,-5.16], [-2.62,-8.20,-1.68]]), + (73, [[-769.20,411.90,25.90], [68.40,-16.90,-33.00], [1.27,-11.00,8.27], [5.91,1.76,3.98], [-6.47,-7.81,-9.40], [5.92,1.76,3.98]]), + (74, [[-679.40,419.00,45.00], [55.50,10.70,-0.20], [-0.79,4.58,13.09], [1.23,4.77,1.54], [2.54,-12.84,4.65], [1.23,4.77,1.54]]), + (75, [[-624.80,428.10,30.90], [37.00,1.10,-8.30], [2.78,4.05,13.03], [0.65,-3.43,0.31], [1.24,-13.32,3.88], [0.65,-3.43,0.31]]), + (76, [[-596.10,415.90,17.90], [13.70,-50.50,-10.30], [1.68,-2.24,13.67], [-2.26,-0.16,-0.25], [-13.40,-3.76,1.03], [-2.26,-0.16,-0.25]]), + (77, [[-633.70,383.40,10.50], [-53.90,-32.70,2.90], [-3.19,6.38,12.04], [-3.48,1.84,-0.84], [-6.50,10.15,-7.11], [-3.48,1.84,-0.84]]), + (78, [[-721.00,400.40,-2.40], [-84.80,146.00,5.60], [-5.70,-3.78,12.29], [0.98,-2.25,0.71], [10.74,5.98,6.82], [0.98,-2.25,0.71]]), + (79, [[-838.90,413.20,12.20], [-5.80,0.00,0.00], [-0.00,2.99,13.82], [-4.26,-1.08,-0.91], [0.00,13.82,-2.99], [-4.26,-1.08,-0.91]]), + (80, [[-841.90,390.30,9.10], [23.70,-40.80,14.10], [-7.16,0.08,12.23], [-3.54,-1.63,-0.61], [-10.15,-7.92,-5.89], [-3.54,-1.63,-0.61]]), + (81, [[-785.00,366.40,25.00], [68.10,-25.40,20.50], [-3.88,0.65,13.65], [2.70,1.81,0.59], [-4.77,-13.36,-0.72], [2.70,1.81,0.59]]), + (82, [[-715.10,372.10,29.90], [45.50,7.30,0.60], [-0.90,4.45,13.52], [1.10,0.20,0.24], [2.08,-13.35,4.54], [1.10,0.20,0.25]]), + (83, [[-676.70,381.70,46.00], [33.50,-1.60,1.70], [-0.65,2.52,14.05], [-2.24,0.19,-0.76], [-0.86,-14.05,2.49], [-2.25,0.19,-0.76]]), + (84, [[-624.70,387.70,43.50], [20.20,30.90,-2.50], [-6.80,5.40,11.39], [0.24,-5.21,-0.06], [9.89,-5.73,8.62], [0.24,-5.21,-0.06]]), + (85, [[-620.00,414.70,50.80], [-23.20,24.50,6.10], [-2.79,-5.83,12.81], [3.51,-2.77,1.11], [10.19,8.17,5.94], [3.51,-2.77,1.11]]), + (86, [[-667.60,418.50,51.40], [-25.90,-0.20,2.60], [1.39,3.45,13.89], [0.14,4.53,0.11], [-0.43,13.96,-3.43], [0.14,4.53,0.11]]), + (87, [[-705.40,416.80,61.80], [-55.10,-17.10,0.00], [-1.73,5.42,13.24], [-3.64,0.65,-0.93], [-3.97,12.62,-5.69], [-3.64,0.65,-0.93]]), + (88, [[-749.80,368.90,72.20], [-21.40,-38.20,-0.90], [-7.82,4.12,11.43], [2.52,2.85,-1.54], [-9.89,5.76,-8.83], [2.52,2.84,-1.54]]), + (89, [[-794.90,366.10,65.90], [-29.10,-4.30,9.30], [1.54,10.70,9.64], [4.72,2.23,-0.88], [-4.54,9.57,-9.88], [4.71,2.23,-0.88]]), + (90, [[-808.20,363.30,93.30], [18.80,-10.20,29.80], [4.22,10.42,9.17], [1.12,-0.05,-0.24], [-7.57,-3.14,11.97], [1.12,-0.05,-0.24]]), + (91, [[-772.30,355.10,95.70], [43.70,-4.20,-0.20], [3.97,10.61,9.11], [-2.39,-0.32,0.63], [2.05,-9.37,10.92], [-2.39,-0.32,0.63]]), + (92, [[-723.70,356.50,92.00], [34.80,14.40,-6.20], [-1.99,9.53,10.84], [2.61,-4.95,1.60], [5.66,-9.55,9.44], [2.61,-4.94,1.59]]), + (93, [[-704.10,380.20,92.30], [-4.50,25.20,1.10], [7.03,0.68,12.77], [-0.50,1.17,-0.66], [12.53,2.53,-7.03], [-0.50,1.17,-0.66]]), + (94, [[-724.40,396.00,92.70], [-30.00,-4.70,-0.50], [-1.81,10.80,9.67], [-4.52,4.97,-1.53], [-1.27,9.59,-10.95], [-4.52,4.97,-1.53]]), + (95, [[-761.40,390.00,92.00], [-26.80,-4.40,-1.30], [-2.26,10.77,9.65], [3.52,-0.78,0.05], [-1.07,9.61,-10.98], [3.52,-0.78,0.05]]), + (96, [[-796.40,394.20,92.00], [-19.90,14.60,-1.10], [6.15,9.03,9.78], [2.73,0.40,-0.79], [6.22,7.57,-10.91], [2.73,0.40,-0.79]]), + (97, [[-808.00,419.20,92.00], [22.20,4.70,-19.80], [4.65,11.45,7.93], [-2.50,1.30,-0.56], [8.76,-8.90,7.71], [-2.50,1.30,-0.56]]), + (98, [[-772.40,406.20,98.30], [40.50,-7.10,9.50], [-0.00,11.80,8.78], [-5.63,0.13,-2.26], [-4.14,-8.43,11.33], [-5.64,0.13,-2.26]]), + (99, [[-743.70,434.90,88.30], [-18.90,-10.80,-19.80], [-8.75,11.71,2.01], [-5.23,-2.29,-1.22], [7.16,7.20,-10.70], [-5.24,-2.29,-1.23]]), + (100, [[-799.10,394.00,52.00], [-21.00,-22.00,-12.00], [-10.41,4.89,9.33], [7.99,-2.65,4.28], [-4.46,9.83,-10.13], [7.99,-2.64,4.28]]), + (101, [[-804.50,342.90,51.10], [18.40,-46.20,24.50], [6.41,4.44,12.63], [5.00,2.57,0.35], [-11.15,-4.70,8.59], [5.00,2.57,0.35]]), + (102, [[-779.40,314.90,94.50], [43.80,-11.60,23.20], [0.13,11.14,9.87], [-2.57,2.84,-1.17], [-5.55,-8.91,10.56], [-2.57,2.84,-1.17]]), + (103, [[-725.70,321.90,94.80], [50.50,2.40,-4.10], [0.25,11.22,9.83], [2.24,-0.48,-0.06], [1.36,-9.80,11.17], [2.24,-0.48,-0.06]]), + (104, [[-673.60,342.20,84.90], [40.10,-23.10,1.40], [5.44,9.98,9.73], [2.31,-3.92,1.73], [-5.14,-8.28,11.36], [2.31,-3.92,1.73]]), + (105, [[-654.80,296.30,92.00], [7.30,-43.20,5.10], [5.88,2.56,13.56], [-3.45,-3.20,1.92], [-13.57,-1.59,6.18], [-3.45,-3.19,1.92]]), + (106, [[-638.40,213.80,96.30], [-29.60,-31.80,0.00], [-5.45,5.06,13.09], [4.65,2.69,-1.87], [-9.58,8.91,-7.44], [4.65,2.69,-1.87]]), + (107, [[-671.50,206.00,94.00], [-29.50,25.20,0.10], [7.27,8.43,10.17], [7.00,-1.55,-0.71], [6.61,7.74,-11.14], [7.00,-1.56,-0.71]]), + (108, [[-693.10,254.60,92.00], [-5.80,31.80,6.00], [8.71,-0.71,12.33], [0.22,-0.48,0.58], [12.05,3.79,-8.30], [0.22,-0.48,0.58]]), + (109, [[-692.70,282.10,99.60], [-11.70,28.50,0.00], [8.32,3.35,12.19], [-4.53,4.59,-0.52], [11.30,4.57,-8.98], [-4.53,4.59,-0.52]]), + (110, [[-714.50,303.80,105.30], [-27.80,-10.40,3.10], [-2.53,10.07,11.05], [-5.61,-1.93,0.96], [-4.90,10.03,-10.26], [-5.61,-1.93,0.96]]), + (111, [[-732.90,276.20,100.40], [-10.50,-24.20,-5.40], [-4.54,-1.23,14.44], [1.14,-6.02,1.63], [-13.22,6.55,-3.59], [1.15,-6.02,1.63]]), + (112, [[-739.60,242.40,94.90], [6.20,-21.60,0.00], [0.18,-3.68,14.76], [1.60,0.58,0.34], [-13.19,-7.53,-0.84], [1.60,0.58,0.33]]), + (113, [[-729.90,208.40,92.90], [31.10,-37.00,1.30], [-0.91,0.18,15.21], [-0.08,2.62,0.24], [-11.84,-9.57,-0.59], [-0.08,2.62,0.25]]), + (114, [[-671.40,183.60,95.20], [26.20,4.60,-18.30], [0.82,1.65,15.17], [0.74,0.62,0.01], [-3.15,-13.87,5.58], [0.74,0.62,0.01]]), + (115, [[-676.50,223.40,56.90], [-64.00,41.80,-9.80], [0.83,1.64,15.22], [0.01,0.00,0.05], [9.90,11.59,-1.60], [0.00,0.01,0.05]]), + (116, [[-680.80,291.90,29.60], [125.60,70.80,-6.60], [0.83,1.66,15.28], [-0.00,0.00,0.05], [8.29,-12.92,1.00], [0.00,0.01,0.05]]), + (117, [[-714.10,347.30,15.30], [-19.50,82.90,-38.40], [0.83,1.65,15.33], [0.00,0.00,0.06], [15.33,-1.59,0.98], [0.00,0.01,0.06]]), + (118, [[-801.90,404.60,-7.10], [-58.90,-30.30,2.30], [0.84,1.66,15.40], [0.00,0.00,0.05], [-6.23,14.16,-1.13], [0.00,0.01,0.05]]), + (119, [[-808.70,365.80,-13.70], [44.60,-53.00,-15.80], [0.84,1.66,15.44], [-0.00,0.00,0.05], [-13.75,-6.78,2.59], [0.00,0.01,0.05]]), + (120, [[-688.00,338.40,-11.70], [63.80,-48.80,8.70], [0.84,1.67,15.52], [0.00,0.01,0.07], [-8.51,-12.96,1.97], [0.00,0.01,0.07]]), + (121, [[-673.00,259.50,-3.20], [81.00,-7.10,7.50], [0.84,1.68,15.58], [0.00,0.01,0.06], [0.58,-15.56,1.94], [0.00,0.01,0.06]]), + (122, [[-674.40,198.70,27.60], [-166.70,-5.50,78.50], [0.85,1.70,15.65], [0.01,0.01,0.08], [-6.47,14.33,0.99], [0.00,0.01,0.08]]), + (123, [[-751.20,330.40,5.60], [-146.40,-62.90,102.70], [0.85,1.70,15.76], [0.01,0.01,0.10], [-11.81,10.19,2.93], [0.01,0.01,0.10]]), + (124, [[-771.40,224.30,-0.50], [-206.60,3.00,-5.40], [0.86,1.71,15.85], [0.01,0.01,0.09], [1.52,15.80,-1.69], [0.00,0.01,0.09]]), + (125, [[-809.20,353.00,16.20], [-189.70,36.40,-2.10], [0.86,1.72,15.95], [0.01,0.00,0.06], [3.70,15.51,-1.85], [0.00,0.01,0.06]]), + (126, [[-838.20,311.90,41.30], [13.30,-30.30,21.40], [0.87,1.72,15.99], [0.00,0.01,0.03], [-10.65,-10.80,5.40], [0.00,0.00,0.03]]), + (127, [[-817.10,288.00,42.40], [34.40,-12.20,0.70], [0.87,1.74,16.01], [-0.00,0.01,0.03], [-4.87,-15.25,1.93], [0.00,0.00,0.03]]), + (128, [[-752.40,294.00,78.80], [68.30,9.10,2.00], [0.87,1.73,16.07], [0.00,0.01,0.05], [3.61,-15.69,1.64], [0.00,0.01,0.05]]), + (129, [[-741.40,241.80,54.90], [-60.00,-10.60,-17.50], [0.87,1.74,16.12], [0.01,0.01,0.05], [3.05,15.94,0.02], [0.00,0.01,0.05]]), + (130, [[-802.80,226.00,43.40], [-39.00,36.40,14.80], [0.88,1.74,16.16], [0.00,0.01,0.04], [6.74,14.81,-0.51], [0.00,0.00,0.04]]), + (131, [[-833.10,266.00,68.30], [-22.10,29.70,29.30], [0.88,1.76,16.20], [0.00,0.00,0.03], [4.07,14.88,5.30], [0.00,0.00,0.03]]), + (132, [[-822.70,279.50,92.00], [26.60,9.70,0.30], [0.88,1.75,16.22], [-0.00,-0.00,0.02], [7.04,-14.68,1.37], [0.00,0.00,0.02]]), + (133, [[-799.30,280.50,92.00], [19.60,-7.30,0.00], [0.88,1.75,16.24], [-0.00,-0.00,0.02], [-5.47,-15.29,1.95], [0.00,0.00,0.02]]), + (134, [[-788.60,264.40,92.00], [-4.80,-26.50,0.00], [0.88,1.75,16.26], [-0.00,-0.00,0.02], [-15.65,4.75,0.55], [0.00,0.00,0.02]]), + (135, [[-814.90,246.10,92.00], [-26.10,-9.00,1.30], [0.88,1.75,16.28], [0.00,0.01,0.02], [-4.78,15.62,-1.40], [0.00,0.00,0.02]]), + (136, [[-826.20,223.00,92.00], [12.30,-25.30,0.00], [0.88,1.77,16.30], [0.00,0.01,0.02], [-15.18,-6.04,1.56], [0.00,0.00,0.02]]), + (137, [[-802.80,203.40,92.00], [45.00,8.60,0.00], [0.88,1.76,16.32], [0.00,0.00,0.03], [4.24,-15.80,1.57], [0.00,0.00,0.03]]), + (138, [[-783.70,237.40,92.10], [32.00,-1.80,-16.20], [0.89,1.76,16.35], [0.01,0.00,0.03], [-5.96,-14.63,4.62], [0.00,0.00,0.03]]), + (139, [[-754.40,192.40,70.50], [45.00,-18.70,-9.80], [0.89,1.78,16.39], [5.40,-1.59,-6.72], [-8.61,-13.85,2.55], [5.40,-1.59,-6.72]]), + (140, [[-680.80,179.60,31.60], [3.90,-10.60,-67.30], [16.13,-2.73,-2.64], [-5.09,-0.39,-13.72], [-2.06,-16.37,-1.55], [-5.09,-0.39,-13.72]]), + (141, [[-737.10,190.00,35.60], [-37.20,15.70,15.30], [-5.54,-0.10,-15.67], [-6.37,1.87,-5.13], [-4.96,-15.76,1.81], [-6.37,1.87,-5.13]]), + (142, [[-781.90,194.00,48.10], [-20.90,-6.20,-4.10], [-2.51,1.67,-16.37], [-2.28,2.28,1.31], [0.24,-16.33,-3.18], [-2.28,2.28,1.31]]), + (143, [[-802.30,178.10,41.90], [-11.30,-27.20,3.00], [-8.38,4.74,-13.60], [-3.69,-0.20,1.59], [12.99,-3.72,-9.76], [-3.69,-0.20,1.59]]), + (144, [[-799.10,145.80,39.00], [22.40,-22.60,-18.40], [-10.46,0.36,-13.00], [-1.30,-2.70,0.36], [8.11,13.21,-6.17], [-1.30,-2.69,0.36]]), + (145, [[-731.20,157.30,2.00], [50.10,-43.00,-3.70], [-10.50,0.36,-13.04], [-0.04,-0.00,-0.04], [2.84,15.32,-6.13], [-0.04,0.00,-0.05]]), + (146, [[-669.40,112.80,4.40], [136.30,170.20,-47.50], [-10.54,0.36,-13.09], [-0.05,0.00,-0.06], [-11.96,7.66,8.98], [-0.04,0.00,-0.06]]), + (147, [[-750.70,184.10,17.70], [-76.40,-20.30,-34.70], [-10.59,0.36,-13.15], [-0.04,0.00,-0.06], [-9.66,-10.81,-8.68], [-0.05,0.00,-0.06]]), + (148, [[-840.70,197.30,-8.00], [-65.70,-54.00,-27.90], [-10.63,0.36,-13.21], [-0.04,0.00,-0.05], [-0.51,-13.45,-10.33], [-0.04,0.00,-0.05]]), + (149, [[-770.00,153.90,-18.30], [146.60,96.20,29.90], [-10.68,0.37,-13.26], [9.19,1.65,-0.79], [-16.16,3.27,4.27], [9.19,1.65,-0.79]]), + (150, [[-687.80,179.20,-17.80], [93.00,6.90,16.70], [7.76,3.67,-14.78], [9.87,3.45,8.75], [3.45,16.26,3.96], [9.86,3.45,8.75]]), + (151, [[-660.00,168.80,104.60], [-61.10,-12.30,52.70], [7.71,8.52,12.78], [-10.02,-0.74,9.08], [-8.33,14.36,-4.45], [-10.02,-0.74,9.08]]), + (152, [[-732.50,164.50,92.40], [-75.70,-13.60,-3.40], [-9.99,4.48,13.31], [-7.28,-3.78,0.66], [-10.45,12.05,-6.54], [-7.28,-3.78,0.66]]), + (153, [[-785.80,124.60,91.40], [-10.20,-35.80,-2.20], [-9.79,-0.00,14.25], [6.65,-4.80,1.10], [-14.18,2.71,-9.51], [6.65,-4.79,1.10]]), + (154, [[-759.00,91.20,83.60], [119.50,-1.50,4.30], [3.74,-6.20,15.74], [5.90,-3.29,1.00], [4.41,-15.65,-5.99], [5.90,-3.29,1.00]]), + (155, [[-640.80,136.60,98.60], [46.60,50.10,7.60], [-5.31,-4.25,16.03], [-2.83,0.60,0.12], [8.81,-15.01,0.44], [-2.82,0.60,0.12]]), + (156, [[-579.70,151.60,100.30], [19.20,-49.70,4.50], [-5.33,-4.26,16.07], [-0.02,-0.02,0.05], [-13.36,-9.37,-6.20], [-0.02,-0.01,0.05]]), + (157, [[-626.30,99.70,102.90], [-45.20,-3.50,0.20], [-5.34,-4.28,16.12], [0.63,2.69,0.49], [-6.93,15.61,3.88], [0.63,2.69,0.49]]), + (158, [[-677.50,87.90,102.10], [-1.10,-44.00,15.60], [-4.07,1.07,17.04], [-0.22,-0.88,-0.12], [-16.52,-5.46,-2.27], [-0.22,-0.88,-0.12]]), + (159, [[-658.60,70.80,123.20], [64.50,-18.30,7.60], [-5.36,-4.29,16.18], [-0.57,-2.37,-0.37], [-5.95,-15.49,-5.79], [-0.57,-2.36,-0.37]]), + (160, [[-663.80,52.80,121.60], [-54.40,-14.30,-27.10], [-5.37,-4.30,16.20], [-0.01,-0.01,0.03], [-4.39,16.75,3.11], [-0.01,-0.01,0.03]]), + (161, [[-714.90,78.70,84.40], [-26.00,-24.40,-65.40], [-5.38,-4.31,16.24], [-0.02,-0.01,0.05], [-5.28,13.99,9.37], [-0.02,-0.01,0.05]]), + (162, [[-658.40,32.50,83.90], [2.10,116.00,-7.20], [-5.40,-4.32,16.31], [-0.02,-0.01,0.06], [15.91,-5.37,5.65], [-0.02,-0.02,0.06]]), + (163, [[-604.60,113.30,63.50], [-28.80,78.00,-53.10], [-5.42,-4.34,16.37], [-0.02,-0.02,0.06], [13.72,-0.73,11.29], [-0.02,-0.02,0.06]]), + (164, [[-692.90,147.10,50.50], [-30.70,48.10,-22.50], [-5.45,-4.36,16.43], [-0.02,-0.01,0.06], [14.65,4.96,8.92], [-0.02,-0.02,0.06]]), + (165, [[-760.40,156.30,47.10], [12.40,-68.30,10.10], [-5.46,-4.37,16.49], [-0.01,-0.01,0.05], [-14.42,-9.21,-5.27], [-0.02,-0.01,0.05]]), + (166, [[-714.60,117.30,46.30], [59.10,-31.90,-3.20], [-5.48,-4.38,16.53], [3.35,-1.81,-0.44], [-11.15,-12.59,-6.28], [3.35,-1.81,-0.44]]), + (167, [[-642.10,94.70,41.50], [86.40,3.30,-36.50], [2.97,-8.92,15.36], [8.28,8.12,-9.98], [-6.20,-15.41,-6.94], [8.28,8.12,-9.98]]), + (168, [[-636.10,134.80,16.40], [117.50,19.20,-27.50], [13.01,11.72,-4.34], [5.09,10.44,-9.95], [16.70,3.66,5.77], [5.09,10.44,-9.94]]), + (169, [[-578.20,88.00,25.20], [2.50,-59.30,17.40], [13.05,11.76,-4.35], [0.54,-10.37,3.35], [0.38,15.32,9.62], [0.54,-10.38,3.35]]), + (170, [[-631.30,39.10,34.60], [-128.70,-21.40,-13.20], [14.18,-10.93,2.97], [-7.55,-13.18,3.33], [10.62,3.52,14.30], [-7.54,-13.18,3.33]]), + (171, [[-704.70,57.70,8.40], [-125.70,-34.50,10.50], [-4.45,-17.41,2.94], [-13.98,6.42,-1.88], [-8.13,0.07,16.29], [-13.98,6.42,-1.88]]), + (172, [[-784.50,117.60,16.90], [39.80,42.00,-36.30], [-16.21,8.23,-1.98], [1.81,11.47,-8.58], [1.21,7.71,16.54], [1.81,11.48,-8.57]]), + (173, [[-699.80,123.10,-24.30], [55.40,-153.80,-40.30], [-0.62,8.58,-16.23], [7.44,0.19,-6.84], [15.51,9.29,3.25], [7.45,0.19,-6.84]]), + (174, [[-800.50,108.10,-31.70], [-87.40,47.70,13.70], [-0.62,8.63,-16.30], [-0.00,0.03,-0.05], [-11.00,-13.11,-6.88], [0.00,0.03,-0.05]]), + (175, [[-802.60,73.80,-45.80], [60.70,-32.10,-7.20], [-0.62,8.65,-16.33], [-0.00,0.02,-0.05], [5.98,15.75,7.61], [0.00,0.02,-0.05]]), + (176, [[-700.50,58.60,-44.70], [56.40,29.00,19.90], [-0.62,8.67,-16.40], [0.00,0.03,-0.05], [-11.15,13.01,7.14], [0.00,0.03,-0.05]]), + (177, [[-650.80,100.60,-19.70], [52.40,82.20,48.00], [-0.62,8.71,-16.44], [-2.79,-2.28,-0.32], [-16.75,6.91,4.24], [-2.78,-2.28,-0.33]]), + (178, [[-659.10,149.90,-29.60], [34.00,79.40,15.20], [-6.40,3.94,-17.07], [-0.18,-0.13,-0.05], [-16.86,3.82,6.99], [-0.18,-0.13,-0.05]]), + (179, [[-609.50,156.90,-23.70], [15.60,-53.60,-14.70], [-0.63,8.73,-16.51], [2.21,1.85,0.20], [16.45,8.41,2.81], [2.21,1.85,0.20]]), + (180, [[-609.70,110.70,-23.20], [40.80,-48.10,-0.90], [-0.63,8.76,-16.54], [-2.04,-1.11,0.02], [8.31,15.92,5.28], [-2.04,-1.11,0.02]]), + (181, [[-646.50,26.10,-11.20], [-162.60,-77.40,15.80], [-7.92,4.72,-16.37], [-2.07,0.47,11.78], [3.29,-16.99,-7.32], [-2.07,0.47,11.79]]), + (182, [[-611.30,41.40,96.10], [57.30,45.80,-2.40], [-3.44,11.46,14.61], [-0.50,-9.06,9.07], [12.59,-8.80,10.96], [-0.50,-9.06,9.07]]), + (183, [[-577.60,74.90,90.60], [55.80,-10.00,15.40], [-5.77,-4.62,17.41], [-1.04,-7.16,1.27], [-1.88,-18.03,-5.40], [-1.04,-7.15,1.27]]), + (184, [[-584.90,34.80,107.90], [-13.40,-36.10,14.60], [-5.78,-4.63,17.44], [-0.01,-0.00,0.03], [-17.60,-7.00,0.74], [-0.01,-0.01,0.03]]), + (185, [[-599.80,-4.20,106.40], [-10.50,-58.00,-59.30], [-5.79,-4.63,17.47], [-0.01,-0.00,0.03], [-14.34,12.16,2.56], [-0.01,-0.01,0.03]]), + (186, [[-560.70,-5.80,103.50], [22.80,77.00,53.00], [-5.80,-4.64,17.50], [-0.01,-0.01,0.04], [17.65,-3.70,6.06], [-0.01,-0.01,0.04]]), + (187, [[-539.50,62.70,103.50], [25.80,91.30,0.00], [-5.81,-4.65,17.55], [-0.01,-0.01,0.04], [15.25,-10.60,4.32], [-0.01,-0.01,0.04]]), + (188, [[-509.90,125.70,103.50], [40.90,31.10,0.00], [-5.83,-4.67,17.59], [-0.01,-0.01,0.03], [4.70,-18.52,-0.19], [-0.01,-0.01,0.03]]), + (189, [[-480.30,136.30,103.50], [27.90,-1.50,0.00], [-5.84,-4.67,17.61], [-0.00,0.00,0.02], [-6.52,-17.29,-4.98], [-0.01,-0.00,0.02]]), + (190, [[-463.80,126.60,103.50], [2.20,-41.60,0.00], [-5.84,-4.67,17.63], [-0.00,-0.00,0.02], [-17.37,-5.28,-6.07], [-0.01,-0.01,0.02]]), + (191, [[-502.40,82.30,103.50], [-23.60,-27.20,0.00], [-5.85,-4.68,17.67], [-0.01,-0.01,0.02], [-18.17,6.02,-1.35], [-0.01,-0.01,0.02]]), + (192, [[-509.30,56.80,103.50], [23.00,-22.90,0.00], [-5.86,-4.69,17.68], [-0.01,-0.01,0.02], [-13.07,-11.93,-7.46], [-0.01,-0.01,0.02]]), + (193, [[-475.50,64.70,103.50], [44.10,-1.90,0.00], [-5.87,-4.70,17.70], [-0.01,-0.01,0.03], [-6.42,-17.44,-4.94], [-0.01,-0.01,0.03]]), + (194, [[-430.20,49.30,103.50], [14.50,-56.10,1.00], [-5.88,-4.70,17.74], [-0.01,-0.01,0.04], [-16.25,-7.81,-6.81], [-0.01,-0.01,0.04]]), + (195, [[-469.90,5.30,104.60], [-58.90,-25.60,-18.20], [-5.89,-4.71,17.78], [-0.01,-0.01,0.04], [-10.01,16.47,1.31], [-0.01,-0.01,0.04]]), + (196, [[-530.20,8.80,71.20], [-89.40,9.00,-28.70], [-5.91,-4.73,17.82], [-0.01,-0.01,0.04], [0.52,18.66,5.13], [-0.01,-0.01,0.04]]), + (197, [[-549.80,51.30,74.50], [56.60,60.50,38.30], [-5.92,-4.74,17.86], [-0.01,-0.01,0.04], [14.25,-13.10,1.27], [-0.01,-0.01,0.04]]), + (198, [[-531.30,109.40,71.30], [86.60,49.60,3.50], [-5.93,-4.75,17.90], [-0.02,-0.01,0.05], [3.10,-19.15,-1.42], [-0.02,-0.01,0.05]]), + (199, [[-456.50,140.50,51.60], [45.40,11.90,-8.30], [-5.95,-4.76,17.95], [-0.02,-0.01,0.05], [-5.85,-18.55,-1.30], [-0.02,-0.01,0.05]]), + (200, [[-423.00,81.00,50.80], [-44.50,-103.30,-0.20], [-5.97,-4.77,18.00], [-0.02,-0.02,0.07], [-19.20,0.97,-3.61], [-0.02,-0.02,0.07]]), + (201, [[-549.80,34.30,52.00], [-12.30,-134.80,-12.90], [-6.00,-4.80,18.09], [-0.02,-0.02,0.08], [-18.71,-1.35,-5.86], [-0.03,-0.02,0.08]]), + (202, [[-465.30,-17.50,49.30], [-46.30,-108.10,-19.60], [-6.02,-4.82,18.17], [2.96,6.02,-0.20], [-18.71,4.67,-4.20], [2.95,6.02,-0.20]]), + (203, [[-578.60,-16.50,42.30], [-82.70,25.50,-15.40], [0.80,9.04,17.62], [-3.24,8.71,-6.08], [7.84,16.08,-8.53], [-3.24,8.71,-6.08]]), + (204, [[-536.60,25.20,15.60], [37.70,57.90,-21.80], [-9.40,16.09,6.92], [-2.87,-6.71,0.69], [13.43,3.94,14.11], [-2.87,-6.71,0.69]]), + (205, [[-529.00,93.90,11.80], [61.50,67.50,-4.90], [-6.08,-4.86,18.34], [1.52,-9.66,5.29], [7.46,-18.40,1.69], [1.52,-9.66,5.29]]), + (206, [[-468.20,137.50,16.60], [50.60,13.70,-2.50], [-6.09,-4.88,18.39], [-0.02,-0.01,0.05], [-3.17,-19.54,-2.73], [-0.02,-0.01,0.05]]), + (207, [[-398.80,135.90,16.10], [54.50,-33.90,-12.10], [-6.11,-4.89,18.43], [-0.02,-0.01,0.04], [-15.45,-11.14,-6.14], [-0.01,-0.01,0.04]]), + (208, [[-378.80,78.80,14.50], [-8.10,-48.90,36.10], [-6.12,-4.90,18.47], [-0.01,-0.01,0.04], [-13.91,-13.60,4.94], [-0.01,-0.01,0.04]]), + (209, [[-398.00,36.20,45.80], [-34.00,-45.80,24.00], [-6.13,-4.91,18.51], [-0.01,-0.01,0.04], [-19.59,-2.70,3.65], [-0.01,-0.01,0.04]]), + (210, [[-442.20,-17.60,57.50], [-86.50,-40.80,33.20], [-6.15,-4.92,18.55], [-0.02,-0.01,0.05], [-17.24,8.47,6.09], [-0.02,-0.01,0.05]]), + (211, [[-533.50,-18.10,72.80], [-62.70,-13.50,25.80], [-6.17,-4.94,18.61], [-0.01,-0.01,0.05], [-14.04,11.94,8.31], [-0.01,-0.01,0.04]]), + (212, [[-559.10,-59.00,75.10], [21.70,-55.50,8.30], [-6.18,-4.94,18.65], [-0.01,-0.01,0.04], [-14.76,-12.09,-6.80], [-0.01,-0.01,0.04]]), + (213, [[-500.70,-84.90,81.00], [63.70,28.70,0.20], [-6.19,-4.96,18.69], [-0.02,-0.02,0.05], [0.74,-20.19,-2.00], [-0.02,-0.01,0.05]]), + (214, [[-421.10,-26.60,49.00], [38.30,45.90,-36.30], [-6.22,-4.97,18.76], [-0.02,-0.02,0.05], [0.75,-17.81,9.88], [-0.02,-0.01,0.05]]), + (215, [[-382.00,4.70,3.40], [8.90,68.80,-40.90], [-6.23,-4.99,18.80], [-0.01,-0.01,0.04], [11.93,-11.30,12.14], [-0.01,-0.01,0.04]]), + (216, [[-389.10,52.20,-22.10], [-29.80,81.20,-22.40], [-6.24,-4.99,18.84], [-0.01,-0.01,0.04], [18.27,1.33,9.13], [-0.01,-0.01,0.04]]), + (217, [[-412.00,118.00,-36.80], [-99.40,115.40,42.30], [-6.26,-5.01,18.88], [-0.02,-0.02,0.05], [11.77,14.09,9.14], [-0.02,-0.01,0.05]]), + (218, [[-500.70,120.50,-22.30], [-52.50,-122.90,19.40], [-6.28,-5.02,18.95], [-0.02,-0.02,0.08], [-20.30,-2.39,-2.37], [-0.03,-0.02,0.08]]), + (219, [[-430.50,6.20,-21.60], [-110.00,-102.90,20.20], [-6.31,-5.05,19.04], [-0.04,-0.03,0.10], [-19.84,5.82,0.77], [-0.03,-0.03,0.10]]), + (220, [[-561.60,93.90,-37.50], [-136.90,-93.80,13.70], [-6.35,-5.08,19.15], [-0.03,-0.02,0.10], [-18.31,9.78,1.39], [-0.03,-0.03,0.10]]), + (221, [[-478.90,-3.90,-57.80], [64.00,-137.50,21.40], [-6.38,-5.10,19.25], [6.63,6.39,-0.25], [-14.64,-13.06,-7.21], [6.62,6.39,-0.25]]), + (222, [[-431.20,-73.10,-4.70], [-33.20,-2.10,83.80], [6.32,7.14,18.69], [-1.05,-1.02,0.11], [-12.55,12.41,11.34], [-1.05,-1.01,0.11]]), + (223, [[-498.10,-26.50,1.10], [-106.30,89.80,-35.30], [-6.42,-5.14,19.37], [-6.98,-6.72,0.41], [13.24,13.90,8.61], [-6.98,-6.72,0.41]]), + (224, [[-612.20,36.10,28.20], [-42.00,-52.50,15.50], [-6.45,-5.16,19.46], [-0.02,-0.01,0.06], [-21.10,1.09,0.98], [-0.02,-0.02,0.06]]), + (225, [[-599.60,-31.30,28.40], [13.40,-54.20,-7.20], [-6.46,-5.17,19.51], [-0.02,-0.01,0.04], [-19.22,-4.73,-7.57], [-0.01,-0.01,0.04]]), + (226, [[-551.10,-68.30,48.80], [70.00,-22.30,2.00], [-6.48,-5.18,19.55], [-0.02,-0.01,0.04], [-9.67,-17.56,-7.01], [-0.01,-0.01,0.04]]), + (227, [[-489.30,-77.50,38.10], [74.30,17.00,-23.00], [-6.49,-5.19,19.59], [-0.01,-0.01,0.04], [-9.28,-19.15,0.25], [-0.01,-0.01,0.04]]), + (228, [[-463.60,-26.20,12.80], [-33.30,65.70,20.70], [-6.51,-5.21,19.64], [-0.02,-0.02,0.06], [16.67,9.94,8.85], [-0.02,-0.02,0.06]]), + (229, [[-582.60,39.80,-15.30], [-97.00,-93.30,-56.80], [-6.54,-5.23,19.73], [-0.03,-0.02,0.09], [-14.65,15.64,-0.71], [-0.03,-0.02,0.09]]), + (230, [[-535.10,-48.00,-7.60], [163.70,-58.30,-145.00], [-6.56,-5.25,19.81], [-0.02,-0.02,0.08], [-20.10,-5.99,4.82], [-0.03,-0.02,0.08]]), + (231, [[-451.00,-130.20,37.30], [-10.40,16.50,63.10], [-6.59,-5.28,19.90], [-0.02,-0.02,0.06], [7.06,1.52,20.37], [-0.02,-0.02,0.06]]), + (232, [[-404.70,-90.30,45.30], [28.50,23.80,-5.20], [-6.61,-5.29,19.95], [-0.02,-0.01,0.04], [3.46,-21.33,1.72], [-0.01,-0.01,0.04]]), + (233, [[-373.40,-43.10,39.40], [5.90,71.90,-6.80], [-6.62,-5.30,19.98], [0.41,8.07,-8.50], [18.70,-8.62,6.86], [0.41,8.07,-8.50]]), + (234, [[-350.70,43.10,-5.50], [0.30,-23.00,-85.30], [-5.32,20.03,-6.74], [3.76,0.99,-18.90], [21.10,4.82,-2.54], [3.76,0.98,-18.90]]), + (235, [[-326.20,-52.10,3.90], [120.10,-136.40,45.10], [1.77,-4.02,-21.42], [8.00,-8.11,-5.57], [15.86,14.96,-1.55], [8.00,-8.11,-5.57]]), + (236, [[-415.40,-151.90,68.80], [-13.60,-50.50,-41.70], [13.15,9.60,-14.76], [-5.91,8.77,17.85], [17.28,-10.65,8.42], [-5.91,8.77,17.85]]), + (237, [[-353.60,-118.40,-8.30], [36.00,49.60,-67.80], [-5.10,16.63,13.41], [-6.76,-0.33,14.51], [18.46,-3.09,11.50], [-6.76,-0.33,14.52]]), + (238, [[-394.00,-54.90,-43.90], [-58.50,62.10,18.60], [-3.49,10.08,19.17], [-2.87,-4.30,1.63], [2.39,21.76,-1.38], [-2.88,-4.30,1.64]]), + (239, [[-374.20,70.30,-64.10], [-51.80,111.20,-42.80], [-13.56,7.99,15.21], [-4.29,-2.14,-1.16], [12.77,16.72,6.04], [-4.31,-2.13,-1.15]]), + (240, [[-480.40,88.90,-81.20], [-77.00,-72.50,-24.50], [-13.35,5.40,16.42], [4.11,-0.54,2.38], [-11.28,13.22,-13.24], [4.12,-0.54,2.40]]), + (241, [[-447.70,23.20,-62.70], [98.20,-53.90,-35.40], [-5.54,6.32,20.13], [6.87,3.25,0.83], [-18.69,-8.92,6.84], [6.89,3.27,0.84]]), + (242, [[-382.90,-144.70,-29.60], [-142.90,-41.30,110.60], [1.45,15.82,14.84], [2.82,3.81,-2.16], [-15.98,11.38,-9.36], [2.83,3.84,-2.15]]), + (243, [[-481.80,-39.40,-48.90], [-146.60,-39.20,12.20], [1.45,15.78,14.80], [-0.00,-0.05,-0.04], [-0.96,15.47,-15.16], [0.00,-0.03,-0.03]]), + (244, [[-453.60,-166.50,-38.80], [150.00,-6.00,-58.50], [1.45,15.73,14.76], [-0.01,-0.05,-0.05], [0.88,-14.09,16.35], [0.00,-0.03,-0.03]]), + (245, [[-534.60,2.00,-60.70], [-321.90,11.50,28.90], [1.44,15.66,14.71], [-0.01,-0.04,-0.04], [-1.31,14.78,-15.61], [0.00,-0.03,-0.03]]), + (246, [[-620.80,88.60,-65.80], [-173.30,-112.90,-24.50], [1.44,15.62,14.67], [-0.00,-0.04,-0.04], [3.37,18.22,-10.88], [0.00,-0.03,-0.02]]), + (247, [[-601.00,-61.20,-12.30], [87.00,-77.00,21.40], [1.44,15.59,14.63], [9.17,-14.24,-6.83], [-17.11,-6.31,11.25], [9.27,-14.39,-6.89]]), + (248, [[-524.30,-72.50,-58.30], [-55.40,-200.40,-26.20], [18.39,-10.71,2.04], [5.34,-1.84,-3.12], [-4.64,-6.66,19.78], [5.41,-1.85,-3.14]]), + (249, [[-516.70,-125.70,44.60], [99.10,-71.00,10.10], [11.44,15.46,9.24], [1.88,3.64,-8.37], [-5.77,-7.15,19.26], [1.91,3.68,-8.47]]), + (250, [[-511.50,-154.20,13.70], [-22.70,29.20,-59.80], [17.60,9.46,-7.43], [-3.65,-0.47,0.86], [3.49,-15.47,-14.24], [-3.69,-0.47,0.87]]), + (251, [[-507.90,-150.60,-52.20], [77.80,65.80,-26.70], [1.42,15.50,14.54], [-8.54,3.17,11.58], [18.21,-6.69,8.76], [-8.65,3.22,11.73]]), + (252, [[-501.90,-69.20,-84.50], [124.80,-47.20,-52.70], [1.42,15.45,14.52], [-0.00,-0.03,-0.03], [-7.08,-10.13,17.29], [-0.00,-0.02,-0.02]]), + (253, [[-435.40,-182.40,-85.30], [133.20,-88.90,11.70], [1.42,15.43,14.48], [-6.83,-0.95,-2.07], [-14.37,-8.41,13.13], [-6.94,-0.95,-2.09]]), + (254, [[-364.90,-190.70,-12.50], [-54.90,-42.00,69.00], [-12.69,13.50,10.23], [-5.25,1.16,-5.56], [-18.74,-6.89,-7.00], [-5.33,1.18,-5.63]]), + (255, [[-340.30,-163.80,48.10], [128.90,72.90,-11.00], [-11.73,17.39,2.56], [1.45,0.79,0.19], [0.95,-2.26,20.99], [1.47,0.81,0.20]]), + (256, [[-317.00,-143.90,-26.80], [-88.40,-30.90,-19.80], [-9.41,14.90,11.59], [6.33,-0.81,5.07], [-2.02,12.17,-17.11], [6.43,-0.81,5.16]]), + (257, [[-358.50,-142.30,-98.10], [-66.10,25.40,-1.30], [1.41,15.33,14.38], [6.65,0.24,1.70], [1.79,14.79,-14.88], [6.77,0.26,1.74]]), + (258, [[-360.30,29.80,-104.30], [133.20,-2.90,37.90], [1.41,15.28,14.32], [-6.70,-8.71,0.72], [0.29,-13.50,16.07], [-6.84,-8.87,0.75]]), + (259, [[-315.60,-96.60,-32.70], [59.80,120.90,165.90], [-13.09,-3.52,15.94], [4.77,-4.90,1.16], [13.62,-10.81,11.63], [4.87,-4.98,1.20]]), + (260, [[-314.20,51.50,-89.10], [14.30,127.70,-5.60], [11.50,4.15,16.90], [-1.05,-1.37,-0.07], [17.48,2.25,-11.17], [-1.08,-1.40,-0.05]]), + (261, [[-333.70,97.10,47.00], [52.00,38.50,28.60], [-12.25,-5.42,15.92], [-3.38,4.27,-19.59], [6.80,-19.65,0.45], [-3.45,4.37,-20.04]]), + (262, [[-304.70,120.30,-32.00], [62.80,-40.80,-60.10], [-3.42,8.27,-18.73], [3.93,2.96,-20.26], [17.05,11.85,0.22], [4.01,3.02,-20.74]]), + (263, [[-235.30,-46.60,17.40], [156.60,-68.60,59.20], [-8.09,-9.42,-16.55], [11.87,-4.32,3.21], [1.70,15.03,-14.11], [12.18,-4.43,3.27]]), + (264, [[-160.60,8.90,41.90], [96.20,60.70,-14.40], [15.14,-6.91,-12.23], [7.32,9.43,12.02], [1.54,13.97,-15.14], [7.50,9.68,12.33]]), + (265, [[-233.60,108.70,14.10], [-196.10,-54.60,-35.60], [1.38,14.98,14.07], [-6.34,10.06,12.10], [6.17,15.14,-12.54], [-6.50,10.34,12.42]]), + (266, [[-327.10,-7.90,-1.40], [30.20,-91.10,80.60], [1.37,14.95,14.03], [-1.77,-3.98,2.52], [-20.16,-1.40,3.63], [-1.82,-4.08,2.60]]), + (267, [[-223.10,8.60,56.80], [64.40,127.00,90.60], [-2.21,6.93,19.16], [5.46,-14.42,-3.87], [16.29,2.53,12.17], [5.63,-14.85,-3.98]]), + (268, [[-253.90,87.40,105.10], [-5.80,39.60,111.40], [11.35,-15.25,7.54], [-1.00,9.40,-0.35], [16.81,11.53,-1.70], [-1.03,9.68,-0.35]]), + (269, [[-243.10,128.50,112.80], [95.00,13.80,1.40], [1.37,14.86,13.96], [-4.00,12.07,2.56], [5.45,-13.26,14.57], [-4.12,12.44,2.65]]), + (270, [[-198.40,111.30,103.50], [29.70,-22.50,0.00], [1.37,14.85,13.95], [-0.01,-0.01,-0.01], [-14.69,-6.36,12.67], [0.00,-0.01,-0.01]]), + (271, [[-179.80,86.80,103.50], [15.50,-40.20,-2.20], [1.36,14.84,13.94], [-0.01,-0.01,-0.01], [-17.27,8.03,7.33], [0.00,-0.01,-0.01]]), + (272, [[-181.00,44.30,103.40], [-23.30,-31.20,0.00], [1.36,14.83,13.93], [-0.00,-0.01,-0.01], [-3.55,18.51,-7.78], [0.00,-0.01,-0.01]]), + (273, [[-212.60,28.50,103.50], [-45.50,-9.50,0.00], [1.36,14.82,13.92], [-0.00,-0.01,-0.01], [1.43,14.51,-14.23], [0.00,-0.01,-0.01]]), + (274, [[-268.30,32.40,103.80], [-47.70,23.20,-5.70], [1.36,14.80,13.91], [-0.00,-0.01,-0.02], [4.29,13.91,-14.23], [0.00,-0.01,-0.01]]), + (275, [[-303.20,68.70,92.20], [-16.00,43.30,-4.00], [1.36,14.80,13.89], [-0.00,-0.01,-0.02], [10.06,16.04,-7.43], [0.00,-0.01,-0.01]]), + (276, [[-264.40,113.10,92.20], [96.40,13.40,-16.30], [1.36,14.77,13.88], [-0.00,-0.02,-0.02], [5.35,-13.63,14.08], [0.00,-0.01,-0.01]]), + (277, [[-194.80,79.90,66.60], [66.40,101.30,-2.50], [1.36,14.76,13.85], [-0.00,-0.02,-0.02], [18.90,3.08,6.69], [0.00,-0.02,-0.02]]), + (278, [[-259.90,145.40,69.10], [-50.20,11.70,0.70], [1.36,14.72,13.83], [-0.00,-0.02,-0.02], [0.79,13.98,-14.62], [0.00,-0.01,-0.01]]), + (279, [[-332.40,128.50,76.00], [-49.00,-52.40,-1.30], [1.37,14.70,13.81], [-0.00,-0.02,-0.02], [-1.68,18.11,-8.83], [0.00,-0.01,-0.01]]), + (280, [[-350.80,61.90,80.80], [-2.80,-49.40,0.50], [1.37,14.70,13.79], [-0.00,-0.02,-0.02], [-13.09,15.37,0.38], [0.00,-0.01,-0.01]]), + (281, [[-310.50,4.10,73.40], [145.80,-25.20,-6.40], [1.35,14.68,13.77], [-0.01,-0.02,-0.02], [-3.44,-13.31,14.75], [0.00,-0.01,-0.01]]), + (282, [[-271.10,-43.80,94.40], [16.10,-48.30,3.80], [1.35,14.65,13.76], [-0.00,-0.01,-0.01], [-18.02,7.51,4.97], [0.00,-0.01,-0.01]]), + (283, [[-270.90,-77.40,103.40], [39.70,-14.80,1.00], [1.34,14.65,13.75], [-0.00,-0.01,-0.01], [-8.45,-11.61,14.10], [0.00,-0.01,-0.01]]), + (284, [[-220.70,-87.80,97.40], [44.90,15.00,0.00], [1.34,14.63,13.73], [-0.00,-0.01,-0.01], [9.96,-11.15,13.45], [0.00,-0.01,-0.01]]), + (285, [[-173.40,-67.30,82.30], [-11.80,54.90,-11.40], [1.34,14.62,13.72], [-0.00,-0.02,-0.02], [13.78,13.09,-6.49], [0.00,-0.01,-0.01]]), + (286, [[-229.90,-30.60,62.70], [-49.80,8.30,-5.90], [1.34,14.60,13.70], [-0.00,-0.02,-0.01], [4.44,13.17,-14.46], [0.00,-0.01,-0.01]]), + (287, [[-291.70,-26.70,39.10], [-43.90,3.80,0.00], [1.34,14.57,13.69], [-0.00,-0.01,-0.01], [1.27,13.63,-14.63], [0.00,-0.01,-0.01]]), + (288, [[-323.60,-28.80,45.90], [-29.10,-6.00,15.70], [1.34,14.56,13.68], [-0.00,-0.01,-0.01], [-11.52,12.00,-11.15], [0.00,-0.01,-0.00]]), + (289, [[-340.40,-46.90,56.00], [-7.70,-28.60,-0.30], [1.34,14.55,13.67], [-0.00,-0.01,-0.01], [-9.27,17.59,-2.33], [0.00,-0.01,-0.01]]), + (290, [[-341.70,-83.90,64.30], [5.20,-25.30,4.60], [1.34,14.56,13.66], [-0.00,-0.01,-0.02], [-17.98,8.50,2.19], [0.00,-0.01,-0.01]]), + (291, [[-327.60,-149.50,76.40], [26.30,-22.60,3.30], [1.34,14.54,13.64], [-0.01,-0.02,-0.02], [-15.60,-5.55,11.17], [0.00,-0.01,-0.01]]), + (292, [[-277.60,-101.40,42.90], [45.10,-4.20,0.00], [1.33,14.50,13.63], [-0.00,-0.02,-0.01], [-1.28,-13.56,14.57], [0.00,-0.01,-0.01]]), + (293, [[-231.00,-108.20,27.80], [42.40,14.10,0.00], [1.33,14.49,13.61], [-0.00,-0.01,-0.02], [9.84,-11.07,13.34], [0.00,-0.01,-0.01]]), + (294, [[-180.10,-109.90,40.70], [59.10,-19.40,39.60], [1.33,14.48,13.60], [-0.00,-0.01,-0.02], [-7.70,-11.37,14.41], [0.00,-0.01,-0.01]]), + (295, [[-174.70,-116.60,80.30], [-37.40,27.50,45.00], [1.33,14.48,13.58], [-0.00,-0.02,-0.02], [-12.89,15.10,1.39], [0.00,-0.01,-0.01]]), + (296, [[-300.70,-86.10,54.30], [-63.80,-23.10,55.90], [1.33,14.44,13.55], [-0.00,-0.03,-0.03], [-15.54,9.66,-7.67], [0.00,-0.02,-0.02]]), + (297, [[-289.00,-163.30,110.50], [-99.30,-43.30,98.20], [1.33,14.42,13.51], [-0.00,-0.03,-0.04], [-16.33,8.92,-6.77], [0.00,-0.02,-0.02]]), + (298, [[-323.00,-11.30,56.10], [39.10,49.20,-8.90], [1.34,14.37,13.48], [-0.01,-0.02,-0.02], [18.66,-0.68,6.41], [0.00,-0.01,-0.01]]), + (299, [[-277.50,6.40,49.70], [95.70,-13.00,0.00], [1.31,14.34,13.47], [-0.01,-0.02,-0.01], [-2.43,-13.25,14.39], [0.00,-0.01,-0.01]]), + (300, [[-191.40,-10.90,80.50], [62.80,-7.70,9.50], [1.31,14.33,13.44], [-0.00,-0.02,-0.02], [-2.20,-13.19,14.45], [0.00,-0.01,-0.01]]), + (301, [[-133.30,24.30,81.00], [42.20,67.00,0.00], [1.31,14.31,13.43], [-0.00,-0.02,-0.01], [18.18,3.68,6.51], [0.00,-0.01,-0.01]]), + (302, [[-125.40,67.10,93.50], [-20.50,21.20,-1.40], [1.31,14.30,13.40], [-0.00,-0.01,-0.01], [4.25,15.50,-11.28], [0.00,-0.01,-0.01]]), + (303, [[-181.30,58.00,64.50], [-62.10,-31.80,-29.80], [1.31,14.28,13.40], [-0.00,-0.02,-0.02], [10.08,15.61,-6.29], [0.00,-0.01,-0.01]]), + (304, [[-295.90,96.80,39.60], [-106.30,-114.70,-51.10], [1.31,14.24,13.36], [-0.00,-0.04,-0.03], [4.76,18.63,-3.64], [0.00,-0.02,-0.02]]), + (305, [[-170.50,62.70,-13.20], [-26.90,-123.60,24.00], [1.31,14.19,13.33], [-0.01,-0.04,-0.04], [-13.05,13.98,-3.83], [0.00,-0.02,-0.02]]), + (306, [[-274.30,42.90,28.40], [-12.60,-108.50,-11.40], [1.30,14.17,13.29], [-0.01,-0.04,-0.04], [-9.87,16.73,1.27], [0.00,-0.02,-0.02]]), + (307, [[-142.90,-22.50,18.30], [11.70,9.50,57.30], [1.30,14.12,13.25], [1.17,-1.58,1.19], [-8.50,1.10,17.40], [1.23,-1.65,1.27]]), + (308, [[-150.90,-36.10,84.20], [-5.30,-48.90,32.20], [3.19,11.59,15.20], [0.04,-0.08,0.03], [-18.85,4.45,0.74], [0.05,-0.07,0.04]]), + (309, [[-135.30,-105.30,94.80], [-3.20,-32.60,55.90], [1.30,14.07,13.22], [5.63,-11.05,0.16], [-19.00,-0.37,3.62], [5.94,-11.65,0.17]]), + (310, [[-138.40,-135.90,107.80], [4.80,-33.70,-0.70], [11.60,-5.52,14.45], [5.06,-12.37,-7.66], [-13.46,-9.01,10.56], [5.34,-13.05,-8.09]]), + (311, [[-150.80,-112.60,40.60], [1.40,115.30,8.10], [6.11,-5.43,-17.49], [-8.73,-1.10,-16.85], [-17.15,-5.91,-6.62], [-9.22,-1.17,-17.79]]), + (312, [[-176.80,19.30,-24.60], [67.20,241.30,-20.60], [-11.23,-9.02,-12.79], [-5.04,-2.23,0.97], [-15.85,-5.85,9.23], [-5.32,-2.36,1.00]]), + (313, [[-276.70,70.90,-69.10], [-51.90,-162.20,10.10], [-3.56,-10.26,-15.83], [2.84,-0.45,-1.11], [12.65,-14.44,0.32], [3.00,-0.48,-1.18]]), + (314, [[-221.20,2.30,-47.30], [-165.70,-117.10,-0.90], [-3.56,-10.24,-15.80], [0.01,0.02,0.03], [1.81,-18.01,6.26], [0.00,0.01,0.02]]), + (315, [[-283.70,-70.80,-59.10], [66.20,-75.00,17.60], [-3.55,-10.22,-15.76], [0.01,0.02,0.03], [15.04,7.81,-8.85], [0.00,0.01,0.02]]), + (316, [[-200.90,-32.00,-51.70], [94.90,36.10,50.70], [-3.55,-10.20,-15.74], [7.54,1.13,2.34], [-11.52,7.36,-13.32], [8.01,1.20,2.48]]), + (317, [[-114.90,21.00,-43.50], [88.80,141.00,123.30], [14.13,-7.58,-10.28], [10.12,6.89,4.80], [-4.72,9.27,-15.96], [10.75,7.32,5.08]]), + (318, [[-154.40,135.80,-62.60], [-78.30,-1.00,-2.30], [16.98,6.86,-5.05], [-4.73,11.66,5.50], [17.17,-5.33,-6.15], [-5.02,12.40,5.84]]), + (319, [[-274.80,136.50,7.90], [22.10,45.90,70.80], [3.58,18.49,2.00], [-5.93,5.11,3.12], [-10.85,8.85,12.76], [-6.30,5.46,3.32]]), + (320, [[-141.60,114.90,31.30], [60.30,66.50,26.50], [3.58,18.43,2.00], [-0.01,-0.03,-0.00], [6.50,11.07,13.86], [0.00,-0.02,0.00]]), + (321, [[-108.40,101.20,30.10], [11.30,-64.60,-17.80], [3.57,18.42,2.00], [5.73,-9.33,0.72], [0.02,15.31,11.02], [6.12,-9.95,0.76]]), + (322, [[-117.50,36.30,28.10], [-11.80,-88.50,4.40], [17.84,-4.74,3.78], [7.09,-9.12,-1.91], [-3.85,-1.13,18.41], [7.57,-9.72,-2.04]]), + (323, [[-123.00,-16.90,76.90], [-5.40,-40.50,20.40], [18.61,-0.28,-2.79], [-0.21,4.61,-0.38], [2.98,10.82,15.11], [-0.21,4.92,-0.40]]), + (324, [[-83.50,-94.80,124.40], [-5.30,-37.10,-69.10], [16.96,5.85,5.55], [-0.96,3.46,4.71], [3.12,-10.39,15.33], [-1.00,3.70,5.04]]), + (325, [[-114.60,-3.80,-22.00], [-48.40,-89.30,-74.40], [16.90,5.83,5.53], [0.13,-7.07,-4.33], [4.87,2.00,17.95], [0.15,-7.57,-4.63]]), + (326, [[-106.10,-89.80,24.00], [-40.70,-98.90,-72.10], [17.17,-6.96,-2.28], [0.23,-2.61,-5.35], [-2.51,-11.23,14.69], [0.26,-2.79,-5.73]]), + (327, [[-134.60,-44.80,-44.70], [-45.50,-59.20,-129.40], [17.42,-0.71,-6.58], [-4.55,4.11,-6.56], [1.78,-17.35,6.53], [-4.87,4.41,-7.04]]), + (328, [[-152.20,-122.40,-0.90], [-138.70,-24.00,-10.70], [6.30,2.05,-17.37], [-2.19,-5.54,0.63], [8.24,-16.66,-0.54], [-2.34,-5.95,0.67]]), + (329, [[-215.00,-66.50,-51.90], [-95.40,-77.80,7.50], [12.21,-12.81,-5.56], [4.44,-4.77,7.49], [5.60,-2.49,17.52], [4.78,-5.13,8.04]]), + (330, [[-281.50,-141.60,-97.10], [-33.10,-74.40,-0.80], [16.28,-8.80,-0.52], [2.14,2.15,2.68], [-0.19,-1.68,18.43], [2.32,2.30,2.88]]), + (331, [[-142.90,-169.80,-24.70], [57.10,22.50,62.40], [16.22,-8.78,-0.52], [-0.05,0.02,0.00], [11.32,13.95,-4.23], [-0.03,0.02,0.00]]), + (332, [[-114.90,-94.60,56.00], [-22.70,-27.90,103.30], [16.18,-8.75,-0.52], [-0.04,0.02,0.00], [8.74,15.58,4.42], [-0.03,0.01,0.00]]), + (333, [[-165.80,-210.20,55.70], [-82.80,8.90,-63.60], [16.14,-8.73,-0.52], [-0.04,0.02,0.00], [5.07,-11.32,13.52], [-0.03,0.01,0.00]]), + (334, [[-221.80,-171.30,-25.00], [-110.60,-77.10,-27.50], [16.10,-8.71,-0.52], [-7.05,1.07,-6.62], [4.94,0.82,17.61], [-7.61,1.16,-7.17]]), + (335, [[-212.40,-201.20,82.90], [136.90,5.40,26.70], [-1.57,-6.04,-17.16], [1.17,-0.16,1.14], [-4.47,16.34,-6.83], [1.28,-0.18,1.23]]), + (336, [[-187.10,-132.60,25.20], [-87.20,10.40,-111.30], [16.02,-8.66,-0.52], [9.16,4.06,10.76], [-0.64,-13.63,12.06], [9.93,4.39,11.65]]), + (337, [[-324.00,-192.70,-37.00], [-25.10,-36.30,21.20], [16.40,5.65,5.36], [0.10,4.80,1.97], [-1.16,17.46,4.81], [0.13,5.20,2.14]]), + (338, [[-280.20,-208.50,37.40], [-89.00,-10.60,119.10], [16.36,5.65,5.36], [-10.49,2.92,-7.65], [-1.38,16.69,-6.91], [-11.39,3.18,-8.31]]), + (339, [[-271.90,-187.90,119.40], [42.70,34.80,6.60], [-6.81,12.13,-11.55], [-5.42,1.49,-5.96], [-7.93,8.70,13.73], [-5.88,1.63,-6.48]]), + (340, [[-252.20,-147.10,107.10], [22.70,45.10,-4.00], [-4.50,11.45,-13.24], [2.55,1.22,0.64], [-6.75,14.49,8.41], [2.78,1.34,0.69]]), + (341, [[-216.60,-117.80,95.70], [40.30,-19.20,-0.50], [-1.03,15.03,-9.94], [9.63,-2.95,8.59], [-2.14,12.12,13.20], [10.48,-3.21,9.35]]), + (342, [[-210.30,-154.50,112.40], [-20.60,-33.90,26.20], [16.29,5.62,5.33], [9.65,-5.25,8.52], [-3.37,17.07,4.70], [10.51,-5.71,9.27]]), + (343, [[-241.10,-217.80,103.30], [-99.30,-50.40,-38.80], [16.26,5.60,5.33], [-2.89,1.23,-6.88], [14.59,6.76,8.10], [-3.14,1.34,-7.50]]), + (344, [[-262.00,-235.10,20.00], [83.30,-4.40,-126.20], [8.59,8.91,-13.03], [-0.53,0.21,-1.21], [16.26,-0.43,-7.64], [-0.57,0.23,-1.31]]), + (345, [[-341.30,-228.90,-31.50], [21.90,106.10,-95.20], [16.20,5.59,5.30], [3.58,-1.58,8.69], [8.06,-9.23,-13.09], [3.93,-1.72,9.48]]), + (346, [[-223.00,-253.50,-46.00], [3.40,60.90,-83.80], [16.15,5.57,5.28], [0.66,-1.98,-3.36], [7.60,-13.50,-8.93], [0.74,-2.16,-3.66]]), + (347, [[-309.60,-169.80,-81.10], [21.90,106.10,-95.20], [17.66,1.21,-2.13], [-7.72,-0.17,-9.71], [-0.02,-7.68,-16.09], [-8.44,-0.18,-10.64]]), + (348, [[-209.50,-219.10,-37.80], [53.10,-46.50,-77.10], [-1.88,5.45,-16.82], [-6.57,1.42,-4.92], [16.09,5.92,-4.73], [-7.20,1.56,-5.40]]), + (349, [[-173.60,-172.20,-85.40], [-26.90,37.00,-15.30], [-1.88,5.43,-16.79], [3.86,-5.85,4.16], [-17.03,-0.68,-4.94], [4.24,-6.42,4.55]]), + (350, [[-291.30,-84.30,-106.00], [97.00,135.70,42.80], [10.76,-13.65,-3.25], [6.72,-8.15,5.15], [-2.27,0.16,-17.54], [7.39,-8.96,5.63]]), + (351, [[-120.90,-148.90,-48.40], [39.70,69.50,-18.40], [12.13,-10.71,-6.95], [0.44,1.01,-1.23], [-9.07,-0.74,-15.07], [0.50,1.10,-1.36]]), + (352, [[-144.10,-35.10,-76.70], [-46.20,4.30,-3.90], [12.10,-10.68,-6.92], [-0.03,0.02,0.02], [10.79,-9.03,10.52], [-0.02,0.02,0.01]]), + (353, [[-190.90,-106.20,-108.70], [-85.30,10.90,-25.60], [12.07,-10.66,-6.92], [-0.03,0.02,0.01], [6.38,-11.33,11.75], [-0.02,0.01,0.01]]), + (354, [[-285.70,-73.50,-145.80], [-88.80,-66.70,-0.90], [12.05,-10.64,-6.89], [-0.03,0.03,0.02], [6.61,-3.69,15.76], [-0.02,0.02,0.01]]), + (355, [[-321.80,-178.80,-111.70], [-31.80,-89.20,89.10], [12.02,-10.61,-6.88], [-0.02,0.02,0.01], [12.07,6.81,10.58], [-0.02,0.01,0.01]]), + (356, [[-371.60,-176.40,-124.40], [19.20,94.50,-4.50], [12.00,-10.59,-6.87], [-1.15,5.43,-2.83], [-8.74,-6.69,-13.49], [-1.26,6.01,-3.14]]), + (357, [[-321.80,-83.50,-118.80], [-75.90,112.20,-24.80], [8.97,3.79,-14.39], [-7.87,9.63,-2.48], [-11.44,-8.95,-9.53], [-8.72,10.67,-2.75]]), + (358, [[-395.50,-163.20,-123.30], [-53.40,-89.20,1.10], [-6.47,10.77,-11.94], [1.54,4.94,6.19], [13.23,-1.02,-11.15], [1.72,5.48,6.85]]), + (359, [[-473.40,-148.90,-123.50], [-56.10,65.20,-46.90], [7.85,15.32,-1.62], [8.17,-9.27,2.34], [2.54,-0.37,-17.10], [9.07,-10.30,2.58]]), + (360, [[-429.70,-106.40,-120.50], [163.60,-61.70,-10.20], [11.90,-10.51,-6.81], [-2.78,-9.61,-6.54], [15.99,0.31,-6.50], [-3.09,-10.68,-7.28]]), + (361, [[-402.50,-38.30,-145.20], [-67.70,81.20,4.50], [0.25,-3.70,-16.83], [-6.38,6.43,-3.19], [-10.37,-13.61,2.01], [-7.10,7.14,-3.56]]), + (362, [[-461.90,-56.90,-150.00], [-80.10,-50.60,3.70], [-4.07,3.87,-16.26], [-5.47,3.23,2.15], [7.90,-14.29,-5.42], [-6.09,3.59,2.38]]), + (363, [[-522.70,-134.30,-113.60], [-48.30,6.50,89.20], [-13.08,1.57,-11.01], [-0.45,2.83,1.70], [-0.50,-16.92,-2.84], [-0.50,3.16,1.88]]), + (364, [[-492.60,-30.90,-110.50], [-4.70,62.60,70.10], [-4.57,10.62,-12.64], [3.44,3.64,-0.64], [-16.20,-5.46,0.93], [3.83,4.07,-0.73]]), + (365, [[-562.40,-79.20,-83.10], [-57.30,18.40,43.90], [-4.56,10.60,-12.61], [0.01,-0.02,0.03], [-8.36,-12.71,-7.79], [0.01,-0.02,0.02]]), + (366, [[-607.00,13.50,-78.80], [37.30,101.70,-7.80], [-4.55,10.57,-12.58], [0.01,-0.03,0.03], [-7.84,13.29,7.24], [0.01,-0.02,0.02]]), + (367, [[-511.10,40.20,-112.70], [103.50,-93.30,-48.20], [-4.54,10.54,-12.55], [0.11,-3.57,-1.75], [7.34,13.94,6.40], [0.12,-3.99,-1.97]]), + (368, [[-523.20,-9.50,-122.50], [-147.00,5.30,22.40], [-4.34,3.49,-16.04], [-0.01,-3.23,-1.48], [-3.07,-16.44,-2.99], [-0.01,-3.61,-1.67]]), + (369, [[-588.70,-24.10,-95.80], [34.00,-42.60,1.70], [-4.54,2.91,-16.07], [0.65,0.95,0.15], [8.97,14.26,-1.90], [0.72,1.07,0.16]]), + (370, [[-532.30,-72.30,-120.30], [111.50,-25.50,-41.10], [-2.90,5.60,-15.71], [1.57,2.29,0.53], [6.54,15.08,4.03], [1.76,2.57,0.59]]), + (371, [[-460.90,-12.40,-123.40], [176.70,55.60,45.00], [-0.94,8.08,-14.80], [0.80,1.00,0.37], [-8.09,12.91,7.28], [0.90,1.13,0.40]]), + (372, [[-427.40,65.30,-95.70], [-43.60,32.50,-16.00], [-1.12,7.82,-14.89], [0.27,0.90,0.56], [-13.67,-5.66,-8.07], [0.30,1.02,0.62]]), + (373, [[-471.40,54.70,-118.00], [-79.10,-33.90,8.90], [-0.57,9.50,-13.88], [-0.62,1.29,1.01], [8.69,-10.93,-9.39], [-0.70,1.46,1.13]]), + (374, [[-580.40,127.50,-99.50], [11.00,31.00,79.80], [-4.48,10.41,-12.37], [1.47,0.43,0.17], [-15.12,-5.54,-4.71], [1.66,0.50,0.18]]), + (375, [[-556.80,144.60,-36.30], [82.20,-21.40,6.30], [0.24,10.67,-12.91], [0.42,0.00,-0.03], [-0.83,13.33,10.11], [0.47,0.02,-0.04]]), + (376, [[-519.60,126.70,-112.70], [103.30,-10.80,-25.10], [-4.46,10.37,-12.34], [-2.19,-0.16,0.28], [1.29,13.22,10.15], [-2.48,-0.17,0.31]]), + (377, [[-425.90,145.30,-95.20], [0.10,5.40,86.10], [-4.45,10.34,-12.31], [0.01,-0.03,0.03], [-11.10,-5.16,-11.33], [0.01,-0.02,0.02]]), + (378, [[-512.40,124.30,-46.70], [-26.40,-6.80,-45.50], [-4.44,10.31,-12.28], [0.01,-0.02,0.03], [4.74,-3.75,-15.50], [0.01,-0.01,0.02]]), + (379, [[-476.90,99.10,-97.70], [61.40,-4.20,-24.70], [-4.43,10.30,-12.24], [0.01,-0.02,0.03], [4.42,13.01,9.33], [0.01,-0.01,0.02]]), + (380, [[-371.40,119.00,-116.30], [47.50,67.00,21.40], [-4.42,10.27,-12.22], [3.72,1.74,2.21], [-10.80,7.73,9.88], [4.22,1.99,2.49]]), + (381, [[-341.60,157.90,-39.40], [-130.40,-15.20,-17.30], [4.12,14.31,-7.18], [0.70,2.51,4.56], [7.38,-7.06,-12.99], [0.79,2.87,5.16]]), + (382, [[-401.40,155.50,-49.20], [-44.00,17.80,118.30], [-0.25,16.40,-1.90], [-2.23,0.58,5.83], [-15.69,-0.81,-5.06], [-2.54,0.67,6.62]]), + (383, [[-326.70,144.80,-18.40], [68.80,-24.00,-65.20], [-0.24,15.08,6.61], [0.05,-0.90,-4.01], [2.61,-2.46,16.07], [0.06,-1.01,-4.56]]), + (384, [[-264.80,135.60,-54.60], [15.70,44.40,54.40], [-0.14,14.29,-8.13], [3.05,-0.30,-4.66], [-15.24,3.30,5.20], [3.48,-0.33,-5.31]]), + (385, [[-311.00,161.60,22.30], [30.30,-19.60,79.00], [7.38,14.50,-2.12], [2.95,0.10,1.93], [-13.62,8.04,4.34], [3.37,0.13,2.19]]), + (386, [[-216.70,146.00,34.60], [48.10,-13.40,2.20], [6.52,14.51,-3.81], [-0.36,-0.13,-1.13], [2.52,3.35,15.82], [-0.41,-0.13,-1.29]]), + (387, [[-127.20,99.80,74.20], [48.10,-23.70,1.30], [6.59,14.19,-4.66], [3.97,-5.53,2.44], [1.29,4.55,15.62], [4.55,-6.30,2.78]]), + (388, [[-31.50,35.80,58.00], [9.60,-94.20,34.00], [16.09,1.23,2.18], [-4.96,-6.31,9.74], [-2.35,4.18,15.56], [-5.67,-7.21,11.15]]), + (389, [[-93.20,47.90,78.70], [-40.40,4.30,-4.70], [0.43,-2.16,16.10], [-13.30,3.09,-2.34], [3.91,15.60,2.37], [-15.22,3.54,-2.68]]), + (390, [[-83.60,41.80,21.70], [-25.40,95.30,-36.30], [-14.30,7.55,-1.39], [1.19,7.30,-7.96], [-1.27,14.38,7.41], [1.37,8.37,-9.11]]), + (391, [[-94.90,120.00,-16.70], [54.70,18.00,-1.30], [7.93,14.11,0.46], [13.15,-4.37,2.41], [11.79,3.11,10.66], [15.08,-5.02,2.76]]), + (392, [[-6.00,8.70,44.40], [-86.70,-73.70,-3.60], [9.84,-11.82,4.85], [1.39,-7.11,-5.37], [-3.52,3.38,15.38], [1.61,-8.16,-6.18]]), + (393, [[-69.50,67.10,-5.30], [-28.20,-6.40,-92.20], [11.21,-7.89,-8.41], [-1.75,10.80,-4.15], [-8.51,-13.50,-1.99], [-2.01,12.43,-4.77]]), + (394, [[-80.80,-39.40,-67.40], [124.60,-54.30,39.80], [4.96,15.06,-2.40], [-6.39,8.82,4.76], [-5.15,4.31,14.56], [-7.36,10.17,5.48]]), + (395, [[-47.50,28.90,-23.70], [59.80,-55.90,69.30], [-3.12,15.47,2.61], [6.16,-4.72,4.76], [-15.89,0.77,1.75], [7.12,-5.43,5.49]]), + (396, [[-37.50,-11.90,-20.60], [-26.30,-38.40,68.20], [11.68,7.11,8.26], [7.91,-7.09,-3.25], [-9.65,12.38,3.01], [9.13,-8.18,-3.75]]), + (397, [[-36.80,-10.90,27.50], [-1.60,7.40,38.00], [15.41,-0.75,-4.09], [1.34,-2.85,-4.47], [0.16,14.03,-7.61], [1.56,-3.28,-5.16]]), + (398, [[-42.70,-8.00,62.70], [-6.50,1.70,7.10], [15.40,-0.75,-4.08], [-0.01,0.00,0.01], [8.70,6.15,-11.87], [-0.01,0.00,0.00]]), + (399, [[-63.30,1.20,96.30], [-26.00,27.20,0.00], [15.39,-0.74,-4.07], [-0.01,0.00,0.00], [4.77,-10.89,-10.61], [-0.01,0.00,0.00]]), + (400, [[-78.00,27.60,100.90], [37.30,13.80,0.20], [15.37,-0.74,-4.07], [-8.40,-4.20,4.36], [11.85,8.81,-5.96], [-9.71,-4.86,5.05]]), + (401, [[-31.50,35.20,105.20], [15.60,-22.20,3.00], [-7.10,-12.01,7.62], [-11.72,-1.75,3.45], [-1.14,-10.45,-11.93], [-13.57,-2.02,3.99]]), + (402, [[-34.50,-1.20,104.80], [-10.90,-26.50,-24.40], [-13.35,-6.68,5.45], [4.66,-0.01,-4.41], [-9.62,6.68,-10.73], [5.39,-0.02,-5.10]]), + (403, [[-5.70,4.10,69.80], [22.60,26.50,-0.50], [7.22,-13.73,-3.36], [11.49,4.26,-3.48], [-6.46,-2.27,-14.31], [13.31,4.94,-4.03]]), + (404, [[-8.00,34.90,79.80], [-9.00,30.20,23.80], [15.31,-0.74,-4.06], [3.58,5.76,-0.31], [-1.18,3.33,-15.46], [4.16,6.67,-0.35]]), + (405, [[-24.40,59.80,98.70], [-18.30,17.30,14.10], [15.30,-0.74,-4.05], [-1.58,4.17,-0.52], [5.62,-2.37,-14.63], [-1.83,4.84,-0.61]]), + (406, [[-52.80,83.20,117.00], [-19.40,32.60,10.00], [11.40,9.59,-5.36], [-1.64,-2.45,7.05], [-7.37,1.06,-13.96], [-1.90,-2.84,8.18]]), + (407, [[-33.10,94.80,102.90], [22.10,-6.20,-30.40], [11.18,-4.03,10.43], [0.95,-7.69,3.13], [-5.60,-14.79,0.42], [1.10,-8.91,3.63]]), + (408, [[-19.60,67.80,71.00], [-12.00,23.60,-71.10], [14.18,-5.72,-3.98], [-0.41,5.00,-8.19], [-6.55,-14.01,-3.24], [-0.47,5.81,-9.51]]), + (409, [[-69.80,126.80,91.50], [-61.80,12.70,9.10], [7.64,13.03,-4.51], [1.21,0.41,0.04], [2.52,-4.38,-14.93], [1.42,0.48,0.04]]), + (410, [[-121.30,169.50,92.00], [-11.10,37.00,0.00], [15.20,-0.73,-4.03], [1.04,-10.30,0.16], [-2.39,-6.01,-14.35], [1.22,-11.98,0.19]]), + (411, [[-114.50,225.50,92.00], [69.10,44.90,0.00], [10.70,-10.76,-4.10], [-8.87,-5.78,-0.28], [0.37,5.13,-14.86], [-10.32,-6.73,-0.33]]), + (412, [[-65.20,213.40,92.00], [33.20,-32.20,0.00], [-4.64,-14.27,-4.64], [-9.41,1.68,-1.87], [7.96,-1.26,-13.48], [-10.96,1.95,-2.18]]), + (413, [[-41.70,168.20,81.00], [8.20,-39.50,-1.80], [-11.15,-7.27,-8.30], [-1.36,1.33,-1.36], [8.85,-2.92,-12.62], [-1.58,1.55,-1.59]]), + (414, [[-32.20,130.30,62.30], [24.30,-54.00,-19.60], [-8.60,-10.28,-8.12], [1.34,-1.11,-0.38], [6.96,-1.16,-14.00], [1.56,-1.30,-0.45]]), + (415, [[13.30,68.90,25.90], [74.40,51.70,-56.50], [-9.28,-7.79,-9.90], [6.57,-0.10,0.78], [-12.40,9.38,1.71], [7.67,-0.13,0.90]]), + (416, [[-52.20,119.90,-39.10], [-64.10,-49.60,36.30], [9.14,-11.37,-5.48], [7.36,2.12,-1.37], [9.51,1.17,12.30], [8.61,2.47,-1.62]]), + (417, [[0.60,40.90,-6.30], [-35.10,-73.30,-52.20], [8.63,-3.53,-12.44], [-8.63,0.31,2.35], [5.24,-13.94,4.44], [-10.11,0.35,2.75]]), + (418, [[-93.60,68.70,-44.60], [-75.00,91.80,-77.60], [-11.00,-10.92,0.23], [-8.60,-3.22,5.56], [-5.10,5.26,13.66], [-10.08,-3.79,6.52]]), + (419, [[-10.30,30.20,-41.90], [25.00,-66.20,-30.80], [-10.97,-10.89,0.23], [8.19,6.85,5.89], [-2.70,-0.59,-15.21], [9.62,8.03,6.92]]), + (420, [[-50.40,-34.50,-84.60], [-46.00,102.90,-35.50], [6.96,4.09,13.14], [6.94,5.55,5.15], [13.88,0.32,-6.72], [8.16,6.52,6.07]]), + (421, [[-41.40,32.40,-58.90], [-91.30,85.20,-56.10], [6.80,3.44,13.37], [-2.72,1.28,0.04], [14.99,1.22,-3.30], [-3.20,1.52,0.06]]), + (422, [[-114.30,-19.20,-124.30], [-81.00,8.40,9.10], [-0.47,7.88,13.17], [0.59,-0.71,0.09], [-2.23,13.25,-7.43], [0.71,-0.83,0.13]]), + (423, [[-129.50,59.30,-86.40], [-83.60,13.00,50.80], [6.56,2.89,13.54], [2.54,-3.98,0.65], [-1.22,15.08,-2.38], [3.00,-4.70,0.79]]), + (424, [[-193.40,-50.20,-121.30], [-158.00,10.70,45.10], [3.30,-1.08,14.87], [-2.63,2.52,-0.11], [0.46,15.22,1.05], [-3.10,2.98,-0.11]]), + (425, [[-260.70,9.90,-99.50], [-72.10,-15.50,-24.10], [0.44,6.55,13.74], [-1.24,1.76,-0.01], [4.85,13.83,-4.13], [-1.46,2.09,0.01]]), + (426, [[-339.40,-58.30,-138.90], [-98.20,0.40,-23.00], [0.64,2.26,15.01], [-1.75,1.21,-0.89], [4.50,14.44,-1.28], [-2.08,1.44,-1.04]]), + (427, [[-392.70,8.10,-127.60], [58.00,12.90,-44.30], [-3.35,8.68,11.96], [-0.09,0.88,-0.16], [0.81,-8.79,12.31], [-0.11,1.05,-0.17]]), + (428, [[-318.60,-12.70,-117.30], [82.30,72.00,33.30], [-0.09,5.02,14.26], [0.82,-1.67,0.99], [12.74,-5.73,5.79], [0.97,-1.97,1.19]]), + (429, [[-400.20,75.30,-134.70], [185.90,159.10,45.20], [-3.30,6.20,13.33], [-0.07,1.98,-1.16], [10.32,-8.05,7.46], [-0.09,2.36,-1.36]]), + (430, [[-297.10,32.20,-114.40], [170.70,159.00,13.00], [-0.44,9.53,11.61], [-1.28,1.68,-1.81], [12.34,-3.86,7.64], [-1.53,2.01,-2.14]]), + (431, [[-183.70,12.90,-89.70], [13.00,150.40,-5.30], [-6.15,10.11,9.18], [-3.94,-4.23,-0.25], [10.28,8.60,6.67], [-4.71,-5.05,-0.28]]), + (432, [[-336.80,87.50,-103.70], [-17.50,86.10,36.10], [-9.24,-1.63,11.58], [4.82,0.55,1.73], [10.27,2.82,10.43], [5.77,0.68,2.09]]), + (433, [[-251.90,87.50,-90.80], [85.40,-108.30,36.10], [1.48,6.38,13.35], [2.95,-0.08,1.37], [-12.10,-7.18,4.81], [3.53,-0.09,1.66]]), + (434, [[-181.50,101.00,-68.40], [88.50,-70.20,49.50], [-1.14,-0.38,14.79], [-1.06,-4.88,0.18], [-4.44,-14.11,1.21], [-1.27,-5.85,0.23]]), + (435, [[-170.30,54.60,-111.80], [73.70,-24.10,-48.10], [-1.11,-5.01,13.90], [-2.34,5.28,-2.64], [-11.88,-8.82,-0.69], [-2.81,6.35,-3.16]]), + (436, [[-123.20,76.70,-98.70], [73.80,14.70,83.70], [-6.08,9.98,9.07], [-4.11,1.60,-5.47], [-3.58,-9.93,10.36], [-4.95,1.91,-6.57]]), + (437, [[-53.70,112.30,-68.10], [-112.20,97.90,113.50], [-10.47,-10.40,0.23], [-1.90,-8.86,-3.85], [5.83,-5.70,12.30], [-2.30,-10.67,-4.63]]), + (438, [[-42.10,136.80,15.40], [139.60,-1.80,110.30], [-10.45,-10.37,0.22], [2.10,-1.42,-0.53], [0.19,-6.57,-13.17], [2.52,-1.73,-0.64]]), + (439, [[8.20,95.10,34.30], [-24.80,-1.90,92.70], [-6.19,-13.30,-0.86], [0.32,0.74,3.30], [12.59,-6.22,4.32], [0.37,0.88,3.99]]), + (440, [[16.90,122.10,92.60], [26.30,5.60,42.10], [-8.88,-9.49,6.81], [-1.66,0.65,-1.50], [8.76,-11.07,-4.01], [-2.01,0.77,-1.81]]), + (441, [[25.30,149.50,92.30], [-11.10,35.90,0.00], [-10.40,-10.33,0.22], [-0.75,-0.41,-3.28], [2.21,-6.43,12.99], [-0.91,-0.50,-3.96]]), + (442, [[-9.30,181.40,93.40], [-17.10,39.40,0.00], [-10.39,-10.31,0.22], [0.35,9.47,-2.05], [2.32,-4.80,13.63], [0.42,11.45,-2.48]]), + (443, [[-3.30,218.30,94.20], [39.10,16.20,0.00], [-9.65,10.16,-4.20], [8.92,8.72,-0.98], [-6.26,1.96,13.08], [10.79,10.55,-1.19]]), + (444, [[33.30,192.20,83.10], [42.50,-69.90,-17.10], [12.42,7.57,-1.31], [12.06,-2.03,2.94], [2.78,-2.09,14.19], [14.60,-2.45,3.56]]), + (445, [[29.00,113.80,73.30], [13.20,-7.90,-43.20], [13.13,5.61,2.93], [0.73,-5.94,-0.50], [4.80,-13.22,3.84], [0.89,-7.19,-0.61]]), + (446, [[53.50,137.40,54.40], [22.90,17.80,6.30], [14.05,-3.81,-0.14], [0.39,-1.17,-2.28], [7.30,8.20,-9.56], [0.48,-1.41,-2.77]]), + (447, [[57.60,178.10,62.90], [-9.40,32.20,-3.10], [14.04,2.98,-2.35], [-0.01,2.18,-0.71], [-1.74,-2.76,-14.18], [-0.01,2.65,-0.87]]), + (448, [[40.10,195.20,59.60], [-3.40,25.80,-0.90], [14.03,2.98,-2.35], [-0.01,-0.00,0.00], [-2.38,0.39,-14.33], [-0.01,0.00,0.00]]), + (449, [[57.30,231.00,78.90], [-15.50,11.50,19.40], [14.02,2.98,-2.35], [-0.01,-0.00,0.00], [1.64,5.09,-13.50], [-0.01,0.00,0.00]]), + (450, [[34.30,245.80,93.80], [-46.90,3.20,0.00], [14.00,2.98,-2.34], [-0.01,-0.00,0.00], [13.58,-3.28,-3.92], [-0.01,0.00,0.00]]), + (451, [[5.80,255.40,92.60], [2.30,2.40,34.80], [13.99,2.98,-2.34], [-4.14,-6.59,-1.04], [-3.20,14.00,-1.97], [-5.03,-8.01,-1.27]]), + (452, [[37.80,263.40,105.50], [25.30,1.40,0.00], [3.92,-13.05,-4.88], [-9.58,-6.24,-0.76], [2.92,5.06,-13.25], [-11.64,-7.58,-0.92]]), + (453, [[72.90,262.00,95.30], [27.10,-36.00,-29.30], [-8.26,-11.16,-4.04], [-3.75,0.11,0.48], [-0.60,2.85,-14.17], [-4.56,0.13,0.57]]), + (454, [[74.30,240.00,41.90], [65.30,-11.40,-10.10], [0.07,-13.89,-3.97], [7.15,-0.12,0.45], [1.53,3.34,-13.97], [8.71,-0.16,0.54]]), + (455, [[104.20,247.50,91.20], [23.80,44.00,5.50], [8.34,-11.39,-3.00], [2.79,12.36,2.88], [-4.37,-3.22,-13.36], [3.41,15.07,3.51]]), + (456, [[105.20,286.30,78.80], [-59.10,14.70,15.40], [7.77,11.94,2.14], [-4.20,11.14,0.08], [1.32,2.98,-14.03], [-5.12,13.58,0.10]]), + (457, [[79.00,257.00,53.90], [-35.60,-5.00,-14.30], [-1.64,13.96,-3.05], [-5.03,0.93,-0.98], [4.80,-2.31,-13.37], [-6.14,1.14,-1.19]]), + (458, [[20.00,252.70,43.90], [-73.70,-16.00,-8.60], [-3.37,13.95,0.50], [-4.01,-3.06,-0.71], [1.21,0.81,-14.29], [-4.90,-3.72,-0.87]]), + (459, [[-18.80,195.30,54.90], [-24.50,-54.20,-37.40], [-11.67,5.99,-5.79], [-3.78,-3.64,-2.86], [6.77,2.24,-12.45], [-4.63,-4.44,-3.50]]), + (460, [[-85.50,167.30,15.40], [-18.50,-23.90,-52.20], [-11.65,5.98,-5.77], [5.22,-1.93,-3.52], [5.56,5.86,-11.81], [6.38,-2.36,-4.33]]), + (461, [[-9.90,178.40,10.90], [70.50,-60.80,38.30], [0.74,1.40,-14.19], [3.58,-3.04,-3.48], [4.04,13.68,-0.74], [4.38,-3.72,-4.28]]), + (462, [[40.80,131.00,22.30], [93.00,82.10,-75.60], [-3.57,-1.06,-13.75], [-0.17,-2.60,0.37], [-5.60,13.08,-0.88], [-0.21,-3.20,0.44]]), + (463, [[15.50,223.00,15.30], [66.30,73.50,-18.10], [1.15,-4.77,-13.34], [5.85,-2.68,3.02], [-10.81,8.34,-3.93], [7.19,-3.30,3.69]]), + (464, [[84.50,187.60,6.70], [63.20,-22.90,74.10], [9.72,-7.39,-7.21], [1.95,3.39,0.57], [8.70,11.18,-0.61], [2.40,4.17,0.68]]), + (465, [[81.80,195.00,99.00], [85.20,-17.50,-8.30], [4.96,3.89,-12.66], [-5.95,3.42,-2.24], [8.04,10.82,4.29], [-7.33,4.21,-2.77]]), + (466, [[144.30,215.80,88.40], [56.60,35.60,-14.80], [-3.43,2.97,-13.36], [-6.00,-0.83,0.66], [-4.99,12.62,3.89], [-7.40,-1.02,0.80]]), + (467, [[178.40,287.40,86.20], [6.50,74.90,-2.80], [-8.76,1.95,-10.85], [-2.09,-5.60,3.23], [-10.59,2.84,8.83], [-2.58,-6.92,3.98]]), + (468, [[160.50,350.90,83.50], [-55.40,54.50,2.60], [-8.76,-9.20,-6.04], [4.12,-6.89,3.11], [-3.63,-4.88,12.68], [5.08,-8.53,3.83]]), + (469, [[79.50,372.50,92.00], [-94.70,-10.00,12.80], [2.10,-13.31,-3.93], [8.18,5.30,-0.77], [3.37,-3.46,13.17], [10.12,6.55,-0.96]]), + (470, [[56.20,296.40,44.30], [5.10,-77.10,-40.60], [10.08,4.95,-8.35], [-0.89,8.18,-2.63], [9.68,-4.29,9.15], [-1.10,10.13,-3.27]]), + (471, [[86.50,241.90,24.50], [53.00,-52.30,0.20], [3.03,8.68,-10.52], [-3.05,-2.57,-2.05], [4.54,10.28,8.30], [-3.77,-3.18,-2.56]]), + (472, [[152.10,205.80,56.00], [63.60,-8.30,10.00], [3.75,-2.52,-13.19], [-0.12,-2.70,-1.03], [3.99,13.25,-1.69], [-0.15,-3.35,-1.29]]), + (473, [[198.40,215.10,56.00], [38.20,22.50,-1.40], [3.11,-0.98,-13.53], [-0.74,1.84,-0.19], [-4.66,12.88,-2.50], [-0.92,2.29,-0.25]]), + (474, [[231.60,243.60,55.70], [23.70,41.90,-1.20], [2.03,1.74,-13.65], [-0.06,0.95,0.02], [-10.43,9.15,-0.98], [-0.08,1.18,0.02]]), + (475, [[254.20,308.60,53.70], [-36.30,58.90,0.00], [3.59,0.22,-13.41], [1.44,-1.14,0.41], [-10.53,-8.47,-3.17], [1.80,-1.42,0.49]]), + (476, [[201.60,339.10,45.30], [-53.50,14.40,-12.40], [5.39,-0.96,-12.74], [1.75,-3.67,9.37], [-1.05,-13.82,0.09], [2.19,-4.57,11.67]]), + (477, [[225.60,364.90,17.70], [84.00,-17.10,-36.30], [7.68,-8.22,8.07], [-1.74,-1.93,11.58], [0.09,-11.24,-8.08], [-2.17,-2.41,14.45]]), + (478, [[262.20,310.80,24.60], [19.90,-60.50,3.10], [0.53,-4.56,13.03], [-3.49,2.51,2.39], [-10.55,-8.90,-0.68], [-4.35,3.12,3.00]]), + (479, [[266.70,240.60,17.50], [-54.80,-92.30,1.00], [-0.35,-2.40,13.58], [-0.74,1.97,0.30], [-12.86,4.89,0.94], [-0.93,2.46,0.39]]), + (480, [[191.50,210.20,17.50], [-54.20,-18.80,19.40], [-1.21,0.07,13.70], [0.91,2.69,-0.23], [-9.15,10.19,1.31], [1.14,3.36,-0.27]]), + (481, [[126.50,239.40,20.10], [-85.50,-4.10,-17.80], [1.56,3.82,13.10], [1.41,1.92,-0.33], [4.42,12.70,-2.76], [1.77,2.40,-0.39]]), + (482, [[27.70,256.90,-12.00], [25.60,34.70,43.20], [1.53,3.79,13.06], [-0.00,-0.01,-0.03], [9.79,2.46,9.24], [0.00,-0.01,-0.02]]), + (483, [[83.20,288.30,-1.00], [33.20,-4.80,-3.70], [1.53,3.78,13.04], [-0.00,-0.01,-0.03], [-1.89,-12.93,3.99], [0.00,-0.01,-0.02]]), + (484, [[213.40,266.00,3.10], [68.30,112.60,23.20], [1.54,3.79,12.99], [-0.00,-0.01,-0.03], [13.46,-1.13,1.71], [0.00,-0.01,-0.02]]), + (485, [[188.20,299.90,26.40], [-48.40,-18.80,4.40], [1.54,3.76,12.97], [-0.00,-0.01,-0.02], [-3.42,12.78,-3.08], [0.00,-0.00,-0.01]]), + (486, [[130.20,290.80,30.50], [-44.60,71.50,28.90], [1.54,3.76,12.95], [-0.01,-0.01,-0.02], [5.93,12.16,-1.02], [0.00,-0.00,-0.01]]), + (487, [[136.70,339.40,47.80], [-100.80,75.50,26.60], [1.53,3.75,12.93], [-0.01,-0.01,-0.03], [3.93,12.60,-3.07], [0.00,-0.01,-0.02]]), + (488, [[47.80,248.50,21.60], [-98.10,56.50,2.30], [1.53,3.74,12.88], [-0.00,-0.01,-0.04], [5.65,11.60,-3.99], [0.00,-0.01,-0.02]]), + (489, [[59.30,327.60,28.10], [34.80,103.20,-11.30], [1.52,3.73,12.85], [-0.00,-0.01,-0.03], [13.35,-1.71,-0.52], [0.00,-0.01,-0.02]]), + (490, [[158.50,381.30,13.00], [145.50,-5.80,-42.40], [1.52,3.72,12.81], [-0.01,-0.01,-0.04], [-1.62,-12.62,4.27], [0.00,-0.01,-0.03]]), + (491, [[240.70,304.70,-6.30], [49.30,-67.70,-27.10], [1.50,3.70,12.77], [-0.01,-0.01,-0.03], [-12.00,-3.05,5.07], [0.00,-0.01,-0.02]]), + (492, [[240.40,234.90,-17.20], [-74.10,-88.50,16.10], [1.51,3.71,12.74], [-0.00,-0.01,-0.03], [-8.90,9.83,-1.49], [0.00,-0.01,-0.02]]), + (493, [[173.00,289.90,-12.50], [56.50,158.10,0.10], [1.51,3.69,12.71], [-0.00,-0.01,-0.04], [13.31,-0.52,-0.18], [0.00,-0.01,-0.02]]), + (494, [[109.50,348.10,-9.70], [-74.10,-88.50,16.10], [1.51,3.69,12.67], [-0.01,-0.01,-0.02], [-8.85,9.78,-1.48], [0.00,-0.00,-0.01]]), + (495, [[88.40,320.90,-6.10], [-71.10,-68.40,21.40], [1.50,3.67,12.66], [-0.01,-0.01,-0.01], [-8.75,9.82,-1.75], [0.00,-0.00,-0.01]]), + (496, [[61.80,280.20,-37.60], [69.10,-114.80,-49.00], [1.50,3.67,12.64], [-0.00,-0.01,-0.03], [-12.10,-1.34,5.24], [0.00,-0.00,-0.02]]), + (497, [[132.90,264.70,-28.90], [-44.70,-165.90,-57.30], [1.48,3.66,12.61], [-0.00,-0.01,-0.04], [-8.48,9.70,2.90], [0.00,-0.01,-0.02]]), + (498, [[147.20,179.70,61.30], [91.20,-36.60,30.40], [1.49,3.66,12.56], [-0.01,-0.01,-0.04], [-2.24,-12.03,4.87], [0.00,-0.01,-0.02]]), + (499, [[238.20,177.20,65.00], [18.30,-82.80,-18.10], [1.47,3.65,12.53], [-6.46,-1.97,-8.08], [-12.42,2.57,3.39], [-8.32,-2.53,-10.38]]), + (500, [[197.80,161.40,50.30], [67.60,35.60,-126.70], [-12.26,-0.53,-4.63], [0.94,-2.52,-10.53], [-2.37,12.18,4.22], [1.21,-3.24,-13.56]]), + (501, [[254.20,183.80,49.30], [-11.80,23.50,62.10], [4.62,-2.23,-12.04], [10.29,-1.14,3.54], [0.07,-2.27,-12.88], [13.26,-1.47,4.56]]), + (502, [[277.70,254.80,52.00], [-1.10,48.50,-21.40], [12.21,-3.24,3.31], [0.61,0.19,-0.28], [1.81,-9.01,-9.27], [0.80,0.24,-0.38]]), + (503, [[291.40,209.50,13.10], [-39.30,-47.20,-6.60], [6.85,-1.93,-10.90], [-3.43,0.14,-6.40], [9.23,-6.36,6.65], [-4.42,0.18,-8.27]]), + (504, [[227.20,207.90,6.30], [-93.70,-69.70,-8.90], [4.07,-2.87,-12.01], [0.12,0.05,0.07], [7.43,-9.54,4.76], [0.16,0.06,0.08]]), + (505, [[186.40,164.40,16.90], [-71.70,-61.20,-10.00], [6.83,-1.92,-10.86], [1.27,0.44,0.54], [8.91,-7.14,6.16], [1.65,0.57,0.68]]), + (506, [[118.40,159.70,1.30], [-74.40,26.40,-38.50], [6.81,-1.92,-10.84], [-0.02,0.00,0.03], [-2.76,-12.65,0.27], [-0.01,0.00,0.02]]), + (507, [[42.70,245.00,-45.30], [77.70,116.50,19.30], [6.79,-1.92,-10.80], [-0.03,0.01,0.04], [-8.26,7.43,-6.56], [-0.02,0.00,0.03]]), + (508, [[159.90,180.50,-31.40], [106.20,76.60,20.20], [6.76,-1.90,-10.75], [-0.03,0.01,0.04], [-3.78,11.20,-5.02], [-0.02,0.00,0.03]]), + (509, [[134.10,292.30,-47.10], [34.50,97.60,13.80], [6.73,-1.90,-10.73], [-0.02,0.01,0.03], [-10.09,3.53,-7.05], [-0.01,0.00,0.02]]), + (510, [[193.30,275.10,-46.30], [23.80,-61.70,26.10], [6.72,-1.89,-10.69], [-3.56,1.74,-0.59], [9.96,6.08,5.19], [-4.64,2.27,-0.79]]), + (511, [[190.90,187.00,-52.20], [66.50,-39.30,3.60], [-2.38,2.55,-12.25], [-3.82,1.31,-0.79], [2.74,12.42,0.81], [-5.00,1.72,-1.05]]), + (512, [[254.20,247.30,-47.60], [-23.50,92.50,19.80], [-1.93,0.97,-12.52], [0.99,-1.69,-0.13], [-11.80,-4.51,1.36], [1.29,-2.21,-0.20]]), + (513, [[228.40,321.30,-41.20], [52.70,188.20,-7.70], [-0.13,-1.39,-12.60], [3.62,-1.19,0.81], [-12.42,2.55,-0.21], [4.76,-1.57,1.05]]), + (514, [[176.60,339.50,-38.20], [-78.70,16.00,21.50], [6.66,-1.86,-10.59], [2.47,-0.17,0.74], [7.34,-10.12,-1.95], [3.25,-0.23,0.96]]), + (515, [[119.00,367.30,-29.70], [-127.00,18.70,4.70], [6.64,-1.87,-10.58], [-0.02,0.00,0.03], [5.68,-11.26,0.62], [-0.01,0.00,0.02]]), + (516, [[91.40,252.30,-63.20], [23.10,-112.20,118.60], [6.62,-1.87,-10.53], [-0.03,0.01,0.04], [7.75,9.89,0.38], [-0.02,0.00,0.03]]), + (517, [[175.10,162.40,-53.90], [-54.80,-66.80,32.70], [6.59,-1.86,-10.49], [-0.03,0.01,0.04], [11.97,0.65,3.64], [-0.02,0.00,0.03]]), + (518, [[70.80,203.50,-65.80], [-102.40,-41.90,-13.50], [6.57,-1.85,-10.45], [-0.02,0.01,0.03], [7.44,-8.87,4.67], [-0.01,0.00,0.02]]), + (519, [[52.30,140.20,-39.60], [-180.50,-24.10,75.00], [6.56,-1.83,-10.42], [-0.01,0.01,0.02], [10.92,-5.86,-1.23], [-0.01,0.00,0.01]]), + (520, [[6.80,106.50,-47.40], [-171.30,31.80,-4.10], [6.54,-1.84,-10.42], [-0.02,0.00,0.02], [4.47,-11.58,0.76], [-0.01,0.00,0.02]]), + (521, [[27.90,191.60,-30.80], [-96.90,52.70,-49.30], [6.53,-1.84,-10.38], [-0.02,0.00,0.03], [-3.83,-11.78,-0.64], [-0.01,0.00,0.02]]), + (522, [[-17.90,115.60,-73.10], [-104.10,42.30,14.10], [6.50,-1.84,-10.34], [-0.02,0.01,0.04], [3.67,-11.67,-1.73], [-0.01,0.00,0.02]]), + (523, [[1.90,223.30,-37.40], [44.00,82.00,-9.10], [6.48,-1.83,-10.30], [-0.02,0.01,0.03], [-8.06,6.38,-6.78], [-0.01,0.00,0.02]]), + (524, [[33.20,282.60,-58.50], [-23.00,67.10,-26.70], [6.46,-1.82,-10.28], [0.79,3.52,4.91], [-9.76,-5.35,-5.20], [1.08,4.71,6.57]]), + (525, [[67.80,358.20,-24.30], [-2.30,0.30,54.60], [8.70,7.96,3.32], [1.46,2.72,1.91], [-8.05,8.86,2.62], [1.97,3.65,2.54]]), + (526, [[40.70,358.70,43.40], [-22.60,47.20,59.80], [10.07,6.17,-3.14], [-2.81,1.16,1.68], [-6.06,5.75,-8.92], [-3.76,1.57,2.26]]), + (527, [[29.20,413.00,41.50], [-60.50,10.90,19.00], [2.71,10.25,6.04], [-2.85,2.07,3.48], [-2.92,6.65,-9.81], [-3.83,2.79,4.68]]), + (528, [[-26.50,361.80,43.10], [-56.30,17.20,1.60], [4.26,10.71,3.91], [2.65,-1.03,-4.10], [1.65,3.61,-11.51], [3.58,-1.38,-5.52]]), + (529, [[-23.40,393.00,43.00], [-7.70,31.40,-0.90], [8.20,8.68,-2.31], [-0.97,0.74,-1.25], [-3.55,5.57,-10.21], [-1.31,1.01,-1.68]]), + (530, [[-36.60,415.60,41.80], [-25.50,17.70,1.00], [3.39,11.66,-0.43], [-4.02,1.55,1.19], [-3.78,1.95,-11.38], [-5.42,2.09,1.60]]), + (531, [[-70.00,421.50,45.40], [-30.80,-9.50,1.40], [-1.42,12.05,0.40], [-5.91,-4.42,2.80], [1.42,0.95,-12.01], [-7.98,-5.96,3.78]]), + (532, [[-90.30,401.60,44.50], [-15.10,-33.40,-0.70], [-10.42,1.99,5.88], [-2.95,-8.68,2.68], [-6.30,0.47,-10.36], [-3.98,-11.72,3.63]]), + (533, [[-91.80,361.20,44.50], [35.10,-38.10,-18.40], [-5.87,-8.91,5.73], [6.01,-6.11,-1.81], [-6.62,-2.05,-9.93], [8.12,-8.26,-2.44]]), + (534, [[-38.80,367.10,17.80], [33.30,56.60,-27.60], [5.34,-10.83,0.53], [6.11,6.76,-2.78], [-6.72,-7.33,-6.87], [8.27,9.14,-3.76]]), + (535, [[-55.20,436.50,11.50], [-50.10,54.50,-0.10], [8.19,8.83,-0.65], [0.24,8.59,-0.86], [-1.11,0.26,-12.00], [0.34,11.63,-1.17]]), + (536, [[-121.40,460.30,17.10], [-86.80,60.90,-1.80], [6.07,10.28,-1.54], [0.90,-2.49,-1.08], [-1.49,-0.82,-11.91], [1.24,-3.38,-1.46]]), + (537, [[-164.50,536.10,-17.30], [-9.90,55.20,-8.50], [11.44,1.36,-3.37], [8.03,-12.39,-1.98], [-3.05,-2.47,-11.34], [10.93,-16.81,-2.68]]) + ] ), 'userAnnotationGroups': [ { @@ -634,157 +635,158 @@ class MeshType_3d_smallintestine1(Scaffold_base): }, 'meshEdits': exnode_string_from_nodeset_field_parameters( [ Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3 ], [ - (1, [ [ -40.03, -124.48, 1057.88 ], [ -9.88, 12.23, -4.08 ], [ -4.33, -5.88, -7.13 ], [ 2.36, -0.32, 0.12 ], [ -3.77, -1.79, 3.76 ], [ -0.25, 2.08, -4.50] ] ), - (2, [ [ -49.64, -111.67, 1050.88 ], [ -6.84, 19.44, -21.94 ], [ -1.59, -6.21, -5.00 ], [ 0.90, 0.69, 1.57 ], [ -6.92, 0.02, 2.18 ], [ -0.76, 2.95, -2.23] ] ), - (3, [ [ -43.45, -95.70, 1015.59 ], [ 40.73, 3.22, -44.80 ], [ -4.94, -3.15, -4.71 ], [ -0.38, 4.38, -0.33 ], [ -2.12, 5.61, -1.53 ], [ 4.59, 3.49, -0.79] ] ), - (4, [ [ 26.76, -119.31, 992.03 ], [ 58.86, -18.68, -8.45 ], [ 0.29, 3.71, -6.21 ], [ 4.15, 2.33, 1.07 ], [ 2.08, 5.13, 3.16 ], [ 3.36, -4.08, 2.37] ] ), - (5, [ [ 68.06, -131.66, 993.83 ], [ 9.68, -30.91, -18.90 ], [ 3.82, 3.44, -3.68 ], [ -0.33, -6.20, 3.78 ], [ 4.96, -1.02, 4.20 ], [ -3.68, -1.57, 1.51] ] ), - (6, [ [ 46.28, -139.94, 982.68 ], [ -22.68, -4.85, -10.94 ], [ 0.98, -6.62, 0.91 ], [ -0.93, -3.80, 3.22 ], [ -2.99, 0.39, 6.02 ], [ -5.34, -0.64, -2.85] ] ), - (7, [ [ 28.56, -141.07, 974.61 ], [ 3.75, -10.52, -21.30 ], [ 1.46, -5.82, 3.13 ], [ -1.00, 0.06, -0.07 ], [ -6.42, -1.75, -0.27 ], [ 1.10, -0.53, -6.40] ] ), - (8, [ [ 52.39, -146.13, 971.40 ], [ 18.40, -3.70, 0.67 ], [ -1.35, -6.67, 0.28 ], [ -0.59, -0.29, -0.54 ], [ 0.18, -0.32, -6.80 ], [ 2.42, 0.06, -1.89] ] ), - (9, [ [ 63.13, -148.18, 973.52 ], [ 10.49, -1.41, 1.47 ], [ -1.00, -6.72, 0.72 ], [ 2.41, 0.38, 0.12 ], [ 0.83, -0.84, -6.72 ], [ -2.03, -1.10, 0.84] ] ), - (10, [ [ 72.69, -148.91, 974.30 ], [ 7.65, 3.57, -7.08 ], [ 3.28, -5.95, 0.54 ], [ 0.43, 0.20, -1.42 ], [ -3.64, -2.47, -5.18 ], [ -3.49, 0.08, 4.65] ] ), - (11, [ [ 71.05, -143.65, 964.65 ], [ -5.96, 4.70, -11.04 ], [ -0.76, -6.41, -2.32 ], [ -2.36, -0.38, -1.14 ], [ -6.00, -0.40, 3.07 ], [ 0.27, 0.95, 6.07] ] ), - (12, [ [ 61.06, -140.78, 954.52 ], [ -17.96, 3.88, -6.22 ], [ -1.00, -6.68, -1.29 ], [ 0.18, -0.25, 1.37 ], [ -2.40, -0.88, 6.38 ], [ 3.84, 0.27, 2.13] ] ), - (13, [ [ 37.99, -136.93, 957.17 ], [ -18.82, 0.88, 5.08 ], [ -0.15, -6.89, 0.63 ], [ 1.90, 0.17, 0.59 ], [ 1.82, 0.57, 6.64 ], [ 2.12, 1.03, -0.12] ] ), - (14, [ [ 24.26, -138.06, 963.16 ], [ -17.40, -6.04, 8.51 ], [ 2.43, -6.48, 0.36 ], [ 2.42, 1.01, 0.69 ], [ 2.61, 1.33, 6.28 ], [ -2.18, -0.67, -0.74] ] ), - (15, [ [ 6.50, -150.31, 973.05 ], [ -8.25, -16.44, -13.42 ], [ 4.59, -4.46, 2.65 ], [ -1.08, -0.49, -0.28 ], [ -4.53, -1.74, 4.92 ], [ -4.27, -0.82, -2.18] ] ), - (16, [ [ 15.97, -149.80, 957.69 ], [ -4.35, -1.25, -14.05 ], [ 0.93, -6.94, 0.33 ], [ -1.04, -0.78, -0.85 ], [ -6.52, -0.78, 2.09 ], [ -0.48, 0.19, -0.50] ] ), - (17, [ [ 8.29, -150.98, 954.25 ], [ -3.34, -0.73, -8.15 ], [ 1.11, -6.93, 0.17 ], [ 0.18, 0.05, 0.37 ], [ -6.30, -0.94, 2.67 ], [ 0.56, -0.43, -3.27] ] ), - (18, [ [ 10.77, -150.88, 946.76 ], [ 5.27, -0.05, -7.15 ], [ 1.29, -6.84, 1.00 ], [ -0.12, -0.03, 0.05 ], [ -5.45, -1.61, -4.01 ], [ 2.05, 0.22, -4.83] ] ), - (19, [ [ 18.30, -151.09, 941.26 ], [ 7.79, 0.88, -2.39 ], [ 0.83, -7.00, 0.15 ], [ 0.05, -0.01, -0.90 ], [ -2.02, -0.38, -6.73 ], [ 4.52, 1.49, -0.77] ] ), - (20, [ [ 24.85, -149.58, 941.59 ], [ 5.32, 0.62, 3.02 ], [ 1.25, -6.91, -0.79 ], [ -0.35, 0.01, -0.65 ], [ 3.30, 1.29, -6.07 ], [ 3.43, 0.58, 1.19] ] ), - (21, [ [ 27.85, -149.81, 945.92 ], [ 3.49, -0.55, 3.99 ], [ 0.31, -6.95, -1.22 ], [ -0.75, -0.04, -0.15 ], [ 5.27, 1.02, -4.47 ], [ -0.58, -0.16, -0.31] ] ), - (22, [ [ 31.64, -150.64, 949.37 ], [ 5.77, -0.50, 1.81 ], [ -0.26, -6.99, -1.09 ], [ 0.32, -0.01, 0.32 ], [ 2.17, 0.96, -6.66 ], [ -4.59, -0.60, -0.74] ] ), - (23, [ [ 38.16, -150.55, 948.48 ], [ 5.40, 1.27, -4.34 ], [ 1.20, -6.96, -0.53 ], [ 1.28, 0.32, -0.53 ], [ -4.35, -0.33, -5.52 ], [ -4.44, -1.61, 3.12] ] ), - (24, [ [ 40.30, -148.53, 942.17 ], [ -0.50, 2.45, -7.55 ], [ 2.28, -6.33, -2.21 ], [ 1.39, 0.82, -0.98 ], [ -6.59, -2.27, -0.30 ], [ -0.57, -0.95, 1.02] ] ), - (25, [ [ 36.76, -146.19, 935.09 ], [ 3.27, 5.38, -6.44 ], [ 4.06, -5.28, -2.35 ], [ 0.26, -0.08, 1.07 ], [ -5.17, -2.04, -4.32 ], [ 3.60, 1.24, -3.41] ] ), - (26, [ [ 44.60, -142.08, 934.77 ], [ 8.65, 3.53, 1.10 ], [ 2.68, -6.58, 0.02 ], [ -1.02, -0.77, 1.00 ], [ 0.78, 0.29, -7.08 ], [ 3.41, 1.45, -1.30] ] ), - (27, [ [ 53.34, -139.44, 937.21 ], [ 8.31, 2.34, 2.22 ], [ 2.02, -6.82, -0.36 ], [ -0.54, -0.17, -0.42 ], [ 1.61, 0.84, -6.90 ], [ 0.07, 0.37, 0.03] ] ), - (28, [ [ 61.18, -137.39, 939.22 ], [ 8.23, 1.72, 1.43 ], [ 1.59, -6.92, -0.81 ], [ -0.38, -0.10, -0.17 ], [ 1.00, 1.05, -7.00 ], [ -0.84, -0.07, -0.12] ] ), - (29, [ [ 69.72, -136.03, 940.04 ], [ 8.42, 1.51, 0.05 ], [ 1.27, -7.02, -0.70 ], [ 0.30, 0.21, -0.63 ], [ -0.08, 0.70, -7.13 ], [ -3.56, -0.97, 1.73] ] ), - (30, [ [ 77.28, -134.50, 939.34 ], [ 4.49, 4.18, -8.53 ], [ 2.17, -6.51, -2.05 ], [ -0.29, 0.07, -0.48 ], [ -6.03, -0.87, -3.60 ], [ -3.19, -0.95, 5.53] ] ), - (31, [ [ 71.89, -131.27, 929.11 ], [ -6.78, 1.09, -6.79 ], [ 0.08, -7.09, -1.22 ], [ -0.44, -0.26, 1.25 ], [ -5.09, -0.91, 4.94 ], [ 0.24, 0.45, 2.90] ] ), - (32, [ [ 66.11, -131.60, 925.90 ], [ -4.09, -0.45, -4.44 ], [ 0.51, -7.19, 0.26 ], [ 0.08, 0.05, 1.40 ], [ -5.23, -0.20, 4.83 ], [ -0.15, 0.88, -0.16] ] ), - (33, [ [ 63.93, -132.09, 921.07 ], [ -3.93, -1.16, -4.37 ], [ 0.30, -7.03, 1.60 ], [ 0.72, 0.30, 0.95 ], [ -5.38, 0.82, 4.63 ], [ 0.66, 0.51, 0.56] ] ), - (34, [ [ 58.47, -133.89, 917.96 ], [ -6.67, -3.36, -3.67 ], [ 2.16, -6.56, 2.08 ], [ 2.28, 0.92, -0.11 ], [ -3.73, 0.71, 6.12 ], [ 2.25, 0.03, 1.31] ] ), - (35, [ [ 51.02, -139.09, 914.02 ], [ -6.63, -6.74, 0.39 ], [ 5.08, -4.94, 1.06 ], [ 1.07, 0.42, -1.32 ], [ -0.56, 0.96, 7.15 ], [ 3.12, 0.37, 0.20] ] ), - (36, [ [ 46.77, -145.49, 918.12 ], [ -5.05, -4.37, 2.87 ], [ 4.53, -5.57, -0.52 ], [ -1.31, -0.89, -0.94 ], [ 2.52, 1.43, 6.62 ], [ 1.26, -0.68, -0.12] ] ), - (37, [ [ 41.95, -147.92, 919.78 ], [ -5.03, -2.38, 1.94 ], [ 2.73, -6.62, -1.04 ], [ -1.32, -0.68, -0.33 ], [ 2.61, 0.01, 6.76 ], [ -0.11, -1.00, 0.12] ] ), - (38, [ [ 36.76, -150.21, 922.00 ], [ -5.10, -1.68, 1.58 ], [ 1.91, -6.90, -1.17 ], [ -0.51, -0.22, 0.81 ], [ 2.30, -0.53, 6.87 ], [ -0.45, 0.50, 0.13] ] ), - (39, [ [ 31.89, -151.33, 922.99 ], [ -5.71, -1.25, 1.56 ], [ 1.67, -7.06, 0.43 ], [ -0.57, -0.18, 0.73 ], [ 1.73, 0.83, 7.02 ], [ -2.05, 0.33, 0.03] ] ), - (40, [ [ 25.55, -152.65, 925.18 ], [ -6.28, -0.56, -2.17 ], [ 0.66, -7.26, -0.03 ], [ -0.69, -0.09, -0.62 ], [ -2.35, -0.24, 6.88 ], [ -3.19, -0.78, -0.83] ] ), - (41, [ [ 22.17, -152.27, 920.06 ], [ -4.85, 0.30, -4.20 ], [ 0.25, -7.25, -0.80 ], [ -0.24, -0.02, 0.24 ], [ -4.73, -0.76, 5.42 ], [ 2.41, 0.37, -0.06] ] ), - (42, [ [ 16.60, -152.11, 917.51 ], [ -6.97, 0.00, 2.68 ], [ 0.19, -7.29, 0.48 ], [ -0.30, -0.03, 0.60 ], [ 2.61, 0.51, 6.79 ], [ 5.78, 0.37, -0.74] ] ), - (43, [ [ 13.12, -152.32, 924.90 ], [ -3.73, 0.41, 7.15 ], [ -0.42, -7.30, 0.20 ], [ -0.14, -0.02, -0.16 ], [ 6.38, -0.28, 3.34 ], [ -0.23, -0.18, 0.20] ] ), - (44, [ [ 9.44, -151.37, 931.31 ], [ -7.88, 0.19, 2.81 ], [ -0.12, -7.33, 0.16 ], [ 0.49, -0.01, 0.12 ], [ 2.46, 0.11, 6.89 ], [ -3.70, 0.33, 2.08] ] ), - (45, [ [ 1.23, -152.17, 928.31 ], [ -8.13, -0.72, -1.08 ], [ 0.58, -7.31, 0.46 ], [ 0.09, -0.01, -0.29 ], [ -1.00, 0.38, 7.26 ], [ 1.43, -0.16, -0.65] ] ), - (46, [ [ -5.97, -152.74, 928.93 ], [ -5.64, -0.31, 4.39 ], [ 0.16, -7.35, -0.31 ], [ -0.93, 0.04, 0.09 ], [ 4.48, -0.15, 5.76 ], [ 3.98, -0.84, -4.11] ] ), - (47, [ [ -8.05, -152.70, 935.12 ], [ 0.84, 0.43, 7.28 ], [ -1.23, -7.23, 0.57 ], [ -1.08, 0.17, 0.74 ], [ 7.08, -1.26, -0.74 ], [ 0.79, -0.43, -1.11] ] ), - (48, [ [ -4.18, -151.98, 940.93 ], [ -5.50, 2.85, 8.02 ], [ -1.95, -7.01, 1.15 ], [ -0.37, 0.07, -0.10 ], [ 5.81, -0.90, 4.30 ], [ -3.01, 0.56, 4.29] ] ), - (49, [ [ -15.92, -150.23, 939.85 ], [ -11.53, 2.83, 0.08 ], [ -1.76, -7.18, -0.02 ], [ 0.12, 0.15, 0.78 ], [ 0.04, -0.03, 7.39 ], [ 0.81, 0.00, -1.16] ] ), - (50, [ [ -25.87, -146.77, 940.97 ], [ -2.69, 4.15, 9.23 ], [ -1.70, -6.74, 2.54 ], [ 0.69, 0.20, 1.48 ], [ 6.83, -0.83, 2.36 ], [ 1.72, -1.41, -6.49] ] ), - (51, [ [ -19.43, -146.58, 946.99 ], [ 7.70, 1.83, 5.13 ], [ -0.46, -6.73, 3.10 ], [ 1.24, -0.13, -0.09 ], [ 4.24, -2.77, -5.37 ], [ -0.59, -0.04, -3.45] ] ), - (52, [ [ -11.61, -143.43, 950.54 ], [ 5.25, 2.52, 5.68 ], [ 0.78, -7.00, 2.38 ], [ 0.75, -0.24, -0.87 ], [ 5.57, -0.98, -4.71 ], [ 0.83, 1.41, 0.57] ] ), - (53, [ [ -9.22, -141.82, 956.88 ], [ 3.60, 1.58, 5.20 ], [ 1.15, -7.22, 1.40 ], [ -0.05, -0.13, -0.42 ], [ 6.02, 0.14, -4.21 ], [ 0.12, 0.28, 0.10] ] ), - (54, [ [ -4.88, -140.39, 960.70 ], [ 3.78, 1.36, 4.90 ], [ 0.74, -7.28, 1.45 ], [ 0.07, -0.06, -0.65 ], [ 5.87, -0.29, -4.45 ], [ 0.53, 0.53, 1.66] ] ), - (55, [ [ -1.98, -139.20, 966.47 ], [ 0.65, 0.13, 7.29 ], [ 1.34, -7.34, 0.01 ], [ 0.23, -0.06, -0.88 ], [ 7.17, 1.31, -0.66 ], [ 0.66, 0.74, 3.14] ] ), - (56, [ [ -4.15, -140.36, 973.96 ], [ -2.38, -0.65, 10.17 ], [ 1.12, -7.39, -0.21 ], [ -0.65, -0.07, -0.20 ], [ 7.07, 1.03, 1.72 ], [ -0.21, -0.70, 2.00] ] ), - (57, [ [ -6.44, -140.06, 986.68 ], [ -4.21, -0.33, 9.07 ], [ -0.23, -7.49, -0.38 ], [ -0.77, 0.02, -0.44 ], [ 6.68, -0.36, 3.09 ], [ -1.82, -1.02, 2.46] ] ), - (58, [ [ -10.86, -140.67, 991.98 ], [ -5.80, 0.04, 3.85 ], [ -0.69, -7.41, -0.97 ], [ 0.04, -0.00, -0.15 ], [ 4.08, -1.18, 6.14 ], [ -3.51, -0.15, 2.18] ] ), - (59, [ [ -17.28, -140.01, 993.95 ], [ -7.30, 0.18, -0.28 ], [ -0.16, -7.49, -0.69 ], [ 0.59, -0.04, 0.75 ], [ -0.30, -0.68, 7.48 ], [ -4.07, 0.69, 0.16] ] ), - (60, [ [ -24.40, -140.40, 991.18 ], [ -6.25, -0.73, -3.97 ], [ 0.50, -7.49, 0.59 ], [ -0.08, 0.16, 1.48 ], [ -4.03, 0.23, 6.31 ], [ -3.14, 0.95, -2.22] ] ), - (61, [ [ -29.47, -141.40, 986.35 ], [ -2.47, -1.37, -4.69 ], [ -0.26, -7.19, 2.25 ], [ -1.43, 0.31, 0.61 ], [ -6.62, 1.22, 3.13 ], [ -0.94, 0.18, -5.15] ] ), - (62, [ [ -29.90, -142.61, 982.98 ], [ 1.86, -2.14, -4.74 ], [ -2.05, -6.88, 2.30 ], [ -1.16, 0.11, -0.29 ], [ -6.69, 0.97, -3.06 ], [ 0.49, -0.35, -4.87] ] ), - (63, [ [ -24.82, -145.19, 978.58 ], [ 4.65, -2.18, -4.59 ], [ -2.01, -7.15, 1.36 ], [ 0.29, -0.26, -0.91 ], [ -5.15, 0.42, -5.42 ], [ -0.33, 0.23, 1.00] ] ), - (64, [ [ -20.75, -146.91, 974.01 ], [ 1.23, -0.70, -6.94 ], [ -1.49, -7.40, 0.48 ], [ 0.08, -0.09, -0.69 ], [ -7.16, 1.35, -1.40 ], [ 0.46, 0.35, 5.77] ] ), - (65, [ [ -23.39, -146.10, 967.33 ], [ -6.32, 1.65, -4.01 ], [ -1.92, -7.32, 0.01 ], [ -0.16, 0.07, 0.36 ], [ -3.81, 1.01, 6.42 ], [ 4.83, -0.40, 4.28] ] ), - (66, [ [ -30.60, -144.33, 967.78 ], [ -6.69, 2.04, 2.19 ], [ -1.82, -7.26, 1.20 ], [ 0.05, 0.00, 0.44 ], [ 2.50, 0.55, 7.13 ], [ 3.03, -0.35, 0.34] ] ), - (67, [ [ -36.17, -142.25, 971.34 ], [ -6.59, 1.94, 2.27 ], [ -1.83, -7.30, 0.95 ], [ 0.04, -0.01, 0.09 ], [ 2.55, 0.29, 7.14 ], [ 0.37, -0.02, -0.15] ] ), - (68, [ [ -43.40, -140.59, 972.07 ], [ -6.04, 1.97, 2.74 ], [ -1.73, -7.28, 1.40 ], [ 0.02, 0.34, 1.18 ], [ 3.28, 0.53, 6.83 ], [ 2.30, -0.41, -2.27] ] ), - (69, [ [ -47.62, -138.63, 976.14 ], [ -1.78, 2.68, 4.62 ], [ -1.77, -6.68, 3.20 ], [ 0.01, 0.35, 0.98 ], [ 6.89, -0.43, 2.91 ], [ 1.72, -1.44, -3.71] ] ), - (70, [ [ -47.10, -135.98, 980.16 ], [ 0.98, 1.95, 4.05 ], [ -1.73, -6.52, 3.55 ], [ 0.21, -0.14, -0.20 ], [ 7.12, -2.24, -0.64 ], [ 0.04, -0.76, -2.21] ] ), - (71, [ [ -45.78, -134.75, 984.02 ], [ 1.92, 1.94, 5.58 ], [ -1.38, -6.93, 2.88 ], [ -0.53, 0.37, 0.09 ], [ 7.01, -2.09, -1.69 ], [ -0.24, 0.26, 1.07] ] ), - (72, [ [ -43.37, -132.13, 990.97 ], [ -1.92, 7.78, 7.36 ], [ -3.57, -5.07, 4.43 ], [ -2.14, 1.26, -0.06 ], [ 6.52, -1.62, 3.41 ], [ -3.47, 2.54, 4.15] ] ), - (73, [ [ -50.92, -122.17, 992.94 ], [ -8.28, 6.98, -7.76 ], [ -5.63, -4.80, 1.69 ], [ 0.61, -1.11, -1.84 ], [ -1.92, 4.37, 5.99 ], [ -6.54, 1.98, -0.43] ] ), - (74, [ [ -54.52, -122.57, 980.90 ], [ -5.10, 0.46, -13.05 ], [ -2.46, -7.24, 0.71 ], [ 2.85, -1.09, 0.85 ], [ -6.63, 2.51, 2.68 ], [ -2.86, -1.79, -2.31] ] ), - (75, [ [ -60.93, -121.16, 967.78 ], [ -3.40, -6.95, -12.83 ], [ 0.01, -6.78, 3.67 ], [ -1.69, 1.75, 1.25 ], [ -7.36, 0.81, 1.51 ], [ 1.21, -0.70, -4.51] ] ), - (76, [ [ -59.94, -133.62, 960.46 ], [ 4.44, -11.12, -4.92 ], [ -5.83, -3.75, 3.22 ], [ -1.80, 0.34, -0.38 ], [ -4.21, 1.12, -6.33 ], [ 1.72, -0.86, -3.60] ] ), - (77, [ [ -53.65, -142.09, 958.04 ], [ 8.15, -8.95, -3.45 ], [ -4.68, -5.37, 2.89 ], [ 2.04, -1.62, -0.11 ], [ -3.54, -0.59, -6.83 ], [ -0.92, -0.86, 0.97] ] ), - (78, [ [ -43.78, -150.90, 953.55 ], [ 6.86, -6.21, -10.82 ], [ -1.48, -6.98, 3.06 ], [ 0.10, -0.47, -1.48 ], [ -6.55, -0.34, -3.95 ], [ -0.50, 1.88, 6.12] ] ), - (79, [ [ -42.79, -151.92, 940.92 ], [ -10.16, 7.35, -12.87 ], [ -4.48, -6.31, -0.07 ], [ -1.78, 0.37, -1.94 ], [ -4.55, 3.17, 5.40 ], [ 1.37, 1.93, 5.90] ] ), - (80, [ [ -59.56, -139.32, 940.87 ], [ -10.47, 7.53, -10.55 ], [ -4.41, -6.40, -0.20 ], [ -0.78, 0.74, 0.77 ], [ -4.15, 2.67, 6.02 ], [ -0.63, 1.74, -4.22] ] ), - (81, [ [ -61.19, -138.43, 930.23 ], [ -0.37, -2.04, -12.19 ], [ -5.64, -5.22, 1.05 ], [ -0.86, 0.96, 0.96 ], [ -5.33, 5.60, -0.78 ], [ 0.65, -0.72, -6.69] ] ), - (82, [ [ -60.05, -143.37, 918.84 ], [ 6.12, -9.41, -3.11 ], [ -6.09, -4.52, 1.69 ], [ 0.25, -0.37, -0.76 ], [ -2.60, 0.74, -7.36 ], [ 3.39, -3.10, -3.06] ] ), - (83, [ [ -54.81, -148.97, 924.54 ], [ 7.07, -6.60, 2.05 ], [ -5.30, -5.72, -0.16 ], [ 0.76, -0.86, -0.33 ], [ 1.31, -0.99, -7.69 ], [ -1.61, 1.40, 1.58] ] ), - (84, [ [ -48.00, -154.67, 922.57 ], [ 3.54, -3.72, -7.48 ], [ -4.57, -6.25, 0.95 ], [ 1.21, -0.76, -0.14 ], [ -5.53, 3.38, -4.30 ], [ -4.06, 1.81, 3.83] ] ), - (85, [ [ -49.39, -154.51, 914.46 ], [ 0.27, 0.35, -10.67 ], [ -2.94, -7.22, -0.31 ], [ 1.86, -0.79, -0.48 ], [ -7.12, 2.90, -0.09 ], [ 1.64, -1.57, -0.54] ] ), - (86, [ [ -46.73, -154.01, 904.00 ], [ 18.99, -1.89, -1.48 ], [ -0.74, -7.74, 0.38 ], [ 1.31, -0.30, 0.50 ], [ -0.63, -0.32, -7.74 ], [ 5.19, -2.31, -4.98] ] ), - (87, [ [ -31.90, -157.00, 923.20 ], [ 20.27, -2.84, 5.71 ], [ -1.21, -7.60, 0.51 ], [ 1.63, 0.18, 0.17 ], [ 1.98, -0.81, -7.42 ], [ -3.21, -0.77, 1.42] ] ), - (88, [ [ -17.04, -158.47, 917.33 ], [ 10.69, 1.60, -10.94 ], [ 1.83, -7.40, 0.70 ], [ 0.87, 0.01, -0.11 ], [ -5.13, -1.77, -5.27 ], [ -1.71, 0.19, -0.09] ] ), - (89, [ [ -12.92, -154.88, 905.59 ], [ 14.28, 1.56, -5.12 ], [ 0.95, -7.55, 0.35 ], [ -0.98, -0.09, -0.58 ], [ -2.50, -0.65, -7.16 ], [ 1.89, 1.14, -1.15] ] ), - (90, [ [ 0.79, -157.22, 913.22 ], [ 17.05, -0.10, -3.50 ], [ -0.15, -7.56, -0.50 ], [ 0.24, 0.09, -0.24 ], [ -1.52, 0.52, -7.39 ], [ 0.10, 0.16, 0.01] ] ), - (91, [ [ 11.37, -154.85, 899.81 ], [ 20.47, 4.34, -7.04 ], [ 1.53, -7.36, -0.09 ], [ 0.67, 0.24, -0.62 ], [ -2.36, -0.40, -7.11 ], [ -1.60, 0.07, 0.92] ] ), - (92, [ [ 35.28, -149.96, 905.73 ], [ 15.01, 5.71, -13.20 ], [ 0.75, -7.07, -2.20 ], [ 1.12, 0.33, 0.34 ], [ -5.05, 1.10, -5.27 ], [ -1.05, -1.38, 0.95] ] ), - (93, [ [ 31.51, -148.90, 893.07 ], [ 11.51, 6.02, -14.64 ], [ 2.99, -6.72, -0.41 ], [ 1.65, 0.51, 0.45 ], [ -5.13, -1.99, -4.85 ], [ 2.20, -0.03, -0.53] ] ), - (94, [ [ 53.21, -142.18, 892.15 ], [ 16.13, 8.56, 4.60 ], [ 3.73, -5.96, -2.01 ], [ 0.42, 0.20, 0.80 ], [ 0.55, 2.65, -6.83 ], [ 3.44, 1.00, -0.61] ] ), - (95, [ [ 62.43, -134.45, 898.99 ], [ 11.35, 7.61, 6.27 ], [ 3.97, -6.09, 0.21 ], [ -1.03, -0.53, 1.15 ], [ 2.65, 1.50, -6.63 ], [ -2.20, -1.80, 0.66] ] ), - (96, [ [ 74.83, -127.92, 903.83 ], [ 13.27, 2.58, -11.41 ], [ 1.50, -7.08, 0.14 ], [ -0.63, -0.25, 0.20 ], [ -4.49, -1.05, -5.45 ], [ -4.38, -1.93, 4.88] ] ), - (97, [ [ 72.51, -133.32, 887.20 ], [ -12.49, -8.25, -22.65 ], [ 3.07, -6.44, 0.66 ], [ 0.84, 0.36, -0.04 ], [ -5.54, -2.24, 3.87 ], [ 0.64, -0.37, 7.04] ] ), - (98, [ [ 47.82, -142.63, 864.93 ], [ -22.72, -8.47, -7.52 ], [ 2.59, -6.58, -0.40 ], [ 0.03, 0.23, -1.27 ], [ -1.82, -1.13, 6.76 ], [ 5.33, 1.35, 0.11] ] ), - (99, [ [ 33.71, -147.84, 866.62 ], [ -7.31, -5.02, 5.80 ], [ 2.84, -6.19, -1.77 ], [ -0.71, 0.24, -1.45 ], [ 4.23, 0.33, 5.62 ], [ 2.35, 2.56, -6.78] ] ), - (100, [ [ 33.45, -149.55, 870.08 ], [ 6.66, -2.67, 8.62 ], [ 1.80, -6.00, -3.25 ], [ -0.81, 0.03, -0.86 ], [ 5.31, 3.27, -3.10 ], [ 0.80, 2.08, -6.77] ] ), - (101, [ [ 48.50, -149.86, 877.56 ], [ 8.44, -1.40, 10.88 ], [ 1.73, -6.47, -2.17 ], [ -0.55, -0.39, 1.17 ], [ 5.25, 2.65, -3.73 ], [ -1.37, -2.16, 5.89] ] ), - (102, [ [ 49.17, -151.34, 885.88 ], [ -14.13, -2.76, 6.71 ], [ 0.88, -6.81, -0.95 ], [ -0.57, 0.33, -0.41 ], [ 3.06, -0.48, 6.24 ], [ -3.09, -3.47, 6.17] ] ), - (103, [ [ 30.33, -151.82, 877.70 ], [ -17.16, 1.53, -4.96 ], [ 0.86, -5.16, -4.59 ], [ -1.51, -0.14, 0.40 ], [ -1.82, -4.63, 4.87 ], [ 0.64, -0.13, 0.13] ] ), - (104, [ [ 16.36, -149.06, 875.57 ], [ -10.97, 1.71, 5.38 ], [ -1.69, -6.55, -1.37 ], [ -0.54, -0.73, 1.97 ], [ 2.66, -1.95, 6.05 ], [ 2.86, 1.80, -0.06] ] ), - (105, [ [ 11.69, -148.72, 883.92 ], [ -10.14, 1.00, 8.83 ], [ -0.88, -6.83, -0.24 ], [ 0.66, -0.15, 1.09 ], [ 4.42, -0.75, 5.16 ], [ -0.40, 1.32, 0.04] ] ), - (106, [ [ -3.83, -146.99, 890.11 ], [ -14.28, 1.09, 0.55 ], [ -0.49, -6.77, 0.78 ], [ 0.36, 0.01, -0.26 ], [ 0.32, 0.76, 6.79 ], [ -1.67, -0.06, 0.66] ] ), - (107, [ [ -14.79, -146.52, 886.71 ], [ -10.85, 0.22, 0.51 ], [ -0.15, -6.79, -0.36 ], [ 0.73, 0.03, -0.30 ], [ 0.31, -0.37, 6.78 ], [ 2.18, 0.02, -0.94] ] ), - (108, [ [ -23.91, -146.55, 890.53 ], [ -7.40, -0.95, 6.58 ], [ 0.92, -6.71, 0.07 ], [ -0.52, 0.10, 0.63 ], [ 4.39, 0.65, 5.03 ], [ 0.75, 0.45, -0.15] ] ), - (109, [ [ -28.03, -148.18, 898.37 ], [ -13.61, 2.90, 3.80 ], [ -1.15, -6.58, 0.90 ], [ -1.43, 0.37, -0.84 ], [ 1.91, 0.54, 6.43 ], [ -3.99, -0.65, 0.17] ] ), - (110, [ [ -42.02, -140.32, 889.27 ], [ -9.93, 7.70, -9.68 ], [ -1.35, -5.73, -3.18 ], [ 0.84, -0.04, -0.89 ], [ -4.99, -1.16, 4.20 ], [ -3.62, 0.11, -4.10] ] ), - (111, [ [ -47.83, -133.82, 880.59 ], [ 1.67, 2.81, -9.02 ], [ 0.18, -6.37, -1.95 ], [ 0.02, -0.24, 2.82 ], [ -6.43, 0.16, -1.14 ], [ 2.63, -0.65, -5.17] ] ), - (112, [ [ -43.36, -134.64, 876.97 ], [ 7.37, -1.12, -1.77 ], [ -0.57, -6.40, 1.69 ], [ -0.49, -0.09, 1.49 ], [ -1.72, -1.49, -6.23 ], [ 3.37, -0.42, -3.09] ] ), - (113, [ [ -34.80, -135.76, 878.37 ], [ 7.33, -0.80, -0.16 ], [ -0.71, -6.57, 0.26 ], [ -0.51, 0.02, -0.71 ], [ -0.17, -0.24, -6.61 ], [ -2.44, 1.36, 1.66] ] ), - (114, [ [ -29.32, -136.24, 877.18 ], [ 3.39, -0.80, -5.31 ], [ -1.47, -6.43, 0.04 ], [ -0.23, 0.05, 0.03 ], [ -5.30, 1.19, -3.57 ], [ -3.22, 0.72, 3.41] ] ), - (115, [ [ -30.61, -136.87, 870.77 ], [ -0.25, -0.25, -5.29 ], [ -1.11, -6.47, 0.36 ], [ 0.28, -0.03, -0.03 ], [ -6.35, 1.10, 0.25 ], [ 0.35, -0.33, -1.21] ] ), - (116, [ [ -30.23, -136.86, 867.08 ], [ 2.79, -0.45, -3.89 ], [ -0.88, -6.50, 0.13 ], [ 0.33, -0.03, -0.12 ], [ -5.21, 0.63, -3.81 ], [ 3.30, -0.63, -3.48] ] ), - (117, [ [ -25.37, -137.76, 865.06 ], [ 8.76, -0.50, 1.85 ], [ -0.41, -6.53, 0.17 ], [ 0.24, 0.00, -0.17 ], [ 1.34, -0.25, -6.40 ], [ 3.73, -0.35, -1.77] ] ), - (118, [ [ -17.01, -136.93, 873.25 ], [ 9.54, -0.88, -1.35 ], [ -0.66, -6.46, -0.44 ], [ -0.79, 0.17, 0.25 ], [ -0.86, 0.52, -6.43 ], [ -3.99, 0.94, 2.86] ] ), - (119, [ [ -14.62, -138.10, 867.37 ], [ 2.47, -1.15, -8.78 ], [ -1.76, -6.23, 0.32 ], [ 1.25, 0.41, -0.04 ], [ -5.90, 1.57, -1.86 ], [ -1.18, 0.21, 1.02] ] ), - (120, [ [ -13.21, -138.67, 858.26 ], [ 15.02, 8.84, -1.86 ], [ 3.15, -5.55, -0.95 ], [ 3.02, 0.32, -0.46 ], [ -1.07, 0.48, -6.36 ], [ 4.30, -0.76, -2.96] ] ), - (121, [ [ -2.01, -129.09, 875.92 ], [ 14.73, 5.57, 5.54 ], [ 2.15, -6.01, 0.34 ], [ -3.38, 0.09, 1.42 ], [ 2.11, 0.42, -6.03 ], [ -4.26, 0.28, 1.85] ] ), - (122, [ [ 5.71, -128.31, 873.45 ], [ 4.22, -3.80, -6.92 ], [ -2.18, -5.70, 1.80 ], [ 1.54, 1.12, 0.79 ], [ -5.12, 0.83, -3.57 ], [ -2.90, -1.92, 4.89] ] ), - (123, [ [ 3.86, -133.45, 867.51 ], [ -1.78, -5.98, -7.59 ], [ 4.53, -3.88, 2.00 ], [ 1.96, 0.65, 1.01 ], [ -4.22, -3.14, 3.46 ], [ 0.30, -2.10, 1.25] ] ), - (124, [ [ 2.44, -139.69, 858.80 ], [ 7.02, -5.19, -6.23 ], [ 0.10, -4.81, 4.11 ], [ -1.69, -0.89, 0.21 ], [ -4.72, -2.72, -3.06 ], [ 2.22, 0.25, -4.49] ] ), - (125, [ [ 11.98, -140.15, 859.35 ], [ 17.70, 2.25, -1.14 ], [ 0.89, -5.66, 2.60 ], [ 1.39, -0.39, -2.08 ], [ -0.04, -2.63, -5.72 ], [ 2.19, 0.11, -1.39] ] ), - (126, [ [ 35.30, -132.99, 854.91 ], [ 8.74, 9.55, -15.22 ], [ 3.78, -4.88, -0.90 ], [ 0.82, 0.89, -2.82 ], [ -4.13, -2.47, -3.92 ], [ -1.33, -1.30, 4.05] ] ), - (127, [ [ 29.93, -128.55, 843.92 ], [ -12.95, 5.12, -19.36 ], [ 3.43, -3.92, -3.33 ], [ -1.41, 0.00, -0.87 ], [ -3.91, -4.60, 1.39 ], [ 1.70, -0.30, 5.11] ] ), - (128, [ [ 9.39, -125.79, 820.06 ], [ -27.75, 1.44, 5.84 ], [ -0.44, -6.13, -0.59 ], [ -1.27, -0.92, 1.78 ], [ 1.23, -0.67, 6.02 ], [ 4.74, 2.19, -0.36] ] ), - (129, [ [ 4.65, -126.74, 840.92 ], [ -6.02, 1.18, 15.73 ], [ 0.12, -6.14, 0.51 ], [ -0.73, 0.09, 0.19 ], [ 5.69, 0.29, 2.16 ], [ -2.11, 0.21, 1.57] ] ), - (130, [ [ 0.04, -125.01, 849.26 ], [ -9.24, 1.85, 1.00 ], [ -1.17, -6.01, 0.30 ], [ 0.68, 0.07, -0.54 ], [ 0.70, 0.17, 6.10 ], [ -5.74, -0.82, -0.60] ] ), - (131, [ [ -4.44, -124.79, 843.15 ], [ -5.02, 0.46, -16.66 ], [ 1.17, -5.99, -0.52 ], [ 1.98, 0.08, -0.42 ], [ -5.67, -1.25, 1.67 ], [ -4.27, -1.02, -2.57] ] ), - (132, [ [ -4.10, -124.24, 817.80 ], [ -14.82, -5.98, -12.69 ], [ 2.08, -5.71, 0.27 ], [ -0.08, -0.02, 0.18 ], [ -3.61, -1.09, 4.72 ], [ 6.33, 1.59, -0.02] ] ), - (133, [ [ -13.82, -128.40, 823.84 ], [ -7.49, -1.58, 13.51 ], [ 1.44, -5.89, 0.11 ], [ -0.55, 0.00, 0.71 ], [ 5.11, 1.30, 2.98 ], [ 4.92, 1.22, -2.01] ] ), - (134, [ [ -15.54, -126.40, 839.81 ], [ -2.26, 3.63, 12.78 ], [ 0.99, -5.69, 1.79 ], [ -1.86, 0.05, -0.36 ], [ 5.77, 1.22, 0.68 ], [ -0.95, -1.43, 1.43] ] ), - (135, [ [ -17.86, -122.19, 848.91 ], [ -6.97, 2.29, 6.40 ], [ -1.77, -5.74, 0.13 ], [ 0.21, -0.11, -0.73 ], [ 3.78, -1.07, 4.51 ], [ -5.50, -0.82, 1.29] ] ), - (136, [ [ -24.46, -122.95, 849.04 ], [ -11.05, -2.26, -14.69 ], [ 0.96, -5.91, 0.19 ], [ 1.60, -0.05, 0.47 ], [ -4.70, -0.65, 3.63 ], [ -6.40, 0.95, -0.75] ] ), - (137, [ [ -23.98, -124.71, 821.70 ], [ -13.90, -3.45, -17.21 ], [ -1.01, -5.56, 1.93 ], [ -0.11, -0.11, -0.76 ], [ -4.54, 1.96, 3.28 ], [ 5.05, -0.43, 0.87] ] ), - (138, [ [ -38.60, -127.22, 820.18 ], [ -12.58, -0.43, 8.78 ], [ -0.02, -5.94, -0.31 ], [ -0.17, -0.02, -0.17 ], [ 3.41, -0.27, 4.87 ], [ 4.86, -1.54, -2.07] ] ), - (139, [ [ -42.52, -125.65, 832.78 ], [ 1.33, 2.91, 14.25 ], [ -1.16, -5.67, 1.27 ], [ -0.03, 0.21, 1.19 ], [ 5.67, -1.22, -0.28 ], [ 1.08, -0.26, -3.49] ] ), - (140, [ [ -35.80, -121.92, 845.73 ], [ 4.20, 3.78, 10.20 ], [ 0.01, -5.54, 2.04 ], [ -0.16, 0.23, 0.57 ], [ 5.46, -0.72, -1.98 ], [ 0.09, 0.03, 0.69] ] ), - (141, [ [ -33.62, -118.72, 852.84 ], [ 0.50, 3.01, 6.47 ], [ -0.86, -5.25, 2.51 ], [ -0.79, -0.03, -0.57 ], [ 5.71, -0.94, 0.00 ], [ -0.33, -0.03, 2.50] ] ), - (142, [ [ -34.44, -116.11, 858.28 ], [ -2.64, 1.81, 5.04 ], [ -1.59, -5.52, 1.14 ], [ 0.58, -0.29, -1.41 ], [ 4.94, -0.83, 2.89 ], [ -1.83, 0.37, 2.71] ] ), - (143, [ [ -38.38, -115.33, 862.17 ], [ -6.05, -0.34, 2.35 ], [ 0.20, -5.83, -0.32 ], [ 1.37, -0.09, -0.25 ], [ 2.12, -0.22, 5.43 ], [ -4.21, 0.45, 0.94] ] ), - (144, [ [ -44.50, -116.93, 861.58 ], [ -11.59, -3.81, -10.16 ], [ 1.03, -5.65, 0.95 ], [ 0.44, 0.12, 0.61 ], [ -3.83, 0.03, 4.36 ], [ -4.54, 0.05, -0.79] ] ), - (145, [ [ -51.78, -120.72, 839.03 ], [ -15.88, -5.45, -10.36 ], [ 1.70, -5.54, 0.30 ], [ -1.36, 0.27, 0.87 ], [ -2.99, -0.65, 4.93 ], [ 4.29, 0.49, 0.09] ] ), - (146, [ [ -64.65, -124.35, 841.48 ], [ -11.51, 0.42, 9.85 ], [ 0.14, -5.74, 0.41 ], [ -0.55, 0.33, 1.54 ], [ 3.68, 0.40, 4.29 ], [ 4.38, -0.52, -2.90] ] ), - (147, [ [ -69.37, -119.95, 854.33 ], [ 5.11, 4.21, 16.62 ], [ -1.23, -5.32, 1.73 ], [ 0.69, 0.27, 0.73 ], [ 5.25, -1.61, -1.21 ], [ 0.56, -1.58, -4.18] ] ), - (148, [ [ -55.63, -118.57, 867.17 ], [ 8.19, 15.70, 8.57 ], [ 0.64, -2.10, 3.23 ], [ 0.89, 1.63, 1.44 ], [ 3.88, -1.19, -1.54 ], [ 0.13, 0.20, 0.14] ] ), - (149, [ [ -52.38, -100.90, 869.76 ], [ 4.76, 24.01, 12.61 ], [ 0.45, -2.26, 4.14 ], [ -0.28, -0.30, -1.61 ], [ 4.16, -0.46, -0.70 ], [ -2.29, 1.10, 4.28] ] ), - (150, [ [ -41.73, -76.29, 892.90 ], [ -14.02, 14.24, 19.65 ], [ -3.16, -2.70, -0.30 ], [ 3.24, -2.89, 0.75 ], [ 1.74, -2.36, 2.95 ], [ -5.09, 5.86, 6.61] ] ), - (151, [ [ -58.69, -78.02, 896.31 ], [ -2.60, -3.83, -1.89 ], [ 4.23, -2.00, -1.76 ], [ 3.24, -2.89, 0.75 ], [ 0.59, -2.51, 4.28 ], [ -5.09, 5.86, 6.61] ] ) ] ), + (1, [[-40.03,-124.48,1057.88], [-9.88,12.23,-4.08], [-4.52,-6.14,-7.44], [2.36,-0.32,0.12], [-4.07,-1.93,4.06], [-0.25,2.08,-4.50]]), + (2, [[-49.64,-111.67,1050.88], [-6.84,19.44,-21.94], [-1.68,-6.55,-5.28], [0.90,0.69,1.57], [-7.35,0.02,2.32], [-0.76,2.95,-2.23]]), + (3, [[-43.45,-95.70,1015.59], [40.73,3.22,-44.80], [-5.24,-3.34,-4.99], [-0.38,4.38,-0.33], [-2.27,6.02,-1.64], [4.59,3.49,-0.79]]), + (4, [[26.76,-119.31,992.03], [58.86,-18.68,-8.45], [0.31,3.94,-6.60], [4.15,2.33,1.07], [2.23,5.49,3.38], [3.36,-4.08,2.37]]), + (5, [[68.06,-131.66,993.83], [9.68,-30.91,-18.90], [4.09,3.68,-3.94], [-0.33,-6.20,3.78], [5.30,-1.09,4.49], [-3.68,-1.57,1.51]]), + (6, [[46.28,-139.94,982.68], [-22.68,-4.85,-10.94], [1.05,-7.06,0.97], [-0.93,-3.80,3.22], [-3.19,0.42,6.42], [-5.34,-0.64,-2.85]]), + (7, [[28.56,-141.07,974.61], [3.75,-10.52,-21.30], [1.56,-6.21,3.34], [-1.00,0.06,-0.07], [-6.85,-1.87,-0.29], [1.10,-0.53,-6.40]]), + (8, [[52.39,-146.13,971.40], [18.40,-3.70,0.67], [-1.44,-7.11,0.30], [-0.59,-0.29,-0.54], [0.19,-0.34,-7.25], [2.42,0.06,-1.89]]), + (9, [[63.13,-148.18,973.52], [10.49,-1.41,1.47], [-1.07,-7.16,0.77], [2.41,0.38,0.12], [0.88,-0.90,-7.16], [-2.03,-1.10,0.84]]), + (10, [[72.69,-148.91,974.30], [7.65,3.57,-7.08], [3.50,-6.34,0.58], [0.43,0.20,-1.42], [-3.88,-2.63,-5.52], [-3.49,0.08,4.65]]), + (11, [[71.05,-143.65,964.65], [-5.96,4.70,-11.04], [-0.81,-6.83,-2.47], [-2.36,-0.38,-1.14], [-6.40,-0.43,3.27], [0.27,0.95,6.07]]), + (12, [[61.06,-140.78,954.52], [-17.96,3.88,-6.22], [-1.07,-7.12,-1.37], [0.18,-0.25,1.37], [-2.56,-0.94,6.80], [3.84,0.27,2.13]]), + (13, [[37.99,-136.93,957.17], [-18.82,0.88,5.08], [-0.16,-7.34,0.67], [1.90,0.17,0.59], [1.94,0.61,7.07], [2.12,1.03,-0.12]]), + (14, [[24.26,-138.06,963.16], [-17.40,-6.04,8.51], [2.59,-6.90,0.38], [2.42,1.01,0.69], [2.78,1.42,6.69], [-2.18,-0.67,-0.74]]), + (15, [[6.50,-150.31,973.05], [-8.25,-16.44,-13.42], [4.89,-4.75,2.82], [-1.08,-0.49,-0.28], [-4.82,-1.85,5.24], [-4.27,-0.82,-2.18]]), + (16, [[15.97,-149.80,957.69], [-4.35,-1.25,-14.05], [0.99,-7.39,0.35], [-1.04,-0.78,-0.85], [-6.95,-0.83,2.23], [-0.48,0.19,-0.50]]), + (17, [[8.29,-150.98,954.25], [-3.34,-0.73,-8.15], [1.18,-7.37,0.18], [0.18,0.05,0.37], [-6.71,-1.00,2.84], [0.56,-0.43,-3.27]]), + (18, [[10.77,-150.88,946.76], [5.27,-0.05,-7.15], [1.37,-7.28,1.06], [-0.12,-0.03,0.05], [-5.80,-1.71,-4.27], [2.05,0.22,-4.83]]), + (19, [[18.30,-151.09,941.26], [7.79,0.88,-2.39], [0.88,-7.45,0.16], [0.05,-0.01,-0.90], [-2.15,-0.40,-7.16], [4.52,1.49,-0.77]]), + (20, [[24.85,-149.58,941.59], [5.32,0.62,3.02], [1.33,-7.35,-0.84], [-0.35,0.01,-0.65], [3.51,1.37,-6.46], [3.43,0.58,1.19]]), + (21, [[27.85,-149.81,945.92], [3.49,-0.55,3.99], [0.33,-7.39,-1.30], [-0.75,-0.04,-0.15], [5.61,1.09,-4.76], [-0.58,-0.16,-0.31]]), + (22, [[31.64,-150.64,949.37], [5.77,-0.50,1.81], [-0.28,-7.43,-1.16], [0.32,-0.01,0.32], [2.31,1.02,-7.08], [-4.59,-0.60,-0.74]]), + (23, [[38.16,-150.55,948.48], [5.40,1.27,-4.34], [1.28,-7.40,-0.56], [1.28,0.32,-0.53], [-4.63,-0.35,-5.87], [-4.44,-1.61,3.12]]), + (24, [[40.30,-148.53,942.17], [-0.50,2.45,-7.55], [2.42,-6.73,-2.35], [1.39,0.82,-0.98], [-7.02,-2.42,-0.32], [-0.57,-0.95,1.02]]), + (25, [[36.76,-146.19,935.09], [3.27,5.38,-6.44], [4.32,-5.62,-2.50], [0.26,-0.08,1.07], [-5.50,-2.17,-4.60], [3.60,1.24,-3.41]]), + (26, [[44.60,-142.08,934.77], [8.65,3.53,1.10], [2.85,-7.00,0.02], [-1.02,-0.77,1.00], [0.83,0.31,-7.53], [3.41,1.45,-1.30]]), + (27, [[53.34,-139.44,937.21], [8.31,2.34,2.22], [2.15,-7.25,-0.38], [-0.54,-0.17,-0.42], [1.71,0.89,-7.34], [0.07,0.37,0.03]]), + (28, [[61.18,-137.39,939.22], [8.23,1.72,1.43], [1.69,-7.36,-0.86], [-0.38,-0.10,-0.17], [1.06,1.12,-7.44], [-0.84,-0.07,-0.12]]), + (29, [[69.72,-136.03,940.04], [8.42,1.51,0.05], [1.35,-7.46,-0.74], [0.30,0.21,-0.63], [-0.09,0.74,-7.58], [-3.56,-0.97,1.73]]), + (30, [[77.28,-134.50,939.34], [4.49,4.18,-8.53], [2.31,-6.92,-2.18], [-0.29,0.07,-0.48], [-6.41,-0.93,-3.83], [-3.19,-0.95,5.53]]), + (31, [[71.89,-131.27,929.11], [-6.78,1.09,-6.79], [0.09,-7.53,-1.30], [-0.44,-0.26,1.25], [-5.41,-0.97,5.25], [0.24,0.45,2.90]]), + (32, [[66.11,-131.60,925.90], [-4.09,-0.45,-4.44], [0.54,-7.64,0.28], [0.08,0.05,1.40], [-5.56,-0.21,5.14], [-0.15,0.88,-0.16]]), + (33, [[63.93,-132.09,921.07], [-3.93,-1.16,-4.37], [0.32,-7.47,1.70], [0.72,0.30,0.95], [-5.72,0.87,4.92], [0.66,0.51,0.56]]), + (34, [[58.47,-133.89,917.96], [-6.67,-3.36,-3.67], [2.29,-6.97,2.21], [2.28,0.92,-0.11], [-3.96,0.75,6.50], [2.25,0.03,1.31]]), + (35, [[51.02,-139.09,914.02], [-6.63,-6.74,0.39], [5.40,-5.25,1.13], [1.07,0.42,-1.32], [-0.59,1.02,7.59], [3.12,0.37,0.20]]), + (36, [[46.77,-145.49,918.12], [-5.05,-4.37,2.87], [4.81,-5.92,-0.55], [-1.31,-0.89,-0.94], [2.68,1.52,7.03], [1.26,-0.68,-0.12]]), + (37, [[41.95,-147.92,919.78], [-5.03,-2.38,1.94], [2.90,-7.03,-1.10], [-1.32,-0.68,-0.33], [2.77,0.01,7.18], [-0.11,-1.00,0.12]]), + (38, [[36.76,-150.21,922.00], [-5.10,-1.68,1.58], [2.03,-7.33,-1.24], [-0.51,-0.22,0.81], [2.44,-0.56,7.30], [-0.45,0.50,0.13]]), + (39, [[31.89,-151.33,922.99], [-5.71,-1.25,1.56], [1.77,-7.50,0.46], [-0.57,-0.18,0.73], [1.84,0.88,7.45], [-2.05,0.33,0.03]]), + (40, [[25.55,-152.65,925.18], [-6.28,-0.56,-2.17], [0.70,-7.71,-0.03], [-0.69,-0.09,-0.62], [-2.50,-0.25,7.31], [-3.19,-0.78,-0.83]]), + (41, [[22.17,-152.27,920.06], [-4.85,0.30,-4.20], [0.27,-7.70,-0.85], [-0.24,-0.02,0.24], [-5.02,-0.81,5.76], [2.41,0.37,-0.06]]), + (42, [[16.60,-152.11,917.51], [-6.97,0.00,2.68], [0.20,-7.74,0.51], [-0.30,-0.03,0.60], [2.77,0.54,7.21], [5.78,0.37,-0.74]]), + (43, [[13.12,-152.32,924.90], [-3.73,0.41,7.15], [-0.45,-7.75,0.21], [-0.14,-0.02,-0.16], [6.78,-0.30,3.55], [-0.23,-0.18,0.20]]), + (44, [[9.44,-151.37,931.31], [-7.88,0.19,2.81], [-0.13,-7.78,0.17], [0.49,-0.01,0.12], [2.61,0.12,7.31], [-3.70,0.33,2.08]]), + (45, [[1.23,-152.17,928.31], [-8.13,-0.72,-1.08], [0.62,-7.76,0.49], [0.09,-0.01,-0.29], [-1.06,0.40,7.71], [1.43,-0.16,-0.65]]), + (46, [[-5.97,-152.74,928.93], [-5.64,-0.31,4.39], [0.17,-7.80,-0.33], [-0.93,0.04,0.09], [4.76,-0.16,6.12], [3.98,-0.84,-4.11]]), + (47, [[-8.05,-152.70,935.12], [0.84,0.43,7.28], [-1.31,-7.67,0.60], [-1.08,0.17,0.74], [7.52,-1.34,-0.79], [0.79,-0.43,-1.11]]), + (48, [[-4.18,-151.98,940.93], [-5.50,2.85,8.02], [-2.07,-7.44,1.22], [-0.37,0.07,-0.10], [6.17,-0.96,4.57], [-3.01,0.56,4.29]]), + (49, [[-15.92,-150.23,939.85], [-11.53,2.83,0.08], [-1.87,-7.62,-0.02], [0.12,0.15,0.78], [0.04,-0.03,7.84], [0.81,0.00,-1.16]]), + (50, [[-25.87,-146.77,940.97], [-2.69,4.15,9.23], [-1.80,-7.15,2.69], [0.69,0.20,1.48], [7.25,-0.88,2.51], [1.72,-1.41,-6.49]]), + (51, [[-19.43,-146.58,946.99], [7.70,1.83,5.13], [-0.49,-7.14,3.29], [1.24,-0.13,-0.09], [4.50,-2.94,-5.70], [-0.59,-0.04,-3.45]]), + (52, [[-11.61,-143.43,950.54], [5.25,2.52,5.68], [0.83,-7.42,2.52], [0.75,-0.24,-0.87], [5.91,-1.04,-5.00], [0.83,1.41,0.57]]), + (53, [[-9.22,-141.82,956.88], [3.60,1.58,5.20], [1.22,-7.66,1.48], [-0.05,-0.13,-0.42], [6.39,0.15,-4.47], [0.12,0.28,0.10]]), + (54, [[-4.88,-140.39,960.70], [3.78,1.36,4.90], [0.78,-7.72,1.54], [0.07,-0.06,-0.65], [6.23,-0.31,-4.72], [0.53,0.53,1.66]]), + (55, [[-1.98,-139.20,966.47], [0.65,0.13,7.29], [1.42,-7.78,0.01], [0.23,-0.06,-0.88], [7.61,1.39,-0.70], [0.66,0.74,3.14]]), + (56, [[-4.15,-140.36,973.96], [-2.38,-0.65,10.17], [1.19,-7.83,-0.22], [-0.65,-0.07,-0.20], [7.50,1.09,1.83], [-0.21,-0.70,2.00]]), + (57, [[-6.44,-140.06,986.68], [-4.21,-0.33,9.07], [-0.24,-7.94,-0.40], [-0.77,0.02,-0.44], [7.09,-0.38,3.28], [-1.82,-1.02,2.46]]), + (58, [[-10.86,-140.67,991.98], [-5.80,0.04,3.85], [-0.73,-7.85,-1.03], [0.04,-0.00,-0.15], [4.33,-1.25,6.51], [-3.51,-0.15,2.18]]), + (59, [[-17.28,-140.01,993.95], [-7.30,0.18,-0.28], [-0.17,-7.94,-0.73], [0.59,-0.04,0.75], [-0.32,-0.72,7.93], [-4.07,0.69,0.16]]), + (60, [[-24.40,-140.40,991.18], [-6.25,-0.73,-3.97], [0.53,-7.94,0.63], [-0.08,0.16,1.48], [-4.27,0.24,6.69], [-3.14,0.95,-2.22]]), + (61, [[-29.47,-141.40,986.35], [-2.47,-1.37,-4.69], [-0.28,-7.62,2.38], [-1.43,0.31,0.61], [-7.02,1.29,3.32], [-0.94,0.18,-5.15]]), + (62, [[-29.90,-142.61,982.98], [1.86,-2.14,-4.74], [-2.17,-7.29,2.44], [-1.16,0.11,-0.29], [-7.10,1.03,-3.25], [0.49,-0.35,-4.87]]), + (63, [[-24.82,-145.19,978.58], [4.65,-2.18,-4.59], [-2.13,-7.58,1.44], [0.29,-0.26,-0.91], [-5.46,0.45,-5.75], [-0.33,0.23,1.00]]), + (64, [[-20.75,-146.91,974.01], [1.23,-0.70,-6.94], [-1.58,-7.84,0.51], [0.08,-0.09,-0.69], [-7.59,1.43,-1.48], [0.46,0.35,5.77]]), + (65, [[-23.39,-146.10,967.33], [-6.32,1.65,-4.01], [-2.03,-7.76,0.01], [-0.16,0.07,0.36], [-4.04,1.07,6.80], [4.83,-0.40,4.28]]), + (66, [[-30.60,-144.33,967.78], [-6.69,2.04,2.19], [-1.93,-7.69,1.27], [0.05,0.00,0.44], [2.65,0.58,7.55], [3.03,-0.35,0.34]]), + (67, [[-36.17,-142.25,971.34], [-6.59,1.94,2.27], [-1.94,-7.73,1.01], [0.04,-0.01,0.09], [2.70,0.31,7.56], [0.37,-0.02,-0.15]]), + (68, [[-43.40,-140.59,972.07], [-6.04,1.97,2.74], [-1.83,-7.71,1.48], [0.02,0.34,1.18], [3.47,0.56,7.23], [2.30,-0.41,-2.27]]), + (69, [[-47.62,-138.63,976.14], [-1.78,2.68,4.62], [-1.87,-7.07,3.39], [0.01,0.35,0.98], [7.30,-0.46,3.08], [1.72,-1.44,-3.71]]), + (70, [[-47.10,-135.98,980.16], [0.98,1.95,4.05], [-1.83,-6.90,3.76], [0.21,-0.14,-0.20], [7.55,-2.37,-0.68], [0.04,-0.76,-2.21]]), + (71, [[-45.78,-134.75,984.02], [1.92,1.94,5.58], [-1.46,-7.34,3.05], [-0.53,0.37,0.09], [7.43,-2.22,-1.79], [-0.24,0.26,1.07]]), + (72, [[-43.37,-132.13,990.97], [-1.92,7.78,7.36], [-3.78,-5.37,4.69], [-2.14,1.26,-0.06], [6.91,-1.72,3.61], [-3.47,2.54,4.15]]), + (73, [[-50.92,-122.17,992.94], [-8.28,6.98,-7.76], [-5.96,-5.08,1.79], [0.61,-1.11,-1.84], [-2.03,4.63,6.34], [-6.54,1.98,-0.43]]), + (74, [[-54.52,-122.57,980.90], [-5.10,0.46,-13.05], [-2.60,-7.66,0.75], [2.85,-1.09,0.85], [-7.02,2.66,2.84], [-2.86,-1.79,-2.31]]), + (75, [[-60.93,-121.16,967.78], [-3.40,-6.95,-12.83], [0.01,-7.18,3.88], [-1.69,1.75,1.25], [-7.80,0.86,1.60], [1.21,-0.70,-4.51]]), + (76, [[-59.94,-133.62,960.46], [4.44,-11.12,-4.92], [-6.17,-3.97,3.41], [-1.80,0.34,-0.38], [-4.46,1.19,-6.70], [1.72,-0.86,-3.60]]), + (77, [[-53.65,-142.09,958.04], [8.15,-8.95,-3.45], [-4.95,-5.68,3.06], [2.04,-1.62,-0.11], [-3.75,-0.62,-7.23], [-0.92,-0.86,0.97]]), + (78, [[-43.78,-150.90,953.55], [6.86,-6.21,-10.82], [-1.57,-7.38,3.24], [0.10,-0.47,-1.48], [-6.93,-0.36,-4.18], [-0.50,1.88,6.12]]), + (79, [[-42.79,-151.92,940.92], [-10.16,7.35,-12.87], [-4.74,-6.68,-0.07], [-1.78,0.37,-1.94], [-4.81,3.35,5.71], [1.37,1.93,5.90]]), + (80, [[-59.56,-139.32,940.87], [-10.47,7.53,-10.55], [-4.67,-6.77,-0.21], [-0.78,0.74,0.77], [-4.39,2.82,6.37], [-0.63,1.74,-4.22]]), + (81, [[-61.19,-138.43,930.23], [-0.37,-2.04,-12.19], [-5.97,-5.52,1.11], [-0.86,0.96,0.96], [-5.64,5.92,-0.83], [0.65,-0.72,-6.69]]), + (82, [[-60.05,-143.37,918.84], [6.12,-9.41,-3.11], [-6.44,-4.78,1.79], [0.25,-0.37,-0.76], [-2.75,0.78,-7.78], [3.39,-3.10,-3.06]]), + (83, [[-54.81,-148.97,924.54], [7.07,-6.60,2.05], [-5.61,-6.05,-0.17], [0.76,-0.86,-0.33], [1.38,-1.05,-8.13], [-1.61,1.40,1.58]]), + (84, [[-48.00,-154.67,922.57], [3.54,-3.72,-7.48], [-4.83,-6.61,1.00], [1.21,-0.76,-0.14], [-5.85,3.58,-4.55], [-4.06,1.81,3.83]]), + (85, [[-49.39,-154.51,914.46], [0.27,0.35,-10.67], [-3.11,-7.64,-0.33], [1.86,-0.79,-0.48], [-7.54,3.07,-0.10], [1.64,-1.57,-0.54]]), + (86, [[-46.73,-154.01,904.00], [18.99,-1.89,-1.48], [-0.78,-8.19,0.40], [1.31,-0.30,0.50], [-0.67,-0.34,-8.19], [5.19,-2.31,-4.98]]), + (87, [[-31.90,-157.00,923.20], [20.27,-2.84,5.71], [-1.28,-8.04,0.54], [1.63,0.18,0.17], [2.10,-0.86,-7.85], [-3.21,-0.77,1.42]]), + (88, [[-17.04,-158.47,917.33], [10.69,1.60,-10.94], [1.94,-7.84,0.74], [0.87,0.01,-0.11], [-5.44,-1.88,-5.58], [-1.71,0.19,-0.09]]), + (89, [[-12.92,-154.88,905.59], [14.28,1.56,-5.12], [1.01,-8.00,0.37], [-0.98,-0.09,-0.58], [-2.65,-0.69,-7.58], [1.89,1.14,-1.15]]), + (90, [[0.79,-157.22,913.22], [17.05,-0.10,-3.50], [-0.16,-8.01,-0.53], [0.24,0.09,-0.24], [-1.61,0.55,-7.83], [0.10,0.16,0.01]]), + (91, [[11.37,-154.85,899.81], [20.47,4.34,-7.04], [1.62,-7.80,-0.10], [0.67,0.24,-0.62], [-2.50,-0.42,-7.54], [-1.60,0.07,0.92]]), + (92, [[35.28,-149.96,905.73], [15.01,5.71,-13.20], [0.80,-7.50,-2.33], [1.12,0.33,0.34], [-5.36,1.17,-5.59], [-1.05,-1.38,0.95]]), + (93, [[31.51,-148.90,893.07], [11.51,6.02,-14.64], [3.17,-7.13,-0.44], [1.65,0.51,0.45], [-5.44,-2.11,-5.15], [2.20,-0.03,-0.53]]), + (94, [[53.21,-142.18,892.15], [16.13,8.56,4.60], [3.96,-6.33,-2.13], [0.42,0.20,0.80], [0.58,2.81,-7.25], [3.44,1.00,-0.61]]), + (95, [[62.43,-134.45,898.99], [11.35,7.61,6.27], [4.22,-6.47,0.22], [-1.03,-0.53,1.15], [2.81,1.59,-7.04], [-2.20,-1.80,0.66]]), + (96, [[74.83,-127.92,903.83], [13.27,2.58,-11.41], [1.59,-7.52,0.15], [-0.63,-0.25,0.20], [-4.77,-1.12,-5.79], [-4.38,-1.93,4.88]]), + (97, [[72.51,-133.32,887.20], [-12.49,-8.25,-22.65], [3.26,-6.84,0.70], [0.84,0.36,-0.04], [-5.89,-2.38,4.11], [0.64,-0.37,7.04]]), + (98, [[47.82,-142.63,864.93], [-22.72,-8.47,-7.52], [2.75,-7.00,-0.43], [0.03,0.23,-1.27], [-1.94,-1.20,7.19], [5.33,1.35,0.11]]), + (99, [[33.71,-147.84,866.62], [-7.31,-5.02,5.80], [3.02,-6.59,-1.88], [-0.71,0.24,-1.45], [4.50,0.35,5.98], [2.35,2.56,-6.78]]), + (100, [[33.45,-149.55,870.08], [6.66,-2.67,8.62], [1.91,-6.38,-3.46], [-0.81,0.03,-0.86], [5.65,3.48,-3.30], [0.80,2.08,-6.77]]), + (101, [[48.50,-149.86,877.56], [8.44,-1.40,10.88], [1.84,-6.88,-2.31], [-0.55,-0.39,1.17], [5.59,2.82,-3.97], [-1.37,-2.16,5.89]]), + (102, [[49.17,-151.34,885.88], [-14.13,-2.76,6.71], [0.94,-7.25,-1.01], [-0.57,0.33,-0.41], [3.26,-0.51,6.64], [-3.09,-3.47,6.17]]), + (103, [[30.33,-151.82,877.70], [-17.16,1.53,-4.96], [0.92,-5.49,-4.89], [-1.51,-0.14,0.40], [-1.94,-4.93,5.18], [0.64,-0.13,0.13]]), + (104, [[16.36,-149.06,875.57], [-10.97,1.71,5.38], [-1.80,-6.98,-1.46], [-0.54,-0.73,1.97], [2.83,-2.08,6.45], [2.86,1.80,-0.06]]), + (105, [[11.69,-148.72,883.92], [-10.14,1.00,8.83], [-0.94,-7.28,-0.26], [0.66,-0.15,1.09], [4.71,-0.80,5.50], [-0.40,1.32,0.04]]), + (106, [[-3.83,-146.99,890.11], [-14.28,1.09,0.55], [-0.52,-7.22,0.83], [0.36,0.01,-0.26], [0.34,0.81,7.24], [-1.67,-0.06,0.66]]), + (107, [[-14.79,-146.52,886.71], [-10.85,0.22,0.51], [-0.16,-7.24,-0.38], [0.73,0.03,-0.30], [0.33,-0.39,7.23], [2.18,0.02,-0.94]]), + (108, [[-23.91,-146.55,890.53], [-7.40,-0.95,6.58], [0.98,-7.16,0.07], [-0.52,0.10,0.63], [4.68,0.69,5.37], [0.75,0.45,-0.15]]), + (109, [[-28.03,-148.18,898.37], [-13.61,2.90,3.80], [-1.23,-7.02,0.96], [-1.43,0.37,-0.84], [2.04,0.58,6.86], [-3.99,-0.65,0.17]]), + (110, [[-42.02,-140.32,889.27], [-9.93,7.70,-9.68], [-1.44,-6.12,-3.39], [0.84,-0.04,-0.89], [-5.33,-1.24,4.49], [-3.62,0.11,-4.10]]), + (111, [[-47.83,-133.82,880.59], [1.67,2.81,-9.02], [0.19,-6.80,-2.08], [0.02,-0.24,2.82], [-6.87,0.17,-1.22], [2.63,-0.65,-5.17]]), + (112, [[-43.36,-134.64,876.97], [7.37,-1.12,-1.77], [-0.61,-6.83,1.80], [-0.49,-0.09,1.49], [-1.84,-1.59,-6.65], [3.37,-0.42,-3.09]]), + (113, [[-34.80,-135.76,878.37], [7.33,-0.80,-0.16], [-0.76,-7.02,0.28], [-0.51,0.02,-0.71], [-0.18,-0.26,-7.06], [-2.44,1.36,1.66]]), + (114, [[-29.32,-136.24,877.18], [3.39,-0.80,-5.31], [-1.57,-6.87,0.04], [-0.23,0.05,0.03], [-5.67,1.27,-3.82], [-3.22,0.72,3.41]]), + (115, [[-30.61,-136.87,870.77], [-0.25,-0.25,-5.29], [-1.19,-6.91,0.38], [0.28,-0.03,-0.03], [-6.79,1.18,0.27], [0.35,-0.33,-1.21]]), + (116, [[-30.23,-136.86,867.08], [2.79,-0.45,-3.89], [-0.94,-6.95,0.14], [0.33,-0.03,-0.12], [-5.57,0.67,-4.07], [3.30,-0.63,-3.48]]), + (117, [[-25.37,-137.76,865.06], [8.76,-0.50,1.85], [-0.44,-6.98,0.18], [0.24,0.00,-0.17], [1.43,-0.27,-6.84], [3.73,-0.35,-1.77]]), + (118, [[-17.01,-136.93,873.25], [9.54,-0.88,-1.35], [-0.71,-6.91,-0.47], [-0.79,0.17,0.25], [-0.92,0.56,-6.87], [-3.99,0.94,2.86]]), + (119, [[-14.62,-138.10,867.37], [2.47,-1.15,-8.78], [-1.88,-6.66,0.34], [1.25,0.41,-0.04], [-6.32,1.68,-1.99], [-1.18,0.21,1.02]]), + (120, [[-13.21,-138.67,858.26], [15.02,8.84,-1.86], [3.37,-5.94,-1.02], [3.02,0.32,-0.46], [-1.14,0.51,-6.80], [4.30,-0.76,-2.96]]), + (121, [[-2.01,-129.09,875.92], [14.73,5.57,5.54], [2.30,-6.43,0.36], [-3.38,0.09,1.42], [2.26,0.45,-6.45], [-4.26,0.28,1.85]]), + (122, [[5.71,-128.31,873.45], [4.22,-3.80,-6.92], [-2.33,-6.10,1.93], [1.54,1.12,0.79], [-5.49,0.89,-3.83], [-2.90,-1.92,4.89]]), + (123, [[3.86,-133.45,867.51], [-1.78,-5.98,-7.59], [4.85,-4.16,2.14], [1.96,0.65,1.01], [-4.52,-3.36,3.71], [0.30,-2.10,1.25]]), + (124, [[2.44,-139.69,858.80], [7.02,-5.19,-6.23], [0.11,-5.15,4.40], [-1.69,-0.89,0.21], [-5.06,-2.92,-3.28], [2.22,0.25,-4.49]]), + (125, [[11.98,-140.15,859.35], [17.70,2.25,-1.14], [0.95,-6.06,2.79], [1.39,-0.39,-2.08], [-0.04,-2.82,-6.13], [2.19,0.11,-1.39]]), + (126, [[35.30,-132.99,854.91], [8.74,9.55,-15.22], [4.05,-5.23,-0.96], [0.82,0.89,-2.82], [-4.43,-2.65,-4.20], [-1.33,-1.30,4.05]]), + (127, [[29.93,-128.55,843.92], [-12.95,5.12,-19.36], [3.68,-4.21,-3.57], [-1.41,0.00,-0.87], [-4.19,-4.93,1.49], [1.70,-0.30,5.11]]), + (128, [[9.39,-125.79,820.06], [-27.75,1.44,5.84], [-0.47,-6.58,-0.63], [-1.27,-0.92,1.78], [1.32,-0.72,6.46], [4.74,2.19,-0.36]]), + (129, [[4.65,-126.74,840.92], [-6.02,1.18,15.73], [0.13,-6.59,0.55], [-0.73,0.09,0.19], [6.11,0.31,2.32], [-2.11,0.21,1.57]]), + (130, [[0.04,-125.01,849.26], [-9.24,1.85,1.00], [-1.26,-6.45,0.32], [0.68,0.07,-0.54], [0.75,0.18,6.55], [-5.74,-0.82,-0.60]]), + (131, [[-4.44,-124.79,843.15], [-5.02,0.46,-16.66], [1.26,-6.43,-0.56], [1.98,0.08,-0.42], [-6.09,-1.34,1.79], [-4.27,-1.02,-2.57]]), + (132, [[-4.10,-124.24,817.80], [-14.82,-5.98,-12.69], [2.23,-6.13,0.29], [-0.08,-0.02,0.18], [-3.88,-1.17,5.07], [6.33,1.59,-0.02]]), + (133, [[-13.82,-128.40,823.84], [-7.49,-1.58,13.51], [1.55,-6.33,0.12], [-0.55,0.00,0.71], [5.49,1.40,3.20], [4.92,1.22,-2.01]]), + (134, [[-15.54,-126.40,839.81], [-2.26,3.63,12.78], [1.06,-6.11,1.92], [-1.86,0.05,-0.36], [6.21,1.31,0.73], [-0.95,-1.43,1.43]]), + (135, [[-17.86,-122.19,848.91], [-6.97,2.29,6.40], [-1.90,-6.17,0.14], [0.21,-0.11,-0.73], [4.06,-1.15,4.85], [-5.50,-0.82,1.29]]), + (136, [[-24.46,-122.95,849.04], [-11.05,-2.26,-14.69], [1.03,-6.35,0.20], [1.60,-0.05,0.47], [-5.05,-0.70,3.90], [-6.40,0.95,-0.75]]), + (137, [[-23.98,-124.71,821.70], [-13.90,-3.45,-17.21], [-1.09,-5.98,2.08], [-0.11,-0.11,-0.76], [-4.88,2.11,3.53], [5.05,-0.43,0.87]]), + (138, [[-38.60,-127.22,820.18], [-12.58,-0.43,8.78], [-0.02,-6.39,-0.33], [-0.17,-0.02,-0.17], [3.67,-0.29,5.24], [4.86,-1.54,-2.07]]), + (139, [[-42.52,-125.65,832.78], [1.33,2.91,14.25], [-1.25,-6.10,1.37], [-0.03,0.21,1.19], [6.11,-1.31,-0.30], [1.08,-0.26,-3.49]]), + (140, [[-35.80,-121.92,845.73], [4.20,3.78,10.20], [0.01,-5.96,2.20], [-0.16,0.23,0.57], [5.88,-0.78,-2.13], [0.09,0.03,0.69]]), + (141, [[-33.62,-118.72,852.84], [0.50,3.01,6.47], [-0.93,-5.65,2.70], [-0.79,-0.03,-0.57], [6.15,-1.01,0.00], [-0.33,-0.03,2.50]]), + (142, [[-34.44,-116.11,858.28], [-2.64,1.81,5.04], [-1.71,-5.94,1.23], [0.58,-0.29,-1.41], [5.32,-0.89,3.11], [-1.83,0.37,2.71]]), + (143, [[-38.38,-115.33,862.17], [-6.05,-0.34,2.35], [0.22,-6.28,-0.34], [1.37,-0.09,-0.25], [2.28,-0.24,5.85], [-4.21,0.45,0.94]]), + (144, [[-44.50,-116.93,861.58], [-11.59,-3.81,-10.16], [1.11,-6.09,1.02], [0.44,0.12,0.61], [-4.13,0.03,4.70], [-4.54,0.05,-0.79]]), + (145, [[-51.78,-120.72,839.03], [-15.88,-5.45,-10.36], [1.83,-5.97,0.32], [-1.36,0.27,0.87], [-3.22,-0.70,5.31], [4.29,0.49,0.09]]), + (146, [[-64.65,-124.35,841.48], [-11.51,0.42,9.85], [0.15,-6.19,0.44], [-0.55,0.33,1.54], [3.97,0.43,4.63], [4.38,-0.52,-2.90]]), + (147, [[-69.37,-119.95,854.33], [5.11,4.21,16.62], [-1.33,-5.74,1.87], [0.69,0.27,0.73], [5.67,-1.74,-1.31], [0.56,-1.58,-4.18]]), + (148, [[-55.63,-118.57,867.17], [8.19,15.70,8.57], [0.71,-2.34,3.60], [0.89,1.63,1.44], [4.28,-1.31,-1.70], [0.13,0.20,0.14]]), + (149, [[-52.38,-100.90,869.76], [4.76,24.01,12.61], [0.49,-2.47,4.53], [-0.28,-0.30,-1.61], [4.60,-0.51,-0.77], [-2.29,1.10,4.28]]), + (150, [[-41.73,-76.29,892.90], [-14.02,14.24,19.65], [-3.50,-2.99,-0.33], [3.24,-2.89,0.75], [1.93,-2.62,3.27], [-5.09,5.86,6.61]]), + (151, [[-58.69,-78.02,896.31], [-2.60,-3.83,-1.89], [4.61,-2.18,-1.92], [3.24,-2.89,0.75], [0.64,-2.74,4.67], [-5.09,5.86,6.61]]) + ] ), 'userAnnotationGroups': [ { @@ -817,52 +819,53 @@ class MeshType_3d_smallintestine1(Scaffold_base): }, 'meshEdits': exnode_string_from_nodeset_field_parameters( [ Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3 ], [ - (1, [ [ -2.30, 18.50, -4.40 ], [ -4.20, -0.80, 3.70 ], [ 0.00, 0.60, 0.00 ], [ 0.00, 0.11, 0.00 ], [ -0.33, 0.01, -0.50 ], [ 0.00, 0.00, 0.50 ] ] ), - (2, [ [ -8.60, 16.30, -0.40 ], [ -7.10, -2.70, 1.60 ], [ 0.00, 0.73, 0.00 ], [ 0.00, 0.14, 0.00 ], [ 0.08, 0.09, -0.72 ], [ 0.00, 0.00, 0.50 ] ] ), - (3, [ [ -18.30, 12.60, -1.50 ], [ -6.40, -1.70, -3.80 ], [ 0.00, 0.90, 0.00 ], [ 0.00, 0.13, 0.00 ], [ 0.61, 0.04, -0.65 ], [ 0.00, 0.00, 0.50 ] ] ), - (4, [ [ -15.60, 13.70, -6.10 ], [ 7.00, 2.10, -1.80 ], [ 0.00, 1.00, 0.00 ], [ 0.00, 0.05, 0.00 ], [ 0.50, 0.08, 0.86 ], [ 0.00, 0.00, 0.50 ] ] ), - (5, [ [ -9.30, 14.80, -4.90 ], [ 4.70, 0.70, 1.80 ], [ 0.00, 1.00, 0.00 ], [ 0.00, 0.00, 0.00 ], [ -0.23, 0.02, 0.97 ], [ 0.00, 0.00, 0.50 ] ] ), - (6, [ [ -3.90, 15.70, -3.00 ], [ 4.30, 0.70, 2.00 ], [ 0.00, 1.00, 0.00 ], [ 0.17, -1.19, 0.09 ], [ -0.29, 0.02, 0.96 ], [ 0.00, 0.00, 0.50 ] ] ), - (7, [ [ -3.40, 13.40, -2.80 ], [ -4.10, -0.70, -1.70 ], [ 0.28, -0.95, 0.14 ], [ 0.03, -1.11, 0.04 ], [ -0.23, 0.05, 0.97 ], [ 0.00, 0.00, 0.50 ] ] ), - (8, [ [ -7.60, 12.40, -4.60 ], [ -3.70, -0.80, -0.90 ], [ 0.00, -1.00, 0.05 ], [ -0.14, -0.02, -0.04 ], [ -0.43, 0.01, 0.90 ], [ 0.00, 0.00, 0.50 ] ] ), - (9, [ [ -11.60, 11.60, -5.70 ], [ -4.20, -0.70, -0.20 ], [ 0.00, -1.00, 0.05 ], [ 0.09, 0.01, -0.08 ], [ -0.21, 0.03, 0.98 ], [ 0.00, 0.00, 0.50 ] ] ), - (10, [ [ -16.50, 11.70, -3.90 ], [ -1.00, 0.20, 5.80 ], [ 0.21, -0.97, -0.14 ], [ -0.04, 0.05, -0.25 ], [ 0.98, 0.17, -0.04 ], [ 0.00, 0.00, 0.50 ] ] ), - (11, [ [ -12.50, 11.70, -1.40 ], [ 3.60, 0.10, 0.60 ], [ -0.06, -0.89, -0.45 ], [ -0.31, 0.12, -0.21 ], [ -0.02, 0.43, -0.90 ], [ 0.00, 0.00, 0.50 ] ] ), - (12, [ [ -6.80, 11.80, -0.60 ], [ 2.90, 0.00, 0.70 ], [ -0.42, -0.72, -0.54 ], [ -0.16, 1.09, 0.46 ], [ -0.35, 0.43, -0.83 ], [ 0.00, 0.00, 0.50 ] ] ), - (13, [ [ -6.40, 9.80, -1.60 ], [ -2.90, -0.30, -1.40 ], [ -0.48, 0.85, 0.21 ], [ 0.07, 0.85, 0.47 ], [ 0.12, 0.37, -0.92 ], [ 0.00, 0.00, 0.50 ] ] ), - (14, [ [ -9.50, 9.50, -2.90 ], [ -4.60, 0.00, -1.80 ], [ -0.26, 0.89, 0.37 ], [ 0.21, 0.05, 0.07 ], [ 0.22, 0.44, -0.87 ], [ 0.00, 0.00, 0.50 ] ] ), - (15, [ [ -14.30, 9.40, -4.60 ], [ -3.40, 0.10, -1.60 ], [ -0.06, 0.95, 0.30 ], [ 0.14, 0.05, -0.18 ], [ 0.46, 0.29, -0.84 ], [ 0.00, 0.00, 0.50 ] ] ), - (16, [ [ -19.00, 9.40, -2.90 ], [ 0.30, 0.20, 6.70 ], [ 0.00, 1.00, 0.00 ], [ 0.17, -0.03, 0.03 ], [ -1.00, 0.00, 0.07 ], [ 0.00, 0.00, 0.50 ] ] ), - (17, [ [ -14.50, 9.70, 0.20 ], [ 3.60, -1.20, 1.00 ], [ 0.28, 0.89, 0.36 ], [ 0.37, -0.41, 0.31 ], [ -0.26, -0.29, 0.92 ], [ 0.00, 0.00, 0.50 ] ] ), - (18, [ [ -12.60, 7.70, 0.70 ], [ 0.60, -2.70, 0.20 ], [ 0.69, 0.32, 0.65 ], [ 0.15, -0.68, 0.19 ], [ -0.68, 0.03, 0.73 ], [ 0.00, 0.00, 0.50 ] ] ), - (19, [ [ -13.10, 3.80, 0.30 ], [ -4.00, -3.60, -1.50 ], [ 0.47, -0.52, 0.71 ], [ -0.73, -0.40, -0.16 ], [ -0.46, 0.51, 0.73 ], [ 0.00, 0.00, 0.50 ] ] ), - (20, [ [ -15.20, 5.10, -0.80 ], [ 6.00, 6.90, 1.80 ], [ -0.87, -0.39, 0.29 ], [ -0.53, 0.27, 0.04 ], [ -0.22, -0.94, 0.24 ], [ 0.00, 0.00, 0.50 ] ] ), - (21, [ [ -17.30, 6.90, -1.00 ], [ -2.50, 0.00, -0.40 ], [ -0.69, 0.00, 0.73 ], [ -0.05, -0.05, -0.12 ], [ -0.55, 0.83, -0.09 ], [ 0.00, 0.00, 0.50 ] ] ), - (22, [ [ -19.90, 6.80, -2.50 ], [ -1.50, -1.10, -3.40 ], [ -0.91, -0.35, 0.20 ], [ 0.18, -0.33, -0.70 ], [ -0.48, 0.80, -0.36 ], [ 0.00, 0.00, 0.50 ] ] ), - (23, [ [ -17.20, 6.30, -5.10 ], [ 4.00, 0.80, -1.30 ], [ -0.20, -0.64, -0.74 ], [ 0.52, -0.04, -0.62 ], [ -0.41, 0.74, -0.54 ], [ 0.00, 0.00, 0.50 ] ] ), - (24, [ [ -12.20, 7.80, -6.80 ], [ 4.80, 1.70, -0.30 ], [ 0.06, -0.35, -0.93 ], [ 0.24, 0.14, -0.07 ], [ -0.34, 0.87, -0.35 ], [ 0.00, 0.00, 0.50 ] ] ), - (25, [ [ -7.90, 9.60, -6.50 ], [ 3.70, 1.70, 0.70 ], [ 0.28, -0.34, -0.90 ], [ -0.23, 0.13, 0.01 ], [ -0.35, 0.84, -0.42 ], [ 0.00, 0.00, 0.50 ] ] ), - (26, [ [ -3.80, 10.30, -5.50 ], [ 3.80, -2.70, -0.10 ], [ -0.39, -0.09, -0.92 ], [ -0.22, 0.47, 0.06 ], [ 0.33, 0.90, -0.29 ], [ 0.00, 0.00, 0.50 ] ] ), - (27, [ [ -5.30, 7.60, -6.40 ], [ -3.50, -1.00, -1.30 ], [ -0.21, 0.58, -0.79 ], [ -0.10, 0.22, 0.09 ], [ 0.12, -0.72, -0.68 ], [ 0.00, 0.00, 0.50 ] ] ), - (28, [ [ -9.00, 6.40, -7.30 ], [ -3.20, -1.30, 1.90 ], [ -0.60, 0.33, -0.73 ], [ -0.33, -0.33, 0.51 ], [ 0.06, -0.89, -0.46 ], [ 0.00, 0.00, 0.50 ] ] ), - (29, [ [ -11.60, 4.00, -2.00 ], [ 5.60, -0.20, 4.30 ], [ -0.82, -0.14, 0.55 ], [ 0.58, -0.22, 0.77 ], [ -0.18, -0.93, -0.32 ], [ 0.00, 0.00, 0.50 ] ] ), - (30, [ [ -5.90, 5.00, -3.10 ], [ 4.10, 1.20, -1.60 ], [ 0.46, -0.14, 0.88 ], [ -0.22, -0.22, -0.11 ], [ 0.25, -0.93, -0.27 ], [ 0.00, 0.00, 0.50 ] ] ), - (31, [ [ -2.50, 6.00, -3.80 ], [ 3.60, 0.70, 3.20 ], [ -0.71, -0.50, 0.50 ], [ -0.65, 0.12, -0.73 ], [ 0.20, -0.87, -0.44 ], [ 0.00, 0.00, 0.50 ] ] ), - (32, [ [ -4.10, 3.20, -0.40 ], [ -3.50, -1.70, 2.60 ], [ -0.65, 0.26, -0.71 ], [ 0.19, 0.53, -0.71 ], [ 0.12, -0.89, -0.43 ], [ 0.00, 0.00, 0.50 ] ] ), - (33, [ [ -9.70, 1.70, 2.30 ], [ -7.90, -1.00, 1.00 ], [ -0.30, 0.51, -0.81 ], [ 0.69, 0.07, 0.25 ], [ -0.09, -0.85, -0.52 ], [ 0.00, 0.00, 0.50 ] ] ), - (34, [ [ -19.00, 0.60, -0.40 ], [ 0.20, 3.70, -6.80 ], [ 0.96, 0.29, 0.00 ], [ 0.12, -0.28, 0.90 ], [ 0.26, -0.76, -0.59 ], [ 0.00, 0.00, 0.50 ] ] ), - (35, [ [ -13.90, 2.30, -5.80 ], [ 4.40, 0.60, -1.10 ], [ 0.20, -0.04, 0.98 ], [ -0.57, -0.13, 0.44 ], [ 0.08, -1.00, -0.06 ], [ 0.00, 0.00, 0.50 ] ] ), - (36, [ [ -7.70, 1.20, -4.60 ], [ 3.90, -3.40, 1.50 ], [ -0.22, 0.00, 0.98 ], [ -0.31, 0.34, -0.17 ], [ -0.54, -0.84, -0.11 ], [ 0.00, 0.00, 0.50 ] ] ), - (37, [ [ -4.80, -4.00, -1.30 ], [ -4.20, -3.30, 3.10 ], [ -0.40, 0.67, 0.62 ], [ 0.01, 0.39, -0.20 ], [ -0.82, 0.10, -0.56 ], [ 0.00, 0.00, 0.50 ] ] ), - (38, [ [ -10.90, -6.10, -0.60 ], [ -5.30, -1.20, -0.90 ], [ -0.21, 0.81, 0.55 ], [ 0.05, 0.11, -0.14 ], [ 0.07, 0.58, -0.81 ], [ 0.00, 0.00, 0.50 ] ] ), - (39, [ [ -19.90, -6.40, -5.50 ], [ -0.30, 1.70, -10.50 ], [ -0.39, 0.87, 0.30 ], [ 0.06, 0.09, -0.23 ], [ 0.91, 0.37, 0.19 ], [ 0.00, 0.00, 0.50 ] ] ), - (40, [ [ -10.70, -3.20, -8.80 ], [ 7.80, 0.40, 0.10 ], [ -0.09, 0.99, 0.09 ], [ -0.32, -0.44, -0.23 ], [ -0.05, -0.10, 0.99 ], [ 0.00, 0.00, 0.50 ] ] ), - (41, [ [ -1.20, -1.90, -7.30 ], [ 0.80, 8.10, 2.50 ], [ -0.99, 0.03, -0.16 ], [ 0.29, -0.98, -0.16 ], [ -0.17, -0.38, 0.91 ], [ 0.00, 0.00, 0.50 ] ] ), - (42, [ [ -6.30, 0.50, -8.10 ], [ -9.80, -1.20, 0.50 ], [ 0.10, -0.96, -0.25 ], [ 0.58, -0.56, -0.12 ], [ 0.08, -0.25, 0.97 ], [ 0.00, 0.00, 0.50 ] ] ), - (43, [ [ -16.00, -0.70, -7.40 ], [ -7.60, 1.20, 1.50 ], [ -0.05, -0.91, -0.41 ], [ -0.62, 0.61, 0.13 ], [ 0.28, -0.43, 0.86 ], [ 0.00, 0.00, 0.50 ] ] ), - (44, [ [ -20.50, 2.30, -6.10 ], [ 3.50, 7.20, -2.90 ], [ -0.99, 0.09, -0.09 ], [ -0.21, 0.77, -0.11 ], [ -0.17, 0.12, 0.98 ], [ 0.00, 0.00, 0.50 ] ] ), - (45, [ [ -11.40, 2.60, -10.10 ], [ 10.40, 1.50, -0.20 ], [ -0.08, 0.51, -0.86 ], [ 0.49, 0.10, -0.38 ], [ -0.10, 0.85, 0.51 ], [ 0.00, 0.00, 0.50 ] ] ), - (46, [ [ -3.80, 4.20, -7.30 ], [ 3.50, 0.90, 2.70 ], [ 0.07, 0.36, -0.93 ], [ -0.19, -0.40, 0.24 ], [ -0.73, 0.68, 0.01 ], [ 0.00, 0.00, 0.50 ] ] ) ] ), + (1, [[-2.30,18.50,-4.40], [-4.20,-0.80,3.70], [0.00,0.70,0.00], [0.00,0.11,0.00], [-0.39,0.01,-0.58], [0.00,0.00,0.50]]), + (2, [[-8.60,16.30,-0.40], [-7.10,-2.70,1.60], [0.00,0.83,0.00], [0.00,0.14,0.00], [0.09,0.10,-0.82], [0.00,0.00,0.50]]), + (3, [[-18.30,12.60,-1.50], [-6.40,-1.70,-3.80], [0.00,1.00,0.00], [0.00,0.13,0.00], [0.68,0.04,-0.72], [0.00,0.00,0.50]]), + (4, [[-15.60,13.70,-6.10], [7.00,2.10,-1.80], [0.00,1.10,0.00], [0.00,0.05,0.00], [0.55,0.09,0.95], [0.00,0.00,0.50]]), + (5, [[-9.30,14.80,-4.90], [4.70,0.70,1.80], [0.00,1.10,0.00], [0.00,0.00,0.00], [-0.25,0.02,1.07], [0.00,0.00,0.50]]), + (6, [[-3.90,15.70,-3.00], [4.30,0.70,2.00], [0.00,1.10,0.00], [0.17,-1.19,0.09], [-0.32,0.02,1.06], [0.00,0.00,0.50]]), + (7, [[-3.40,13.40,-2.80], [-4.10,-0.70,-1.70], [0.31,-1.04,0.15], [0.03,-1.11,0.04], [-0.25,0.06,1.07], [0.00,0.00,0.50]]), + (8, [[-7.60,12.40,-4.60], [-3.70,-0.80,-0.90], [0.00,-1.10,0.05], [-0.14,-0.02,-0.04], [-0.47,0.01,0.99], [0.00,0.00,0.50]]), + (9, [[-11.60,11.60,-5.70], [-4.20,-0.70,-0.20], [0.00,-1.10,0.05], [0.09,0.01,-0.08], [-0.23,0.03,1.08], [0.00,0.00,0.50]]), + (10, [[-16.50,11.70,-3.90], [-1.00,0.20,5.80], [0.23,-1.07,-0.15], [-0.04,0.05,-0.25], [1.08,0.19,-0.04], [0.00,0.00,0.50]]), + (11, [[-12.50,11.70,-1.40], [3.60,0.10,0.60], [-0.07,-0.98,-0.50], [-0.31,0.12,-0.21], [-0.02,0.47,-0.99], [0.00,0.00,0.50]]), + (12, [[-6.80,11.80,-0.60], [2.90,0.00,0.70], [-0.46,-0.79,-0.59], [-0.16,1.09,0.46], [-0.39,0.47,-0.91], [0.00,0.00,0.50]]), + (13, [[-6.40,9.80,-1.60], [-2.90,-0.30,-1.40], [-0.53,0.94,0.23], [0.07,0.85,0.47], [0.13,0.41,-1.01], [0.00,0.00,0.50]]), + (14, [[-9.50,9.50,-2.90], [-4.60,0.00,-1.80], [-0.29,0.98,0.41], [0.21,0.05,0.07], [0.24,0.48,-0.96], [0.00,0.00,0.50]]), + (15, [[-14.30,9.40,-4.60], [-3.40,0.10,-1.60], [-0.07,1.05,0.33], [0.14,0.05,-0.18], [0.51,0.32,-0.92], [0.00,0.00,0.50]]), + (16, [[-19.00,9.40,-2.90], [0.30,0.20,6.70], [0.00,1.10,0.00], [0.17,-0.03,0.03], [-1.10,0.00,0.08], [0.00,0.00,0.50]]), + (17, [[-14.50,9.70,0.20], [3.60,-1.20,1.00], [0.31,0.98,0.40], [0.37,-0.41,0.31], [-0.29,-0.32,1.01], [0.00,0.00,0.50]]), + (18, [[-12.60,7.70,0.70], [0.60,-2.70,0.20], [0.76,0.35,0.71], [0.15,-0.68,0.19], [-0.75,0.03,0.80], [0.00,0.00,0.50]]), + (19, [[-13.10,3.80,0.30], [-4.00,-3.60,-1.50], [0.52,-0.57,0.78], [-0.73,-0.40,-0.16], [-0.51,0.56,0.80], [0.00,0.00,0.50]]), + (20, [[-15.20,5.10,-0.80], [6.00,6.90,1.80], [-0.96,-0.43,0.32], [-0.53,0.27,0.04], [-0.24,-1.03,0.26], [0.00,0.00,0.50]]), + (21, [[-17.30,6.90,-1.00], [-2.50,0.00,-0.40], [-0.76,0.00,0.80], [-0.05,-0.05,-0.12], [-0.61,0.91,-0.10], [0.00,0.00,0.50]]), + (22, [[-19.90,6.80,-2.50], [-1.50,-1.10,-3.40], [-1.00,-0.39,0.22], [0.18,-0.33,-0.70], [-0.53,0.88,-0.40], [0.00,0.00,0.50]]), + (23, [[-17.20,6.30,-5.10], [4.00,0.80,-1.30], [-0.22,-0.70,-0.81], [0.52,-0.04,-0.62], [-0.45,0.81,-0.59], [0.00,0.00,0.50]]), + (24, [[-12.20,7.80,-6.80], [4.80,1.70,-0.30], [0.07,-0.39,-1.02], [0.24,0.14,-0.07], [-0.37,0.96,-0.39], [0.00,0.00,0.50]]), + (25, [[-7.90,9.60,-6.50], [3.70,1.70,0.70], [0.31,-0.37,-0.99], [-0.23,0.13,0.01], [-0.38,0.92,-0.46], [0.00,0.00,0.50]]), + (26, [[-3.80,10.30,-5.50], [3.80,-2.70,-0.10], [-0.43,-0.10,-1.01], [-0.22,0.47,0.06], [0.36,0.99,-0.32], [0.00,0.00,0.50]]), + (27, [[-5.30,7.60,-6.40], [-3.50,-1.00,-1.30], [-0.23,0.64,-0.87], [-0.10,0.22,0.09], [0.13,-0.79,-0.75], [0.00,0.00,0.50]]), + (28, [[-9.00,6.40,-7.30], [-3.20,-1.30,1.90], [-0.66,0.36,-0.80], [-0.33,-0.33,0.51], [0.07,-0.98,-0.51], [0.00,0.00,0.50]]), + (29, [[-11.60,4.00,-2.00], [5.60,-0.20,4.30], [-0.90,-0.15,0.61], [0.58,-0.22,0.77], [-0.20,-1.02,-0.35], [0.00,0.00,0.50]]), + (30, [[-5.90,5.00,-3.10], [4.10,1.20,-1.60], [0.51,-0.15,0.97], [-0.22,-0.22,-0.11], [0.27,-1.02,-0.30], [0.00,0.00,0.50]]), + (31, [[-2.50,6.00,-3.80], [3.60,0.70,3.20], [-0.78,-0.55,0.55], [-0.65,0.12,-0.73], [0.22,-0.96,-0.48], [0.00,0.00,0.50]]), + (32, [[-4.10,3.20,-0.40], [-3.50,-1.70,2.60], [-0.72,0.29,-0.78], [0.19,0.53,-0.71], [0.13,-0.98,-0.47], [0.00,0.00,0.50]]), + (33, [[-9.70,1.70,2.30], [-7.90,-1.00,1.00], [-0.33,0.56,-0.89], [0.69,0.07,0.25], [-0.10,-0.93,-0.57], [0.00,0.00,0.50]]), + (34, [[-19.00,0.60,-0.40], [0.20,3.70,-6.80], [1.06,0.32,0.00], [0.12,-0.28,0.90], [0.29,-0.84,-0.65], [0.00,0.00,0.50]]), + (35, [[-13.90,2.30,-5.80], [4.40,0.60,-1.10], [0.22,-0.04,1.08], [-0.57,-0.13,0.44], [0.09,-1.10,-0.07], [0.00,0.00,0.50]]), + (36, [[-7.70,1.20,-4.60], [3.90,-3.40,1.50], [-0.24,0.00,1.08], [-0.31,0.34,-0.17], [-0.59,-0.92,-0.12], [0.00,0.00,0.50]]), + (37, [[-4.80,-4.00,-1.30], [-4.20,-3.30,3.10], [-0.44,0.74,0.68], [0.01,0.39,-0.20], [-0.90,0.11,-0.62], [0.00,0.00,0.50]]), + (38, [[-10.90,-6.10,-0.60], [-5.30,-1.20,-0.90], [-0.23,0.89,0.60], [0.05,0.11,-0.14], [0.08,0.64,-0.89], [0.00,0.00,0.50]]), + (39, [[-19.90,-6.40,-5.50], [-0.30,1.70,-10.50], [-0.43,0.96,0.33], [0.06,0.09,-0.23], [1.00,0.41,0.21], [0.00,0.00,0.50]]), + (40, [[-10.70,-3.20,-8.80], [7.80,0.40,0.10], [-0.10,1.09,0.10], [-0.32,-0.44,-0.23], [-0.06,-0.11,1.09], [0.00,0.00,0.50]]), + (41, [[-1.20,-1.90,-7.30], [0.80,8.10,2.50], [-1.09,0.03,-0.18], [0.29,-0.98,-0.16], [-0.19,-0.42,1.00], [0.00,0.00,0.50]]), + (42, [[-6.30,0.50,-8.10], [-9.80,-1.20,0.50], [0.11,-1.06,-0.28], [0.58,-0.56,-0.12], [0.09,-0.27,1.07], [0.00,0.00,0.50]]), + (43, [[-16.00,-0.70,-7.40], [-7.60,1.20,1.50], [-0.06,-1.00,-0.45], [-0.62,0.61,0.13], [0.31,-0.47,0.95], [0.00,0.00,0.50]]), + (44, [[-20.50,2.30,-6.10], [3.50,7.20,-2.90], [-1.09,0.10,-0.10], [-0.21,0.77,-0.11], [-0.19,0.13,1.08], [0.00,0.00,0.50]]), + (45, [[-11.40,2.60,-10.10], [10.40,1.50,-0.20], [-0.09,0.56,-0.95], [0.49,0.10,-0.38], [-0.11,0.94,0.56], [0.00,0.00,0.50]]), + (46, [[-3.80,4.20,-7.30], [3.50,0.90,2.70], [0.08,0.40,-1.02], [-0.19,-0.40,0.24], [-0.80,0.75,0.01], [0.00,0.00,0.50]]) + ] ), 'userAnnotationGroups': [ { @@ -928,7 +931,7 @@ def getDefaultOptions(cls, parameterSetName='Default'): 'Refine number of elements through wall': 1 } if 'Cattle 1' in parameterSetName: - options['Number of segments'] = 300 + options['Number of segments'] = 400 options['Wall thickness'] = 2.0 elif 'Mouse 1' in parameterSetName: options['Number of segments'] = 100 @@ -1233,7 +1236,7 @@ def generateBaseMesh(cls, region, options): # Create coordinates and derivatives xList, d1List, d2List, d3List, curvatureList = tubemesh.extrudeSurfaceCoordinates(xExtrude, d1Extrude, d2Extrude, d3UnitExtrude, [wallThickness]*(elementsCountAlong+1), relativeThicknessList, - elementsCountAround, elementsCountAlong, elementsCountThroughWall, transitElementList, outward=True) + elementsCountAround, elementsCountAlong, elementsCountThroughWall, transitElementList, outward=False) flatWidthList, xiList = smallIntestineSegmentTubeMeshInnerPoints.getFlatWidthAndXiList() From 39ffbbf0f2f93c271c23ff0c5a247000e6edb57a Mon Sep 17 00:00:00 2001 From: mlin865 Date: Wed, 6 Sep 2023 17:30:23 +1200 Subject: [PATCH 15/24] Add T-junctions for stomach scaffolds --- .../meshtypes/meshtype_3d_stomach1.py | 617 ++++++++++-------- 1 file changed, 347 insertions(+), 270 deletions(-) diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py index e02513d5..0e3f00fe 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py @@ -22,8 +22,8 @@ from scaffoldmaker.annotation.esophagus_terms import get_esophagus_term from scaffoldmaker.annotation.smallintestine_terms import get_smallintestine_term from scaffoldmaker.annotation.stomach_terms import get_stomach_term -from scaffoldmaker.meshtypes.meshtype_1d_path1 import MeshType_1d_path1 -from scaffoldmaker.meshtypes.meshtype_3d_ostium1 import MeshType_3d_ostium1, generateOstiumMesh +from scaffoldmaker.meshtypes.meshtype_1d_network_layout1 import MeshType_1d_network_layout1 +from scaffoldmaker.meshtypes.meshtype_3d_ostium2 import MeshType_3d_ostium2, generateOstiumMesh from scaffoldmaker.meshtypes.scaffold_base import Scaffold_base from scaffoldmaker.scaffoldpackage import ScaffoldPackage from scaffoldmaker.utils import interpolation as interp @@ -32,11 +32,12 @@ from scaffoldmaker.utils.annulusmesh import createAnnulusMesh3d from scaffoldmaker.utils.eftfactory_bicubichermitelinear import eftfactory_bicubichermitelinear from scaffoldmaker.utils.eftfactory_tricubichermite import eftfactory_tricubichermite -from scaffoldmaker.utils.eft_utils import setEftScaleFactorIds, remapEftNodeValueLabel, remapEftNodeValueLabelsVersion +from scaffoldmaker.utils.eft_utils import setEftScaleFactorIds, remapEftNodeValueLabel from scaffoldmaker.utils.geometry import sampleEllipsePoints from scaffoldmaker.utils.tracksurface import TrackSurface from scaffoldmaker.utils.zinc_utils import exnode_string_from_nodeset_field_parameters, \ - mesh_destroy_elements_and_nodes_by_identifiers, get_nodeset_path_field_parameters + mesh_destroy_elements_and_nodes_by_identifiers, get_nodeset_path_ordered_field_parameters, \ + get_nodeset_path_field_parameters class MeshType_3d_stomach1(Scaffold_base): @@ -46,375 +47,405 @@ class MeshType_3d_stomach1(Scaffold_base): of the stomach. D2 of the central path points to the greater curvature of the stomach and magnitude of D2 and D3 are the radii of the stomach in the respective direction. """ - centralPathDefaultScaffoldPackages = { - 'Human 1': ScaffoldPackage(MeshType_1d_path1, { + parameterSetStructureStrings = { + 'Human 1': ScaffoldPackage(MeshType_1d_network_layout1, { 'scaffoldSettings': { - 'Coordinate dimensions': 3, - 'D2 derivatives': True, - 'D3 derivatives': True, - 'Length': 1.0, - 'Number of elements': 12 + "Structure": "1-2-3.2, 4-5-6-7-8-3-9-10-11-12-13-14-15" }, 'meshEdits': exnode_string_from_nodeset_field_parameters( [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ - (1, [[0.49,0.06,0.00], [-0.03,-0.00,-0.00], [0.01,-0.04,0.00], [0.02,-0.14,0.00], [0.00,0.00,0.04], [0.00,0.00,0.13]]), - (2, [[0.45,0.05,-0.00], [-0.06,-0.01,-0.00], [0.03,-0.17,0.00], [0.02,-0.12,0.00], [0.00,0.00,0.17], [0.00,0.00,0.13]]), - (3, [[0.38,0.04,0.00], [-0.08,-0.02,0.00], [0.04,-0.27,0.00], [0.01,-0.10,0.00], [0.00,0.00,0.29], [0.00,0.00,0.11]]), - (4, [[0.28,0.02,0.00], [-0.11,-0.02,0.00], [0.05,-0.36,0.00], [0.00,-0.07,0.00], [0.00,0.00,0.38], [0.00,0.00,0.07]]), - (5, [[0.16,0.01,0.00], [-0.14,-0.01,0.00], [0.04,-0.40,0.00], [-0.03,-0.02,0.00], [0.00,0.00,0.42], [0.00,0.00,0.03]]), - (6, [[0.00,0.00,0.00], [-0.20,0.00,0.00], [-0.01,-0.40,0.00], [-0.06,0.01,0.00], [0.00,0.00,0.43], [0.00,0.00,0.01]]), - (7, [[-0.23,0.02,0.00], [-0.23,0.05,0.00], [-0.09,-0.37,0.00], [-0.08,0.05,0.00], [0.00,0.00,0.44], [0.00,0.00,-0.01]]), - (8, [[-0.45,0.10,0.00], [-0.20,0.12,0.00], [-0.18,-0.29,0.00], [-0.06,0.11,0.00], [0.00,0.00,0.41], [0.00,0.00,-0.05]]), - (9, [[-0.61,0.26,0.00], [-0.15,0.20,0.00], [-0.22,-0.16,0.00], [-0.02,0.13,0.00], [0.00,0.00,0.34], [0.00,0.00,-0.09]]), - (10, [[-0.73,0.50,0.00], [-0.04,0.23,0.00], [-0.21,-0.04,0.00], [0.04,0.09,0.00], [0.00,0.00,0.23], [0.00,0.00,-0.07]]), - (11, [[-0.71,0.69,0.00], [0.05,0.17,0.00], [-0.14,0.03,0.00], [0.06,0.05,-0.00], [0.00,0.00,0.18], [0.00,0.00,-0.06]]), - (12, [[-0.64,0.83,0.00], [0.10,0.14,0.00], [-0.08,0.06,0.00], [0.03,0.03,-0.00], [0.00,0.00,0.11], [0.00,0.00,-0.03]]), - (13, [[-0.51,0.97,0.00], [0.16,0.14,0.00], [-0.08,0.09,0.00], [-0.03,0.03,0.00], [0.00,0.00,0.13], [0.00,0.00,0.07]]) + (1, [[0.000,0.560,0.000], [0.000,-0.070,0.000], [0.060,0.000,0.000], [0.170,0.120,-0.000], [0.000,0.000,0.060], [0.000,0.000,0.110]]), + (2, [[0.000,0.390,0.000], [0.000,-0.280,0.000], [0.130,0.000,0.000], [0.020,-0.120,-0.000], [0.000,0.000,0.130], [0.000,0.000,0.170]]), + (3, [[0.000,0.000,0.000], [[-0.200,0.000,0.000],[0.000,-0.490,0.000]], [[0.000,-0.400,0.000],[0.130,0.000,0.000]], [[-0.060,0.010,0.000],[-0.010,-0.400,0.000]], [[0.000,0.000,0.430],[0.000,0.000,0.130]], [[0.000,0.000,0.010],[0.000,0.000,0.010]]]), + (4, [[0.490,0.060,0.000], [-0.030,-0.000,-0.000], [0.010,-0.040,0.000], [0.020,-0.140,0.000], [0.000,0.000,0.040], [0.000,0.000,0.130]]), + (5, [[0.450,0.050,-0.000], [-0.060,-0.010,-0.000], [0.030,-0.170,0.000], [0.020,-0.120,0.000], [0.000,0.000,0.170], [0.000,0.000,0.130]]), + (6, [[0.380,0.040,0.000], [-0.080,-0.020,0.000], [0.040,-0.270,0.000], [0.010,-0.100,0.000], [0.000,0.000,0.290], [0.000,0.000,0.110]]), + (7, [[0.280,0.020,0.000], [-0.110,-0.020,0.000], [0.050,-0.360,0.000], [0.000,-0.070,0.000], [0.000,0.000,0.380], [0.000,0.000,0.070]]), + (8, [[0.160,0.010,0.000], [-0.140,-0.010,0.000], [0.040,-0.400,0.000], [-0.030,-0.020,0.000], [0.000,0.000,0.420], [0.000,0.000,0.030]]), + (9, [[-0.230,0.020,0.000], [-0.230,0.050,0.000], [-0.090,-0.370,0.000], [-0.080,0.050,0.000], [0.000,0.000,0.440], [0.000,0.000,-0.010]]), + (10, [[-0.450,0.100,0.000], [-0.200,0.120,0.000], [-0.180,-0.290,0.000], [-0.060,0.110,0.000], [0.000,0.000,0.410], [0.000,0.000,-0.050]]), + (11, [[-0.610,0.260,0.000], [-0.150,0.200,0.000], [-0.220,-0.160,0.000], [-0.020,0.130,0.000], [0.000,0.000,0.340], [0.000,0.000,-0.090]]), + (12, [[-0.730,0.500,0.000], [-0.040,0.230,0.000], [-0.210,-0.040,0.000], [0.040,0.090,0.000], [0.000,0.000,0.230], [0.000,0.000,-0.070]]), + (13, [[-0.710,0.690,0.000], [0.050,0.170,0.000], [-0.140,0.030,0.000], [0.060,0.050,-0.000], [0.000,0.000,0.180], [0.000,0.000,-0.060]]), + (14, [[-0.640,0.830,0.000], [0.100,0.140,0.000], [-0.080,0.060,0.000], [0.030,0.030,-0.000], [0.000,0.000,0.110], [0.000,0.000,-0.030]]), + (15, [[-0.510,0.970,0.000], [0.160,0.140,0.000], [-0.080,0.090,0.000], [-0.030,0.030,0.000], [0.000,0.000,0.130], [0.000,0.000,0.070]]) ]), 'userAnnotationGroups': [ { '_AnnotationGroup': True, 'dimension': 1, - 'identifierRanges': '1-5', + 'identifierRanges': '1-2', + 'name': get_esophagus_term('esophagus')[0], + 'ontId': get_esophagus_term('esophagus')[1] + }, + { + '_AnnotationGroup': True, + 'dimension': 1, + 'identifierRanges': '3-7', 'name': get_stomach_term('fundus of stomach')[0], 'ontId': get_stomach_term('fundus of stomach')[1] }, { '_AnnotationGroup': True, 'dimension': 1, - 'identifierRanges': '6-8', + 'identifierRanges': '8-10', 'name': get_stomach_term('body of stomach')[0], 'ontId': get_stomach_term('body of stomach')[1] }, { '_AnnotationGroup': True, 'dimension': 1, - 'identifierRanges': '9-10', + 'identifierRanges': '11-12', 'name': get_stomach_term('pyloric antrum')[0], 'ontId': get_stomach_term('pyloric antrum')[1] }, { '_AnnotationGroup': True, 'dimension': 1, - 'identifierRanges': '11', + 'identifierRanges': '13', 'name': get_stomach_term('pyloric canal')[0], 'ontId': get_stomach_term('pyloric canal')[1] }, { '_AnnotationGroup': True, 'dimension': 1, - 'identifierRanges': '12', + 'identifierRanges': '14', 'name': get_smallintestine_term('duodenum')[0], 'ontId': get_smallintestine_term('duodenum')[1] }] }), - 'Human 2': ScaffoldPackage(MeshType_1d_path1, { + 'Human 2': ScaffoldPackage(MeshType_1d_network_layout1, { 'scaffoldSettings': { - 'Coordinate dimensions': 3, - 'D2 derivatives': True, - 'D3 derivatives': True, - 'Length': 1.0, - 'Number of elements': 12 + "Structure": "1-2-3.2, 4-5-6-7-3-8-9-10-11-12-13-14-15" }, 'meshEdits': exnode_string_from_nodeset_field_parameters( [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ - (1, [[61.590,-101.050,1152.900], [0.442,-2.863,-3.864], [11.300,-0.230,1.460], [15.701,-3.029,2.832], [-0.850,-7.440,5.420], [-5.756,-22.456,14.946]]), - (2, [[61.990,-104.310,1148.310], [0.358,-3.656,-5.314], [24.170,-2.490,3.340], [10.039,-1.491,0.928], [-4.920,-25.060,16.910], [-2.384,-12.784,8.034]]), - (3, [[62.280,-108.340,1142.260], [0.251,-4.603,-7.040], [30.560,-2.990,3.040], [5.720,-0.448,-0.071], [-5.130,-31.610,20.490], [-0.206,-5.098,2.599]]), - (4, [[62.470,-113.500,1134.220], [0.315,-6.148,-9.733], [35.400,-3.370,3.270], [4.541,-0.488,0.325], [-5.330,-34.800,21.800], [-0.383,-3.012,1.219]]), - (5, [[62.940,-120.610,1122.780], [0.448,-8.598,-13.993], [39.520,-4.010,3.730], [3.189,-0.587,-0.295], [-5.970,-37.560,22.890], [-0.099,-1.218,0.549]]), - (6, [[63.320,-130.670,1106.220], [-0.184,-10.489,-16.967], [41.370,-4.520,2.350], [0.495,-2.468,-4.032], [-5.290,-36.560,22.660], [0.257,0.762,0.246]]), - (7, [[62.540,-141.560,1088.910], [-4.623,-11.401,-18.639], [40.430,-9.060,-4.490], [-4.947,-4.939,-8.800], [-5.480,-36.050,23.410], [0.770,0.606,1.053]]), - (8, [[53.670,-152.880,1069.820], [-15.955,-9.817,-16.265], [30.765,-14.468,-15.598], [-14.187,-3.408,-7.577], [-3.580,-35.330,24.820], [2.031,4.346,-1.238]]), - (9, [[32.230,-159.890,1058.560], [-22.295,-4.560,-7.466], [11.809,-15.766,-19.452], [-15.401,0.331,-0.624], [-1.410,-27.160,20.790], [1.197,8.617,-5.083]]), - (10, [[10.360,-162.050,1054.830], [-21.098,1.023,-0.272], [-0.460,-14.000,-17.230], [-8.754,2.830,4.764], [-1.070,-18.150,14.780], [-1.003,7.491,-3.260]]), - (11, [[-8.740,-158.280,1057.630], [-17.280,7.584,3.006], [-6.110,-10.230,-10.220], [-2.634,4.430,6.290], [-3.260,-12.000,13.950], [-1.380,7.085,-2.660]]), - (12, [[-23.259,-147.625,1060.642], [-11.148,12.211,0.633], [-5.944,-5.188,-4.599], [-0.696,3.015,1.714], [-3.887,-4.046,9.590], [-2.080,5.832,-2.463]]), - (13, [[-30.740,-135.240,1059.320], [-3.618,11.918,-3.109], [-7.329,-3.791,-6.004], [-2.074,-0.221,-4.524], [-7.127,0.091,8.642], [-4.400,2.442,0.567]]) + (1, [[11.530,-113.400,1127.840], [3.973,-1.388,-5.231], [5.366,2.230,1.829], [-8.397,13.092,24.878], [1.554,-5.290,1.584], [-0.807,-7.995,7.596]]), + (2, [[23.420,-116.600,1119.050], [26.718,-4.658,-7.157], [4.014,6.257,10.913], [10.037,1.800,8.968], [-0.216,-11.420,6.626], [-2.926,-13.889,10.204]]), + (3, [[62.940,-120.610,1122.780], [[0.448,-8.598,-13.993],[50.547,-3.248,14.121]], [[39.520,-4.011,3.729],[-2.448,7.606,10.512]], [[3.190,-0.590,-0.290],[3.190,-0.590,-0.290]], [[-5.970,-37.560,22.890],[-2.692,-10.763,7.161]], [[-0.100,-1.220,0.550],[-0.100,-1.220,0.550]]]), + (4, [[61.590,-101.050,1152.900], [0.442,-2.863,-3.864], [11.300,-0.230,1.460], [15.701,-3.029,2.832], [-0.850,-7.440,5.420], [-5.756,-22.456,14.946]]), + (5, [[61.990,-104.310,1148.310], [0.358,-3.656,-5.314], [24.170,-2.490,3.340], [10.039,-1.491,0.928], [-4.920,-25.060,16.910], [-2.384,-12.784,8.034]]), + (6, [[62.280,-108.340,1142.260], [0.251,-4.603,-7.040], [30.560,-2.990,3.040], [5.720,-0.448,-0.071], [-5.130,-31.610,20.490], [-0.206,-5.098,2.599]]), + (7, [[62.470,-113.500,1134.220], [0.315,-6.148,-9.733], [35.400,-3.370,3.270], [4.541,-0.488,0.325], [-5.330,-34.800,21.800], [-0.383,-3.012,1.219]]), + (8, [[63.320,-130.670,1106.220], [-0.184,-10.489,-16.967], [41.370,-4.520,2.350], [0.495,-2.468,-4.032], [-5.290,-36.560,22.660], [0.257,0.762,0.246]]), + (9, [[62.540,-141.560,1088.910], [-4.623,-11.401,-18.639], [40.430,-9.060,-4.490], [-4.947,-4.939,-8.800], [-5.480,-36.050,23.410], [0.770,0.606,1.053]]), + (10, [[53.670,-152.880,1069.820], [-15.955,-9.817,-16.265], [30.765,-14.468,-15.598], [-14.187,-3.408,-7.577], [-3.580,-35.330,24.820], [2.031,4.346,-1.238]]), + (11, [[32.230,-159.890,1058.560], [-22.295,-4.560,-7.466], [11.809,-15.766,-19.452], [-15.401,0.331,-0.624], [-1.410,-27.160,20.790], [1.197,8.617,-5.083]]), + (12, [[10.360,-162.050,1054.830], [-21.098,1.023,-0.272], [-0.460,-14.000,-17.230], [-8.754,2.830,4.764], [-1.070,-18.150,14.780], [-1.003,7.491,-3.260]]), + (13, [[-8.740,-158.280,1057.630], [-17.280,7.584,3.006], [-6.110,-10.230,-10.220], [-2.634,4.430,6.290], [-3.260,-12.000,13.950], [-1.380,7.085,-2.660]]), + (14, [[-23.259,-147.625,1060.642], [-11.148,12.211,0.633], [-5.944,-5.188,-4.599], [-0.696,3.015,1.714], [-3.887,-4.046,9.590], [-2.080,5.832,-2.463]]), + (15, [[-30.740,-135.240,1059.320], [-3.618,11.918,-3.109], [-7.329,-3.791,-6.004], [-2.074,-0.221,-4.524], [-7.127,0.091,8.642], [-4.400,2.442,0.567]]) ]), 'userAnnotationGroups': [ { '_AnnotationGroup': True, 'dimension': 1, - 'identifierRanges': '1-4', + 'identifierRanges': '1-2', + 'name': get_esophagus_term('esophagus')[0], + 'ontId': get_esophagus_term('esophagus')[1] + }, + { + '_AnnotationGroup': True, + 'dimension': 1, + 'identifierRanges': '3-6', 'name': get_stomach_term('fundus of stomach')[0], 'ontId': get_stomach_term('fundus of stomach')[1] }, { '_AnnotationGroup': True, 'dimension': 1, - 'identifierRanges': '5-8', + 'identifierRanges': '7-10', 'name': get_stomach_term('body of stomach')[0], 'ontId': get_stomach_term('body of stomach')[1] }, { '_AnnotationGroup': True, 'dimension': 1, - 'identifierRanges': '9-10', + 'identifierRanges': '11-12', 'name': get_stomach_term('pyloric antrum')[0], 'ontId': get_stomach_term('pyloric antrum')[1] }, { '_AnnotationGroup': True, 'dimension': 1, - 'identifierRanges': '11', + 'identifierRanges': '13', 'name': get_stomach_term('pyloric canal')[0], 'ontId': get_stomach_term('pyloric canal')[1] }, { '_AnnotationGroup': True, 'dimension': 1, - 'identifierRanges': '12', + 'identifierRanges': '14', 'name': get_smallintestine_term('duodenum')[0], 'ontId': get_smallintestine_term('duodenum')[1] }] }), - 'Mouse 1': ScaffoldPackage(MeshType_1d_path1, { + 'Mouse 1': ScaffoldPackage(MeshType_1d_network_layout1, { 'scaffoldSettings': { - 'Coordinate dimensions': 3, - 'D2 derivatives': True, - 'D3 derivatives': True, - 'Length': 1.0, - 'Number of elements': 11 + "Structure": "1-2-3.2, 4-5-6-7-8-9-3-10-11-12-13-14" }, 'meshEdits': exnode_string_from_nodeset_field_parameters( [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ - (1, [[0.540,0.710,0.000], [-0.005,-0.065,0.000], [0.080,-0.010,0.000], [0.098,-0.016,0.000], [0.000,0.000,0.040], [0.000,0.000,0.124]]), - (2, [[0.530,0.630,0.000], [-0.015,-0.095,0.000], [0.170,-0.030,0.000], [0.082,-0.024,0.000], [0.000,0.000,0.160], [0.000,0.000,0.116]]), - (3, [[0.510,0.520,0.000], [-0.029,-0.135,0.000], [0.240,-0.060,0.000], [0.066,-0.042,0.000], [0.000,0.000,0.270], [0.000,0.000,0.098]]), - (4, [[0.470,0.360,0.000], [-0.055,-0.161,0.000], [0.300,-0.120,0.000], [0.026,-0.089,0.000], [0.000,0.000,0.350], [0.000,0.000,0.056]]), - (5, [[0.400,0.200,0.000], [-0.107,-0.145,0.000], [0.290,-0.240,0.000], [-0.054,-0.110,0.000], [0.000,0.000,0.380], [0.000,0.000,0.020]]), - (6, [[0.260,0.080,0.000], [-0.202,-0.111,0.000], [0.190,-0.340,0.000], [-0.132,-0.084,0.000], [0.000,0.000,0.390], [0.000,0.000,0.002]]), - (7, [[0.000,0.000,0.000], [-0.288,-0.009,0.000], [0.010,-0.400,0.000], [-0.194,0.007,0.000], [0.000,0.000,0.380], [0.000,0.000,-0.015]]), - (8, [[-0.290,0.070,0.000], [-0.237,0.128,0.000], [-0.200,-0.320,0.000], [-0.109,0.097,0.000], [0.000,0.000,0.360], [0.000,0.000,-0.031]]), - (9, [[-0.460,0.230,0.000], [-0.099,0.191,0.000], [-0.230,-0.210,0.000], [0.020,0.121,0.000], [0.000,0.000,0.320], [0.000,0.000,-0.079]]), - (10, [[-0.486,0.419,0.000], [-0.008,0.167,0.000], [-0.170,-0.080,0.000], [0.069,0.087,0.000], [0.000,0.000,0.210], [0.000,0.000,-0.109]]), - (11, [[-0.480,0.560,0.000], [-0.012,0.142,0.000], [-0.094,-0.025,0.000], [0.030,0.020,0.000], [0.000,0.000,0.102], [0.000,0.000,-0.046]]), - (12, [[-0.510,0.700,0.000], [-0.048,0.137,0.000], [-0.110,-0.040,0.000], [-0.062,-0.050,0.000], [0.000,0.000,0.120], [0.000,0.000,0.082]]) + (1, [[-0.047,0.617,-0.000], [0.043,-0.123,0.000], [0.065,0.011,0.000], [0.098,-0.016,0.000], [0.000,0.000,0.066], [0.000,0.000,0.124]]), + (2, [[-0.010,0.400,-0.000], [0.030,-0.309,0.000], [0.109,0.019,0.000], [0.082,-0.024,0.000], [0.000,-0.000,0.110], [0.000,0.000,0.116]]), + (3, [[0.000,0.000,0.000], [[-0.288,-0.009,0.000],[-0.010,-0.490,0.000]], [[0.010,-0.400,0.000],[0.109,0.019,0.000]], [[-0.194,0.007,0.000],[-0.194,0.007,0.000]], [[0.000,0.000,0.380],[0.000,-0.000,0.110]], [[0.000,0.000,-0.015],[0.000,0.000,-0.015]]]), + (4, [[0.540,0.710,0.000], [-0.005,-0.065,0.000], [0.080,-0.010,0.000], [0.098,-0.016,0.000], [0.000,0.000,0.040], [0.000,0.000,0.124]]), + (5, [[0.530,0.630,0.000], [-0.015,-0.095,0.000], [0.170,-0.030,0.000], [0.082,-0.024,0.000], [0.000,0.000,0.160], [0.000,0.000,0.116]]), + (6, [[0.510,0.520,0.000], [-0.029,-0.135,0.000], [0.240,-0.060,0.000], [0.066,-0.042,0.000], [0.000,0.000,0.270], [0.000,0.000,0.098]]), + (7, [[0.470,0.360,0.000], [-0.055,-0.161,0.000], [0.300,-0.120,0.000], [0.026,-0.089,0.000], [0.000,0.000,0.350], [0.000,0.000,0.056]]), + (8, [[0.400,0.200,0.000], [-0.107,-0.145,0.000], [0.290,-0.240,0.000], [-0.054,-0.110,0.000], [0.000,0.000,0.380], [0.000,0.000,0.020]]), + (9, [[0.260,0.080,0.000], [-0.202,-0.111,0.000], [0.190,-0.340,0.000], [-0.132,-0.084,0.000], [0.000,0.000,0.390], [0.000,0.000,0.002]]), + (10, [[-0.290,0.070,0.000], [-0.237,0.128,0.000], [-0.200,-0.320,0.000], [-0.109,0.097,0.000], [0.000,0.000,0.360], [0.000,0.000,-0.031]]), + (11, [[-0.460,0.230,0.000], [-0.099,0.191,0.000], [-0.230,-0.210,0.000], [0.020,0.121,0.000], [0.000,0.000,0.320], [0.000,0.000,-0.079]]), + (12, [[-0.486,0.419,0.000], [-0.008,0.167,0.000], [-0.170,-0.080,0.000], [0.069,0.087,0.000], [0.000,0.000,0.210], [0.000,0.000,-0.109]]), + (13, [[-0.480,0.560,0.000], [-0.012,0.142,0.000], [-0.094,-0.025,0.000], [0.030,0.020,0.000], [0.000,0.000,0.102], [0.000,0.000,-0.046]]), + (14, [[-0.510,0.700,0.000], [-0.048,0.137,0.000], [-0.110,-0.040,0.000], [-0.062,-0.050,0.000], [0.000,0.000,0.120], [0.000,0.000,0.082]]) ]), 'userAnnotationGroups': [ { '_AnnotationGroup': True, 'dimension': 1, - 'identifierRanges': '1-6', + 'identifierRanges': '1-2', + 'name': get_esophagus_term('esophagus')[0], + 'ontId': get_esophagus_term('esophagus')[1] + }, + { + '_AnnotationGroup': True, + 'dimension': 1, + 'identifierRanges': '3-8', 'name': get_stomach_term('fundus of stomach')[0], 'ontId': get_stomach_term('fundus of stomach')[1] }, { '_AnnotationGroup': True, 'dimension': 1, - 'identifierRanges': '7-8', + 'identifierRanges': '9-10', 'name': get_stomach_term('body of stomach')[0], 'ontId': get_stomach_term('body of stomach')[1] }, { '_AnnotationGroup': True, 'dimension': 1, - 'identifierRanges': '9', + 'identifierRanges': '11', 'name': get_stomach_term('pyloric antrum')[0], 'ontId': get_stomach_term('pyloric antrum')[1] }, { '_AnnotationGroup': True, 'dimension': 1, - 'identifierRanges': '10', + 'identifierRanges': '12', 'name': get_stomach_term('pyloric canal')[0], 'ontId': get_stomach_term('pyloric canal')[1] }, { '_AnnotationGroup': True, 'dimension': 1, - 'identifierRanges': '11', + 'identifierRanges': '13', 'name': get_smallintestine_term('duodenum')[0], 'ontId': get_smallintestine_term('duodenum')[1] }] }), - 'Pig 1': ScaffoldPackage(MeshType_1d_path1, { + 'Pig 1': ScaffoldPackage(MeshType_1d_network_layout1, { 'scaffoldSettings': { - 'Coordinate dimensions': 3, - 'D2 derivatives': True, - 'D3 derivatives': True, - 'Length': 1.0, - 'Number of elements': 10 + "Structure": "1-2-3.2, 4-5-6-7-3-8-9-10-11-12-13" }, 'meshEdits': exnode_string_from_nodeset_field_parameters( [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ - (1, [[0.44,0.01,0.00], [-0.01,-0.00,0.00], [0.01,-0.05,0.00], [-0.01,-0.09,0.00], [0.00,0.00,0.08], [0.00,0.00,0.06]]), - (2, [[0.42,0.01,0.00], [-0.05,-0.01,0.00], [-0.00,-0.15,0.00], [-0.00,-0.10,0.00], [0.00,0.00,0.15], [0.00,0.00,0.08]]), - (3, [[0.33,0.00,0.00], [-0.11,-0.00,0.00], [0.00,-0.28,0.00], [-0.00,-0.13,0.00], [0.00,0.00,0.28], [0.00,0.00,0.12]]), - (4, [[0.19,0.00,0.00], [-0.17,-0.01,0.00], [0.01,-0.39,0.00], [-0.02,-0.08,0.00], [0.00,0.00,0.38], [0.00,0.00,0.07]]), - (5, [[0.00,0.00,0.00], [-0.21,0.00,0.00], [-0.03,-0.43,0.00], [-0.02,-0.02,0.00], [0.00,0.00,0.40], [0.00,0.00,0.01]]), - (6, [[-0.22,0.01,0.00], [-0.25,0.03,0.00], [-0.03,-0.43,0.00], [-0.05,0.03,0.00], [0.00,0.00,0.40], [0.00,0.00,-0.01]]), - (7, [[-0.50,0.05,0.00], [-0.26,0.12,0.00], [-0.16,-0.36,0.00], [-0.12,0.14,0.00], [0.00,0.00,0.37], [0.00,0.00,-0.05]]), - (8, [[-0.70,0.24,0.00], [-0.11,0.27,0.00], [-0.28,-0.16,0.00], [-0.05,0.21,0.00], [0.00,0.00,0.31], [0.00,0.00,-0.09]]), - (9, [[-0.70,0.52,0.00], [0.12,0.26,0.00], [-0.27,0.05,0.00], [0.10,0.09,0.00], [0.00,0.00,0.18], [0.00,0.00,-0.11]]), - (10, [[-0.50,0.70,0.00], [0.14,0.19,0.00], [-0.09,0.03,0.00], [0.08,-0.02,0.00], [0.00,0.00,0.09], [0.00,0.00,-0.04]]), - (11, [[-0.41,0.88,0.00], [0.03,0.16,0.00], [-0.09,0.01,0.00], [-0.08,-0.03,0.00], [0.00,0.00,0.09], [0.00,0.00,0.04]]) + (1, [[0.040,0.550,0.000], [0.000,-0.040,-0.000], [0.055,-0.007,0.000], [-0.010,-0.090,0.000], [0.000,0.000,0.0554], [0.000,0.000,0.060]]), + (2, [[0.030,0.430,0.000], [-0.020,-0.270,-0.000], [0.118,-0.005,-0.000], [-0.000,-0.100,0.000], [-0.000,0.000,0.118], [0.000,0.000,0.080]]), + (3, [[0.000,0.000,0.000], [[-0.210,0.000,0.000],[-0.040,-0.590,-0.000]], [[0.000,-0.431,0.000],[0.118,-0.005,-0.000]], [[-0.020,-0.020,0.000],[-0.020,-0.020,0.000]], [[0.000,0.000,0.400],[-0.000,0.000,0.118]], [[0.000,0.000,0.010],[0.000,0.000,0.010]]]), + (4, [[0.440,0.010,0.000], [-0.010,-0.000,0.000], [0.010,-0.050,0.000], [-0.010,-0.090,0.000], [0.000,0.000,0.080], [0.000,0.000,0.060]]), + (5, [[0.420,0.010,0.000], [-0.050,-0.010,0.000], [-0.000,-0.150,0.000], [-0.000,-0.100,0.000], [0.000,0.000,0.150], [0.000,0.000,0.080]]), + (6, [[0.330,0.000,0.000], [-0.110,-0.000,0.000], [0.000,-0.280,0.000], [-0.000,-0.130,0.000], [0.000,0.000,0.280], [0.000,0.000,0.120]]), + (7, [[0.190,0.000,0.000], [-0.170,-0.010,0.000], [0.010,-0.390,0.000], [-0.020,-0.080,0.000], [0.000,0.000,0.380], [0.000,0.000,0.070]]), + (8, [[-0.220,0.010,0.000], [-0.250,0.030,0.000], [-0.030,-0.430,0.000], [-0.050,0.030,0.000], [0.000,0.000,0.400], [0.000,0.000,-0.010]]), + (9, [[-0.500,0.050,0.000], [-0.260,0.120,0.000], [-0.160,-0.360,0.000], [-0.120,0.140,0.000], [0.000,0.000,0.370], [0.000,0.000,-0.050]]), + (10, [[-0.700,0.240,0.000], [-0.110,0.270,0.000], [-0.280,-0.160,0.000], [-0.050,0.210,0.000], [0.000,0.000,0.310], [0.000,0.000,-0.090]]), + (11, [[-0.700,0.520,0.000], [0.120,0.260,0.000], [-0.270,0.050,0.000], [0.100,0.090,0.000], [0.000,0.000,0.180], [0.000,0.000,-0.110]]), + (12, [[-0.500,0.700,0.000], [0.140,0.190,0.000], [-0.090,0.030,0.000], [0.080,-0.020,0.000], [0.000,0.000,0.090], [0.000,0.000,-0.040]]), + (13, [[-0.410,0.880,0.000], [0.030,0.160,0.000], [-0.090,0.010,0.000], [-0.080,-0.030,0.000], [0.000,0.000,0.090], [0.000,0.000,0.040]]) ]), 'userAnnotationGroups': [ { '_AnnotationGroup': True, 'dimension': 1, - 'identifierRanges': '1-4', + 'identifierRanges': '1-2', + 'name': get_esophagus_term('esophagus')[0], + 'ontId': get_esophagus_term('esophagus')[1] + }, + { + '_AnnotationGroup': True, + 'dimension': 1, + 'identifierRanges': '3-6', 'name': get_stomach_term('fundus of stomach')[0], 'ontId': get_stomach_term('fundus of stomach')[1] }, { '_AnnotationGroup': True, 'dimension': 1, - 'identifierRanges': '5-7', + 'identifierRanges': '7-9', 'name': get_stomach_term('body of stomach')[0], 'ontId': get_stomach_term('body of stomach')[1] }, { '_AnnotationGroup': True, 'dimension': 1, - 'identifierRanges': '8', + 'identifierRanges': '10', 'name': get_stomach_term('pyloric antrum')[0], 'ontId': get_stomach_term('pyloric antrum')[1] }, { '_AnnotationGroup': True, 'dimension': 1, - 'identifierRanges': '9', + 'identifierRanges': '11', 'name': get_stomach_term('pyloric canal')[0], 'ontId': get_stomach_term('pyloric canal')[1] }, { '_AnnotationGroup': True, 'dimension': 1, - 'identifierRanges': '10', + 'identifierRanges': '12', 'name': get_smallintestine_term('duodenum')[0], 'ontId': get_smallintestine_term('duodenum')[1] }] }), - 'Rat 1': ScaffoldPackage(MeshType_1d_path1, { + 'Rat 1': ScaffoldPackage(MeshType_1d_network_layout1, { 'scaffoldSettings': { - 'Coordinate dimensions': 3, - 'D2 derivatives': True, - 'D3 derivatives': True, - 'Length': 1.0, - 'Number of elements': 12 + "Structure": "1-2-3.2, 4-5-6-7-8-9-3-10-11-12-13-14-15" }, 'meshEdits': exnode_string_from_nodeset_field_parameters( [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ - (1, [[0.601,0.602,0.000], [-0.027,-0.056,0.000], [0.077,-0.036,0.000], [0.122,-0.056,0.000], [0.000,0.000,0.080], [0.000,0.000,0.076]]), - (2, [[0.564,0.524,0.000], [-0.047,-0.100,-0.000], [0.189,-0.097,0.000], [0.101,-0.066,0.000], [0.000,0.000,0.160], [0.000,0.000,0.084]]), - (3, [[0.507,0.402,0.000], [-0.071,-0.139,-0.000], [0.273,-0.171,0.000], [0.062,-0.070,-0.000], [0.000,0.000,0.250], [0.000,0.000,0.073]]), - (4, [[0.420,0.248,0.000], [-0.097,-0.137,-0.000], [0.307,-0.237,0.000], [-0.011,-0.067,-0.000], [0.000,0.000,0.300], [0.000,0.000,0.039]]), - (5, [[0.315,0.129,0.000], [-0.125,-0.109,-0.000], [0.256,-0.304,0.000], [-0.080,-0.076,0.000], [0.000,0.000,0.330], [0.000,0.000,0.030]]), - (6, [[0.171,0.034,0.000], [-0.161,-0.066,0.000], [0.144,-0.389,0.000], [-0.125,-0.058,0.000], [0.000,0.000,0.360], [0.000,0.000,0.015]]), - (7, [[0.000,0.000,0.000], [-0.200,0.002,0.000], [0.005,-0.420,0.000], [-0.156,0.003,0.000], [0.000,0.000,0.360], [0.000,0.000,-0.009]]), - (8, [[-0.218,0.048,0.000], [-0.208,0.094,0.000], [-0.173,-0.374,0.000], [-0.152,0.079,0.000], [0.000,0.000,0.340], [0.000,0.000,-0.015]]), - (9, [[-0.404,0.184,0.000], [-0.142,0.162,0.000], [-0.299,-0.260,0.000], [-0.044,0.113,0.000], [0.000,0.000,0.330], [0.000,0.000,-0.025]]), - (10, [[-0.497,0.356,0.000], [-0.049,0.209,0.000], [-0.255,-0.188,0.000], [0.077,0.107,0.000], [0.000,0.000,0.290], [0.000,0.000,-0.111]]), - (11, [[-0.490,0.587,0.000], [-0.018,0.189,-0.000], [-0.152,-0.045,0.000], [0.069,0.049,0.000], [0.000,0.000,0.120], [0.000,0.000,-0.073]]), - (12, [[-0.523,0.730,0.000], [-0.032,0.116,0.000], [-0.111,-0.036,0.000], [0.003,-0.002,0.000], [0.000,0.000,0.120], [0.000,0.000,0.018]]), - (13, [[-0.552,0.820,0.000], [-0.026,0.063,0.000], [-0.132,-0.045,0.000], [-0.045,-0.016,0.000], [0.000,0.000,0.150], [0.000,0.000,0.042]]) + (1, [[-0.011,0.636,0.000], [0.012,-0.116,0.000], [0.057,0.000,0.000], [0.122,-0.056,0.000], [-0.000,0.000,0.057], [0.000,0.000,0.076]]), + (2, [[-0.001,0.419,-0.000], [0.008,-0.318,0.000], [0.108,0.000,0.000], [0.101,-0.066,0.000], [0.000,0.000,0.108], [0.000,0.000,0.084]]), + (3, [[0.000,0.000,0.000], [[-0.200,0.002,0.000],[-0.006,-0.520,0.000]], [[0.005,-0.420,0.000],[0.108,0.000,0.000]], [[-0.156,0.003,0.000],[-0.156,0.003,0.000]], [[0.000,0.000,0.360],[0.000,0.000,0.108]], [[0.000,0.000,-0.009],[0.000,0.000,-0.009]]]), + (4, [[0.601,0.602,0.000], [-0.027,-0.056,0.000], [0.077,-0.036,0.000], [0.122,-0.056,0.000], [0.000,0.000,0.080], [0.000,0.000,0.076]]), + (5, [[0.564,0.524,0.000], [-0.047,-0.100,-0.000], [0.189,-0.097,0.000], [0.101,-0.066,0.000], [0.000,0.000,0.160], [0.000,0.000,0.084]]), + (6, [[0.507,0.402,0.000], [-0.071,-0.139,-0.000], [0.273,-0.171,0.000], [0.062,-0.070,-0.000], [0.000,0.000,0.250], [0.000,0.000,0.073]]), + (7, [[0.420,0.248,0.000], [-0.097,-0.137,-0.000], [0.307,-0.237,0.000], [-0.011,-0.067,-0.000], [0.000,0.000,0.300], [0.000,0.000,0.039]]), + (8, [[0.315,0.129,0.000], [-0.125,-0.109,-0.000], [0.256,-0.304,0.000], [-0.080,-0.076,0.000], [0.000,0.000,0.330], [0.000,0.000,0.030]]), + (9, [[0.171,0.034,0.000], [-0.161,-0.066,0.000], [0.144,-0.389,0.000], [-0.125,-0.058,0.000], [0.000,0.000,0.360], [0.000,0.000,0.015]]), + (10, [[-0.218,0.048,0.000], [-0.208,0.094,0.000], [-0.173,-0.374,0.000], [-0.152,0.079,0.000], [0.000,0.000,0.340], [0.000,0.000,-0.015]]), + (11, [[-0.404,0.184,0.000], [-0.142,0.162,0.000], [-0.299,-0.260,0.000], [-0.044,0.113,0.000], [0.000,0.000,0.330], [0.000,0.000,-0.025]]), + (12, [[-0.497,0.356,0.000], [-0.049,0.209,0.000], [-0.255,-0.188,0.000], [0.077,0.107,0.000], [0.000,0.000,0.290], [0.000,0.000,-0.111]]), + (13, [[-0.490,0.587,0.000], [-0.018,0.189,-0.000], [-0.152,-0.045,0.000], [0.069,0.049,0.000], [0.000,0.000,0.120], [0.000,0.000,-0.073]]), + (14, [[-0.523,0.730,0.000], [-0.032,0.116,0.000], [-0.111,-0.036,0.000], [0.003,-0.002,0.000], [0.000,0.000,0.120], [0.000,0.000,0.018]]), + (15, [[-0.552,0.820,0.000], [-0.026,0.063,0.000], [-0.132,-0.045,0.000], [-0.045,-0.016,0.000], [0.000,0.000,0.150], [0.000,0.000,0.042]]) ]), 'userAnnotationGroups': [ { '_AnnotationGroup': True, 'dimension': 1, - 'identifierRanges': '1-6', + 'identifierRanges': '1-2', + 'name': get_esophagus_term('esophagus')[0], + 'ontId': get_esophagus_term('esophagus')[1] + }, + { + '_AnnotationGroup': True, + 'dimension': 1, + 'identifierRanges': '3-8', 'name': get_stomach_term('fundus of stomach')[0], 'ontId': get_stomach_term('fundus of stomach')[1] }, { '_AnnotationGroup': True, 'dimension': 1, - 'identifierRanges': '7-9', + 'identifierRanges': '9-11', 'name': get_stomach_term('body of stomach')[0], 'ontId': get_stomach_term('body of stomach')[1] }, { '_AnnotationGroup': True, 'dimension': 1, - 'identifierRanges': '10', + 'identifierRanges': '12', 'name': get_stomach_term('pyloric antrum')[0], 'ontId': get_stomach_term('pyloric antrum')[1] }, { '_AnnotationGroup': True, 'dimension': 1, - 'identifierRanges': '11', + 'identifierRanges': '13', 'name': get_stomach_term('pyloric canal')[0], 'ontId': get_stomach_term('pyloric canal')[1] }, { '_AnnotationGroup': True, 'dimension': 1, - 'identifierRanges': '12', + 'identifierRanges': '14', 'name': get_smallintestine_term('duodenum')[0], 'ontId': get_smallintestine_term('duodenum')[1] }] }), - 'Material': ScaffoldPackage(MeshType_1d_path1, { + 'Material': ScaffoldPackage(MeshType_1d_network_layout1, { 'scaffoldSettings': { - 'Coordinate dimensions': 3, - 'D2 derivatives': True, - 'D3 derivatives': True, - 'Length': 1.0, - 'Number of elements': 15 + "Structure": "1-2-3.2, 4-5-6-7-8-9-3-10-11-12-13-14-15-16-17-18" }, 'meshEdits': exnode_string_from_nodeset_field_parameters( [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ - (1, [[0.700,0.000,0.000], [-0.020,0.000,0.000], [0.000,-0.050,0.000], [0.000,-0.100,0.000], [0.000,0.000,0.050], [0.000,0.000,0.100]]), - (2, [[0.680,0.000,0.000], [-0.050,0.000,0.000], [0.000,-0.150,0.000], [0.000,-0.110,0.000], [0.000,0.000,0.150], [0.000,0.000,0.110]]), - (3, [[0.600,0.000,0.000], [-0.100,0.000,0.000], [0.000,-0.290,0.000], [0.000,-0.130,0.000], [0.000,0.000,0.290], [0.000,0.000,0.130]]), - (4, [[0.490,0.000,0.000], [-0.130,0.000,0.000], [0.000,-0.400,0.000], [0.000,-0.100,0.000], [0.000,0.000,0.400], [0.000,0.000,0.100]]), - (5, [[0.350,0.000,0.000], [-0.160,0.000,0.000], [0.000,-0.480,0.000], [0.000,-0.050,0.000], [0.000,0.000,0.480], [0.000,0.000,0.050]]), - (6, [[0.180,0.000,0.000], [-0.170,0.000,0.000], [0.000,-0.500,0.000], [0.000,-0.010,0.000], [0.000,0.000,0.500], [0.000,0.000,0.010]]), - (7, [[0.000,0.000,0.000], [-0.190,0.000,0.000], [0.000,-0.500,0.000], [0.000,0.000,0.000], [0.000,0.000,0.500], [0.000,0.000,0.000]]), - (8, [[-0.200,0.000,0.000], [-0.200,0.000,0.000], [0.000,-0.500,0.000], [0.000,0.000,0.000], [0.000,0.000,0.500], [0.000,0.000,0.000]]), - (9, [[-0.400,0.000,0.000], [-0.200,0.000,0.000], [0.000,-0.500,0.000], [0.000,0.000,0.000], [0.000,0.000,0.500], [0.000,0.000,0.000]]), - (10, [[-0.600,0.000,0.000], [-0.180,0.000,0.000], [0.000,-0.500,0.000], [0.000,0.000,0.000], [0.000,0.000,0.500], [0.000,0.000,0.000]]), - (11, [[-0.750,0.000,0.000], [-0.150,0.000,0.000], [0.000,-0.440,0.000], [0.000,0.100,0.000], [0.000,0.000,0.440], [0.000,0.000,-0.100]]), - (12, [[-0.900,0.000,0.000], [-0.120,0.000,0.000], [0.000,-0.310,0.000], [0.000,0.120,0.000], [0.000,0.000,0.310], [0.000,0.000,-0.120]]), - (13, [[-1.000,0.000,0.000], [-0.100,0.000,0.000], [0.000,-0.200,0.000], [0.000,0.000,0.000], [0.000,0.000,0.200], [0.000,0.000,0.000]]), - (14, [[-1.100,0.000,0.000], [-0.100,0.000,0.000], [0.000,-0.200,0.000], [0.000,0.000,0.000], [0.000,0.000,0.200], [0.000,0.000,0.000]]), - (15, [[-1.200,0.000,0.000], [-0.100,0.000,0.000], [0.000,-0.200,0.000], [0.000,0.000,0.000], [0.000,0.000,0.200], [0.000,0.000,0.000]]), - (16, [[-1.300,0.000,0.000], [-0.100,0.000,0.000], [0.000,-0.200,0.000], [0.000,0.000,0.000], [0.000,0.000,0.200], [0.000,0.000,0.000]]) + (1, [[0.000,0.800,0.000], [0.000,-0.200,0.000], [0.080,-0.000,0.000], [0.000,-0.100,0.000], [0.000,0.000,0.080], [0.000,0.000,0.100]]), + (2, [[0.000,0.500,0.000], [0.000,-0.400,0.000], [0.150,0.000,0.000], [0.000,-0.110,0.000], [0.000,0.000,0.150], [0.000,0.000,0.110]]), + (3, [[0.000,0.000,0.000], [[-0.190,0.000,0.000],[0.000,-0.600,0.000]], [[0.000,-0.500,0.000], [0.210,0.000,0.000]], [[0.000,0.000,0.000],[0.000,0.000,0.000]], [[0.000,0.000,0.500],[0.000,0.000,0.200]], [[0.000,0.000,0.000],[0.000,0.000,0.000]]]), + (4, [[0.700,0.000,0.000], [-0.020,0.000,0.000], [0.000,-0.050,0.000], [0.000,-0.100,0.000], [0.000,0.000,0.050], [0.000,0.000,0.100]]), + (5, [[0.680,0.000,0.000], [-0.050,0.000,0.000], [0.000,-0.150,0.000], [0.000,-0.110,0.000], [0.000,0.000,0.150], [0.000,0.000,0.110]]), + (6, [[0.600,0.000,0.000], [-0.100,0.000,0.000], [0.000,-0.290,0.000], [0.000,-0.130,0.000], [0.000,0.000,0.290], [0.000,0.000,0.130]]), + (7, [[0.490,0.000,0.000], [-0.130,0.000,0.000], [0.000,-0.400,0.000], [0.000,-0.100,0.000], [0.000,0.000,0.400], [0.000,0.000,0.100]]), + (8, [[0.350,0.000,0.000], [-0.160,0.000,0.000], [0.000,-0.480,0.000], [0.000,-0.050,0.000], [0.000,0.000,0.480], [0.000,0.000,0.050]]), + (9, [[0.180,0.000,0.000], [-0.170,0.000,0.000], [0.000,-0.500,0.000], [0.000,-0.010,0.000], [0.000,0.000,0.500], [0.000,0.000,0.010]]), + (10, [[-0.200,0.000,0.000], [-0.200,0.000,0.000], [0.000,-0.500,0.000], [0.000,0.000,0.000], [0.000,0.000,0.500], [0.000,0.000,0.000]]), + (11, [[-0.400,0.000,0.000], [-0.200,0.000,0.000], [0.000,-0.500,0.000], [0.000,0.000,0.000], [0.000,0.000,0.500], [0.000,0.000,0.000]]), + (12, [[-0.600,0.000,0.000], [-0.180,0.000,0.000], [0.000,-0.500,0.000], [0.000,0.000,0.000], [0.000,0.000,0.500], [0.000,0.000,0.000]]), + (13, [[-0.750,0.000,0.000], [-0.150,0.000,0.000], [0.000,-0.440,0.000], [0.000,0.100,0.000], [0.000,0.000,0.440], [0.000,0.000,-0.100]]), + (14, [[-0.900,0.000,0.000], [-0.120,0.000,0.000], [0.000,-0.310,0.000], [0.000,0.120,0.000], [0.000,0.000,0.310], [0.000,0.000,-0.120]]), + (15, [[-1.000,0.000,0.000], [-0.100,0.000,0.000], [0.000,-0.200,0.000], [0.000,0.000,0.000], [0.000,0.000,0.200], [0.000,0.000,0.000]]), + (16, [[-1.100,0.000,0.000], [-0.100,0.000,0.000], [0.000,-0.200,0.000], [0.000,0.000,0.000], [0.000,0.000,0.200], [0.000,0.000,0.000]]), + (17, [[-1.200,0.000,0.000], [-0.100,0.000,0.000], [0.000,-0.200,0.000], [0.000,0.000,0.000], [0.000,0.000,0.200], [0.000,0.000,0.000]]), + (18, [[-1.300,0.000,0.000], [-0.100,0.000,0.000], [0.000,-0.200,0.000], [0.000,0.000,0.000], [0.000,0.000,0.200], [0.000,0.000,0.000]]) ]), 'userAnnotationGroups': [ { '_AnnotationGroup': True, 'dimension': 1, - 'identifierRanges': '1-6', + 'identifierRanges': '1-2', + 'name': get_esophagus_term('esophagus')[0], + 'ontId': get_esophagus_term('esophagus')[1] + }, + { + '_AnnotationGroup': True, + 'dimension': 1, + 'identifierRanges': '3-8', 'name': get_stomach_term('fundus of stomach')[0], 'ontId': get_stomach_term('fundus of stomach')[1] }, { '_AnnotationGroup': True, 'dimension': 1, - 'identifierRanges': '7-9', + 'identifierRanges': '9-11', 'name': get_stomach_term('body of stomach')[0], 'ontId': get_stomach_term('body of stomach')[1] }, { '_AnnotationGroup': True, 'dimension': 1, - 'identifierRanges': '10-11', + 'identifierRanges': '12-13', 'name': get_stomach_term('pyloric antrum')[0], 'ontId': get_stomach_term('pyloric antrum')[1] }, { '_AnnotationGroup': True, 'dimension': 1, - 'identifierRanges': '12-13', + 'identifierRanges': '14-15', 'name': get_stomach_term('pyloric canal')[0], 'ontId': get_stomach_term('pyloric canal')[1] }, { '_AnnotationGroup': True, 'dimension': 1, - 'identifierRanges': '14-15', + 'identifierRanges': '16-17', 'name': get_smallintestine_term('duodenum')[0], 'ontId': get_smallintestine_term('duodenum')[1] }] @@ -422,29 +453,18 @@ class MeshType_3d_stomach1(Scaffold_base): } ostiumDefaultScaffoldPackages = { - 'Human 1': ScaffoldPackage(MeshType_3d_ostium1, { + 'Human 1': ScaffoldPackage(MeshType_3d_ostium2, { 'scaffoldSettings': { - 'Number of vessels': 1, - 'Number of elements across common': 2, 'Number of elements around ostium': 8, 'Number of elements along': 3, 'Number of elements through wall': 4, 'Unit scale': 0.0105, 'Outlet': False, - 'Ostium diameter': 25.0, - 'Ostium length': 15.0, 'Ostium wall thickness': 5.0, 'Ostium wall relative thicknesses': [0.55, 0.15, 0.25, 0.05], - 'Ostium inter-vessel distance': 0.0, - 'Ostium inter-vessel height': 0.0, 'Use linear through ostium wall': True, - 'Vessel end length factor': 1.0, - 'Vessel inner diameter': 5.0, 'Vessel wall thickness': 3.0, 'Vessel wall relative thicknesses': [0.55, 0.15, 0.25, 0.05], - 'Vessel angle 1 degrees': 0.0, - 'Vessel angle 1 spread degrees': 0.0, - 'Vessel angle 2 degrees': 0.0, 'Use linear through vessel wall': True, 'Use cross derivatives': False, 'Refine': False, @@ -453,29 +473,18 @@ class MeshType_3d_stomach1(Scaffold_base): 'Refine number of elements through wall': 1 }, }), - 'Human 2': ScaffoldPackage(MeshType_3d_ostium1, { + 'Human 2': ScaffoldPackage(MeshType_3d_ostium2, { 'scaffoldSettings': { - 'Number of vessels': 1, - 'Number of elements across common': 2, 'Number of elements around ostium': 8, 'Number of elements along': 3, 'Number of elements through wall': 1, 'Unit scale': 0.0105 * 101, 'Outlet': False, - 'Ostium diameter': 25.0, - 'Ostium length': 15.0, 'Ostium wall thickness': 5.0, 'Ostium wall relative thicknesses': [0.55, 0.15, 0.25, 0.05], - 'Ostium inter-vessel distance': 0.0, - 'Ostium inter-vessel height': 0.0, 'Use linear through ostium wall': True, - 'Vessel end length factor': 1.0, - 'Vessel inner diameter': 5.0, 'Vessel wall thickness': 3.0, 'Vessel wall relative thicknesses': [0.55, 0.15, 0.25, 0.05], - 'Vessel angle 1 degrees': -40.0, - 'Vessel angle 1 spread degrees': 0.0, - 'Vessel angle 2 degrees': -60.0, 'Use linear through vessel wall': True, 'Use cross derivatives': False, 'Refine': False, @@ -484,29 +493,18 @@ class MeshType_3d_stomach1(Scaffold_base): 'Refine number of elements through wall': 1 }, }), - 'Mouse 1': ScaffoldPackage(MeshType_3d_ostium1, { + 'Mouse 1': ScaffoldPackage(MeshType_3d_ostium2, { 'scaffoldSettings': { - 'Number of vessels': 1, - 'Number of elements across common': 2, 'Number of elements around ostium': 8, 'Number of elements along': 3, 'Number of elements through wall': 4, 'Unit scale': 0.147, 'Outlet': False, - 'Ostium diameter': 1.5, - 'Ostium length': 1.5, 'Ostium wall thickness': 0.35, 'Ostium wall relative thicknesses': [0.75, 0.05, 0.15, 0.05], - 'Ostium inter-vessel distance': 0.0, - 'Ostium inter-vessel height': 0.0, 'Use linear through ostium wall': True, - 'Vessel end length factor': 1.0, - 'Vessel inner diameter': 0.5, 'Vessel wall thickness': 0.2, 'Vessel wall relative thicknesses': [0.75, 0.05, 0.15, 0.05], - 'Vessel angle 1 degrees': 0.0, - 'Vessel angle 1 spread degrees': 0.0, - 'Vessel angle 2 degrees': 0.0, 'Use linear through vessel wall': True, 'Use cross derivatives': False, 'Refine': False, @@ -515,29 +513,18 @@ class MeshType_3d_stomach1(Scaffold_base): 'Refine number of elements through wall': 1 }, }), - 'Pig 1': ScaffoldPackage(MeshType_3d_ostium1, { + 'Pig 1': ScaffoldPackage(MeshType_3d_ostium2, { 'scaffoldSettings': { - 'Number of vessels': 1, - 'Number of elements across common': 2, 'Number of elements around ostium': 8, 'Number of elements along': 3, 'Number of elements through wall': 4, 'Unit scale': 0.0118, 'Outlet': False, - 'Ostium diameter': 20.0, - 'Ostium length': 10.0, 'Ostium wall thickness': 5.0, 'Ostium wall relative thicknesses': [0.47, 0.1, 0.33, 0.1], - 'Ostium inter-vessel distance': 0.0, - 'Ostium inter-vessel height': 0.0, 'Use linear through ostium wall': True, - 'Vessel end length factor': 1.0, - 'Vessel inner diameter': 3.0, 'Vessel wall thickness': 3.0, 'Vessel wall relative thicknesses': [0.47, 0.1, 0.33, 0.1], - 'Vessel angle 1 degrees': 0.0, - 'Vessel angle 1 spread degrees': 0.0, - 'Vessel angle 2 degrees': 0.0, 'Use linear through vessel wall': True, 'Use cross derivatives': False, 'Refine': False, @@ -546,29 +533,18 @@ class MeshType_3d_stomach1(Scaffold_base): 'Refine number of elements through wall': 1 }, }), - 'Rat 1': ScaffoldPackage(MeshType_3d_ostium1, { + 'Rat 1': ScaffoldPackage(MeshType_3d_ostium2, { 'scaffoldSettings': { - 'Number of vessels': 1, - 'Number of elements across common': 2, 'Number of elements around ostium': 8, 'Number of elements along': 3, 'Number of elements through wall': 4, 'Unit scale': 0.043, 'Outlet': False, - 'Ostium diameter': 5.0, - 'Ostium length': 5.0, 'Ostium wall thickness': 0.5, 'Ostium wall relative thicknesses': [0.65, 0.12, 0.18, 0.05], - 'Ostium inter-vessel distance': 0.0, - 'Ostium inter-vessel height': 0.0, 'Use linear through ostium wall': True, - 'Vessel end length factor': 1.0, - 'Vessel inner diameter': 2.0, 'Vessel wall thickness': 0.3, 'Vessel wall relative thicknesses': [0.65, 0.12, 0.18, 0.05], - 'Vessel angle 1 degrees': 0.0, - 'Vessel angle 1 spread degrees': 0.0, - 'Vessel angle 2 degrees': 0.0, 'Use linear through vessel wall': True, 'Use cross derivatives': False, 'Refine': False, @@ -577,29 +553,18 @@ class MeshType_3d_stomach1(Scaffold_base): 'Refine number of elements through wall': 1 }, }), - 'Material': ScaffoldPackage(MeshType_3d_ostium1, { + 'Material': ScaffoldPackage(MeshType_3d_ostium2, { 'scaffoldSettings': { - 'Number of vessels': 1, - 'Number of elements across common': 2, 'Number of elements around ostium': 8, 'Number of elements along': 3, 'Number of elements through wall': 4, 'Unit scale': 1.0, 'Outlet': False, - 'Ostium diameter': 0.3, - 'Ostium length': 0.3, 'Ostium wall thickness': 0.05, 'Ostium wall relative thicknesses': [0.25, 0.25, 0.25, 0.25], - 'Ostium inter-vessel distance': 0.0, - 'Ostium inter-vessel height': 0.0, 'Use linear through ostium wall': True, - 'Vessel end length factor': 1.0, - 'Vessel inner diameter': 0.1, 'Vessel wall thickness': 0.03, 'Vessel wall relative thicknesses': [0.25, 0.25, 0.25, 0.25], - 'Vessel angle 1 degrees': 0.0, - 'Vessel angle 1 spread degrees': 0.0, - 'Vessel angle 2 degrees': 0.0, 'Use linear through vessel wall': True, 'Use cross derivatives': False, 'Refine': False, @@ -628,22 +593,22 @@ def getParameterSetNames(): @classmethod def getDefaultOptions(cls, parameterSetName='Default'): if 'Human 2' in parameterSetName: - centralPathOption = cls.centralPathDefaultScaffoldPackages['Human 2'] + centralPathOption = cls.parameterSetStructureStrings['Human 2'] ostiumOption = cls.ostiumDefaultScaffoldPackages['Human 2'] elif 'Mouse 1' in parameterSetName: - centralPathOption = cls.centralPathDefaultScaffoldPackages['Mouse 1'] + centralPathOption = cls.parameterSetStructureStrings['Mouse 1'] ostiumOption = cls.ostiumDefaultScaffoldPackages['Mouse 1'] elif 'Pig 1' in parameterSetName: - centralPathOption = cls.centralPathDefaultScaffoldPackages['Pig 1'] + centralPathOption = cls.parameterSetStructureStrings['Pig 1'] ostiumOption = cls.ostiumDefaultScaffoldPackages['Pig 1'] elif 'Rat 1' in parameterSetName: - centralPathOption = cls.centralPathDefaultScaffoldPackages['Rat 1'] + centralPathOption = cls.parameterSetStructureStrings['Rat 1'] ostiumOption = cls.ostiumDefaultScaffoldPackages['Rat 1'] elif 'Material' in parameterSetName: - centralPathOption = cls.centralPathDefaultScaffoldPackages['Material'] + centralPathOption = cls.parameterSetStructureStrings['Material'] ostiumOption = cls.ostiumDefaultScaffoldPackages['Material'] else: - centralPathOption = cls.centralPathDefaultScaffoldPackages['Human 1'] + centralPathOption = cls.parameterSetStructureStrings['Human 1'] ostiumOption = cls.ostiumDefaultScaffoldPackages['Human 1'] options = { @@ -724,15 +689,15 @@ def getOrderedOptionNames(): @classmethod def getOptionValidScaffoldTypes(cls, optionName): if optionName == 'Central path': - return [MeshType_1d_path1] + return [MeshType_1d_network_layout1] if optionName == 'Gastro-esophageal junction': - return [MeshType_3d_ostium1] + return [MeshType_3d_ostium2] return [] @classmethod def getOptionScaffoldTypeParameterSetNames(cls, optionName, scaffoldType): if optionName == 'Central path': - return list(cls.centralPathDefaultScaffoldPackages.keys()) + return list(cls.parameterSetStructureStrings.keys()) if optionName == 'Gastro-esophageal junction': return list(cls.ostiumDefaultScaffoldPackages.keys()) assert scaffoldType in cls.getOptionValidScaffoldTypes(optionName), \ @@ -752,8 +717,8 @@ def getOptionScaffoldPackage(cls, optionName, scaffoldType, parameterSetName=Non ' in option ' + str(optionName) + ' of scaffold ' + cls.getName() if optionName == 'Central path': if not parameterSetName: - parameterSetName = list(cls.centralPathDefaultScaffoldPackages.keys())[0] - return copy.deepcopy(cls.centralPathDefaultScaffoldPackages[parameterSetName]) + parameterSetName = list(cls.parameterSetStructureStrings.keys())[0] + return copy.deepcopy(cls.parameterSetStructureStrings[parameterSetName]) if optionName == 'Gastro-esophageal junction': if not parameterSetName: parameterSetName = list(cls.ostiumDefaultScaffoldPackages.keys())[0] @@ -763,11 +728,11 @@ def getOptionScaffoldPackage(cls, optionName, scaffoldType, parameterSetName=Non @classmethod def checkOptions(cls, options): if not options['Central path'].getScaffoldType() in cls.getOptionValidScaffoldTypes('Central path'): - options['Central path'] = cls.getOptionScaffoldPackage('Central path', MeshType_1d_path1) + options['Central path'] = cls.getOptionScaffoldPackage('Central path', MeshType_1d_network_layout1) if not options['Gastro-esophageal junction'].getScaffoldType() in cls.getOptionValidScaffoldTypes( 'Gastro-esophageal junction'): options['Gastro-esophageal junction'] = cls.getOptionScaffoldPackage('Gastro-esophageal junction', - MeshType_3d_ostium1) + MeshType_3d_ostium2) if options['Number of elements around esophagus'] < 8: options['Number of elements around esophagus'] = 8 if options['Number of elements around duodenum'] < 12: @@ -823,14 +788,14 @@ def generateBaseMesh(cls, region, options): """ cls.updateSubScaffoldOptions(options) geometricCentralPath = options['Central path'] - materialCentralPath = cls.centralPathDefaultScaffoldPackages['Material'] + materialCentralPath = cls.parameterSetStructureStrings['Material'] limitingRidge = options['Limiting ridge'] elementsCountThroughWall = options['Number of elements through wall'] allAnnotationGroups = [] stomachTermsAlong = [None, 'fundus of stomach', 'body of stomach', - 'pyloric antrum', 'pyloric canal', 'duodenum'] + 'pyloric antrum', 'pyloric canal', 'duodenum', 'esophagus'] # Geometric coordinates fm = region.getFieldmodule() @@ -1212,7 +1177,7 @@ class StomachCentralPath: def __init__(self, region, centralPath, stomachTermsAlong=[None]): """ :param region: Zinc region needed to create path region to define path in. - :param centralPath: Central path subscaffold from meshtype_1d_path1 + :param centralPath: Central path subscaffold from meshtype_1d_network_layout1 :param stomachTermsAlong: Annotation terms along length of stomach """ # Extract length of each group along stomach from central path @@ -1224,21 +1189,71 @@ def __init__(self, region, centralPath, stomachTermsAlong=[None]): cd12Groups = [] cd13Groups = [] - self._path_region = region.createRegion() - centralPath.generate(self._path_region) - tmpFieldmodule = self._path_region.getFieldmodule() + tmpRegion = region.createRegion() + centralPath.generate(tmpRegion) + pathNetworkMesh = centralPath.getConstructionObject() + tmpFieldmodule = tmpRegion.getFieldmodule() tmpNodes = tmpFieldmodule.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES) tmpCoordinates = tmpFieldmodule.findFieldByName('coordinates') + networkSegments = pathNetworkMesh.getNetworkSegments() + + cxGroup = [] + cd1Group = [] + cd2Group = [] + cd3Group = [] + cd12Group = [] + cd13Group = [] for termName in stomachTermsAlong: tmpGroup = tmpFieldmodule.findFieldByName(termName).castGroup() if termName else None tmpNodeset = tmpGroup.getNodesetGroup(tmpNodes) if tmpGroup else tmpNodes - cxGroup, cd1Group, cd2Group, cd3Group, cd12Group, cd13Group = get_nodeset_path_field_parameters( - tmpNodeset, tmpCoordinates, - [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]) + if termName == "esophagus": + cxGroup, cd1Group, cd2Group, cd3Group, cd12Group, cd13Group = \ + get_nodeset_path_ordered_field_parameters(tmpNodeset, tmpCoordinates, + [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], + networkSegments[0].getNodeIdentifiers(), + networkSegments[0].getNodeVersions()) + elif termName is None: + for i in range(2): + cx, cd1, cd2, cd3, cd12, cd13 = get_nodeset_path_ordered_field_parameters( + tmpNodeset, tmpCoordinates, + [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], + networkSegments[i + 1].getNodeIdentifiers(), networkSegments[i + 1].getNodeVersions()) + + cxGroup += cx[(1 if i else 0):] + cd1Group += cd1[(1 if i else 0):] + cd2Group += cd2[(1 if i else 0):] + cd3Group += cd3[(1 if i else 0):] + cd12Group += cd12[(1 if i else 0):] + cd13Group += cd13[(1 if i else 0):] + + if i == 0: + xbranchpt = cx[-1] + d2branchpt = cd2[-1] + d3branchpt = cd3[-1] + arcLengthToBranchPt = 0.0 + for n in range(len(cx) - 1): + arcLengthToBranchPt += interp.getCubicHermiteArcLength(cx[n], cd1[n], cx[n + 1], cd1[n + 1]) + + elif termName == "fundus of stomach": + cxGroup, cd1Group, cd2Group, cd3Group, cd12Group, cd13Group = \ + get_nodeset_path_ordered_field_parameters(tmpNodeset, tmpCoordinates, + [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], + networkSegments[1].getNodeIdentifiers(), + networkSegments[1].getNodeVersions()) + else: + cxGroup, cd1Group, cd2Group, cd3Group, cd12Group, cd13Group = \ + get_nodeset_path_field_parameters(tmpNodeset, tmpCoordinates, + [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]) arcLength = 0.0 for e in range(len(cxGroup) - 1): @@ -1266,6 +1281,10 @@ def __init__(self, region, centralPath, stomachTermsAlong=[None]): self.cd3Groups = cd3Groups self.cd12Groups = cd12Groups self.cd13Groups = cd13Groups + self.xBranchPt = xbranchpt + self.d2BranchPt = d2branchpt + self.d3BranchPt = d3branchpt + self.arcLengthToBranchPt = arcLengthToBranchPt def findCurvatureAroundLoop(nx, nd, radialVectors): @@ -1341,13 +1360,13 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio GEJSettings = GEJOptions.getScaffoldSettings() elementsAlongEsophagus = GEJSettings['Number of elements along'] elementsThroughEsophagusWall = GEJSettings['Number of elements through wall'] - ostiumDiameter = GEJSettings['Ostium diameter'] + ostiumRadius = vector.magnitude(centralPath.cd2Groups[-1][1]) limitingRidge = options['Limiting ridge'] wallThickness = options['Wall thickness'] elementsCountAcrossCardia = 1 cardiaDiameterFactor = 1.4 # scale to ostium diameter - sf = (cardiaDiameterFactor - 1) * ostiumDiameter * 0.5 * GEJSettings['Unit scale'] + sf = (cardiaDiameterFactor - 1) * ostiumRadius elementsAroundHalfEso = int(elementsCountAroundEso * 0.5) elementsAroundQuarterEso = int(elementsCountAroundEso * 0.25) @@ -1367,26 +1386,16 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio relThicknesses = [1.0] unitScale = GEJSettings['Unit scale'] - ostiumLength = GEJSettings['Ostium length'] ostiumWallThickness = GEJSettings['Ostium wall thickness'] ostiumWallRelThicknesses = GEJSettings['Ostium wall relative thicknesses'] - vesselInnerDiameter = GEJSettings['Vessel inner diameter'] vesselWallThickness = GEJSettings['Vessel wall thickness'] vesselWallRelThicknesses = GEJSettings['Vessel wall relative thicknesses'] - vesselAngle1 = GEJSettings['Vessel angle 1 degrees'] - vesselAngle2 = GEJSettings['Vessel angle 2 degrees'] GEJSettings['Unit scale'] = 1.0 - GEJSettings['Ostium diameter'] = 0.3 - GEJSettings['Ostium length'] = 0.3 GEJSettings['Ostium wall thickness'] = wallThickness GEJSettings['Ostium wall relative thicknesses'] = relThicknesses - GEJSettings['Vessel inner diameter'] = 0.1 GEJSettings['Vessel wall thickness'] = wallThickness * 0.6 GEJSettings['Vessel wall relative thicknesses'] = relThicknesses - sf = (cardiaDiameterFactor - 1) * GEJSettings['Ostium diameter'] * 0.5 - GEJSettings['Vessel angle 1 degrees'] = 0.0 - GEJSettings['Vessel angle 2 degrees'] = 0.0 nodes = fm.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES) nodetemplate = nodes.createNodetemplate() @@ -1411,7 +1420,7 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio arcLengthOfGroupsAlong = centralPath.arcLengthOfGroupsAlong stomachCentralPathLength = arcLengthOfGroupsAlong[0] - for i in range(1, len(stomachTermsAlong)): + for i in range(1, len(stomachTermsAlong) - 1): arcLengthRatio = arcLengthOfGroupsAlong[i] / stomachCentralPathLength arcLengthRatioForGroupsFromFundusApex.append(arcLengthRatio) @@ -1457,7 +1466,7 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio targetLengthTS = 0.025 - for i in (list(range(1, len(stomachTermsAlong) - 1)) + [0]): # start from body, go back to fundus + for i in (list(range(1, len(stomachTermsAlong) - 2)) + [0]): # start from body, go back to fundus cxGroup = centralPath.cxGroups[i + 1] cd1Group = centralPath.cd1Groups[i + 1] cd2Group = centralPath.cd2Groups[i + 1] @@ -1474,7 +1483,7 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, cd3Group[n2]) # nodeIdentifier += 1 - if materialCoordinates and i == len(stomachTermsAlong) - 1: + if materialCoordinates and i == len(stomachTermsAlong) - 2: for n in range(len(cxGroup)): cd12Group[n] = zero cd13Group[n] = zero @@ -1632,11 +1641,60 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio # Visualise track surface # nodeIdentifier, elementIdentifier = trackSurfaceStomach.generateMesh(region) - # Set up gastro-esophageal junction with midpoint aligned to fundus-body junction + # Set up gastro-esophageal junction with network layout + cxEso = centralPath.cxGroups[-1] + cd1Eso = centralPath.cd1Groups[-1] + cd2Eso = centralPath.cd2Groups[-1] + cd3Eso = centralPath.cd3Groups[-1] + cd12Eso = centralPath.cd12Groups[-1] + + # Find centre position + # track along esophagus path and since cxEso[1] could be above or below the track surface, we check both side to + # determine direction to track. At each point, find the nearest position and take the diff between nearest point + # to the point in line, keep tracking till diff is close to zero. + + xTol = 1.0E-6 + arcStart = 0.0 + arcEnd = centralPath.arcLengthOfGroupsAlong[-1] + nearestPosition = trackSurfaceStomach.findNearestPosition(cxEso[0]) + xNearestStart = trackSurfaceStomach.evaluateCoordinates(nearestPosition, derivatives=False) + distStart = vector.magnitude([cxEso[0][c] - xNearestStart[c] for c in range(3)]) + nearestPosition = trackSurfaceStomach.findNearestPosition(cxEso[-1]) + xNearestEnd = trackSurfaceStomach.evaluateCoordinates(nearestPosition, derivatives=False) + distEnd = vector.magnitude([cxEso[-1][c] - xNearestEnd[c] for c in range(3)]) + + for iter in range(100): + arcDistance = (arcStart + arcEnd) * 0.5 + x, d1 = interp.getCubicHermiteCurvesPointAtArcDistance(cxEso, cd1Eso, arcDistance)[0:2] + nearestPosition = trackSurfaceStomach.findNearestPosition(x) + xNearest = trackSurfaceStomach.evaluateCoordinates(nearestPosition, derivatives=False) + dist = vector.magnitude([x[c] - xNearest[c] for c in range(3)]) + + if abs(distStart - distEnd) > xTol: + if distStart < distEnd: + arcEnd = arcDistance + distEnd = dist + else: + arcStart = arcDistance + distStart = dist + + else: + xCentre, d1Centre, d2Centre = trackSurfaceStomach.evaluateCoordinates(nearestPosition, derivatives=True) + normAxis = vector.normalise([-d for d in d1]) + eIdx = interp.getNearestPointIndex(cxEso, xCentre) - 1 + arcLenghtSum = 0.0 + for e in range(eIdx): + arcLenghtSum += interp.getCubicHermiteArcLength(cxEso[e], cd1Eso[e], + cxEso[e + 1], cd1Eso[e + 1]) + xi = (arcDistance - arcLenghtSum) / \ + interp.getCubicHermiteArcLength(cxEso[eIdx], cd1Eso[eIdx], cxEso[eIdx + 1], cd1Eso[eIdx + 1]) + d2Centre = interp.interpolateCubicHermite(cd2Eso[eIdx], cd12Eso[eIdx], cd2Eso[eIdx + 1], + cd12Eso[eIdx + 1], xi) + break + if iter > 98: + print('Search for ileum entry centre - Max iters reached:', iter) + GEJSettings['Number of elements around ostium'] = elementsCountAroundEso - GEJPosition = trackSurfaceStomach.findNearestPosition(xGEJ) - xCentre, d1Centre, d2Centre = trackSurfaceStomach.evaluateCoordinates(GEJPosition, derivatives=True) - axis1 = d1Centre esophagusGroup = AnnotationGroup(region, get_esophagus_term("esophagus")) esophagusMeshGroup = esophagusGroup.getMeshGroup(mesh) @@ -1663,8 +1721,20 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio allAnnotationGroups += [esophagusMucosaGroup, esophagusSubmucosaGroup, esophagusCircularGroup, esophagusLongitudinalGroup] + xPath = [cxEso[0], xCentre] + d1Path = [cd1Eso[0], [-d for d in normAxis]] + ostiumLength = interp.computeCubicHermiteArcLength(xPath[0], d1Path[0], xPath[1], d1Path[1], + rescaleDerivatives=True) + d1Path[1] = vector.setMagnitude(d1Path[1], ostiumLength*0.1) + d2Path = [cd2Eso[0], d2Centre] + d3Path = [cd3Eso[0], vector.setMagnitude([-d for d in d1Centre], vector.magnitude(d2Centre))] + d12Path = [cd2Eso[0], [0.0, 0.0, 0.0]] + d13Path = [cd3Eso[0], [0.0, 0.0, 0.0]] + + centralPathIleum = CustomCentralPath(xPath, d1Path, d2Path, d3Path, d12Path, d13Path) + nextNodeIdentifier, nextElementIdentifier, (o1_x, o1_d1, o1_d2, o1_d3, o1_NodeId, o1_Positions) = \ - generateOstiumMesh(region, GEJSettings, trackSurfaceStomach, GEJPosition, axis1, + generateOstiumMesh(region, GEJSettings, trackSurfaceStomach, centralPathIleum, nodeIdentifier, elementIdentifier, vesselMeshGroups=[[stomachMeshGroup, esophagusMeshGroup, abdominalEsoMeshGroup]], ostiumMeshGroups=[stomachMeshGroup, esophagogastricJunctionMeshGroup], @@ -1676,15 +1746,10 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio if materialCoordinates: GEJSettings['Unit scale'] = unitScale - GEJSettings['Ostium diameter'] = ostiumDiameter - GEJSettings['Ostium length'] = ostiumLength GEJSettings['Ostium wall thickness'] = ostiumWallThickness GEJSettings['Ostium wall relative thicknesses'] = ostiumWallRelThicknesses - GEJSettings['Vessel inner diameter'] = vesselInnerDiameter GEJSettings['Vessel wall thickness'] = vesselWallThickness GEJSettings['Vessel wall relative thicknesses'] = vesselWallRelThicknesses - GEJSettings['Vessel angle 1 degrees'] = vesselAngle1 - GEJSettings['Vessel angle 2 degrees'] = vesselAngle2 # Create location of annulus xAnnulusOuter = [[] for x in range(elementsCountAroundEso)] @@ -2809,3 +2874,15 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio allAnnotationGroups.append(nearLCGroup) return allAnnotationGroups, nextNodeIdentifier, nextElementIdentifier, elementsAlongSections + +class CustomCentralPath: + """ + Generates sampled central path for part of central path. + """ + def __init__(self, cx, cd1, cd2, cd3, cd12, cd13): + self.cxPath = cx + self.cd1Path = cd1 + self.cd2Path = cd2 + self.cd3Path = cd3 + self.cd12Path = cd12 + self.cd13Path = cd13 From 1cf4f7e871f383be02900df48c64bcf9e4e139f6 Mon Sep 17 00:00:00 2001 From: mlin865 Date: Fri, 8 Sep 2023 13:55:10 +1200 Subject: [PATCH 16/24] Clean up derivatives around annulus --- .../meshtypes/meshtype_3d_cecum1.py | 566 ++++++++++++------ 1 file changed, 390 insertions(+), 176 deletions(-) diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_cecum1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_cecum1.py index 96c3d0f4..0ee195ed 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_cecum1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_cecum1.py @@ -106,8 +106,8 @@ class MeshType_3d_cecum1(Scaffold_base): 'meshEdits': exnode_string_from_nodeset_field_parameters( [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ (1, [[164.00,29.75,51.53], [0.00,-9.63,-16.67], [-6.00,0.00,0.00], [0.00,0.00,0.00], [0.00,5.20,-3.00], [0.00,0.00,0.00]]), - (2, [[164.00,17.50,30.31], [0.00,-14.87,-25.77], [-12.00,0.00,0.00], [0.00,0.00,0.00], [0.00,10.39,-6.00], [0.00,0.00,0.00]]), - (3, [[164.00,0.00,0.00], [[30.00,0.00,0.00],[0.00,-20.13,-34.85]], [[0.00,37.00,0.00],[-12.00,0.00,0.00]], [[0.00,0.00,0.00],[0.00,0.00,0.00]], [[0.00,0.00,37.00],[0.00,10.39,-6.00]], [[0.00,0.00,0.00],[0.00,0.00,0.00]]]), + (2, [[164.00,17.50,30.31], [0.00,-14.87,-25.77], [-10.00,0.00,0.00], [0.00,0.00,0.00], [0.00,8.66,-5.00], [0.00,0.00,0.00]]), + (3, [[164.00,0.00,0.00], [[30.00,0.00,0.00],[0.00,-20.13,-34.85]], [[0.00,37.00,0.00],[-10.00,0.00,0.00]], [[0.00,0.00,0.00],[0.00,0.00,0.00]], [[0.00,0.00,37.00],[0.00,8.66,-5.00]], [[0.00,0.00,0.00],[0.00,0.00,0.00]]]), (4, [[0.00,0.00,0.00], [60.00,0.00,0.00], [0.00,37.00,0.00], [0.00,0.00,0.00], [0.00,0.00,37.00], [0.00,0.00,0.00]]), (5, [[60.00,0.00,0.00], [60.00,0.00,0.00], [0.00,37.00,0.00], [0.00,0.00,0.00], [0.00,0.00,37.00], [0.00,0.00,0.00]]), (6, [[120.00,0.00,0.00], [52.00,0.00,0.00], [0.00,37.00,0.00], [0.00,0.00,0.00], [0.00,0.00,37.00], [0.00,0.00,0.00]]), @@ -238,6 +238,7 @@ def getDefaultOptions(cls, parameterSetName='Default'): elif 'Pig 1' in parameterSetName: options['Number of segments'] = 5 + options['Number of elements around haustrum'] = 12 options['Haustrum outer radius factor'] = 0.25 options['Segment length end derivative factor'] = 0.5 options['Segment length mid derivative factor'] = 4.0 @@ -857,12 +858,19 @@ def createCecumMesh3d(region, options, centralPath, nodeIdentifier, elementIdent # Deal with multiple nodes at end point for closed proximal end xApexInner = xList[0] # arclength between apex point and corresponding point on next face - mag = interp.getCubicHermiteArcLength(xList[0], d2List[0], - xList[elementsCountAround * (elementsCountThroughWall + 1)], - d2List[elementsCountAround * (elementsCountThroughWall + 1)]) - d2ApexInner = vector.setMagnitude(sd2Cecum[0], mag * 0.5) + magMin = interp.computeCubicHermiteArcLength(xList[0], d2List[0], + xList[elementsCountAround * (elementsCountThroughWall + 1)], + d2List[elementsCountAround * (elementsCountThroughWall + 1)], + rescaleDerivatives=True) + magMax = interp.computeCubicHermiteArcLength(xList[int(0.5*(elementsCountAroundTC + elementsCountAroundHaustrum))], + d2List[int(0.5*(elementsCountAroundTC + elementsCountAroundHaustrum))], + xList[int(0.5*(elementsCountAroundTC + elementsCountAroundHaustrum)) + elementsCountAround * (elementsCountThroughWall + 1)], + d2List[int(0.5*(elementsCountAroundTC + elementsCountAroundHaustrum)) + elementsCountAround * (elementsCountThroughWall + 1)], + rescaleDerivatives=True) + mag = 0.5*(magMin + magMax) + d2ApexInner = vector.setMagnitude(sd2Cecum[0], mag) d1ApexInner = vector.crossproduct3(sd1Cecum[0], d2ApexInner) - d1ApexInner = vector.setMagnitude(d1ApexInner, mag * 0.5) + d1ApexInner = vector.setMagnitude(d1ApexInner, mag) d3ApexUnit = vector.normalise(vector.crossproduct3(vector.normalise(d1ApexInner), vector.normalise(d2ApexInner))) d3ApexInner = [d3ApexUnit[c] * wallThickness / elementsCountThroughWall for c in range(3)] @@ -1062,19 +1070,12 @@ def createCecumMesh3d(region, options, centralPath, nodeIdentifier, elementIdent else: sideNodes.append(nodesOnRHS[n2 + (0 if segmentIdx else -1)][n3]) - # # Visualise track surface - # for n1 in range(len(xTrackSurface)): - # node = nodes.createNode(nextNodeIdentifier, nodetemplate) - # cache.setNode(node) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, xTrackSurface[n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS1, 1, d2TrackSurface[n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, d1TrackSurface[n1]) - # coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS3, 1, [0.0, 0.0, 0.0]) - # nextNodeIdentifier += 1 - trackSurfaceOstium = TrackSurface(elementsAroundTrackSurface, elementsAlongTrackSurface, xTrackSurface, d1TrackSurface, d2TrackSurface) + # # Visualise track surface + # nodeIdentifier, elementIdentifier = trackSurfaceOstium.generateMesh(region) + # Find centre position # track along ileum path and since cxIleum[1] could be above or below the track surface, we check both side to # determine direction to track. At each point, find the nearest position and take the diff between nearest point @@ -1178,7 +1179,7 @@ def createCecumMesh3d(region, options, centralPath, nodeIdentifier, elementIdent e1Right = 0 e2Top = 0 e2Bottom = elementsAlongTrackSurface - sf = vector.magnitude(centralPathIleum.cd2Path[-1]) * 0.25 + sf = vector.magnitude(centralPathIleum.cd2Path[-1]) * 0.35 for n1 in range(elementsCountAroundOstium): normD2 = vector.normalise(o1_d2[-1][n1]) d1AnnulusNorm.append(normD2) @@ -1250,6 +1251,8 @@ def createCecumMesh3d(region, options, centralPath, nodeIdentifier, elementIdent xPositionA = trackSurfaceOstium.findNearestPosition(xStart) xProportionA = trackSurfaceOstium.getProportion(xPositionA) derivativeA = trackSurfaceOstium.evaluateCoordinates(xPositionA, derivatives=True)[2] + derivativeA = vector.setMagnitude(derivativeA, vector.magnitude(d2ApexInner)) + derivativeMagnitudeA = vector.magnitude(derivativeA) xPositionB = trackSurfaceOstium.findNearestPosition(xAnnulusOuter[0]) xProportionB = trackSurfaceOstium.getProportion(xPositionB) @@ -1259,12 +1262,13 @@ def createCecumMesh3d(region, options, centralPath, nodeIdentifier, elementIdent nx, nd1, nd2, nd3, proportions = \ trackSurfaceOstium.createHermiteCurvePoints( xProportionA[0], xProportionA[1], xProportionB[0], xProportionB[1], - rowsBelow + 1, derivativeStart=derivativeA, derivativeEnd=derivativeB) + rowsBelow + 1, derivativeStart=derivativeA, derivativeEnd=None) pxAlongMidLine, pd2AlongMidLine, pd1AlongMidLine = \ trackSurfaceOstium.resampleHermiteCurvePointsSmooth( - nx, nd1, nd2, nd3, proportions, - derivativeMagnitudeEnd=derivativeMagnitudeB)[0:3] + nx, nd1, nd2, nd3, proportions, derivativeMagnitudeStart=derivativeMagnitudeA)[0:3] + + annulusD2ZeroMag = vector.magnitude(pd2AlongMidLine[-1]) for n in range(len(pd1AlongMidLine)): pd1AlongMidLine[n] = [-d for d in pd1AlongMidLine[n]] @@ -1278,16 +1282,19 @@ def createCecumMesh3d(region, options, centralPath, nodeIdentifier, elementIdent xPositionB = trackSurfaceOstium.findNearestPosition(xB) xProportionB = trackSurfaceOstium.getProportion(xPositionB) derivativeB = d2TrackSurface[-elementsCountAroundHalfHaustrum] + derivativeMagnitudeB = vector.magnitude(d2TrackSurface[-elementsCountAroundHalfHaustrum]) nx, nd1, nd2, nd3, proportions = \ trackSurfaceOstium.createHermiteCurvePoints( xProportionA[0], xProportionA[1], xProportionB[0], xProportionB[1], - rowsAbove + 1, derivativeStart=derivativeA, derivativeEnd=derivativeB) + rowsAbove + 1, derivativeStart=None, derivativeEnd=derivativeB) pxAlongMidLineBottom, pd2AlongMidLineBottom, pd1AlongMidLineBottom = \ trackSurfaceOstium.resampleHermiteCurvePointsSmooth( - nx, nd1, nd2, nd3, proportions, derivativeMagnitudeStart=derivativeMagnitudeA, - derivativeMagnitudeEnd=derivativeMagnitudeA)[0:3] + nx, nd1, nd2, nd3, proportions, derivativeMagnitudeStart=None, + derivativeMagnitudeEnd=derivativeMagnitudeB)[0:3] + + annulusD2HalfOstiumMag = vector.magnitude(pd2AlongMidLineBottom[0]) for n in range(len(pd1AlongMidLineBottom)): pd1AlongMidLineBottom[n] = [-d for d in pd1AlongMidLineBottom[n]] @@ -1313,24 +1320,23 @@ def createCecumMesh3d(region, options, centralPath, nodeIdentifier, elementIdent xTrackSurface[n2 * (elementsCountAroundHaustrum + 1)]) xProportionA = trackSurfaceOstium.getProportion(xPositionA) derivativeA = d1TrackSurface[n2 * (elementsCountAroundHaustrum + 1)] + derivativeMagnitudeA = vector.magnitude(derivativeA) if n2 < rowsBelow + 1: xPositionB = trackSurfaceOstium.findNearestPosition(pxAlongMidLine[n2]) derivativeB = None + derivativeMagnitudeB = None elif n2 >= rowsBelow + rowsOstium: idx = n2 - (rowsBelow + rowsOstium) + 1 xPositionB = trackSurfaceOstium.findNearestPosition(pxAlongMidLineBottom[idx]) derivativeB = None + derivativeMagnitudeB = None else: xPositionB = trackSurfaceOstium.findNearestPosition(xAnnulusOuter[annulusIdx]) - rotAngle = math.pi - rotFrame = matrix.getRotationMatrixFromAxisAngle(vector.normalise(d3Annulus[annulusIdx]), - rotAngle) - derivativeB = [rotFrame[j][0] * d1AnnulusOuter[annulusIdx][0] + - rotFrame[j][1] * d1AnnulusOuter[annulusIdx][1] + - rotFrame[j][2] * d1AnnulusOuter[annulusIdx][2] for j in range(3)] + derivativeB = None + derivativeMagnitudeB = None xProportionB = trackSurfaceOstium.getProportion(xPositionB) @@ -1338,21 +1344,25 @@ def createCecumMesh3d(region, options, centralPath, nodeIdentifier, elementIdent if n2 < rowsBelow + 1: xPositionA = trackSurfaceOstium.findNearestPosition(pxAlongMidLine[n2]) derivativeA = None + derivativeMagnitudeA = None elif n2 >= rowsBelow + rowsOstium: idx = n2 - (rowsBelow + rowsOstium) + 1 xPositionA = trackSurfaceOstium.findNearestPosition(pxAlongMidLineBottom[idx]) derivativeA = None + derivativeMagnitudeA = None else: xPositionA = trackSurfaceOstium.findNearestPosition(xAnnulusOuter[-annulusIdx]) - derivativeA = d1AnnulusOuter[-annulusIdx] - xProportionA = trackSurfaceOstium.getProportion(xPositionA) + derivativeA = None + derivativeMagnitudeA = None + xProportionA = trackSurfaceOstium.getProportion(xPositionA) xPositionB = trackSurfaceOstium.findNearestPosition( xTrackSurface[n2 * (elementsCountAroundHaustrum + 1) + elementsCountAroundHaustrum]) xProportionB = trackSurfaceOstium.getProportion(xPositionB) derivativeB = d1TrackSurface[n2 * (elementsCountAroundHaustrum + 1) + elementsCountAroundHaustrum] + derivativeMagnitudeB = vector.magnitude(derivativeB) nx, nd1, nd2, nd3, proportions = \ trackSurfaceOstium.createHermiteCurvePoints( @@ -1362,15 +1372,9 @@ def createCecumMesh3d(region, options, centralPath, nodeIdentifier, elementIdent nx, nd1 = \ trackSurfaceOstium.resampleHermiteCurvePointsSmooth( - nx, nd1, nd2, nd3, proportions)[0:2] + nx, nd1, nd2, nd3, proportions, derivativeMagnitudeStart=derivativeMagnitudeA, + derivativeMagnitudeEnd=derivativeMagnitudeB)[0:2] - if n2 == rowsBelow + 1 or n2 == rowsBelow + rowsOstium - 1: - mag = 0.5 * (vector.magnitude(d1AnnulusOuter[0]) + vector.magnitude( - d2AnnulusOuter[0])) if n2 == startRowIdx else vector.magnitude(d1AnnulusOuter[0]) - if n == 0: - nd1[-1] = vector.setMagnitude(nd1[-1], mag) - else: - nd1[0] = vector.setMagnitude(nd1[0], mag) if n == 0: xAround += nx d1Around += nd1 @@ -1380,7 +1384,6 @@ def createCecumMesh3d(region, options, centralPath, nodeIdentifier, elementIdent if n2 < rowsBelow + 1 or n2 >= rowsBelow + rowsOstium: d1Around = interp.smoothCubicHermiteDerivativesLine(xAround, d1Around, fixStartDerivative=True, fixEndDerivative=True) - if n2 >= rowsBelow + 1 and n2 < rowsBelow + rowsOstium: annulusIdx += 1 @@ -1394,6 +1397,7 @@ def createCecumMesh3d(region, options, centralPath, nodeIdentifier, elementIdent d1Around.append(d1TrackSurface[n1 + (elementsCountAroundHaustrum + 1) * elementsCountAlongSegment]) xAroundAlong.append(xAround) d1AroundAlong.append(d1Around) + d1AroundAlongOriginal = copy.deepcopy(d1AroundAlong) # Calculate d2 along segment d2AroundAlong = [] @@ -1409,7 +1413,10 @@ def createCecumMesh3d(region, options, centralPath, nodeIdentifier, elementIdent for n1 in range(elementsCountAroundHaustrum + 1): nxAlong = [] nd2Along = [] - if n1 < elementsCountAroundHalfHaustrum - 1: + nxTop = [] + nd2Top = [] + annulusIdx = 1 + if n1 < elementsCountAroundHalfHaustrum - 2: for n2 in range(elementsCountAlongSegment): nxAlong.append(xAroundAlong[n2][n1]) nd2Along.append(findDerivativeBetweenPoints(xAroundAlong[n2][n1], xAroundAlong[n2 + 1][n1])) @@ -1418,16 +1425,54 @@ def createCecumMesh3d(region, options, centralPath, nodeIdentifier, elementIdent nd2Along = interp.smoothCubicHermiteDerivativesLine(nxAlong, nd2Along, fixStartDerivative=True, fixEndDerivative=True) - # Replace d2 on node along annulus LHS with d2Annulus - if n1 == elementsCountAroundHalfHaustrum - 2: - nd2Along[startRowIdx] = d2AnnulusOuter[1] - nd2Along[endRowIdx] = d2AnnulusOuter[int(elementsCountAroundOstium * 0.5) - 1] + xAlongAll.append(nxAlong) + d2AlongAll.append(nd2Along) + + for n2 in range(len(nd2Along)): + d2AroundAlong[n2][n1] = nd2Along[n2] + + # Deal with annulus + elif n1 == elementsCountAroundHalfHaustrum - 2: + # Smooth from apex to annulus + for n2 in range(startRowIdx + 1): + nxAlong.append(xAroundAlong[n2][n1]) + nd2Along.append(findDerivativeBetweenPoints(xAroundAlong[n2][n1], xAroundAlong[n2 + 1][n1])) + nd2Along = interp.smoothCubicHermiteDerivativesLine(nxAlong, nd2Along, fixStartDerivative=True) + nd2AlongBottomLHS = interp.smoothCubicHermiteDerivativesLine(nxAlong, nd2Along, fixStartDerivative=True) + + # Make sure d2 at annulus is length of element below + nd2Along[-1] = vector.setMagnitude(d1AnnulusOuter[1], vector.magnitude(nd2Along[-1])) + + # Make magnitude of annulus d2 between start and end row equivalent to arclength of element on its left + for m in range(endRowIdx - startRowIdx - 1): + nxAlong.append(xAnnulusOuter[2 + m]) + n2Idx = m + startRowIdx + 1 + nd2Along.append(vector.setMagnitude(d1AnnulusOuter[2+m], vector.magnitude(d1AroundAlong[n2Idx][n1]))) + + # Smooth from annulus to end of cecum + for n2 in range(endRowIdx, elementsCountAlongSegment): + nxTop.append(xAroundAlong[n2][n1]) + nd2Top.append(findDerivativeBetweenPoints(xAroundAlong[n2][n1], xAroundAlong[n2 + 1][n1])) + nxTop.append(xAroundAlong[elementsCountAlongSegment][n1]) + nd2Top.append(d2TrackSurface[(elementsCountAroundHaustrum + 1) * elementsCountAlongSegment + n1]) + nd2Top = interp.smoothCubicHermiteDerivativesLine(nxTop, nd2Top, fixEndDerivative=True) + nd2AlongTopLHS = interp.smoothCubicHermiteDerivativesLine(nxTop, nd2Top, fixEndDerivative=True) + + # Make sure d2 at annulus is length of element above + nd2Top[0] = vector.setMagnitude(d1AnnulusOuter[int(elementsCountAroundOstium * 0.5) - 1], + vector.magnitude(nd2Top[0])) + + nxAlong += nxTop + nd2Along += nd2Top xAlongAll.append(nxAlong) d2AlongAll.append(nd2Along) for n2 in range(len(nd2Along)): d2AroundAlong[n2][n1] = nd2Along[n2] + if n1 == elementsCountAroundHalfHaustrum - 2 and startRowIdx -1 < n2 < endRowIdx + 1: + d1AroundAlong[n2][n1] = d2AnnulusOuter[annulusIdx] + annulusIdx += 1 elif n1 == elementsCountAroundHalfHaustrum - 1: for n2 in range(len(pxAlongMidLine)): @@ -1438,6 +1483,57 @@ def createCecumMesh3d(region, options, centralPath, nodeIdentifier, elementIdent xAlongAll.append(nxAlong) d2AlongAll.append(pd2AlongMidLine + pd2AlongMidLineBottom) + elif n1 == elementsCountAroundHalfHaustrum: + # Smooth from apex to annulus + for n2 in range(startRowIdx + 1): + nxAlong.append(xAroundAlong[n2][n1 + (0 if n2 < startRowIdx else -1)]) + nd2Along.append(findDerivativeBetweenPoints(xAroundAlong[n2][n1], xAroundAlong[n2 + 1][n1])) + nd2Along = interp.smoothCubicHermiteDerivativesLine(nxAlong, nd2Along, fixStartDerivative=True) + nd2AlongBottomRHS = interp.smoothCubicHermiteDerivativesLine(nxAlong, nd2Along, fixStartDerivative=True) + + # Make sure d2 at annulus is length of element below + nd2Along[-1] = vector.setMagnitude(d1AnnulusOuter[-1], vector.magnitude(nd2Along[-1])) + + # Make magnitude of annulus d2 between start and end row equivalent to arclength of element on its right + for m in range(endRowIdx - startRowIdx - 1): + nxAlong.append(xAnnulusOuter[-(2 + m)]) + n2Idx = m + startRowIdx + 1 + nd2Along.append(vector.setMagnitude(d1AnnulusOuter[-(2 + m)], vector.magnitude(d1AroundAlong[n2Idx][n1 - 1]))) + + # Smooth from annulus to end of cecum + for n2 in range(endRowIdx, elementsCountAlongSegment): + nxTop.append(xAroundAlong[n2][n1 + (0 if n2 > endRowIdx else -1)]) + if n2 > endRowIdx - 1: + nxAlongNext = xAroundAlong[n2 + 1][n1] + else: + nxAlongNext = xAroundAlong[n2 + 1][n1 - 1] + nd2Top.append(findDerivativeBetweenPoints(xAroundAlong[n2][n1 + (0 if n2 > endRowIdx else -1)], + nxAlongNext)) + nxTop.append(xAroundAlong[elementsCountAlongSegment][n1]) + nd2Top.append(d2TrackSurface[(elementsCountAroundHaustrum + 1) * elementsCountAlongSegment + n1]) + nd2Top = interp.smoothCubicHermiteDerivativesLine(nxTop, nd2Top, fixEndDerivative=True) + nd2AlongTopRHS = interp.smoothCubicHermiteDerivativesLine(nxTop, nd2Top, fixEndDerivative=True) + + # Make sure d2 at annulus is length of element above + nd2Top[0] = vector.setMagnitude(d1AnnulusOuter[int(elementsCountAroundOstium * 0.5) + 1], + vector.magnitude(nd2Top[0])) + + nxAlong += nxTop + nd2Along += nd2Top + + xAlongAll.append(nxAlong) + d2AlongAll.append(nd2Along) + + for n2 in range(len(nd2Along)): + if n2 < startRowIdx or n2 > endRowIdx: + n1Idx = n1 + else: + n1Idx = n1 - 1 + if n1 == elementsCountAroundHalfHaustrum: + d1AroundAlong[n2][n1Idx] = d2AnnulusOuter[-annulusIdx] + annulusIdx += 1 + d2AroundAlong[n2][n1Idx] = nd2Along[n2] + else: for n2 in range(elementsCountAlongSegment): nxAlong.append(xAroundAlong[n2][n1 + (0 if (n2 < startRowIdx or n2 > endRowIdx) else -1)]) @@ -1445,19 +1541,13 @@ def createCecumMesh3d(region, options, centralPath, nodeIdentifier, elementIdent nxAlongNext = xAroundAlong[n2 + 1][n1] else: nxAlongNext = xAroundAlong[n2 + 1][n1 - 1] - nd2Along.append(findDerivativeBetweenPoints( - xAroundAlong[n2][n1 + (0 if (n2 < startRowIdx or n2 > endRowIdx) else -1)], nxAlongNext)) + nd2Along.append(findDerivativeBetweenPoints(xAroundAlong[n2][n1 + (0 if (n2 < startRowIdx or n2 > endRowIdx) else -1)], nxAlongNext)) nxAlong.append(xAroundAlong[n2 + 1][n1]) nd2Along.append(d2TrackSurface[(elementsCountAroundHaustrum + 1) * elementsCountAlongSegment + n1]) nd2Along = interp.smoothCubicHermiteDerivativesLine(nxAlong, nd2Along, fixStartDerivative=True, fixEndDirection=True) - # Replace d2 on node along annulus RHS with d2Annulus - if n1 == elementsCountAroundHalfHaustrum: - nd2Along[startRowIdx] = [-d for d in d2AnnulusOuter[-1]] - nd2Along[endRowIdx] = [-d for d in d2AnnulusOuter[int(elementsCountAroundOstium * 0.5) + 1]] - xAlongAll.append(nxAlong) d2AlongAll.append(nd2Along) @@ -1484,18 +1574,17 @@ def createCecumMesh3d(region, options, centralPath, nodeIdentifier, elementIdent d1Curvature.append([0.0]) for n2 in range(1 if segmentIdx == 0 else 0, elementsCountAlongSegment + 1): - if n2 < startRowIdx or n2 == elementsCountAlongSegment: - d1Curvature.append(interp.findCurvatureAlongLine(xAroundAlong[n2], d1AroundAlong[n2], + if n2 < startRowIdx or n2 > endRowIdx: #== elementsCountAlongSegment: + d1Curvature.append(interp.findCurvatureAlongLine(xAroundAlong[n2], d1AroundAlongOriginal[n2], d3UnitAroundAlong[n2])) else: d1CurvatureLeft = interp.findCurvatureAlongLine(xAroundAlong[n2][:int(0.5 * len(xAroundAlong[n2]))], - d1AroundAlong[n2][:int(0.5 * len(xAroundAlong[n2]))], + d1AroundAlongOriginal[n2][:int(0.5 * len(xAroundAlong[n2]))], d3UnitAroundAlong[n2][:int(0.5 * len(xAroundAlong[n2]))]) d1CurvatureRight = interp.findCurvatureAlongLine(xAroundAlong[n2][int(0.5 * len(xAroundAlong[n2])):], - d1AroundAlong[n2][int(0.5 * len(xAroundAlong[n2])):], + d1AroundAlongOriginal[n2][int(0.5 * len(xAroundAlong[n2])):], d3UnitAroundAlong[n2][int(0.5 * len(xAroundAlong[n2])):]) - d1Curvature.append(d1CurvatureLeft + d1CurvatureRight) # Curvatures along @@ -1510,43 +1599,84 @@ def createCecumMesh3d(region, options, centralPath, nodeIdentifier, elementIdent xAlong = xAlongAll[n1] d2Along = d2AlongAll[n1] d3UnitAlong = [] + annulusIdx = 1 - if n1 < elementsCountAroundHalfHaustrum - 1: + if n1 < elementsCountAroundHalfHaustrum - 2: for n2 in range(elementsCountAlongSegment): d3UnitAlong.append(d3UnitAroundAlong[n2][n1]) d3UnitAlong.append(d3UnitAroundAlong[n2 + 1][n1]) d2CurvatureAlong = interp.findCurvatureAlongLine(xAlong, d2Along, d3UnitAlong) - # Adjust for corners - if n1 == elementsCountAroundHalfHaustrum - 2: - d2CurvatureAlong[endRowIdx] = annulusD2Curvature[int(elementsCountAlongSegment * 0.5) - 1] for n2 in range(len(d2CurvatureAlong)): d2Curvature[n2][n1] = d2CurvatureAlong[n2] + elif n1 == elementsCountAroundHalfHaustrum - 2: + # From apex to annulus + for n2 in range(elementsCountAlongSegment): + d3UnitAlong.append(d3UnitAroundAlong[n2][n1]) + d3UnitAlong.append(d3UnitAroundAlong[n2 + 1][n1]) + d2CurvatureAlong = interp.findCurvatureAlongLine(xAlong[:startRowIdx + 1], nd2AlongBottomLHS, + d3UnitAlong[:startRowIdx + 1]) + + # Curvature of nodes along LHS annulus + for m in range(endRowIdx - startRowIdx - 1): + d2CurvatureAlong.append(d1Curvature[m + startRowIdx + 1][n1]) + + # From annulus to distal end + d2CurvatureAlong += interp.findCurvatureAlongLine(xAlong[endRowIdx:], nd2AlongTopLHS, + d3UnitAlong[endRowIdx:]) + + for n2 in range(len(d2CurvatureAlong)): + d2Curvature[n2][n1] = d2CurvatureAlong[n2] + + for n2 in range(startRowIdx, endRowIdx + 1): + d1Curvature[n2][n1] = annulusD2Curvature[annulusIdx] + annulusIdx += 1 + elif n1 == elementsCountAroundHalfHaustrum - 1: - xAlong = [] - d2Along = [] - d3UnitAlong = [] - for n2 in range(len(pd2AlongMidLine)): - xAlong.append(xAroundAlong[n2][n1]) - d2Along.append(d2AroundAlong[n2][n1]) + # From apex to annulus + for n2 in range(len(pxAlongMidLine)): d3UnitAlong.append(d3UnitAroundAlong[n2][n1]) - d2CurvatureAlong = interp.findCurvatureAlongLine(xAlong, d2Along, d3UnitAlong) - for n2 in range(len(pd2AlongMidLine)): + d2CurvatureAlong = interp.findCurvatureAlongLine(pxAlongMidLine, pd2AlongMidLine, d3UnitAlong) + d2CurvatureAnnulusZero = d2CurvatureAlong[-1] + for n2 in range(len(d2CurvatureAlong) - 1): d2Curvature[n2][n1] = d2CurvatureAlong[n2] - # Calculate curvature for node on edge - xAlong = [] - d2Along = [] d3UnitAlong = [] + for n in range(len(pxAlongMidLineBottom)): + d3UnitAlong.append(d3UnitAroundAlong[n + endRowIdx][n1]) + d2CurvatureAlong = interp.findCurvatureAlongLine(pxAlongMidLineBottom, pd2AlongMidLineBottom, d3UnitAlong) + d2CurvatureAlongHalfOstium = d2CurvatureAlong[0] for n in range(1, len(pd2AlongMidLineBottom)): nIdx = n + endRowIdx - xAlong.append(xAroundAlong[nIdx][n1]) - d2Along.append(d2AroundAlong[nIdx][n1]) - d3UnitAlong.append(d3UnitAroundAlong[nIdx][n1]) - d2CurvatureAlong = interp.findCurvatureAlongLine(xAlong, d2Along, d3UnitAlong) - for n in range(len(pd2AlongMidLineBottom) - 1): - nIdx = n + endRowIdx + 1 d2Curvature[nIdx][n1] = d2CurvatureAlong[n] + + elif n1 == elementsCountAroundHalfHaustrum: + # From apex to annulus + for n2 in range(elementsCountAlongSegment): + d3UnitAlong.append(d3UnitAroundAlong[n2][n1 + (0 if (n2 < startRowIdx or n2 > endRowIdx) else -1)]) + d3UnitAlong.append(d3UnitAroundAlong[n2 + 1][n1]) + d2CurvatureAlong = interp.findCurvatureAlongLine(xAlong[:startRowIdx + 1], nd2AlongBottomRHS, + d3UnitAlong[:startRowIdx + 1]) + + # Curvature of nodes along LHS annulus + for m in range(endRowIdx - startRowIdx - 1): + d2CurvatureAlong.append(d1Curvature[m + startRowIdx + 1][n1 - 1]) + + # From annulus to distal end + d2CurvatureAlong += interp.findCurvatureAlongLine(xAlong[endRowIdx:], nd2AlongTopRHS, + d3UnitAlong[endRowIdx:]) + + for n2 in range(len(d2CurvatureAlong)): + if n2 < startRowIdx or n2 > endRowIdx: + n1Idx = n1 + else: + n1Idx = n1 - 1 + d2Curvature[n2][n1Idx] = d2CurvatureAlong[n2] + + for n2 in range(startRowIdx, endRowIdx + 1): + d1Curvature[n2][n1] = annulusD2Curvature[-annulusIdx] + annulusIdx += 1 + else: for n2 in range(elementsCountAlongSegment): d3UnitAlong.append(d3UnitAroundAlong[n2][n1 + (0 if (n2 < startRowIdx or n2 > endRowIdx) else -1)]) @@ -1564,24 +1694,21 @@ def createCecumMesh3d(region, options, centralPath, nodeIdentifier, elementIdent n1Idx = n1 - 1 d2Curvature[n2][n1Idx] = d2CurvatureAlong[n2] - # Slot in annulus points along the midline - rotFrame = matrix.getRotationMatrixFromAxisAngle(d3Annulus[0], math.pi) - rotD2 = [rotFrame[j][0] * d2AnnulusOuter[0][0] + rotFrame[j][1] * d2AnnulusOuter[0][1] + - rotFrame[j][2] * d2AnnulusOuter[0][2] for j in range(3)] + # Adjust annulus points xAroundAlong[startRowIdx].insert(int(elementsCountAroundHaustrum * 0.5), xAnnulusOuter[0]) - d1AroundAlong[startRowIdx].insert(int(elementsCountAroundHaustrum * 0.5), rotD2) - d2AroundAlong[startRowIdx].insert(int(elementsCountAroundHaustrum * 0.5), d1AnnulusOuter[0]) + d1AroundAlong[startRowIdx].insert(int(elementsCountAroundHaustrum * 0.5), d2AnnulusOuter[0]) + d2AroundAlong[startRowIdx].insert(int(elementsCountAroundHaustrum * 0.5), vector.setMagnitude(d1AnnulusOuter[0], annulusD2ZeroMag)) d3UnitAroundAlong[startRowIdx].insert(int(elementsCountAroundHaustrum * 0.5), d3Annulus[0]) d1Curvature[startRowIdx].insert(int(elementsCountAroundHaustrum * 0.5), annulusD2Curvature[0]) - d2Curvature[startRowIdx].insert(int(elementsCountAroundHaustrum * 0.5), annulusD2Curvature[0]) + d2Curvature[startRowIdx].insert(int(elementsCountAroundHaustrum * 0.5), d2CurvatureAnnulusZero) idx = int(elementsCountAlongSegment * 0.5) xAroundAlong[endRowIdx].insert(int(elementsCountAroundHaustrum * 0.5), xAnnulusOuter[idx]) d1AroundAlong[endRowIdx].insert(int(elementsCountAroundHaustrum * 0.5), d2AnnulusOuter[idx]) - d2AroundAlong[endRowIdx].insert(int(elementsCountAroundHaustrum * 0.5), d1AnnulusOuter[idx]) + d2AroundAlong[endRowIdx].insert(int(elementsCountAroundHaustrum * 0.5), vector.setMagnitude(d1AnnulusOuter[idx], annulusD2HalfOstiumMag)) d3UnitAroundAlong[endRowIdx].insert(int(elementsCountAroundHaustrum * 0.5), d3Annulus[idx]) d1Curvature[endRowIdx].insert(int(elementsCountAroundHaustrum * 0.5), annulusD2Curvature[idx]) - d2Curvature[endRowIdx].insert(int(elementsCountAroundHaustrum * 0.5), annulusD2Curvature[idx]) + d2Curvature[endRowIdx].insert(int(elementsCountAroundHaustrum * 0.5), d2CurvatureAlongHalfOstium) # Create inner nodes sideNodesToDelete = [] @@ -1763,86 +1890,180 @@ def createCecumMesh3d(region, options, centralPath, nodeIdentifier, elementIdent nodeIdentifiers = [bni111, bni211, bni121, bni221, bni112, bni212, bni122, bni222] - if e2 == startRowIdx - 1 and e1 == elementsCountAroundHalfHaustrum - 2: # LHS bottom - scaleFactors = [-1.0] - eft1 = eftfactory.createEftNoCrossDerivatives() - setEftScaleFactorIds(eft1, [1], []) - remapEftNodeValueLabel(eft1, [3, 7], Node.VALUE_LABEL_D_DS1, - [(Node.VALUE_LABEL_D_DS2, [1])]) - remapEftNodeValueLabel(eft1, [3, 7], Node.VALUE_LABEL_D_DS2, - [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [])]) - remapEftNodeValueLabel(eft1, [4, 8], Node.VALUE_LABEL_D_DS2, - [(Node.VALUE_LABEL_D_DS2, [1])]) - - elementtemplateX.defineField(coordinates, -1, eft1) - elementtemplate1 = elementtemplateX - - elif e2 == startRowIdx - 1 and e1 == elementsCountAroundHalfHaustrum - 1: # RHS bottom - scaleFactors = [-1.0] - eft1 = eftfactory.createEftNoCrossDerivatives() - setEftScaleFactorIds(eft1, [1], []) - remapEftNodeValueLabel(eft1, [3, 7], Node.VALUE_LABEL_D_DS2, - [(Node.VALUE_LABEL_D_DS2, [1])]) - remapEftNodeValueLabel(eft1, [4, 8], Node.VALUE_LABEL_D_DS2, - [(Node.VALUE_LABEL_D_DS1, [1]), (Node.VALUE_LABEL_D_DS2, [])]) - remapEftNodeValueLabel(eft1, [4, 8], Node.VALUE_LABEL_D_DS1, - [(Node.VALUE_LABEL_D_DS2, [])]) - elementtemplateX.defineField(coordinates, -1, eft1) - elementtemplate1 = elementtemplateX - - elif e2 == startRowIdx - 1 and e1 == elementsCountAroundHalfHaustrum: # RHS bottom + 1 - scaleFactors = [-1.0] - eft1 = eftfactory.createEftNoCrossDerivatives() - setEftScaleFactorIds(eft1, [1], []) - remapEftNodeValueLabel(eft1, [3, 7], Node.VALUE_LABEL_D_DS2, - [(Node.VALUE_LABEL_D_DS1, [1]), (Node.VALUE_LABEL_D_DS2, [])]) - elementtemplateX.defineField(coordinates, -1, eft1) - elementtemplate1 = elementtemplateX - - elif e2 == startRowIdx - 1 and e1 == elementsCountAroundHalfHaustrum - 3: # LHS Bottom Left - 1 - eft1 = eftfactory.createEftNoCrossDerivatives() - remapEftNodeValueLabel(eft1, [4, 8], Node.VALUE_LABEL_D_DS2, - [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [])]) - elementtemplateX.defineField(coordinates, -1, eft1) - elementtemplate1 = elementtemplateX - - elif e2 == endRowIdx and e1 == elementsCountAroundHalfHaustrum - 2: # end LHS - scaleFactors = [-1.0] - eft1 = eftfactory.createEftNoCrossDerivatives() - setEftScaleFactorIds(eft1, [1], []) - remapEftNodeValueLabel(eft1, [1, 5], Node.VALUE_LABEL_D_DS2, - [(Node.VALUE_LABEL_D_DS1, [1]), (Node.VALUE_LABEL_D_DS2, [])]) - remapEftNodeValueLabel(eft1, [1, 5], Node.VALUE_LABEL_D_DS1, [(Node.VALUE_LABEL_D_DS2, [])]) - elementtemplateX.defineField(coordinates, -1, eft1) - elementtemplate1 = elementtemplateX - - elif e2 == endRowIdx and e1 == elementsCountAroundHalfHaustrum - 3: # end LHS -1 - scaleFactors = [-1.0] - eft1 = eftfactory.createEftNoCrossDerivatives() - setEftScaleFactorIds(eft1, [1], []) - remapEftNodeValueLabel(eft1, [2, 6], Node.VALUE_LABEL_D_DS2, - [(Node.VALUE_LABEL_D_DS1, [1]), (Node.VALUE_LABEL_D_DS2, [])]) - elementtemplateX.defineField(coordinates, -1, eft1) - elementtemplate1 = elementtemplateX - - elif e2 == endRowIdx and e1 == elementsCountAroundHalfHaustrum - 1: # end RHS - scaleFactors = [-1.0] - eft1 = eftfactory.createEftNoCrossDerivatives() - setEftScaleFactorIds(eft1, [1], []) - remapEftNodeValueLabel(eft1, [2, 6], Node.VALUE_LABEL_D_DS1, - [(Node.VALUE_LABEL_D_DS2, [1])]) - remapEftNodeValueLabel(eft1, [2, 6], Node.VALUE_LABEL_D_DS2, - [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [])]) - - elementtemplateX.defineField(coordinates, -1, eft1) - elementtemplate1 = elementtemplateX - - elif e2 == endRowIdx and e1 == elementsCountAroundHalfHaustrum: # end RHS + 1 - eft1 = eftfactory.createEftNoCrossDerivatives() - remapEftNodeValueLabel(eft1, [1, 5], Node.VALUE_LABEL_D_DS2, - [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [])]) - elementtemplateX.defineField(coordinates, -1, eft1) - elementtemplate1 = elementtemplateX + if e2 == startRowIdx - 1: + if e1 == elementsCountAroundHalfHaustrum - 3: + scaleFactors = [-1.0] + eft1 = eftfactory.createEftNoCrossDerivatives() + setEftScaleFactorIds(eft1, [1], []) + remapEftNodeValueLabel(eft1, [4, 8], Node.VALUE_LABEL_D_DS1, + [(Node.VALUE_LABEL_D_DS1, [1]), (Node.VALUE_LABEL_D_DS2, [1])]) + remapEftNodeValueLabel(eft1, [4, 8], Node.VALUE_LABEL_D_DS2, + [(Node.VALUE_LABEL_D_DS2, [1])]) + elementtemplateX.defineField(coordinates, -1, eft1) + elementtemplate1 = elementtemplateX + # print(elementIdentifier) # 331 + + elif e1 == elementsCountAroundHalfHaustrum - 2: # LHS bottom + scaleFactors = [-1.0] + eft1 = eftfactory.createEftNoCrossDerivatives() + setEftScaleFactorIds(eft1, [1], []) + remapEftNodeValueLabel(eft1, [3, 7], Node.VALUE_LABEL_D_DS1, + [(Node.VALUE_LABEL_D_DS1, [1])]) + remapEftNodeValueLabel(eft1, [3, 7], Node.VALUE_LABEL_D_DS2, + [(Node.VALUE_LABEL_D_DS2, [1])]) + remapEftNodeValueLabel(eft1, [4, 8], Node.VALUE_LABEL_D_DS1, + [(Node.VALUE_LABEL_D_DS1, [1])]) + remapEftNodeValueLabel(eft1, [4, 8], Node.VALUE_LABEL_D_DS2, + [(Node.VALUE_LABEL_D_DS2, [1])]) + # print(elementIdentifier) # 332 + elementtemplateX.defineField(coordinates, -1, eft1) + elementtemplate1 = elementtemplateX + + elif e1 == elementsCountAroundHalfHaustrum - 1: # RHS bottom + scaleFactors = [-1.0] + eft1 = eftfactory.createEftNoCrossDerivatives() + setEftScaleFactorIds(eft1, [1], []) + remapEftNodeValueLabel(eft1, [3, 7], Node.VALUE_LABEL_D_DS1, + [(Node.VALUE_LABEL_D_DS1, [1])]) + remapEftNodeValueLabel(eft1, [3, 7], Node.VALUE_LABEL_D_DS2, + [(Node.VALUE_LABEL_D_DS2, [1])]) + remapEftNodeValueLabel(eft1, [4, 8], Node.VALUE_LABEL_D_DS2, + [(Node.VALUE_LABEL_D_DS2, [1])]) + remapEftNodeValueLabel(eft1, [4, 8], Node.VALUE_LABEL_D_DS1, + [(Node.VALUE_LABEL_D_DS1, [1])]) + # print(elementIdentifier) # 333 + elementtemplateX.defineField(coordinates, -1, eft1) + elementtemplate1 = elementtemplateX + + elif e1 == elementsCountAroundHalfHaustrum: + scaleFactors = [-1.0] + eft1 = eftfactory.createEftNoCrossDerivatives() + setEftScaleFactorIds(eft1, [1], []) + remapEftNodeValueLabel(eft1, [3, 7], Node.VALUE_LABEL_D_DS2, + [(Node.VALUE_LABEL_D_DS2, [1])]) + remapEftNodeValueLabel(eft1, [3, 7], Node.VALUE_LABEL_D_DS1, + [(Node.VALUE_LABEL_D_DS1, [1]), (Node.VALUE_LABEL_D_DS2, [])]) + elementtemplateX.defineField(coordinates, -1, eft1) + elementtemplate1 = elementtemplateX + # print(elementIdentifier) #334 + + elif e2 == startRowIdx: + if e1 == elementsCountAroundHalfHaustrum - 3: + scaleFactors = [-1.0] + eft1 = eftfactory.createEftNoCrossDerivatives() + setEftScaleFactorIds(eft1, [1], []) + remapEftNodeValueLabel(eft1, [2, 6], Node.VALUE_LABEL_D_DS1, + [(Node.VALUE_LABEL_D_DS1, [1]), (Node.VALUE_LABEL_D_DS2, [1])]) + remapEftNodeValueLabel(eft1, [2, 6], Node.VALUE_LABEL_D_DS2, + [(Node.VALUE_LABEL_D_DS1, [])]) + remapEftNodeValueLabel(eft1, [4, 8], Node.VALUE_LABEL_D_DS1, + [(Node.VALUE_LABEL_D_DS2, [1])]) + remapEftNodeValueLabel(eft1, [4, 8], Node.VALUE_LABEL_D_DS2, + [(Node.VALUE_LABEL_D_DS1, [])]) + elementtemplateX.defineField(coordinates, -1, eft1) + elementtemplate1 = elementtemplateX + # print(elementIdentifier) # 339 + + elif e1 == elementsCountAroundHalfHaustrum: + scaleFactors = [-1.0] + eft1 = eftfactory.createEftNoCrossDerivatives() + setEftScaleFactorIds(eft1, [1], []) + remapEftNodeValueLabel(eft1, [1, 5], Node.VALUE_LABEL_D_DS2, + [(Node.VALUE_LABEL_D_DS1, [1])]) + remapEftNodeValueLabel(eft1, [1, 5], Node.VALUE_LABEL_D_DS1, + [(Node.VALUE_LABEL_D_DS1, [1]), (Node.VALUE_LABEL_D_DS2, [])]) + remapEftNodeValueLabel(eft1, [3, 7], Node.VALUE_LABEL_D_DS2, + [(Node.VALUE_LABEL_D_DS1, [1])]) + remapEftNodeValueLabel(eft1, [3, 7], Node.VALUE_LABEL_D_DS1, + [(Node.VALUE_LABEL_D_DS2, [])]) + elementtemplateX.defineField(coordinates, -1, eft1) + elementtemplate1 = elementtemplateX + # print(elementIdentifier) # 340 + + elif int(elementsCountAroundOstium*0.25) - 2 > 0 and startRowIdx + 1 <= e2 < startRowIdx + 1 + 2.0 * (int(elementsCountAroundOstium*0.25) - 2): + if e1 == elementsCountAroundHalfHaustrum - 3: + scaleFactors = [-1.0] + eft1 = eftfactory.createEftNoCrossDerivatives() + setEftScaleFactorIds(eft1, [1], []) + remapEftNodeValueLabel(eft1, [2, 6], Node.VALUE_LABEL_D_DS1, + [(Node.VALUE_LABEL_D_DS2, [1])]) + remapEftNodeValueLabel(eft1, [2, 6], Node.VALUE_LABEL_D_DS2, + [(Node.VALUE_LABEL_D_DS1, [])]) + remapEftNodeValueLabel(eft1, [4, 8], Node.VALUE_LABEL_D_DS1, + [(Node.VALUE_LABEL_D_DS2, [1])]) + remapEftNodeValueLabel(eft1, [4, 8], Node.VALUE_LABEL_D_DS2, + [(Node.VALUE_LABEL_D_DS1, [])]) + elementtemplateX.defineField(coordinates, -1, eft1) + elementtemplate1 = elementtemplateX + # print(elementIdentifier) # 183, 201 + + elif e1 == elementsCountAroundHalfHaustrum - 1: + scaleFactors = [-1.0] + eft1 = eftfactory.createEftNoCrossDerivatives() + setEftScaleFactorIds(eft1, [1], []) + remapEftNodeValueLabel(eft1, [1, 5], Node.VALUE_LABEL_D_DS2, + [(Node.VALUE_LABEL_D_DS1, [1])]) + remapEftNodeValueLabel(eft1, [1, 5], Node.VALUE_LABEL_D_DS1, + [(Node.VALUE_LABEL_D_DS2, [])]) + remapEftNodeValueLabel(eft1, [3, 7], Node.VALUE_LABEL_D_DS2, + [(Node.VALUE_LABEL_D_DS1, [1])]) + remapEftNodeValueLabel(eft1, [3, 7], Node.VALUE_LABEL_D_DS1, + [(Node.VALUE_LABEL_D_DS2, [])]) + elementtemplateX.defineField(coordinates, -1, eft1) + elementtemplate1 = elementtemplateX + # print(elementIdentifier) # 184, 202 + + elif e2 == endRowIdx - 1: + if e1 == elementsCountAroundHalfHaustrum - 3: + scaleFactors = [-1.0] + eft1 = eftfactory.createEftNoCrossDerivatives() + setEftScaleFactorIds(eft1, [1], []) + remapEftNodeValueLabel(eft1, [2, 6], Node.VALUE_LABEL_D_DS1, + [(Node.VALUE_LABEL_D_DS2, [1])]) + remapEftNodeValueLabel(eft1, [2, 6], Node.VALUE_LABEL_D_DS2, + [(Node.VALUE_LABEL_D_DS1, [])]) + remapEftNodeValueLabel(eft1, [4, 8], Node.VALUE_LABEL_D_DS1, + [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [1])]) + remapEftNodeValueLabel(eft1, [4, 8], Node.VALUE_LABEL_D_DS2, + [(Node.VALUE_LABEL_D_DS1, [])]) + elementtemplateX.defineField(coordinates, -1, eft1) + elementtemplate1 = elementtemplateX + # print(elementIdentifier) # 345 + + elif e1 == elementsCountAroundHalfHaustrum - 1: + scaleFactors = [-1.0] + eft1 = eftfactory.createEftNoCrossDerivatives() + setEftScaleFactorIds(eft1, [1], []) + remapEftNodeValueLabel(eft1, [1, 5], Node.VALUE_LABEL_D_DS2, + [(Node.VALUE_LABEL_D_DS1, [1])]) + remapEftNodeValueLabel(eft1, [1, 5], Node.VALUE_LABEL_D_DS1, + [(Node.VALUE_LABEL_D_DS2, [])]) + remapEftNodeValueLabel(eft1, [3, 7], Node.VALUE_LABEL_D_DS2, + [(Node.VALUE_LABEL_D_DS1, [1])]) + remapEftNodeValueLabel(eft1, [3, 7], Node.VALUE_LABEL_D_DS1, + [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [])]) + elementtemplateX.defineField(coordinates, -1, eft1) + elementtemplate1 = elementtemplateX + # print(elementIdentifier) # 346 + + elif e2 == endRowIdx: + if e1 == elementsCountAroundHalfHaustrum - 3: # end LHS -1 + scaleFactors = [-1.0] + eft1 = eftfactory.createEftNoCrossDerivatives() + setEftScaleFactorIds(eft1, [1], []) + remapEftNodeValueLabel(eft1, [2, 6], Node.VALUE_LABEL_D_DS1, + [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [1])]) + elementtemplateX.defineField(coordinates, -1, eft1) + elementtemplate1 = elementtemplateX + # print('1', elementIdentifier) #351 + + elif e1 == elementsCountAroundHalfHaustrum: # end RHS + 1 + eft1 = eftfactory.createEftNoCrossDerivatives() + remapEftNodeValueLabel(eft1, [1, 5], Node.VALUE_LABEL_D_DS1, + [(Node.VALUE_LABEL_D_DS1, []), (Node.VALUE_LABEL_D_DS2, [])]) + elementtemplateX.defineField(coordinates, -1, eft1) + elementtemplate1 = elementtemplateX + # print(elementIdentifier) #354 element = mesh.createElement(elementIdentifier, elementtemplate1) element.setNodesByIdentifier(eft1, nodeIdentifiers) @@ -1896,14 +2117,7 @@ def createCecumMesh3d(region, options, centralPath, nodeIdentifier, elementIdent for n3 in range(elementsCountThroughWall + 1): for nAround in range(elementsCountAroundOstium): - if nAround == 0: - endDerivativesMap[n3][nAround] = ((-1, 0, 0), (0, 1, 0), None) - elif 1 <= nAround < int(elementsCountAroundOstium * 0.5): - endDerivativesMap[n3][nAround] = ((0, 1, 0), (-1, 0, 0), None) - elif nAround == int(elementsCountAroundOstium * 0.5): - endDerivativesMap[n3][nAround] = (None, None, None) - else: - endDerivativesMap[n3][nAround] = ((0, -1, 0), (1, 0, 0), None) + endDerivativesMap[n3][nAround] = (None, None, None) startProportions = [] for n in range(elementsCountAroundOstium): From e5c7c4e82db01f450644c1ff35e8d0e11c962d1c Mon Sep 17 00:00:00 2001 From: mlin865 Date: Wed, 27 Sep 2023 17:25:36 +1300 Subject: [PATCH 17/24] Add gastrointestinal tract --- src/scaffoldmaker/annotation/cecum_terms.py | 1 + src/scaffoldmaker/annotation/stomach_terms.py | 2 + .../meshtypes/meshtype_3d_cecum1.py | 134 ++- .../meshtypes/meshtype_3d_colon1.py | 822 +++++++++------- .../meshtypes/meshtype_3d_colonsegment1.py | 252 +++-- .../meshtypes/meshtype_3d_esophagus1.py | 708 ++++++++------ .../meshtype_3d_gastrointestinaltract1.py | 711 ++++++++++++++ .../meshtypes/meshtype_3d_ostium2.py | 66 +- .../meshtypes/meshtype_3d_smallintestine1.py | 914 ++++++++++-------- .../meshtypes/meshtype_3d_stomach1.py | 250 +++-- src/scaffoldmaker/scaffolds.py | 2 + src/scaffoldmaker/utils/tracksurface.py | 4 + src/scaffoldmaker/utils/tubemesh.py | 162 +++- 13 files changed, 2709 insertions(+), 1319 deletions(-) create mode 100644 src/scaffoldmaker/meshtypes/meshtype_3d_gastrointestinaltract1.py diff --git a/src/scaffoldmaker/annotation/cecum_terms.py b/src/scaffoldmaker/annotation/cecum_terms.py index 8a9533d5..96c0f852 100644 --- a/src/scaffoldmaker/annotation/cecum_terms.py +++ b/src/scaffoldmaker/annotation/cecum_terms.py @@ -7,6 +7,7 @@ ("caecum", "UBERON:0001153", "FMA:14541", "ILX:0732270"), ("cecum mucosa", "UBERON:0000314", "FMA:14998", "ILX:0723957"), ("circular muscle layer of cecum", "ILX:0774843"), + ("ileum part of cecum", "None"), ("longitudinal muscle layer of cecum", "ILX:0776047"), ("serosa of cecum", "ILX:0773223"), ("submucosa of cecum", "UBERON:0004927", "FMA:14999", "ILX:0725500") diff --git a/src/scaffoldmaker/annotation/stomach_terms.py b/src/scaffoldmaker/annotation/stomach_terms.py index 394dc062..bf04962d 100644 --- a/src/scaffoldmaker/annotation/stomach_terms.py +++ b/src/scaffoldmaker/annotation/stomach_terms.py @@ -23,6 +23,7 @@ ("distal point of lower esophageal sphincter serosa on the greater curvature of stomach", "ILX:0793179"), ("distal point of lower esophageal sphincter serosa on the lesser curvature of stomach", "ILX:0793180"), ("dorsal stomach", "ILX:0793086"), + ("duodenum part of stomach", "None"), ("esophagogastric junction", "UBERON:0007650", "FMA: 9434", "ILX:0733910"), ("esophagogastric junction along the greater curvature on circular-longitudinal muscle interface", "ILX:0793098"), ("esophagogastric junction along the greater curvature on luminal surface", "ILX:0793099"), @@ -30,6 +31,7 @@ ("esophagogastric junction along the lesser curvature on circular-longitudinal muscle interface", "ILX:0793101"), ("esophagogastric junction along the lesser curvature on luminal surface", "ILX:0793102"), ("esophagogastric junction along the lesser curvature on serosa", "ILX:0793103"), + ("esophagus part of stomach", "None"), ("forestomach-glandular stomach junction", "UBERON:0012270", "ILX:0729974"), ("fundus of stomach", "UBERON:0001160", " FMA:14559", "ILX:0724443"), ("fundus-body junction along the greater curvature on circular-longitudinal muscle interface", "ILX:0793104"), diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_cecum1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_cecum1.py index 0ee195ed..fa65df02 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_cecum1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_cecum1.py @@ -48,7 +48,7 @@ class MeshType_3d_cecum1(Scaffold_base): }, 'meshEdits': exnode_string_from_nodeset_field_parameters( [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ - (1, [[7.50,-20.00,0.00], [0.00,8.28,0.00], [-1.50,0.00,0.00], [0.00,0.00,0.00], [0.00,-0.00,1.50], [0.00,0.00,0.00]]), + (1, [[7.50,-20.00,0.00], [0.00,8.28,0.00], [-2.50,0.00,0.00], [0.00,0.00,0.00], [0.00,-0.00,2.50], [0.00,0.00,0.00]]), (2, [[7.50,-10.86,0.00], [0.00,10.00,0.00], [-4.50,0.00,0.00], [0.00,0.00,0.00], [0.00,-0.00,4.50], [0.00,0.00,0.00]]), (3, [[7.50,0.00,0.00], [[8.44,0.00,0.04],[0.00,11.72,0.00]], [[0.00,11.60,0.00],[-4.50,0.00,0.00]], [[1.02,6.79,0.00],[0.00,0.00,0.00]], [[0.00,0.00,11.60],[0.00,-0.00,4.50]], [[0.00,0.00,5.77],[0.00,0.00,0.00]]]), (4, [[-1.88,0.00,-0.08], [10.32,0.00,0.12], [0.00,11.60,0.00], [0.00,0.00,0.00], [0.00,0.00,11.60], [0.00,0.00,0.00]]), @@ -59,7 +59,7 @@ class MeshType_3d_cecum1(Scaffold_base): { '_AnnotationGroup': True, 'dimension': 1, - 'identifierRanges': '3-4', + 'identifierRanges': '1-4', 'name': get_cecum_term('caecum')[0], 'ontId': get_cecum_term('caecum')[1] }, @@ -67,8 +67,8 @@ class MeshType_3d_cecum1(Scaffold_base): '_AnnotationGroup': True, 'dimension': 1, 'identifierRanges': '1-2', - 'name': get_smallintestine_term('ileum')[0], - 'ontId': get_smallintestine_term('ileum')[1] + 'name': get_cecum_term('ileum part of cecum')[0], + 'ontId': get_cecum_term('ileum part of cecum')[1] }] }), 'Human 2': ScaffoldPackage(MeshType_1d_network_layout1, { @@ -77,17 +77,17 @@ class MeshType_3d_cecum1(Scaffold_base): }, 'meshEdits': exnode_string_from_nodeset_field_parameters( [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ - (1, [[-60.63,-80.53,895.25], [-6.17,-10.10,-5.87], [2.66,0.73,-4.05], [2.38,0.99,-1.14], [3.31,-2.97,1.64], [2.38,0.99,-1.14]]), - (2, [[-68.64,-93.29,888.06], [-9.85,-15.42,-8.51], [3.88,1.20,-6.66], [2.38,0.99,-1.14], [2.82,-2.46,1.20], [2.38,0.99,-1.14]]), - (3, [[-80.39,-111.37,878.29], [[-7.79,-0.98,12.36],[-13.65,-20.74,-11.03]], [[20.72,-4.04,12.54],[5.59,1.31,-9.38]], [[2.38,0.99,-1.14],[2.38,0.99,-1.14]], [[2.47,23.83,3.61],[1.51,-1.37,0.71]], [[2.38,0.99,-1.14],[2.38,0.99,-1.14]]]), - (4, [[-71.69,-109.00,866.04], [-9.55,-3.73,12.06], [17.41,-4.85,11.46], [3.73,0.68,4.20], [0.82,19.94,7.20], [3.74,0.69,4.20]]), - (5, [[-87.21,-111.06,890.54], [-5.80,1.59,12.04], [22.20,-3.00,8.61], [2.46,-0.39,-2.95], [3.05,23.70,0.39], [1.83,0.46,-4.31]]) + (1, [[-60.630,-80.530,895.250], [-6.170,-10.100,-5.870], [2.660,0.730,-4.050], [2.380,0.990,-1.140], [3.310,-2.970,1.640], [2.380,0.990,-1.140]]), + (2, [[-68.640,-93.290,888.060], [-9.850,-15.420,-8.510], [3.880,1.200,-6.660], [2.380,0.990,-1.140], [2.820,-2.460,1.200], [2.380,0.990,-1.140]]), + (3, [[-80.390,-111.370,878.290], [[-7.790,-0.980,12.360],[-13.650,-20.740,-11.030]], [[20.720,-4.040,12.540],[5.590,1.310,-9.380]], [[2.380,0.990,-1.140],[2.380,0.990,-1.140]], [[2.470,23.830,3.610],[1.510,-1.370,0.710]], [[2.380,0.990,-1.140],[2.380,0.990,-1.140]]]), + (4, [[-71.690,-109.000,866.040], [-9.550,-3.730,12.060], [17.410,-4.850,11.460], [3.730,0.680,4.200], [0.820,19.940,7.200], [3.740,0.690,4.200]]), + (5, [[-87.210,-111.060,890.540], [-4.750,0.410,12.390], [23.270,-3.130,7.880], [2.460,-0.390,-2.950], [3.090,24.460,0.450], [1.830,0.460,-4.310]]) ]), 'userAnnotationGroups': [ { '_AnnotationGroup': True, 'dimension': 1, - 'identifierRanges': '3-4', + 'identifierRanges': '1-4', 'name': get_cecum_term('caecum')[0], 'ontId': get_cecum_term('caecum')[1] }, @@ -95,8 +95,8 @@ class MeshType_3d_cecum1(Scaffold_base): '_AnnotationGroup': True, 'dimension': 1, 'identifierRanges': '1-2', - 'name': get_smallintestine_term('ileum')[0], - 'ontId': get_smallintestine_term('ileum')[1] + 'name': get_cecum_term('ileum part of cecum')[0], + 'ontId': get_cecum_term('ileum part of cecum')[1] }] }), 'Pig 1': ScaffoldPackage(MeshType_1d_network_layout1, { @@ -118,7 +118,7 @@ class MeshType_3d_cecum1(Scaffold_base): { '_AnnotationGroup': True, 'dimension': 1, - 'identifierRanges': '3-6', + 'identifierRanges': '1-6', 'name': get_cecum_term('caecum')[0], 'ontId': get_cecum_term('caecum')[1] }, @@ -126,8 +126,8 @@ class MeshType_3d_cecum1(Scaffold_base): '_AnnotationGroup': True, 'dimension': 1, 'identifierRanges': '1-2', - 'name': get_smallintestine_term('ileum')[0], - 'ontId': get_smallintestine_term('ileum')[1] + 'name': get_cecum_term('ileum part of cecum')[0], + 'ontId': get_cecum_term('ileum part of cecum')[1] }] }), } @@ -143,7 +143,7 @@ class MeshType_3d_cecum1(Scaffold_base): 'Ostium wall thickness': 1.6, 'Ostium wall relative thicknesses': [0.55, 0.15, 0.25, 0.05], 'Use linear through ostium wall': True, - 'Vessel wall thickness': 0.45, + 'Vessel wall thickness': 1.6, 'Vessel wall relative thicknesses': [0.55, 0.15, 0.25, 0.05], 'Use linear through vessel wall': True, 'Use cross derivatives': False, @@ -229,6 +229,7 @@ def getDefaultOptions(cls, parameterSetName='Default'): } if 'Human 2' in parameterSetName: + options['Number of elements along segment'] = 12 options['Segment length mid derivative factor'] = 3.0 options['Start tenia coli width'] = 10.0 options['Start tenia coli width derivative'] = 0.0 @@ -248,6 +249,7 @@ def getDefaultOptions(cls, parameterSetName='Default'): options['End tenia coli width derivative'] = 0.0 options['Wall thickness'] = 2.0 + options['Base parameter set'] = parameterSetName cls.updateSubScaffoldOptions(options) return options @@ -368,6 +370,8 @@ def updateSubScaffoldOptions(cls, options): ostiumSettings['Ostium wall thickness'] = wallThickness elementsCountThroughWall = options['Number of elements through wall'] ostiumSettings['Number of elements through wall'] = elementsCountThroughWall + ostiumSettings['Use linear through ostium wall'] = options['Use linear through wall'] + ostiumSettings['Use linear through vessel wall'] = options['Use linear through wall'] if elementsCountThroughWall == 1: ostiumSettings['Ostium wall relative thicknesses'] = [1.0] ostiumSettings['Vessel wall relative thicknesses'] = [1.0] @@ -393,11 +397,11 @@ def generateBaseMesh(cls, region, options): nextElementIdentifier = 1 cls.updateSubScaffoldOptions(options) geometricCentralPath = options['Central path'] - cecumTermsAlong = ['caecum', 'ileum'] + cecumTermsAlong = ['caecum', 'ileum part of cecum'] geometricCentralPath = CecumCentralPath(region, geometricCentralPath, cecumTermsAlong) annotationGroups, nextNodeIdentifier, nextElementIdentifier = \ createCecumMesh3d(region, options, geometricCentralPath, nextNodeIdentifier, - nextElementIdentifier) + nextElementIdentifier)[0:3] return annotationGroups, None @@ -651,7 +655,8 @@ def findDerivativeBetweenPoints(v1, v2): return d -def createCecumMesh3d(region, options, centralPath, nodeIdentifier, elementIdentifier): +def createCecumMesh3d(region, options, centralPath, nodeIdentifier, elementIdentifier, nodeIdProximalIleum=[], + xProximalIleum=[], d1ProximalIleum=[], d2ProximalIleum=[], d3ProximalIleum=[]): """ Generates a cecum scaffold in the region using a network layout and parameter options. :param region: Region to create elements in. @@ -659,8 +664,14 @@ def createCecumMesh3d(region, options, centralPath, nodeIdentifier, elementIdent :param centralPath: Central path through the axis of the cecum scaffold. :param nodeIdentifier: First node identifier. :param elementIdentifier: First element identifier. + :param nodeIdProximalIleum: Node identifiers of nodes around starting nodes for ileum. + :param xProximalIleum, d1ProximalIleum, d2ProximalIleum, d3ProximalIleum: coordinates and derivatives of nodes + around starting nodes for ileum. :return allAnnotationGroups, nextNodeIdentifier, nextElementIdentifier. """ + parameterSetName = options['Base parameter set'] + isHuman = 'Human' in parameterSetName + segmentCount = options['Number of segments'] startPhase = 0.0 elementsCountAroundTC = options['Number of elements around tenia coli'] @@ -849,7 +860,7 @@ def createCecumMesh3d(region, options, centralPath, nodeIdentifier, elementIdent # Create coordinates and derivatives wallThicknessList = [wallThickness] * (elementsCountAlong + 1) - xList, d1List, d2List, d3List, curvatureList = \ + xList, d1List, d2List, d3List, curvatureList, localIdxDistal, xDistal, d1Distal, d2Distal, d3Distal = \ tubemesh.extrudeSurfaceCoordinates(xWarpedList, d1WarpedList,d2WarpedList, d3WarpedUnitList, wallThicknessList, relativeThicknessList, elementsCountAround, elementsCountAlong, elementsCountThroughWall, transitElementList, @@ -864,8 +875,10 @@ def createCecumMesh3d(region, options, centralPath, nodeIdentifier, elementIdent rescaleDerivatives=True) magMax = interp.computeCubicHermiteArcLength(xList[int(0.5*(elementsCountAroundTC + elementsCountAroundHaustrum))], d2List[int(0.5*(elementsCountAroundTC + elementsCountAroundHaustrum))], - xList[int(0.5*(elementsCountAroundTC + elementsCountAroundHaustrum)) + elementsCountAround * (elementsCountThroughWall + 1)], - d2List[int(0.5*(elementsCountAroundTC + elementsCountAroundHaustrum)) + elementsCountAround * (elementsCountThroughWall + 1)], + xList[int(0.5*(elementsCountAroundTC + elementsCountAroundHaustrum)) + + elementsCountAround * (elementsCountThroughWall + 1)], + d2List[int(0.5*(elementsCountAroundTC + elementsCountAroundHaustrum)) + + elementsCountAround * (elementsCountThroughWall + 1)], rescaleDerivatives=True) mag = 0.5*(magMin + magMax) d2ApexInner = vector.setMagnitude(sd2Cecum[0], mag) @@ -898,20 +911,21 @@ def createCecumMesh3d(region, options, centralPath, nodeIdentifier, elementIdent # Create nodes and elements if tcThickness > 0: tubeTCWidthList = colonSegmentTubeMeshOuterPoints.getTubeTCWidthList() - xCecum, d1Cecum, d2Cecum, d3Cecum, annotationArrayAround = getTeniaColi( - region, xCecum, d1Cecum, d2Cecum, d3Cecum, curvatureList, tcCount, elementsCountAroundTC, - elementsCountAroundHaustrum, elementsCountAlong, elementsCountThroughWall, - tubeTCWidthList, tcThickness, sxRefList, annotationGroupsAround, closedProximalEnd) + xCecum, d1Cecum, d2Cecum, d3Cecum, annotationArrayAround, localIdxDistal, xDistal, d1Distal, d2Distal, \ + d3Distal = \ + getTeniaColi(region, xCecum, d1Cecum, d2Cecum, d3Cecum, curvatureList, tcCount, elementsCountAroundTC, + elementsCountAroundHaustrum, elementsCountAlong, elementsCountThroughWall, + tubeTCWidthList, tcThickness, annotationGroupsAround, closedProximalEnd, isHuman) - nextNodeIdentifier, nextElementIdentifier, allAnnotationGroups = createNodesAndElementsTeniaColi( + nextNodeIdentifier, nextElementIdentifier, allAnnotationGroups, nodesIdDistal = createNodesAndElementsTeniaColi( region, xCecum, d1Cecum, d2Cecum, d3Cecum, xFlat, d1Flat, d2Flat, xOrgan, d1Organ, d2Organ, None, elementsCountAroundTC, elementsCountAroundHaustrum, elementsCountAlong, elementsCountThroughWall, tcCount, annotationGroupsAround, annotationGroupsAlong, annotationGroupsThroughWall, firstNodeIdentifier, firstElementIdentifier, useCubicHermiteThroughWall, useCrossDerivatives, - closedProximalEnd) + closedProximalEnd, localIdxDistal) else: - nextNodeIdentifier, nextElementIdentifier, allAnnotationGroups = tubemesh.createNodesAndElements( + nextNodeIdentifier, nextElementIdentifier, allAnnotationGroups, nodesIdDistal = tubemesh.createNodesAndElements( region, xCecum, d1Cecum, d2Cecum, d3Cecum, xFlat, d1Flat, d2Flat, xOrgan, d1Organ, d2Organ, None, elementsCountAround, elementsCountAlong, elementsCountThroughWall, annotationGroupsAround, annotationGroupsAlong, annotationGroupsThroughWall, @@ -1124,6 +1138,8 @@ def createCecumMesh3d(region, options, centralPath, nodeIdentifier, elementIdent ostiumSettings['Number of elements around ostium'] = elementsCountAlongSegment elementsCountAroundOstium = ostiumSettings['Number of elements around ostium'] + ostiumSettings['Use linear through ostium wall'] = options['Use linear through wall'] + ostiumSettings['Use linear through vessel wall'] = options['Use linear through wall'] ileumGroup = AnnotationGroup(region, get_smallintestine_term("ileum")) ileumMeshGroup = ileumGroup.getMeshGroup(mesh) @@ -1163,6 +1179,8 @@ def createCecumMesh3d(region, options, centralPath, nodeIdentifier, elementIdent nextNodeIdentifier, nextElementIdentifier, (o1_x, o1_d1, o1_d2, o1_d3, o1_NodeId, o1_Positions) = \ generateOstiumMesh(region, ostiumSettings, trackSurfaceOstium, centralPathIleum, startNodeIdentifier=nextNodeIdentifier, startElementIdentifier=nextElementIdentifier, + nodeIdProximal=nodeIdProximalIleum, xProximal=xProximalIleum, d1Proximal=d1ProximalIleum, + d2Proximal=d2ProximalIleum, d3Proximal=d3ProximalIleum, vesselMeshGroups=[[cecumMeshGroup, smallIntestineMeshGroup, ileumMeshGroup]], ostiumMeshGroups=[cecumMeshGroup, ileocecalJunctionMeshGroup], wallAnnotationGroups=ostiumWallAnnotationGroups, coordinates=None) @@ -1256,8 +1274,6 @@ def createCecumMesh3d(region, options, centralPath, nodeIdentifier, elementIdent xPositionB = trackSurfaceOstium.findNearestPosition(xAnnulusOuter[0]) xProportionB = trackSurfaceOstium.getProportion(xPositionB) - derivativeB = d2B - derivativeMagnitudeB = vector.magnitude(derivativeB) nx, nd1, nd2, nd3, proportions = \ trackSurfaceOstium.createHermiteCurvePoints( @@ -1275,8 +1291,6 @@ def createCecumMesh3d(region, options, centralPath, nodeIdentifier, elementIdent xPositionA = trackSurfaceOstium.findNearestPosition(xAnnulusOuter[int(elementsCountAlongSegment * 0.5)]) xProportionA = trackSurfaceOstium.getProportion(xPositionA) - xA, derivative2A, derivativeA = trackSurfaceOstium.evaluateCoordinates(xPositionA, derivatives=True) - derivativeMagnitudeA = vector.magnitude(d2AnnulusOuter[int(elementsCountAlongSegment * 0.5)]) xB = xTrackSurface[-elementsCountAroundHalfHaustrum] xPositionB = trackSurfaceOstium.findNearestPosition(xB) @@ -1498,7 +1512,8 @@ def createCecumMesh3d(region, options, centralPath, nodeIdentifier, elementIdent for m in range(endRowIdx - startRowIdx - 1): nxAlong.append(xAnnulusOuter[-(2 + m)]) n2Idx = m + startRowIdx + 1 - nd2Along.append(vector.setMagnitude(d1AnnulusOuter[-(2 + m)], vector.magnitude(d1AroundAlong[n2Idx][n1 - 1]))) + nd2Along.append(vector.setMagnitude(d1AnnulusOuter[-(2 + m)], + vector.magnitude(d1AroundAlong[n2Idx][n1 - 1]))) # Smooth from annulus to end of cecum for n2 in range(endRowIdx, elementsCountAlongSegment): @@ -1541,7 +1556,8 @@ def createCecumMesh3d(region, options, centralPath, nodeIdentifier, elementIdent nxAlongNext = xAroundAlong[n2 + 1][n1] else: nxAlongNext = xAroundAlong[n2 + 1][n1 - 1] - nd2Along.append(findDerivativeBetweenPoints(xAroundAlong[n2][n1 + (0 if (n2 < startRowIdx or n2 > endRowIdx) else -1)], nxAlongNext)) + nd2Along.append(findDerivativeBetweenPoints( + xAroundAlong[n2][n1 + (0 if (n2 < startRowIdx or n2 > endRowIdx) else -1)], nxAlongNext)) nxAlong.append(xAroundAlong[n2 + 1][n1]) nd2Along.append(d2TrackSurface[(elementsCountAroundHaustrum + 1) * elementsCountAlongSegment + n1]) @@ -1697,7 +1713,8 @@ def createCecumMesh3d(region, options, centralPath, nodeIdentifier, elementIdent # Adjust annulus points xAroundAlong[startRowIdx].insert(int(elementsCountAroundHaustrum * 0.5), xAnnulusOuter[0]) d1AroundAlong[startRowIdx].insert(int(elementsCountAroundHaustrum * 0.5), d2AnnulusOuter[0]) - d2AroundAlong[startRowIdx].insert(int(elementsCountAroundHaustrum * 0.5), vector.setMagnitude(d1AnnulusOuter[0], annulusD2ZeroMag)) + d2AroundAlong[startRowIdx].insert(int(elementsCountAroundHaustrum * 0.5), vector.setMagnitude(d1AnnulusOuter[0], + annulusD2ZeroMag)) d3UnitAroundAlong[startRowIdx].insert(int(elementsCountAroundHaustrum * 0.5), d3Annulus[0]) d1Curvature[startRowIdx].insert(int(elementsCountAroundHaustrum * 0.5), annulusD2Curvature[0]) d2Curvature[startRowIdx].insert(int(elementsCountAroundHaustrum * 0.5), d2CurvatureAnnulusZero) @@ -1705,7 +1722,8 @@ def createCecumMesh3d(region, options, centralPath, nodeIdentifier, elementIdent idx = int(elementsCountAlongSegment * 0.5) xAroundAlong[endRowIdx].insert(int(elementsCountAroundHaustrum * 0.5), xAnnulusOuter[idx]) d1AroundAlong[endRowIdx].insert(int(elementsCountAroundHaustrum * 0.5), d2AnnulusOuter[idx]) - d2AroundAlong[endRowIdx].insert(int(elementsCountAroundHaustrum * 0.5), vector.setMagnitude(d1AnnulusOuter[idx], annulusD2HalfOstiumMag)) + d2AroundAlong[endRowIdx].insert(int(elementsCountAroundHaustrum * 0.5), vector.setMagnitude(d1AnnulusOuter[idx], + annulusD2HalfOstiumMag)) d3UnitAroundAlong[endRowIdx].insert(int(elementsCountAroundHaustrum * 0.5), d3Annulus[idx]) d1Curvature[endRowIdx].insert(int(elementsCountAroundHaustrum * 0.5), annulusD2Curvature[idx]) d2Curvature[endRowIdx].insert(int(elementsCountAroundHaustrum * 0.5), d2CurvatureAlongHalfOstium) @@ -1980,7 +1998,9 @@ def createCecumMesh3d(region, options, centralPath, nodeIdentifier, elementIdent elementtemplate1 = elementtemplateX # print(elementIdentifier) # 340 - elif int(elementsCountAroundOstium*0.25) - 2 > 0 and startRowIdx + 1 <= e2 < startRowIdx + 1 + 2.0 * (int(elementsCountAroundOstium*0.25) - 2): + elif int(elementsCountAroundOstium*0.25) - 2 > 0 and \ + startRowIdx + 1 <= e2 < startRowIdx + 1 + \ + 2.0 * (int(elementsCountAroundOstium*0.25) - 2): if e1 == elementsCountAroundHalfHaustrum - 3: scaleFactors = [-1.0] eft1 = eftfactory.createEftNoCrossDerivatives() @@ -2142,20 +2162,23 @@ def createCecumMesh3d(region, options, centralPath, nodeIdentifier, elementIdent # Delete elements in new haustrum mesh_destroy_elements_and_nodes_by_identifiers(mesh, deleteElementIdentifier) - return allAnnotationGroups, nextNodeIdentifier, nextElementIdentifier #, nodeIdDistal, xDistal, d1Distal, \ - # d2Distal, d3Distal + return allAnnotationGroups, nextNodeIdentifier, nextElementIdentifier, nodesIdDistal, xDistal, d1Distal, \ + d2Distal, d3Distal class CecumCentralPath: """ Generates sampled central path for cecum scaffold. """ - def __init__(self, region, centralPath, termsAlong=[None]): + def __init__(self, region, centralPath, termsAlong=[None], ileumSegmentIdx=0, cecumSegmentIdx=[1,2]): """ :param region: Zinc region to define model in. :param centralPath: Central path subscaffold from meshtype_1d_path1 :param termsAlong: Annotation terms along length of central path + :param ileumSegmentIdx: Segment index of ileum branch. + :param cecumSegmentIdx: Segment index of body of cecum. """ + # Extract length of each group along cecum from central path arcLengthOfGroupsAlong = [] cxGroups = [] @@ -2179,19 +2202,36 @@ def __init__(self, region, centralPath, termsAlong=[None]): cd3Group = [] cd12Group = [] cd13Group = [] + cecumNodes = [] + lowerCecumNodes = [] + lowerCecumVersions = [] + ileumNodes = [] + ileumVersions = [] for termName in termsAlong: tmpGroup = tmpFieldmodule.findFieldByName(termName).castGroup() if termName else None tmpNodeset = tmpGroup.getNodesetGroup(tmpNodes) if tmpGroup else tmpNodes if termName == "caecum": + nodeiterator = tmpNodeset.createNodeiterator() + node = nodeiterator.next() + while node.isValid(): + cecumNodes.append(node.getIdentifier()) + node = nodeiterator.next() + + for i in range(len(networkSegments[cecumSegmentIdx[1]].getNodeIdentifiers())): + if networkSegments[cecumSegmentIdx[1]].getNodeIdentifiers()[i] in cecumNodes: + lowerCecumNodes.append(networkSegments[cecumSegmentIdx[1]].getNodeIdentifiers()[i]) + lowerCecumVersions.append(networkSegments[cecumSegmentIdx[1]].getNodeVersions()[i]) + for i in range(2): cx, cd1, cd2, cd3, cd12, cd13 = get_nodeset_path_ordered_field_parameters( tmpNodeset, tmpCoordinates, [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], - networkSegments[i + 1].getNodeIdentifiers(), networkSegments[i + 1].getNodeVersions()) + (lowerCecumNodes if i else networkSegments[cecumSegmentIdx[0]].getNodeIdentifiers()), + (lowerCecumVersions if i else networkSegments[cecumSegmentIdx[0]].getNodeVersions())) cxGroup += cx[(1 if i else 0):] cd1Group += cd1[(1 if i else 0):] @@ -2208,14 +2248,18 @@ def __init__(self, region, centralPath, termsAlong=[None]): for n in range(len(cx) - 1): arcLengthToBranchPt += interp.getCubicHermiteArcLength(cx[n], cd1[n], cx[n + 1], cd1[n + 1]) - elif termName == "ileum": + elif termName == "ileum part of cecum": + for i in range(len(networkSegments[ileumSegmentIdx].getNodeIdentifiers())): + if networkSegments[ileumSegmentIdx].getNodeIdentifiers()[i] in cecumNodes: + ileumNodes.append(networkSegments[ileumSegmentIdx].getNodeIdentifiers()[i]) + ileumVersions.append(networkSegments[ileumSegmentIdx].getNodeVersions()[i]) + cxGroup, cd1Group, cd2Group, cd3Group, cd12Group, cd13Group = \ get_nodeset_path_ordered_field_parameters(tmpNodes, tmpCoordinates, [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], - networkSegments[0].getNodeIdentifiers(), - networkSegments[0].getNodeVersions()) + ileumNodes, ileumVersions) arcLength = 0.0 for e in range(len(cxGroup) - 1): diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_colon1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_colon1.py index dadf1076..4742eebc 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_colon1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_colon1.py @@ -98,6 +98,13 @@ class MeshType_3d_colon1(Scaffold_base): ] ), 'userAnnotationGroups': [ + { + '_AnnotationGroup': True, + 'dimension': 1, + 'identifierRanges': '1-52', + 'name': get_colon_term('colon')[0], + 'ontId': get_colon_term('colon')[1] + }, { '_AnnotationGroup': True, 'dimension': 1, @@ -138,6 +145,13 @@ class MeshType_3d_colon1(Scaffold_base): ]), 'userAnnotationGroups': [ + { + '_AnnotationGroup': True, + 'dimension': 1, + 'identifierRanges': '1-8', + 'name': get_colon_term('colon')[0], + 'ontId': get_colon_term('colon')[1] + }, { '_AnnotationGroup': True, 'dimension': 1, @@ -178,6 +192,13 @@ class MeshType_3d_colon1(Scaffold_base): ] ), 'userAnnotationGroups': [ + { + '_AnnotationGroup': True, + 'dimension': 1, + 'identifierRanges': '1-8', + 'name': get_colon_term('colon')[0], + 'ontId': get_colon_term('colon')[1] + }, { '_AnnotationGroup': True, 'dimension': 1, @@ -207,55 +228,55 @@ class MeshType_3d_colon1(Scaffold_base): }, 'meshEdits': exnode_string_from_nodeset_field_parameters( [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ - (1, [[-87.21,-111.06,890.54], [-4.75,0.41,12.39], [23.27,-3.13,7.88], [2.46,-0.39,-2.95], [3.09,24.46,0.45], [1.83,0.46,-4.31]]), - (2, [[-89.99,-110.57,902.65], [-2.05,0.53,12.72], [24.71,-3.28,4.13], [0.07,0.14,-2.81], [3.42,25.00,-0.64], [0.43,0.10,-3.97]]), - (3, [[-91.25,-110.01,915.92], [-0.55,0.53,13.39], [23.61,-2.82,1.08], [-1.46,0.55,-1.92], [2.85,23.61,-0.91], [-1.42,0.54,-2.13]]), - (4, [[-91.08,-109.52,929.39], [0.13,0.65,13.47], [21.83,-2.10,-0.10], [-0.53,0.22,-1.06], [2.08,21.81,-1.18], [-0.53,0.21,-1.17]]), - (5, [[-91.00,-108.72,942.85], [0.83,0.67,13.37], [22.56,-2.35,-1.28], [-0.88,0.27,-1.85], [2.29,22.56,-1.42], [-0.92,0.27,-2.03]]), - (6, [[-89.43,-108.18,956.08], [2.81,0.32,13.11], [20.05,-1.51,-4.27], [-1.96,0.62,-1.35], [1.38,20.44,-0.86], [-2.00,0.62,-1.49]]), - (7, [[-85.39,-108.09,968.92], [3.10,0.44,13.08], [18.60,-0.99,-4.38], [-0.76,0.32,0.66], [0.82,19.04,-0.91], [-0.73,0.31,0.71]]), - (8, [[-83.24,-107.30,982.14], [2.05,0.85,13.23], [18.55,-0.80,-2.82], [-0.24,0.09,0.57], [0.62,18.71,-1.44], [-0.21,0.08,0.63]]), - (9, [[-81.29,-106.40,995.37], [2.32,1.34,13.29], [18.15,-0.79,-3.10], [0.14,0.24,-0.11], [0.47,18.29,-2.13], [0.05,0.31,-0.57]]), - (10, [[-78.60,-104.62,1008.65], [2.14,-1.50,13.27], [18.84,-0.25,-3.07], [-0.91,1.85,-0.22], [0.84,18.75,3.43], [-0.95,1.98,-0.15]]), - (11, [[-77.17,-109.18,1020.82], [4.07,-9.07,9.68], [16.31,3.44,-3.63], [-2.15,4.06,0.80], [-0.01,12.03,12.60], [-1.97,3.89,1.43]]), - (12, [[-71.19,-121.03,1025.58], [7.48,-11.42,0.49], [14.20,9.26,-1.14], [-1.27,2.69,3.17], [0.00,1.98,17.64], [-1.27,2.72,3.23]]), - (13, [[-63.35,-130.56,1022.18], [7.99,-9.44,-3.40], [13.31,9.97,3.60], [-0.81,0.70,2.42], [0.00,-5.47,16.79], [-0.91,0.85,2.43]]), - (14, [[-55.27,-139.84,1018.80], [8.88,-8.59,-3.55], [12.32,10.87,4.49], [-1.07,0.87,0.81], [0.00,-6.18,16.54], [-1.09,0.87,0.81]]), - (15, [[-45.66,-147.66,1015.10], [9.90,-7.39,-3.36], [10.81,11.99,5.47], [-1.63,1.38,0.03], [-0.01,-6.69,16.29], [-1.62,1.36,0.02]]), - (16, [[-35.52,-154.60,1012.08], [11.08,-6.08,-1.98], [8.54,14.06,4.58], [-1.99,1.15,0.25], [-0.01,-5.00,17.00], [-1.97,1.13,0.24]]), - (17, [[-23.71,-159.68,1011.20], [11.97,-4.32,-1.79], [6.20,14.65,6.07], [-1.74,-0.44,2.51], [0.01,-6.17,16.49], [-1.79,-0.44,2.52]]), - (18, [[-11.72,-163.20,1008.53], [12.26,-2.58,-2.06], [4.48,13.03,10.39], [-2.16,-0.11,1.44], [-0.01,-10.22,14.20], [-2.14,-0.12,1.43]]), - (19, [[0.67,-164.82,1007.10], [12.71,-0.73,-0.48], [1.18,14.35,9.43], [-2.67,0.76,-0.81], [-0.01,-8.95,15.09], [-2.58,0.75,-0.81]]), - (20, [[13.53,-164.63,1007.59], [12.75,0.98,0.85], [-1.70,14.80,8.53], [-1.75,0.42,-1.04], [-0.32,-8.14,15.58], [-1.71,0.43,-1.04]]), - (21, [[26.09,-162.88,1008.79], [12.63,1.81,1.23], [-2.89,15.32,7.02], [-2.26,-0.16,-1.14], [-0.45,-6.81,16.27], [-2.23,-0.14,-1.14]]), - (22, [[38.73,-161.01,1010.04], [11.76,4.53,2.77], [-6.96,14.45,5.88], [-3.08,-0.42,-3.34], [-0.98,-6.49,16.38], [-3.12,-0.44,-3.35]]), - (23, [[48.79,-154.12,1014.15], [9.86,7.10,4.16], [-10.00,14.30,-0.72], [-1.93,-0.52,-2.09], [-4.77,-2.54,17.36], [-1.97,-0.53,-2.09]]), - (24, [[58.41,-146.84,1018.34], [9.34,7.75,4.35], [-11.40,13.19,0.98], [-1.82,-1.10,1.29], [-3.67,-4.33,17.26], [-1.80,-1.06,1.30]]), - (25, [[67.43,-138.64,1022.84], [7.99,8.77,4.67], [-14.11,11.66,2.24], [-2.50,-1.97,-0.34], [-2.61,-6.25,17.94], [-2.59,-2.16,-0.41]]), - (26, [[74.34,-129.42,1027.61], [5.08,9.97,3.83], [-16.98,8.56,0.25], [0.03,-2.06,0.33], [-2.65,-5.79,18.73], [-1.53,-1.17,0.49]]), - (27, [[77.56,-119.25,1030.43], [5.04,10.78,-0.51], [-14.63,6.98,2.78], [0.10,1.23,-1.77], [4.28,1.14,20.24], [0.40,1.97,-2.97]]), - (28, [[83.86,-109.53,1026.21], [6.93,6.51,-9.45], [-16.87,11.64,-4.35], [-2.81,1.30,-3.77], [7.22,14.78,13.52], [-1.24,0.30,-4.60]]), - (29, [[89.55,-108.42,1013.56], [3.91,0.86,-13.16], [-20.29,9.17,-5.43], [-1.85,-1.68,0.87], [8.38,20.86,4.28], [-2.14,-1.95,1.17]]), - (30, [[91.64,-107.83,1000.37], [1.78,0.55,-13.27], [-20.93,7.77,-2.48], [-0.80,-1.12,1.76], [7.59,21.03,2.07], [-0.86,-1.12,1.92]]), - (31, [[93.10,-107.33,987.04], [1.01,0.30,-13.42], [-22.05,6.68,-1.51], [-0.56,-0.65,1.35], [6.63,22.10,1.09], [-0.58,-0.66,1.49]]), - (32, [[93.66,-107.24,973.55], [-0.02,1.05,-13.41], [-22.12,6.28,0.52], [0.93,-2.25,1.33], [6.31,22.05,1.91], [0.92,-2.27,1.47]]), - (33, [[93.06,-105.25,960.32], [-0.77,2.25,-13.20], [-20.31,1.70,1.47], [0.92,-2.34,0.15], [1.92,20.03,3.65], [0.93,-2.36,0.17]]), - (34, [[92.12,-102.74,947.16], [-0.42,2.82,-13.16], [-20.35,1.10,0.88], [0.74,-0.11,-0.85], [1.25,19.86,4.69], [0.73,-0.09,-0.94]]), - (35, [[92.23,-99.62,934.04], [0.47,1.78,-13.24], [-18.82,1.46,-0.47], [1.01,0.01,-1.14], [1.39,18.64,2.85], [1.03,0.02,-1.27]]), - (36, [[93.04,-99.17,920.86], [1.21,-0.74,-13.33], [-18.31,1.15,-1.73], [0.28,-0.61,0.54], [1.23,18.35,-1.00], [0.28,-0.69,-0.02]]), - (37, [[94.65,-101.12,907.56], [-0.61,-1.62,-13.47], [-18.27,0.06,0.82], [-0.21,-1.55,3.28], [-0.05,18.16,-2.30], [-0.49,-1.71,2.07]]), - (38, [[91.84,-102.35,894.35], [-3.47,-1.64,-11.95], [-18.62,-2.39,5.74], [0.91,-2.20,3.65], [-3.00,19.30,-1.81], [-0.73,-2.58,3.87]]), - (39, [[87.88,-104.31,883.75], [-5.21,-2.13,-10.32], [-16.28,-4.94,9.25], [2.73,-2.87,2.50], [-6.69,20.72,-1.11], [0.46,-3.19,4.53]]), - (40, [[81.45,-106.59,873.90], [-6.99,-2.14,-9.27], [-12.43,-8.97,11.45], [0.33,-3.15,2.69], [-10.29,21.20,2.18], [2.23,-2.67,3.37]]), - (41, [[73.98,-108.57,865.27], [-8.31,-0.22,-8.52], [-14.99,-11.80,14.92], [-1.28,-1.76,1.51], [-8.89,20.57,8.15], [3.18,-1.46,2.05]]), - (42, [[65.06,-106.92,857.15], [-8.97,1.81,-7.69], [-14.84,-12.55,14.36], [1.28,0.43,-0.09], [-4.45,19.47,13.19], [2.48,0.16,0.52]]), - (43, [[56.07,-104.97,849.91], [-10.00,1.92,-6.88], [-12.33,-11.02,14.85], [2.49,5.00,1.79], [-2.27,18.06,12.29], [2.28,4.69,1.10]]), - (44, [[45.11,-103.12,843.53], [-11.00,4.81,-5.26], [-9.46,-1.10,18.78], [2.56,4.66,2.88], [6.93,18.41,4.84], [2.42,4.35,0.87]]), - (45, [[34.86,-95.59,839.81], [-9.59,8.68,-2.67], [-6.61,-0.76,21.27], [0.94,-0.41,0.56], [12.62,13.25,3.92], [0.00,0.16,-0.54]]), - (46, [[26.14,-85.99,838.23], [-8.26,10.16,-2.00], [-7.29,-2.00,20.04], [-0.32,-0.12,-0.85], [14.71,10.71,6.32], [-1.05,-0.47,0.41]]), - (47, [[18.39,-75.31,835.82], [-8.42,10.08,-2.66], [-7.37,-0.99,19.53], [-0.56,0.61,0.80], [16.03,10.17,6.78], [-0.36,-0.28,1.59]]), - (48, [[9.35,-65.88,832.92], [-11.90,13.24,-4.28], [-8.47,-0.62,21.63], [-0.85,0.48,1.28], [17.76,11.50,7.33], [-1.39,-0.78,1.04]]), - (49, [[-5.12,-48.68,827.11], [-17.03,21.16,-7.34], [-8.98,0.20,21.43], [-0.08,1.01,-1.64], [17.76,11.50,7.33], [-1.39,-0.78,1.04]]) + (1, [[-87.210,-111.060,890.540], [-4.750,0.410,12.390], [23.270,-3.130,7.880], [2.460,-0.390,-2.950], [3.090,24.460,0.450], [1.830,0.460,-4.310]]), + (2, [[-89.990,-110.570,902.650], [-2.050,0.530,12.720], [24.710,-3.280,4.130], [0.070,0.140,-2.810], [3.420,25.000,-0.640], [0.430,0.100,-3.970]]), + (3, [[-91.250,-110.010,915.920], [-0.550,0.530,13.390], [23.610,-2.820,1.080], [-1.460,0.550,-1.920], [2.850,23.610,-0.910], [-1.420,0.540,-2.130]]), + (4, [[-91.080,-109.520,929.390], [0.130,0.650,13.470], [21.830,-2.100,-0.100], [-0.530,0.220,-1.060], [2.080,21.810,-1.180], [-0.530,0.210,-1.170]]), + (5, [[-91.000,-108.720,942.850], [0.830,0.670,13.370], [22.560,-2.350,-1.280], [-0.880,0.270,-1.850], [2.290,22.560,-1.420], [-0.920,0.270,-2.030]]), + (6, [[-89.430,-108.180,956.080], [2.810,0.320,13.110], [20.050,-1.510,-4.270], [-1.960,0.620,-1.350], [1.380,20.440,-0.860], [-2.000,0.620,-1.490]]), + (7, [[-85.390,-108.090,968.920], [3.100,0.440,13.080], [18.600,-0.990,-4.380], [-0.760,0.320,0.660], [0.820,19.040,-0.910], [-0.730,0.310,0.710]]), + (8, [[-83.240,-107.300,982.140], [2.050,0.850,13.230], [18.550,-0.800,-2.820], [-0.240,0.090,0.570], [0.620,18.710,-1.440], [-0.210,0.080,0.630]]), + (9, [[-81.290,-106.400,995.370], [2.320,1.340,13.290], [18.150,-0.790,-3.100], [0.140,0.240,-0.110], [0.470,18.290,-2.130], [0.050,0.310,-0.570]]), + (10, [[-78.600,-104.620,1008.650], [2.140,-1.500,13.270], [18.840,-0.250,-3.070], [-0.910,1.850,-0.220], [0.840,18.750,3.430], [-0.950,1.980,-0.150]]), + (11, [[-77.170,-109.180,1020.820], [4.070,-9.070,9.680], [16.310,3.440,-3.630], [-2.150,4.060,0.800], [-0.010,12.030,12.600], [-1.970,3.890,1.430]]), + (12, [[-71.190,-121.030,1025.580], [7.480,-11.420,0.490], [14.200,9.260,-1.140], [-1.270,2.690,3.170], [0.000,1.980,17.640], [-1.270,2.720,3.230]]), + (13, [[-63.350,-130.560,1022.180], [7.990,-9.440,-3.400], [13.310,9.970,3.600], [-0.810,0.700,2.420], [0.000,-5.470,16.790], [-0.910,0.850,2.430]]), + (14, [[-55.270,-139.840,1018.800], [8.880,-8.590,-3.550], [12.320,10.870,4.490], [-1.070,0.870,0.810], [0.000,-6.180,16.540], [-1.090,0.870,0.810]]), + (15, [[-45.660,-147.660,1015.100], [9.900,-7.390,-3.360], [10.810,11.990,5.470], [-1.630,1.380,0.030], [-0.010,-6.690,16.290], [-1.620,1.360,0.020]]), + (16, [[-35.520,-154.600,1012.080], [11.080,-6.080,-1.980], [8.540,14.060,4.580], [-1.990,1.150,0.250], [-0.010,-5.000,17.000], [-1.970,1.130,0.240]]), + (17, [[-23.710,-159.680,1011.200], [11.970,-4.320,-1.790], [6.200,14.650,6.070], [-1.740,-0.440,2.510], [0.010,-6.170,16.490], [-1.790,-0.440,2.520]]), + (18, [[-11.720,-163.200,1008.530], [12.260,-2.580,-2.060], [4.480,13.030,10.390], [-2.160,-0.110,1.440], [-0.010,-10.220,14.200], [-2.140,-0.120,1.430]]), + (19, [[0.670,-164.820,1007.100], [12.710,-0.730,-0.480], [1.180,14.350,9.430], [-2.670,0.760,-0.810], [-0.010,-8.950,15.090], [-2.580,0.750,-0.810]]), + (20, [[13.556,-164.739,1007.051], [12.750,0.980,0.850], [-1.700,14.800,8.530], [-1.750,0.420,-1.040], [-0.320,-8.140,15.580], [-1.710,0.430,-1.040]]), + (21, [[26.116,-162.906,1008.217], [12.630,1.810,1.230], [-2.890,15.320,7.020], [-2.260,-0.160,-1.140], [-0.450,-6.810,16.270], [-2.230,-0.140,-1.140]]), + (22, [[38.730,-161.010,1010.040], [11.760,4.530,2.770], [-6.960,14.450,5.880], [-3.080,-0.420,-3.340], [-0.980,-6.490,16.380], [-3.120,-0.440,-3.350]]), + (23, [[50.563,-154.087,1013.645], [9.860,7.100,4.160], [-9.105,10.240,0.863], [-1.930,-0.520,-2.090], [-4.770,-2.540,17.360], [-1.970,-0.530,-2.090]]), + (24, [[58.745,-146.870,1017.469], [9.340,7.750,4.350], [-9.097,10.778,0.486], [-1.820,-1.100,1.290], [-3.670,-4.330,17.260], [-1.800,-1.060,1.300]]), + (25, [[67.501,-138.309,1022.249], [7.990,8.770,4.670], [-10.568,9.341,0.117], [-2.500,-1.970,-0.340], [-2.610,-6.250,17.940], [-2.590,-2.160,-0.410]]), + (26, [[74.433,-129.298,1027.145], [5.080,9.970,3.830], [-13.880,7.949,-1.165], [0.030,-2.060,0.330], [-2.126,-4.930,16.625], [-1.530,-1.170,0.490]]), + (27, [[77.560,-119.250,1030.430], [5.040,10.780,-0.510], [-14.630,6.980,2.780], [0.100,1.230,-1.770], [4.280,1.140,20.240], [0.400,1.970,-2.970]]), + (28, [[83.860,-109.530,1026.210], [6.930,6.510,-9.450], [-16.870,11.640,-4.350], [-2.810,1.300,-3.770], [7.220,14.780,13.520], [-1.240,0.300,-4.600]]), + (29, [[89.550,-108.420,1013.560], [3.910,0.860,-13.160], [-20.290,9.170,-5.430], [-1.850,-1.680,0.870], [8.380,20.860,4.280], [-2.140,-1.950,1.170]]), + (30, [[91.640,-107.830,1000.370], [1.780,0.550,-13.270], [-20.930,7.770,-2.480], [-0.800,-1.120,1.760], [7.590,21.030,2.070], [-0.860,-1.120,1.920]]), + (31, [[93.100,-107.330,987.040], [1.010,0.300,-13.420], [-22.050,6.680,-1.510], [-0.560,-0.650,1.350], [6.630,22.100,1.090], [-0.580,-0.660,1.490]]), + (32, [[93.660,-107.240,973.550], [-0.020,1.050,-13.410], [-22.120,6.280,0.520], [0.930,-2.250,1.330], [6.310,22.050,1.910], [0.920,-2.270,1.470]]), + (33, [[93.060,-105.250,960.320], [-0.770,2.250,-13.200], [-20.310,1.700,1.470], [0.920,-2.340,0.150], [1.920,20.030,3.650], [0.930,-2.360,0.170]]), + (34, [[92.120,-102.740,947.160], [-0.420,2.820,-13.160], [-20.350,1.100,0.880], [0.740,-0.110,-0.850], [1.250,19.860,4.690], [0.730,-0.090,-0.940]]), + (35, [[92.230,-99.620,934.040], [0.470,1.780,-13.240], [-18.820,1.460,-0.470], [1.010,0.010,-1.140], [1.390,18.640,2.850], [1.030,0.020,-1.270]]), + (36, [[93.040,-99.170,920.860], [1.210,-0.740,-13.330], [-18.310,1.150,-1.730], [0.280,-0.610,0.540], [1.230,18.350,-1.000], [0.280,-0.690,-0.020]]), + (37, [[94.650,-101.120,907.560], [-0.610,-1.620,-13.470], [-18.270,0.060,0.820], [-0.210,-1.550,3.280], [-0.050,18.160,-2.300], [-0.490,-1.710,2.070]]), + (38, [[91.840,-102.350,894.350], [-3.470,-1.640,-11.950], [-18.620,-2.390,5.740], [0.910,-2.200,3.650], [-3.000,19.300,-1.810], [-0.730,-2.580,3.870]]), + (39, [[87.880,-104.310,883.750], [-5.210,-2.130,-10.320], [-16.280,-4.940,9.250], [2.730,-2.870,2.500], [-6.690,20.720,-1.110], [0.460,-3.190,4.530]]), + (40, [[81.450,-106.590,873.900], [-6.990,-2.140,-9.270], [-12.430,-8.970,11.450], [0.330,-3.150,2.690], [-6.303,19.245,1.555], [2.230,-2.670,3.370]]), + (41, [[73.980,-108.570,865.270], [-8.310,-0.220,-8.520], [-12.268,-8.435,13.125], [-1.280,-1.760,1.510], [-6.633,18.953,4.087], [3.180,-1.460,2.050]]), + (42, [[65.060,-106.920,857.150], [-8.970,1.810,-7.690], [-14.794,-6.343,11.919], [1.280,0.430,-0.090], [-4.396,19.311,7.084], [2.480,0.160,0.520]]), + (43, [[56.070,-104.970,849.910], [-10.000,1.920,-6.880], [-14.078,-6.138,12.772], [2.490,5.000,1.790], [0.172,16.517,6.181], [2.280,4.690,1.100]]), + (44, [[45.110,-103.120,843.530], [-11.000,4.810,-5.260], [-9.460,-1.100,18.780], [2.560,4.660,2.880], [6.930,18.410,4.840], [2.420,4.350,0.870]]), + (45, [[34.860,-95.590,839.810], [-9.590,8.680,-2.670], [-6.610,-0.760,21.270], [0.940,-0.410,0.560], [12.620,13.250,3.920], [0.000,0.160,-0.540]]), + (46, [[26.140,-85.990,838.230], [-8.260,10.160,-2.000], [-7.290,-2.000,20.040], [-0.320,-0.120,-0.850], [14.710,10.710,6.320], [-1.050,-0.470,0.410]]), + (47, [[18.390,-75.310,835.820], [-8.420,10.080,-2.660], [-7.370,-0.990,19.530], [-0.560,0.610,0.800], [16.030,10.170,6.780], [-0.360,-0.280,1.590]]), + (48, [[9.350,-65.880,832.920], [-11.900,13.240,-4.280], [-8.470,-0.620,21.630], [-0.850,0.480,1.280], [17.760,11.500,7.330], [-1.390,-0.780,1.040]]), + (49, [[-5.120,-48.680,827.110], [-17.030,21.160,-7.340], [-8.980,0.200,21.430], [-0.080,1.010,-1.640], [17.760,11.500,7.330], [-1.390,-0.780,1.040]]) ] ), 'userAnnotationGroups': [ @@ -305,6 +326,13 @@ class MeshType_3d_colon1(Scaffold_base): ] ), 'userAnnotationGroups': [ + { + '_AnnotationGroup': True, + 'dimension': 1, + 'identifierRanges': '1-7', + 'name': get_colon_term('colon')[0], + 'ontId': get_colon_term('colon')[1] + }, { '_AnnotationGroup': True, 'dimension': 1, @@ -341,6 +369,13 @@ class MeshType_3d_colon1(Scaffold_base): ] ), 'userAnnotationGroups': [ + { + '_AnnotationGroup': True, + 'dimension': 1, + 'identifierRanges': '1-4', + 'name': get_colon_term('colon')[0], + 'ontId': get_colon_term('colon')[1] + }, { '_AnnotationGroup': True, 'dimension': 1, @@ -413,6 +448,13 @@ class MeshType_3d_colon1(Scaffold_base): ] ), 'userAnnotationGroups': [ + { + '_AnnotationGroup': True, + 'dimension': 1, + 'identifierRanges': '1-39', + 'name': get_colon_term('colon')[0], + 'ontId': get_colon_term('colon')[1] + }, { '_AnnotationGroup': True, 'dimension': 1, @@ -489,6 +531,7 @@ def getDefaultOptions(cls, parameterSetName='Default'): 'Proximal-transverse tenia coli width': 10.0, 'Transverse-distal tenia coli width': 10.0, 'Distal tenia coli width': 10.0, + 'Use linear through wall': True, 'Refine': False, 'Refine number of elements around': 1, 'Refine number of elements along': 1, @@ -514,6 +557,7 @@ def getDefaultOptions(cls, parameterSetName='Default'): options['Proximal-transverse tenia coli width'] = 4.0 options['Transverse-distal tenia coli width'] = 3.0 options['Distal tenia coli width'] = 1.5 + options['Base parameter set'] = parameterSetName return options @staticmethod @@ -527,6 +571,7 @@ def getOrderedOptionNames(): 'Proximal-transverse tenia coli width', 'Transverse-distal tenia coli width', 'Distal tenia coli width', + 'Use linear through wall', 'Refine', 'Refine number of elements around', 'Refine number of elements along', @@ -598,315 +643,26 @@ def generateBaseMesh(cls, region, options): :param options: Dict containing options. See getDefaultOptions(). :return: list of AnnotationGroup, None """ - centralPath = options['Central path'] + nextNodeIdentifier = 1 + nextElementIdentifier = 1 + segmentProfile = options['Segment profile'] - segmentCount = options['Number of segments'] - startPhase = options['Start phase'] % 360.0 - proximalTCWidth = options['Proximal tenia coli width'] - proximalTransverseTCWidth = options['Proximal-transverse tenia coli width'] - transverseDistalTCWidth = options['Transverse-distal tenia coli width'] - distalTCWidth = options['Distal tenia coli width'] segmentSettings = segmentProfile.getScaffoldSettings() - - elementsCountAroundTC = segmentSettings['Number of elements around tenia coli'] - elementsCountAroundHaustrum = segmentSettings['Number of elements around haustrum'] - cornerOuterRadiusFactor = segmentSettings['Corner outer radius factor'] - haustrumOuterRadiusFactor = segmentSettings['Haustrum outer 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'] - mucosaRelThickness = segmentSettings['Mucosa relative thickness'] - submucosaRelThickness = segmentSettings['Submucosa relative thickness'] - circularRelThickness = segmentSettings['Circular muscle layer relative thickness'] - longitudinalRelThickness = segmentSettings['Longitudinal muscle layer relative thickness'] - useCrossDerivatives = segmentSettings['Use cross derivatives'] - useCubicHermiteThroughWall = not (segmentSettings['Use linear through wall']) - elementsCountAlong = int(elementsCountAlongSegment * segmentCount) - - # Colon coordinates - lengthToDiameterRatio = 24 - wallThicknessToDiameterRatio = 0.1 - teniaColiThicknessToDiameterRatio = 0.25 * wallThicknessToDiameterRatio - relativeThicknessListColonCoordinates = [1.0 / elementsCountThroughWall for n3 in range(elementsCountThroughWall)] - - firstNodeIdentifier = 1 - firstElementIdentifier = 1 - - # Central path - if tcCount == 1: - colonTermsAlong = [None, 'right colon', 'transverse colon', 'left colon'] - elif tcCount == 2: - colonTermsAlong = [None, 'spiral colon', 'transverse colon', 'descending colon'] - elif tcCount == 3: - colonTermsAlong = [None, 'ascending colon', 'transverse colon', 'descending colon'] - - tmpRegion = region.createRegion() - centralPath.generate(tmpRegion) - tmpFieldmodule = tmpRegion.getFieldmodule() - tmpNodes = tmpFieldmodule.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES) - tmpCoordinates = tmpFieldmodule.findFieldByName('coordinates') - arcLengthOfGroupsAlong = [] - - for termName in colonTermsAlong: - tmpGroup = tmpFieldmodule.findFieldByName(termName).castGroup() if termName else None - tmpNodeset = tmpGroup.getNodesetGroup(tmpNodes) if tmpGroup else tmpNodes - - cxGroup, cd1Group, cd2Group, cd3Group, cd12Group, cd13Group = get_nodeset_path_field_parameters( - tmpNodeset, tmpCoordinates, - [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]) - 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 not termName: - cx = cxGroup - cd1 = cd1Group - cd2 = cd2Group - cd3 = cd3Group - cd12 = cd12Group - cd13 = cd13Group - - del tmpNodeset - del tmpGroup - - del tmpCoordinates - del tmpNodes - del tmpFieldmodule - 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 - - # Sample central path - sx, sd1, se, sxi, ssf = interp.sampleCubicHermiteCurves(cx, cd1, elementsCountAlong) - sd2, sd12 = interp.interpolateSampleCubicHermite(cd2, cd12, 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(colonTermsAlong)): - 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 - - # Generate variation of radius & tc width along length - lengthList = [0.0, arcLengthOfGroupsAlong[1], arcLengthOfGroupsAlong[1] + arcLengthOfGroupsAlong[2], - arcLengthOfGroupsAlong[0]] - - outerRadiusListCP = [vector.magnitude(c) for c in cd2] - dOuterRadiusListCP = [] - for n in range(len(outerRadiusListCP) - 1): - dOuterRadiusListCP.append(outerRadiusListCP[n + 1] - outerRadiusListCP[n]) - dOuterRadiusListCP.append(outerRadiusListCP[-1] - outerRadiusListCP[-2]) - outerRadiusAlongElementList, dOuterRadiusAlongElementList = interp.interpolateSampleCubicHermite( - outerRadiusListCP, dOuterRadiusListCP, se, sxi, ssf) - - 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: - haustrumOuterRadiusFactorList = [haustrumOuterRadiusFactor, haustrumOuterRadiusFactor * 0.75, - haustrumOuterRadiusFactor * 0.5, haustrumOuterRadiusFactor * 0.2] - haustrumOuterRadiusFactorAlongElementList = \ - interp.sampleParameterAlongLine(lengthList, haustrumOuterRadiusFactorList, elementsCountAlong)[0] - else: - haustrumOuterRadiusFactorAlongElementList = [haustrumOuterRadiusFactor] * (elementsCountAlong + 1) - - # Create annotation groups for colon sections - colonGroup = AnnotationGroup(region, get_colon_term("colon")) + geometricCentralPath = options['Central path'] if tcCount == 1: - proximalGroup = AnnotationGroup(region, get_colon_term("right colon")) - transverseGroup = AnnotationGroup(region, get_colon_term("transverse colon")) - distalGroup = AnnotationGroup(region, get_colon_term("left colon")) - annotationGroupAlong = [[colonGroup, proximalGroup], - [colonGroup, transverseGroup], - [colonGroup, distalGroup]] - + colonTermsAlong = ['colon', 'right colon', 'transverse colon', 'left colon'] 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("descending colon")) - annotationGroupAlong = [[colonGroup, spiralGroup], - [colonGroup, transverseGroup], - [colonGroup, distalGroup]] - + colonTermsAlong = ['colon', 'spiral colon', 'transverse colon', 'descending colon'] 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]) - - xExtrude = [] - d1Extrude = [] - d2Extrude = [] - d3UnitExtrude = [] - sxRefExtrudeList = [] - - if elementsCountThroughWall == 1: - relativeThicknessList = [1.0] - annotationGroupsThroughWall = [[]] - else: - relativeThicknessList = [mucosaRelThickness, submucosaRelThickness, - circularRelThickness, longitudinalRelThickness] - mucosaGroup = AnnotationGroup(region, get_colon_term("colonic mucosa")) - submucosaGroup = AnnotationGroup(region, get_colon_term("submucosa of colon")) - circularMuscleGroup = AnnotationGroup(region, get_colon_term("circular muscle layer of colon")) - longitudinalMuscleGroup = AnnotationGroup(region, get_colon_term("longitudinal muscle layer of colon")) - annotationGroupsThroughWall = [[mucosaGroup], [submucosaGroup], - [circularMuscleGroup], [longitudinalMuscleGroup]] - - # Create object - colonSegmentTubeMeshOuterPoints = ColonSegmentTubeMeshOuterPoints( - region, elementsCountAroundTC, elementsCountAroundHaustrum, elementsCountAlongSegment, - tcCount, segmentLengthEndDerivativeFactor, segmentLengthMidDerivativeFactor, - segmentLength, wallThickness, cornerOuterRadiusFactor, haustrumOuterRadiusFactorAlongElementList, - outerRadiusAlongElementList, dOuterRadiusAlongElementList, tcWidthAlongElementList, - startPhase) - - for nSegment in range(segmentCount): - # Create inner points - xOuter, d1Outer, d2Outer, transitElementList, segmentAxis, annotationGroupsAround \ - = colonSegmentTubeMeshOuterPoints.getColonSegmentTubeMeshOuterPoints(nSegment) - - # Project reference point for warping onto central path - start = nSegment * elementsCountAlongSegment - end = (nSegment + 1) * elementsCountAlongSegment + 1 - sxRefList, sd1RefList, sd2ProjectedListRef, zRefList = \ - tubemesh.getPlaneProjectionOnCentralPath(xOuter, elementsCountAround, elementsCountAlongSegment, - segmentLength, sx[start:end], sd1[start:end], sd2[start:end], - sd12[start:end]) - - # Warp segment points - xWarpedList, d1WarpedList, d2WarpedList, d3WarpedUnitList = tubemesh.warpSegmentPoints( - xOuter, d1Outer, d2Outer, segmentAxis, sxRefList, sd1RefList, sd2ProjectedListRef, - elementsCountAround, elementsCountAlongSegment, zRefList) - - # 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 = colonSegmentTubeMeshOuterPoints.getContractedWallThicknessList() - - # Create coordinates and derivatives - xList, d1List, d2List, d3List, curvatureList = \ - tubemesh.extrudeSurfaceCoordinates(xExtrude, d1Extrude, d2Extrude, d3UnitExtrude, - contractedWallThicknessList, relativeThicknessList, - elementsCountAround, elementsCountAlong, elementsCountThroughWall, - transitElementList, outward=False) - - relaxedLengthList, xiList = colonSegmentTubeMeshOuterPoints.getRelaxedLengthAndXiList() - - closedProximalEnd = False - - if tcThickness > 0: - tubeTCWidthList = colonSegmentTubeMeshOuterPoints.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 coordinates - xFlat, d1Flat, d2Flat = createFlatCoordinatesTeniaColi( - xiList, relaxedLengthList, length, wallThickness, relativeThicknessList, tcCount, tcThickness, - elementsCountAroundTC, elementsCountAroundHaustrum, elementsCountAlong, - elementsCountThroughWall, transitElementList, closedProximalEnd) + colonTermsAlong = ['colon', 'ascending colon', 'transverse colon', 'descending colon'] - # Create colon coordinates - xColon, d1Colon, d2Colon = createColonCoordinatesTeniaColi(xiList, relativeThicknessListColonCoordinates, - lengthToDiameterRatio, - wallThicknessToDiameterRatio, - teniaColiThicknessToDiameterRatio, tcCount, - elementsCountAroundTC, - elementsCountAroundHaustrum, - elementsCountAlong, elementsCountThroughWall, - transitElementList, closedProximalEnd) - - # Create nodes and elements - nextNodeIdentifier, nextElementIdentifier, annotationGroups = createNodesAndElementsTeniaColi( - region, xList, d1List, d2List, d3List, xFlat, d1Flat, d2Flat, xColon, d1Colon, d2Colon, - "colon coordinates", elementsCountAroundTC, elementsCountAroundHaustrum, elementsCountAlong, - elementsCountThroughWall, tcCount, annotationGroupsAround, annotationGroupsAlong, - annotationGroupsThroughWall, firstNodeIdentifier, firstElementIdentifier, useCubicHermiteThroughWall, - useCrossDerivatives, closedProximalEnd) + geometricCentralPath = ColonCentralPath(region, geometricCentralPath, colonTermsAlong) - else: - # Create flat coordinates - xFlat, d1Flat, d2Flat = tubemesh.createFlatCoordinates( - xiList, relaxedLengthList, length, wallThickness, relativeThicknessList, elementsCountAround, - elementsCountAlong, elementsCountThroughWall, transitElementList) - - # Create colon coordinates - xColon, d1Colon, d2Colon = tubemesh.createOrganCoordinates(xiList, relativeThicknessListColonCoordinates, - lengthToDiameterRatio, - wallThicknessToDiameterRatio, - elementsCountAround, - elementsCountAlong, elementsCountThroughWall, - transitElementList) - - # Create nodes and elements - nextNodeIdentifier, nextElementIdentifier, annotationGroups = tubemesh.createNodesAndElements( - region, xList, d1List, d2List, d3List, xFlat, d1Flat, d2Flat, xColon, d1Colon, d2Colon, - "colon coordinates", elementsCountAround, elementsCountAlong, elementsCountThroughWall, - annotationGroupsAround, annotationGroupsAlong, annotationGroupsThroughWall, - firstNodeIdentifier, firstElementIdentifier, useCubicHermiteThroughWall, useCrossDerivatives, - closedProximalEnd) + annotationGroups, nextNodeIdentifier, nextElementIdentifier = \ + createColonMesh3d(region, options, geometricCentralPath, nextNodeIdentifier, + nextElementIdentifier, flatCoordinates=True, materialCoordinates=True)[0:3] return annotationGroups, None @@ -951,3 +707,371 @@ def defineFaceAnnotations(cls, region, options, annotationGroups): mucosaInnerSurface = findOrCreateAnnotationGroupForTerm(annotationGroups, region, get_colon_term("luminal surface of the colonic mucosa")) mucosaInnerSurface.getMeshGroup(mesh2d).addElementsConditional(is_mucosaInnerSurface) + +def createColonMesh3d(region, options, centralPath, nextNodeIdentifier, nextElementIdentifier, + flatCoordinates=False, materialCoordinates=False, + nodeIdProximal=[], xProximal=[], d1Proximal=[], d2Proximal=[], d3Proximal=[]): + """ + Generates a colon scaffold in the region using a central path and parameter options. + :param region: Region to create elements in. + :param options: Parameter options for creating scaffold. + :param centralPath: Central path through the path of the colon. + :param nextNodeIdentifier: Next node identifier to use. + :param nextElementIdentifier: Next element identifier to use. + :param flatCoordinates: Generate flat coordinates if True. + :param materialCoordinates: Create material coordinates if True. + :param nodeIdProximal, xProximal, d1Proximal, d2Proximal, d3Proximal: Node identifier, coordinates and derivatives + of nodes to use at proximal end of scaffold. + :return annotationGroups, nextNodeIdentifier, nextElementIdentifier, nodesIdDistal, xDistal, d1Distal, d2Distal, + d3Distal + """ + parameterSetName = options['Base parameter set'] + isHuman = 'Human' in parameterSetName + segmentProfile = options['Segment profile'] + segmentCount = options['Number of segments'] + startPhase = options['Start phase'] % 360.0 + proximalTCWidth = options['Proximal tenia coli width'] + proximalTransverseTCWidth = options['Proximal-transverse tenia coli width'] + transverseDistalTCWidth = options['Transverse-distal tenia coli width'] + distalTCWidth = options['Distal tenia coli width'] + useCubicHermiteThroughWall = not (options['Use linear through wall']) + segmentSettings = segmentProfile.getScaffoldSettings() + + elementsCountAroundTC = segmentSettings['Number of elements around tenia coli'] + elementsCountAroundHaustrum = segmentSettings['Number of elements around haustrum'] + cornerOuterRadiusFactor = segmentSettings['Corner outer radius factor'] + haustrumOuterRadiusFactor = segmentSettings['Haustrum outer 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'] + mucosaRelThickness = segmentSettings['Mucosa relative thickness'] + submucosaRelThickness = segmentSettings['Submucosa relative thickness'] + circularRelThickness = segmentSettings['Circular muscle layer relative thickness'] + longitudinalRelThickness = segmentSettings['Longitudinal muscle layer relative thickness'] + useCrossDerivatives = segmentSettings['Use cross derivatives'] + + elementsCountAlong = int(elementsCountAlongSegment * segmentCount) + + # Colon coordinates + lengthToDiameterRatio = 24 + wallThicknessToDiameterRatio = 0.1 + teniaColiThicknessToDiameterRatio = 0.25 * wallThicknessToDiameterRatio + relativeThicknessListColonCoordinates = [1.0 / elementsCountThroughWall for n3 in range(elementsCountThroughWall)] + + # Central path + if tcCount == 1: + colonTermsAlong = [None, 'right colon', 'transverse colon', 'left colon'] + elif tcCount == 2: + colonTermsAlong = [None, 'spiral colon', 'transverse colon', 'descending colon'] + elif tcCount == 3: + colonTermsAlong = [None, 'ascending colon', 'transverse colon', 'descending colon'] + + centralPathLength = centralPath.arcLengthOfGroupsAlong[0] + cx = centralPath.cxGroups[0] + cd1 = centralPath.cd1Groups[0] + cd2 = centralPath.cd2Groups[0] + cd12 = centralPath.cd12Groups[0] + arcLengthOfGroupsAlong = centralPath.arcLengthOfGroupsAlong + + # 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 + + # Sample central path + sx, sd1, se, sxi, ssf = interp.sampleCubicHermiteCurves(cx, cd1, elementsCountAlong) + sd2, sd12 = interp.interpolateSampleCubicHermite(cd2, cd12, se, sxi, ssf) + + elementAlongLength = centralPathLength / elementsCountAlong + + elementsCountAlongGroups = [] + groupLength = 0.0 + e = 0 + elementsCount = 1 + length = elementAlongLength + for i in range(1, len(colonTermsAlong)): + 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 + + # Generate variation of radius & tc width along length + lengthList = [0.0, arcLengthOfGroupsAlong[1], + arcLengthOfGroupsAlong[1] + arcLengthOfGroupsAlong[2], + arcLengthOfGroupsAlong[0]] + + outerRadiusListCP = [vector.magnitude(c) for c in cd2] + dOuterRadiusListCP = [] + for n in range(len(outerRadiusListCP) - 1): + dOuterRadiusListCP.append(outerRadiusListCP[n + 1] - outerRadiusListCP[n]) + dOuterRadiusListCP.append(outerRadiusListCP[-1] - outerRadiusListCP[-2]) + outerRadiusAlongElementList, dOuterRadiusAlongElementList = interp.interpolateSampleCubicHermite( + outerRadiusListCP, dOuterRadiusListCP, se, sxi, ssf) + + 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: + haustrumOuterRadiusFactorList = [haustrumOuterRadiusFactor, haustrumOuterRadiusFactor * 0.75, + haustrumOuterRadiusFactor * 0.5, haustrumOuterRadiusFactor * 0.2] + haustrumOuterRadiusFactorAlongElementList = \ + interp.sampleParameterAlongLine(lengthList, haustrumOuterRadiusFactorList, elementsCountAlong)[0] + else: + haustrumOuterRadiusFactorAlongElementList = [haustrumOuterRadiusFactor] * (elementsCountAlong + 1) + + # Create annotation groups for colon sections + colonGroup = AnnotationGroup(region, get_colon_term("colon")) + + if tcCount == 1: + proximalGroup = AnnotationGroup(region, get_colon_term("right colon")) + transverseGroup = AnnotationGroup(region, get_colon_term("transverse colon")) + distalGroup = AnnotationGroup(region, get_colon_term("left 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("descending 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]) + + xExtrude = [] + d1Extrude = [] + d2Extrude = [] + d3UnitExtrude = [] + sxRefExtrudeList = [] + + if elementsCountThroughWall == 1: + relativeThicknessList = [1.0] + annotationGroupsThroughWall = [[]] + else: + relativeThicknessList = [mucosaRelThickness, submucosaRelThickness, + circularRelThickness, longitudinalRelThickness] + mucosaGroup = AnnotationGroup(region, get_colon_term("colonic mucosa")) + submucosaGroup = AnnotationGroup(region, get_colon_term("submucosa of colon")) + circularMuscleGroup = AnnotationGroup(region, get_colon_term("circular muscle layer of colon")) + longitudinalMuscleGroup = AnnotationGroup(region, get_colon_term("longitudinal muscle layer of colon")) + annotationGroupsThroughWall = [[mucosaGroup], [submucosaGroup], + [circularMuscleGroup], [longitudinalMuscleGroup]] + + # Create object + colonSegmentTubeMeshOuterPoints = ColonSegmentTubeMeshOuterPoints( + region, elementsCountAroundTC, elementsCountAroundHaustrum, elementsCountAlongSegment, + tcCount, segmentLengthEndDerivativeFactor, segmentLengthMidDerivativeFactor, + segmentLength, wallThickness, cornerOuterRadiusFactor, haustrumOuterRadiusFactorAlongElementList, + outerRadiusAlongElementList, dOuterRadiusAlongElementList, tcWidthAlongElementList, + startPhase) + + for nSegment in range(segmentCount): + # Create inner points + xOuter, d1Outer, d2Outer, transitElementList, segmentAxis, annotationGroupsAround \ + = colonSegmentTubeMeshOuterPoints.getColonSegmentTubeMeshOuterPoints(nSegment) + + # Project reference point for warping onto central path + start = nSegment * elementsCountAlongSegment + end = (nSegment + 1) * elementsCountAlongSegment + 1 + sxRefList, sd1RefList, sd2ProjectedListRef, zRefList = \ + tubemesh.getPlaneProjectionOnCentralPath(xOuter, elementsCountAround, elementsCountAlongSegment, + segmentLength, sx[start:end], sd1[start:end], sd2[start:end], + sd12[start:end]) + + # Warp segment points + xWarpedList, d1WarpedList, d2WarpedList, d3WarpedUnitList = tubemesh.warpSegmentPoints( + xOuter, d1Outer, d2Outer, segmentAxis, sxRefList, sd1RefList, sd2ProjectedListRef, + elementsCountAround, elementsCountAlongSegment, zRefList) + + # 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 = colonSegmentTubeMeshOuterPoints.getContractedWallThicknessList() + + # Create coordinates and derivatives + xList, d1List, d2List, d3List, curvatureList, localIdxDistal, xDistal, d1Distal, d2Distal, d3Distal = \ + tubemesh.extrudeSurfaceCoordinates(xExtrude, d1Extrude, d2Extrude, d3UnitExtrude, + contractedWallThicknessList, relativeThicknessList, + elementsCountAround, elementsCountAlong, elementsCountThroughWall, + transitElementList, outward=False, xProximal=xProximal, + d1Proximal=d1Proximal, d2Proximal=d2Proximal, d3Proximal=d3Proximal) + + relaxedLengthList, xiList = colonSegmentTubeMeshOuterPoints.getRelaxedLengthAndXiList() + + closedProximalEnd = False + + if tcThickness > 0: + tubeTCWidthList = colonSegmentTubeMeshOuterPoints.getTubeTCWidthList() + xList, d1List, d2List, d3List, annotationArrayAround, localIdxDistal, xDistal, d1Distal, d2Distal, \ + d3Distal = \ + getTeniaColi(region, xList, d1List, d2List, d3List, curvatureList, tcCount, elementsCountAroundTC, + elementsCountAroundHaustrum, elementsCountAlong, elementsCountThroughWall, + tubeTCWidthList, tcThickness, annotationGroupsAround, closedProximalEnd, + isHuman, xProximal=xProximal, d1Proximal=d1Proximal, d2Proximal=d2Proximal, + d3Proximal=d3Proximal) + + # Create flat coordinates + if flatCoordinates: + xFlat, d1Flat, d2Flat = createFlatCoordinatesTeniaColi( + xiList, relaxedLengthList, length, wallThickness, relativeThicknessList, tcCount, tcThickness, + elementsCountAroundTC, elementsCountAroundHaustrum, elementsCountAlong, + elementsCountThroughWall, transitElementList, closedProximalEnd) + else: + xFlat = d1Flat = d2Flat = [] + + # Create colon coordinates + if materialCoordinates: + xColon, d1Colon, d2Colon = \ + createColonCoordinatesTeniaColi(xiList, relativeThicknessListColonCoordinates, lengthToDiameterRatio, + wallThicknessToDiameterRatio, teniaColiThicknessToDiameterRatio, + tcCount, elementsCountAroundTC, elementsCountAroundHaustrum, + elementsCountAlong, elementsCountThroughWall, transitElementList, + closedProximalEnd) + else: + xColon = d1Colon = d2Colon = [] + + # Create nodes and elements + nextNodeIdentifier, nextElementIdentifier, annotationGroups, nodesIdDistal = createNodesAndElementsTeniaColi( + region, xList, d1List, d2List, d3List, xFlat, d1Flat, d2Flat, xColon, d1Colon, d2Colon, + "colon coordinates", elementsCountAroundTC, elementsCountAroundHaustrum, elementsCountAlong, + elementsCountThroughWall, tcCount, annotationGroupsAround, annotationGroupsAlong, + annotationGroupsThroughWall, nextNodeIdentifier, nextElementIdentifier, useCubicHermiteThroughWall, + useCrossDerivatives, closedProximalEnd, localIdxDistal=localIdxDistal, nodeIdProximal=nodeIdProximal) + + else: + # Create flat coordinates + xFlat, d1Flat, d2Flat = tubemesh.createFlatCoordinates( + xiList, relaxedLengthList, length, wallThickness, relativeThicknessList, elementsCountAround, + elementsCountAlong, elementsCountThroughWall, transitElementList) + + # Create colon coordinates + xColon, d1Colon, d2Colon = tubemesh.createOrganCoordinates(xiList, relativeThicknessListColonCoordinates, + lengthToDiameterRatio, + wallThicknessToDiameterRatio, + elementsCountAround, + elementsCountAlong, elementsCountThroughWall, + transitElementList) + + # Create nodes and elements + nextNodeIdentifier, nextElementIdentifier, annotationGroups, nodesIdDistal = tubemesh.createNodesAndElements( + region, xList, d1List, d2List, d3List, xFlat, d1Flat, d2Flat, xColon, d1Colon, d2Colon, + "colon coordinates", elementsCountAround, elementsCountAlong, elementsCountThroughWall, + annotationGroupsAround, annotationGroupsAlong, annotationGroupsThroughWall, + nextNodeIdentifier, nextElementIdentifier, useCubicHermiteThroughWall, useCrossDerivatives, + closedProximalEnd, localIdxDistal=localIdxDistal, nodeIdProximal=nodeIdProximal) + + return annotationGroups, nextNodeIdentifier, nextElementIdentifier, nodesIdDistal, xDistal, d1Distal, d2Distal, \ + d3Distal + +class ColonCentralPath: + + def __init__(self, region, centralPath, termsAlong=[None]): + """ + :param region: Zinc region to define model in. + :param centralPath: Central path subscaffold from meshtype_1d_network_layout1 + :param termsAlong: Annotation terms along length of colon + """ + # Extract length of each group along colon from central path + cxGroups = [] + cd1Groups = [] + cd2Groups = [] + cd3Groups = [] + cd12Groups = [] + cd13Groups = [] + + tmpRegion = region.createRegion() + centralPath.generate(tmpRegion) + tmpFieldmodule = tmpRegion.getFieldmodule() + tmpNodes = tmpFieldmodule.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES) + tmpCoordinates = tmpFieldmodule.findFieldByName('coordinates') + arcLengthOfGroupsAlong = [] + + for termName in termsAlong: + tmpGroup = tmpFieldmodule.findFieldByName(termName).castGroup() if termName else None + tmpNodeset = tmpGroup.getNodesetGroup(tmpNodes) if tmpGroup else tmpNodes + + cxGroup, cd1Group, cd2Group, cd3Group, cd12Group, cd13Group = get_nodeset_path_field_parameters( + tmpNodeset, tmpCoordinates, + [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]) + + 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 termName == "colon": + cxGroups.append(cxGroup) + cd1Groups.append(cd1Group) + cd2Groups.append(cd2Group) + cd3Groups.append(cd3Group) + cd12Groups.append(cd12Group) + cd13Groups.append(cd13Group) + + del tmpNodeset + del tmpGroup + + del tmpCoordinates + del tmpNodes + del tmpFieldmodule + del tmpRegion + + self.arcLengthOfGroupsAlong = arcLengthOfGroupsAlong + self.cxGroups = cxGroups + self.cd1Groups = cd1Groups + self.cd2Groups = cd2Groups + self.cd3Groups = cd3Groups + self.cd12Groups = cd12Groups + self.cd13Groups = cd13Groups diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_colonsegment1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_colonsegment1.py index 1d19ac47..f1dcaecb 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_colonsegment1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_colonsegment1.py @@ -102,6 +102,7 @@ def getDefaultOptions(parameterSetName='Default'): options['Tenia coli thickness'] = 0.0 options['Wall thickness'] = 3.02 elif 'Human 2' in parameterSetName: + options['Number of elements through wall'] = 1 options['Haustrum outer radius factor'] = 0.364 options['Tenia coli thickness'] = 1.6 elif 'Mouse' in parameterSetName: @@ -137,6 +138,7 @@ def getDefaultOptions(parameterSetName='Default'): options['Submucosa relative thickness'] = 0.25 options['Circular muscle layer relative thickness'] = 0.25 options['Longitudinal muscle layer relative thickness'] = 0.16 + options['Base parameter set'] = parameterSetName return options @@ -242,6 +244,8 @@ def generateBaseMesh(cls, region, options): :param options: Dict containing options. See getDefaultOptions(). :return: list of AnnotationGroup, None """ + parameterSetName = options['Base parameter set'] + isHuman = 'Human' in parameterSetName elementsCountAroundTC = options['Number of elements around tenia coli'] elementsCountAroundHaustrum = options['Number of elements around haustrum'] elementsCountAlongSegment = options['Number of elements along segment'] @@ -351,7 +355,7 @@ def generateBaseMesh(cls, region, options): tubemesh.extrudeSurfaceCoordinates(xWarpedList, d1WarpedList, d2WarpedList, d3WarpedUnitList, contractedWallThicknessList, relativeThicknessList, elementsCountAround, elementsCountAlongSegment, elementsCountThroughWall, transitElementList, - outward=False) + outward=False)[0:5] xColonSegment = d1ColonSegment = d2ColonSegment = [] @@ -362,7 +366,7 @@ def generateBaseMesh(cls, region, options): xList, d1List, d2List, d3List, annotationGroupsAround = getTeniaColi( region, xList, d1List, d2List, d3List, curvatureList, tcCount, elementsCountAroundTC, elementsCountAroundHaustrum, elementsCountAlongSegment, elementsCountThroughWall, - tubeTCWidthList, tcThickness, sxRefList, annotationGroupsAround, closedProximalEnd) + tubeTCWidthList, tcThickness, annotationGroupsAround, closedProximalEnd, isHuman)[0:5] # Create flat coordinates xFlat, d1Flat, d2Flat = createFlatCoordinatesTeniaColi( @@ -376,7 +380,7 @@ def generateBaseMesh(cls, region, options): d2ColonSegment, None, elementsCountAroundTC, elementsCountAroundHaustrum, elementsCountAlongSegment, elementsCountThroughWall, tcCount, annotationGroupsAround, annotationGroupsAlong, annotationGroupsThroughWall, firstNodeIdentifier, firstElementIdentifier, - useCubicHermiteThroughWall, useCrossDerivatives, closedProximalEnd) + useCubicHermiteThroughWall, useCrossDerivatives, closedProximalEnd)[0:3] else: # Create flat coordinates xFlat, d1Flat, d2Flat = tubemesh.createFlatCoordinates( @@ -389,7 +393,7 @@ def generateBaseMesh(cls, region, options): d2ColonSegment, None, elementsCountAround, elementsCountAlongSegment, elementsCountThroughWall, annotationGroupsAround, annotationGroupsAlong, annotationGroupsThroughWall, firstNodeIdentifier, firstElementIdentifier, useCubicHermiteThroughWall, useCrossDerivatives, - closedProximalEnd) + closedProximalEnd)[0:3] return annotationGroups, None @@ -1290,7 +1294,8 @@ def getXiListFromOuterLengthProfile(xOuter, d1Outer): def getTeniaColi(region, xList, d1List, d2List, d3List, curvatureList, tcCount, elementsCountAroundTC, elementsCountAroundHaustrum, elementsCountAlong, elementsCountThroughWall, - tubeTCWidthList, tcThickness, sx, annotationGroupsAround, closedProximalEnd): + tubeTCWidthList, tcThickness, annotationGroupsAround, closedProximalEnd, isHuman, + xProximal=[], d1Proximal=[], d2Proximal=[], d3Proximal=[]): """ Create equally spaced points for tenia coli over the outer surface of the colon. Points are sampled from a cubic @@ -1312,11 +1317,13 @@ def getTeniaColi(region, xList, d1List, d2List, d3List, curvatureList, :param elementsCountThroughWall: Number of elements through wall. :param tubeTCWidthList: List of tenia coli width along tube length. :param tcThickness: Thickness of tenia coli at its thickest part. - :param sx: Coordinates of central path. :param annotationGroupsAround: annotation groups for elements around tube. :param closedProximalEnd: True when proximal end of tube is closed. - :return: coordinates, derivatives, annotationGroupsAround for colon with tenia - coli. + :param isHuman: True if making scaffold for human. + :param xProximal, d1Proximal, d2Proximal, d3Proximal: Optional for passing coordinates and derivatives of points on + proximal end of colon segment. + :return: coordinates, derivatives, annotationGroupsAround for colon with tenia coli and local index, coordinates and + derivatives for nodes around distal end of colon. """ elementsCountAround = (elementsCountAroundTC + elementsCountAroundHaustrum) * tcCount @@ -1375,11 +1382,10 @@ def getTeniaColi(region, xList, d1List, d2List, d3List, curvatureList, d3TCRaw.append(d3) d3List[xTCInnerSet[n]] = d3 - innerIdx = xTCInnerSet[n] - elementsCountThroughWall * elementsCountAround - curvature = curvatureList[innerIdx] - distanceToInnerIdx = vector.magnitude([xTCOuter[i] - xList[innerIdx][i] for i in range(3)]) + curvature = curvatureList[xTCInnerSet[n]] + distanceToInnerIdx = vector.magnitude([xTCOuter[i] - xTCInner[i] for i in range(3)]) factor = 1.0 - curvature * distanceToInnerIdx - d2 = [factor * c for c in d2List[innerIdx]] + d2 = [factor * c for c in d2List[xTCInnerSet[n]]] d2TCRaw.append(d2) xTCArranged = xTCArranged + xTCRaw[int(elementsCountAroundTC * 0.5 - 1):] + \ @@ -1391,17 +1397,19 @@ def getTeniaColi(region, xList, d1List, d2List, d3List, curvatureList, d3TCArranged = d3TCArranged + d3TCRaw[int(elementsCountAroundTC * 0.5 - 1):] + \ d3TCRaw[:int(elementsCountAroundTC * 0.5 - 1)] - x, d1, d2, d3 = combineTeniaColiWithColon(xList, d1List, d2List, d3List, xTCArranged, d1TCArranged, - d2TCArranged, d3TCArranged, (elementsCountAroundTC - 1) * tcCount, elementsCountAround, - elementsCountAlong, elementsCountThroughWall, closedProximalEnd) + x, d1, d2, d3, localIdxDistal, xDistal, d1Distal, d2Distal, d3Distal = \ + combineTeniaColiWithColon(xList, d1List, d2List, d3List, xTCArranged, d1TCArranged, + d2TCArranged, d3TCArranged, (elementsCountAroundTC - 1) * tcCount, + elementsCountAround, elementsCountAlong, elementsCountThroughWall, closedProximalEnd, + xProximal, d1Proximal, d2Proximal, d3Proximal) # Update annotation groups - if tcCount == 2 or closedProximalEnd: + if tcCount == 2 or not isHuman: tcGroup = AnnotationGroup(region, get_colon_term("taenia coli")) for i in range(elementsCountAroundTC * tcCount): annotationGroupsAround.append([tcGroup]) - elif tcCount == 3: + elif tcCount == 3 and isHuman: tlGroup = AnnotationGroup(region, get_colon_term("taenia libera")) tmGroup = AnnotationGroup(region, get_colon_term("taenia mesocolica")) toGroup = AnnotationGroup(region, get_colon_term("taenia omentalis")) @@ -1414,16 +1422,15 @@ def getTeniaColi(region, xList, d1List, d2List, d3List, curvatureList, for n in range(elementsCount): annotationGroupsAround.append(annotationGroupAround[i]) - return x, d1, d2, d3, annotationGroupsAround + return x, d1, d2, d3, annotationGroupsAround, localIdxDistal, xDistal, d1Distal, d2Distal, d3Distal -def combineTeniaColiWithColon(xList, d1List, d2List, d3List, xTC, d1TC, d2TC, - d3TC, nodesCountAroundTC, elementsCountAround, elementsCountAlong, - elementsCountThroughWall, closedProximalEnd): +def combineTeniaColiWithColon(xList, d1List, d2List, d3List, xTC, d1TC, d2TC, d3TC, nodesCountAroundTC, + elementsCountAround, elementsCountAlong, elementsCountThroughWall, closedProximalEnd, + xProximal=[], d1Proximal=[], d2Proximal=[], d3Proximal=[]): """ - Arranges coordinates and derivatives around inner surface to - outer surface, followed by tenia coli points before extending - along length of colon. + Arranges coordinates and derivatives around inner surface to outer surface, followed by tenia coli points before + extending along length of colon. :param xList, d1List, d2List, d3List: coordinates and derivatives of colon. :param xTC, d1TC, d2TC, d3TC: coordinates and derivatives of tenia coli. :param nodesCountAroundTC: Number of nodes around tenia coli. @@ -1431,22 +1438,37 @@ def combineTeniaColiWithColon(xList, d1List, d2List, d3List, xTC, d1TC, d2TC, :param elementsCountAlong: Number of elements along colon. :param elementsCountThroughWall: Number of elements through wall. :param closedProximalEnd: True when proximal end of tube is closed. - : return: reordered coordinates and derivatives + :param xProximal, d1Proximal, d2Proximal, d3Proximal: Optional for passing coordinates and derivatives of points on + proximal end of colon segment. + :return: reordered coordinates and derivatives and local index, coordinates and derivatives of nodes on distal end. """ x = [] d1 = [] d2 = [] d3 = [] + count = 0 + localIdxDistal = [] + xDistal = [] + d1Distal = [] + d2Distal = [] + d3Distal = [] # Add tenia coli points to coordinates list for n2 in range(elementsCountAlong + 1): for n3 in range(elementsCountThroughWall + 1): + xDistalAround = [] + d1DistalAround = [] + d2DistalAround = [] + d3DistalAround = [] + localIdxDistalAround = [] + if closedProximalEnd and n2 == 0: x.append(xList[n3]) d1.append(d1List[n3]) d2.append(d2List[n3]) if d3List: d3.append(d3List[n3]) + count += 1 else: for n1 in range(elementsCountAround): # Append colon wall coordinates from inside to outside wall @@ -1455,23 +1477,61 @@ def combineTeniaColiWithColon(xList, d1List, d2List, d3List, xTC, d1TC, d2TC, n3 * elementsCountAround + n1 if closedProximalEnd \ else n2 * elementsCountAround * (elementsCountThroughWall + 1) + n3 * elementsCountAround + n1 - x.append(xList[n]) - d1.append(d1List[n]) - d2.append(d2List[n]) - if d3List: - d3.append(d3List[n]) + if xProximal and n2 == 0 and not closedProximalEnd: + x.append(xProximal[n3][n1]) + d1.append(d1Proximal[n3][n1]) + d2.append(d2Proximal[n3][n1]) + if d3List: + d3.append(d3Proximal[n3][n1]) + else: + x.append(xList[n]) + d1.append(d1List[n]) + d2.append(d2List[n]) + if d3List: + d3.append(d3List[n]) + + if n2 == elementsCountAlong: + localIdxDistalAround.append(count) + xDistalAround.append(xList[n]) + d1DistalAround.append(d1List[n]) + d2DistalAround.append(d2List[n]) + if d3List: + d3DistalAround.append(d3List[n]) + count += 1 + + if n2 == elementsCountAlong: + xDistal.append(xDistalAround) + d1Distal.append(d1DistalAround) + d2Distal.append(d2DistalAround) + d3Distal.append(d3DistalAround) + localIdxDistal.append(localIdxDistalAround) # Append tenia coli coordinates if not (closedProximalEnd and n2 == 0): for nTC in range(nodesCountAroundTC): - nTCCount = (n2 - 1 if closedProximalEnd else n2) * nodesCountAroundTC + nTC - x.append(xTC[nTCCount]) - d1.append(d1TC[nTCCount]) - d2.append(d2TC[nTCCount]) - if d3TC: - d3.append(d3TC[nTCCount]) - - return x, d1, d2, d3 + if xProximal and n2 == 0: + x.append(xProximal[-1][elementsCountAround + nTC]) + d1.append(d1Proximal[-1][elementsCountAround + nTC]) + d2.append(d2Proximal[-1][elementsCountAround + nTC]) + if d3List: + d3.append(d3Proximal[-1][elementsCountAround + nTC]) + else: + nTCCount = (n2 - 1 if closedProximalEnd else n2) * nodesCountAroundTC + nTC + x.append(xTC[nTCCount]) + d1.append(d1TC[nTCCount]) + d2.append(d2TC[nTCCount]) + if d3TC: + d3.append(d3TC[nTCCount]) + if n2 == elementsCountAlong: + localIdxDistal[-1].append(count) + xDistal[-1].append(xTC[nTCCount]) + d1Distal[-1].append(d1TC[nTCCount]) + d2Distal[-1].append(d2TC[nTCCount]) + if d3TC: + d3Distal[-1].append(d3TC[nTCCount]) + count += 1 + + return x, d1, d2, d3, localIdxDistal, xDistal, d1Distal, d2Distal, d3Distal def createFlatCoordinatesTeniaColi(xiList, relaxedLengthList, @@ -1565,11 +1625,11 @@ def createFlatCoordinatesTeniaColi(xiList, relaxedLengthList, d2FlatListTC.append(d2Flat) d2FlatListTC = d2FlatListTC + d2FlatListTC[-((elementsCountAroundTC - 1) * tcCount + 1):] - xFlat, d1Flat, d2Flat, _ = combineTeniaColiWithColon(xFlatColon, d1FlatColon, d2FlatColon, [], + xFlat, d1Flat, d2Flat = combineTeniaColiWithColon(xFlatColon, d1FlatColon, d2FlatColon, [], xFlatListTC, d1FlatListTC, d2FlatListTC, [], (elementsCountAroundTC - 1) * tcCount + 1, elementsCountAround + 1, elementsCountAlong, - elementsCountThroughWall, closedProximalEnd) + elementsCountThroughWall, closedProximalEnd)[0:3] return xFlat, d1Flat, d2Flat @@ -1640,10 +1700,10 @@ def createColonCoordinatesTeniaColi(xiList, relativeThicknessList, lengthToDiame d2TC = [d2 for n in range(len(xTC))] - xColon, d1Colon, d2Colon, _ = combineTeniaColiWithColon(xColon, d1Colon, d2Colon, [], xTC, d1TC, d2TC, [], + xColon, d1Colon, d2Colon = combineTeniaColiWithColon(xColon, d1Colon, d2Colon, [], xTC, d1TC, d2TC, [], (elementsCountAroundTC - 1) * tcCount, elementsCountAround, elementsCountAlong, - elementsCountThroughWall, closedProximalEnd) + elementsCountThroughWall, closedProximalEnd)[0:3] return xColon, d1Colon, d2Colon @@ -1656,7 +1716,8 @@ def createNodesAndElementsTeniaColi(region, elementsCountAlong, elementsCountThroughWall, tcCount, annotationGroupsAround, annotationGroupsAlong, annotationGroupsThroughWall, firstNodeIdentifier, firstElementIdentifier, - useCubicHermiteThroughWall, useCrossDerivatives, closedProximalEnd): + useCubicHermiteThroughWall, useCrossDerivatives, closedProximalEnd, + localIdxDistal=[], nodeIdProximal=[]): """ Create nodes and elements for the coordinates and flat coordinates fields. Note that flat coordinates not implemented for closedProximalEnd yet. @@ -1678,15 +1739,23 @@ def createNodesAndElementsTeniaColi(region, :param useCubicHermiteThroughWall: use linear when false. :param useCrossDerivatives: use cross derivatives when true. :param closedProximalEnd: True when proximal end of tube is closed. - :return nodeIdentifier, elementIdentifier, allAnnotationGroups + :param localIdxDistal: Local identifiers derived for distal nodes of the tube. + :param nodeIdProximal: Node identifiers to use as proximal end of tube. + :return nodeIdentifier, elementIdentifier, allAnnotationGroups, nodes on distal end of scaffold. """ nodeIdentifier = firstNodeIdentifier elementIdentifier = firstElementIdentifier elementsCountAround = (elementsCountAroundTC + elementsCountAroundHaustrum) * tcCount + startNode = firstNodeIdentifier # Create coordinates field zero = [0.0, 0.0, 0.0] + nodesDistal = [] + + for i in range(len(localIdxDistal)): + nodesDistal.append([firstNodeIdentifier + c for c in localIdxDistal[i]]) + fm = region.getFieldmodule() fm.beginChange() cache = fm.createFieldcache() @@ -1806,7 +1875,22 @@ def createNodesAndElementsTeniaColi(region, organElementtemplate2.defineField(organCoordinates, -1, eftOrgan2) # create nodes for coordinates field - for n in range(len(x)): + if nodeIdProximal: + proximalNodesOffset = 0 + for m in range(len(nodeIdProximal)): + proximalNodesOffset += len(nodeIdProximal[m]) + # proximalNodesOffset = len(nodeIdProximal) * len(nodeIdProximal[0]) + nodeList = [] + newNodeList = [] + + if nodeIdProximal: + for n3 in range(len(nodeIdProximal)): + for n1 in range(len(nodeIdProximal[n3])): + nodeList.append(nodeIdentifier) + newNodeList.append(nodeIdProximal[n3][n1]) + nodeIdentifier = nodeIdentifier + 1 + + for n in range(proximalNodesOffset if nodeIdProximal else 0, len(x)): node = nodes.createNode(nodeIdentifier, nodetemplate) cache.setNode(node) coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, x[n]) @@ -1818,7 +1902,6 @@ def createNodesAndElementsTeniaColi(region, coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D2_DS1DS3, 1, zero) coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D2_DS2DS3, 1, zero) coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D3_DS1DS2DS3, 1, zero) - # print('NodeIdentifier = ', nodeIdentifier, x[n], d1[n], d2[n]) nodeIdentifier = nodeIdentifier + 1 # Create nodes for flat coordinates field @@ -1924,6 +2007,7 @@ def createNodesAndElementsTeniaColi(region, bni2 = elementsCountThroughWall + 1 + elementsCountAround * e3 + e1 + 1 bni3 = elementsCountThroughWall + 1 + elementsCountAround * e3 + (e1 + 1) % elementsCountAround + 1 nodeIdentifiers = [bni1, bni2, bni3, bni1 + 1, bni2 + elementsCountAround, bni3 + elementsCountAround] + nodeIdentifiers = [c + startNode - 1 for c in nodeIdentifiers] element.setNodesByIdentifier(eft3, nodeIdentifiers) # set general linear map coefficients radiansAround = e1 * radiansPerElementAround @@ -1956,7 +2040,7 @@ def createNodesAndElementsTeniaColi(region, math.sin(radiansAround), math.cos(radiansAround), radiansPerElementAround, math.sin(radiansAroundNext), math.cos(radiansAroundNext), radiansPerElementAround] - bni21 = elementsCountThroughWall + 1 + bni21 = elementsCountThroughWall + 1 + startNode - 1 bni22 = bni21 + elementsCountAround * elementsCountThroughWall + 1 + eTC bni23 = bni22 + 1 bni31 = bni22 + elementsCountAround @@ -1997,7 +2081,7 @@ def createNodesAndElementsTeniaColi(region, math.sin(radiansAround), math.cos(radiansAround), radiansPerElementAround, math.sin(radiansAroundNext), math.cos(radiansAroundNext), radiansPerElementAround] - bni21 = elementsCountThroughWall + 1 + bni21 = elementsCountThroughWall + 1 + startNode - 1 bni22 = bni21 + elementsCountAround * elementsCountThroughWall + int(elementsCountAroundTC * 0.5) + \ elementsCountAroundHaustrum + N * (elementsCountAroundTC + elementsCountAroundHaustrum) + \ eTC + 1 @@ -2050,7 +2134,7 @@ def createNodesAndElementsTeniaColi(region, math.sin(radiansAround), math.cos(radiansAround), radiansPerElementAround, math.sin(radiansAroundNext), math.cos(radiansAroundNext), radiansPerElementAround] - bni21 = elementsCountThroughWall + 1 + bni21 = elementsCountThroughWall + 1 + startNode - 1 bni22 = bni21 + elementsCountAround * (elementsCountThroughWall + 1) - \ int(elementsCountAroundTC * 0.5) + eTC + 1 if elementsCountAroundTC > 2: @@ -2112,6 +2196,12 @@ def createNodesAndElementsTeniaColi(region, bni22 = e2 * now + (e3 + 1) * elementsCountAround + (e1 + 1) % elementsCountAround + 1 + tcOffset1 nodeIdentifiers = [bni11, bni12, bni11 + now + tcOffset, bni12 + now + tcOffset, bni21, bni22, bni21 + now + tcOffset, bni22 + now + tcOffset] + nodeIdentifiers = [c + startNode - 1 for c in nodeIdentifiers] + if e2 == 0 and nodeIdProximal: + for m in range(len(nodeIdentifiers)): + if nodeIdentifiers[m] in nodeList: + idx = nodeList.index(nodeIdentifiers[m]) + nodeIdentifiers[m] = newNodeList[idx] onOpening = e1 > elementsCountAround - 2 element = mesh.createElement(elementIdentifier, elementtemplate) element.setNodesByIdentifier(eft, nodeIdentifiers) @@ -2151,6 +2241,14 @@ def createNodesAndElementsTeniaColi(region, else: nodeIdentifiers = [bni21, bni22, bni21 + now + tcOffset, bni22 + now + tcOffset, bni31, bni31 + now + tcOffset] + + nodeIdentifiers = [c + startNode - 1 for c in nodeIdentifiers] + if e2 == 0 and nodeIdProximal: + for m in range(len(nodeIdentifiers)): + if nodeIdentifiers[m] in nodeList: + idx = nodeList.index(nodeIdentifiers[m]) + nodeIdentifiers[m] = newNodeList[idx] + element = \ mesh.createElement(elementIdentifier, elementtemplate if eTC < int(elementsCountAroundTC * 0.5) - 1 else elementtemplate1) @@ -2180,29 +2278,34 @@ def createNodesAndElementsTeniaColi(region, bni21 = elementsCountThroughWall + 1 + ( e2 - 1) * now + elementsCountThroughWall * elementsCountAround \ + eTC + 1 + tcOffset1 + int(elementsCountAroundTC * 0.5) + \ - (N + 1) * elementsCountAroundHaustrum + N * elementsCountAroundTC + (N + 1) * elementsCountAroundHaustrum + N * elementsCountAroundTC + startNode - 1 bni22 = elementsCountThroughWall + 1 + ( e2 - 1) * now + elementsCountThroughWall * elementsCountAround + \ eTC + 2 + tcOffset1 + int(elementsCountAroundTC * 0.5) + \ - (N + 1) * elementsCountAroundHaustrum + N * elementsCountAroundTC + (N + 1) * elementsCountAroundHaustrum + N * elementsCountAroundTC + startNode - 1 bni31 = elementsCountThroughWall + 1 + e2 * now + eTC + 1 + tcOffset1 + \ - int(elementsCountAroundTC * 0.5) - 1 + N * (elementsCountAroundTC - 1) + int(elementsCountAroundTC * 0.5) - 1 + N * (elementsCountAroundTC - 1) + startNode - 1 bni32 = elementsCountThroughWall + 1 + e2 * now + eTC + 2 + tcOffset1 + \ - int(elementsCountAroundTC * 0.5) - 1 + N * (elementsCountAroundTC - 1) + int(elementsCountAroundTC * 0.5) - 1 + N * (elementsCountAroundTC - 1) + startNode - 1 else: bni21 = e2 * now + elementsCountThroughWall * elementsCountAround + eTC + 1 + tcOffset1 + \ int(elementsCountAroundTC * 0.5) + ( - N + 1) * elementsCountAroundHaustrum + N * elementsCountAroundTC + N + 1) * elementsCountAroundHaustrum + N * elementsCountAroundTC + startNode - 1 bni22 = e2 * now + elementsCountThroughWall * elementsCountAround + eTC + 2 + tcOffset1 + \ int(elementsCountAroundTC * 0.5) + (N + 1) * elementsCountAroundHaustrum + \ - N * elementsCountAroundTC + N * elementsCountAroundTC + startNode - 1 bni31 = (e2 + 1) * now + eTC + 1 + tcOffset1 + int(elementsCountAroundTC * 0.5) - 1 + \ - N * (elementsCountAroundTC - 1) + N * (elementsCountAroundTC - 1) + startNode - 1 bni32 = (e2 + 1) * now + eTC + 2 + tcOffset1 + int(elementsCountAroundTC * 0.5) - 1 + \ - N * (elementsCountAroundTC - 1) + N * (elementsCountAroundTC - 1) + startNode - 1 if eTC == 0: nodeIdentifiers = [bni21, bni22, bni21 + now + tcOffset, bni22 + now + tcOffset, bni32, bni32 + now + tcOffset] + if e2 == 0 and nodeIdProximal: + for m in range(len(nodeIdentifiers)): + if nodeIdentifiers[m] in nodeList: + idx = nodeList.index(nodeIdentifiers[m]) + nodeIdentifiers[m] = newNodeList[idx] element = mesh.createElement(elementIdentifier, elementtemplate2) element.setNodesByIdentifier(eft2, nodeIdentifiers) if xFlat: @@ -2214,6 +2317,11 @@ def createNodesAndElementsTeniaColi(region, elif 0 < eTC < elementsCountAroundTC - 1: nodeIdentifiers = [bni21, bni22, bni21 + now + tcOffset, bni22 + now + tcOffset, bni31, bni32, bni31 + now + tcOffset, bni32 + now + tcOffset] + if e2 == 0 and nodeIdProximal: + for m in range(len(nodeIdentifiers)): + if nodeIdentifiers[m] in nodeList: + idx = nodeList.index(nodeIdentifiers[m]) + nodeIdentifiers[m] = newNodeList[idx] element = mesh.createElement(elementIdentifier, elementtemplate) element.setNodesByIdentifier(eft, nodeIdentifiers) if xFlat: @@ -2225,6 +2333,11 @@ def createNodesAndElementsTeniaColi(region, else: nodeIdentifiers = [bni21, bni22, bni21 + now + tcOffset, bni22 + now + tcOffset, bni31, bni31 + now + tcOffset] + if e2 == 0 and nodeIdProximal: + for m in range(len(nodeIdentifiers)): + if nodeIdentifiers[m] in nodeList: + idx = nodeList.index(nodeIdentifiers[m]) + nodeIdentifiers[m] = newNodeList[idx] element = mesh.createElement(elementIdentifier, elementtemplate1) element.setNodesByIdentifier(eft1, nodeIdentifiers) if xFlat: @@ -2249,30 +2362,37 @@ def createNodesAndElementsTeniaColi(region, bni21 = elementsCountThroughWall + 1 + (e2 - 1) * now + \ elementsCountThroughWall * elementsCountAround + eTC + 1 + tcOffset1 + \ int(elementsCountAroundTC * 0.5) + tcCount * elementsCountAroundHaustrum + \ - (tcCount - 1) * elementsCountAroundTC - bni22 = elementsCountThroughWall + 1 + (e2 - 1) * now + \ + (tcCount - 1) * elementsCountAroundTC + startNode - 1 + bni22 = + startNode - 1 + elementsCountThroughWall + 1 + (e2 - 1) * now + \ elementsCountThroughWall * elementsCountAround + 1 + \ tcOffset1 if eTC == int(elementsCountAroundTC * 0.5 - 1) else bni21 + 1 bni31 = elementsCountThroughWall + 1 + e2 * now + eTC + 1 + tcOffset1 + \ - int(elementsCountAroundTC * 0.5) - 1 + (tcCount - 1) * (elementsCountAroundTC - 1) - bni32 = elementsCountThroughWall + 1 + e2 * now + 1 + tcOffset1 if eTC == int( + int(elementsCountAroundTC * 0.5) - 1 + (tcCount - 1) * (elementsCountAroundTC - 1) + startNode - 1 + bni32 = startNode - 1 + elementsCountThroughWall + 1 + e2 * now + 1 + tcOffset1 if eTC == int( elementsCountAroundTC * 0.5 - 1) \ else bni31 + 1 else: bni21 = e2 * now + elementsCountThroughWall * elementsCountAround + eTC + 1 + tcOffset1 + \ int(elementsCountAroundTC * 0.5) + tcCount * elementsCountAroundHaustrum + \ - (tcCount - 1) * elementsCountAroundTC - bni22 = e2 * now + elementsCountThroughWall * elementsCountAround + 1 + tcOffset1 if eTC == int( + (tcCount - 1) * elementsCountAroundTC + startNode - 1 + bni22 = e2 * now + elementsCountThroughWall * elementsCountAround + 1 + tcOffset1 + startNode - 1 if eTC == int( elementsCountAroundTC * 0.5 - 1) else bni21 + 1 bni31 = (e2 + 1) * now + eTC + 1 + tcOffset1 + int(elementsCountAroundTC * 0.5) - 1 + \ - (tcCount - 1) * (elementsCountAroundTC - 1) - bni32 = (e2 + 1) * now + 1 + tcOffset1 if eTC == int(elementsCountAroundTC * 0.5 - 1) else bni31 + 1 + (tcCount - 1) * (elementsCountAroundTC - 1) + startNode - 1 + bni32 = (e2 + 1) * now + 1 + tcOffset1 + startNode - 1 if eTC == int(elementsCountAroundTC * 0.5 - 1) else bni31 + 1 if eTC > 0: nodeIdentifiers = [bni21, bni22, bni21 + now + tcOffset, bni22 + now + tcOffset, bni31, bni32, bni31 + now + tcOffset, bni32 + now + tcOffset] else: nodeIdentifiers = [bni21, bni22, bni21 + now + tcOffset, bni22 + now + tcOffset, bni32, bni32 + now + tcOffset] + + if e2 == 0 and nodeIdProximal: + for m in range(len(nodeIdentifiers)): + if nodeIdentifiers[m] in nodeList: + idx = nodeList.index(nodeIdentifiers[m]) + nodeIdentifiers[m] = newNodeList[idx] + onOpening = (eTC == int(elementsCountAroundTC * 0.5 - 1)) element = mesh.createElement(elementIdentifier, elementtemplate if eTC > 0 else elementtemplate2) element.setNodesByIdentifier(eft if eTC > 0 else eft2, nodeIdentifiers) @@ -2298,4 +2418,4 @@ def createNodesAndElementsTeniaColi(region, fm.endChange() - return nodeIdentifier, elementIdentifier, allAnnotationGroups + return nodeIdentifier, elementIdentifier, allAnnotationGroups, nodesDistal diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_esophagus1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_esophagus1.py index 17e0f066..96eec051 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_esophagus1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_esophagus1.py @@ -44,10 +44,17 @@ class MeshType_3d_esophagus1(Scaffold_base): (2, [[0.520,-86.043,1340.066], [0.501,16.682,-77.602], [9.142,-0.799,-0.113], [0.212,-0.392,0.096], [-0.465,-5.159,-1.112], [-0.215,-0.377,0.515]]), (3, [[1.368,-67.733,1247.932], [0.235,-3.685,-89.672], [9.061,-1.366,0.080], [-0.833,-0.231,0.187], [-0.714,-4.722,0.192], [-0.167,0.445,1.659]]), (4, [[0.361,-91.057,1165.531], [-2.499,-24.560,-49.102], [7.540,-1.290,0.261], [-0.809,1.514,2.095], [-0.806,-4.269,2.176], [0.001,0.896,0.910]]), - (5, [[11.471,-112.192,1126.439], [9.994,-15.550,-16.424], [7.114,0.998,3.385], [-0.043,3.060,4.152], [-0.754,-3.134,2.509], [0.102,1.373,-0.245]]) + (5, [[11.750,-111.874,1127.887], [7.636,-5.715,-7.930], [5.678,1.265,4.556], [-8.397,13.092,24.878], [-0.708,-3.530,1.862], [-0.807,-7.995,7.596]]) ]), 'userAnnotationGroups': [ + { + '_AnnotationGroup': True, + 'dimension': 1, + 'identifierRanges': '1-4', + 'name': get_esophagus_term('esophagus')[0], + 'ontId': get_esophagus_term('esophagus')[1] + }, { '_AnnotationGroup': True, 'dimension': 1, @@ -89,7 +96,7 @@ def getDefaultOptions(cls, parameterSetName='Default'): 'Central path': copy.deepcopy(centralPathOption), 'Number of elements around': 8, 'Number of elements along': 20, - 'Number of elements through wall': 4, + 'Number of elements through wall': 1, 'Wall thickness': 1.2, 'Mucosa relative thickness': 0.35, 'Submucosa relative thickness': 0.15, @@ -180,324 +187,16 @@ def generateBaseMesh(cls, region, options): :param options: Dict containing options. See getDefaultOptions(). :return: list of AnnotationGroup, None """ - 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']) - - # Esophagus coordinates - lengthToDiameterRatio = 15 - wallThicknessToDiameterRatio = 0.15 - relativeThicknessListEsoCoordinates = [1.0 / elementsCountThroughWall for n3 in range(elementsCountThroughWall)] - - firstNodeIdentifier = 1 - firstElementIdentifier = 1 - - # Central path - tmpRegion = region.createRegion() - centralPath.generate(tmpRegion) - tmpFieldmodule = tmpRegion.getFieldmodule() - tmpNodes = tmpFieldmodule.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES) - tmpCoordinates = tmpFieldmodule.findFieldByName('coordinates') + nextNodeIdentifier = 1 + nextElementIdentifier = 1 + esophagusTermsAlong = ['esophagus', 'cervical part of esophagus', 'thoracic part of esophagus', + 'abdominal part of esophagus'] + geometricCentralPath = options['Central path'] + geometricCentralPath = EsophagusCentralPath(region, geometricCentralPath, esophagusTermsAlong) - esophagusTermsAlong =\ - [None, 'cervical part of esophagus', 'thoracic part of esophagus', 'abdominal part of esophagus'] - arcLengthOfGroupsAlong = [] - - for termName in esophagusTermsAlong: - tmpGroup = tmpFieldmodule.findFieldByName(termName).castGroup() if termName else None - tmpNodeset = tmpGroup.getNodesetGroup(tmpNodes) if tmpGroup else tmpNodes - - cxGroup, cd1Group, cd2Group, cd3Group, cd12Group, cd13Group = get_nodeset_path_field_parameters( - tmpNodeset, tmpCoordinates, - [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]) - 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 not termName: - cx = cxGroup - cd1 = cd1Group - cd2 = cd2Group - cd3 = cd3Group - cd12 = cd12Group - cd13 = cd13Group - - del tmpNodeset - del tmpGroup - - del tmpCoordinates - del tmpNodes - del tmpFieldmodule - 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) - - # Create coordinates and derivatives - transitElementList = [0]*elementsCountAround - xList, d1List, d2List, d3List, curvatureList = \ - tubemesh.extrudeSurfaceCoordinates(xWarpedList, d1WarpedList, d2WarpedList, d3WarpedUnitList, - [wallThickness]*(elementsCountAlong+1), relativeThicknessList, - elementsCountAround, elementsCountAlong, elementsCountThroughWall, - transitElementList, outward=False) - - # Create flat coordinates - xFlat, d1Flat, d2Flat = tubemesh.createFlatCoordinates(xiList, flatWidthList, length, wallThickness, - relativeThicknessList, elementsCountAround, - elementsCountAlong, elementsCountThroughWall, - transitElementList) - - # Create colon coordinates - xEso, d1Eso, d2Eso = \ - tubemesh.createOrganCoordinates(xiList, relativeThicknessListEsoCoordinates, lengthToDiameterRatio, - wallThicknessToDiameterRatio, elementsCountAround, elementsCountAlong, - elementsCountThroughWall, transitElementList) - - # Create nodes and elements - nodeIdentifier, elementIdentifier, annotationGroups = \ - tubemesh.createNodesAndElements(region, xList, d1List, d2List, d3List, xFlat, d1Flat, d2Flat, - xEso, d1Eso, d2Eso, "esophagus coordinates", 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 = markerGroup.getOrCreateNodesetGroup(nodes) - 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() + annotationGroups, nextNodeIdentifier, nextElementIdentifier = \ + createEsophagusMesh3d(region, options, geometricCentralPath, nextNodeIdentifier, nextElementIdentifier, + flatCoordinates=True, materialCoordinates=True)[:3] return annotationGroups, None @@ -542,3 +241,374 @@ def defineFaceAnnotations(cls, region, options, annotationGroups): mucosaInnerSurface = findOrCreateAnnotationGroupForTerm(annotationGroups, region, get_esophagus_term("luminal surface of esophagus")) mucosaInnerSurface.getMeshGroup(mesh2d).addElementsConditional(is_mucosaInnerSurface) + +def createEsophagusMesh3d(region, options, centralPath, nextNodeIdentifier, nextElementIdentifier, + flatCoordinates=False, materialCoordinates=False): + """ + Generates an esophagus scaffold in the region using a central path and parameter options. + :param region: Region to create elements in. + :param options: Parameter options for esophagus scaffold. + :param centralPath: Central path describing path of the esophagus. + :param nextNodeIdentifier: Next node identifier to use. + :param nextElementIdentifier: Next element identifier to use. + :param flatCoordinates: Create flat coordinates if True. + :param materialCoordinates: Create material coordinates if True. + :return annotationGroups, nodeIdentifier, elementIdentifier, nodeIdDistal, xDistal, d1Distal, d2Distal, d3Distal + """ + 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']) + + # Esophagus coordinates + lengthToDiameterRatio = 15 + wallThicknessToDiameterRatio = 0.15 + relativeThicknessListEsoCoordinates = [1.0 / elementsCountThroughWall for n3 in range(elementsCountThroughWall)] + + esophagusTermsAlong =\ + ['esophagus', 'cervical part of esophagus', 'thoracic part of esophagus', 'abdominal part of esophagus'] + + centralPathLength = centralPath.arcLengthOfGroupsAlong[0] + cx = centralPath.cxGroups[0] + cd1 = centralPath.cd1Groups[0] + cd2 = centralPath.cd2Groups[0] + cd12 = centralPath.cd12Groups[0] + cd3 = centralPath.cd3Groups[0] + cd13 = centralPath.cd13Groups[0] + arcLengthOfGroupsAlong = centralPath.arcLengthOfGroupsAlong + + # 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) + + 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) + + # Create coordinates and derivatives + transitElementList = [0]*elementsCountAround + xList, d1List, d2List, d3List, curvatureList, localIdxDistal, xDistal, d1Distal, d2Distal, d3Distal = \ + tubemesh.extrudeSurfaceCoordinates(xWarpedList, d1WarpedList, d2WarpedList, d3WarpedUnitList, + [wallThickness]*(elementsCountAlong+1), relativeThicknessList, + elementsCountAround, elementsCountAlong, elementsCountThroughWall, + transitElementList, outward=False) + + # Create flat coordinates + if flatCoordinates: + xFlat, d1Flat, d2Flat = tubemesh.createFlatCoordinates(xiList, flatWidthList, length, wallThickness, + relativeThicknessList, elementsCountAround, + elementsCountAlong, elementsCountThroughWall, + transitElementList) + else: + xFlat = d1Flat = d2Flat = [] + + # Create colon coordinates + if materialCoordinates: + xEso, d1Eso, d2Eso = \ + tubemesh.createOrganCoordinates(xiList, relativeThicknessListEsoCoordinates, lengthToDiameterRatio, + wallThicknessToDiameterRatio, elementsCountAround, elementsCountAlong, + elementsCountThroughWall, transitElementList) + else: + xEso = d1Eso = d2Eso = [] + + # Create nodes and elements + nodeIdentifier, elementIdentifier, annotationGroups, nodeIdDistal = \ + tubemesh.createNodesAndElements(region, xList, d1List, d2List, d3List, xFlat, d1Flat, d2Flat, + xEso, d1Eso, d2Eso, "esophagus coordinates", elementsCountAround, + elementsCountAlong, elementsCountThroughWall, annotationGroupsAround, + annotationGroupsAlong, annotationGroupsThroughWall, + nextNodeIdentifier, nextElementIdentifier, + useCubicHermiteThroughWall, useCrossDerivatives, closedProximalEnd, + localIdxDistal) + + # 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 = markerGroup.getOrCreateNodesetGroup(nodes) + 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, nodeIdentifier, elementIdentifier, nodeIdDistal, xDistal, d1Distal, d2Distal, d3Distal + +class EsophagusCentralPath: + """ + Generates sampled central path for esophagus scaffold. + """ + def __init__(self, region, centralPath, termsAlong=[None]): + """ + :param region: Zinc region to define model in. + :param centralPath: Central path subscaffold from meshtype_1d_network_layout1 + :param termsAlong: Annotation terms along length of central path + """ + # Extract length of each group along esophagus from central path + cxGroups = [] + cd1Groups = [] + cd2Groups = [] + cd3Groups = [] + cd12Groups = [] + cd13Groups = [] + + tmpRegion = region.createRegion() + centralPath.generate(tmpRegion) + tmpFieldmodule = tmpRegion.getFieldmodule() + tmpNodes = tmpFieldmodule.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES) + tmpCoordinates = tmpFieldmodule.findFieldByName('coordinates') + arcLengthOfGroupsAlong = [] + + for termName in termsAlong: + tmpGroup = tmpFieldmodule.findFieldByName(termName).castGroup() if termName else None + tmpNodeset = tmpGroup.getNodesetGroup(tmpNodes) if tmpGroup else tmpNodes + + cxGroup, cd1Group, cd2Group, cd3Group, cd12Group, cd13Group = get_nodeset_path_field_parameters( + tmpNodeset, tmpCoordinates, + [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]) + + 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 termName == "esophagus": + cxGroups.append(cxGroup) + cd1Groups.append(cd1Group) + cd2Groups.append(cd2Group) + cd3Groups.append(cd3Group) + cd12Groups.append(cd12Group) + cd13Groups.append(cd13Group) + + del tmpNodeset + del tmpGroup + + del tmpCoordinates + del tmpNodes + del tmpFieldmodule + del tmpRegion + + self.arcLengthOfGroupsAlong = arcLengthOfGroupsAlong + self.cxGroups = cxGroups + self.cd1Groups = cd1Groups + self.cd2Groups = cd2Groups + self.cd3Groups = cd3Groups + self.cd12Groups = cd12Groups + self.cd13Groups = cd13Groups diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_gastrointestinaltract1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_gastrointestinaltract1.py new file mode 100644 index 00000000..824cb3d9 --- /dev/null +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_gastrointestinaltract1.py @@ -0,0 +1,711 @@ +""" +Generates a 3-D gastrointestinal tract mesh along the central line, +with variable numbers of elements around, along and through +wall, with variable radius and thickness along. +""" + +import copy + +from cmlibs.utils.zinc.field import findOrCreateFieldCoordinates +from cmlibs.zinc.field import Field +from cmlibs.zinc.node import Node +from scaffoldmaker.annotation.annotationgroup import mergeAnnotationGroups, getAnnotationGroupForTerm +from scaffoldmaker.annotation.cecum_terms import get_cecum_term +from scaffoldmaker.annotation.colon_terms import get_colon_term +from scaffoldmaker.annotation.esophagus_terms import get_esophagus_term +from scaffoldmaker.annotation.smallintestine_terms import get_smallintestine_term +from scaffoldmaker.annotation.stomach_terms import get_stomach_term +from scaffoldmaker.meshtypes.meshtype_1d_network_layout1 import MeshType_1d_network_layout1 +from scaffoldmaker.meshtypes.meshtype_3d_cecum1 import MeshType_3d_cecum1, createCecumMesh3d, CecumCentralPath +from scaffoldmaker.meshtypes.meshtype_3d_colon1 import MeshType_3d_colon1, createColonMesh3d, ColonCentralPath +from scaffoldmaker.meshtypes.meshtype_3d_esophagus1 import MeshType_3d_esophagus1, createEsophagusMesh3d, \ + EsophagusCentralPath +from scaffoldmaker.meshtypes.meshtype_3d_smallintestine1 import MeshType_3d_smallintestine1, \ + createSmallIntestineMesh3d, SmallIntestineCentralPath +from scaffoldmaker.meshtypes.meshtype_3d_stomach1 import MeshType_3d_stomach1, createStomachMesh3d, StomachCentralPath +from scaffoldmaker.meshtypes.scaffold_base import Scaffold_base +from scaffoldmaker.scaffoldpackage import ScaffoldPackage +from scaffoldmaker.utils import interpolation as interp +from scaffoldmaker.utils.zinc_utils import exnode_string_from_nodeset_field_parameters + + +class MeshType_3d_gastrointestinaltract1(Scaffold_base): + ''' + Generates a 3-D gastrointestinal tract mesh with variable numbers of elements around, along the central line, + and through wall. The tract is created by following an annotated central path and calling scaffold function to + generate the respective segment along the central line profile. + ''' + + parameterSetStructureStrings = { + 'Human 1': ScaffoldPackage(MeshType_1d_network_layout1, { + 'scaffoldSettings': { + "Structure": "1-2-3-4-5-6-7.2, 8-9-10-11-7-12-13-14-15-16-17-18-19-20-21-22-23-24-25-26-27-28-29-30-31-" + "32-33-34-35-36-37-38-39-40-41-42-43-44-45-46-47-48-49-50-51-52-53-54-55-56-57-58-59-60-" + "61-62-63-64-65-66-67-68-69-70-71-72-73-74-75-76-77-78-79-80-81-82-83-84-85-86-87-88-89-" + "90-91-92-93-94-95-96-97-98-99-100-101-102-103-104-105-106-107-108-109-110-111-112-113-" + "114-115-116-117-118-119-120-121-122-123-124-125-126-127-128-129-130-131-132-133-134-135-" + "136-137-138-139-140-141-142-143-144-145-146-147-148-149-150-151-152-153-154-155-156-157-" + "158-159-160-161-162-163-164-165-166-167-168-169-170-171-172.2, 173-172-174-175-176-177-" + "178-179-180-181-182-183-184-185-186-187-188-189-190-191-192-193-194-195-196-197-198-199-" + "200-201-202-203-204-205-206-207-208-209-210-211-212-213-214-215-216-217-218-219-220-221-" + "222" + }, + 'meshEdits': exnode_string_from_nodeset_field_parameters( + [ Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ + (1, [[0.394,-100.872,1402.818], [-0.035,12.367,-48.020], [8.730,-0.526,-0.142], [0.613,-0.153,-0.037], [-0.272,-4.224,-1.088], [-0.169,-1.491,-0.564]]), + (2, [[0.520,-86.043,1340.066], [0.501,16.682,-77.602], [9.142,-0.799,-0.113], [0.212,-0.392,0.096], [-0.465,-5.159,-1.112], [-0.215,-0.377,0.515]]), + (3, [[1.368,-67.733,1247.932], [0.235,-3.685,-89.672], [9.061,-1.366,0.080], [-0.833,-0.231,0.187], [-0.714,-4.722,0.192], [-0.167,0.445,1.659]]), + (4, [[0.361,-91.057,1165.531], [-2.499,-24.560,-49.102], [7.540,-1.290,0.261], [-0.809,1.514,2.095], [-0.806,-4.269,2.176], [0.001,0.896,0.910]]), + (5, [[11.750,-111.874,1127.887], [7.636,-5.715,-7.930], [5.678,1.265,4.556], [-8.397,13.092,24.878], [-0.708,-3.530,1.862], [-0.807,-7.995,7.596]]),# stomach + (6, [[23.789,-117.922,1120.040], [26.354,-6.724,-6.404], [4.223,6.205,10.864], [10.037,1.800,8.968], [-1.192,-11.215,6.869], [-2.926,-13.889,10.204]]), + (7, [[63.704,-120.094,1123.374], [[0.500,-9.138,-13.405],[50.106,1.267,11.056]], [[37.742,-3.477,3.778],[-2.509,7.605,10.499]], [[3.190,-0.590,-0.290],[3.190,-0.590,-0.290]], [[-5.452,-34.121,23.056],[-1.379,-10.790,7.486]], [[-0.100,-1.220,0.550],[-0.100,-1.220,0.550]]]), + (8, [[61.247,-99.931,1152.681], [0.346,-2.728,-3.873], [11.320,-0.365,1.269], [15.701,-3.029,2.832], [-0.653,-5.931,4.119], [-5.756,-22.456,14.946]]), + (9, [[61.743,-103.510,1147.760], [0.413,-3.592,-5.311], [24.159,-2.387,3.493], [10.039,-1.491,0.928], [-2.982,-15.339,10.142], [-2.384,-12.784,8.034]]), + (10, [[62.381,-107.527,1141.785], [0.249,-4.737,-7.073], [30.559,-2.973,3.067], [5.720,-0.448,-0.071], [-3.839,-23.420,15.550], [-0.206,-5.098,2.599]]), + (11, [[62.800,-113.150,1133.665], [0.116,-6.546,-9.651], [35.408,-3.630,2.888], [4.541,-0.488,0.325], [-4.677,-29.659,20.061], [-0.383,-3.012,1.219]]), + (12, [[64.339,-131.197,1107.233], [0.086,-11.682,-16.915], [39.201,-3.705,2.758], [0.490,-2.470,-4.030], [-5.108,-35.712,24.638], [0.260,0.760,0.250]]), + (13, [[62.912,-143.954,1088.811], [-5.216,-12.408,-17.967], [34.623,-8.161,-4.415], [-4.950,-4.940,-8.800], [-4.917,-34.532,25.275], [0.770,0.610,1.050]]), + (14, [[53.361,-155.397,1072.006], [-15.833,-9.775,-15.486], [25.117,-13.916,-16.896], [-14.190,-3.410,-7.580], [-2.355,-30.712,21.794], [2.030,4.350,-1.240]]), + (15, [[32.110,-162.230,1059.680], [-22.173,-3.681,-8.142], [10.067,-16.126,-20.126], [-15.400,0.330,-0.620], [-2.559,-23.629,17.653], [1.200,8.620,-5.080]]), + (16, [[10.560,-162.970,1055.650], [-20.956,2.164,-0.908], [-0.696,-13.976,-17.241], [-8.750,2.830,4.760], [-2.502,-18.048,14.732], [-1.000,7.490,-3.260]]), + (17, [[-8.740,-158.280,1057.630], [-17.269,8.027,2.588], [-6.253,-10.164,-10.200], [-2.630,4.430,6.290], [-3.442,-11.913,13.981], [-1.380,7.080,-2.660]]), + (18, [[-23.260,-147.620,1060.640], [-11.787,11.369,1.720], [-5.807,-5.321,-4.621], [-0.700,3.020,1.710], [-3.207,-4.764,9.515], [-2.080,5.830,-2.460]]), + (19, [[-32.281,-136.261,1061.249], [-6.125,11.114,-0.493], [-5.735,-3.374,-4.823], [-2.070,-0.220,-4.520], [-4.630,-2.238,7.071], [-4.400,2.440,0.570]]),# small intestine + (20, [[-40.674,-122.300,1060.850], [-5.403,7.321,-2.629], [-4.779,-4.249,-5.161], [2.360,-0.320,0.120], [-5.138,-1.668,6.875], [-0.250,2.080,-4.500]]), + (21, [[-48.346,-108.981,1049.574], [-6.840,19.440,-21.940], [-3.459,-4.108,-5.699], [0.900,0.690,1.570], [-7.043,0.777,3.341], [-0.760,2.950,-2.230]]), + (22, [[-43.450,-95.700,1015.590], [40.730,3.220,-44.800], [-5.240,-3.340,-4.990], [-0.380,4.380,-0.330], [-2.270,6.020,-1.640], [4.590,3.490,-0.790]]), + (23, [[26.760,-119.310,992.030], [58.860,-18.680,-8.450], [0.310,3.940,-6.600], [4.150,2.330,1.070], [2.230,5.490,3.380], [3.360,-4.080,2.370]]), + (24, [[63.862,-132.266,992.002], [9.680,-30.910,-18.900], [5.846,1.916,2.960], [-0.330,-6.200,3.780], [5.300,-1.090,4.490], [-3.680,-1.570,1.510]]), + (25, [[46.280,-139.940,982.680], [-22.680,-4.850,-10.940], [1.050,-7.060,0.970], [-0.930,-3.800,3.220], [-3.190,0.420,6.420], [-5.340,-0.640,-2.850]]), + (26, [[28.560,-141.070,974.610], [3.750,-10.520,-21.300], [1.560,-6.210,3.340], [-1.000,0.060,-0.070], [-6.850,-1.870,-0.290], [1.100,-0.530,-6.400]]), + (27, [[52.390,-146.130,971.400], [18.400,-3.700,0.670], [-1.440,-7.110,0.300], [-0.590,-0.290,-0.540], [0.190,-0.340,-7.250], [2.420,0.060,-1.890]]), + (28, [[63.130,-148.180,973.520], [10.490,-1.410,1.470], [-1.070,-7.160,0.770], [2.410,0.380,0.120], [0.880,-0.900,-7.160], [-2.030,-1.100,0.840]]), + (29, [[72.690,-148.910,974.300], [7.650,3.570,-7.080], [3.500,-6.340,0.580], [0.430,0.200,-1.420], [-3.880,-2.630,-5.520], [-3.490,0.080,4.650]]), + (30, [[71.050,-143.650,964.650], [-5.960,4.700,-11.040], [-0.810,-6.830,-2.470], [-2.360,-0.380,-1.140], [-6.400,-0.430,3.270], [0.270,0.950,6.070]]), + (31, [[61.060,-140.780,954.520], [-17.960,3.880,-6.220], [-1.070,-7.120,-1.370], [0.180,-0.250,1.370], [-2.560,-0.940,6.800], [3.840,0.270,2.130]]), + (32, [[37.990,-136.930,957.170], [-18.820,0.880,5.080], [-0.160,-7.340,0.670], [1.900,0.170,0.590], [1.940,0.610,7.070], [2.120,1.030,-0.120]]), + (33, [[24.260,-138.060,963.160], [-17.400,-6.040,8.510], [2.590,-6.900,0.380], [2.420,1.010,0.690], [2.780,1.420,6.690], [-2.180,-0.670,-0.740]]), + (34, [[6.500,-150.310,973.050], [-8.250,-16.440,-13.420], [4.890,-4.750,2.820], [-1.080,-0.490,-0.280], [-4.820,-1.850,5.240], [-4.270,-0.820,-2.180]]), + (35, [[15.970,-149.800,957.690], [-4.350,-1.250,-14.050], [0.990,-7.390,0.350], [-1.040,-0.780,-0.850], [-6.950,-0.830,2.230], [-0.480,0.190,-0.500]]), + (36, [[8.290,-150.980,954.250], [-3.340,-0.730,-8.150], [1.180,-7.370,0.180], [0.180,0.050,0.370], [-6.710,-1.000,2.840], [0.560,-0.430,-3.270]]), + (37, [[10.770,-150.880,946.760], [5.270,-0.050,-7.150], [1.370,-7.280,1.060], [-0.120,-0.030,0.050], [-5.800,-1.710,-4.270], [2.050,0.220,-4.830]]), + (38, [[18.300,-151.090,941.260], [7.790,0.880,-2.390], [0.880,-7.450,0.160], [0.050,-0.010,-0.900], [-2.150,-0.400,-7.160], [4.520,1.490,-0.770]]), + (39, [[24.850,-149.580,941.590], [5.320,0.620,3.020], [1.330,-7.350,-0.840], [-0.350,0.010,-0.650], [3.510,1.370,-6.460], [3.430,0.580,1.190]]), + (40, [[27.850,-149.810,945.920], [3.490,-0.550,3.990], [0.330,-7.390,-1.300], [-0.750,-0.040,-0.150], [5.610,1.090,-4.760], [-0.580,-0.160,-0.310]]), + (41, [[31.640,-150.640,949.370], [5.770,-0.500,1.810], [-0.280,-7.430,-1.160], [0.320,-0.010,0.320], [2.310,1.020,-7.080], [-4.590,-0.600,-0.740]]), + (42, [[38.160,-150.550,948.480], [5.400,1.270,-4.340], [1.280,-7.400,-0.560], [1.280,0.320,-0.530], [-4.630,-0.350,-5.870], [-4.440,-1.610,3.120]]), + (43, [[40.300,-148.530,942.170], [-0.500,2.450,-7.550], [2.420,-6.730,-2.350], [1.390,0.820,-0.980], [-7.020,-2.420,-0.320], [-0.570,-0.950,1.020]]), + (44, [[36.760,-146.190,935.090], [3.270,5.380,-6.440], [4.320,-5.620,-2.500], [0.260,-0.080,1.070], [-5.500,-2.170,-4.600], [3.600,1.240,-3.410]]), + (45, [[44.600,-142.080,934.770], [8.650,3.530,1.100], [2.850,-7.000,0.020], [-1.020,-0.770,1.000], [0.830,0.310,-7.530], [3.410,1.450,-1.300]]), + (46, [[53.340,-139.440,937.210], [8.310,2.340,2.220], [2.150,-7.250,-0.380], [-0.540,-0.170,-0.420], [1.710,0.890,-7.340], [0.070,0.370,0.030]]), + (47, [[61.180,-137.390,939.220], [8.230,1.720,1.430], [1.690,-7.360,-0.860], [-0.380,-0.100,-0.170], [1.060,1.120,-7.440], [-0.840,-0.070,-0.120]]), + (48, [[69.720,-136.030,940.040], [8.420,1.510,0.050], [1.350,-7.460,-0.740], [0.300,0.210,-0.630], [-0.090,0.740,-7.580], [-3.560,-0.970,1.730]]), + (49, [[77.280,-134.500,939.340], [4.490,4.180,-8.530], [2.310,-6.920,-2.180], [-0.290,0.070,-0.480], [-6.410,-0.930,-3.830], [-3.190,-0.950,5.530]]), + (50, [[71.890,-131.270,929.110], [-6.780,1.090,-6.790], [0.090,-7.530,-1.300], [-0.440,-0.260,1.250], [-5.410,-0.970,5.250], [0.240,0.450,2.900]]), + (51, [[66.110,-131.600,925.900], [-4.090,-0.450,-4.440], [0.540,-7.640,0.280], [0.080,0.050,1.400], [-5.560,-0.210,5.140], [-0.150,0.880,-0.160]]), + (52, [[63.930,-132.090,921.070], [-3.930,-1.160,-4.370], [0.320,-7.470,1.700], [0.720,0.300,0.950], [-5.720,0.870,4.920], [0.660,0.510,0.560]]), + (53, [[58.470,-133.890,917.960], [-6.670,-3.360,-3.670], [2.290,-6.970,2.210], [2.280,0.920,-0.110], [-3.960,0.750,6.500], [2.250,0.030,1.310]]), + (54, [[51.020,-139.090,914.020], [-6.630,-6.740,0.390], [5.400,-5.250,1.130], [1.070,0.420,-1.320], [-0.590,1.020,7.590], [3.120,0.370,0.200]]), + (55, [[46.770,-145.490,918.120], [-5.050,-4.370,2.870], [4.810,-5.920,-0.550], [-1.310,-0.890,-0.940], [2.680,1.520,7.030], [1.260,-0.680,-0.120]]), + (56, [[41.950,-147.920,919.780], [-5.030,-2.380,1.940], [2.900,-7.030,-1.100], [-1.320,-0.680,-0.330], [2.770,0.010,7.180], [-0.110,-1.000,0.120]]), + (57, [[36.760,-150.210,922.000], [-5.100,-1.680,1.580], [2.030,-7.330,-1.240], [-0.510,-0.220,0.810], [2.440,-0.560,7.300], [-0.450,0.500,0.130]]), + (58, [[31.890,-151.330,922.990], [-5.710,-1.250,1.560], [1.770,-7.500,0.460], [-0.570,-0.180,0.730], [1.840,0.880,7.450], [-2.050,0.330,0.030]]), + (59, [[25.550,-152.650,925.180], [-6.280,-0.560,-2.170], [0.700,-7.710,-0.030], [-0.690,-0.090,-0.620], [-2.500,-0.250,7.310], [-3.190,-0.780,-0.830]]), + (60, [[22.170,-152.270,920.060], [-4.850,0.300,-4.200], [0.270,-7.700,-0.850], [-0.240,-0.020,0.240], [-5.020,-0.810,5.760], [2.410,0.370,-0.060]]), + (61, [[16.600,-152.110,917.510], [-6.970,0.000,2.680], [0.200,-7.740,0.510], [-0.300,-0.030,0.600], [2.770,0.540,7.210], [5.780,0.370,-0.740]]), + (62, [[13.120,-152.320,924.900], [-3.730,0.410,7.150], [-0.450,-7.750,0.210], [-0.140,-0.020,-0.160], [6.780,-0.300,3.550], [-0.230,-0.180,0.200]]), + (63, [[9.440,-151.370,931.310], [-7.880,0.190,2.810], [-0.130,-7.780,0.170], [0.490,-0.010,0.120], [2.610,0.120,7.310], [-3.700,0.330,2.080]]), + (64, [[1.230,-152.170,928.310], [-8.130,-0.720,-1.080], [0.620,-7.760,0.490], [0.090,-0.010,-0.290], [-1.060,0.400,7.710], [1.430,-0.160,-0.650]]), + (65, [[-5.970,-152.740,928.930], [-5.640,-0.310,4.390], [0.170,-7.800,-0.330], [-0.930,0.040,0.090], [4.760,-0.160,6.120], [3.980,-0.840,-4.110]]), + (66, [[-8.050,-152.700,935.120], [0.840,0.430,7.280], [-1.310,-7.670,0.600], [-1.080,0.170,0.740], [7.520,-1.340,-0.790], [0.790,-0.430,-1.110]]), + (67, [[-4.180,-151.980,940.930], [-5.500,2.850,8.020], [-2.070,-7.440,1.220], [-0.370,0.070,-0.100], [6.170,-0.960,4.570], [-3.010,0.560,4.290]]), + (68, [[-15.920,-150.230,939.850], [-11.530,2.830,0.080], [-1.870,-7.620,-0.020], [0.120,0.150,0.780], [0.040,-0.030,7.840], [0.810,0.000,-1.160]]), + (69, [[-25.870,-146.770,940.970], [-2.690,4.150,9.230], [-1.800,-7.150,2.690], [0.690,0.200,1.480], [7.250,-0.880,2.510], [1.720,-1.410,-6.490]]), + (70, [[-19.430,-146.580,946.990], [7.700,1.830,5.130], [-0.490,-7.140,3.290], [1.240,-0.130,-0.090], [4.500,-2.940,-5.700], [-0.590,-0.040,-3.450]]), + (71, [[-11.610,-143.430,950.540], [5.250,2.520,5.680], [0.830,-7.420,2.520], [0.750,-0.240,-0.870], [5.910,-1.040,-5.000], [0.830,1.410,0.570]]), + (72, [[-9.220,-141.820,956.880], [3.600,1.580,5.200], [1.220,-7.660,1.480], [-0.050,-0.130,-0.420], [6.390,0.150,-4.470], [0.120,0.280,0.100]]), + (73, [[-4.880,-140.390,960.700], [3.780,1.360,4.900], [0.780,-7.720,1.540], [0.070,-0.060,-0.650], [6.230,-0.310,-4.720], [0.530,0.530,1.660]]), + (74, [[-1.980,-139.200,966.470], [0.650,0.130,7.290], [1.420,-7.780,0.010], [0.230,-0.060,-0.880], [7.610,1.390,-0.700], [0.660,0.740,3.140]]), + (75, [[-4.150,-140.360,973.960], [-2.380,-0.650,10.170], [1.190,-7.830,-0.220], [-0.650,-0.070,-0.200], [7.500,1.090,1.830], [-0.210,-0.700,2.000]]), + (76, [[-6.206,-140.381,984.826], [-3.997,1.953,8.625], [-0.240,-7.940,-0.400], [-0.770,0.020,-0.440], [7.090,-0.380,3.280], [-1.820,-1.020,2.460]]), + (77, [[-11.071,-137.239,990.534], [-6.502,2.564,3.616], [-0.730,-7.850,-1.030], [0.040,-0.000,-0.150], [4.330,-1.250,6.510], [-3.510,-0.150,2.180]]), + (78, [[-18.114,-135.562,991.751], [-6.821,0.865,-0.438], [-0.170,-7.940,-0.730], [0.590,-0.040,0.750], [-0.320,-0.720,7.930], [-4.070,0.690,0.160]]), + (79, [[-24.108,-135.469,989.949], [-5.560,-1.043,-2.740], [0.530,-7.940,0.630], [-0.080,0.160,1.480], [-4.270,0.240,6.690], [-3.140,0.950,-2.220]]), + (80, [[-28.764,-137.545,986.518], [-3.033,-3.486,-4.184], [-0.280,-7.620,2.380], [-1.430,0.310,0.610], [-7.020,1.290,3.320], [-0.940,0.180,-5.150]]), + (81, [[-29.636,-141.811,982.334], [1.634,-2.756,-5.189], [-2.170,-7.290,2.440], [-1.160,0.110,-0.290], [-7.100,1.030,-3.250], [0.490,-0.350,-4.870]]), + (82, [[-24.820,-145.190,978.580], [4.650,-2.180,-4.590], [-2.130,-7.580,1.440], [0.290,-0.260,-0.910], [-5.460,0.450,-5.750], [-0.330,0.230,1.000]]), + (83, [[-20.750,-146.910,974.010], [1.230,-0.700,-6.940], [-1.580,-7.840,0.510], [0.080,-0.090,-0.690], [-7.590,1.430,-1.480], [0.460,0.350,5.770]]), + (84, [[-23.390,-146.100,967.330], [-6.320,1.650,-4.010], [-2.030,-7.760,0.010], [-0.160,0.070,0.360], [-4.040,1.070,6.800], [4.830,-0.400,4.280]]), + (85, [[-30.600,-144.330,967.780], [-6.690,2.040,2.190], [-1.930,-7.690,1.270], [0.050,0.000,0.440], [2.650,0.580,7.550], [3.030,-0.350,0.340]]), + (86, [[-36.170,-142.250,971.340], [-6.590,1.940,2.270], [-1.940,-7.730,1.010], [0.040,-0.010,0.090], [2.700,0.310,7.560], [0.370,-0.020,-0.150]]), + (87, [[-43.400,-140.590,972.070], [-6.040,1.970,2.740], [-1.830,-7.710,1.480], [0.020,0.340,1.180], [3.470,0.560,7.230], [2.300,-0.410,-2.270]]), + (88, [[-47.620,-138.630,976.140], [-1.780,2.680,4.620], [-1.870,-7.070,3.390], [0.010,0.350,0.980], [7.300,-0.460,3.080], [1.720,-1.440,-3.710]]), + (89, [[-47.100,-135.980,980.160], [0.980,1.950,4.050], [-1.830,-6.900,3.760], [0.210,-0.140,-0.200], [7.550,-2.370,-0.680], [0.040,-0.760,-2.210]]), + (90, [[-45.780,-134.750,984.020], [1.920,1.940,5.580], [-1.460,-7.340,3.050], [-0.530,0.370,0.090], [7.430,-2.220,-1.790], [-0.240,0.260,1.070]]), + (91, [[-42.419,-130.149,990.122], [-1.920,7.780,7.360], [-3.780,-5.370,4.690], [-2.140,1.260,-0.060], [6.910,-1.720,3.610], [-3.470,2.540,4.150]]), + (92, [[-48.414,-118.983,992.238], [-8.280,6.980,-7.760], [-5.960,-5.080,1.790], [0.610,-1.110,-1.840], [-2.030,4.630,6.340], [-6.540,1.980,-0.430]]), + (93, [[-54.520,-122.570,980.900], [-5.100,0.460,-13.050], [-2.600,-7.660,0.750], [2.850,-1.090,0.850], [-7.020,2.660,2.840], [-2.860,-1.790,-2.310]]), + (94, [[-56.534,-121.929,967.273], [-3.400,-6.950,-12.830], [-2.036,-6.714,3.150], [-1.690,1.750,1.250], [-7.800,0.860,1.600], [1.210,-0.700,-4.510]]), + (95, [[-57.601,-134.069,961.014], [4.440,-11.120,-4.920], [-6.170,-3.970,3.410], [-1.800,0.340,-0.380], [-4.460,1.190,-6.700], [1.720,-0.860,-3.600]]), + (96, [[-53.650,-142.090,958.040], [8.150,-8.950,-3.450], [-4.950,-5.680,3.060], [2.040,-1.620,-0.110], [-3.750,-0.620,-7.230], [-0.920,-0.860,0.970]]), + (97, [[-43.780,-150.900,953.550], [6.860,-6.210,-10.820], [-1.570,-7.380,3.240], [0.100,-0.470,-1.480], [-6.930,-0.360,-4.180], [-0.500,1.880,6.120]]), + (98, [[-42.790,-151.920,940.920], [-10.160,7.350,-12.870], [-4.740,-6.680,-0.070], [-1.780,0.370,-1.940], [-4.810,3.350,5.710], [1.370,1.930,5.900]]), + (99, [[-59.560,-139.320,940.870], [-10.470,7.530,-10.550], [-4.670,-6.770,-0.210], [-0.780,0.740,0.770], [-4.390,2.820,6.370], [-0.630,1.740,-4.220]]), + (100, [[-61.190,-138.430,930.230], [-0.370,-2.040,-12.190], [-5.970,-5.520,1.110], [-0.860,0.960,0.960], [-5.640,5.920,-0.830], [0.650,-0.720,-6.690]]), + (101, [[-60.050,-143.370,918.840], [6.120,-9.410,-3.110], [-6.440,-4.780,1.790], [0.250,-0.370,-0.760], [-2.750,0.780,-7.780], [3.390,-3.100,-3.060]]), + (102, [[-54.810,-148.970,924.540], [7.070,-6.600,2.050], [-5.610,-6.050,-0.170], [0.760,-0.860,-0.330], [1.380,-1.050,-8.130], [-1.610,1.400,1.580]]), + (103, [[-48.000,-154.670,922.570], [3.540,-3.720,-7.480], [-4.830,-6.610,1.000], [1.210,-0.760,-0.140], [-5.850,3.580,-4.550], [-4.060,1.810,3.830]]), + (104, [[-49.390,-154.510,914.460], [0.270,0.350,-10.670], [-3.110,-7.640,-0.330], [1.860,-0.790,-0.480], [-7.540,3.070,-0.100], [1.640,-1.570,-0.540]]), + (105, [[-46.730,-154.010,904.000], [18.990,-1.890,-1.480], [-0.780,-8.190,0.400], [1.310,-0.300,0.500], [-0.670,-0.340,-8.190], [5.190,-2.310,-4.980]]), + (106, [[-31.900,-157.000,923.200], [20.270,-2.840,5.710], [-1.280,-8.040,0.540], [1.630,0.180,0.170], [2.100,-0.860,-7.850], [-3.210,-0.770,1.420]]), + (107, [[-17.040,-158.470,917.330], [10.690,1.600,-10.940], [1.940,-7.840,0.740], [0.870,0.010,-0.110], [-5.440,-1.880,-5.580], [-1.710,0.190,-0.090]]), + (108, [[-12.920,-154.880,905.590], [14.280,1.560,-5.120], [1.010,-8.000,0.370], [-0.980,-0.090,-0.580], [-2.650,-0.690,-7.580], [1.890,1.140,-1.150]]), + (109, [[0.790,-157.220,913.220], [17.050,-0.100,-3.500], [-0.160,-8.010,-0.530], [0.240,0.090,-0.240], [-1.610,0.550,-7.830], [0.100,0.160,0.010]]), + (110, [[11.370,-154.850,899.810], [20.470,4.340,-7.040], [1.620,-7.800,-0.100], [0.670,0.240,-0.620], [-2.500,-0.420,-7.540], [-1.600,0.070,0.920]]), + (111, [[35.280,-149.960,905.730], [15.010,5.710,-13.200], [0.800,-7.500,-2.330], [1.120,0.330,0.340], [-5.360,1.170,-5.590], [-1.050,-1.380,0.950]]), + (112, [[31.510,-148.900,893.070], [11.510,6.020,-14.640], [3.170,-7.130,-0.440], [1.650,0.510,0.450], [-5.440,-2.110,-5.150], [2.200,-0.030,-0.530]]), + (113, [[53.210,-142.180,892.150], [16.130,8.560,4.600], [3.960,-6.330,-2.130], [0.420,0.200,0.800], [0.580,2.810,-7.250], [3.440,1.000,-0.610]]), + (114, [[61.915,-135.512,899.756], [10.425,5.807,7.557], [4.220,-6.470,0.220], [-1.030,-0.530,1.150], [2.810,1.590,-7.040], [-2.200,-1.800,0.660]]), + (115, [[72.652,-131.499,906.138], [13.270,2.580,-11.410], [1.590,-7.520,0.150], [-0.630,-0.250,0.200], [-4.770,-1.120,-5.790], [-4.380,-1.930,4.880]]), + (116, [[70.933,-136.139,889.296], [-12.490,-8.250,-22.650], [3.260,-6.840,0.700], [0.840,0.360,-0.040], [-5.890,-2.380,4.110], [0.640,-0.370,7.040]]), + (117, [[47.820,-142.630,864.930], [-22.720,-8.470,-7.520], [2.750,-7.000,-0.430], [0.030,0.230,-1.270], [-1.940,-1.200,7.190], [5.330,1.350,0.110]]), + (118, [[33.710,-147.840,866.620], [-7.310,-5.020,5.800], [3.020,-6.590,-1.880], [-0.710,0.240,-1.450], [4.500,0.350,5.980], [2.350,2.560,-6.780]]), + (119, [[33.450,-149.550,870.080], [6.660,-2.670,8.620], [1.910,-6.380,-3.460], [-0.810,0.030,-0.860], [5.650,3.480,-3.300], [0.800,2.080,-6.770]]), + (120, [[48.500,-149.860,877.560], [8.440,-1.400,10.880], [1.840,-6.880,-2.310], [-0.550,-0.390,1.170], [5.590,2.820,-3.970], [-1.370,-2.160,5.890]]), + (121, [[49.170,-151.340,885.880], [-14.130,-2.760,6.710], [0.940,-7.250,-1.010], [-0.570,0.330,-0.410], [3.260,-0.510,6.640], [-3.090,-3.470,6.170]]), + (122, [[30.330,-151.820,877.700], [-17.160,1.530,-4.960], [0.920,-5.490,-4.890], [-1.510,-0.140,0.400], [-1.940,-4.930,5.180], [0.640,-0.130,0.130]]), + (123, [[16.360,-149.060,875.570], [-10.970,1.710,5.380], [-1.800,-6.980,-1.460], [-0.540,-0.730,1.970], [2.830,-2.080,6.450], [2.860,1.800,-0.060]]), + (124, [[11.690,-148.720,883.920], [-10.140,1.000,8.830], [-0.940,-7.280,-0.260], [0.660,-0.150,1.090], [4.710,-0.800,5.500], [-0.400,1.320,0.040]]), + (125, [[-3.830,-146.990,890.110], [-14.280,1.090,0.550], [-0.520,-7.220,0.830], [0.360,0.010,-0.260], [0.340,0.810,7.240], [-1.670,-0.060,0.660]]), + (126, [[-14.790,-146.520,886.710], [-10.850,0.220,0.510], [-0.160,-7.240,-0.380], [0.730,0.030,-0.300], [0.330,-0.390,7.230], [2.180,0.020,-0.940]]), + (127, [[-23.910,-146.550,890.530], [-7.400,-0.950,6.580], [0.980,-7.160,0.070], [-0.520,0.100,0.630], [4.680,0.690,5.370], [0.750,0.450,-0.150]]), + (128, [[-28.030,-148.180,898.370], [-13.610,2.900,3.800], [-1.230,-7.020,0.960], [-1.430,0.370,-0.840], [2.040,0.580,6.860], [-3.990,-0.650,0.170]]), + (129, [[-42.020,-140.320,889.270], [-9.930,7.700,-9.680], [-1.440,-6.120,-3.390], [0.840,-0.040,-0.890], [-5.330,-1.240,4.490], [-3.620,0.110,-4.100]]), + (130, [[-47.830,-133.820,880.590], [1.670,2.810,-9.020], [0.190,-6.800,-2.080], [0.020,-0.240,2.820], [-6.870,0.170,-1.220], [2.630,-0.650,-5.170]]), + (131, [[-43.360,-134.640,876.970], [7.370,-1.120,-1.770], [-0.610,-6.830,1.800], [-0.490,-0.090,1.490], [-1.840,-1.590,-6.650], [3.370,-0.420,-3.090]]), + (132, [[-34.800,-135.760,878.370], [7.330,-0.800,-0.160], [-0.760,-7.020,0.280], [-0.510,0.020,-0.710], [-0.180,-0.260,-7.060], [-2.440,1.360,1.660]]), + (133, [[-29.320,-136.240,877.180], [3.390,-0.800,-5.310], [-1.570,-6.870,0.040], [-0.230,0.050,0.030], [-5.670,1.270,-3.820], [-3.220,0.720,3.410]]), + (134, [[-30.610,-136.870,870.770], [-0.250,-0.250,-5.290], [-1.190,-6.910,0.380], [0.280,-0.030,-0.030], [-6.790,1.180,0.270], [0.350,-0.330,-1.210]]), + (135, [[-30.230,-136.860,867.080], [2.790,-0.450,-3.890], [-0.940,-6.950,0.140], [0.330,-0.030,-0.120], [-5.570,0.670,-4.070], [3.300,-0.630,-3.480]]), + (136, [[-25.370,-137.760,865.060], [8.760,-0.500,1.850], [-0.440,-6.980,0.180], [0.240,0.000,-0.170], [1.430,-0.270,-6.840], [3.730,-0.350,-1.770]]), + (137, [[-17.010,-136.930,873.250], [9.540,-0.880,-1.350], [-0.710,-6.910,-0.470], [-0.790,0.170,0.250], [-0.920,0.560,-6.870], [-3.990,0.940,2.860]]), + (138, [[-14.620,-138.100,867.370], [2.470,-1.150,-8.780], [-1.880,-6.660,0.340], [1.250,0.410,-0.040], [-6.320,1.680,-1.990], [-1.180,0.210,1.020]]), + (139, [[-13.210,-138.670,858.260], [15.020,8.840,-1.860], [3.370,-5.940,-1.020], [3.020,0.320,-0.460], [-1.140,0.510,-6.800], [4.300,-0.760,-2.960]]), + (140, [[-2.010,-129.090,875.920], [14.730,5.570,5.540], [2.300,-6.430,0.360], [-3.380,0.090,1.420], [2.260,0.450,-6.450], [-4.260,0.280,1.850]]), + (141, [[5.710,-128.310,873.450], [4.220,-3.800,-6.920], [-2.330,-6.100,1.930], [1.540,1.120,0.790], [-5.490,0.890,-3.830], [-2.900,-1.920,4.890]]), + (142, [[3.860,-133.450,867.510], [-1.780,-5.980,-7.590], [4.850,-4.160,2.140], [1.960,0.650,1.010], [-4.520,-3.360,3.710], [0.300,-2.100,1.250]]), + (143, [[2.440,-139.690,858.800], [7.020,-5.190,-6.230], [0.110,-5.150,4.400], [-1.690,-0.890,0.210], [-5.060,-2.920,-3.280], [2.220,0.250,-4.490]]), + (144, [[11.980,-140.150,859.350], [17.700,2.250,-1.140], [0.950,-6.060,2.790], [1.390,-0.390,-2.080], [-0.040,-2.820,-6.130], [2.190,0.110,-1.390]]), + (145, [[35.300,-132.990,854.910], [8.740,9.550,-15.220], [4.050,-5.230,-0.960], [0.820,0.890,-2.820], [-4.430,-2.650,-4.200], [-1.330,-1.300,4.050]]), + (146, [[29.930,-128.550,843.920], [-12.950,5.120,-19.360], [3.680,-4.210,-3.570], [-1.410,0.000,-0.870], [-4.190,-4.930,1.490], [1.700,-0.300,5.110]]), + (147, [[9.390,-125.790,820.060], [-27.750,1.440,5.840], [-0.470,-6.580,-0.630], [-1.270,-0.920,1.780], [1.320,-0.720,6.460], [4.740,2.190,-0.360]]), + (148, [[4.650,-126.740,840.920], [-6.020,1.180,15.730], [0.130,-6.590,0.550], [-0.730,0.090,0.190], [6.110,0.310,2.320], [-2.110,0.210,1.570]]), + (149, [[0.040,-125.010,849.260], [-9.240,1.850,1.000], [-1.260,-6.450,0.320], [0.680,0.070,-0.540], [0.750,0.180,6.550], [-5.740,-0.820,-0.600]]), + (150, [[-4.440,-124.790,843.150], [-5.020,0.460,-16.660], [1.260,-6.430,-0.560], [1.980,0.080,-0.420], [-6.090,-1.340,1.790], [-4.270,-1.020,-2.570]]), + (151, [[-4.100,-124.240,817.800], [-14.820,-5.980,-12.690], [2.230,-6.130,0.290], [-0.080,-0.020,0.180], [-3.880,-1.170,5.070], [6.330,1.590,-0.020]]), + (152, [[-13.820,-128.400,823.840], [-7.490,-1.580,13.510], [1.550,-6.330,0.120], [-0.550,0.000,0.710], [5.490,1.400,3.200], [4.920,1.220,-2.010]]), + (153, [[-15.540,-126.400,839.810], [-2.260,3.630,12.780], [1.060,-6.110,1.920], [-1.860,0.050,-0.360], [6.210,1.310,0.730], [-0.950,-1.430,1.430]]), + (154, [[-17.860,-122.190,848.910], [-6.970,2.290,6.400], [-1.900,-6.170,0.140], [0.210,-0.110,-0.730], [4.060,-1.150,4.850], [-5.500,-0.820,1.290]]), + (155, [[-24.460,-122.950,849.040], [-11.050,-2.260,-14.690], [1.030,-6.350,0.200], [1.600,-0.050,0.470], [-5.050,-0.700,3.900], [-6.400,0.950,-0.750]]), + (156, [[-23.980,-124.710,821.700], [-13.900,-3.450,-17.210], [-1.090,-5.980,2.080], [-0.110,-0.110,-0.760], [-4.880,2.110,3.530], [5.050,-0.430,0.870]]), + (157, [[-38.600,-127.220,820.180], [-12.580,-0.430,8.780], [-0.020,-6.390,-0.330], [-0.170,-0.020,-0.170], [3.670,-0.290,5.240], [4.860,-1.540,-2.070]]), + (158, [[-42.520,-125.650,832.780], [1.330,2.910,14.250], [-1.250,-6.100,1.370], [-0.030,0.210,1.190], [6.110,-1.310,-0.300], [1.080,-0.260,-3.490]]), + (159, [[-35.800,-121.920,845.730], [4.200,3.780,10.200], [0.010,-5.960,2.200], [-0.160,0.230,0.570], [5.880,-0.780,-2.130], [0.090,0.030,0.690]]), + (160, [[-33.620,-118.720,852.840], [0.500,3.010,6.470], [-0.930,-5.650,2.700], [-0.790,-0.030,-0.570], [6.150,-1.010,0.000], [-0.330,-0.030,2.500]]), + (161, [[-34.440,-116.110,858.280], [-2.640,1.810,5.040], [-1.710,-5.940,1.230], [0.580,-0.290,-1.410], [5.320,-0.890,3.110], [-1.830,0.370,2.710]]), + (162, [[-38.380,-115.330,862.170], [-6.050,-0.340,2.350], [0.220,-6.280,-0.340], [1.370,-0.090,-0.250], [2.280,-0.240,5.850], [-4.210,0.450,0.940]]), + (163, [[-44.500,-116.930,861.580], [-11.590,-3.810,-10.160], [1.110,-6.090,1.020], [0.440,0.120,0.610], [-4.130,0.030,4.700], [-4.540,0.050,-0.790]]), + (164, [[-51.780,-120.720,839.030], [-15.880,-5.450,-10.360], [1.830,-5.970,0.320], [-1.360,0.270,0.870], [-3.220,-0.700,5.310], [4.290,0.490,0.090]]), + (165, [[-64.650,-124.350,841.480], [-11.510,0.420,9.850], [0.150,-6.190,0.440], [-0.550,0.330,1.540], [3.970,0.430,4.630], [4.380,-0.520,-2.900]]), + (166, [[-69.370,-119.950,854.330], [5.110,4.210,16.620], [-1.330,-5.740,1.870], [0.690,0.270,0.730], [5.670,-1.740,-1.310], [0.560,-1.580,-4.180]]), + (167, [[-55.630,-118.570,867.170], [8.190,15.700,8.570], [-2.415,-2.636,3.160], [0.890,1.630,1.440], [4.280,-1.310,-1.700], [0.130,0.200,0.140]]), + (168, [[-52.380,-100.900,869.760], [4.760,24.010,12.610], [-3.169,0.219,3.447], [-0.280,-0.300,-1.610], [4.600,-0.510,-0.770], [-2.290,1.100,4.280]]), + (169, [[-41.730,-76.290,892.900], [-14.020,14.240,19.650], [-3.750,-3.589,-1.622], [3.240,-2.890,0.750], [1.930,-2.620,3.270], [-5.090,5.860,6.610]]), + (170, [[-60.630,-80.530,895.250], [-6.170,-10.100,-5.870], [2.660,0.730,-4.050], [2.380,0.990,-1.140], [3.310,-2.970,1.640], [2.380,0.990,-1.140]]),# cecum + (171, [[-68.640,-93.290,888.060], [-9.850,-15.420,-8.510], [3.880,1.200,-6.660], [2.380,0.990,-1.140], [2.820,-2.460,1.200], [2.380,0.990,-1.140]]), + (172, [[-80.390,-111.370,878.290], [[-7.790,-0.980,12.360],[-13.650,-20.740,-11.030]], [[20.720,-4.040,12.540],[5.590,1.310,-9.380]], [[2.380,0.990,-1.140],[2.380,0.990,-1.140]], [[2.470,23.830,3.610],[1.510,-1.370,0.710]], [[2.380,0.990,-1.140],[2.380,0.990,-1.140]]]), + (173, [[-71.690,-109.000,866.040], [-9.550,-3.730,12.060], [17.410,-4.850,11.460], [3.730,0.680,4.200], [0.820,19.940,7.200], [3.740,0.690,4.200]]), + (174, [[-87.210,-111.060,890.540], [-4.750,0.410,12.390], [23.270,-3.130,7.880], [2.460,-0.390,-2.950], [3.090,24.460,0.450], [1.830,0.460,-4.310]]),# colon + (175, [[-89.990,-110.570,902.650], [-2.050,0.530,12.720], [24.710,-3.280,4.130], [0.070,0.140,-2.810], [3.420,25.000,-0.640], [0.430,0.100,-3.970]]), + (176, [[-91.250,-110.010,915.920], [-0.550,0.530,13.390], [23.610,-2.820,1.080], [-1.460,0.550,-1.920], [2.850,23.610,-0.910], [-1.420,0.540,-2.130]]), + (177, [[-91.080,-109.520,929.390], [0.130,0.650,13.470], [21.830,-2.100,-0.100], [-0.530,0.220,-1.060], [2.080,21.810,-1.180], [-0.530,0.210,-1.170]]), + (178, [[-91.000,-108.720,942.850], [0.830,0.670,13.370], [22.560,-2.350,-1.280], [-0.880,0.270,-1.850], [2.290,22.560,-1.420], [-0.920,0.270,-2.030]]), + (179, [[-89.430,-108.180,956.080], [2.810,0.320,13.110], [20.050,-1.510,-4.270], [-1.960,0.620,-1.350], [1.380,20.440,-0.860], [-2.000,0.620,-1.490]]), + (180, [[-85.390,-108.090,968.920], [3.100,0.440,13.080], [18.600,-0.990,-4.380], [-0.760,0.320,0.660], [0.820,19.040,-0.910], [-0.730,0.310,0.710]]), + (181, [[-83.240,-107.300,982.140], [2.050,0.850,13.230], [18.550,-0.800,-2.820], [-0.240,0.090,0.570], [0.620,18.710,-1.440], [-0.210,0.080,0.630]]), + (182, [[-81.290,-106.400,995.370], [2.320,1.340,13.290], [18.150,-0.790,-3.100], [0.140,0.240,-0.110], [0.470,18.290,-2.130], [0.050,0.310,-0.570]]), + (183, [[-78.600,-104.620,1008.650], [2.140,-1.500,13.270], [18.840,-0.250,-3.070], [-0.910,1.850,-0.220], [0.840,18.750,3.430], [-0.950,1.980,-0.150]]), + (184, [[-77.170,-109.180,1020.820], [4.070,-9.070,9.680], [16.310,3.440,-3.630], [-2.150,4.060,0.800], [-0.010,12.030,12.600], [-1.970,3.890,1.430]]), + (185, [[-71.190,-121.030,1025.580], [7.480,-11.420,0.490], [14.200,9.260,-1.140], [-1.270,2.690,3.170], [0.000,1.980,17.640], [-1.270,2.720,3.230]]), + (186, [[-63.350,-130.560,1022.180], [7.990,-9.440,-3.400], [13.310,9.970,3.600], [-0.810,0.700,2.420], [0.000,-5.470,16.790], [-0.910,0.850,2.430]]), + (187, [[-55.270,-139.840,1018.800], [8.880,-8.590,-3.550], [12.320,10.870,4.490], [-1.070,0.870,0.810], [0.000,-6.180,16.540], [-1.090,0.870,0.810]]), + (188, [[-45.660,-147.660,1015.100], [9.900,-7.390,-3.360], [10.810,11.990,5.470], [-1.630,1.380,0.030], [-0.010,-6.690,16.290], [-1.620,1.360,0.020]]), + (189, [[-35.520,-154.600,1012.080], [11.080,-6.080,-1.980], [8.540,14.060,4.580], [-1.990,1.150,0.250], [-0.010,-5.000,17.000], [-1.970,1.130,0.240]]), + (190, [[-23.710,-159.680,1011.200], [11.970,-4.320,-1.790], [6.200,14.650,6.070], [-1.740,-0.440,2.510], [0.010,-6.170,16.490], [-1.790,-0.440,2.520]]), + (191, [[-11.720,-163.200,1008.530], [12.260,-2.580,-2.060], [4.480,13.030,10.390], [-2.160,-0.110,1.440], [-0.010,-10.220,14.200], [-2.140,-0.120,1.430]]), + (192, [[0.670,-164.820,1007.100], [12.710,-0.730,-0.480], [1.180,14.350,9.430], [-2.670,0.760,-0.810], [-0.010,-8.950,15.090], [-2.580,0.750,-0.810]]), + (193, [[13.556,-164.739,1007.051], [12.750,0.980,0.850], [-1.700,14.800,8.530], [-1.750,0.420,-1.040], [-0.320,-8.140,15.580], [-1.710,0.430,-1.040]]), + (194, [[26.116,-162.906,1008.217], [12.630,1.810,1.230], [-2.890,15.320,7.020], [-2.260,-0.160,-1.140], [-0.450,-6.810,16.270], [-2.230,-0.140,-1.140]]), + (195, [[38.730,-161.010,1010.040], [11.760,4.530,2.770], [-6.960,14.450,5.880], [-3.080,-0.420,-3.340], [-0.980,-6.490,16.380], [-3.120,-0.440,-3.350]]), + (196, [[50.563,-154.087,1013.645], [9.860,7.100,4.160], [-9.105,10.240,0.863], [-1.930,-0.520,-2.090], [-4.770,-2.540,17.360], [-1.970,-0.530,-2.090]]), + (197, [[58.745,-146.870,1017.469], [9.340,7.750,4.350], [-9.097,10.778,0.486], [-1.820,-1.100,1.290], [-3.670,-4.330,17.260], [-1.800,-1.060,1.300]]), + (198, [[67.501,-138.309,1022.249], [7.990,8.770,4.670], [-10.568,9.341,0.117], [-2.500,-1.970,-0.340], [-2.610,-6.250,17.940], [-2.590,-2.160,-0.410]]), + (199, [[74.433,-129.298,1027.145], [5.080,9.970,3.830], [-13.880,7.949,-1.165], [0.030,-2.060,0.330], [-2.126,-4.930,16.625], [-1.530,-1.170,0.490]]), + (200, [[77.560,-119.250,1030.430], [5.040,10.780,-0.510], [-14.630,6.980,2.780], [0.100,1.230,-1.770], [4.280,1.140,20.240], [0.400,1.970,-2.970]]), + (201, [[83.860,-109.530,1026.210], [6.930,6.510,-9.450], [-16.870,11.640,-4.350], [-2.810,1.300,-3.770], [7.220,14.780,13.520], [-1.240,0.300,-4.600]]), + (202, [[89.550,-108.420,1013.560], [3.910,0.860,-13.160], [-20.290,9.170,-5.430], [-1.850,-1.680,0.870], [8.380,20.860,4.280], [-2.140,-1.950,1.170]]), + (203, [[91.640,-107.830,1000.370], [1.780,0.550,-13.270], [-20.930,7.770,-2.480], [-0.800,-1.120,1.760], [7.590,21.030,2.070], [-0.860,-1.120,1.920]]), + (204, [[93.100,-107.330,987.040], [1.010,0.300,-13.420], [-22.050,6.680,-1.510], [-0.560,-0.650,1.350], [6.630,22.100,1.090], [-0.580,-0.660,1.490]]), + (205, [[93.660,-107.240,973.550], [-0.020,1.050,-13.410], [-22.120,6.280,0.520], [0.930,-2.250,1.330], [6.310,22.050,1.910], [0.920,-2.270,1.470]]), + (206, [[93.060,-105.250,960.320], [-0.770,2.250,-13.200], [-20.310,1.700,1.470], [0.920,-2.340,0.150], [1.920,20.030,3.650], [0.930,-2.360,0.170]]), + (207, [[92.120,-102.740,947.160], [-0.420,2.820,-13.160], [-20.350,1.100,0.880], [0.740,-0.110,-0.850], [1.250,19.860,4.690], [0.730,-0.090,-0.940]]), + (208, [[92.230,-99.620,934.040], [0.470,1.780,-13.240], [-18.820,1.460,-0.470], [1.010,0.010,-1.140], [1.390,18.640,2.850], [1.030,0.020,-1.270]]), + (209, [[93.040,-99.170,920.860], [1.210,-0.740,-13.330], [-18.310,1.150,-1.730], [0.280,-0.610,0.540], [1.230,18.350,-1.000], [0.280,-0.690,-0.020]]), + (210, [[94.650,-101.120,907.560], [-0.610,-1.620,-13.470], [-18.270,0.060,0.820], [-0.210,-1.550,3.280], [-0.050,18.160,-2.300], [-0.490,-1.710,2.070]]), + (211, [[91.840,-102.350,894.350], [-3.470,-1.640,-11.950], [-18.620,-2.390,5.740], [0.910,-2.200,3.650], [-3.000,19.300,-1.810], [-0.730,-2.580,3.870]]), + (212, [[87.880,-104.310,883.750], [-5.210,-2.130,-10.320], [-16.280,-4.940,9.250], [2.730,-2.870,2.500], [-6.690,20.720,-1.110], [0.460,-3.190,4.530]]), + (213, [[81.450,-106.590,873.900], [-6.990,-2.140,-9.270], [-12.430,-8.970,11.450], [0.330,-3.150,2.690], [-6.303,19.245,1.555], [2.230,-2.670,3.370]]), + (214, [[73.980,-108.570,865.270], [-8.310,-0.220,-8.520], [-12.268,-8.435,13.125], [-1.280,-1.760,1.510], [-6.633,18.953,4.087], [3.180,-1.460,2.050]]), + (215, [[65.060,-106.920,857.150], [-8.970,1.810,-7.690], [-14.794,-6.343,11.919], [1.280,0.430,-0.090], [-4.396,19.311,7.084], [2.480,0.160,0.520]]), + (216, [[56.070,-104.970,849.910], [-10.000,1.920,-6.880], [-14.078,-6.138,12.772], [2.490,5.000,1.790], [0.172,16.517,6.181], [2.280,4.690,1.100]]), + (217, [[45.110,-103.120,843.530], [-11.000,4.810,-5.260], [-9.460,-1.100,18.780], [2.560,4.660,2.880], [6.930,18.410,4.840], [2.420,4.350,0.870]]), + (218, [[34.860,-95.590,839.810], [-9.590,8.680,-2.670], [-6.610,-0.760,21.270], [0.940,-0.410,0.560], [12.620,13.250,3.920], [0.000,0.160,-0.540]]), + (219, [[26.140,-85.990,838.230], [-8.260,10.160,-2.000], [-7.290,-2.000,20.040], [-0.320,-0.120,-0.850], [14.710,10.710,6.320], [-1.050,-0.470,0.410]]), + (220, [[18.390,-75.310,835.820], [-8.420,10.080,-2.660], [-7.370,-0.990,19.530], [-0.560,0.610,0.800], [16.030,10.170,6.780], [-0.360,-0.280,1.590]]), + (221, [[9.350,-65.880,832.920], [-11.900,13.240,-4.280], [-8.470,-0.620,21.630], [-0.850,0.480,1.280], [17.760,11.500,7.330], [-1.390,-0.780,1.040]]), + (222, [[-5.120,-48.680,827.110], [-17.030,21.160,-7.340], [-8.980,0.200,21.430], [-0.080,1.010,-1.640], [17.760,11.500,7.330], [-1.390,-0.780,1.040]]) + ] ), + + 'userAnnotationGroups': [ + { + '_AnnotationGroup': True, + 'dimension': 1, + 'identifierRanges': '1-4', + 'name': get_esophagus_term('esophagus')[0], + 'ontId': get_esophagus_term('esophagus')[1] + }, + { + '_AnnotationGroup': True, + 'dimension': 1, + 'identifierRanges': '1', + 'name': get_esophagus_term('cervical part of esophagus')[0], + 'ontId': get_esophagus_term('cervical part of esophagus')[1] + }, + { + '_AnnotationGroup': True, + 'dimension': 1, + 'identifierRanges': '2-3', + 'name': get_esophagus_term('thoracic part of esophagus')[0], + 'ontId': get_esophagus_term('thoracic part of esophagus')[1] + }, + { + '_AnnotationGroup': True, + 'dimension': 1, + 'identifierRanges': '4', + 'name': get_esophagus_term('abdominal part of esophagus')[0], + 'ontId': get_esophagus_term('abdominal part of esophagus')[1] + }, + { + '_AnnotationGroup': True, + 'dimension': 1, + 'identifierRanges': '5-18', + 'name': get_stomach_term('stomach')[0], + 'ontId': get_stomach_term('stomach')[1] + }, + { + '_AnnotationGroup': True, + 'dimension': 1, + 'identifierRanges': '5-6', + 'name': get_stomach_term('esophagus part of stomach')[0], + 'ontId': get_stomach_term('esophagus part of stomach')[1] + }, + { + '_AnnotationGroup': True, + 'dimension': 1, + 'identifierRanges': '7-10', + 'name': get_stomach_term('fundus of stomach')[0], + 'ontId': get_stomach_term('fundus of stomach')[1] + }, + { + '_AnnotationGroup': True, + 'dimension': 1, + 'identifierRanges': '11-14', + 'name': get_stomach_term('body of stomach')[0], + 'ontId': get_stomach_term('body of stomach')[1] + }, + { + '_AnnotationGroup': True, + 'dimension': 1, + 'identifierRanges': '15-16', + 'name': get_stomach_term('pyloric antrum')[0], + 'ontId': get_stomach_term('pyloric antrum')[1] + }, + { + '_AnnotationGroup': True, + 'dimension': 1, + 'identifierRanges': '17', + 'name': get_stomach_term('pyloric canal')[0], + 'ontId': get_stomach_term('pyloric canal')[1] + }, + { + '_AnnotationGroup': True, + 'dimension': 1, + 'identifierRanges': '18', + 'name': get_stomach_term('duodenum part of stomach')[0], + 'ontId': get_stomach_term('duodenum part of stomach')[1] + }, + { + '_AnnotationGroup': True, + 'dimension': 1, + 'identifierRanges': '19-169', + 'name': get_smallintestine_term('small intestine')[0], + 'ontId': get_smallintestine_term('small intestine')[1] + }, + { + '_AnnotationGroup': True, + 'dimension': 1, + 'identifierRanges': '19-23', + 'name': get_smallintestine_term('duodenum')[0], + 'ontId': get_smallintestine_term('duodenum')[1] + }, + { + '_AnnotationGroup': True, + 'dimension': 1, + 'identifierRanges': '24-100', + 'name': get_smallintestine_term('jejunum')[0], + 'ontId': get_smallintestine_term('jejunum')[1] + }, + { + '_AnnotationGroup': True, + 'dimension': 1, + 'identifierRanges': '101-169', + 'name': get_smallintestine_term('ileum')[0], + 'ontId': get_smallintestine_term('ileum')[1] + }, + { + '_AnnotationGroup': True, + 'dimension': 1, + 'identifierRanges': '170-173', + 'name': get_cecum_term('caecum')[0], + 'ontId': get_cecum_term('caecum')[1] + }, + { + '_AnnotationGroup': True, + 'dimension': 1, + 'identifierRanges': '170-171', + 'name': get_cecum_term('ileum part of cecum')[0], + 'ontId': get_cecum_term('ileum part of cecum')[1] + }, + { + '_AnnotationGroup': True, + 'dimension': 1, + 'identifierRanges': '174-221', + 'name': get_colon_term('colon')[0], + 'ontId': get_colon_term('colon')[1] + }, + { + '_AnnotationGroup': True, + 'dimension': 1, + 'identifierRanges': '174-184', + 'name': get_colon_term('ascending colon')[0], + 'ontId': get_colon_term('ascending colon')[1] + }, + { + '_AnnotationGroup': True, + 'dimension': 1, + 'identifierRanges': '185-199', + 'name': get_colon_term('transverse colon')[0], + 'ontId': get_colon_term('transverse colon')[1] + }, + { + '_AnnotationGroup': True, + 'dimension': 1, + 'identifierRanges': '200-222', + 'name': get_colon_term('descending colon')[0], + 'ontId': get_colon_term('descending colon')[1] + }] + }) + } + + @staticmethod + def getName(): + return '3D Gastrointestinal Tract 1' + + @staticmethod + def getParameterSetNames(): + return [ + 'Default', + 'Human 1'] + + @classmethod + def getDefaultOptions(cls, parameterSetName='Default'): + centralPathOption = cls.parameterSetStructureStrings['Human 1'] + esophagusOption = ScaffoldPackage(MeshType_3d_esophagus1, defaultParameterSetName='Human 1') + stomachOption = ScaffoldPackage(MeshType_3d_stomach1, defaultParameterSetName='Human 2') + smallIntestineOption = ScaffoldPackage(MeshType_3d_smallintestine1, defaultParameterSetName='Human 1') + cecumOption = ScaffoldPackage(MeshType_3d_cecum1, defaultParameterSetName='Human 2') + colonOption = ScaffoldPackage(MeshType_3d_colon1, defaultParameterSetName='Human 3') + options = {'Central path': copy.deepcopy(centralPathOption), + 'Esophagus': esophagusOption, + 'Stomach': stomachOption, + 'Small intestine': smallIntestineOption, + 'Cecum': cecumOption, + 'Colon': colonOption, + 'Use linear through wall': True, + 'Refine': False, + 'Refine number of elements surface': 4, + 'Refine number of elements through wall': 1 + } + + return options + + @staticmethod + def getOrderedOptionNames(): + return [ + 'Central path', + 'Esophagus', + 'Stomach', + 'Small intestine', + 'Cecum', + 'Colon', + 'Use linear through wall', + 'Refine', + 'Refine number of elements surface', + 'Refine number of elements through wall'] + + @classmethod + def getOptionValidScaffoldTypes(cls, optionName): + if optionName == 'Central path': + return [MeshType_1d_network_layout1] + if optionName == 'Esophagus': + return [MeshType_3d_esophagus1] + if optionName == 'Stomach': + return [MeshType_3d_stomach1] + if optionName == 'Small intestine': + return [MeshType_3d_smallintestine1] + if optionName == 'Cecum': + return [MeshType_3d_cecum1] + if optionName == 'Colon': + return [MeshType_3d_colon1] + return [] + + @classmethod + def getOptionScaffoldTypeParameterSetNames(cls, optionName, scaffoldType): + if optionName == 'Central path': + return list(cls.parameterSetStructureStrings.keys()) + assert scaffoldType in cls.getOptionValidScaffoldTypes(optionName), \ + cls.__name__ + '.getOptionScaffoldTypeParameterSetNames. ' + \ + 'Invalid option \'' + optionName + '\' scaffold type ' + scaffoldType.getName() + return scaffoldType.getParameterSetNames() + + @classmethod + def getOptionScaffoldPackage(cls, optionName, scaffoldType, parameterSetName=None): + ''' + :param parameterSetName: Name of valid parameter set for option Scaffold, or None for default. + :return: ScaffoldPackage. + ''' + if parameterSetName: + assert parameterSetName in cls.getOptionScaffoldTypeParameterSetNames(optionName, scaffoldType), \ + 'Invalid parameter set ' + str(parameterSetName) + ' for scaffold ' + str(scaffoldType.getName()) + \ + ' in option ' + str(optionName) + ' of scaffold ' + cls.getName() + if optionName == 'Central path': + if not parameterSetName: + parameterSetName = list(cls.parameterSetStructureStrings.keys())[0] + return copy.deepcopy(cls.parameterSetStructureStrings[parameterSetName]) + if optionName == 'Esophagus': + if not parameterSetName: + parameterSetName = scaffoldType.getParameterSetNames()[0] + return ScaffoldPackage(scaffoldType, defaultParameterSetName=parameterSetName) + if optionName == 'Stomach': + if not parameterSetName: + parameterSetName = scaffoldType.getParameterSetNames()[0] + return ScaffoldPackage(scaffoldType, defaultParameterSetName=parameterSetName) + if optionName == 'Small intestine': + if not parameterSetName: + parameterSetName = scaffoldType.getParameterSetNames()[0] + return ScaffoldPackage(scaffoldType, defaultParameterSetName=parameterSetName) + if optionName == 'Cecum': + if not parameterSetName: + parameterSetName = scaffoldType.getParameterSetNames()[0] + return ScaffoldPackage(scaffoldType, defaultParameterSetName=parameterSetName) + if optionName == 'Colon': + if not parameterSetName: + parameterSetName = scaffoldType.getParameterSetNames()[0] + return ScaffoldPackage(scaffoldType, defaultParameterSetName=parameterSetName) + assert False, cls.__name__ + '.getOptionScaffoldPackage: Option ' + optionName + ' is not a scaffold' + + @classmethod + def checkOptions(cls, options): + if not options['Central path'].getScaffoldType() in cls.getOptionValidScaffoldTypes('Central path'): + options['Central path'] = cls.getOptionScaffoldPackage('Central path', MeshType_1d_network_layout1) + if not options['Esophagus'].getScaffoldType() in cls.getOptionValidScaffoldTypes('Esophagus'): + options['Esophagus'] = cls.getOptionScaffoldPackage('Esophagus', MeshType_3d_stomach1) + if not options['Stomach'].getScaffoldType() in cls.getOptionValidScaffoldTypes('Stomach'): + options['Stomach'] = cls.getOptionScaffoldPackage('Stomach', MeshType_3d_stomach1) + if not options['Small intestine'].getScaffoldType() in cls.getOptionValidScaffoldTypes('Small intestine'): + options['Small intestine'] = cls.getOptionScaffoldPackage('Small intestine', MeshType_3d_smallintestine1) + if not options['Cecum'].getScaffoldType() in cls.getOptionValidScaffoldTypes('Cecum'): + options['Cecum'] = cls.getOptionScaffoldPackage('Cecum', MeshType_3d_cecum1) + if not options['Colon'].getScaffoldType() in cls.getOptionValidScaffoldTypes('Colon'): + options['Colon'] = cls.getOptionScaffoldPackage('Colon', MeshType_3d_colon1) + for key in [ + 'Refine number of elements surface', + 'Refine number of elements through wall']: + if options[key] < 1: + options[key] = 1 + + # cls.updateSubScaffoldOptions(options) + + @classmethod + def generateBaseMesh(cls, region, options): + """ + Generate the base tricubic Hermite mesh. + :param region: Zinc region to define model in. Must be empty. + :param options: Dict containing options. See getDefaultOptions(). + :return: annotationGroups + """ + centralPath = options['Central path'] + esophagusOptions = options['Esophagus'] + stomachOptions = options['Stomach'] + smallIntestineOptions = options['Small intestine'] + cecumOptions = options['Cecum'] + colonOptions = options['Colon'] + esophagusSettings = esophagusOptions.getScaffoldSettings() + stomachSettings = stomachOptions.getScaffoldSettings() + smallIntestineSettings = smallIntestineOptions.getScaffoldSettings() + cecumSettings = cecumOptions.getScaffoldSettings() + colonSettings = colonOptions.getScaffoldSettings() + + esophagusSettings['Use linear through wall'] = options['Use linear through wall'] + stomachSettings['Use linear through wall'] = options['Use linear through wall'] + smallIntestineSettings['Use linear through wall'] = options['Use linear through wall'] + cecumSettings['Use linear through wall'] = options['Use linear through wall'] + colonSettings['Use linear through wall'] = options['Use linear through wall'] + + nextNodeIdentifier = 1 + nextElementIdentifier = 1 + + tmpRegion = region.createRegion() + centralPath.generate(tmpRegion) + + # Central path + gastroTermsAlong = [['esophagus', 'cervical part of esophagus', 'thoracic part of esophagus', + 'abdominal part of esophagus'], + ['stomach', 'fundus of stomach', 'body of stomach', 'pyloric antrum', 'pyloric canal', + 'duodenum part of stomach', 'esophagus part of stomach'], + ['small intestine', 'duodenum', 'jejunum', 'ileum'], + ['caecum', 'ileum part of cecum'], + ['colon', 'ascending colon', 'transverse colon', 'descending colon']] + + for section in range(len(gastroTermsAlong)): + fm = region.getFieldmodule() + coordinates = findOrCreateFieldCoordinates(fm) + allAnnotationGroups = [] + + if gastroTermsAlong[section][0] == 'esophagus': + esoCentralPath = EsophagusCentralPath(region, centralPath, gastroTermsAlong[section]) + annotationGroupsEsophagus, nextNodeIdentifier, nextElementIdentifier, nodesIdEsoDistal,\ + xEsoDistal, d1EsoDistal, d2EsoDistal, d3EsoDistal = \ + createEsophagusMesh3d(region, esophagusSettings, esoCentralPath, nextNodeIdentifier, + nextElementIdentifier) + + elif gastroTermsAlong[section][0] == 'stomach': + stomachCentralPath = StomachCentralPath(region, centralPath, gastroTermsAlong[section], esoSegmentIdx=0, + stomachSegmentIdx=[1,2]) + annotationGroupsStomach, nextNodeIdentifier, nextElementIdentifier, _, nodesIdStomachDistal,\ + xStomachDistal, d1StomachDistal, d2StomachDistal, d3StomachDistal, arclengthCPStomachDistal, xPrev, \ + d2Prev = \ + createStomachMesh3d(region, fm, coordinates, gastroTermsAlong[section], + allAnnotationGroups, stomachCentralPath, + options=stomachSettings, nodeIdentifier=nextNodeIdentifier, + elementIdentifier=nextElementIdentifier, + nodeIdProximalEso=nodesIdEsoDistal, xProximalEso=xEsoDistal, + d1ProximalEso=d1EsoDistal, d2ProximalEso=d2EsoDistal, d3ProximalEso=d3EsoDistal) + nearLCGroup = getAnnotationGroupForTerm(annotationGroupsStomach, + ("elements adjacent to lesser curvature", "None")) + annotationGroupsStomach.remove(nearLCGroup) + + elif gastroTermsAlong[section][0] == 'small intestine': + smallIntestineCentralPath = SmallIntestineCentralPath(region, centralPath, gastroTermsAlong[section]) + + annotationGroupsSmallIntestine, nextNodeIdentifier, nextElementIdentifier, \ + nodesIdSmallIntestineDistal, xSmallIntestineDistal, d1SmallIntestineDistal, d2SmallIntestineDistal, \ + d3SmallIntestineDistal, xNext, d2Next = \ + createSmallIntestineMesh3d(region, smallIntestineSettings, smallIntestineCentralPath, + nextNodeIdentifier, nextElementIdentifier, + nodeIdProximal=nodesIdStomachDistal, xProximal=xStomachDistal, + d1Proximal=d1StomachDistal, d2Proximal=d2StomachDistal, + d3Proximal=d3StomachDistal, arclengthCPProximal=arclengthCPStomachDistal) + + # Smooth d2 at intersection between stomach and small intestine + cache = fm.createFieldcache() + nodes = fm.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES) + for n3 in range(len(nodesIdStomachDistal)): + for n in range(len(nodesIdStomachDistal[n3])): + newD2 = interp.smoothCubicHermiteDerivativesLine( + [xPrev[n3][n], xStomachDistal[n3][n], xNext[n3][n]], + [d2Prev[n3][n], d2StomachDistal[n3][n], d2Next[n3][n]], + fixStartDerivative=True, fixEndDerivative=True)[1] + + cache.setNode(nodes.findNodeByIdentifier(nodesIdStomachDistal[n3][n])) + coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, newD2) + + elif gastroTermsAlong[section][0] == 'caecum': + cecumCentralPath = CecumCentralPath(region, centralPath, gastroTermsAlong[section], + ileumSegmentIdx=2, cecumSegmentIdx=[3,4]) + annotationGroupsCecum, nextNodeIdentifier, nextElementIdentifier, nodesIdCecumDistal, \ + xCecumDistal, d1CecumDistal, d2CecumDistal, d3CecumDistal = \ + createCecumMesh3d(region, cecumSettings, cecumCentralPath, nextNodeIdentifier, + nextElementIdentifier, nodeIdProximalIleum=nodesIdSmallIntestineDistal, + xProximalIleum=xSmallIntestineDistal, d1ProximalIleum=d1SmallIntestineDistal, + d2ProximalIleum=d2SmallIntestineDistal, d3ProximalIleum=d3SmallIntestineDistal) + + elif gastroTermsAlong[section][0] == 'colon': + colonCentralPath = ColonCentralPath(region, centralPath, gastroTermsAlong[section]) + annotationGroupsColon, nextNodeIdentifier, nextElementIdentifier, \ + nodesIdColonDistal, xColonDistal, d1ColonDistal, d2ColonDistal, d3ColonDistal = \ + createColonMesh3d(region, colonSettings, colonCentralPath, nextNodeIdentifier, + nextElementIdentifier, nodeIdProximal=nodesIdCecumDistal, + xProximal=xCecumDistal, d1Proximal=d1CecumDistal, d2Proximal=d2CecumDistal, + d3Proximal=d3CecumDistal) + + del tmpRegion + + annotationGroups = mergeAnnotationGroups(annotationGroupsEsophagus, annotationGroupsStomach, + annotationGroupsSmallIntestine, annotationGroupsCecum, + annotationGroupsColon) + + return annotationGroups, None + + @classmethod + def refineMesh(cls, meshrefinement, options): + """ + Refine source mesh into separate region, with change of basis. + :param meshrefinement: MeshRefinement, which knows source and target region. + :param options: Dict containing options. See getDefaultOptions(). + """ + refineElementsCountAround = options['Refine number of elements surface'] + refineElementsCountAlong = options['Refine number of elements surface'] + refineElementsCountThroughWall = options['Refine number of elements through wall'] + + meshrefinement.refineAllElementsCubeStandard3d(refineElementsCountAround, refineElementsCountAlong, + refineElementsCountThroughWall) + return + +class SectionCentralPath: + """ + Generates sampled central path for GI Tract scaffold. + """ + def __init__(self, arcLengthOfGroupsAlong, cxGroups, cd1Groups, cd2Groups,cd3Groups, cd12Groups, cd13Groups): + """ + :param region: Zinc region to define model in. + :param centralPath: Central path subscaffold from meshtype_1d_path1 + :param stomachTermsAlong: Annotation terms along length of central path + """ + self.arcLengthOfGroupsAlong = arcLengthOfGroupsAlong + self.cxGroups = cxGroups + self.cd1Groups = cd1Groups + self.cd2Groups = cd2Groups + self.cd3Groups = cd3Groups + self.cd12Groups = cd12Groups + self.cd13Groups = cd13Groups diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_ostium2.py b/src/scaffoldmaker/meshtypes/meshtype_3d_ostium2.py index 22928a38..d661c3af 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_ostium2.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_ostium2.py @@ -272,8 +272,18 @@ def getOstiumElementsCountsAroundVessels(elementsCountAroundOstium, elementsCoun def generateOstiumMesh(region, options, trackSurface, centralPath, startNodeIdentifier=1, startElementIdentifier=1, + nodeIdProximal=[], xProximal=[], d1Proximal=[], d2Proximal=[], d3Proximal=[], vesselMeshGroups=None, ostiumMeshGroups=None, wallAnnotationGroups=None, coordinates=None): """ + Generates an ostium mesh in the region using a central path and parameter options. + :param region: Region to create elements in. + :param options: Parameter options for ostium scaffold. + :param trackSurface: Track surface for building ostium scaffold. + :param centralPath: Central path through the axis of the ostium scaffold. + :param startNodeIdentifier: First node identifier to use. + :param startElementIdentifier: First element identifier to use. + :param nodeIdProximal, xProximal, d1Proximal, d2Proximal, d3Proximal: Identifier, coordinates and derivatives of + nodes to use on proximal end of vessel. :param vesselMeshGroups: List (over number of vessels) of list of mesh groups to add vessel elements to. :param ostiumMeshGroups: List of mesh groups to add only row of elements at ostium end to. :param wallAnnotationGroups: list of annotation groups to add to wall elements. @@ -612,28 +622,34 @@ def generateOstiumMesh(region, options, trackSurface, centralPath, startNodeIden vod3.append([]) for n3 in range(elementsCountThroughWall + 1): - radius1 = vector.magnitude(centralPath.cd2Path[0]) - (1.0 - vesselWallThicknessXi3List[n3]) * vesselWallThickness - radius2 = vector.magnitude(centralPath.cd3Path[0]) - (1.0 - vesselWallThicknessXi3List[n3]) * vesselWallThickness - vAxis1 = vector.setMagnitude(centralPath.cd2Path[0], radius1) - vAxis2 = vector.setMagnitude(centralPath.cd3Path[0], radius2) - # print(centralPath.cd2Path[0], centralPath.cd3Path[0]) - # if vesselsCount == 1: - startRadians = 0.0 # 0.5 * math.pi - # else: - # startRadians = 0.5 * radiansPerElementVessel * elementsCountAcross - # if v == (vesselsCount - 1): - # startRadians -= math.pi - px, pd1 = sampleEllipsePoints(centralPath.cxPath[0], vAxis1, vAxis2, 0.0, 2.0 * math.pi, elementsCountAroundVessel) - del px[-1], pd1[-1] - - vox[-1].append(px) - vod1[-1].append(pd1) - vesselEndDerivative = vector.setMagnitude(centralPath.cd1Path[0], arcLength/elementsCountAlong) - vod2[-1].append([vesselEndDerivative] * elementsCountAroundVessel) # need to scale with bending? - if useCubicHermiteThroughVesselWall: - vod3[-1].append([vector.setMagnitude(vector.crossproduct3(d1, vesselEndDerivative), #cd1Path[-1]), - vesselWallThickness * vesselWallThicknessProportions[n3]) - for d1 in pd1]) + if xProximal: + vox[-1].append(xProximal[n3]) + vod1[-1].append(d1Proximal[n3]) + vod2[-1].append(d2Proximal[n3]) + vod3[-1].append(d3Proximal[n3]) + else: + radius1 = vector.magnitude(centralPath.cd2Path[0]) - (1.0 - vesselWallThicknessXi3List[n3]) * vesselWallThickness + radius2 = vector.magnitude(centralPath.cd3Path[0]) - (1.0 - vesselWallThicknessXi3List[n3]) * vesselWallThickness + vAxis1 = vector.setMagnitude(centralPath.cd2Path[0], radius1) + vAxis2 = vector.setMagnitude(centralPath.cd3Path[0], radius2) + # print(centralPath.cd2Path[0], centralPath.cd3Path[0]) + # if vesselsCount == 1: + startRadians = 0.0 # 0.5 * math.pi + # else: + # startRadians = 0.5 * radiansPerElementVessel * elementsCountAcross + # if v == (vesselsCount - 1): + # startRadians -= math.pi + px, pd1 = sampleEllipsePoints(centralPath.cxPath[0], vAxis1, vAxis2, 0.0, 2.0 * math.pi, elementsCountAroundVessel) + del px[-1], pd1[-1] + + vox[-1].append(px) + vod1[-1].append(pd1) + vesselEndDerivative = vector.setMagnitude(centralPath.cd1Path[0], arcLength/elementsCountAlong) + vod2[-1].append([vesselEndDerivative] * elementsCountAroundVessel) # need to scale with bending? + if useCubicHermiteThroughVesselWall: + vod3[-1].append([vector.setMagnitude(vector.crossproduct3(d1, vesselEndDerivative), #cd1Path[-1]), + vesselWallThickness * vesselWallThicknessProportions[n3]) + for d1 in pd1]) # for v in range(len(vox)): # for n3 in range(len(vox[v])): @@ -946,7 +962,8 @@ def generateOstiumMesh(region, options, trackSurface, centralPath, startNodeIden startPointsx, startPointsd1, startPointsd2, startPointsd3, startNodeId, startDerivativesMap = \ mvPointsx[v], mvPointsd1[v], mvPointsd2[v], mvPointsd3[v], mvNodeId[v], mvDerivativesMap[v] endPointsx, endPointsd1, endPointsd2, endPointsd3, endNodeId, endDerivativesMap = \ - vox[v], vod1[v], vod2[v], vod3[v] if useCubicHermiteThroughVesselWall else None, None, None + vox[v], vod1[v], vod2[v], vod3[v] if useCubicHermiteThroughVesselWall else None, \ + nodeIdProximal if xProximal else None, None # reverse order of nodes around: for px in [startPointsx, startPointsd1, startPointsd2, startPointsd3, startNodeId, startDerivativesMap, endPointsx, endPointsd1, endPointsd2, endPointsd3, endNodeId, endDerivativesMap]: @@ -965,7 +982,8 @@ def generateOstiumMesh(region, options, trackSurface, centralPath, startNodeIden rowMeshGroups[0] += ostiumMeshGroups else: startPointsx, startPointsd1, startPointsd2, startPointsd3, startNodeId, startDerivativesMap = \ - vox[v], vod1[v], vod2[v], vod3[v] if useCubicHermiteThroughVesselWall else None, None, None + vox[v], vod1[v], vod2[v], vod3[v] if useCubicHermiteThroughVesselWall else None, \ + nodeIdProximal if xProximal else None, None endPointsx, endPointsd1, endPointsd2, endPointsd3, endNodeId, endDerivativesMap = \ mvPointsx[v], mvPointsd1[v], mvPointsd2[v], mvPointsd3[v], mvNodeId[v], mvDerivativesMap[v] if ostiumMeshGroups: diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_smallintestine1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_smallintestine1.py index 7ecb1f95..85c21aaf 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_smallintestine1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_smallintestine1.py @@ -18,7 +18,7 @@ from scaffoldmaker.utils import interpolation as interp from scaffoldmaker.utils import tubemesh from scaffoldmaker.utils import vector -from scaffoldmaker.utils.tubemesh import CylindricalSegmentTubeMeshInnerPoints +from scaffoldmaker.utils.tubemesh import CylindricalSegmentTubeMeshOuterPoints from scaffoldmaker.utils.zinc_utils import exnode_string_from_nodeset_field_parameters, \ get_nodeset_path_field_parameters @@ -602,6 +602,13 @@ class MeshType_3d_smallintestine1(Scaffold_base): ] ), 'userAnnotationGroups': [ + { + '_AnnotationGroup': True, + 'dimension': 1, + 'identifierRanges': '1-536', + 'name': get_smallintestine_term('small intestine')[0], + 'ontId': get_smallintestine_term('small intestine')[1] + }, { '_AnnotationGroup': True, 'dimension': 1, @@ -631,164 +638,172 @@ class MeshType_3d_smallintestine1(Scaffold_base): "62-63-64-65-66-67-68-69-70-71-72-73-74-75-76-77-78-79-80-81-82-83-84-85-86-87-88-89-90-" "91-92-93-94-95-96-97-98-99-100-101-102-103-104-105-106-107-108-109-110-111-112-113-114-" "115-116-117-118-119-120-121-122-123-124-125-126-127-128-129-130-131-132-133-134-135-136-" - "137-138-139-140-141-142-143-144-145-146-147-148-149-150-151" + "137-138-139-140-141-142-143-144-145-146-147-148-149-150-151-152" }, 'meshEdits': exnode_string_from_nodeset_field_parameters( [ Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3 ], [ - (1, [[-40.03,-124.48,1057.88], [-9.88,12.23,-4.08], [-4.52,-6.14,-7.44], [2.36,-0.32,0.12], [-4.07,-1.93,4.06], [-0.25,2.08,-4.50]]), - (2, [[-49.64,-111.67,1050.88], [-6.84,19.44,-21.94], [-1.68,-6.55,-5.28], [0.90,0.69,1.57], [-7.35,0.02,2.32], [-0.76,2.95,-2.23]]), - (3, [[-43.45,-95.70,1015.59], [40.73,3.22,-44.80], [-5.24,-3.34,-4.99], [-0.38,4.38,-0.33], [-2.27,6.02,-1.64], [4.59,3.49,-0.79]]), - (4, [[26.76,-119.31,992.03], [58.86,-18.68,-8.45], [0.31,3.94,-6.60], [4.15,2.33,1.07], [2.23,5.49,3.38], [3.36,-4.08,2.37]]), - (5, [[68.06,-131.66,993.83], [9.68,-30.91,-18.90], [4.09,3.68,-3.94], [-0.33,-6.20,3.78], [5.30,-1.09,4.49], [-3.68,-1.57,1.51]]), - (6, [[46.28,-139.94,982.68], [-22.68,-4.85,-10.94], [1.05,-7.06,0.97], [-0.93,-3.80,3.22], [-3.19,0.42,6.42], [-5.34,-0.64,-2.85]]), - (7, [[28.56,-141.07,974.61], [3.75,-10.52,-21.30], [1.56,-6.21,3.34], [-1.00,0.06,-0.07], [-6.85,-1.87,-0.29], [1.10,-0.53,-6.40]]), - (8, [[52.39,-146.13,971.40], [18.40,-3.70,0.67], [-1.44,-7.11,0.30], [-0.59,-0.29,-0.54], [0.19,-0.34,-7.25], [2.42,0.06,-1.89]]), - (9, [[63.13,-148.18,973.52], [10.49,-1.41,1.47], [-1.07,-7.16,0.77], [2.41,0.38,0.12], [0.88,-0.90,-7.16], [-2.03,-1.10,0.84]]), - (10, [[72.69,-148.91,974.30], [7.65,3.57,-7.08], [3.50,-6.34,0.58], [0.43,0.20,-1.42], [-3.88,-2.63,-5.52], [-3.49,0.08,4.65]]), - (11, [[71.05,-143.65,964.65], [-5.96,4.70,-11.04], [-0.81,-6.83,-2.47], [-2.36,-0.38,-1.14], [-6.40,-0.43,3.27], [0.27,0.95,6.07]]), - (12, [[61.06,-140.78,954.52], [-17.96,3.88,-6.22], [-1.07,-7.12,-1.37], [0.18,-0.25,1.37], [-2.56,-0.94,6.80], [3.84,0.27,2.13]]), - (13, [[37.99,-136.93,957.17], [-18.82,0.88,5.08], [-0.16,-7.34,0.67], [1.90,0.17,0.59], [1.94,0.61,7.07], [2.12,1.03,-0.12]]), - (14, [[24.26,-138.06,963.16], [-17.40,-6.04,8.51], [2.59,-6.90,0.38], [2.42,1.01,0.69], [2.78,1.42,6.69], [-2.18,-0.67,-0.74]]), - (15, [[6.50,-150.31,973.05], [-8.25,-16.44,-13.42], [4.89,-4.75,2.82], [-1.08,-0.49,-0.28], [-4.82,-1.85,5.24], [-4.27,-0.82,-2.18]]), - (16, [[15.97,-149.80,957.69], [-4.35,-1.25,-14.05], [0.99,-7.39,0.35], [-1.04,-0.78,-0.85], [-6.95,-0.83,2.23], [-0.48,0.19,-0.50]]), - (17, [[8.29,-150.98,954.25], [-3.34,-0.73,-8.15], [1.18,-7.37,0.18], [0.18,0.05,0.37], [-6.71,-1.00,2.84], [0.56,-0.43,-3.27]]), - (18, [[10.77,-150.88,946.76], [5.27,-0.05,-7.15], [1.37,-7.28,1.06], [-0.12,-0.03,0.05], [-5.80,-1.71,-4.27], [2.05,0.22,-4.83]]), - (19, [[18.30,-151.09,941.26], [7.79,0.88,-2.39], [0.88,-7.45,0.16], [0.05,-0.01,-0.90], [-2.15,-0.40,-7.16], [4.52,1.49,-0.77]]), - (20, [[24.85,-149.58,941.59], [5.32,0.62,3.02], [1.33,-7.35,-0.84], [-0.35,0.01,-0.65], [3.51,1.37,-6.46], [3.43,0.58,1.19]]), - (21, [[27.85,-149.81,945.92], [3.49,-0.55,3.99], [0.33,-7.39,-1.30], [-0.75,-0.04,-0.15], [5.61,1.09,-4.76], [-0.58,-0.16,-0.31]]), - (22, [[31.64,-150.64,949.37], [5.77,-0.50,1.81], [-0.28,-7.43,-1.16], [0.32,-0.01,0.32], [2.31,1.02,-7.08], [-4.59,-0.60,-0.74]]), - (23, [[38.16,-150.55,948.48], [5.40,1.27,-4.34], [1.28,-7.40,-0.56], [1.28,0.32,-0.53], [-4.63,-0.35,-5.87], [-4.44,-1.61,3.12]]), - (24, [[40.30,-148.53,942.17], [-0.50,2.45,-7.55], [2.42,-6.73,-2.35], [1.39,0.82,-0.98], [-7.02,-2.42,-0.32], [-0.57,-0.95,1.02]]), - (25, [[36.76,-146.19,935.09], [3.27,5.38,-6.44], [4.32,-5.62,-2.50], [0.26,-0.08,1.07], [-5.50,-2.17,-4.60], [3.60,1.24,-3.41]]), - (26, [[44.60,-142.08,934.77], [8.65,3.53,1.10], [2.85,-7.00,0.02], [-1.02,-0.77,1.00], [0.83,0.31,-7.53], [3.41,1.45,-1.30]]), - (27, [[53.34,-139.44,937.21], [8.31,2.34,2.22], [2.15,-7.25,-0.38], [-0.54,-0.17,-0.42], [1.71,0.89,-7.34], [0.07,0.37,0.03]]), - (28, [[61.18,-137.39,939.22], [8.23,1.72,1.43], [1.69,-7.36,-0.86], [-0.38,-0.10,-0.17], [1.06,1.12,-7.44], [-0.84,-0.07,-0.12]]), - (29, [[69.72,-136.03,940.04], [8.42,1.51,0.05], [1.35,-7.46,-0.74], [0.30,0.21,-0.63], [-0.09,0.74,-7.58], [-3.56,-0.97,1.73]]), - (30, [[77.28,-134.50,939.34], [4.49,4.18,-8.53], [2.31,-6.92,-2.18], [-0.29,0.07,-0.48], [-6.41,-0.93,-3.83], [-3.19,-0.95,5.53]]), - (31, [[71.89,-131.27,929.11], [-6.78,1.09,-6.79], [0.09,-7.53,-1.30], [-0.44,-0.26,1.25], [-5.41,-0.97,5.25], [0.24,0.45,2.90]]), - (32, [[66.11,-131.60,925.90], [-4.09,-0.45,-4.44], [0.54,-7.64,0.28], [0.08,0.05,1.40], [-5.56,-0.21,5.14], [-0.15,0.88,-0.16]]), - (33, [[63.93,-132.09,921.07], [-3.93,-1.16,-4.37], [0.32,-7.47,1.70], [0.72,0.30,0.95], [-5.72,0.87,4.92], [0.66,0.51,0.56]]), - (34, [[58.47,-133.89,917.96], [-6.67,-3.36,-3.67], [2.29,-6.97,2.21], [2.28,0.92,-0.11], [-3.96,0.75,6.50], [2.25,0.03,1.31]]), - (35, [[51.02,-139.09,914.02], [-6.63,-6.74,0.39], [5.40,-5.25,1.13], [1.07,0.42,-1.32], [-0.59,1.02,7.59], [3.12,0.37,0.20]]), - (36, [[46.77,-145.49,918.12], [-5.05,-4.37,2.87], [4.81,-5.92,-0.55], [-1.31,-0.89,-0.94], [2.68,1.52,7.03], [1.26,-0.68,-0.12]]), - (37, [[41.95,-147.92,919.78], [-5.03,-2.38,1.94], [2.90,-7.03,-1.10], [-1.32,-0.68,-0.33], [2.77,0.01,7.18], [-0.11,-1.00,0.12]]), - (38, [[36.76,-150.21,922.00], [-5.10,-1.68,1.58], [2.03,-7.33,-1.24], [-0.51,-0.22,0.81], [2.44,-0.56,7.30], [-0.45,0.50,0.13]]), - (39, [[31.89,-151.33,922.99], [-5.71,-1.25,1.56], [1.77,-7.50,0.46], [-0.57,-0.18,0.73], [1.84,0.88,7.45], [-2.05,0.33,0.03]]), - (40, [[25.55,-152.65,925.18], [-6.28,-0.56,-2.17], [0.70,-7.71,-0.03], [-0.69,-0.09,-0.62], [-2.50,-0.25,7.31], [-3.19,-0.78,-0.83]]), - (41, [[22.17,-152.27,920.06], [-4.85,0.30,-4.20], [0.27,-7.70,-0.85], [-0.24,-0.02,0.24], [-5.02,-0.81,5.76], [2.41,0.37,-0.06]]), - (42, [[16.60,-152.11,917.51], [-6.97,0.00,2.68], [0.20,-7.74,0.51], [-0.30,-0.03,0.60], [2.77,0.54,7.21], [5.78,0.37,-0.74]]), - (43, [[13.12,-152.32,924.90], [-3.73,0.41,7.15], [-0.45,-7.75,0.21], [-0.14,-0.02,-0.16], [6.78,-0.30,3.55], [-0.23,-0.18,0.20]]), - (44, [[9.44,-151.37,931.31], [-7.88,0.19,2.81], [-0.13,-7.78,0.17], [0.49,-0.01,0.12], [2.61,0.12,7.31], [-3.70,0.33,2.08]]), - (45, [[1.23,-152.17,928.31], [-8.13,-0.72,-1.08], [0.62,-7.76,0.49], [0.09,-0.01,-0.29], [-1.06,0.40,7.71], [1.43,-0.16,-0.65]]), - (46, [[-5.97,-152.74,928.93], [-5.64,-0.31,4.39], [0.17,-7.80,-0.33], [-0.93,0.04,0.09], [4.76,-0.16,6.12], [3.98,-0.84,-4.11]]), - (47, [[-8.05,-152.70,935.12], [0.84,0.43,7.28], [-1.31,-7.67,0.60], [-1.08,0.17,0.74], [7.52,-1.34,-0.79], [0.79,-0.43,-1.11]]), - (48, [[-4.18,-151.98,940.93], [-5.50,2.85,8.02], [-2.07,-7.44,1.22], [-0.37,0.07,-0.10], [6.17,-0.96,4.57], [-3.01,0.56,4.29]]), - (49, [[-15.92,-150.23,939.85], [-11.53,2.83,0.08], [-1.87,-7.62,-0.02], [0.12,0.15,0.78], [0.04,-0.03,7.84], [0.81,0.00,-1.16]]), - (50, [[-25.87,-146.77,940.97], [-2.69,4.15,9.23], [-1.80,-7.15,2.69], [0.69,0.20,1.48], [7.25,-0.88,2.51], [1.72,-1.41,-6.49]]), - (51, [[-19.43,-146.58,946.99], [7.70,1.83,5.13], [-0.49,-7.14,3.29], [1.24,-0.13,-0.09], [4.50,-2.94,-5.70], [-0.59,-0.04,-3.45]]), - (52, [[-11.61,-143.43,950.54], [5.25,2.52,5.68], [0.83,-7.42,2.52], [0.75,-0.24,-0.87], [5.91,-1.04,-5.00], [0.83,1.41,0.57]]), - (53, [[-9.22,-141.82,956.88], [3.60,1.58,5.20], [1.22,-7.66,1.48], [-0.05,-0.13,-0.42], [6.39,0.15,-4.47], [0.12,0.28,0.10]]), - (54, [[-4.88,-140.39,960.70], [3.78,1.36,4.90], [0.78,-7.72,1.54], [0.07,-0.06,-0.65], [6.23,-0.31,-4.72], [0.53,0.53,1.66]]), - (55, [[-1.98,-139.20,966.47], [0.65,0.13,7.29], [1.42,-7.78,0.01], [0.23,-0.06,-0.88], [7.61,1.39,-0.70], [0.66,0.74,3.14]]), - (56, [[-4.15,-140.36,973.96], [-2.38,-0.65,10.17], [1.19,-7.83,-0.22], [-0.65,-0.07,-0.20], [7.50,1.09,1.83], [-0.21,-0.70,2.00]]), - (57, [[-6.44,-140.06,986.68], [-4.21,-0.33,9.07], [-0.24,-7.94,-0.40], [-0.77,0.02,-0.44], [7.09,-0.38,3.28], [-1.82,-1.02,2.46]]), - (58, [[-10.86,-140.67,991.98], [-5.80,0.04,3.85], [-0.73,-7.85,-1.03], [0.04,-0.00,-0.15], [4.33,-1.25,6.51], [-3.51,-0.15,2.18]]), - (59, [[-17.28,-140.01,993.95], [-7.30,0.18,-0.28], [-0.17,-7.94,-0.73], [0.59,-0.04,0.75], [-0.32,-0.72,7.93], [-4.07,0.69,0.16]]), - (60, [[-24.40,-140.40,991.18], [-6.25,-0.73,-3.97], [0.53,-7.94,0.63], [-0.08,0.16,1.48], [-4.27,0.24,6.69], [-3.14,0.95,-2.22]]), - (61, [[-29.47,-141.40,986.35], [-2.47,-1.37,-4.69], [-0.28,-7.62,2.38], [-1.43,0.31,0.61], [-7.02,1.29,3.32], [-0.94,0.18,-5.15]]), - (62, [[-29.90,-142.61,982.98], [1.86,-2.14,-4.74], [-2.17,-7.29,2.44], [-1.16,0.11,-0.29], [-7.10,1.03,-3.25], [0.49,-0.35,-4.87]]), - (63, [[-24.82,-145.19,978.58], [4.65,-2.18,-4.59], [-2.13,-7.58,1.44], [0.29,-0.26,-0.91], [-5.46,0.45,-5.75], [-0.33,0.23,1.00]]), - (64, [[-20.75,-146.91,974.01], [1.23,-0.70,-6.94], [-1.58,-7.84,0.51], [0.08,-0.09,-0.69], [-7.59,1.43,-1.48], [0.46,0.35,5.77]]), - (65, [[-23.39,-146.10,967.33], [-6.32,1.65,-4.01], [-2.03,-7.76,0.01], [-0.16,0.07,0.36], [-4.04,1.07,6.80], [4.83,-0.40,4.28]]), - (66, [[-30.60,-144.33,967.78], [-6.69,2.04,2.19], [-1.93,-7.69,1.27], [0.05,0.00,0.44], [2.65,0.58,7.55], [3.03,-0.35,0.34]]), - (67, [[-36.17,-142.25,971.34], [-6.59,1.94,2.27], [-1.94,-7.73,1.01], [0.04,-0.01,0.09], [2.70,0.31,7.56], [0.37,-0.02,-0.15]]), - (68, [[-43.40,-140.59,972.07], [-6.04,1.97,2.74], [-1.83,-7.71,1.48], [0.02,0.34,1.18], [3.47,0.56,7.23], [2.30,-0.41,-2.27]]), - (69, [[-47.62,-138.63,976.14], [-1.78,2.68,4.62], [-1.87,-7.07,3.39], [0.01,0.35,0.98], [7.30,-0.46,3.08], [1.72,-1.44,-3.71]]), - (70, [[-47.10,-135.98,980.16], [0.98,1.95,4.05], [-1.83,-6.90,3.76], [0.21,-0.14,-0.20], [7.55,-2.37,-0.68], [0.04,-0.76,-2.21]]), - (71, [[-45.78,-134.75,984.02], [1.92,1.94,5.58], [-1.46,-7.34,3.05], [-0.53,0.37,0.09], [7.43,-2.22,-1.79], [-0.24,0.26,1.07]]), - (72, [[-43.37,-132.13,990.97], [-1.92,7.78,7.36], [-3.78,-5.37,4.69], [-2.14,1.26,-0.06], [6.91,-1.72,3.61], [-3.47,2.54,4.15]]), - (73, [[-50.92,-122.17,992.94], [-8.28,6.98,-7.76], [-5.96,-5.08,1.79], [0.61,-1.11,-1.84], [-2.03,4.63,6.34], [-6.54,1.98,-0.43]]), - (74, [[-54.52,-122.57,980.90], [-5.10,0.46,-13.05], [-2.60,-7.66,0.75], [2.85,-1.09,0.85], [-7.02,2.66,2.84], [-2.86,-1.79,-2.31]]), - (75, [[-60.93,-121.16,967.78], [-3.40,-6.95,-12.83], [0.01,-7.18,3.88], [-1.69,1.75,1.25], [-7.80,0.86,1.60], [1.21,-0.70,-4.51]]), - (76, [[-59.94,-133.62,960.46], [4.44,-11.12,-4.92], [-6.17,-3.97,3.41], [-1.80,0.34,-0.38], [-4.46,1.19,-6.70], [1.72,-0.86,-3.60]]), - (77, [[-53.65,-142.09,958.04], [8.15,-8.95,-3.45], [-4.95,-5.68,3.06], [2.04,-1.62,-0.11], [-3.75,-0.62,-7.23], [-0.92,-0.86,0.97]]), - (78, [[-43.78,-150.90,953.55], [6.86,-6.21,-10.82], [-1.57,-7.38,3.24], [0.10,-0.47,-1.48], [-6.93,-0.36,-4.18], [-0.50,1.88,6.12]]), - (79, [[-42.79,-151.92,940.92], [-10.16,7.35,-12.87], [-4.74,-6.68,-0.07], [-1.78,0.37,-1.94], [-4.81,3.35,5.71], [1.37,1.93,5.90]]), - (80, [[-59.56,-139.32,940.87], [-10.47,7.53,-10.55], [-4.67,-6.77,-0.21], [-0.78,0.74,0.77], [-4.39,2.82,6.37], [-0.63,1.74,-4.22]]), - (81, [[-61.19,-138.43,930.23], [-0.37,-2.04,-12.19], [-5.97,-5.52,1.11], [-0.86,0.96,0.96], [-5.64,5.92,-0.83], [0.65,-0.72,-6.69]]), - (82, [[-60.05,-143.37,918.84], [6.12,-9.41,-3.11], [-6.44,-4.78,1.79], [0.25,-0.37,-0.76], [-2.75,0.78,-7.78], [3.39,-3.10,-3.06]]), - (83, [[-54.81,-148.97,924.54], [7.07,-6.60,2.05], [-5.61,-6.05,-0.17], [0.76,-0.86,-0.33], [1.38,-1.05,-8.13], [-1.61,1.40,1.58]]), - (84, [[-48.00,-154.67,922.57], [3.54,-3.72,-7.48], [-4.83,-6.61,1.00], [1.21,-0.76,-0.14], [-5.85,3.58,-4.55], [-4.06,1.81,3.83]]), - (85, [[-49.39,-154.51,914.46], [0.27,0.35,-10.67], [-3.11,-7.64,-0.33], [1.86,-0.79,-0.48], [-7.54,3.07,-0.10], [1.64,-1.57,-0.54]]), - (86, [[-46.73,-154.01,904.00], [18.99,-1.89,-1.48], [-0.78,-8.19,0.40], [1.31,-0.30,0.50], [-0.67,-0.34,-8.19], [5.19,-2.31,-4.98]]), - (87, [[-31.90,-157.00,923.20], [20.27,-2.84,5.71], [-1.28,-8.04,0.54], [1.63,0.18,0.17], [2.10,-0.86,-7.85], [-3.21,-0.77,1.42]]), - (88, [[-17.04,-158.47,917.33], [10.69,1.60,-10.94], [1.94,-7.84,0.74], [0.87,0.01,-0.11], [-5.44,-1.88,-5.58], [-1.71,0.19,-0.09]]), - (89, [[-12.92,-154.88,905.59], [14.28,1.56,-5.12], [1.01,-8.00,0.37], [-0.98,-0.09,-0.58], [-2.65,-0.69,-7.58], [1.89,1.14,-1.15]]), - (90, [[0.79,-157.22,913.22], [17.05,-0.10,-3.50], [-0.16,-8.01,-0.53], [0.24,0.09,-0.24], [-1.61,0.55,-7.83], [0.10,0.16,0.01]]), - (91, [[11.37,-154.85,899.81], [20.47,4.34,-7.04], [1.62,-7.80,-0.10], [0.67,0.24,-0.62], [-2.50,-0.42,-7.54], [-1.60,0.07,0.92]]), - (92, [[35.28,-149.96,905.73], [15.01,5.71,-13.20], [0.80,-7.50,-2.33], [1.12,0.33,0.34], [-5.36,1.17,-5.59], [-1.05,-1.38,0.95]]), - (93, [[31.51,-148.90,893.07], [11.51,6.02,-14.64], [3.17,-7.13,-0.44], [1.65,0.51,0.45], [-5.44,-2.11,-5.15], [2.20,-0.03,-0.53]]), - (94, [[53.21,-142.18,892.15], [16.13,8.56,4.60], [3.96,-6.33,-2.13], [0.42,0.20,0.80], [0.58,2.81,-7.25], [3.44,1.00,-0.61]]), - (95, [[62.43,-134.45,898.99], [11.35,7.61,6.27], [4.22,-6.47,0.22], [-1.03,-0.53,1.15], [2.81,1.59,-7.04], [-2.20,-1.80,0.66]]), - (96, [[74.83,-127.92,903.83], [13.27,2.58,-11.41], [1.59,-7.52,0.15], [-0.63,-0.25,0.20], [-4.77,-1.12,-5.79], [-4.38,-1.93,4.88]]), - (97, [[72.51,-133.32,887.20], [-12.49,-8.25,-22.65], [3.26,-6.84,0.70], [0.84,0.36,-0.04], [-5.89,-2.38,4.11], [0.64,-0.37,7.04]]), - (98, [[47.82,-142.63,864.93], [-22.72,-8.47,-7.52], [2.75,-7.00,-0.43], [0.03,0.23,-1.27], [-1.94,-1.20,7.19], [5.33,1.35,0.11]]), - (99, [[33.71,-147.84,866.62], [-7.31,-5.02,5.80], [3.02,-6.59,-1.88], [-0.71,0.24,-1.45], [4.50,0.35,5.98], [2.35,2.56,-6.78]]), - (100, [[33.45,-149.55,870.08], [6.66,-2.67,8.62], [1.91,-6.38,-3.46], [-0.81,0.03,-0.86], [5.65,3.48,-3.30], [0.80,2.08,-6.77]]), - (101, [[48.50,-149.86,877.56], [8.44,-1.40,10.88], [1.84,-6.88,-2.31], [-0.55,-0.39,1.17], [5.59,2.82,-3.97], [-1.37,-2.16,5.89]]), - (102, [[49.17,-151.34,885.88], [-14.13,-2.76,6.71], [0.94,-7.25,-1.01], [-0.57,0.33,-0.41], [3.26,-0.51,6.64], [-3.09,-3.47,6.17]]), - (103, [[30.33,-151.82,877.70], [-17.16,1.53,-4.96], [0.92,-5.49,-4.89], [-1.51,-0.14,0.40], [-1.94,-4.93,5.18], [0.64,-0.13,0.13]]), - (104, [[16.36,-149.06,875.57], [-10.97,1.71,5.38], [-1.80,-6.98,-1.46], [-0.54,-0.73,1.97], [2.83,-2.08,6.45], [2.86,1.80,-0.06]]), - (105, [[11.69,-148.72,883.92], [-10.14,1.00,8.83], [-0.94,-7.28,-0.26], [0.66,-0.15,1.09], [4.71,-0.80,5.50], [-0.40,1.32,0.04]]), - (106, [[-3.83,-146.99,890.11], [-14.28,1.09,0.55], [-0.52,-7.22,0.83], [0.36,0.01,-0.26], [0.34,0.81,7.24], [-1.67,-0.06,0.66]]), - (107, [[-14.79,-146.52,886.71], [-10.85,0.22,0.51], [-0.16,-7.24,-0.38], [0.73,0.03,-0.30], [0.33,-0.39,7.23], [2.18,0.02,-0.94]]), - (108, [[-23.91,-146.55,890.53], [-7.40,-0.95,6.58], [0.98,-7.16,0.07], [-0.52,0.10,0.63], [4.68,0.69,5.37], [0.75,0.45,-0.15]]), - (109, [[-28.03,-148.18,898.37], [-13.61,2.90,3.80], [-1.23,-7.02,0.96], [-1.43,0.37,-0.84], [2.04,0.58,6.86], [-3.99,-0.65,0.17]]), - (110, [[-42.02,-140.32,889.27], [-9.93,7.70,-9.68], [-1.44,-6.12,-3.39], [0.84,-0.04,-0.89], [-5.33,-1.24,4.49], [-3.62,0.11,-4.10]]), - (111, [[-47.83,-133.82,880.59], [1.67,2.81,-9.02], [0.19,-6.80,-2.08], [0.02,-0.24,2.82], [-6.87,0.17,-1.22], [2.63,-0.65,-5.17]]), - (112, [[-43.36,-134.64,876.97], [7.37,-1.12,-1.77], [-0.61,-6.83,1.80], [-0.49,-0.09,1.49], [-1.84,-1.59,-6.65], [3.37,-0.42,-3.09]]), - (113, [[-34.80,-135.76,878.37], [7.33,-0.80,-0.16], [-0.76,-7.02,0.28], [-0.51,0.02,-0.71], [-0.18,-0.26,-7.06], [-2.44,1.36,1.66]]), - (114, [[-29.32,-136.24,877.18], [3.39,-0.80,-5.31], [-1.57,-6.87,0.04], [-0.23,0.05,0.03], [-5.67,1.27,-3.82], [-3.22,0.72,3.41]]), - (115, [[-30.61,-136.87,870.77], [-0.25,-0.25,-5.29], [-1.19,-6.91,0.38], [0.28,-0.03,-0.03], [-6.79,1.18,0.27], [0.35,-0.33,-1.21]]), - (116, [[-30.23,-136.86,867.08], [2.79,-0.45,-3.89], [-0.94,-6.95,0.14], [0.33,-0.03,-0.12], [-5.57,0.67,-4.07], [3.30,-0.63,-3.48]]), - (117, [[-25.37,-137.76,865.06], [8.76,-0.50,1.85], [-0.44,-6.98,0.18], [0.24,0.00,-0.17], [1.43,-0.27,-6.84], [3.73,-0.35,-1.77]]), - (118, [[-17.01,-136.93,873.25], [9.54,-0.88,-1.35], [-0.71,-6.91,-0.47], [-0.79,0.17,0.25], [-0.92,0.56,-6.87], [-3.99,0.94,2.86]]), - (119, [[-14.62,-138.10,867.37], [2.47,-1.15,-8.78], [-1.88,-6.66,0.34], [1.25,0.41,-0.04], [-6.32,1.68,-1.99], [-1.18,0.21,1.02]]), - (120, [[-13.21,-138.67,858.26], [15.02,8.84,-1.86], [3.37,-5.94,-1.02], [3.02,0.32,-0.46], [-1.14,0.51,-6.80], [4.30,-0.76,-2.96]]), - (121, [[-2.01,-129.09,875.92], [14.73,5.57,5.54], [2.30,-6.43,0.36], [-3.38,0.09,1.42], [2.26,0.45,-6.45], [-4.26,0.28,1.85]]), - (122, [[5.71,-128.31,873.45], [4.22,-3.80,-6.92], [-2.33,-6.10,1.93], [1.54,1.12,0.79], [-5.49,0.89,-3.83], [-2.90,-1.92,4.89]]), - (123, [[3.86,-133.45,867.51], [-1.78,-5.98,-7.59], [4.85,-4.16,2.14], [1.96,0.65,1.01], [-4.52,-3.36,3.71], [0.30,-2.10,1.25]]), - (124, [[2.44,-139.69,858.80], [7.02,-5.19,-6.23], [0.11,-5.15,4.40], [-1.69,-0.89,0.21], [-5.06,-2.92,-3.28], [2.22,0.25,-4.49]]), - (125, [[11.98,-140.15,859.35], [17.70,2.25,-1.14], [0.95,-6.06,2.79], [1.39,-0.39,-2.08], [-0.04,-2.82,-6.13], [2.19,0.11,-1.39]]), - (126, [[35.30,-132.99,854.91], [8.74,9.55,-15.22], [4.05,-5.23,-0.96], [0.82,0.89,-2.82], [-4.43,-2.65,-4.20], [-1.33,-1.30,4.05]]), - (127, [[29.93,-128.55,843.92], [-12.95,5.12,-19.36], [3.68,-4.21,-3.57], [-1.41,0.00,-0.87], [-4.19,-4.93,1.49], [1.70,-0.30,5.11]]), - (128, [[9.39,-125.79,820.06], [-27.75,1.44,5.84], [-0.47,-6.58,-0.63], [-1.27,-0.92,1.78], [1.32,-0.72,6.46], [4.74,2.19,-0.36]]), - (129, [[4.65,-126.74,840.92], [-6.02,1.18,15.73], [0.13,-6.59,0.55], [-0.73,0.09,0.19], [6.11,0.31,2.32], [-2.11,0.21,1.57]]), - (130, [[0.04,-125.01,849.26], [-9.24,1.85,1.00], [-1.26,-6.45,0.32], [0.68,0.07,-0.54], [0.75,0.18,6.55], [-5.74,-0.82,-0.60]]), - (131, [[-4.44,-124.79,843.15], [-5.02,0.46,-16.66], [1.26,-6.43,-0.56], [1.98,0.08,-0.42], [-6.09,-1.34,1.79], [-4.27,-1.02,-2.57]]), - (132, [[-4.10,-124.24,817.80], [-14.82,-5.98,-12.69], [2.23,-6.13,0.29], [-0.08,-0.02,0.18], [-3.88,-1.17,5.07], [6.33,1.59,-0.02]]), - (133, [[-13.82,-128.40,823.84], [-7.49,-1.58,13.51], [1.55,-6.33,0.12], [-0.55,0.00,0.71], [5.49,1.40,3.20], [4.92,1.22,-2.01]]), - (134, [[-15.54,-126.40,839.81], [-2.26,3.63,12.78], [1.06,-6.11,1.92], [-1.86,0.05,-0.36], [6.21,1.31,0.73], [-0.95,-1.43,1.43]]), - (135, [[-17.86,-122.19,848.91], [-6.97,2.29,6.40], [-1.90,-6.17,0.14], [0.21,-0.11,-0.73], [4.06,-1.15,4.85], [-5.50,-0.82,1.29]]), - (136, [[-24.46,-122.95,849.04], [-11.05,-2.26,-14.69], [1.03,-6.35,0.20], [1.60,-0.05,0.47], [-5.05,-0.70,3.90], [-6.40,0.95,-0.75]]), - (137, [[-23.98,-124.71,821.70], [-13.90,-3.45,-17.21], [-1.09,-5.98,2.08], [-0.11,-0.11,-0.76], [-4.88,2.11,3.53], [5.05,-0.43,0.87]]), - (138, [[-38.60,-127.22,820.18], [-12.58,-0.43,8.78], [-0.02,-6.39,-0.33], [-0.17,-0.02,-0.17], [3.67,-0.29,5.24], [4.86,-1.54,-2.07]]), - (139, [[-42.52,-125.65,832.78], [1.33,2.91,14.25], [-1.25,-6.10,1.37], [-0.03,0.21,1.19], [6.11,-1.31,-0.30], [1.08,-0.26,-3.49]]), - (140, [[-35.80,-121.92,845.73], [4.20,3.78,10.20], [0.01,-5.96,2.20], [-0.16,0.23,0.57], [5.88,-0.78,-2.13], [0.09,0.03,0.69]]), - (141, [[-33.62,-118.72,852.84], [0.50,3.01,6.47], [-0.93,-5.65,2.70], [-0.79,-0.03,-0.57], [6.15,-1.01,0.00], [-0.33,-0.03,2.50]]), - (142, [[-34.44,-116.11,858.28], [-2.64,1.81,5.04], [-1.71,-5.94,1.23], [0.58,-0.29,-1.41], [5.32,-0.89,3.11], [-1.83,0.37,2.71]]), - (143, [[-38.38,-115.33,862.17], [-6.05,-0.34,2.35], [0.22,-6.28,-0.34], [1.37,-0.09,-0.25], [2.28,-0.24,5.85], [-4.21,0.45,0.94]]), - (144, [[-44.50,-116.93,861.58], [-11.59,-3.81,-10.16], [1.11,-6.09,1.02], [0.44,0.12,0.61], [-4.13,0.03,4.70], [-4.54,0.05,-0.79]]), - (145, [[-51.78,-120.72,839.03], [-15.88,-5.45,-10.36], [1.83,-5.97,0.32], [-1.36,0.27,0.87], [-3.22,-0.70,5.31], [4.29,0.49,0.09]]), - (146, [[-64.65,-124.35,841.48], [-11.51,0.42,9.85], [0.15,-6.19,0.44], [-0.55,0.33,1.54], [3.97,0.43,4.63], [4.38,-0.52,-2.90]]), - (147, [[-69.37,-119.95,854.33], [5.11,4.21,16.62], [-1.33,-5.74,1.87], [0.69,0.27,0.73], [5.67,-1.74,-1.31], [0.56,-1.58,-4.18]]), - (148, [[-55.63,-118.57,867.17], [8.19,15.70,8.57], [0.71,-2.34,3.60], [0.89,1.63,1.44], [4.28,-1.31,-1.70], [0.13,0.20,0.14]]), - (149, [[-52.38,-100.90,869.76], [4.76,24.01,12.61], [0.49,-2.47,4.53], [-0.28,-0.30,-1.61], [4.60,-0.51,-0.77], [-2.29,1.10,4.28]]), - (150, [[-41.73,-76.29,892.90], [-14.02,14.24,19.65], [-3.50,-2.99,-0.33], [3.24,-2.89,0.75], [1.93,-2.62,3.27], [-5.09,5.86,6.61]]), - (151, [[-58.69,-78.02,896.31], [-2.60,-3.83,-1.89], [4.61,-2.18,-1.92], [3.24,-2.89,0.75], [0.64,-2.74,4.67], [-5.09,5.86,6.61]]) + (1, [[-32.281,-136.261,1061.249], [-6.125,11.114,-0.493], [-5.735,-3.374,-4.823], [-2.070,-0.220,-4.520], [-4.630,-2.238,7.071], [-4.400,2.440,0.570]]), + (2, [[-40.674,-122.300,1060.850], [-5.403,7.321,-2.629], [-4.779,-4.249,-5.161], [2.360,-0.320,0.120], [-5.138,-1.668,6.875], [-0.250,2.080,-4.500]]), + (3, [[-48.346,-108.981,1049.574], [-6.840,19.440,-21.940], [-3.459,-4.108,-5.699], [0.900,0.690,1.570], [-7.043,0.777,3.341], [-0.760,2.950,-2.230]]), + (4, [[-43.450,-95.700,1015.590], [40.730,3.220,-44.800], [-5.240,-3.340,-4.990], [-0.380,4.380,-0.330], [-2.270,6.020,-1.640], [4.590,3.490,-0.790]]), + (5, [[26.760,-119.310,992.030], [58.860,-18.680,-8.450], [0.310,3.940,-6.600], [4.150,2.330,1.070], [2.230,5.490,3.380], [3.360,-4.080,2.370]]), + (6, [[63.862,-132.266,992.002], [9.680,-30.910,-18.900], [5.846,1.916,2.960], [-0.330,-6.200,3.780], [5.300,-1.090,4.490], [-3.680,-1.570,1.510]]), + (7, [[46.280,-139.940,982.680], [-22.680,-4.850,-10.940], [1.050,-7.060,0.970], [-0.930,-3.800,3.220], [-3.190,0.420,6.420], [-5.340,-0.640,-2.850]]), + (8, [[28.560,-141.070,974.610], [3.750,-10.520,-21.300], [1.560,-6.210,3.340], [-1.000,0.060,-0.070], [-6.850,-1.870,-0.290], [1.100,-0.530,-6.400]]), + (9, [[52.390,-146.130,971.400], [18.400,-3.700,0.670], [-1.440,-7.110,0.300], [-0.590,-0.290,-0.540], [0.190,-0.340,-7.250], [2.420,0.060,-1.890]]), + (10, [[63.130,-148.180,973.520], [10.490,-1.410,1.470], [-1.070,-7.160,0.770], [2.410,0.380,0.120], [0.880,-0.900,-7.160], [-2.030,-1.100,0.840]]), + (11, [[72.690,-148.910,974.300], [7.650,3.570,-7.080], [3.500,-6.340,0.580], [0.430,0.200,-1.420], [-3.880,-2.630,-5.520], [-3.490,0.080,4.650]]), + (12, [[71.050,-143.650,964.650], [-5.960,4.700,-11.040], [-0.810,-6.830,-2.470], [-2.360,-0.380,-1.140], [-6.400,-0.430,3.270], [0.270,0.950,6.070]]), + (13, [[61.060,-140.780,954.520], [-17.960,3.880,-6.220], [-1.070,-7.120,-1.370], [0.180,-0.250,1.370], [-2.560,-0.940,6.800], [3.840,0.270,2.130]]), + (14, [[37.990,-136.930,957.170], [-18.820,0.880,5.080], [-0.160,-7.340,0.670], [1.900,0.170,0.590], [1.940,0.610,7.070], [2.120,1.030,-0.120]]), + (15, [[24.260,-138.060,963.160], [-17.400,-6.040,8.510], [2.590,-6.900,0.380], [2.420,1.010,0.690], [2.780,1.420,6.690], [-2.180,-0.670,-0.740]]), + (16, [[6.500,-150.310,973.050], [-8.250,-16.440,-13.420], [4.890,-4.750,2.820], [-1.080,-0.490,-0.280], [-4.820,-1.850,5.240], [-4.270,-0.820,-2.180]]), + (17, [[15.970,-149.800,957.690], [-4.350,-1.250,-14.050], [0.990,-7.390,0.350], [-1.040,-0.780,-0.850], [-6.950,-0.830,2.230], [-0.480,0.190,-0.500]]), + (18, [[8.290,-150.980,954.250], [-3.340,-0.730,-8.150], [1.180,-7.370,0.180], [0.180,0.050,0.370], [-6.710,-1.000,2.840], [0.560,-0.430,-3.270]]), + (19, [[10.770,-150.880,946.760], [5.270,-0.050,-7.150], [1.370,-7.280,1.060], [-0.120,-0.030,0.050], [-5.800,-1.710,-4.270], [2.050,0.220,-4.830]]), + (20, [[18.300,-151.090,941.260], [7.790,0.880,-2.390], [0.880,-7.450,0.160], [0.050,-0.010,-0.900], [-2.150,-0.400,-7.160], [4.520,1.490,-0.770]]), + (21, [[24.850,-149.580,941.590], [5.320,0.620,3.020], [1.330,-7.350,-0.840], [-0.350,0.010,-0.650], [3.510,1.370,-6.460], [3.430,0.580,1.190]]), + (22, [[27.850,-149.810,945.920], [3.490,-0.550,3.990], [0.330,-7.390,-1.300], [-0.750,-0.040,-0.150], [5.610,1.090,-4.760], [-0.580,-0.160,-0.310]]), + (23, [[31.640,-150.640,949.370], [5.770,-0.500,1.810], [-0.280,-7.430,-1.160], [0.320,-0.010,0.320], [2.310,1.020,-7.080], [-4.590,-0.600,-0.740]]), + (24, [[38.160,-150.550,948.480], [5.400,1.270,-4.340], [1.280,-7.400,-0.560], [1.280,0.320,-0.530], [-4.630,-0.350,-5.870], [-4.440,-1.610,3.120]]), + (25, [[40.300,-148.530,942.170], [-0.500,2.450,-7.550], [2.420,-6.730,-2.350], [1.390,0.820,-0.980], [-7.020,-2.420,-0.320], [-0.570,-0.950,1.020]]), + (26, [[36.760,-146.190,935.090], [3.270,5.380,-6.440], [4.320,-5.620,-2.500], [0.260,-0.080,1.070], [-5.500,-2.170,-4.600], [3.600,1.240,-3.410]]), + (27, [[44.600,-142.080,934.770], [8.650,3.530,1.100], [2.850,-7.000,0.020], [-1.020,-0.770,1.000], [0.830,0.310,-7.530], [3.410,1.450,-1.300]]), + (28, [[53.340,-139.440,937.210], [8.310,2.340,2.220], [2.150,-7.250,-0.380], [-0.540,-0.170,-0.420], [1.710,0.890,-7.340], [0.070,0.370,0.030]]), + (29, [[61.180,-137.390,939.220], [8.230,1.720,1.430], [1.690,-7.360,-0.860], [-0.380,-0.100,-0.170], [1.060,1.120,-7.440], [-0.840,-0.070,-0.120]]), + (30, [[69.720,-136.030,940.040], [8.420,1.510,0.050], [1.350,-7.460,-0.740], [0.300,0.210,-0.630], [-0.090,0.740,-7.580], [-3.560,-0.970,1.730]]), + (31, [[77.280,-134.500,939.340], [4.490,4.180,-8.530], [2.310,-6.920,-2.180], [-0.290,0.070,-0.480], [-6.410,-0.930,-3.830], [-3.190,-0.950,5.530]]), + (32, [[71.890,-131.270,929.110], [-6.780,1.090,-6.790], [0.090,-7.530,-1.300], [-0.440,-0.260,1.250], [-5.410,-0.970,5.250], [0.240,0.450,2.900]]), + (33, [[66.110,-131.600,925.900], [-4.090,-0.450,-4.440], [0.540,-7.640,0.280], [0.080,0.050,1.400], [-5.560,-0.210,5.140], [-0.150,0.880,-0.160]]), + (34, [[63.930,-132.090,921.070], [-3.930,-1.160,-4.370], [0.320,-7.470,1.700], [0.720,0.300,0.950], [-5.720,0.870,4.920], [0.660,0.510,0.560]]), + (35, [[58.470,-133.890,917.960], [-6.670,-3.360,-3.670], [2.290,-6.970,2.210], [2.280,0.920,-0.110], [-3.960,0.750,6.500], [2.250,0.030,1.310]]), + (36, [[51.020,-139.090,914.020], [-6.630,-6.740,0.390], [5.400,-5.250,1.130], [1.070,0.420,-1.320], [-0.590,1.020,7.590], [3.120,0.370,0.200]]), + (37, [[46.770,-145.490,918.120], [-5.050,-4.370,2.870], [4.810,-5.920,-0.550], [-1.310,-0.890,-0.940], [2.680,1.520,7.030], [1.260,-0.680,-0.120]]), + (38, [[41.950,-147.920,919.780], [-5.030,-2.380,1.940], [2.900,-7.030,-1.100], [-1.320,-0.680,-0.330], [2.770,0.010,7.180], [-0.110,-1.000,0.120]]), + (39, [[36.760,-150.210,922.000], [-5.100,-1.680,1.580], [2.030,-7.330,-1.240], [-0.510,-0.220,0.810], [2.440,-0.560,7.300], [-0.450,0.500,0.130]]), + (40, [[31.890,-151.330,922.990], [-5.710,-1.250,1.560], [1.770,-7.500,0.460], [-0.570,-0.180,0.730], [1.840,0.880,7.450], [-2.050,0.330,0.030]]), + (41, [[25.550,-152.650,925.180], [-6.280,-0.560,-2.170], [0.700,-7.710,-0.030], [-0.690,-0.090,-0.620], [-2.500,-0.250,7.310], [-3.190,-0.780,-0.830]]), + (42, [[22.170,-152.270,920.060], [-4.850,0.300,-4.200], [0.270,-7.700,-0.850], [-0.240,-0.020,0.240], [-5.020,-0.810,5.760], [2.410,0.370,-0.060]]), + (43, [[16.600,-152.110,917.510], [-6.970,0.000,2.680], [0.200,-7.740,0.510], [-0.300,-0.030,0.600], [2.770,0.540,7.210], [5.780,0.370,-0.740]]), + (44, [[13.120,-152.320,924.900], [-3.730,0.410,7.150], [-0.450,-7.750,0.210], [-0.140,-0.020,-0.160], [6.780,-0.300,3.550], [-0.230,-0.180,0.200]]), + (45, [[9.440,-151.370,931.310], [-7.880,0.190,2.810], [-0.130,-7.780,0.170], [0.490,-0.010,0.120], [2.610,0.120,7.310], [-3.700,0.330,2.080]]), + (46, [[1.230,-152.170,928.310], [-8.130,-0.720,-1.080], [0.620,-7.760,0.490], [0.090,-0.010,-0.290], [-1.060,0.400,7.710], [1.430,-0.160,-0.650]]), + (47, [[-5.970,-152.740,928.930], [-5.640,-0.310,4.390], [0.170,-7.800,-0.330], [-0.930,0.040,0.090], [4.760,-0.160,6.120], [3.980,-0.840,-4.110]]), + (48, [[-8.050,-152.700,935.120], [0.840,0.430,7.280], [-1.310,-7.670,0.600], [-1.080,0.170,0.740], [7.520,-1.340,-0.790], [0.790,-0.430,-1.110]]), + (49, [[-4.180,-151.980,940.930], [-5.500,2.850,8.020], [-2.070,-7.440,1.220], [-0.370,0.070,-0.100], [6.170,-0.960,4.570], [-3.010,0.560,4.290]]), + (50, [[-15.920,-150.230,939.850], [-11.530,2.830,0.080], [-1.870,-7.620,-0.020], [0.120,0.150,0.780], [0.040,-0.030,7.840], [0.810,0.000,-1.160]]), + (51, [[-25.870,-146.770,940.970], [-2.690,4.150,9.230], [-1.800,-7.150,2.690], [0.690,0.200,1.480], [7.250,-0.880,2.510], [1.720,-1.410,-6.490]]), + (52, [[-19.430,-146.580,946.990], [7.700,1.830,5.130], [-0.490,-7.140,3.290], [1.240,-0.130,-0.090], [4.500,-2.940,-5.700], [-0.590,-0.040,-3.450]]), + (53, [[-11.610,-143.430,950.540], [5.250,2.520,5.680], [0.830,-7.420,2.520], [0.750,-0.240,-0.870], [5.910,-1.040,-5.000], [0.830,1.410,0.570]]), + (54, [[-9.220,-141.820,956.880], [3.600,1.580,5.200], [1.220,-7.660,1.480], [-0.050,-0.130,-0.420], [6.390,0.150,-4.470], [0.120,0.280,0.100]]), + (55, [[-4.880,-140.390,960.700], [3.780,1.360,4.900], [0.780,-7.720,1.540], [0.070,-0.060,-0.650], [6.230,-0.310,-4.720], [0.530,0.530,1.660]]), + (56, [[-1.980,-139.200,966.470], [0.650,0.130,7.290], [1.420,-7.780,0.010], [0.230,-0.060,-0.880], [7.610,1.390,-0.700], [0.660,0.740,3.140]]), + (57, [[-4.150,-140.360,973.960], [-2.380,-0.650,10.170], [1.190,-7.830,-0.220], [-0.650,-0.070,-0.200], [7.500,1.090,1.830], [-0.210,-0.700,2.000]]), + (58, [[-6.206,-140.381,984.826], [-3.997,1.953,8.625], [-0.240,-7.940,-0.400], [-0.770,0.020,-0.440], [7.090,-0.380,3.280], [-1.820,-1.020,2.460]]), + (59, [[-11.071,-137.239,990.534], [-6.502,2.564,3.616], [-0.730,-7.850,-1.030], [0.040,-0.000,-0.150], [4.330,-1.250,6.510], [-3.510,-0.150,2.180]]), + (60, [[-18.114,-135.562,991.751], [-6.821,0.865,-0.438], [-0.170,-7.940,-0.730], [0.590,-0.040,0.750], [-0.320,-0.720,7.930], [-4.070,0.690,0.160]]), + (61, [[-24.108,-135.469,989.949], [-5.560,-1.043,-2.740], [0.530,-7.940,0.630], [-0.080,0.160,1.480], [-4.270,0.240,6.690], [-3.140,0.950,-2.220]]), + (62, [[-28.764,-137.545,986.518], [-3.033,-3.486,-4.184], [-0.280,-7.620,2.380], [-1.430,0.310,0.610], [-7.020,1.290,3.320], [-0.940,0.180,-5.150]]), + (63, [[-29.636,-141.811,982.334], [1.634,-2.756,-5.189], [-2.170,-7.290,2.440], [-1.160,0.110,-0.290], [-7.100,1.030,-3.250], [0.490,-0.350,-4.870]]), + (64, [[-24.820,-145.190,978.580], [4.650,-2.180,-4.590], [-2.130,-7.580,1.440], [0.290,-0.260,-0.910], [-5.460,0.450,-5.750], [-0.330,0.230,1.000]]), + (65, [[-20.750,-146.910,974.010], [1.230,-0.700,-6.940], [-1.580,-7.840,0.510], [0.080,-0.090,-0.690], [-7.590,1.430,-1.480], [0.460,0.350,5.770]]), + (66, [[-23.390,-146.100,967.330], [-6.320,1.650,-4.010], [-2.030,-7.760,0.010], [-0.160,0.070,0.360], [-4.040,1.070,6.800], [4.830,-0.400,4.280]]), + (67, [[-30.600,-144.330,967.780], [-6.690,2.040,2.190], [-1.930,-7.690,1.270], [0.050,0.000,0.440], [2.650,0.580,7.550], [3.030,-0.350,0.340]]), + (68, [[-36.170,-142.250,971.340], [-6.590,1.940,2.270], [-1.940,-7.730,1.010], [0.040,-0.010,0.090], [2.700,0.310,7.560], [0.370,-0.020,-0.150]]), + (69, [[-43.400,-140.590,972.070], [-6.040,1.970,2.740], [-1.830,-7.710,1.480], [0.020,0.340,1.180], [3.470,0.560,7.230], [2.300,-0.410,-2.270]]), + (70, [[-47.620,-138.630,976.140], [-1.780,2.680,4.620], [-1.870,-7.070,3.390], [0.010,0.350,0.980], [7.300,-0.460,3.080], [1.720,-1.440,-3.710]]), + (71, [[-47.100,-135.980,980.160], [0.980,1.950,4.050], [-1.830,-6.900,3.760], [0.210,-0.140,-0.200], [7.550,-2.370,-0.680], [0.040,-0.760,-2.210]]), + (72, [[-45.780,-134.750,984.020], [1.920,1.940,5.580], [-1.460,-7.340,3.050], [-0.530,0.370,0.090], [7.430,-2.220,-1.790], [-0.240,0.260,1.070]]), + (73, [[-42.419,-130.149,990.122], [-1.920,7.780,7.360], [-3.780,-5.370,4.690], [-2.140,1.260,-0.060], [6.910,-1.720,3.610], [-3.470,2.540,4.150]]), + (74, [[-48.414,-118.983,992.238], [-8.280,6.980,-7.760], [-5.960,-5.080,1.790], [0.610,-1.110,-1.840], [-2.030,4.630,6.340], [-6.540,1.980,-0.430]]), + (75, [[-54.520,-122.570,980.900], [-5.100,0.460,-13.050], [-2.600,-7.660,0.750], [2.850,-1.090,0.850], [-7.020,2.660,2.840], [-2.860,-1.790,-2.310]]), + (76, [[-56.534,-121.929,967.273], [-3.400,-6.950,-12.830], [-2.036,-6.714,3.150], [-1.690,1.750,1.250], [-7.800,0.860,1.600], [1.210,-0.700,-4.510]]), + (77, [[-57.601,-134.069,961.014], [4.440,-11.120,-4.920], [-6.170,-3.970,3.410], [-1.800,0.340,-0.380], [-4.460,1.190,-6.700], [1.720,-0.860,-3.600]]), + (78, [[-53.650,-142.090,958.040], [8.150,-8.950,-3.450], [-4.950,-5.680,3.060], [2.040,-1.620,-0.110], [-3.750,-0.620,-7.230], [-0.920,-0.860,0.970]]), + (79, [[-43.780,-150.900,953.550], [6.860,-6.210,-10.820], [-1.570,-7.380,3.240], [0.100,-0.470,-1.480], [-6.930,-0.360,-4.180], [-0.500,1.880,6.120]]), + (80, [[-42.790,-151.920,940.920], [-10.160,7.350,-12.870], [-4.740,-6.680,-0.070], [-1.780,0.370,-1.940], [-4.810,3.350,5.710], [1.370,1.930,5.900]]), + (81, [[-59.560,-139.320,940.870], [-10.470,7.530,-10.550], [-4.670,-6.770,-0.210], [-0.780,0.740,0.770], [-4.390,2.820,6.370], [-0.630,1.740,-4.220]]), + (82, [[-61.190,-138.430,930.230], [-0.370,-2.040,-12.190], [-5.970,-5.520,1.110], [-0.860,0.960,0.960], [-5.640,5.920,-0.830], [0.650,-0.720,-6.690]]), + (83, [[-60.050,-143.370,918.840], [6.120,-9.410,-3.110], [-6.440,-4.780,1.790], [0.250,-0.370,-0.760], [-2.750,0.780,-7.780], [3.390,-3.100,-3.060]]), + (84, [[-54.810,-148.970,924.540], [7.070,-6.600,2.050], [-5.610,-6.050,-0.170], [0.760,-0.860,-0.330], [1.380,-1.050,-8.130], [-1.610,1.400,1.580]]), + (85, [[-48.000,-154.670,922.570], [3.540,-3.720,-7.480], [-4.830,-6.610,1.000], [1.210,-0.760,-0.140], [-5.850,3.580,-4.550], [-4.060,1.810,3.830]]), + (86, [[-49.390,-154.510,914.460], [0.270,0.350,-10.670], [-3.110,-7.640,-0.330], [1.860,-0.790,-0.480], [-7.540,3.070,-0.100], [1.640,-1.570,-0.540]]), + (87, [[-46.730,-154.010,904.000], [18.990,-1.890,-1.480], [-0.780,-8.190,0.400], [1.310,-0.300,0.500], [-0.670,-0.340,-8.190], [5.190,-2.310,-4.980]]), + (88, [[-31.900,-157.000,923.200], [20.270,-2.840,5.710], [-1.280,-8.040,0.540], [1.630,0.180,0.170], [2.100,-0.860,-7.850], [-3.210,-0.770,1.420]]), + (89, [[-17.040,-158.470,917.330], [10.690,1.600,-10.940], [1.940,-7.840,0.740], [0.870,0.010,-0.110], [-5.440,-1.880,-5.580], [-1.710,0.190,-0.090]]), + (90, [[-12.920,-154.880,905.590], [14.280,1.560,-5.120], [1.010,-8.000,0.370], [-0.980,-0.090,-0.580], [-2.650,-0.690,-7.580], [1.890,1.140,-1.150]]), + (91, [[0.790,-157.220,913.220], [17.050,-0.100,-3.500], [-0.160,-8.010,-0.530], [0.240,0.090,-0.240], [-1.610,0.550,-7.830], [0.100,0.160,0.010]]), + (92, [[11.370,-154.850,899.810], [20.470,4.340,-7.040], [1.620,-7.800,-0.100], [0.670,0.240,-0.620], [-2.500,-0.420,-7.540], [-1.600,0.070,0.920]]), + (93, [[35.280,-149.960,905.730], [15.010,5.710,-13.200], [0.800,-7.500,-2.330], [1.120,0.330,0.340], [-5.360,1.170,-5.590], [-1.050,-1.380,0.950]]), + (94, [[31.510,-148.900,893.070], [11.510,6.020,-14.640], [3.170,-7.130,-0.440], [1.650,0.510,0.450], [-5.440,-2.110,-5.150], [2.200,-0.030,-0.530]]), + (95, [[53.210,-142.180,892.150], [16.130,8.560,4.600], [3.960,-6.330,-2.130], [0.420,0.200,0.800], [0.580,2.810,-7.250], [3.440,1.000,-0.610]]), + (96, [[61.915,-135.512,899.756], [10.425,5.807,7.557], [4.220,-6.470,0.220], [-1.030,-0.530,1.150], [2.810,1.590,-7.040], [-2.200,-1.800,0.660]]), + (97, [[72.652,-131.499,906.138], [13.270,2.580,-11.410], [1.590,-7.520,0.150], [-0.630,-0.250,0.200], [-4.770,-1.120,-5.790], [-4.380,-1.930,4.880]]), + (98, [[70.933,-136.139,889.296], [-12.490,-8.250,-22.650], [3.260,-6.840,0.700], [0.840,0.360,-0.040], [-5.890,-2.380,4.110], [0.640,-0.370,7.040]]), + (99, [[47.820,-142.630,864.930], [-22.720,-8.470,-7.520], [2.750,-7.000,-0.430], [0.030,0.230,-1.270], [-1.940,-1.200,7.190], [5.330,1.350,0.110]]), + (100, [[33.710,-147.840,866.620], [-7.310,-5.020,5.800], [3.020,-6.590,-1.880], [-0.710,0.240,-1.450], [4.500,0.350,5.980], [2.350,2.560,-6.780]]), + (101, [[33.450,-149.550,870.080], [6.660,-2.670,8.620], [1.910,-6.380,-3.460], [-0.810,0.030,-0.860], [5.650,3.480,-3.300], [0.800,2.080,-6.770]]), + (102, [[48.500,-149.860,877.560], [8.440,-1.400,10.880], [1.840,-6.880,-2.310], [-0.550,-0.390,1.170], [5.590,2.820,-3.970], [-1.370,-2.160,5.890]]), + (103, [[49.170,-151.340,885.880], [-14.130,-2.760,6.710], [0.940,-7.250,-1.010], [-0.570,0.330,-0.410], [3.260,-0.510,6.640], [-3.090,-3.470,6.170]]), + (104, [[30.330,-151.820,877.700], [-17.160,1.530,-4.960], [0.920,-5.490,-4.890], [-1.510,-0.140,0.400], [-1.940,-4.930,5.180], [0.640,-0.130,0.130]]), + (105, [[16.360,-149.060,875.570], [-10.970,1.710,5.380], [-1.800,-6.980,-1.460], [-0.540,-0.730,1.970], [2.830,-2.080,6.450], [2.860,1.800,-0.060]]), + (106, [[11.690,-148.720,883.920], [-10.140,1.000,8.830], [-0.940,-7.280,-0.260], [0.660,-0.150,1.090], [4.710,-0.800,5.500], [-0.400,1.320,0.040]]), + (107, [[-3.830,-146.990,890.110], [-14.280,1.090,0.550], [-0.520,-7.220,0.830], [0.360,0.010,-0.260], [0.340,0.810,7.240], [-1.670,-0.060,0.660]]), + (108, [[-14.790,-146.520,886.710], [-10.850,0.220,0.510], [-0.160,-7.240,-0.380], [0.730,0.030,-0.300], [0.330,-0.390,7.230], [2.180,0.020,-0.940]]), + (109, [[-23.910,-146.550,890.530], [-7.400,-0.950,6.580], [0.980,-7.160,0.070], [-0.520,0.100,0.630], [4.680,0.690,5.370], [0.750,0.450,-0.150]]), + (110, [[-28.030,-148.180,898.370], [-13.610,2.900,3.800], [-1.230,-7.020,0.960], [-1.430,0.370,-0.840], [2.040,0.580,6.860], [-3.990,-0.650,0.170]]), + (111, [[-42.020,-140.320,889.270], [-9.930,7.700,-9.680], [-1.440,-6.120,-3.390], [0.840,-0.040,-0.890], [-5.330,-1.240,4.490], [-3.620,0.110,-4.100]]), + (112, [[-47.830,-133.820,880.590], [1.670,2.810,-9.020], [0.190,-6.800,-2.080], [0.020,-0.240,2.820], [-6.870,0.170,-1.220], [2.630,-0.650,-5.170]]), + (113, [[-43.360,-134.640,876.970], [7.370,-1.120,-1.770], [-0.610,-6.830,1.800], [-0.490,-0.090,1.490], [-1.840,-1.590,-6.650], [3.370,-0.420,-3.090]]), + (114, [[-34.800,-135.760,878.370], [7.330,-0.800,-0.160], [-0.760,-7.020,0.280], [-0.510,0.020,-0.710], [-0.180,-0.260,-7.060], [-2.440,1.360,1.660]]), + (115, [[-29.320,-136.240,877.180], [3.390,-0.800,-5.310], [-1.570,-6.870,0.040], [-0.230,0.050,0.030], [-5.670,1.270,-3.820], [-3.220,0.720,3.410]]), + (116, [[-30.610,-136.870,870.770], [-0.250,-0.250,-5.290], [-1.190,-6.910,0.380], [0.280,-0.030,-0.030], [-6.790,1.180,0.270], [0.350,-0.330,-1.210]]), + (117, [[-30.230,-136.860,867.080], [2.790,-0.450,-3.890], [-0.940,-6.950,0.140], [0.330,-0.030,-0.120], [-5.570,0.670,-4.070], [3.300,-0.630,-3.480]]), + (118, [[-25.370,-137.760,865.060], [8.760,-0.500,1.850], [-0.440,-6.980,0.180], [0.240,0.000,-0.170], [1.430,-0.270,-6.840], [3.730,-0.350,-1.770]]), + (119, [[-17.010,-136.930,873.250], [9.540,-0.880,-1.350], [-0.710,-6.910,-0.470], [-0.790,0.170,0.250], [-0.920,0.560,-6.870], [-3.990,0.940,2.860]]), + (120, [[-14.620,-138.100,867.370], [2.470,-1.150,-8.780], [-1.880,-6.660,0.340], [1.250,0.410,-0.040], [-6.320,1.680,-1.990], [-1.180,0.210,1.020]]), + (121, [[-13.210,-138.670,858.260], [15.020,8.840,-1.860], [3.370,-5.940,-1.020], [3.020,0.320,-0.460], [-1.140,0.510,-6.800], [4.300,-0.760,-2.960]]), + (122, [[-2.010,-129.090,875.920], [14.730,5.570,5.540], [2.300,-6.430,0.360], [-3.380,0.090,1.420], [2.260,0.450,-6.450], [-4.260,0.280,1.850]]), + (123, [[5.710,-128.310,873.450], [4.220,-3.800,-6.920], [-2.330,-6.100,1.930], [1.540,1.120,0.790], [-5.490,0.890,-3.830], [-2.900,-1.920,4.890]]), + (124, [[3.860,-133.450,867.510], [-1.780,-5.980,-7.590], [4.850,-4.160,2.140], [1.960,0.650,1.010], [-4.520,-3.360,3.710], [0.300,-2.100,1.250]]), + (125, [[2.440,-139.690,858.800], [7.020,-5.190,-6.230], [0.110,-5.150,4.400], [-1.690,-0.890,0.210], [-5.060,-2.920,-3.280], [2.220,0.250,-4.490]]), + (126, [[11.980,-140.150,859.350], [17.700,2.250,-1.140], [0.950,-6.060,2.790], [1.390,-0.390,-2.080], [-0.040,-2.820,-6.130], [2.190,0.110,-1.390]]), + (127, [[35.300,-132.990,854.910], [8.740,9.550,-15.220], [4.050,-5.230,-0.960], [0.820,0.890,-2.820], [-4.430,-2.650,-4.200], [-1.330,-1.300,4.050]]), + (128, [[29.930,-128.550,843.920], [-12.950,5.120,-19.360], [3.680,-4.210,-3.570], [-1.410,0.000,-0.870], [-4.190,-4.930,1.490], [1.700,-0.300,5.110]]), + (129, [[9.390,-125.790,820.060], [-27.750,1.440,5.840], [-0.470,-6.580,-0.630], [-1.270,-0.920,1.780], [1.320,-0.720,6.460], [4.740,2.190,-0.360]]), + (130, [[4.650,-126.740,840.920], [-6.020,1.180,15.730], [0.130,-6.590,0.550], [-0.730,0.090,0.190], [6.110,0.310,2.320], [-2.110,0.210,1.570]]), + (131, [[0.040,-125.010,849.260], [-9.240,1.850,1.000], [-1.260,-6.450,0.320], [0.680,0.070,-0.540], [0.750,0.180,6.550], [-5.740,-0.820,-0.600]]), + (132, [[-4.440,-124.790,843.150], [-5.020,0.460,-16.660], [1.260,-6.430,-0.560], [1.980,0.080,-0.420], [-6.090,-1.340,1.790], [-4.270,-1.020,-2.570]]), + (133, [[-4.100,-124.240,817.800], [-14.820,-5.980,-12.690], [2.230,-6.130,0.290], [-0.080,-0.020,0.180], [-3.880,-1.170,5.070], [6.330,1.590,-0.020]]), + (134, [[-13.820,-128.400,823.840], [-7.490,-1.580,13.510], [1.550,-6.330,0.120], [-0.550,0.000,0.710], [5.490,1.400,3.200], [4.920,1.220,-2.010]]), + (135, [[-15.540,-126.400,839.810], [-2.260,3.630,12.780], [1.060,-6.110,1.920], [-1.860,0.050,-0.360], [6.210,1.310,0.730], [-0.950,-1.430,1.430]]), + (136, [[-17.860,-122.190,848.910], [-6.970,2.290,6.400], [-1.900,-6.170,0.140], [0.210,-0.110,-0.730], [4.060,-1.150,4.850], [-5.500,-0.820,1.290]]), + (137, [[-24.460,-122.950,849.040], [-11.050,-2.260,-14.690], [1.030,-6.350,0.200], [1.600,-0.050,0.470], [-5.050,-0.700,3.900], [-6.400,0.950,-0.750]]), + (138, [[-23.980,-124.710,821.700], [-13.900,-3.450,-17.210], [-1.090,-5.980,2.080], [-0.110,-0.110,-0.760], [-4.880,2.110,3.530], [5.050,-0.430,0.870]]), + (139, [[-38.600,-127.220,820.180], [-12.580,-0.430,8.780], [-0.020,-6.390,-0.330], [-0.170,-0.020,-0.170], [3.670,-0.290,5.240], [4.860,-1.540,-2.070]]), + (140, [[-42.520,-125.650,832.780], [1.330,2.910,14.250], [-1.250,-6.100,1.370], [-0.030,0.210,1.190], [6.110,-1.310,-0.300], [1.080,-0.260,-3.490]]), + (141, [[-35.800,-121.920,845.730], [4.200,3.780,10.200], [0.010,-5.960,2.200], [-0.160,0.230,0.570], [5.880,-0.780,-2.130], [0.090,0.030,0.690]]), + (142, [[-33.620,-118.720,852.840], [0.500,3.010,6.470], [-0.930,-5.650,2.700], [-0.790,-0.030,-0.570], [6.150,-1.010,0.000], [-0.330,-0.030,2.500]]), + (143, [[-34.440,-116.110,858.280], [-2.640,1.810,5.040], [-1.710,-5.940,1.230], [0.580,-0.290,-1.410], [5.320,-0.890,3.110], [-1.830,0.370,2.710]]), + (144, [[-38.380,-115.330,862.170], [-6.050,-0.340,2.350], [0.220,-6.280,-0.340], [1.370,-0.090,-0.250], [2.280,-0.240,5.850], [-4.210,0.450,0.940]]), + (145, [[-44.500,-116.930,861.580], [-11.590,-3.810,-10.160], [1.110,-6.090,1.020], [0.440,0.120,0.610], [-4.130,0.030,4.700], [-4.540,0.050,-0.790]]), + (146, [[-51.780,-120.720,839.030], [-15.880,-5.450,-10.360], [1.830,-5.970,0.320], [-1.360,0.270,0.870], [-3.220,-0.700,5.310], [4.290,0.490,0.090]]), + (147, [[-64.650,-124.350,841.480], [-11.510,0.420,9.850], [0.150,-6.190,0.440], [-0.550,0.330,1.540], [3.970,0.430,4.630], [4.380,-0.520,-2.900]]), + (148, [[-69.370,-119.950,854.330], [5.110,4.210,16.620], [-1.330,-5.740,1.870], [0.690,0.270,0.730], [5.670,-1.740,-1.310], [0.560,-1.580,-4.180]]), + (149, [[-55.630,-118.570,867.170], [8.190,15.700,8.570], [-2.415,-2.636,3.160], [0.890,1.630,1.440], [4.280,-1.310,-1.700], [0.130,0.200,0.140]]), + (150, [[-52.380,-100.900,869.760], [4.760,24.010,12.610], [-3.169,0.219,3.447], [-0.280,-0.300,-1.610], [4.600,-0.510,-0.770], [-2.290,1.100,4.280]]), + (151, [[-41.730,-76.290,892.900], [-14.020,14.240,19.650], [-3.750,-3.589,-1.622], [3.240,-2.890,0.750], [1.930,-2.620,3.270], [-5.090,5.860,6.610]]), + (152, [[-60.630,-80.530,895.250], [-6.170,-10.100,-5.870], [2.660,0.730,-4.050], [2.380,0.990,-1.140], [3.310,-2.970,1.640], [2.380,0.990,-1.140]]) ] ), 'userAnnotationGroups': [ + { + '_AnnotationGroup': True, + 'dimension': 1, + 'identifierRanges': '1-150', + 'name': get_smallintestine_term('small intestine')[0], + 'ontId': get_smallintestine_term('small intestine')[1] + }, { '_AnnotationGroup': True, 'dimension': 1, @@ -863,11 +878,18 @@ class MeshType_3d_smallintestine1(Scaffold_base): (42, [[-6.30,0.50,-8.10], [-9.80,-1.20,0.50], [0.11,-1.06,-0.28], [0.58,-0.56,-0.12], [0.09,-0.27,1.07], [0.00,0.00,0.50]]), (43, [[-16.00,-0.70,-7.40], [-7.60,1.20,1.50], [-0.06,-1.00,-0.45], [-0.62,0.61,0.13], [0.31,-0.47,0.95], [0.00,0.00,0.50]]), (44, [[-20.50,2.30,-6.10], [3.50,7.20,-2.90], [-1.09,0.10,-0.10], [-0.21,0.77,-0.11], [-0.19,0.13,1.08], [0.00,0.00,0.50]]), - (45, [[-11.40,2.60,-10.10], [10.40,1.50,-0.20], [-0.09,0.56,-0.95], [0.49,0.10,-0.38], [-0.11,0.94,0.56], [0.00,0.00,0.50]]), + (45, [[-11.40,2.60,-10.10], [10.40,1.50,-0.20], [-0.09,0.56,-0.95], [0.49,0.10,-0.38], [-0.11,0.94,0.56], [0.00,0.00,0.50]]), (46, [[-3.80,4.20,-7.30], [3.50,0.90,2.70], [0.08,0.40,-1.02], [-0.19,-0.40,0.24], [-0.80,0.75,0.01], [0.00,0.00,0.50]]) ] ), 'userAnnotationGroups': [ + { + '_AnnotationGroup': True, + 'dimension': 1, + 'identifierRanges': '1-45', + 'name': get_smallintestine_term('small intestine')[0], + 'ontId': get_smallintestine_term('small intestine')[1] + }, { '_AnnotationGroup': True, 'dimension': 1, @@ -915,10 +937,10 @@ def getDefaultOptions(cls, parameterSetName='Default'): options = { 'Central path': copy.deepcopy(centralPathOption), 'Number of segments': 80, - 'Number of elements around': 8, + 'Number of elements around': 12, 'Number of elements along segment': 3, - 'Number of elements through wall': 4, - 'Wall thickness': 0.45, + 'Number of elements through wall': 1, + 'Wall thickness': 3.0, 'Mucosa relative thickness': 0.55, 'Submucosa relative thickness': 0.15, 'Circular muscle layer relative thickness': 0.25, @@ -932,9 +954,11 @@ def getDefaultOptions(cls, parameterSetName='Default'): } if 'Cattle 1' in parameterSetName: options['Number of segments'] = 400 + options['Number of elements around'] = 8 options['Wall thickness'] = 2.0 elif 'Mouse 1' in parameterSetName: options['Number of segments'] = 100 + options['Number of elements around'] = 8 options['Wall thickness'] = 0.1 return options @@ -1016,250 +1040,15 @@ def generateBaseMesh(cls, region, options): :param options: Dict containing options. See getDefaultOptions(). :return: list of AnnotationGroup, None """ - 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'] - 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']) - elementsCountAlong = int(elementsCountAlongSegment*segmentCount) - startPhase = 0.0 - - # Small intestine coordinates - lengthToDiameterRatio = 200 - wallThicknessToDiameterRatio = 0.15 - relativeThicknessListSmallIntestineCoordinates = [1.0 / elementsCountThroughWall - for n3 in range(elementsCountThroughWall)] - - firstNodeIdentifier = 1 - firstElementIdentifier = 1 - - # Central path - tmpRegion = region.createRegion() - centralPath.generate(tmpRegion) - tmpFieldmodule = tmpRegion.getFieldmodule() - tmpNodes = tmpFieldmodule.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES) - tmpCoordinates = tmpFieldmodule.findFieldByName('coordinates') - smallIntestineTermsAlong = [None, 'duodenum', 'jejunum', 'ileum'] - arcLengthOfGroupsAlong = [] - - for termName in smallIntestineTermsAlong: - tmpGroup = tmpFieldmodule.findFieldByName(termName).castGroup() if termName else None - tmpNodeset = tmpGroup.getNodesetGroup(tmpNodes) if tmpGroup else tmpNodes - - cxGroup, cd1Group, cd2Group, cd3Group, cd12Group, cd13Group = get_nodeset_path_field_parameters( - tmpNodeset, tmpCoordinates, - [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]) - 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 not termName: - cx = cxGroup - cd1 = cd1Group - cd2 = cd2Group - cd3 = cd3Group - cd12 = cd12Group - cd13 = cd13Group - - del tmpNodeset - del tmpGroup - - del tmpCoordinates - del tmpNodes - del tmpFieldmodule - 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) - - innerRadiusListCP = [vector.magnitude(c) for c in cd2] - dInnerRadiusListCP = [] - for n in range(len(innerRadiusListCP) - 1): - dInnerRadiusListCP.append(innerRadiusListCP[n + 1] - innerRadiusListCP[n]) - dInnerRadiusListCP.append(innerRadiusListCP[-1] - innerRadiusListCP[-2]) - innerRadiusList, dInnerRadiusList = interp.interpolateSampleCubicHermite( - innerRadiusListCP, dInnerRadiusListCP, 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(smallIntestineTermsAlong)): - 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 - - # Groups along small intestine - 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([ ]) - - # Groups through wall - longitudinalMuscleGroup = AnnotationGroup(region, - get_smallintestine_term( - "longitudinal muscle layer of small intestine")) - circularMuscleGroup = AnnotationGroup(region, - get_smallintestine_term("circular muscle layer of small intestine")) - submucosaGroup = AnnotationGroup(region, get_smallintestine_term("submucosa of small intestine")) - mucosaGroup = AnnotationGroup(region, get_smallintestine_term("mucosa of small intestine")) - - if elementsCountThroughWall == 1: - relativeThicknessList = [1.0] - annotationGroupsThroughWall = [[]] - else: - relativeThicknessList = [mucosaRelThickness, submucosaRelThickness, - circularRelThickness, longitudinalRelThickness] - annotationGroupsThroughWall = [[mucosaGroup], [submucosaGroup], - [circularMuscleGroup], [longitudinalMuscleGroup]] - - xExtrude = [] - d1Extrude = [] - d2Extrude = [] - d3UnitExtrude = [] - - # Create object - smallIntestineSegmentTubeMeshInnerPoints = CylindricalSegmentTubeMeshInnerPoints( - elementsCountAround, elementsCountAlongSegment, segmentLength, - wallThickness, innerRadiusList, 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) - - # 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.extrudeSurfaceCoordinates(xExtrude, d1Extrude, - d2Extrude, d3UnitExtrude, [wallThickness]*(elementsCountAlong+1), relativeThicknessList, - elementsCountAround, elementsCountAlong, elementsCountThroughWall, transitElementList, outward=False) - - flatWidthList, xiList = smallIntestineSegmentTubeMeshInnerPoints.getFlatWidthAndXiList() - - # Create flat coordinates - xFlat, d1Flat, d2Flat = tubemesh.createFlatCoordinates( - xiList, flatWidthList, length, wallThickness, relativeThicknessList, elementsCountAround, - elementsCountAlong, elementsCountThroughWall, transitElementList) - - # Create small intestine coordinates - xSmallIntestine, d1SmallIntestine, d2SmallIntestine = \ - tubemesh.createOrganCoordinates(xiList, relativeThicknessListSmallIntestineCoordinates, - lengthToDiameterRatio, wallThicknessToDiameterRatio, - elementsCountAround, elementsCountAlong, elementsCountThroughWall, - transitElementList) + nextNodeIdentifier = 1 + nextElementIdentifier = 1 + smallIntestineTermsAlong = ['small intestine', 'duodenum', 'jejunum', 'ileum'] + geometricCentralPath = options['Central path'] + geometricCentralPath = SmallIntestineCentralPath(region, geometricCentralPath, smallIntestineTermsAlong) - # Create nodes and elements - nextNodeIdentifier, nextElementIdentifier, annotationGroups = tubemesh.createNodesAndElements( - region, xList, d1List, d2List, d3List, xFlat, d1Flat, d2Flat, - xSmallIntestine, d1SmallIntestine, d2SmallIntestine, "small intestine coordinates", - elementsCountAround, elementsCountAlong, elementsCountThroughWall, - annotationGroupsAround, annotationGroupsAlong, annotationGroupsThroughWall, - firstNodeIdentifier, firstElementIdentifier, useCubicHermiteThroughWall, useCrossDerivatives, - closedProximalEnd=False) + annotationGroups, nextNodeIdentifier, nextElementIdentifier = \ + createSmallIntestineMesh3d(region, options, geometricCentralPath, nextNodeIdentifier, + nextElementIdentifier, flatCoordinates=True, materialCoordinates=True)[0:3] return annotationGroups, None @@ -1315,3 +1104,328 @@ def defineFaceAnnotations(cls, region, options, annotationGroups): "luminal surface of duodenum")) duodenumLuminal.getMeshGroup(mesh2d).addElementsConditional(is_duodenumLuminal) +def createSmallIntestineMesh3d(region, options, centralPath, nextNodeIdentifier, nextElementIdentifier, + flatCoordinates=False, materialCoordinates=False, nodeIdProximal=[], + xProximal=[], d1Proximal=[], d2Proximal=[], d3Proximal=[], arclengthCPProximal=0.0): + """ + Generates a small intestine scaffold in the region using a central path and parameter options. + :param region: Region to create elements in. + :param options: Parameter options for small intestine scaffold. + :param centralPath: Central path describing path of small intestine. + :param nextNodeIdentifier: Next node identifier to use. + :param nextElementIdentifier: Next element identifier to use. + :param flatCoordinates: Create flat coordinates if True. + :param nodeIdProximal, xProximal, d1Proximal, d2Proximal, d3Proximal: Identifier, coordinates and derivatives of + nodes to use on proximal end of small intestine. + :param arclengthCPProximal: Arc length of central path in the element leading up to the start of the small + intestine. + :param materialCoordinates: Create material coordinates if True. + :return annotationGroups, nextNodeIdentifier, nextElementIdentifier, nodesIdDistal, xDistal, d1Distal, d2Distal, + d3Distal, xNext, d2Next + """ + 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'] + 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']) + elementsCountAlong = int(elementsCountAlongSegment*segmentCount) + startPhase = 0.0 + + # Small intestine coordinates + lengthToDiameterRatio = 200 + wallThicknessToDiameterRatio = 0.15 + relativeThicknessListSmallIntestineCoordinates = [1.0 / elementsCountThroughWall + for n3 in range(elementsCountThroughWall)] + + smallIntestineTermsAlong = ['small intestine', 'duodenum', 'jejunum', 'ileum'] + + centralPathLength = centralPath.arcLengthOfGroupsAlong[0] + cx = centralPath.cxGroups[0] + cd1 = centralPath.cd1Groups[0] + cd2 = centralPath.cd2Groups[0] + cd12 = centralPath.cd12Groups[0] + arcLengthOfGroupsAlong = centralPath.arcLengthOfGroupsAlong + + # 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 + startLength = 0.0 + lengthFraction = 1.0 + if xProximal: + startLength = arclengthCPProximal + lengthFraction = 0.5 + sx, sd1, se, sxi, ssf = interp.sampleCubicHermiteCurves(cx, cd1, elementsCountAlongSegment*segmentCount, + addLengthStart=0.5*startLength, + lengthFractionStart=lengthFraction) + sd2, sd12 = interp.interpolateSampleCubicHermite(cd2, cd12, se, sxi, ssf) + + outerRadiusListCP = [vector.magnitude(c) for c in cd2] + dOuterRadiusListCP = [] + for n in range(len(outerRadiusListCP) - 1): + dOuterRadiusListCP.append(outerRadiusListCP[n + 1] - outerRadiusListCP[n]) + dOuterRadiusListCP.append(outerRadiusListCP[-1] - outerRadiusListCP[-2]) + outerRadiusList, dOuterRadiusList = interp.interpolateSampleCubicHermite( + outerRadiusListCP, dOuterRadiusListCP, se, sxi, ssf) + + elementAlongLength = centralPathLength / elementsCountAlong + + elementsCountAlongGroups = [] + groupLength = 0.0 + e = 0 + elementsCount = 1 + length = elementAlongLength + for i in range(1, len(smallIntestineTermsAlong)): + 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 + + # Groups along small intestine + 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([ ]) + + # Groups through wall + longitudinalMuscleGroup = AnnotationGroup(region, + get_smallintestine_term( + "longitudinal muscle layer of small intestine")) + circularMuscleGroup = AnnotationGroup(region, + get_smallintestine_term("circular muscle layer of small intestine")) + submucosaGroup = AnnotationGroup(region, get_smallintestine_term("submucosa of small intestine")) + mucosaGroup = AnnotationGroup(region, get_smallintestine_term("mucosa of small intestine")) + + if elementsCountThroughWall == 1: + relativeThicknessList = [1.0] + annotationGroupsThroughWall = [[]] + else: + relativeThicknessList = [mucosaRelThickness, submucosaRelThickness, + circularRelThickness, longitudinalRelThickness] + annotationGroupsThroughWall = [[mucosaGroup], [submucosaGroup], + [circularMuscleGroup], [longitudinalMuscleGroup]] + + xExtrude = [] + d1Extrude = [] + d2Extrude = [] + d3UnitExtrude = [] + + # Create object + smallIntestineSegmentTubeMeshOuterPoints = CylindricalSegmentTubeMeshOuterPoints( + elementsCountAround, elementsCountAlongSegment, segmentLength, + wallThickness, outerRadiusList, startPhase) + + for nSegment in range(segmentCount): + # Create outer points + xOuter, d1Outer, d2Outer, transitElementList, segmentAxis, radiusAlongSegmentList = \ + smallIntestineSegmentTubeMeshOuterPoints.getCylindricalSegmentTubeMeshOuterPoints(nSegment) + + # Project reference point for warping onto central path + start = nSegment*elementsCountAlongSegment + end = (nSegment + 1)*elementsCountAlongSegment + 1 + sxRefList, sd1RefList, sd2ProjectedListRef, zRefList = \ + tubemesh.getPlaneProjectionOnCentralPath(xOuter, elementsCountAround, elementsCountAlongSegment, + segmentLength, sx[start:end], sd1[start:end], sd2[start:end], + sd12[start:end]) + + # Warp segment points + xWarpedList, d1WarpedList, d2WarpedList, d3WarpedUnitList = tubemesh.warpSegmentPoints( + xOuter, d1Outer, d2Outer, segmentAxis, sxRefList, sd1RefList, sd2ProjectedListRef, + elementsCountAround, elementsCountAlongSegment, zRefList) + + # 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, localIdxDistal, xDistal, d1Distal, d2Distal, d3Distal = \ + tubemesh.extrudeSurfaceCoordinates(xExtrude, d1Extrude, d2Extrude, d3UnitExtrude, + [wallThickness]*(elementsCountAlong+1), relativeThicknessList, + elementsCountAround, elementsCountAlong, elementsCountThroughWall, + transitElementList, outward=False, xProximal=xProximal, + d1Proximal=d1Proximal, d2Proximal=d2Proximal, d3Proximal=d3Proximal) + + flatWidthList, xiList = smallIntestineSegmentTubeMeshOuterPoints.getFlatWidthAndXiList() + + # Create flat coordinates + if flatCoordinates: + xFlat, d1Flat, d2Flat = tubemesh.createFlatCoordinates( + xiList, flatWidthList, length, wallThickness, relativeThicknessList, elementsCountAround, + elementsCountAlong, elementsCountThroughWall, transitElementList) + else: + xFlat = d1Flat = d2Flat = [] + + # Create small intestine coordinates + if materialCoordinates: + xSmallIntestine, d1SmallIntestine, d2SmallIntestine = \ + tubemesh.createOrganCoordinates(xiList, relativeThicknessListSmallIntestineCoordinates, + lengthToDiameterRatio, wallThicknessToDiameterRatio, + elementsCountAround, elementsCountAlong, elementsCountThroughWall, + transitElementList) + else: + xSmallIntestine = d1SmallIntestine = d2SmallIntestine = [] + + # Create nodes and elements + nextNodeIdentifier, nextElementIdentifier, annotationGroups, nodesIdDistal = \ + tubemesh.createNodesAndElements(region, xList, d1List, d2List, d3List, xFlat, d1Flat, d2Flat, xSmallIntestine, + d1SmallIntestine, d2SmallIntestine, "small intestine coordinates", + elementsCountAround, elementsCountAlong, elementsCountThroughWall, + annotationGroupsAround, annotationGroupsAlong, annotationGroupsThroughWall, + nextNodeIdentifier, nextElementIdentifier, useCubicHermiteThroughWall, + useCrossDerivatives, closedProximalEnd=False, localIdxDistal=localIdxDistal, + nodeIdProximal=nodeIdProximal) + + xNext = [] + d2Next = [] + for n3 in range(elementsCountThroughWall + 1): + xNextAround = [] + d2NextAround = [] + for n1 in range(elementsCountAround): + n = elementsCountAround * (elementsCountThroughWall + 1) + elementsCountAround * n3 + n1 + xNextAround.append(xList[n]) + d2NextAround.append(d2List[n]) + xNext.append(xNextAround) + d2Next.append(d2NextAround) + + return annotationGroups, nextNodeIdentifier, nextElementIdentifier, nodesIdDistal, xDistal, d1Distal, d2Distal, \ + d3Distal, xNext, d2Next + +class SmallIntestineCentralPath: + """ + Generates sampled central path for small intestine scaffold. + """ + def __init__(self, region, centralPath, termsAlong=[None]): + """ + :param region: Zinc region to define model in. + :param centralPath: Central path subscaffold from meshtype_1d_network_layout1 + :param termsAlong: Annotation terms along length of central path + """ + # Extract length of each group along small intestine from central path + cxGroups = [] + cd1Groups = [] + cd2Groups = [] + cd3Groups = [] + cd12Groups = [] + cd13Groups = [] + + tmpRegion = region.createRegion() + centralPath.generate(tmpRegion) + tmpFieldmodule = tmpRegion.getFieldmodule() + tmpNodes = tmpFieldmodule.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES) + tmpCoordinates = tmpFieldmodule.findFieldByName('coordinates') + arcLengthOfGroupsAlong = [] + + for termName in termsAlong: + tmpGroup = tmpFieldmodule.findFieldByName(termName).castGroup() if termName else None + tmpNodeset = tmpGroup.getNodesetGroup(tmpNodes) if tmpGroup else tmpNodes + + cxGroup, cd1Group, cd2Group, cd3Group, cd12Group, cd13Group = get_nodeset_path_field_parameters( + tmpNodeset, tmpCoordinates, + [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]) + + 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 termName == "small intestine": + cxGroups.append(cxGroup) + cd1Groups.append(cd1Group) + cd2Groups.append(cd2Group) + cd3Groups.append(cd3Group) + cd12Groups.append(cd12Group) + cd13Groups.append(cd13Group) + + del tmpNodeset + del tmpGroup + + del tmpCoordinates + del tmpNodes + del tmpFieldmodule + del tmpRegion + + self.arcLengthOfGroupsAlong = arcLengthOfGroupsAlong + self.cxGroups = cxGroups + self.cd1Groups = cd1Groups + self.cd2Groups = cd2Groups + self.cd3Groups = cd3Groups + self.cd12Groups = cd12Groups + self.cd13Groups = cd13Groups diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py index 0e3f00fe..c271910c 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py @@ -72,12 +72,19 @@ class MeshType_3d_stomach1(Scaffold_base): ]), 'userAnnotationGroups': [ + { + '_AnnotationGroup': True, + 'dimension': 1, + 'identifierRanges': '1-14', + 'name': get_stomach_term('stomach')[0], + 'ontId': get_stomach_term('stomach')[1] + }, { '_AnnotationGroup': True, 'dimension': 1, 'identifierRanges': '1-2', - 'name': get_esophagus_term('esophagus')[0], - 'ontId': get_esophagus_term('esophagus')[1] + 'name': get_stomach_term('esophagus part of stomach')[0], + 'ontId': get_stomach_term('esophagus part of stomach')[1] }, { '_AnnotationGroup': True, @@ -111,8 +118,8 @@ class MeshType_3d_stomach1(Scaffold_base): '_AnnotationGroup': True, 'dimension': 1, 'identifierRanges': '14', - 'name': get_smallintestine_term('duodenum')[0], - 'ontId': get_smallintestine_term('duodenum')[1] + 'name': get_stomach_term('duodenum part of stomach')[0], + 'ontId': get_stomach_term('duodenum part of stomach')[1] }] }), 'Human 2': ScaffoldPackage(MeshType_1d_network_layout1, { @@ -121,30 +128,37 @@ class MeshType_3d_stomach1(Scaffold_base): }, 'meshEdits': exnode_string_from_nodeset_field_parameters( [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ - (1, [[11.530,-113.400,1127.840], [3.973,-1.388,-5.231], [5.366,2.230,1.829], [-8.397,13.092,24.878], [1.554,-5.290,1.584], [-0.807,-7.995,7.596]]), - (2, [[23.420,-116.600,1119.050], [26.718,-4.658,-7.157], [4.014,6.257,10.913], [10.037,1.800,8.968], [-0.216,-11.420,6.626], [-2.926,-13.889,10.204]]), - (3, [[62.940,-120.610,1122.780], [[0.448,-8.598,-13.993],[50.547,-3.248,14.121]], [[39.520,-4.011,3.729],[-2.448,7.606,10.512]], [[3.190,-0.590,-0.290],[3.190,-0.590,-0.290]], [[-5.970,-37.560,22.890],[-2.692,-10.763,7.161]], [[-0.100,-1.220,0.550],[-0.100,-1.220,0.550]]]), - (4, [[61.590,-101.050,1152.900], [0.442,-2.863,-3.864], [11.300,-0.230,1.460], [15.701,-3.029,2.832], [-0.850,-7.440,5.420], [-5.756,-22.456,14.946]]), - (5, [[61.990,-104.310,1148.310], [0.358,-3.656,-5.314], [24.170,-2.490,3.340], [10.039,-1.491,0.928], [-4.920,-25.060,16.910], [-2.384,-12.784,8.034]]), - (6, [[62.280,-108.340,1142.260], [0.251,-4.603,-7.040], [30.560,-2.990,3.040], [5.720,-0.448,-0.071], [-5.130,-31.610,20.490], [-0.206,-5.098,2.599]]), - (7, [[62.470,-113.500,1134.220], [0.315,-6.148,-9.733], [35.400,-3.370,3.270], [4.541,-0.488,0.325], [-5.330,-34.800,21.800], [-0.383,-3.012,1.219]]), - (8, [[63.320,-130.670,1106.220], [-0.184,-10.489,-16.967], [41.370,-4.520,2.350], [0.495,-2.468,-4.032], [-5.290,-36.560,22.660], [0.257,0.762,0.246]]), - (9, [[62.540,-141.560,1088.910], [-4.623,-11.401,-18.639], [40.430,-9.060,-4.490], [-4.947,-4.939,-8.800], [-5.480,-36.050,23.410], [0.770,0.606,1.053]]), - (10, [[53.670,-152.880,1069.820], [-15.955,-9.817,-16.265], [30.765,-14.468,-15.598], [-14.187,-3.408,-7.577], [-3.580,-35.330,24.820], [2.031,4.346,-1.238]]), - (11, [[32.230,-159.890,1058.560], [-22.295,-4.560,-7.466], [11.809,-15.766,-19.452], [-15.401,0.331,-0.624], [-1.410,-27.160,20.790], [1.197,8.617,-5.083]]), - (12, [[10.360,-162.050,1054.830], [-21.098,1.023,-0.272], [-0.460,-14.000,-17.230], [-8.754,2.830,4.764], [-1.070,-18.150,14.780], [-1.003,7.491,-3.260]]), - (13, [[-8.740,-158.280,1057.630], [-17.280,7.584,3.006], [-6.110,-10.230,-10.220], [-2.634,4.430,6.290], [-3.260,-12.000,13.950], [-1.380,7.085,-2.660]]), - (14, [[-23.259,-147.625,1060.642], [-11.148,12.211,0.633], [-5.944,-5.188,-4.599], [-0.696,3.015,1.714], [-3.887,-4.046,9.590], [-2.080,5.832,-2.463]]), - (15, [[-30.740,-135.240,1059.320], [-3.618,11.918,-3.109], [-7.329,-3.791,-6.004], [-2.074,-0.221,-4.524], [-7.127,0.091,8.642], [-4.400,2.442,0.567]]) + (1, [[11.750,-111.874,1127.887], [7.636,-5.715,-7.930], [5.678,1.265,4.556], [-8.397,13.092,24.878], [-0.708,-3.530,1.862], [-0.807,-7.995,7.596]]), + (2, [[23.789,-117.922,1120.040], [26.354,-6.724,-6.404], [4.223,6.205,10.864], [10.037,1.800,8.968], [-1.192,-11.215,6.869], [-2.926,-13.889,10.204]]), + (3, [[63.704,-120.094,1123.374], [[0.500,-9.138,-13.405],[50.106,1.267,11.056]], [[37.742,-3.477,3.778],[-2.509,7.605,10.499]], [[3.190,-0.590,-0.290],[3.190,-0.590,-0.290]], [[-5.452,-34.121,23.056],[-1.379,-10.790,7.486]], [[-0.100,-1.220,0.550],[-0.100,-1.220,0.550]]]), + (4, [[61.247,-99.931,1152.681], [0.346,-2.728,-3.873], [11.320,-0.365,1.269], [15.701,-3.029,2.832], [-0.653,-5.931,4.119], [-5.756,-22.456,14.946]]), + (5, [[61.743,-103.510,1147.760], [0.413,-3.592,-5.311], [24.159,-2.387,3.493], [10.039,-1.491,0.928], [-2.982,-15.339,10.142], [-2.384,-12.784,8.034]]), + (6, [[62.381,-107.527,1141.785], [0.249,-4.737,-7.073], [30.559,-2.973,3.067], [5.720,-0.448,-0.071], [-3.839,-23.420,15.550], [-0.206,-5.098,2.599]]), + (7, [[62.800,-113.150,1133.665], [0.116,-6.546,-9.651], [35.408,-3.630,2.888], [4.541,-0.488,0.325], [-4.677,-29.659,20.061], [-0.383,-3.012,1.219]]), + (8, [[64.339,-131.197,1107.233], [0.086,-11.682,-16.915], [39.201,-3.705,2.758], [0.490,-2.470,-4.030], [-5.108,-35.712,24.638], [0.260,0.760,0.250]]), + (9, [[62.912,-143.954,1088.811], [-5.216,-12.408,-17.967], [34.623,-8.161,-4.415], [-4.950,-4.940,-8.800], [-4.917,-34.532,25.275], [0.770,0.610,1.050]]), + (10, [[53.361,-155.397,1072.006], [-15.833,-9.775,-15.486], [25.117,-13.916,-16.896], [-14.190,-3.410,-7.580], [-2.355,-30.712,21.794], [2.030,4.350,-1.240]]), + (11, [[32.110,-162.230,1059.680], [-22.173,-3.681,-8.142], [10.067,-16.126,-20.126], [-15.400,0.330,-0.620], [-2.559,-23.629,17.653], [1.200,8.620,-5.080]]), + (12, [[10.560,-162.970,1055.650], [-20.956,2.164,-0.908], [-0.696,-13.976,-17.241], [-8.750,2.830,4.760], [-2.502,-18.048,14.732], [-1.000,7.490,-3.260]]), + (13, [[-8.740,-158.280,1057.630], [-17.269,8.027,2.588], [-6.253,-10.164,-10.200], [-2.630,4.430,6.290], [-3.442,-11.913,13.981], [-1.380,7.080,-2.660]]), + (14, [[-23.260,-147.620,1060.640], [-11.787,11.369,1.720], [-5.807,-5.321,-4.621], [-0.700,3.020,1.710], [-3.207,-4.764,9.515], [-2.080,5.830,-2.460]]), + (15, [[-32.281,-136.261,1061.249], [-6.125,11.114,-0.493], [-5.735,-3.374,-4.823], [-2.070,-0.220,-4.520], [-4.630,-2.238,7.071], [-4.400,2.440,0.570]]) ]), 'userAnnotationGroups': [ + { + '_AnnotationGroup': True, + 'dimension': 1, + 'identifierRanges': '1-14', + 'name': get_stomach_term('stomach')[0], + 'ontId': get_stomach_term('stomach')[1] + }, { '_AnnotationGroup': True, 'dimension': 1, 'identifierRanges': '1-2', - 'name': get_esophagus_term('esophagus')[0], - 'ontId': get_esophagus_term('esophagus')[1] + 'name': get_stomach_term('esophagus part of stomach')[0], + 'ontId': get_stomach_term('esophagus part of stomach')[1] }, { '_AnnotationGroup': True, @@ -178,8 +192,8 @@ class MeshType_3d_stomach1(Scaffold_base): '_AnnotationGroup': True, 'dimension': 1, 'identifierRanges': '14', - 'name': get_smallintestine_term('duodenum')[0], - 'ontId': get_smallintestine_term('duodenum')[1] + 'name': get_stomach_term('duodenum part of stomach')[0], + 'ontId': get_stomach_term('duodenum part of stomach')[1] }] }), 'Mouse 1': ScaffoldPackage(MeshType_1d_network_layout1, { @@ -205,12 +219,19 @@ class MeshType_3d_stomach1(Scaffold_base): ]), 'userAnnotationGroups': [ + { + '_AnnotationGroup': True, + 'dimension': 1, + 'identifierRanges': '1-13', + 'name': get_stomach_term('stomach')[0], + 'ontId': get_stomach_term('stomach')[1] + }, { '_AnnotationGroup': True, 'dimension': 1, 'identifierRanges': '1-2', - 'name': get_esophagus_term('esophagus')[0], - 'ontId': get_esophagus_term('esophagus')[1] + 'name': get_stomach_term('esophagus part of stomach')[0], + 'ontId': get_stomach_term('esophagus part of stomach')[1] }, { '_AnnotationGroup': True, @@ -244,8 +265,8 @@ class MeshType_3d_stomach1(Scaffold_base): '_AnnotationGroup': True, 'dimension': 1, 'identifierRanges': '13', - 'name': get_smallintestine_term('duodenum')[0], - 'ontId': get_smallintestine_term('duodenum')[1] + 'name': get_stomach_term('duodenum part of stomach')[0], + 'ontId': get_stomach_term('duodenum part of stomach')[1] }] }), 'Pig 1': ScaffoldPackage(MeshType_1d_network_layout1, { @@ -270,12 +291,19 @@ class MeshType_3d_stomach1(Scaffold_base): ]), 'userAnnotationGroups': [ + { + '_AnnotationGroup': True, + 'dimension': 1, + 'identifierRanges': '1-12', + 'name': get_stomach_term('stomach')[0], + 'ontId': get_stomach_term('stomach')[1] + }, { '_AnnotationGroup': True, 'dimension': 1, 'identifierRanges': '1-2', - 'name': get_esophagus_term('esophagus')[0], - 'ontId': get_esophagus_term('esophagus')[1] + 'name': get_stomach_term('esophagus part of stomach')[0], + 'ontId': get_stomach_term('esophagus part of stomach')[1] }, { '_AnnotationGroup': True, @@ -309,8 +337,8 @@ class MeshType_3d_stomach1(Scaffold_base): '_AnnotationGroup': True, 'dimension': 1, 'identifierRanges': '12', - 'name': get_smallintestine_term('duodenum')[0], - 'ontId': get_smallintestine_term('duodenum')[1] + 'name': get_stomach_term('duodenum part of stomach')[0], + 'ontId': get_stomach_term('duodenum part of stomach')[1] }] }), 'Rat 1': ScaffoldPackage(MeshType_1d_network_layout1, { @@ -337,12 +365,19 @@ class MeshType_3d_stomach1(Scaffold_base): ]), 'userAnnotationGroups': [ + { + '_AnnotationGroup': True, + 'dimension': 1, + 'identifierRanges': '1-14', + 'name': get_stomach_term('stomach')[0], + 'ontId': get_stomach_term('stomach')[1] + }, { '_AnnotationGroup': True, 'dimension': 1, 'identifierRanges': '1-2', - 'name': get_esophagus_term('esophagus')[0], - 'ontId': get_esophagus_term('esophagus')[1] + 'name': get_stomach_term('esophagus part of stomach')[0], + 'ontId': get_stomach_term('esophagus part of stomach')[1] }, { '_AnnotationGroup': True, @@ -376,8 +411,8 @@ class MeshType_3d_stomach1(Scaffold_base): '_AnnotationGroup': True, 'dimension': 1, 'identifierRanges': '14', - 'name': get_smallintestine_term('duodenum')[0], - 'ontId': get_smallintestine_term('duodenum')[1] + 'name': get_stomach_term('duodenum part of stomach')[0], + 'ontId': get_stomach_term('duodenum part of stomach')[1] }] }), 'Material': ScaffoldPackage(MeshType_1d_network_layout1, { @@ -407,12 +442,19 @@ class MeshType_3d_stomach1(Scaffold_base): ]), 'userAnnotationGroups': [ + { + '_AnnotationGroup': True, + 'dimension': 1, + 'identifierRanges': '1-17', + 'name': get_stomach_term('stomach')[0], + 'ontId': get_stomach_term('stomach')[1] + }, { '_AnnotationGroup': True, 'dimension': 1, 'identifierRanges': '1-2', - 'name': get_esophagus_term('esophagus')[0], - 'ontId': get_esophagus_term('esophagus')[1] + 'name': get_stomach_term('esophagus part of stomach')[0], + 'ontId': get_stomach_term('esophagus part of stomach')[1] }, { '_AnnotationGroup': True, @@ -446,8 +488,8 @@ class MeshType_3d_stomach1(Scaffold_base): '_AnnotationGroup': True, 'dimension': 1, 'identifierRanges': '16-17', - 'name': get_smallintestine_term('duodenum')[0], - 'ontId': get_smallintestine_term('duodenum')[1] + 'name': get_stomach_term('duodenum part of stomach')[0], + 'ontId': get_stomach_term('duodenum part of stomach')[1] }] }), } @@ -631,8 +673,9 @@ def getDefaultOptions(cls, parameterSetName='Default'): 'Refine number of elements through wall': 1 } if 'Human 2' in parameterSetName: + options['Number of elements around duodenum'] = 12 options['Number of elements through wall'] = 1 - options['Wall thickness'] = 0.0525 * 101 + options['Wall thickness'] = 3.0 elif 'Mouse 1' in parameterSetName: options['Wall thickness'] = 0.05145 options['Mucosa relative thickness'] = 0.75 @@ -766,6 +809,8 @@ def updateSubScaffoldOptions(cls, options): ostiumSettings['Ostium wall thickness'] = wallThickness elementsCountThroughWall = options['Number of elements through wall'] ostiumSettings['Number of elements through wall'] = elementsCountThroughWall + ostiumSettings['Use linear through ostium wall'] = options['Use linear through wall'] + ostiumSettings['Use linear through vessel wall'] = options['Use linear through wall'] if elementsCountThroughWall == 1: ostiumSettings['Ostium wall relative thicknesses'] = [1.0] ostiumSettings['Vessel wall relative thicknesses'] = [1.0] @@ -794,8 +839,8 @@ def generateBaseMesh(cls, region, options): allAnnotationGroups = [] - stomachTermsAlong = [None, 'fundus of stomach', 'body of stomach', - 'pyloric antrum', 'pyloric canal', 'duodenum', 'esophagus'] + stomachTermsAlong = ['stomach', 'fundus of stomach', 'body of stomach', + 'pyloric antrum', 'pyloric canal', 'duodenum part of stomach', 'esophagus part of stomach'] # Geometric coordinates fm = region.getFieldmodule() @@ -806,7 +851,7 @@ def generateBaseMesh(cls, region, options): allAnnotationGroups, nextNodeIdentifier, nextElementIdentifier, elementsAlongGroups = \ createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotationGroups, centralPath=geometricCentralPath, - options=options, nodeIdentifier=1, elementIdentifier=1) + options=options, nodeIdentifier=1, elementIdentifier=1)[0:4] # Material coordinates stomach_coordinates = find_or_create_field_coordinates(fm, name="stomach coordinates") @@ -823,7 +868,7 @@ def generateBaseMesh(cls, region, options): allAnnotationGroupsMaterial, centralPath=materialCentralPath, options=options, nodeIdentifier=1, elementIdentifier=1, elementsAlongSections=elementsAlongGroups, - materialCoordinates=True)[:-1] + materialCoordinates=True)[:3] # Write two coordinates sir = tmp_region.createStreaminformationRegion() @@ -882,6 +927,7 @@ def generateBaseMesh(cls, region, options): return allAnnotationGroups, None + @classmethod def refineMesh(cls, meshrefinement, options): """ @@ -1174,11 +1220,13 @@ class StomachCentralPath: """ Generates sampled central path for stomach scaffold. """ - def __init__(self, region, centralPath, stomachTermsAlong=[None]): + def __init__(self, region, centralPath, stomachTermsAlong=[None], esoSegmentIdx=0, stomachSegmentIdx=[1,2]): """ :param region: Zinc region needed to create path region to define path in. :param centralPath: Central path subscaffold from meshtype_1d_network_layout1 :param stomachTermsAlong: Annotation terms along length of stomach + :param esoSegmentIdx: Segment index of esophagus branch. + :param stomachSegmentIdx: Segment index of the body of stomach. """ # Extract length of each group along stomach from central path arcLengthOfGroupsAlong = [] @@ -1203,27 +1251,36 @@ def __init__(self, region, centralPath, stomachTermsAlong=[None]): cd3Group = [] cd12Group = [] cd13Group = [] + stomachNodes = [] + esoNodes = [] + esoVersions = [] + lowerStomachNodes = [] + lowerStomachVersions = [] for termName in stomachTermsAlong: tmpGroup = tmpFieldmodule.findFieldByName(termName).castGroup() if termName else None tmpNodeset = tmpGroup.getNodesetGroup(tmpNodes) if tmpGroup else tmpNodes - if termName == "esophagus": - cxGroup, cd1Group, cd2Group, cd3Group, cd12Group, cd13Group = \ - get_nodeset_path_ordered_field_parameters(tmpNodeset, tmpCoordinates, - [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], - networkSegments[0].getNodeIdentifiers(), - networkSegments[0].getNodeVersions()) - elif termName is None: + if termName == "stomach": + nodeiterator = tmpNodeset.createNodeiterator() + node = nodeiterator.next() + while node.isValid(): + stomachNodes.append(node.getIdentifier()) + node = nodeiterator.next() + + for i in range(len(networkSegments[stomachSegmentIdx[1]].getNodeIdentifiers())): + if networkSegments[stomachSegmentIdx[1]].getNodeIdentifiers()[i] in stomachNodes: + lowerStomachNodes.append(networkSegments[stomachSegmentIdx[1]].getNodeIdentifiers()[i]) + lowerStomachVersions.append(networkSegments[stomachSegmentIdx[1]].getNodeVersions()[i]) + for i in range(2): cx, cd1, cd2, cd3, cd12, cd13 = get_nodeset_path_ordered_field_parameters( tmpNodeset, tmpCoordinates, [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], - networkSegments[i + 1].getNodeIdentifiers(), networkSegments[i + 1].getNodeVersions()) + (lowerStomachNodes if i else networkSegments[stomachSegmentIdx[0]].getNodeIdentifiers()), + (lowerStomachVersions if i else networkSegments[stomachSegmentIdx[0]].getNodeVersions())) cxGroup += cx[(1 if i else 0):] cd1Group += cd1[(1 if i else 0):] @@ -1240,6 +1297,19 @@ def __init__(self, region, centralPath, stomachTermsAlong=[None]): for n in range(len(cx) - 1): arcLengthToBranchPt += interp.getCubicHermiteArcLength(cx[n], cd1[n], cx[n + 1], cd1[n + 1]) + elif termName == "esophagus part of stomach": + for i in range(len(networkSegments[esoSegmentIdx].getNodeIdentifiers())): + if networkSegments[esoSegmentIdx].getNodeIdentifiers()[i] in stomachNodes: + esoNodes.append(networkSegments[esoSegmentIdx].getNodeIdentifiers()[i]) + esoVersions.append(networkSegments[esoSegmentIdx].getNodeVersions()[i]) + + cxGroup, cd1Group, cd2Group, cd3Group, cd12Group, cd13Group = \ + get_nodeset_path_ordered_field_parameters(tmpNodeset, tmpCoordinates, + [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], + esoNodes, esoVersions) + elif termName == "fundus of stomach": cxGroup, cd1Group, cd2Group, cd3Group, cd12Group, cd13Group = \ get_nodeset_path_ordered_field_parameters(tmpNodeset, tmpCoordinates, @@ -1329,7 +1399,8 @@ def findCurvatureAlongLine(nx, nd, radialVectors): def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotationGroups, centralPath, options, - nodeIdentifier, elementIdentifier, elementsAlongSections = [], materialCoordinates=False): + nodeIdentifier, elementIdentifier, elementsAlongSections = [], materialCoordinates=False, + nodeIdProximalEso=[], xProximalEso=[], d1ProximalEso=[], d2ProximalEso=[], d3ProximalEso=[]): """ Generates a stomach scaffold in the region using a central path and parameter options. :param region: Region to create elements in. @@ -1343,7 +1414,10 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio :param elementIdentifier: First element identifier. :param elementsAlongSections: Number of elements along each section. :param materialCoordinates: Create material coordinates if True. - :return allAnnotationGroups, elementsAlongSections + :param nodeIdProximalEso, xProximalEso, d1ProximalEso, d2ProximalEso, d3ProximalEso: Identifier, coordinates and + derivatives of nodes to use at the start of esophagus section joining to the stomach. + :return allAnnotationGroups, nextNodeIdentifier, nextElementIdentifier, elementsAlongSections, nodeIdxDistal, + xDistal, d1Distal, d2Distal, d3Distal, arclengthDuodenumCP, xPrev, d2Prev """ elementsCountAroundEso = options['Number of elements around esophagus'] elementsCountAroundDuod = options['Number of elements around duodenum'] @@ -1363,6 +1437,8 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio ostiumRadius = vector.magnitude(centralPath.cd2Groups[-1][1]) limitingRidge = options['Limiting ridge'] wallThickness = options['Wall thickness'] + GEJSettings['Use linear through ostium wall'] = options['Use linear through wall'] + GEJSettings['Use linear through vessel wall'] = options['Use linear through wall'] elementsCountAcrossCardia = 1 cardiaDiameterFactor = 1.4 # scale to ostium diameter @@ -1425,6 +1501,7 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio arcLengthRatioForGroupsFromFundusApex.append(arcLengthRatio) stomachGroup = AnnotationGroup(region, get_stomach_term("stomach")) + smallIntestineGroup = AnnotationGroup(region, get_smallintestine_term("small intestine")) fundusGroup = AnnotationGroup(region, get_stomach_term("fundus of stomach")) bodyGroup = AnnotationGroup(region, get_stomach_term("body of stomach")) antrumGroup = AnnotationGroup(region, get_stomach_term("pyloric antrum")) @@ -1435,7 +1512,7 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio [stomachGroup, bodyGroup], [stomachGroup, antrumGroup], [stomachGroup, pylorusGroup], - [stomachGroup, duodenumGroup]] + [smallIntestineGroup, duodenumGroup]] longitudinalMuscleGroup = AnnotationGroup(region, get_stomach_term("longitudinal muscle layer of stomach")) circularMuscleGroup = AnnotationGroup(region, get_stomach_term("circular muscle layer of stomach")) @@ -1731,12 +1808,14 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio d12Path = [cd2Eso[0], [0.0, 0.0, 0.0]] d13Path = [cd3Eso[0], [0.0, 0.0, 0.0]] - centralPathIleum = CustomCentralPath(xPath, d1Path, d2Path, d3Path, d12Path, d13Path) + centralPathEso = CustomCentralPath(xPath, d1Path, d2Path, d3Path, d12Path, d13Path) nextNodeIdentifier, nextElementIdentifier, (o1_x, o1_d1, o1_d2, o1_d3, o1_NodeId, o1_Positions) = \ - generateOstiumMesh(region, GEJSettings, trackSurfaceStomach, centralPathIleum, - nodeIdentifier, elementIdentifier, - vesselMeshGroups=[[stomachMeshGroup, esophagusMeshGroup, abdominalEsoMeshGroup]], + generateOstiumMesh(region, GEJSettings, trackSurfaceStomach, centralPathEso, + nodeIdentifier, elementIdentifier, nodeIdProximal=nodeIdProximalEso, + xProximal=xProximalEso, d1Proximal=d1ProximalEso, d2Proximal=d2ProximalEso, + d3Proximal=d3ProximalEso, + vesselMeshGroups=[[esophagusMeshGroup, abdominalEsoMeshGroup]], ostiumMeshGroups=[stomachMeshGroup, esophagogastricJunctionMeshGroup], wallAnnotationGroups=ostiumWallAnnotationGroups, coordinates=coordinates) @@ -1812,7 +1891,8 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio minElementsInSections = [4, 3, 2, 2, 1] excessElements = elementsCountAlong - sum(minElementsInSections) - diff = [quarterLengthSections[c] - targetLengthPerElement * minElementsInSections[c] for c in range(len(minElementsInSections))] + diff = [quarterLengthSections[c] - targetLengthPerElement * minElementsInSections[c] + for c in range(len(minElementsInSections))] for i in range(excessElements): maxIdx = max(range(len(diff)), key=diff.__getitem__) minElementsInSections[maxIdx] += 1 @@ -1820,6 +1900,7 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio elementsAlongSections = minElementsInSections totalElementsAlong = sum(elementsAlongSections) + arclengthDuodenumCP = arcLengthOfGroupsAlong[5]/elementsAlongSections[-1] xSampledAlong = [[] for n1 in range(elementsCountAroundDuod)] d1SampledAlong = [[] for n1 in range(elementsCountAroundDuod)] @@ -1881,7 +1962,8 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio nxR, nd1R, nd2R, nd3R = \ trackSurfaceStomach.resampleHermiteCurvePointsSmooth( nx, nd1, nd2, nd3, proportions, derivativeMagnitudeEnd= - vector.magnitude(d1EllipseAroundAll[sectionIdx[1]][elementsAroundQuarterDuod + elementsAroundHalfDuod]))[0:-1] + vector.magnitude( + d1EllipseAroundAll[sectionIdx[1]][elementsAroundQuarterDuod + elementsAroundHalfDuod]))[0:-1] for n in range(len(nxR)): xEllipseAroundAll[sectionIdx[1]][elementsAroundHalfDuod + 1 + n] = nxR[n] @@ -2343,6 +2425,14 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio nodeIdx = stomachStartNode idxMat = [] + xDistal = [] + d1Distal = [] + d2Distal = [] + d3Distal = [] + xPrev = [] + d2Prev = [] + nodeIdxDistal = [] + if elementsCountThroughWall > 1: thicknessProportionsUI = [0.0, mucosaRelThickness, submucosaRelThickness, circularRelThickness, longitudinalRelThickness, longitudinalRelThickness] @@ -2360,6 +2450,12 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio for n3 in range(elementsCountThroughWall + 1): xi3 = xi3List[n3] if elementsCountThroughWall > 1 else 1.0 / elementsCountThroughWall * n3 idxAround = [] + xDistalAround = [] + d1DistalAround = [] + d2DistalAround = [] + d3DistalAround = [] + nodeIdxDistalAround = [] + for n1 in range(len(xSampledAroundAlong[n2])): # Coordinates norm = vector.normalise(d3SampledAroundAlong[n2][n1]) @@ -2384,9 +2480,27 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio for c in norm] d3List.append(d3) + if n2 >= len(xSampledAroundAlong) - 2: + xDistalAround.append(x) + d1DistalAround.append(d1) + d2DistalAround.append(d2) + d3DistalAround.append(d3) + nodeIdxDistalAround.append(nodeIdx) + idxAround.append(nodeIdx) nodeIdx += 1 idxThroughWall.append(idxAround) + + if n2 == len(xSampledAroundAlong) - 2: + xPrev.append(xDistalAround) + d2Prev.append(d2DistalAround) + + if n2 == len(xSampledAroundAlong) - 1: + xDistal.append(xDistalAround) + d1Distal.append(d1DistalAround) + d2Distal.append(d2DistalAround) + d3Distal.append(d3DistalAround) + nodeIdxDistal.append(nodeIdxDistalAround) idxMat.append(idxThroughWall) nodeIdxGC = [] @@ -2623,7 +2737,9 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio elementtemplate1 = elementtemplateX # print(elementIdentifier) # 166 - elif (elementsAroundQuarterEso - 2) > 0 and annulusFundusOpenRingIdx <= e2 < annulusFundusOpenRingIdx + 2.0 * (elementsAroundQuarterEso - 2): + elif (elementsAroundQuarterEso - 2) > 0 and \ + annulusFundusOpenRingIdx <= e2 < annulusFundusOpenRingIdx + \ + 2.0 * (elementsAroundQuarterEso - 2): if e1 == elementsAroundHalfDuod - 2: scaleFactors = [-1.0] eft1 = eftfactory.createEftNoCrossDerivatives() @@ -2873,7 +2989,9 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio element = elementIter.next() allAnnotationGroups.append(nearLCGroup) - return allAnnotationGroups, nextNodeIdentifier, nextElementIdentifier, elementsAlongSections + return allAnnotationGroups, nextNodeIdentifier, nextElementIdentifier, elementsAlongSections, nodeIdxDistal, \ + xDistal, d1Distal, d2Distal, d3Distal, arclengthDuodenumCP, xPrev, d2Prev + class CustomCentralPath: """ diff --git a/src/scaffoldmaker/scaffolds.py b/src/scaffoldmaker/scaffolds.py index 52971183..e62e19fb 100644 --- a/src/scaffoldmaker/scaffolds.py +++ b/src/scaffoldmaker/scaffolds.py @@ -22,6 +22,7 @@ from scaffoldmaker.meshtypes.meshtype_3d_colon1 import MeshType_3d_colon1 from scaffoldmaker.meshtypes.meshtype_3d_colonsegment1 import MeshType_3d_colonsegment1 from scaffoldmaker.meshtypes.meshtype_3d_esophagus1 import MeshType_3d_esophagus1 +from scaffoldmaker.meshtypes.meshtype_3d_gastrointestinaltract1 import MeshType_3d_gastrointestinaltract1 from scaffoldmaker.meshtypes.meshtype_3d_heart1 import MeshType_3d_heart1 from scaffoldmaker.meshtypes.meshtype_3d_heart2 import MeshType_3d_heart2 from scaffoldmaker.meshtypes.meshtype_3d_heartarterialroot1 import MeshType_3d_heartarterialroot1 @@ -77,6 +78,7 @@ def __init__(self): MeshType_3d_colon1, MeshType_3d_colonsegment1, MeshType_3d_esophagus1, + MeshType_3d_gastrointestinaltract1, MeshType_3d_heart1, MeshType_3d_heart2, MeshType_3d_heartarterialroot1, diff --git a/src/scaffoldmaker/utils/tracksurface.py b/src/scaffoldmaker/utils/tracksurface.py index 20be933e..20020f41 100644 --- a/src/scaffoldmaker/utils/tracksurface.py +++ b/src/scaffoldmaker/utils/tracksurface.py @@ -113,6 +113,10 @@ def createPositionProportion(self, proportion1, proportion2): :return: TrackSurfacePosition ''' maxProportion1 = 2.0 if self.loop1 else 1.0 + if abs(proportion1) < 1e-12: + proportion1 = 0.0 + if abs(proportion2) < 1e-12: + proportion2 = 0.0 assert (proportion1 >= 0.0) and (proportion1 <= maxProportion1), 'createPositionProportion: Proportion 1 (' + str(proportion1) + ') out of range' assert (proportion2 >= 0.0) and (proportion2 <= 1.0), 'createPositionProportion: Proportion 2 (' + str(proportion2) + ') out of range' diff --git a/src/scaffoldmaker/utils/tubemesh.py b/src/scaffoldmaker/utils/tubemesh.py index b1c4c493..e8e356dd 100644 --- a/src/scaffoldmaker/utils/tubemesh.py +++ b/src/scaffoldmaker/utils/tubemesh.py @@ -243,9 +243,9 @@ def warpSegmentPoints(xList, d1List, d2List, segmentAxis, sx, sd1, sd2, elements return xWarpedList, d1WarpedList, d2WarpedListFinal, d3WarpedUnitList -def extrudeSurfaceCoordinates(xSurf, d1Surf, d2Surf, d3Surf, - wallThicknessList, relativeThicknessList, elementsCountAround, - elementsCountAlong, elementsCountThroughWall, transitElementList, outward=True): +def extrudeSurfaceCoordinates(xSurf, d1Surf, d2Surf, d3Surf, wallThicknessList, relativeThicknessList, + elementsCountAround, elementsCountAlong, elementsCountThroughWall, transitElementList, + outward=True, xProximal=[], d1Proximal=[], d2Proximal=[], d3Proximal=[]): """ Generates extruded coordinates using coordinates and derivatives of a surface. :param xSurf: Coordinates on surface @@ -260,6 +260,7 @@ def extrudeSurfaceCoordinates(xSurf, d1Surf, d2Surf, d3Surf, :param transitElementList: stores true if element around is a transition element that is between a big and a small element. :param outward: Set to True to generate coordinates from inner to outer surface. + :param xProximal, d1Proximal, d2Proximal, d3Proximal: coordinates and derivatives of nodes to use on proximal end. return nodes and derivatives for mesh, and curvature along extruded surface. """ @@ -271,6 +272,12 @@ def extrudeSurfaceCoordinates(xSurf, d1Surf, d2Surf, d3Surf, d1List = [] d2List = [] d3List = [] + count = 0 + localIdxDistal = [] + xDistal = [] + d1Distal = [] + d2Distal = [] + d3Distal = [] if relativeThicknessList: xi3 = 0.0 @@ -324,35 +331,64 @@ def extrudeSurfaceCoordinates(xSurf, d1Surf, d2Surf, d3Surf, for n3 in range(elementsCountThroughWall + 1): xi3 = xi3List[n3] if relativeThicknessList else 1.0/elementsCountThroughWall * n3 + xDistalAround = [] + d1DistalAround = [] + d2DistalAround = [] + d3DistalAround = [] + localIdxDistalAround = [] + for n1 in range(elementsCountAround): - n = n2*elementsCountAround + n1 - norm = d3Surf[n] - surfx = xSurf[n] - extrudedx = xExtrudedSurf[n] - # x - dWall = [wallThickness * c for c in norm] - if outward: - x = interp.interpolateCubicHermite(surfx, dWall, extrudedx, dWall, xi3) + if n2 == 0 and xProximal: + xList.append(xProximal[n3][n1]) + d1List.append(d1Proximal[n3][n1]) + d2List.append(d2Proximal[n3][n1]) + d3List.append(d3Proximal[n3][n1]) + n = n2 * elementsCountAround + n1 + curvatureList.append(curvatureAlong[n]) else: - x = interp.interpolateCubicHermite(extrudedx, dWall, surfx, dWall, xi3) - xList.append(x) - - # dx_ds1 - factor = 1.0 - wallOutwardDisplacement * (xi3 if outward else (1.0 - xi3)) * curvatureAroundSurf[n] - d1 = [factor*c for c in d1Surf[n]] - d1List.append(d1) - - # dx_ds2 - factor = 1.0 - wallOutwardDisplacement * (xi3 if outward else (1.0 - xi3)) * curvatureAlong[n] - d2 = [factor * c for c in d2Surf[n]] - d2List.append(d2) - curvatureList.append(curvatureAlong[n]) - - # dx_ds3 - d3 = [c * wallThickness * (relativeThicknessList[n3] if relativeThicknessList else 1.0/elementsCountThroughWall) for c in norm] - d3List.append(d3) - - return xList, d1List, d2List, d3List, curvatureList + n = n2*elementsCountAround + n1 + norm = d3Surf[n] + surfx = xSurf[n] + extrudedx = xExtrudedSurf[n] + # x + dWall = [wallThickness * c for c in norm] + if outward: + x = interp.interpolateCubicHermite(surfx, dWall, extrudedx, dWall, xi3) + else: + x = interp.interpolateCubicHermite(extrudedx, dWall, surfx, dWall, xi3) + xList.append(x) + + # dx_ds1 + factor = 1.0 - wallOutwardDisplacement * (xi3 if outward else (1.0 - xi3)) * curvatureAroundSurf[n] + d1 = [factor*c for c in d1Surf[n]] + d1List.append(d1) + + # dx_ds2 + factor = 1.0 - wallOutwardDisplacement * (xi3 if outward else (1.0 - xi3)) * curvatureAlong[n] + d2 = [factor * c for c in d2Surf[n]] + d2List.append(d2) + curvatureList.append(curvatureAlong[n]) + + # dx_ds3 + d3 = [c * wallThickness * (relativeThicknessList[n3] if relativeThicknessList else 1.0/elementsCountThroughWall) for c in norm] + d3List.append(d3) + + if n2 == elementsCountAlong: + xDistalAround.append(x) + d1DistalAround.append(d1) + d2DistalAround.append(d2) + d3DistalAround.append(d3) + localIdxDistalAround.append(count) + count += 1 + + if n2 == elementsCountAlong: + xDistal.append(xDistalAround) + d1Distal.append(d1DistalAround) + d2Distal.append(d2DistalAround) + d3Distal.append(d3DistalAround) + localIdxDistal.append(localIdxDistalAround) + + return xList, d1List, d2List, d3List, curvatureList, localIdxDistal, xDistal, d1Distal, d2Distal, d3Distal def createFlatCoordinates(xiList, lengthAroundList, totalLengthAlong, wallThickness, relativeThicknessList, elementsCountAround, elementsCountAlong, elementsCountThroughWall, transitElementList): @@ -485,7 +521,7 @@ def createNodesAndElements(region, elementsCountAround, elementsCountAlong, elementsCountThroughWall, annotationGroupsAround, annotationGroupsAlong, annotationGroupsThroughWall, firstNodeIdentifier, firstElementIdentifier, - useCubicHermiteThroughWall, useCrossDerivatives, closedProximalEnd): + useCubicHermiteThroughWall, useCrossDerivatives, closedProximalEnd, localIdxDistal=[], nodeIdProximal=[]): """ Create nodes and elements for the coordinates and flat coordinates fields. :param x, d1, d2, d3: coordinates and derivatives of coordinates field. @@ -499,16 +535,23 @@ def createNodesAndElements(region, :param annotationGroupsAround: Annotation groups of elements around. :param annotationGroupsAlong: Annotation groups of elements along. :param annotationGroupsThroughWall: Annotation groups of elements through wall. - :param firstNodeIdentifier, firstElementIdentifier: first node and - element identifier to use. + :param firstNodeIdentifier, firstElementIdentifier: first node and element identifier to use. :param useCubicHermiteThroughWall: use linear when false :param useCrossDerivatives: use cross derivatives when true - :return nodeIdentifier, elementIdentifier, allAnnotationGroups + :param closedProximalEnd: Proximal end of tube is closed if true + :param localIdxDistal: local node identifiers for nodes on distal end of the tube. + :param nodeIdProximal: Node identifiers for nodes to use on proximal end of the tube. + :return nodeIdentifier, elementIdentifier, allAnnotationGroups, nodesDistal """ nodeIdentifier = firstNodeIdentifier elementIdentifier = firstElementIdentifier + startNode = firstNodeIdentifier zero = [ 0.0, 0.0, 0.0 ] + nodesDistal = [] + + for i in range(len(localIdxDistal)): + nodesDistal.append([firstNodeIdentifier + c for c in localIdxDistal[i]]) fm = region.getFieldmodule() fm.beginChange() @@ -622,7 +665,19 @@ def createNodesAndElements(region, # Create nodes # Coordinates field - for n in range(len(x)): + if nodeIdProximal: + proximalNodesOffset = len(nodeIdProximal) * len(nodeIdProximal[0]) + nodeList = [] + newNodeList = [] + + if nodeIdProximal: + for n3 in range(len(nodeIdProximal)): + for n1 in range(len(nodeIdProximal[n3])): + nodeList.append(nodeIdentifier) + newNodeList.append(nodeIdProximal[n3][n1]) + nodeIdentifier = nodeIdentifier + 1 + + for n in range(proximalNodesOffset if nodeIdProximal else 0, len(x)): node = nodes.createNode(nodeIdentifier, nodetemplate) cache.setNode(node) coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_VALUE, 1, x[n]) @@ -709,9 +764,9 @@ def createNodesAndElements(region, eftApex = eftfactory.createEftShellPoleBottom(va * 100, vb * 100) elementtemplateApex.defineField(coordinates, -1, eftApex) element = mesh.createElement(elementIdentifier, elementtemplateApex) - bni1 = e3 + 1 - bni2 = elementsCountThroughWall + 1 + elementsCountAround*e3 + e1 + 1 - bni3 = elementsCountThroughWall + 1 + elementsCountAround*e3 + (e1 + 1) % elementsCountAround + 1 + bni1 = e3 + 1 + startNode - 1 + bni2 = elementsCountThroughWall + 1 + elementsCountAround*e3 + e1 + 1 + startNode - 1 + bni3 = elementsCountThroughWall + 1 + elementsCountAround*e3 + (e1 + 1) % elementsCountAround + 1 + startNode - 1 nodeIdentifiers = [bni1, bni2, bni3, bni1 + 1, bni2 + elementsCountAround, bni3 + elementsCountAround] element.setNodesByIdentifier(eftApex, nodeIdentifiers) onOpening = e1 > elementsCountAround - 2 @@ -790,6 +845,13 @@ def createNodesAndElements(region, bni21 = e2 * now + (e3 + 1) * elementsCountAround + e1 + 1 bni22 = e2 * now + (e3 + 1) * elementsCountAround + (e1 + 1) % elementsCountAround + 1 nodeIdentifiers = [bni11, bni12, bni11 + now, bni12 + now, bni21, bni22, bni21 + now, bni22 + now] + nodeIdentifiers = [startNode - 1 + c for c in nodeIdentifiers] + if e2 == 0 and nodeIdProximal: + for m in range(len(nodeIdentifiers)): + if nodeIdentifiers[m] in nodeList: + idx = nodeList.index(nodeIdentifiers[m]) + nodeIdentifiers[m] = newNodeList[idx] + onOpening = e1 > elementsCountAround - 2 element = mesh.createElement(elementIdentifier, elementtemplate) element.setNodesByIdentifier(eft, nodeIdentifiers) @@ -811,34 +873,34 @@ def createNodesAndElements(region, fm.endChange() - return nodeIdentifier, elementIdentifier, allAnnotationGroups + return nodeIdentifier, elementIdentifier, allAnnotationGroups, nodesDistal -class CylindricalSegmentTubeMeshInnerPoints: +class CylindricalSegmentTubeMeshOuterPoints: """ - Generates inner profile of a cylindrical segment for use by tubemesh. + Generates outer profile of a cylindrical segment for use by tubemesh. """ def __init__(self, elementsCountAround, elementsCountAlongSegment, - segmentLength, wallThickness, innerRadiusList, startPhase): + segmentLength, wallThickness, outerRadiusList, startPhase): self._elementsCountAround = elementsCountAround self._elementsCountAlongSegment = elementsCountAlongSegment self._segmentLength = segmentLength self._wallThickness = wallThickness - self._innerRadiusList = innerRadiusList + self._outerRadiusList = outerRadiusList self._xiList = [] self._flatWidthList = [] self._startPhase = startPhase - def getCylindricalSegmentTubeMeshInnerPoints(self, nSegment): + def getCylindricalSegmentTubeMeshOuterPoints(self, nSegment): elementAlongStartIdx = nSegment * self._elementsCountAlongSegment elementAlongEndIdx = (nSegment + 1) * self._elementsCountAlongSegment - xInner, d1Inner, d2Inner, transitElementList, xiSegment, flatWidthSegment, segmentAxis, radiusAlongSegmentList \ - = getCylindricalSegmentInnerPoints(self._elementsCountAround, self._elementsCountAlongSegment, + xOuter, d1Outer, d2Outer, transitElementList, xiSegment, flatWidthSegment, segmentAxis, radiusAlongSegmentList \ + = getCylindricalSegmentOuterPoints(self._elementsCountAround, self._elementsCountAlongSegment, self._segmentLength, self._wallThickness, - self._innerRadiusList[elementAlongStartIdx: elementAlongEndIdx + 1], + self._outerRadiusList[elementAlongStartIdx: elementAlongEndIdx + 1], self._startPhase) startIdx = 0 if nSegment == 0 else 1 @@ -848,12 +910,12 @@ def getCylindricalSegmentTubeMeshInnerPoints(self, nSegment): flatWidth = flatWidthSegment[startIdx:self._elementsCountAlongSegment + 1] self._flatWidthList += flatWidth - return xInner, d1Inner, d2Inner, transitElementList, segmentAxis, radiusAlongSegmentList + return xOuter, d1Outer, d2Outer, transitElementList, segmentAxis, radiusAlongSegmentList def getFlatWidthAndXiList(self): return self._flatWidthList, self._xiList -def getCylindricalSegmentInnerPoints(elementsCountAround, elementsCountAlongSegment, segmentLength, +def getCylindricalSegmentOuterPoints(elementsCountAround, elementsCountAlongSegment, segmentLength, wallThickness, radiusList, startPhase): """ Generates a 3-D cylindrical segment mesh with variable numbers of elements @@ -862,7 +924,7 @@ def getCylindricalSegmentInnerPoints(elementsCountAround, elementsCountAlongSegm :param elementsCountAlongSegment: Number of elements along cylindrical segment. :param segmentLength: Length of a cylindrical segment. :param wallThickness: Thickness of wall. - :param radiusList: Inner radius at elements along tube length. + :param radiusList: Outer radius at elements along tube length. :param startPhase: Phase at start. :return coordinates, derivatives on inner surface of a cylindrical segment. :return transitElementList: stores true if element around is an element that From 33956af8c7754e784de10a57dd827e1d445a0095 Mon Sep 17 00:00:00 2001 From: mlin865 Date: Thu, 28 Sep 2023 13:13:22 +1300 Subject: [PATCH 18/24] Update unit tests and add test for GI Tract --- .../meshtypes/meshtype_3d_bladder1.py | 4 +- .../meshtypes/meshtype_3d_bladderurethra1.py | 16 +- .../meshtypes/meshtype_3d_colon1.py | 11 +- .../meshtypes/meshtype_3d_colonsegment1.py | 2 +- tests/test_cecum.py | 32 ++-- tests/test_colon.py | 36 ++-- tests/test_colonsegment.py | 28 ++-- tests/test_esophagus.py | 52 +++--- tests/test_gastrointestinaltract1.py | 155 ++++++++++++++++++ tests/test_general.py | 4 +- tests/test_smallintestine.py | 27 +-- tests/test_stomach.py | 18 +- 12 files changed, 274 insertions(+), 111 deletions(-) create mode 100644 tests/test_gastrointestinaltract1.py diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_bladder1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_bladder1.py index 1bb877d0..a6ec6a92 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_bladder1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_bladder1.py @@ -573,7 +573,7 @@ def generateBaseMesh(cls, region, options): bladderCoordinatesFieldName, elementsCountAround, elementsCountAlongBladder, elementsCountThroughWall, annotationGroupsAround, annotationGroupsAlong, annotationGroupsThroughWall, firstNodeIdentifier, firstElementIdentifier, - useCubicHermiteThroughWall, useCrossDerivatives, closedProximalEnd=True) + useCubicHermiteThroughWall, useCrossDerivatives, closedProximalEnd=True)[0:3] bladderCoordinates = fm.findFieldByName(bladderCoordinatesFieldName) @@ -1335,7 +1335,7 @@ def getBladderCoordinates(elementsCountAlongDome, elementsCountAlongNeck, elemen xList, d1List, d2List, d3List, curvatureList = \ tubemesh.extrudeSurfaceCoordinates(xInner, d1Inner, d2Inner, d3Inner, wallThicknessList, relativeThicknessList, elementsCountAround, elementsCountAlongBladder, elementsCountThroughWall, - transitElementList, outward=False) + transitElementList, outward=False)[0:5] # Deal with multiple nodes at the start point for closed proximal end n = elementsCountAround * (elementsCountThroughWall + 1) diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_bladderurethra1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_bladderurethra1.py index e97d58fd..4141402c 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_bladderurethra1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_bladderurethra1.py @@ -884,14 +884,12 @@ def generateBaseMesh(cls, region, options): transitElementList = [0] * elementsCountAround relativeThicknessList = [] - xList, d1List, d2List, d3List, curvatureList = tubemesh.extrudeSurfaceCoordinates(xWarpedList, d1WarpedList, - d2WarpedList, d3WarpedUnitList, - wallThicknessList, - relativeThicknessList, - elementsCountAround, - elementsCountAlong, - elementsCountThroughWall, - transitElementList, outward=True) + xList, d1List, d2List, d3List, curvatureList = \ + tubemesh.extrudeSurfaceCoordinates(xWarpedList, d1WarpedList, d2WarpedList, d3WarpedUnitList, + wallThicknessList, relativeThicknessList, elementsCountAround, + elementsCountAlong, elementsCountThroughWall, transitElementList, + outward=True)[0:5] + # Call the derivatives from the transition list to be replaced in the d2List idx = elementsCountAlongBladder * elementsCountAround for n2 in range(elementsCountThroughWall + 1): @@ -1045,7 +1043,7 @@ def generateBaseMesh(cls, region, options): elementsCountAround, elementsCountAlong, elementsCountThroughWall, annotationGroupsAround, annotationGroupsAlong, annotationGroupsThroughWall, firstNodeIdentifier, firstElementIdentifier, - useCubicHermiteThroughWall, useCrossDerivatives, closedProximalEnd=True) + useCubicHermiteThroughWall, useCrossDerivatives, closedProximalEnd=True)[0:3] if includeUreter: annotationGroups.append(ureterGroup) diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_colon1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_colon1.py index 4742eebc..12287446 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_colon1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_colon1.py @@ -476,7 +476,7 @@ class MeshType_3d_colon1(Scaffold_base): 'name': get_colon_term('descending colon')[0], 'ontId': get_colon_term('descending colon')[1] }] - }), + }) } @staticmethod @@ -523,6 +523,7 @@ def getDefaultOptions(cls, parameterSetName='Default'): else: segmentProfileOption = ScaffoldPackage(MeshType_3d_colonsegment1, defaultParameterSetName='Human 1') options = { + 'Base parameter set': parameterSetName, 'Central path': copy.deepcopy(centralPathOption), 'Segment profile': segmentProfileOption, 'Number of segments': 30, @@ -557,7 +558,7 @@ def getDefaultOptions(cls, parameterSetName='Default'): options['Proximal-transverse tenia coli width'] = 4.0 options['Transverse-distal tenia coli width'] = 3.0 options['Distal tenia coli width'] = 1.5 - options['Base parameter set'] = parameterSetName + return options @staticmethod @@ -766,11 +767,11 @@ def createColonMesh3d(region, options, centralPath, nextNodeIdentifier, nextElem # Central path if tcCount == 1: - colonTermsAlong = [None, 'right colon', 'transverse colon', 'left colon'] + colonTermsAlong = ['colon', 'right colon', 'transverse colon', 'left colon'] elif tcCount == 2: - colonTermsAlong = [None, 'spiral colon', 'transverse colon', 'descending colon'] + colonTermsAlong = ['colon', 'spiral colon', 'transverse colon', 'descending colon'] elif tcCount == 3: - colonTermsAlong = [None, 'ascending colon', 'transverse colon', 'descending colon'] + colonTermsAlong = ['colon', 'ascending colon', 'transverse colon', 'descending colon'] centralPathLength = centralPath.arcLengthOfGroupsAlong[0] cx = centralPath.cxGroups[0] diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_colonsegment1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_colonsegment1.py index f1dcaecb..6fc7b8be 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_colonsegment1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_colonsegment1.py @@ -57,6 +57,7 @@ def getParameterSetNames(): @staticmethod def getDefaultOptions(parameterSetName='Default'): options = { + 'Base parameter set': parameterSetName, 'Number of elements around tenia coli': 2, 'Number of elements around haustrum': 8, 'Number of elements along segment': 4, @@ -138,7 +139,6 @@ def getDefaultOptions(parameterSetName='Default'): options['Submucosa relative thickness'] = 0.25 options['Circular muscle layer relative thickness'] = 0.25 options['Longitudinal muscle layer relative thickness'] = 0.16 - options['Base parameter set'] = parameterSetName return options diff --git a/tests/test_cecum.py b/tests/test_cecum.py index aed9c5dc..e850dc1c 100644 --- a/tests/test_cecum.py +++ b/tests/test_cecum.py @@ -29,13 +29,13 @@ def test_cecum1(self): centralPathSettings = centralPath.getScaffoldSettings() self.assertEqual("1-2-3.2, 4-3-5", centralPathSettings["Structure"]) - self.assertEqual(28, len(options)) + self.assertEqual(29, len(options)) self.assertEqual(1, options.get("Number of segments")) self.assertEqual(2, options.get("Number of elements around tenia coli")) - self.assertEqual(8, options.get("Number of elements along segment")) + self.assertEqual(12, options.get("Number of elements along segment")) self.assertEqual(1, options.get("Number of elements through wall")) - self.assertEqual(0.5, options.get("Corner inner radius factor")) - self.assertEqual(0.4, options.get("Haustrum inner radius factor")) + self.assertEqual(0.536, options.get("Corner outer radius factor")) + self.assertEqual(0.464, options.get("Haustrum outer radius factor")) self.assertEqual(3.0, options.get("Segment length mid derivative factor")) self.assertEqual(3, options.get("Number of tenia coli")) self.assertEqual(10.0, options.get("Start tenia coli width")) @@ -50,26 +50,26 @@ def test_cecum1(self): region = context.getDefaultRegion() self.assertTrue(region.isValid()) annotationGroups = MeshType_3d_cecum1.generateBaseMesh(region, options)[0] - self.assertEqual(5, len(annotationGroups)) + self.assertEqual(7, len(annotationGroups)) fieldmodule = region.getFieldmodule() self.assertEqual(RESULT_OK, fieldmodule.defineAllFaces()) mesh3d = fieldmodule.findMeshByDimension(3) - self.assertEqual(308, mesh3d.getSize()) + self.assertEqual(460, mesh3d.getSize()) mesh2d = fieldmodule.findMeshByDimension(2) - self.assertEqual(1164, mesh2d.getSize()) + self.assertEqual(1738, mesh2d.getSize()) mesh1d = fieldmodule.findMeshByDimension(1) - self.assertEqual(1408, mesh1d.getSize()) + self.assertEqual(2102, mesh1d.getSize()) nodes = fieldmodule.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES) - self.assertEqual(552, nodes.getSize()) + self.assertEqual(824, nodes.getSize()) datapoints = fieldmodule.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_DATAPOINTS) self.assertEqual(0, datapoints.getSize()) coordinates = fieldmodule.findFieldByName("coordinates").castFiniteElement() self.assertTrue(coordinates.isValid()) minimums, maximums = evaluateFieldNodesetRange(coordinates, nodes) - assertAlmostEqualList(self, minimums, [-110.98815807992678, -144.1649444946355, 854.4533092097239], 1.0E-6) - assertAlmostEqualList(self, maximums, [-55.3885994876074, -77.17764626881537, 900.1398770921413], 1.0E-6) + assertAlmostEqualList(self, minimums, [-112.4222871639696, -146.3433620526202, 852.5876977230726], 1.0E-6) + assertAlmostEqualList(self, maximums, [-54.14347619948218, -77.56, 899.9973429272325], 1.0E-6) with ChangeManager(fieldmodule): one = fieldmodule.createFieldConstant(1.0) @@ -81,16 +81,16 @@ def test_cecum1(self): fieldcache = fieldmodule.createFieldcache() result, surfaceArea = surfaceAreaField.evaluateReal(fieldcache, 1) self.assertEqual(result, RESULT_OK) - self.assertAlmostEqual(surfaceArea, 8014.802826468518, delta=1.0E-6) + self.assertAlmostEqual(surfaceArea, 8554.479888104559, delta=1.0E-6) result, volume = volumeField.evaluateReal(fieldcache, 1) self.assertEqual(result, RESULT_OK) - self.assertAlmostEqual(volume, 12562.715396659782, delta=1.0E-6) + self.assertAlmostEqual(volume, 13809.92644167005, delta=1.0E-6) # check some annotationGroups: expectedSizes3d = { - "caecum": 308, - "ileum": 16, - "ileocecal junction": 8 + "caecum": 460, + "ileum": 24, + "ileocecal junction": 12 } for name in expectedSizes3d: diff --git a/tests/test_colon.py b/tests/test_colon.py index 8c0e3247..ef51bad8 100644 --- a/tests/test_colon.py +++ b/tests/test_colon.py @@ -42,6 +42,13 @@ def test_colon1(self): (4, [ [ 130.00, 384.10, 0.00 ], [ 130.80, -40.50, 0.00 ], [ -5.35, 4.28, 31.06 ], [ 5.83, -8.41, 8.86 ], [ -15.28, -27.78, 2.51 ], [ 0.00, 1.00, 24.00] ] ) ] ), 'userAnnotationGroups': [ + { + '_AnnotationGroup': True, + 'dimension': 1, + 'identifierRanges': '1-3', + 'name': get_colon_term('colon')[0], + 'ontId': get_colon_term('colon')[1] + }, { '_AnnotationGroup': True, 'dimension': 1, @@ -68,6 +75,7 @@ def test_colon1(self): centralPathOption = parameterSetStructureStrings['Test line'] segmentProfileOption = ScaffoldPackage(MeshType_3d_colonsegment1, defaultParameterSetName='Human 1') options = { + 'Base parameter set': 'Human 1', 'Central path': copy.deepcopy(centralPathOption), 'Segment profile': segmentProfileOption, 'Number of segments': 3, @@ -76,18 +84,19 @@ def test_colon1(self): 'Proximal-transverse tenia coli width': 6.0, 'Transverse-distal tenia coli width': 5.0, 'Distal tenia coli width': 5.0, + 'Use linear through wall': True, 'Refine': False, 'Refine number of elements around': 1, 'Refine number of elements along': 1, 'Refine number of elements through wall': 1 } - self.assertEqual(12, len(options)) + self.assertEqual(14, len(options)) centralPath = options['Central path'] segmentProfile = options.get("Segment profile") segmentSettings = segmentProfile.getScaffoldSettings() self.assertEqual(8, segmentSettings.get("Number of elements around haustrum")) - self.assertEqual(0.5, segmentSettings.get("Corner inner radius factor")) - self.assertEqual(0.5, segmentSettings.get("Haustrum inner radius factor")) + self.assertEqual(0.536, segmentSettings.get("Corner outer radius factor")) + self.assertEqual(0.464, segmentSettings.get("Haustrum outer radius factor")) self.assertEqual(0.5, segmentSettings.get("Segment length end derivative factor")) self.assertEqual(3, segmentSettings.get("Number of tenia coli")) self.assertEqual(0.6, segmentSettings.get("Tenia coli thickness")) @@ -136,19 +145,20 @@ def test_colon1(self): coordinates = fieldmodule.findFieldByName("coordinates").castFiniteElement() self.assertTrue(coordinates.isValid()) minimums, maximums = evaluateFieldNodesetRange(coordinates, nodes) - assertAlmostEqualList(self, minimums, [-102.55487309988112, -11.951736893846785, -63.16829934203756], 1.0E-6) - assertAlmostEqualList(self, maximums, [139.2604050120047, 450.61008758758777, 52.71048326055835], 1.0E-6) + assertAlmostEqualList(self, minimums, [-100.08668914502144, -11.342531039430702, -60.09737764484168], 1.0E-6) + assertAlmostEqualList(self, maximums, [138.56897619597683, 447.93686761958236, 50.13111447364834], 1.0E-6) flatCoordinates = fieldmodule.findFieldByName("flat coordinates").castFiniteElement() self.assertTrue(flatCoordinates.isValid()) minimums, maximums = evaluateFieldNodesetRange(flatCoordinates, nodes) + print(minimums, maximums) assertAlmostEqualList(self, minimums, [0.0, 0.0, 0.0], 1.0E-6) - assertAlmostEqualList(self, maximums, [397.9905020852475, 561.3383898388232, 2.2], 1.0E-6) + assertAlmostEqualList(self, maximums, [377.06179507784395, 561.3383898388232, 2.2], 1.0E-6) colonCoordinates = fieldmodule.findFieldByName("colon coordinates").castFiniteElement() minimums, maximums = evaluateFieldNodesetRange(colonCoordinates, nodes) - assertAlmostEqualList(self, minimums, [-0.599793206103745, 0.0, -0.6], 1.0E-4) - assertAlmostEqualList(self, maximums, [0.599793206103745, 24.0, 0.625], 1.0E-4) + assertAlmostEqualList(self, minimums, [-0.599920500334689, 0.0, -0.6], 1.0E-4) + assertAlmostEqualList(self, maximums, [0.599920500334689, 24.0, 0.625], 1.0E-4) with ChangeManager(fieldmodule): one = fieldmodule.createFieldConstant(1.0) @@ -160,10 +170,10 @@ def test_colon1(self): fieldcache = fieldmodule.createFieldcache() result, surfaceArea = surfaceAreaField.evaluateReal(fieldcache, 1) self.assertEqual(result, RESULT_OK) - self.assertAlmostEqual(surfaceArea, 174749.05868939584, delta=1.0E-6) + self.assertAlmostEqual(surfaceArea, 164285.41543554227, delta=1.0E-6) result, volume = volumeField.evaluateReal(fieldcache, 1) self.assertEqual(result, RESULT_OK) - self.assertAlmostEqual(volume, 314670.65237072564, delta=1.0E-6) + self.assertAlmostEqual(volume, 294925.4567043401, delta=1.0E-6) def test_mousecolon1(self): """ @@ -199,13 +209,13 @@ def test_mousecolon1(self): fieldcache = fieldmodule.createFieldcache() result, flatSurfaceArea = flatSurfaceAreaField.evaluateReal(fieldcache, 1) self.assertEqual(result, RESULT_OK) - self.assertAlmostEqual(flatSurfaceArea, 651.2624843023726, delta=1.0E-6) + self.assertAlmostEqual(flatSurfaceArea, 650.8919830877059, delta=1.0E-6) result, colonSurfaceArea = colonSurfaceAreaField.evaluateReal(fieldcache, 1) self.assertEqual(result, RESULT_OK) - self.assertAlmostEqual(colonSurfaceArea, 90.45789313556386, delta=1.0E-6) + self.assertAlmostEqual(colonSurfaceArea, 90.45785287687968, delta=1.0E-6) result, colonVolume = colonVolumeField.evaluateReal(fieldcache, 1) self.assertEqual(result, RESULT_OK) - self.assertAlmostEqual(colonVolume, 8.290058800222006, delta=1.0E-6) + self.assertAlmostEqual(colonVolume, 8.290050554292705, delta=1.0E-6) if __name__ == "__main__": diff --git a/tests/test_colonsegment.py b/tests/test_colonsegment.py index 55f58781..7ae5a525 100644 --- a/tests/test_colonsegment.py +++ b/tests/test_colonsegment.py @@ -21,20 +21,20 @@ def test_humancolonsegment1(self): parameterSetNames = MeshType_3d_colonsegment1.getParameterSetNames() self.assertEqual(parameterSetNames, ["Default", "Cattle 1", "Human 1", "Human 2", "Mouse 1", "Pig 1"]) options = MeshType_3d_colonsegment1.getDefaultOptions("Human 1") - self.assertEqual(31, len(options)) + self.assertEqual(32, len(options)) self.assertEqual(0.0, options.get("Start phase")) self.assertEqual(2, options.get("Number of elements around tenia coli")) self.assertEqual(4, options.get("Number of elements along segment")) self.assertEqual(4, options.get("Number of elements through wall")) - self.assertEqual(43.5, options.get("Start inner radius")) - self.assertEqual(0.0, options.get("Start inner radius derivative")) - self.assertEqual(33.0, options.get("End inner radius")) - self.assertEqual(0.0, options.get("End inner radius derivative")) + self.assertEqual(None, options.get("Start inner radius")) + self.assertEqual(None, options.get("Start inner radius derivative")) + self.assertEqual(None, options.get("End inner radius")) + self.assertEqual(None, options.get("End inner radius derivative")) self.assertEqual(3.0, options.get("Segment length mid derivative factor")) self.assertEqual(50.0, options.get("Segment length")) self.assertEqual(3, options.get("Number of tenia coli")) - self.assertEqual(10.0, options.get("Start tenia coli width")) - self.assertEqual(0.0, options.get("End tenia coli width derivative")) + self.assertEqual(11.1, options.get("Start tenia coli width")) + self.assertEqual(0.4, options.get("End tenia coli width derivative")) self.assertEqual(1.6, options.get("Wall thickness")) context = Context("Test") @@ -59,14 +59,14 @@ def test_humancolonsegment1(self): coordinates = fieldmodule.findFieldByName("coordinates").castFiniteElement() self.assertTrue(coordinates.isValid()) minimums, maximums = evaluateFieldNodesetRange(coordinates, nodes) - assertAlmostEqualList(self, minimums, [-2.172286248499807e-15, -58.95670186936737, -55.54662267827035], 1.0E-6) - assertAlmostEqualList(self, maximums, [50.0, 50.52621132610023, 55.54662267827035], 1.0E-6) + assertAlmostEqualList(self, minimums, [-2.172286248499807e-15, -59.07417787753859, -55.60850335002243], 1.0E-6) + assertAlmostEqualList(self, maximums, [50.0, 50.60638395601446, 55.60850335002243], 1.0E-6) flatCoordinates = fieldmodule.findFieldByName("flat coordinates").castFiniteElement() self.assertTrue(flatCoordinates.isValid()) minimums, maximums = evaluateFieldNodesetRange(flatCoordinates, nodes) assertAlmostEqualList(self, minimums, [0.0, 0.0, 0.0], 1.0E-6) - assertAlmostEqualList(self, maximums, [397.2736607240895, 50.0, 2.2], 1.0E-6) + assertAlmostEqualList(self, maximums, [392.25861666443416, 50.0, 2.2], 1.0E-6) with ChangeManager(fieldmodule): one = fieldmodule.createFieldConstant(1.0) @@ -78,10 +78,10 @@ def test_humancolonsegment1(self): fieldcache = fieldmodule.createFieldcache() result, surfaceArea = surfaceAreaField.evaluateReal(fieldcache, 1) self.assertEqual(result, RESULT_OK) - self.assertAlmostEqual(surfaceArea, 21032.6788157990, delta=1.0E-6) + self.assertAlmostEqual(surfaceArea, 20870.63159749863, delta=1.0E-6) result, volume = volumeField.evaluateReal(fieldcache, 1) self.assertEqual(result, RESULT_OK) - self.assertAlmostEqual(volume, 39836.60239335828, delta=1.0E-6) + self.assertAlmostEqual(volume, 39988.68541401406, delta=1.0E-6) def test_mousecolonsegment1(self): """ @@ -114,10 +114,10 @@ def test_mousecolonsegment1(self): fieldcache = fieldmodule.createFieldcache() result, surfaceArea = surfaceAreaField.evaluateReal(fieldcache, 1) self.assertEqual(result, RESULT_OK) - self.assertAlmostEqual(surfaceArea, 468.17062489996886, delta=1.0E-6) + self.assertAlmostEqual(surfaceArea, 467.98576432245915, delta=1.0E-6) result, flatSurfaceArea = flatSurfaceAreaField.evaluateReal(fieldcache, 1) self.assertEqual(result, RESULT_OK) - self.assertAlmostEqual(flatSurfaceArea, surfaceArea, delta=1.0E-3) + self.assertAlmostEqual(flatSurfaceArea, 467.98905126160287, delta=1.0E-3) if __name__ == "__main__": diff --git a/tests/test_esophagus.py b/tests/test_esophagus.py index b3d43748..2ee82bdf 100644 --- a/tests/test_esophagus.py +++ b/tests/test_esophagus.py @@ -29,8 +29,8 @@ def test_esophagus1(self): self.assertEqual(15, len(options)) self.assertEqual(8, options.get("Number of elements around")) self.assertEqual(20, options.get("Number of elements along")) - self.assertEqual(4, options.get("Number of elements through wall")) - self.assertEqual(3.2, options.get("Wall thickness")) + self.assertEqual(1, options.get("Number of elements through wall")) + self.assertEqual(1.2, options.get("Wall thickness")) self.assertEqual(0.35, options.get("Mucosa relative thickness")) self.assertEqual(0.15, options.get("Submucosa relative thickness")) self.assertEqual(0.25, options.get("Circular muscle layer relative thickness")) @@ -40,32 +40,32 @@ def test_esophagus1(self): region = context.getDefaultRegion() self.assertTrue(region.isValid()) annotationGroups = scaffold.generateBaseMesh(region, options)[0] - self.assertEqual(12, len(annotationGroups)) + self.assertEqual(8, len(annotationGroups)) fieldmodule = region.getFieldmodule() self.assertEqual(RESULT_OK, fieldmodule.defineAllFaces()) mesh3d = fieldmodule.findMeshByDimension(3) - self.assertEqual(640, mesh3d.getSize()) + self.assertEqual(160, mesh3d.getSize()) mesh2d = fieldmodule.findMeshByDimension(2) - self.assertEqual(2112, mesh2d.getSize()) + self.assertEqual(648, mesh2d.getSize()) mesh1d = fieldmodule.findMeshByDimension(1) - self.assertEqual(2312, mesh1d.getSize()) + self.assertEqual(824, mesh1d.getSize()) nodes = fieldmodule.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES) - self.assertEqual(844, nodes.getSize()) + self.assertEqual(340, nodes.getSize()) datapoints = fieldmodule.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_DATAPOINTS) self.assertEqual(0, datapoints.getSize()) coordinates = fieldmodule.findFieldByName("coordinates").castFiniteElement() self.assertTrue(coordinates.isValid()) minimums, maximums = evaluateFieldNodesetRange(coordinates, nodes) - assertAlmostEqualList(self, minimums, [-11.461359765715862, -117.02328007059768, 1124.746516933097], 1.0E-6) - assertAlmostEqualList(self, maximums, [14.41809738372959, -62.10186570804781, 1403.745932596971], 1.0E-6) + assertAlmostEqualList(self, minimums, [-8.645606404075409, -115.4469482741834, 1123.3296869517246], 1.0E-6) + assertAlmostEqualList(self, maximums, [17.428066853931824, -63.05159903323634, 1403.9055789269714], 1.0E-6) flatCoordinates = fieldmodule.findFieldByName("flat coordinates").castFiniteElement() self.assertTrue(flatCoordinates.isValid()) minimums, maximums = evaluateFieldNodesetRange(flatCoordinates, nodes) - assertAlmostEqualList(self, minimums, [0.0, 0.0, 0.0], 1.0E-6) - assertAlmostEqualList(self, maximums, [31.765221935414147, 287.8507353356311, 3.2], 1.0E-6) + assertAlmostEqualList(self, minimums, [-2.023676644962851, 0.0, 0.0], 1.0E-6) + assertAlmostEqualList(self, maximums, [38.56398979676183, 289.9673186862639, 1.2], 1.0E-6) esophagusCoordinates = fieldmodule.findFieldByName("esophagus coordinates").castFiniteElement() minimums, maximums = evaluateFieldNodesetRange(esophagusCoordinates, nodes) @@ -82,21 +82,17 @@ def test_esophagus1(self): fieldcache = fieldmodule.createFieldcache() result, surfaceArea = surfaceAreaField.evaluateReal(fieldcache, 1) self.assertEqual(result, RESULT_OK) - self.assertAlmostEqual(surfaceArea, 13952.301236699395, delta=1.0E-6) + self.assertAlmostEqual(surfaceArea, 12544.147466204333, delta=1.0E-6) result, volume = volumeField.evaluateReal(fieldcache, 1) self.assertEqual(result, RESULT_OK) - self.assertAlmostEqual(volume, 35523.4403218177, delta=1.0E-6) + self.assertAlmostEqual(volume, 13787.433711373638, delta=1.0E-6) # check some annotationGroups: expectedSizes3d = { - "abdominal part of esophagus": 96, - "cervical part of esophagus": 160, - "esophagus": 640, - "esophagus mucosa": 160, - "esophagus smooth muscle circular layer": 160, - "esophagus smooth muscle longitudinal layer": 160, - "submucosa of esophagus": 160, - "thoracic part of esophagus": 384 + "abdominal part of esophagus": 24, + "cervical part of esophagus": 40, + "esophagus": 160, + "thoracic part of esophagus": 96 } for name in expectedSizes3d: group = getAnnotationGroupForTerm(annotationGroups, get_esophagus_term(name)) @@ -113,7 +109,7 @@ def test_esophagus1(self): for annotationGroup in removeAnnotationGroups: annotationGroups.remove(annotationGroup) - self.assertEqual(12, len(annotationGroups)) + self.assertEqual(8, len(annotationGroups)) refineRegion = region.createRegion() refineFieldmodule = refineRegion.getFieldmodule() @@ -132,16 +128,16 @@ def test_esophagus1(self): for annotation in annotationGroups: if annotation not in oldAnnotationGroups: annotationGroup.addSubelements() - self.assertEqual(14, len(annotationGroups)) + self.assertEqual(10, len(annotationGroups)) # mesh3d = refineFieldmodule.findMeshByDimension(3) - self.assertEqual(40960, mesh3d.getSize()) + self.assertEqual(10240, mesh3d.getSize()) mesh2d = refineFieldmodule.findMeshByDimension(2) - self.assertEqual(125952, mesh2d.getSize()) + self.assertEqual(33408, mesh2d.getSize()) mesh1d = refineFieldmodule.findMeshByDimension(1) - self.assertEqual(129056, mesh1d.getSize()) + self.assertEqual(36128, mesh1d.getSize()) nodes = refineFieldmodule.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES) - self.assertEqual(44068, nodes.getSize()) + self.assertEqual(12964, nodes.getSize()) datapoints = refineFieldmodule.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_DATAPOINTS) self.assertEqual(0, datapoints.getSize()) @@ -166,7 +162,7 @@ def test_esophagus1(self): self.assertTrue(node.isValid()) cache.setNode(node) element, xi = markerLocation.evaluateMeshLocation(cache, 3) - self.assertEqual(40509, element.getIdentifier()) + self.assertEqual(9789, element.getIdentifier()) assertAlmostEqualList(self, xi, [0.0, 1.0, 1.0], 1.0E-10) if __name__ == "__main__": diff --git a/tests/test_gastrointestinaltract1.py b/tests/test_gastrointestinaltract1.py new file mode 100644 index 00000000..2c0f97b9 --- /dev/null +++ b/tests/test_gastrointestinaltract1.py @@ -0,0 +1,155 @@ +import unittest +from testutils import assertAlmostEqualList + +from cmlibs.zinc.context import Context +from cmlibs.zinc.element import Element +from cmlibs.zinc.field import Field +from cmlibs.utils.zinc.finiteelement import evaluateFieldNodesetRange +from cmlibs.utils.zinc.general import ChangeManager +from cmlibs.zinc.result import RESULT_OK +from scaffoldmaker.annotation.annotationgroup import getAnnotationGroupForTerm +from scaffoldmaker.annotation.cecum_terms import get_cecum_term +from scaffoldmaker.annotation.colon_terms import get_colon_term +from scaffoldmaker.annotation.esophagus_terms import get_esophagus_term +from scaffoldmaker.annotation.stomach_terms import get_stomach_term +from scaffoldmaker.annotation.smallintestine_terms import get_smallintestine_term +from scaffoldmaker.meshtypes.meshtype_3d_gastrointestinaltract1 import MeshType_3d_gastrointestinaltract1 +from scaffoldmaker.utils.meshrefinement import MeshRefinement +from scaffoldmaker.utils.zinc_utils import createFaceMeshGroupExteriorOnFace + + +class GastrointestinalTractScaffoldTestCase(unittest.TestCase): + + def test_gastrointestinaltract1(self): + """ + Test creation of gastrointestinal tract scaffold. + """ + scaffold = MeshType_3d_gastrointestinaltract1 + parameterSetNames = scaffold.getParameterSetNames() + self.assertEqual(parameterSetNames, ['Default', 'Human 1']) + options = scaffold.getDefaultOptions("Default") + self.assertEqual(10, len(options)) + centralPathOptions = options['Central path'] + centralPathSettings = centralPathOptions.getScaffoldSettings() + self.assertEqual("1-2-3-4-5-6-7.2, 8-9-10-11-7-12-13-14-15-16-17-18-19-20-21-22-23-24-25-26-27-28-29-30-31-32-" + "33-34-35-36-37-38-39-40-41-42-43-44-45-46-47-48-49-50-51-52-53-54-55-56-57-58-59-60-61-62-63-" + "64-65-66-67-68-69-70-71-72-73-74-75-76-77-78-79-80-81-82-83-84-85-86-87-88-89-90-91-92-93-94-" + "95-96-97-98-99-100-101-102-103-104-105-106-107-108-109-110-111-112-113-114-115-116-117-118-" + "119-120-121-122-123-124-125-126-127-128-129-130-131-132-133-134-135-136-137-138-139-140-141-" + "142-143-144-145-146-147-148-149-150-151-152-153-154-155-156-157-158-159-160-161-162-163-164-" + "165-166-167-168-169-170-171-172.2, 173-172-174-175-176-177-178-179-180-181-182-183-184-185-" + "186-187-188-189-190-191-192-193-194-195-196-197-198-199-200-201-202-203-204-205-206-207-208-" + "209-210-211-212-213-214-215-216-217-218-219-220-221-222", + centralPathSettings.get("Structure")) + esoOptions = options['Esophagus'] + esoSettings = esoOptions.getScaffoldSettings() + self.assertEqual(8, esoSettings['Number of elements around']) + self.assertEqual(1, esoSettings['Number of elements through wall']) + stomachOptions = options['Stomach'] + stomachSettings = stomachOptions.getScaffoldSettings() + self.assertEqual(8, stomachSettings['Number of elements around esophagus']) + self.assertEqual(12, stomachSettings['Number of elements around duodenum']) + self.assertEqual(14, stomachSettings['Number of elements along']) + self.assertEqual(1, stomachSettings['Number of elements through wall']) + self.assertEqual(3.0, stomachSettings['Wall thickness']) + smallIntestineOptions = options['Small intestine'] + smallIntestineSettings = smallIntestineOptions.getScaffoldSettings() + self.assertEqual(80, smallIntestineSettings['Number of segments']) + self.assertEqual(12, smallIntestineSettings['Number of elements around']) + self.assertEqual(3, smallIntestineSettings['Number of elements along segment']) + self.assertEqual(1, smallIntestineSettings['Number of elements through wall']) + self.assertEqual(3, smallIntestineSettings['Wall thickness']) + cecumOptions = options['Cecum'] + cecumSettings = cecumOptions.getScaffoldSettings() + self.assertEqual(1, cecumSettings['Number of segments']) + self.assertEqual(8, cecumSettings['Number of elements around haustrum']) + self.assertEqual(12, cecumSettings['Number of elements along segment']) + self.assertEqual(1, cecumSettings['Number of elements through wall']) + self.assertEqual(1.6, cecumSettings['Wall thickness']) + colonOptions = options['Colon'] + colonSettings = colonOptions.getScaffoldSettings() + self.assertEqual(33, colonSettings['Number of segments']) + self.assertEqual(True, options['Use linear through wall']) + self.assertEqual(False, options['Refine']) + self.assertEqual(4, options['Refine number of elements surface']) + self.assertEqual(1, options['Refine number of elements through wall']) + + context = Context("Test") + region = context.getDefaultRegion() + self.assertTrue(region.isValid()) + annotationGroups = scaffold.generateMesh(region, options)[0] + self.assertEqual(30, len(annotationGroups)) + + fieldmodule = region.getFieldmodule() + self.assertEqual(RESULT_OK, fieldmodule.defineAllFaces()) + mesh3d = fieldmodule.findMeshByDimension(3) + self.assertEqual(8448, mesh3d.getSize()) + mesh2d = fieldmodule.findMeshByDimension(2) + self.assertEqual(32494, mesh2d.getSize()) + mesh1d = fieldmodule.findMeshByDimension(1) + self.assertEqual(39642, mesh1d.getSize()) + nodes = fieldmodule.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES) + self.assertEqual(15600, nodes.getSize()) + datapoints = fieldmodule.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_DATAPOINTS) + self.assertEqual(0, datapoints.getSize()) + + # check coordinates range + coordinates = fieldmodule.findFieldByName("coordinates").castFiniteElement() + self.assertTrue(coordinates.isValid()) + minimums, maximums = evaluateFieldNodesetRange(coordinates, nodes) + assertAlmostEqualList(self, minimums, [-123.4289535529459, -190.90949289431342, 799.4386433354306], 1.0E-6) + assertAlmostEqualList(self, maximums, [124.21567892707846, -33.094490024089325, 1403.9055789269714], 1.0E-6) + + with ChangeManager(fieldmodule): + one = fieldmodule.createFieldConstant(1.0) + faceMeshGroup = createFaceMeshGroupExteriorOnFace(fieldmodule, Element.FACE_TYPE_XI3_1) + surfaceAreaField = fieldmodule.createFieldMeshIntegral(one, coordinates, faceMeshGroup) + surfaceAreaField.setNumbersOfPoints(4) + volumeField = fieldmodule.createFieldMeshIntegral(one, coordinates, mesh3d) + volumeField.setNumbersOfPoints(3) + fieldcache = fieldmodule.createFieldcache() + result, surfaceArea = surfaceAreaField.evaluateReal(fieldcache, 1) + self.assertEqual(result, RESULT_OK) + self.assertAlmostEqual(surfaceArea, 280350.6499309959, delta=1.0E-6) + result, volume = volumeField.evaluateReal(fieldcache, 1) + self.assertEqual(result, RESULT_OK) + self.assertAlmostEqual(volume, 598505.9260947731, delta=1.0E-6) + + # check some annotationGroups: + expectedSizes3d = { + "esophagus": 184, + "stomach": 168, + "small intestine": 2916, + "caecum": 460, + "colon": 4752 + } + for name in expectedSizes3d: + if name == "esophagus": + term = get_esophagus_term(name) + elif name == ("stomach"): + term = get_stomach_term(name) + elif name == ("small intestine"): + term = get_smallintestine_term(name) + elif name == ("caecum"): + term = get_cecum_term(name) + elif name == ("colon"): + term = get_colon_term(name) + group = getAnnotationGroupForTerm(annotationGroups, term) + size = group.getMeshGroup(mesh3d).getSize() + self.assertEqual(expectedSizes3d[name], size, name) + + # refine 8x8x8 and check result + refineRegion = region.createRegion() + refineFieldmodule = refineRegion.getFieldmodule() + options['Refine number of elements surface'] = 2 + options['Refine number of elements through wall'] = 1 + meshrefinement = MeshRefinement(region, refineRegion, []) + scaffold.refineMesh(meshrefinement, options) + + refineFieldmodule.defineAllFaces() + mesh3d = refineFieldmodule.findMeshByDimension(3) + self.assertEqual(33792, mesh3d.getSize()) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/test_general.py b/tests/test_general.py index 17ec4c2f..034c52f7 100644 --- a/tests/test_general.py +++ b/tests/test_general.py @@ -436,7 +436,7 @@ def test_deletion(self): # delete element ranges for body annotationGroups = scaffoldPackage.getAnnotationGroups() - self.assertEqual(73, len(annotationGroups)) + self.assertEqual(74, len(annotationGroups)) scaffoldPackage.deleteElementsInRanges(region, [[313, 496]]) self.assertEqual(824, mesh3d.getSize()) element = mesh3d.findElementByIdentifier(400) @@ -457,7 +457,7 @@ def test_deletion(self): # check that bob is deleted annotationGroups = scaffoldPackage.getAnnotationGroups() - self.assertEqual(70, len(annotationGroups)) + self.assertEqual(71, len(annotationGroups)) bob = scaffoldPackage.findAnnotationGroupByName('bob') self.assertNotIn(bob, annotationGroups) node = nodes.findNodeByIdentifier(bobNodeIdentifier) diff --git a/tests/test_smallintestine.py b/tests/test_smallintestine.py index d5b4d680..e2fd47e9 100644 --- a/tests/test_smallintestine.py +++ b/tests/test_smallintestine.py @@ -38,6 +38,13 @@ def test_smallintestine1(self): (4, [ [ -15.60, 13.70, -6.10 ], [ 7.00, 2.10, -1.80 ], [ 0.00, 1.00, 0.00 ], [ 0.00, 0.05, 0.00 ], [ 0.50, 0.08, 0.86 ], [ 0.00, 0.00, 0.50 ] ] ) ] ), 'userAnnotationGroups': [ + { + '_AnnotationGroup': True, + 'dimension': 1, + 'identifierRanges': '1-3', + 'name': get_smallintestine_term('small intestine')[0], + 'ontId': get_smallintestine_term('small intestine')[1] + }, { '_AnnotationGroup': True, 'dimension': 1, @@ -70,7 +77,7 @@ def test_smallintestine1(self): self.assertEqual(3, options.get("Number of segments")) self.assertEqual(8, options.get("Number of elements around")) self.assertEqual(3, options.get("Number of elements along segment")) - self.assertEqual(4, options.get("Number of elements through wall")) + self.assertEqual(1, options.get("Number of elements through wall")) self.assertEqual(None, options.get("Duodenum length")) self.assertEqual(None, options.get("Jejunum-ileum inner radius")) self.assertEqual(0.1, options.get("Wall thickness")) @@ -93,26 +100,26 @@ def test_smallintestine1(self): del tmpRegion annotationGroups = MeshType_3d_smallintestine1.generateBaseMesh(region, options)[0] - self.assertEqual(8, len(annotationGroups)) + self.assertEqual(4, len(annotationGroups)) fieldmodule = region.getFieldmodule() self.assertEqual(RESULT_OK, fieldmodule.defineAllFaces()) mesh3d = fieldmodule.findMeshByDimension(3) - self.assertEqual(288, mesh3d.getSize()) + self.assertEqual(72, mesh3d.getSize()) mesh2d = fieldmodule.findMeshByDimension(2) - self.assertEqual(968, mesh2d.getSize()) + self.assertEqual(296, mesh2d.getSize()) mesh1d = fieldmodule.findMeshByDimension(1) - self.assertEqual(1080, mesh1d.getSize()) + self.assertEqual(384, mesh1d.getSize()) nodes = fieldmodule.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES) - self.assertEqual(400, nodes.getSize()) + self.assertEqual(160, nodes.getSize()) datapoints = fieldmodule.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_DATAPOINTS) self.assertEqual(0, datapoints.getSize()) coordinates = fieldmodule.findFieldByName("coordinates").castFiniteElement() self.assertTrue(coordinates.isValid()) minimums, maximums = evaluateFieldNodesetRange(coordinates, nodes) - assertAlmostEqualList(self, minimums, [-20.053209723800897, 11.40926084082289, -7.165067989112036], 1.0E-6) - assertAlmostEqualList(self, maximums, [-1.8359517172713313, 19.193196743341623, 0.7249488391024033], 1.0E-6) + assertAlmostEqualList(self, minimums, [-19.956658197690174, 11.509153871441058, -7.068492932596849], 1.0E-6) + assertAlmostEqualList(self, maximums, [-1.9033816741586018, 19.093964008729433, 0.6249529551386831], 1.0E-6) flatCoordinates = fieldmodule.findFieldByName("flat coordinates").castFiniteElement() self.assertTrue(flatCoordinates.isValid()) @@ -138,10 +145,10 @@ def test_smallintestine1(self): fieldcache = fieldmodule.createFieldcache() result, surfaceArea = surfaceAreaField.evaluateReal(fieldcache, 1) self.assertEqual(result, RESULT_OK) - self.assertAlmostEqual(surfaceArea, 143.8501823770281, delta=1.0E-6) + self.assertAlmostEqual(surfaceArea, 127.90324495617577, delta=1.0E-6) result, volume = volumeField.evaluateReal(fieldcache, 1) self.assertEqual(result, RESULT_OK) - self.assertAlmostEqual(volume, 13.608455265457282, delta=1.0E-6) + self.assertAlmostEqual(volume, 12.011251644596864, delta=1.0E-6) result, flatSurfaceArea = flatSurfaceAreaField.evaluateReal(fieldcache, 1) self.assertEqual(result, RESULT_OK) self.assertAlmostEqual(flatSurfaceArea, 144.42091907104523, delta=1.0E-3) diff --git a/tests/test_stomach.py b/tests/test_stomach.py index c0fc2557..d2f076ae 100644 --- a/tests/test_stomach.py +++ b/tests/test_stomach.py @@ -35,23 +35,19 @@ def test_stomach1(self): self.assertEqual(True, options.get("Limiting ridge")) ostiumOptions = options['Gastro-esophageal junction'] ostiumSettings = ostiumOptions.getScaffoldSettings() - self.assertEqual(1, ostiumSettings.get("Number of vessels")) self.assertEqual(8, ostiumSettings.get("Number of elements around ostium")) self.assertEqual(4, ostiumSettings.get("Number of elements through wall")) - self.assertEqual(5.0, ostiumSettings.get("Ostium diameter")) - self.assertEqual(5.0, ostiumSettings.get("Ostium length")) + self.assertEqual(None, ostiumSettings.get("Ostium diameter")) self.assertEqual(0.5, ostiumSettings.get("Ostium wall thickness")) self.assertEqual([0.65, 0.12, 0.18, 0.05], ostiumSettings.get("Ostium wall relative thicknesses")) - self.assertEqual(2.0, ostiumSettings.get("Vessel inner diameter")) self.assertEqual(0.3, ostiumSettings.get("Vessel wall thickness")) self.assertEqual([0.65, 0.12, 0.18, 0.05], ostiumSettings.get("Vessel wall relative thicknesses")) - self.assertEqual(0.0, ostiumSettings.get("Vessel angle 1 degrees")) context = Context("Test") region = context.getDefaultRegion() self.assertTrue(region.isValid()) annotationGroups = scaffold.generateBaseMesh(region, options)[0] - self.assertEqual(41, len(annotationGroups)) + self.assertEqual(42, len(annotationGroups)) fieldmodule = region.getFieldmodule() self.assertEqual(RESULT_OK, fieldmodule.defineAllFaces()) @@ -87,10 +83,10 @@ def test_stomach1(self): fieldcache = fieldmodule.createFieldcache() result, surfaceArea = surfaceAreaField.evaluateReal(fieldcache, 1) self.assertEqual(result, RESULT_OK) - self.assertAlmostEqual(surfaceArea, 4.090555416482455, delta=1.0E-6) + self.assertAlmostEqual(surfaceArea, 4.092273543567514, delta=1.0E-6) result, volume = volumeField.evaluateReal(fieldcache, 1) self.assertEqual(result, RESULT_OK) - self.assertAlmostEqual(volume, 0.05785162434759533, delta=1.0E-6) + self.assertAlmostEqual(volume, 0.05789368036003227, delta=1.0E-6) # check some annotationGroups: expectedSizes3d = { @@ -101,7 +97,7 @@ def test_stomach1(self): "pyloric antrum": 128, "pyloric canal": 128, "duodenum": 64, - "stomach": 906 + "stomach": 778 } for name in expectedSizes3d: @@ -125,7 +121,7 @@ def test_stomach1(self): for annotationGroup in removeAnnotationGroups: annotationGroups.remove(annotationGroup) - self.assertEqual(41, len(annotationGroups)) + self.assertEqual(42, len(annotationGroups)) refineRegion = region.createRegion() refineFieldmodule = refineRegion.getFieldmodule() @@ -144,7 +140,7 @@ def test_stomach1(self): for annotation in annotationGroups: if annotation not in oldAnnotationGroups: annotationGroup.addSubelements() - self.assertEqual(75, len(annotationGroups)) + self.assertEqual(76, len(annotationGroups)) # mesh3d = refineFieldmodule.findMeshByDimension(3) self.assertEqual(57984, mesh3d.getSize()) From eea4b43e93a13bccaf7db0f61834e0b9e63bdbd9 Mon Sep 17 00:00:00 2001 From: mlin865 Date: Wed, 21 Feb 2024 16:52:57 +1300 Subject: [PATCH 19/24] Change central path to network layout and move parameterSetStructureStrings to a function for GI organs --- .../meshtypes/meshtype_3d_cecum1.py | 112 ++--- .../meshtypes/meshtype_3d_colon1.py | 407 ++++++++-------- .../meshtypes/meshtype_3d_esophagus1.py | 63 +-- .../meshtype_3d_gastrointestinaltract1.py | 45 +- .../meshtypes/meshtype_3d_ostium2.py | 49 +- .../meshtypes/meshtype_3d_smallintestine1.py | 450 +++++++++--------- .../meshtypes/meshtype_3d_stomach1.py | 223 ++++----- 7 files changed, 673 insertions(+), 676 deletions(-) diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_cecum1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_cecum1.py index 4670662a..ddcea32d 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_cecum1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_cecum1.py @@ -33,45 +33,40 @@ mesh_destroy_elements_and_nodes_by_identifiers, get_nodeset_path_ordered_field_parameters -class MeshType_3d_cecum1(Scaffold_base): - ''' - Generates a 3-D cecum mesh with variable numbers of elements around, along the central line, and through wall. The - cecum is created by a function that generates a cecum segment and uses tubemesh to map the segment along a network - layout. The proximal end of the cecum is closed up with an apex plate. An ostium is included to generate the - ileo-cecal junction. - ''' - - parameterSetStructureStrings = { - 'Human 1': ScaffoldPackage(MeshType_1d_network_layout1, { +def getDefaultNetworkLayoutScaffoldPackage(cls, parameterSetName): + assert parameterSetName in cls.getParameterSetNames() # make sure parameter set is in list of parameters of parent scaffold + if parameterSetName in ("Default", "Human 1"): + return ScaffoldPackage(MeshType_1d_network_layout1, { 'scaffoldSettings': { - "Structure": "1-2-3.2, 4-3-5" - }, - 'meshEdits': exnode_string_from_nodeset_field_parameters( - [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ - (1, [[7.50,-20.00,0.00], [0.00,8.28,0.00], [-2.50,0.00,0.00], [0.00,0.00,0.00], [0.00,-0.00,2.50], [0.00,0.00,0.00]]), - (2, [[7.50,-10.86,0.00], [0.00,10.00,0.00], [-4.50,0.00,0.00], [0.00,0.00,0.00], [0.00,-0.00,4.50], [0.00,0.00,0.00]]), - (3, [[7.50,0.00,0.00], [[8.44,0.00,0.04],[0.00,11.72,0.00]], [[0.00,11.60,0.00],[-4.50,0.00,0.00]], [[1.02,6.79,0.00],[0.00,0.00,0.00]], [[0.00,0.00,11.60],[0.00,-0.00,4.50]], [[0.00,0.00,5.77],[0.00,0.00,0.00]]]), - (4, [[-1.88,0.00,-0.08], [10.32,0.00,0.12], [0.00,11.60,0.00], [0.00,0.00,0.00], [0.00,0.00,11.60], [0.00,0.00,0.00]]), - (5, [[15.00,0.00,0.00], [6.56,0.00,-0.04], [0.00,11.60,0.00], [0.00,0.00,0.00], [0.00,0.00,11.60], [0.00,0.00,0.00]]) - ]), - - 'userAnnotationGroups': [ - { - '_AnnotationGroup': True, - 'dimension': 1, - 'identifierRanges': '1-4', - 'name': get_cecum_term('caecum')[0], - 'ontId': get_cecum_term('caecum')[1] + "Structure": "1-2-3.2, 4-3-5" }, - { - '_AnnotationGroup': True, - 'dimension': 1, - 'identifierRanges': '1-2', - 'name': get_cecum_term('ileum part of cecum')[0], - 'ontId': get_cecum_term('ileum part of cecum')[1] - }] - }), - 'Human 2': ScaffoldPackage(MeshType_1d_network_layout1, { + 'meshEdits': exnode_string_from_nodeset_field_parameters( + [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ + (1, [[7.50,-20.00,0.00], [0.00,8.28,0.00], [-2.50,0.00,0.00], [0.00,0.00,0.00], [0.00,-0.00,2.50], [0.00,0.00,0.00]]), + (2, [[7.50,-10.86,0.00], [0.00,10.00,0.00], [-4.50,0.00,0.00], [0.00,0.00,0.00], [0.00,-0.00,4.50], [0.00,0.00,0.00]]), + (3, [[7.50,0.00,0.00], [[8.44,0.00,0.04],[0.00,11.72,0.00]], [[0.00,11.60,0.00],[-4.50,0.00,0.00]], [[1.02,6.79,0.00],[0.00,0.00,0.00]], [[0.00,0.00,11.60],[0.00,-0.00,4.50]], [[0.00,0.00,5.77],[0.00,0.00,0.00]]]), + (4, [[-1.88,0.00,-0.08], [10.32,0.00,0.12], [0.00,11.60,0.00], [0.00,0.00,0.00], [0.00,0.00,11.60], [0.00,0.00,0.00]]), + (5, [[15.00,0.00,0.00], [6.56,0.00,-0.04], [0.00,11.60,0.00], [0.00,0.00,0.00], [0.00,0.00,11.60], [0.00,0.00,0.00]]) + ]), + + 'userAnnotationGroups': [ + { + '_AnnotationGroup': True, + 'dimension': 1, + 'identifierRanges': '1-4', + 'name': get_cecum_term('caecum')[0], + 'ontId': get_cecum_term('caecum')[1] + }, + { + '_AnnotationGroup': True, + 'dimension': 1, + 'identifierRanges': '1-2', + 'name': get_cecum_term('ileum part of cecum')[0], + 'ontId': get_cecum_term('ileum part of cecum')[1] + }] + }) + elif "Human 2" in parameterSetName: + return ScaffoldPackage(MeshType_1d_network_layout1, { 'scaffoldSettings': { "Structure": "1-2-3.2, 4-3-5" }, @@ -83,6 +78,7 @@ class MeshType_3d_cecum1(Scaffold_base): (4, [[-71.690,-109.000,866.040], [-9.550,-3.730,12.060], [17.410,-4.850,11.460], [3.730,0.680,4.200], [0.820,19.940,7.200], [3.740,0.690,4.200]]), (5, [[-87.210,-111.060,890.540], [-4.750,0.410,12.390], [23.270,-3.130,7.880], [2.460,-0.390,-2.950], [3.090,24.460,0.450], [1.830,0.460,-4.310]]) ]), + 'userAnnotationGroups': [ { '_AnnotationGroup': True, @@ -98,8 +94,9 @@ class MeshType_3d_cecum1(Scaffold_base): 'name': get_cecum_term('ileum part of cecum')[0], 'ontId': get_cecum_term('ileum part of cecum')[1] }] - }), - 'Pig 1': ScaffoldPackage(MeshType_1d_network_layout1, { + }) + elif "Pig 1" in parameterSetName: + return ScaffoldPackage(MeshType_1d_network_layout1, { 'scaffoldSettings': { "Structure": "1-2-3.2, 4-5-6-3-7" }, @@ -129,8 +126,16 @@ class MeshType_3d_cecum1(Scaffold_base): 'name': get_cecum_term('ileum part of cecum')[0], 'ontId': get_cecum_term('ileum part of cecum')[1] }] - }), - } + }) + + +class MeshType_3d_cecum1(Scaffold_base): + ''' + Generates a 3-D cecum mesh with variable numbers of elements around, along the central line, and through wall. The + cecum is created by a function that generates a cecum segment and uses tubemesh to map the segment along a network + layout. The proximal end of the cecum is closed up with an apex plate. An ostium is included to generate the + ileo-cecal junction. + ''' ostiumDefaultScaffoldPackages = { 'Human 1': ScaffoldPackage(MeshType_3d_ostium2, { @@ -188,17 +193,14 @@ def getParameterSetNames(): @classmethod def getDefaultOptions(cls, parameterSetName='Default'): if 'Human 2' in parameterSetName: - centralPathOption = cls.parameterSetStructureStrings['Human 2'] ostiumOption = cls.ostiumDefaultScaffoldPackages['Human 1'] elif 'Pig 1' in parameterSetName: - centralPathOption = cls.parameterSetStructureStrings['Pig 1'] ostiumOption = cls.ostiumDefaultScaffoldPackages['Pig 1'] else: - centralPathOption = cls.parameterSetStructureStrings['Human 1'] ostiumOption = cls.ostiumDefaultScaffoldPackages['Human 1'] options = { - 'Central path': copy.deepcopy(centralPathOption), + 'Network layout': getDefaultNetworkLayoutScaffoldPackage(cls, parameterSetName), 'Number of segments': 1, 'Number of elements around tenia coli': 2, 'Number of elements around haustrum': 8, @@ -256,7 +258,7 @@ def getDefaultOptions(cls, parameterSetName='Default'): @staticmethod def getOrderedOptionNames(): return [ - 'Central path', + 'Network layout', 'Number of segments', 'Number of elements around tenia coli', 'Number of elements around haustrum', @@ -287,7 +289,7 @@ def getOrderedOptionNames(): @classmethod def getOptionValidScaffoldTypes(cls, optionName): - if optionName == 'Central path': + if optionName == 'Network layout': return [ MeshType_1d_network_layout1 ] if optionName == 'Ileocecal junction': return [ MeshType_3d_ostium2 ] @@ -295,8 +297,8 @@ def getOptionValidScaffoldTypes(cls, optionName): @classmethod def getOptionScaffoldTypeParameterSetNames(cls, optionName, scaffoldType): - if optionName == 'Central path': - return list(cls.parameterSetStructureStrings.keys()) + if optionName == 'Network layout': + return cls.getParameterSetNames() if optionName == 'Ileocecal junction': return list(cls.ostiumDefaultScaffoldPackages.keys()) assert scaffoldType in cls.getOptionValidScaffoldTypes(optionName), cls.__name__ + '.getOptionScaffoldTypeParameterSetNames. ' + \ @@ -312,10 +314,10 @@ def getOptionScaffoldPackage(cls, optionName, scaffoldType, parameterSetName=Non if parameterSetName: assert parameterSetName in cls.getOptionScaffoldTypeParameterSetNames(optionName, scaffoldType), \ 'Invalid parameter set ' + str(parameterSetName) + ' for scaffold ' + str(scaffoldType.getName()) + ' in option ' + str(optionName) + ' of scaffold ' + cls.getName() - if optionName == 'Central path': + if optionName == 'Network layout': if not parameterSetName: - parameterSetName = list(cls.parameterSetStructureStrings.keys())[0] - return copy.deepcopy(cls.parameterSetStructureStrings[parameterSetName]) + parameterSetName = "Default" + return getDefaultNetworkLayoutScaffoldPackage(cls, parameterSetName) if optionName == 'Ileocecal junction': if not parameterSetName: parameterSetName = list(cls.ostiumDefaultScaffoldPackages.keys())[0] @@ -324,8 +326,8 @@ def getOptionScaffoldPackage(cls, optionName, scaffoldType, parameterSetName=Non @classmethod def checkOptions(cls, options): - if not options['Central path'].getScaffoldType() in cls.getOptionValidScaffoldTypes('Central path'): - options['Central path'] = cls.getOptionScaffoldPackage('Central path', MeshType_1d_network_layout1) + if not options['Network layout'].getScaffoldType() in cls.getOptionValidScaffoldTypes('Network layout'): + options['Network layout'] = cls.getOptionScaffoldPackage('Network layout', MeshType_1d_network_layout1) if not options['Ileocecal junction'].getScaffoldType() in cls.getOptionValidScaffoldTypes('Ileocecal junction'): options['Ileocecal junction'] = cls.getOptionScaffoldPackage('Ileocecal junction', MeshType_3d_ostium2) for key in [ @@ -396,7 +398,7 @@ def generateBaseMesh(cls, region, options): nextNodeIdentifier = 1 nextElementIdentifier = 1 cls.updateSubScaffoldOptions(options) - geometricCentralPath = options['Central path'] + geometricCentralPath = options['Network layout'] cecumTermsAlong = ['caecum', 'ileum part of cecum'] geometricCentralPath = CecumCentralPath(region, geometricCentralPath, cecumTermsAlong) annotationGroups, nextNodeIdentifier, nextElementIdentifier = \ diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_colon1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_colon1.py index 12287446..358f2ee8 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_colon1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_colon1.py @@ -24,181 +24,34 @@ from scaffoldmaker.utils.zinc_utils import exnode_string_from_nodeset_field_parameters, \ get_nodeset_path_field_parameters - -class MeshType_3d_colon1(Scaffold_base): - ''' - Generates a 3-D colon mesh with variable numbers - of elements around, along the central line, and through wall. - The colon is created by a function that generates a colon - segment and uses tubemesh to map the segment along a central - line profile. - ''' - - parameterSetStructureStrings = { - 'Cattle 1': ScaffoldPackage(MeshType_1d_network_layout1, { - 'scaffoldSettings': { - "Structure": "1-2-3-4-5-6-7-8-9-10-11-12-13-14-15-16-17-18-19-20-21-22-23-24-25-26-27-28-29-30-31-32-" - "33-34-35-36-37-38-39-40-41-42-43-44-45-46-47-48-49-50-51-52-53" - }, - 'meshEdits': exnode_string_from_nodeset_field_parameters( - [ Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3 ], [ - (1, [[-245.30,444.60,-49.10], [-267.70,-53.10,-20.20], [0.00,0.00,38.02], [0.00,0.00,-4.41], [-7.40,37.29,0.00], [0.00,0.00,-4.41]]), - (2, [[-380.30,484.80,-45.00], [24.50,102.70,15.70], [0.00,0.00,34.49], [0.00,0.00,-2.65], [33.55,-8.00,0.00], [0.00,0.00,-2.65]]), - (3, [[-298.10,510.40,-36.80], [73.60,9.90,-16.40], [0.00,0.00,32.36], [-12.52,-3.10,-14.34], [4.31,-32.07,0.00], [-12.52,-3.10,-14.34]]), - (4, [[-213.10,527.90,-22.50], [-1.00,-10.80,125.60], [-29.16,-7.23,1.80], [-4.10,-6.11,-25.37], [7.07,-29.15,-2.45], [-4.10,-6.11,-25.37]]), - (5, [[-315.50,570.20,18.90], [-107.90,9.30,21.90], [-2.95,-13.63,-23.41], [14.35,4.82,-10.40], [0.73,-23.58,13.64], [14.35,4.82,-10.40]]), - (6, [[-417.40,555.00,14.60], [-83.00,-41.30,-0.80], [4.80,1.33,-24.41], [0.54,4.88,0.73], [11.08,-22.29,0.97], [0.54,4.88,0.73]]), - (7, [[-497.30,488.90,13.60], [-44.60,-81.60,10.00], [-1.80,-2.76,-22.33], [-2.12,-0.60,2.13], [19.79,-10.85,-0.25], [-2.12,-0.60,2.13]]), - (8, [[-527.00,392.50,2.70], [47.40,-82.00,-7.90], [0.00,0.00,-20.22], [0.68,1.04,1.96], [17.50,10.12,0.00], [0.68,1.04,1.96]]), - (9, [[-461.20,345.90,-0.80], [56.90,-44.50,2.40], [0.00,0.00,-18.40], [0.00,0.00,1.09], [11.33,14.49,0.00], [0.00,0.00,1.09]]), - (10, [[-415.60,293.80,3.90], [93.20,-62.60,3.10], [0.00,0.00,-17.93], [0.00,0.00,0.43], [9.99,14.89,0.00], [0.00,0.00,0.43]]), - (11, [[-232.20,264.90,0.20], [140.10,58.20,-1.00], [0.00,0.00,-17.60], [0.00,0.00,0.25], [-6.75,16.25,0.00], [0.00,0.00,0.25]]), - (12, [[-168.40,357.20,1.30], [10.10,78.60,-3.20], [0.00,0.00,-17.40], [0.00,0.00,0.15], [-17.26,2.21,0.00], [0.00,0.00,0.15]]), - (13, [[-185.30,419.10,-0.70], [-45.10,57.10,-0.90], [0.00,0.00,-17.29], [0.00,0.00,0.13], [-13.57,-10.71,0.00], [0.00,0.00,0.13]]), - (14, [[-253.20,466.70,-0.30], [-63.40,24.70,0.20], [0.00,0.00,-17.15], [0.00,0.00,0.13], [-6.23,-15.98,0.00], [0.00,0.00,0.13]]), - (15, [[-323.80,482.50,0.10], [-68.20,2.90,-1.20], [0.00,0.00,-17.02], [0.00,0.00,0.12], [-0.72,-17.01,0.00], [0.00,0.00,0.12]]), - (16, [[-387.50,485.40,-0.20], [-44.20,-17.10,-1.00], [0.00,0.00,-16.91], [0.00,0.00,0.12], [6.10,-15.77,0.00], [0.00,0.00,0.12]]), - (17, [[-435.60,433.50,3.30], [3.40,-109.50,1.40], [0.00,0.00,-16.78], [0.00,0.00,0.14], [16.77,0.52,0.00], [0.00,0.00,0.14]]), - (18, [[-370.60,376.30,-1.10], [66.90,-29.20,-0.90], [0.00,0.00,-16.62], [0.00,0.00,0.12], [6.65,15.23,0.00], [0.00,0.00,0.12]]), - (19, [[-313.00,357.90,-0.10], [40.00,-33.50,9.60], [0.00,0.00,-16.52], [0.00,0.00,0.10], [10.61,12.67,0.00], [0.00,0.00,0.10]]), - (20, [[-259.20,340.70,2.10], [48.90,6.40,1.40], [0.00,0.00,-16.42], [0.00,0.00,0.09], [-2.13,16.28,0.00], [0.00,0.00,0.09]]), - (21, [[-246.50,380.30,-0.80], [-29.70,33.60,-0.70], [0.00,0.00,-16.33], [0.00,0.00,0.09], [-12.23,-10.82,0.00], [0.00,0.00,0.09]]), - (22, [[-297.30,387.10,0.60], [-59.70,12.60,-0.00], [0.00,0.00,-16.24], [0.00,0.00,0.09], [-3.35,-15.89,0.00], [0.00,0.00,0.09]]), - (23, [[-340.20,415.60,-1.00], [-86.20,28.90,-2.90], [0.00,0.00,-16.15], [0.00,0.00,0.10], [-5.13,-15.31,0.00], [0.00,0.00,0.10]]), - (24, [[-398.30,443.10,-0.10], [10.60,82.10,-2.60], [0.00,0.00,-16.03], [0.00,0.00,0.12], [-15.90,2.06,0.00], [0.00,0.00,0.12]]), - (25, [[-329.80,449.10,-2.10], [53.20,14.00,-0.50], [0.00,0.00,-15.90], [0.00,0.00,0.14], [-4.05,15.38,0.00], [0.00,0.00,0.14]]), - (26, [[-251.30,425.90,-0.30], [43.90,-19.30,0.00], [0.00,0.00,-15.76], [0.00,0.00,0.11], [6.35,14.42,0.00], [0.00,0.00,0.11]]), - (27, [[-209.10,390.60,0.00], [26.00,-38.80,0.90], [0.00,0.00,-15.67], [0.00,0.00,0.08], [13.02,8.72,0.00], [0.00,0.00,0.08]]), - (28, [[-207.80,350.80,1.40], [-9.40,-43.60,1.80], [0.00,0.00,-15.59], [0.00,0.00,0.09], [15.24,-3.29,0.00], [0.00,0.00,0.09]]), - (29, [[-245.80,299.40,7.60], [-70.30,-36.00,1.40], [0.00,0.00,-15.48], [0.00,0.00,0.14], [7.06,-13.78,0.00], [0.00,0.00,0.14]]), - (30, [[-345.30,304.10,3.10], [-100.20,27.90,-1.90], [0.00,0.00,-15.31], [0.00,0.00,0.17], [-4.11,-14.75,0.00], [0.00,0.00,0.17]]), - (31, [[-418.40,361.10,-0.20], [-57.80,55.80,-1.70], [0.00,0.00,-15.15], [0.00,0.00,0.15], [-10.52,-10.90,0.00], [0.00,0.00,0.15]]), - (32, [[-479.20,415.60,2.20], [-8.80,73.10,-1.60], [0.00,0.00,-15.00], [0.00,0.00,0.15], [-14.89,-1.79,0.00], [0.00,0.00,0.15]]), - (33, [[-439.60,495.70,-2.10], [61.10,57.10,-1.30], [0.00,0.00,-14.84], [0.00,0.00,0.15], [-10.13,10.85,0.00], [0.00,0.00,0.15]]), - (34, [[-361.60,522.60,-3.00], [78.60,9.90,0.20], [0.00,0.00,-14.70], [0.00,0.00,0.15], [-1.84,14.59,0.00], [0.00,0.00,0.15]]), - (35, [[-270.10,506.50,-3.80], [103.60,-33.30,1.00], [0.00,0.00,-14.54], [0.00,0.00,0.19], [4.46,13.84,0.00], [0.00,0.00,0.19]]), - (36, [[-148.90,441.40,-2.10], [79.70,-91.50,2.80], [0.00,0.00,-14.30], [0.00,0.00,0.23], [10.79,9.39,0.00], [0.00,0.00,0.23]]), - (37, [[-130.90,313.30,4.00], [-4.00,-107.20,3.10], [0.00,0.00,-14.07], [0.00,0.00,0.18], [14.06,-0.52,0.00], [0.00,0.00,0.18]]), - (38, [[-183.90,251.00,3.80], [-65.50,-60.20,3.60], [0.00,0.00,-13.92], [0.00,0.00,0.16], [9.42,-10.25,0.00], [0.00,0.00,0.16]]), - (39, [[-280.30,213.00,3.40], [-165.10,-18.60,0.10], [0.00,0.00,-13.74], [0.00,0.00,0.20], [1.54,-13.65,0.00], [0.00,0.00,0.20]]), - (40, [[-400.80,247.50,6.80], [-127.10,36.80,1.30], [0.00,0.00,-13.53], [0.00,0.00,0.23], [-3.76,-13.00,0.00], [0.00,0.00,0.23]]), - (41, [[-530.50,290.70,5.20], [-89.00,86.50,0.30], [0.00,0.00,-13.29], [0.00,0.00,0.21], [-9.27,-9.52,0.00], [0.00,0.00,0.21]]), - (42, [[-568.80,392.30,6.90], [-77.40,67.70,-5.50], [0.00,0.00,-13.10], [0.00,0.00,0.23], [-8.63,-9.86,0.00], [0.00,0.00,0.23]]), - (43, [[-511.20,535.10,2.50], [86.20,111.40,-1.00], [0.00,0.00,-12.82], [0.00,0.00,0.25], [-10.14,7.85,0.00], [0.00,0.00,0.25]]), - (44, [[-405.00,601.70,6.40], [143.60,52.20,2.60], [0.00,0.00,-12.60], [1.49,-1.44,0.82], [-4.30,11.84,0.00], [1.49,-1.44,0.82]]), - (45, [[-238.80,615.90,16.60], [63.30,-9.10,19.10], [4.57,-4.41,-10.54], [-5.13,0.21,1.79], [2.73,11.44,-3.61], [-5.13,0.21,1.79]]), - (46, [[-146.20,605.90,36.50], [49.30,-9.90,-50.60], [-8.95,-1.40,-8.08], [-3.12,3.94,7.67], [0.13,11.93,-2.21], [-3.12,3.94,7.67]]), - (47, [[-218.40,585.30,-2.00], [-124.00,0.40,-37.50], [-4.06,6.01,9.60], [2.76,2.30,8.98], [1.78,10.41,-5.77], [2.76,2.30,8.98]]), - (48, [[-376.30,579.60,-40.80], [-189.20,-50.70,-8.80], [-2.47,1.63,11.71], [4.16,0.49,-2.60], [-2.97,11.49,-2.23], [4.16,0.49,-2.60]]), - (49, [[-557.90,493.90,-24.90], [-30.30,24.10,152.80], [8.24,8.85,0.92], [1.49,-2.48,-8.73], [-8.46,8.18,-2.97], [1.49,-2.48,-8.73]]), - (50, [[-484.80,594.40,0.70], [132.70,97.00,3.50], [4.32,-1.57,-11.27], [-2.78,-5.06,-5.12], [-6.74,9.35,-3.88], [-2.78,-5.06,-5.12]]), - (51, [[-318.10,641.90,-8.50], [166.70,17.60,5.50], [0.89,-3.82,-11.58], [-2.15,-0.82,-0.11], [-1.09,11.54,-3.89], [-2.15,-0.82,-0.11]]), - (52, [[-158.30,634.70,-1.90], [176.50,-14.00,10.80], [-1.43,-3.83,-11.56], [-0.81,0.27,-0.12], [1.15,11.54,-3.97], [-0.81,0.27,-0.12]]), - (53, [[32.70,611.70,13.60], [205.50,-32.20,20.00], [-1.01,-3.02,-11.90], [1.46,0.96,-0.42], [2.15,11.71,-3.15], [1.46,0.96,-0.42]]) - ] ), - - 'userAnnotationGroups': [ - { - '_AnnotationGroup': True, - 'dimension': 1, - 'identifierRanges': '1-52', - 'name': get_colon_term('colon')[0], - 'ontId': get_colon_term('colon')[1] - }, - { - '_AnnotationGroup': True, - 'dimension': 1, - 'identifierRanges': '1-8', - 'name': get_colon_term('right colon')[0], - 'ontId': get_colon_term('right colon')[1] - }, - { - '_AnnotationGroup': True, - 'dimension': 1, - 'identifierRanges': '9-46', - 'name': get_colon_term('transverse colon')[0], - 'ontId': get_colon_term('transverse colon')[1] - }, - { - '_AnnotationGroup': True, - 'dimension': 1, - 'identifierRanges': '47-52', - 'name': get_colon_term('left colon')[0], - 'ontId': get_colon_term('left colon')[1] - }] - }), - 'Human 1': ScaffoldPackage(MeshType_1d_network_layout1, { +def getDefaultNetworkLayoutScaffoldPackage(cls, parameterSetName): + assert parameterSetName in cls.getParameterSetNames() # make sure parameter set is in list of parameters of parent scaffold + if parameterSetName in ("Default", "Human 1"): + return ScaffoldPackage(MeshType_1d_network_layout1, { 'scaffoldSettings': { - "Structure": "1-2-3-4-5-6-7-8-9" - }, - 'meshEdits': exnode_string_from_nodeset_field_parameters( - [ Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ - (1, [[0.00,0.00,0.00], [-50.70,178.20,0.00], [-40.03,-10.00,-20.01], [-6.86,-11.39,-2.36], [-19.62,-4.20,41.24], [-14.00,-1.00,-12.00]]), - (2, [[-47.40,188.60,0.00], [-19.30,177.10,0.00], [-37.98,-6.91,-13.80], [11.23,17.36,14.31], [-13.43,-4.23,38.50], [-4.00,19.00,22.00]]), - (3, [[-4.40,396.50,0.00], [206.00,40.10,0.00], [-14.88,29.77,11.90], [13.54,-1.87,21.51], [-6.48,-13.39,32.07], [-6.00,0.00,51.00]]), - (4, [[130.00,384.10,0.00], [130.80,-40.50,0.00], [-5.75,4.60,33.36], [5.83,-8.41,8.86], [-16.41,-29.84,2.70], [0.00,1.00,24.00]]), - (5, [[279.40,383.00,0.00], [118.00,48.70,0.00], [-2.70,13.54,29.79], [9.30,9.73,-10.83], [13.82,-26.53,13.55], [5.00,25.00,-20.00]]), - (6, [[443.90,390.80,0.00], [111.30,-97.00,0.00], [15.21,25.87,9.13], [12.36,-3.74,-23.50], [-10.16,-3.25,29.50], [1.00,-6.00,-35.00]]), - (7, [[475.20,168.00,0.00], [-0.80,-112.40,0.00], [22.45,0.00,-22.45], [-2.41,-19.32,-15.36], [22.45,-0.00,22.45], [15.00,-1.00,-10.00]]), - (8, [[432.60,-32.30,0.00], [-90.50,-59.00,0.00], [10.89,-16.33,-25.41], [-9.58,-7.07,-2.37], [14.04,-21.18,19.63], [8.00,-11.00,-13.00]]), - (9, [[272.40,7.50,0.00], [-79.00,47.40,0.00], [1.53,-16.88,-27.61], [-7.76,6.05,-1.75], [-5.63,-28.82,13.68], [4.00,-12.00,-12.00]]) - ]), - - 'userAnnotationGroups': [ - { - '_AnnotationGroup': True, - 'dimension': 1, - 'identifierRanges': '1-8', - 'name': get_colon_term('colon')[0], - 'ontId': get_colon_term('colon')[1] + "Structure": "1-2-3-4-5-6-7-8-9" }, - { - '_AnnotationGroup': True, - 'dimension': 1, - 'identifierRanges': '1-2', - 'name': get_colon_term('ascending colon')[0], - 'ontId': get_colon_term('ascending colon')[1] - }, - { - '_AnnotationGroup': True, - 'dimension': 1, - 'identifierRanges': '3-5', - 'name': get_colon_term('transverse colon')[0], - 'ontId': get_colon_term('transverse colon')[1] - }, - { - '_AnnotationGroup': True, - 'dimension': 1, - 'identifierRanges': '6-8', - 'name': get_colon_term('descending colon')[0], - 'ontId': get_colon_term('descending colon')[1] - }] - }), - 'Human 2': ScaffoldPackage(MeshType_1d_network_layout1, { - 'scaffoldSettings': { - "Structure": "1-2-3-4-5-6-7-8-9" - }, - 'meshEdits': exnode_string_from_nodeset_field_parameters( - [ Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ - (1, [[0.00,0.00,0.00], [-56.81,105.14,-38.05], [-40.03,-10.00,-20.01], [-3.67,-11.77,-1.56], [-22.35,6.24,39.56], [-14.00,-1.00,-12.00]]), - (2, [[-34.50,114.00,-18.10], [-9.51,117.91,3.65], [-35.93,-6.53,-13.07], [12.13,18.49,14.99], [-13.40,-4.92,36.05], [-4.00,19.00,22.00]]), - (3, [[-19.10,218.50,5.50], [79.23,66.40,77.49], [-14.71,29.43,11.78], [14.61,7.18,21.72], [-24.58,-18.69,16.37], [-6.00,0.00,51.00]]), - (4, [[82.50,189.10,94.20], [140.70,-1.06,48.14], [-5.74,4.59,33.25], [5.75,-8.29,9.07], [12.40,-27.90,15.07], [0.00,1.00,24.00]]), - (5, [[226.60,218.70,85.70], [164.08,101.90,-75.52], [-2.72,13.61,29.95], [8.00,9.47,-9.25], [20.99,-22.00,12.86], [5.00,25.00,-20.00]]), - (6, [[325.50,381.70,-57.90], [187.36,-116.61,-173.53], [15.21,25.87,9.13], [12.05,-5.07,-23.99], [5.96,-11.86,28.42], [1.00,-6.00,-35.00]]), - (7, [[354.00,105.30,-24.40], [-20.59,-269.54,30.48], [22.54,0.00,-22.54], [-2.92,-19.10,-14.61], [22.47,6.25,21.72], [15.00,-1.00,-10.00]]), - (8, [[296.50,-121.20,-0.60], [-170.98,-102.19,-18.39], [10.95,-16.42,-25.54], [-9.48,-6.06,-2.33], [14.12,-21.29,19.73], [8.00,-11.00,-13.00]]), - (9, [[169.80,-73.40,-33.50], [-42.47,101.91,-24.43], [1.54,-16.94,-27.72], [-7.96,5.07,-1.75], [-18.03,-23.55,13.36], [4.00,-12.00,-12.00]]) - ] ), - - 'userAnnotationGroups': [ + 'meshEdits': exnode_string_from_nodeset_field_parameters( + [ Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ + (1, [[0.00,0.00,0.00], [-50.70,178.20,0.00], [-40.03,-10.00,-20.01], [-6.86,-11.39,-2.36], [-19.62,-4.20,41.24], [-14.00,-1.00,-12.00]]), + (2, [[-47.40,188.60,0.00], [-19.30,177.10,0.00], [-37.98,-6.91,-13.80], [11.23,17.36,14.31], [-13.43,-4.23,38.50], [-4.00,19.00,22.00]]), + (3, [[-4.40,396.50,0.00], [206.00,40.10,0.00], [-14.88,29.77,11.90], [13.54,-1.87,21.51], [-6.48,-13.39,32.07], [-6.00,0.00,51.00]]), + (4, [[130.00,384.10,0.00], [130.80,-40.50,0.00], [-5.75,4.60,33.36], [5.83,-8.41,8.86], [-16.41,-29.84,2.70], [0.00,1.00,24.00]]), + (5, [[279.40,383.00,0.00], [118.00,48.70,0.00], [-2.70,13.54,29.79], [9.30,9.73,-10.83], [13.82,-26.53,13.55], [5.00,25.00,-20.00]]), + (6, [[443.90,390.80,0.00], [111.30,-97.00,0.00], [15.21,25.87,9.13], [12.36,-3.74,-23.50], [-10.16,-3.25,29.50], [1.00,-6.00,-35.00]]), + (7, [[475.20,168.00,0.00], [-0.80,-112.40,0.00], [22.45,0.00,-22.45], [-2.41,-19.32,-15.36], [22.45,-0.00,22.45], [15.00,-1.00,-10.00]]), + (8, [[432.60,-32.30,0.00], [-90.50,-59.00,0.00], [10.89,-16.33,-25.41], [-9.58,-7.07,-2.37], [14.04,-21.18,19.63], [8.00,-11.00,-13.00]]), + (9, [[272.40,7.50,0.00], [-79.00,47.40,0.00], [1.53,-16.88,-27.61], [-7.76,6.05,-1.75], [-5.63,-28.82,13.68], [4.00,-12.00,-12.00]]) + ]), + + 'userAnnotationGroups': [ { - '_AnnotationGroup': True, - 'dimension': 1, - 'identifierRanges': '1-8', - 'name': get_colon_term('colon')[0], - 'ontId': get_colon_term('colon')[1] - }, + '_AnnotationGroup': True, + 'dimension': 1, + 'identifierRanges': '1-8', + 'name': get_colon_term('colon')[0], + 'ontId': get_colon_term('colon')[1] + }, { '_AnnotationGroup': True, 'dimension': 1, @@ -220,8 +73,57 @@ class MeshType_3d_colon1(Scaffold_base): 'name': get_colon_term('descending colon')[0], 'ontId': get_colon_term('descending colon')[1] }] - }), - 'Human 3': ScaffoldPackage(MeshType_1d_network_layout1, { + }) + elif "Human 2" in parameterSetName: + return ScaffoldPackage(MeshType_1d_network_layout1, { + 'scaffoldSettings': { + "Structure": "1-2-3-4-5-6-7-8-9" + }, + 'meshEdits': exnode_string_from_nodeset_field_parameters( + [ Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ + (1, [[0.00,0.00,0.00], [-56.81,105.14,-38.05], [-40.03,-10.00,-20.01], [-3.67,-11.77,-1.56], [-22.35,6.24,39.56], [-14.00,-1.00,-12.00]]), + (2, [[-34.50,114.00,-18.10], [-9.51,117.91,3.65], [-35.93,-6.53,-13.07], [12.13,18.49,14.99], [-13.40,-4.92,36.05], [-4.00,19.00,22.00]]), + (3, [[-19.10,218.50,5.50], [79.23,66.40,77.49], [-14.71,29.43,11.78], [14.61,7.18,21.72], [-24.58,-18.69,16.37], [-6.00,0.00,51.00]]), + (4, [[82.50,189.10,94.20], [140.70,-1.06,48.14], [-5.74,4.59,33.25], [5.75,-8.29,9.07], [12.40,-27.90,15.07], [0.00,1.00,24.00]]), + (5, [[226.60,218.70,85.70], [164.08,101.90,-75.52], [-2.72,13.61,29.95], [8.00,9.47,-9.25], [20.99,-22.00,12.86], [5.00,25.00,-20.00]]), + (6, [[325.50,381.70,-57.90], [187.36,-116.61,-173.53], [15.21,25.87,9.13], [12.05,-5.07,-23.99], [5.96,-11.86,28.42], [1.00,-6.00,-35.00]]), + (7, [[354.00,105.30,-24.40], [-20.59,-269.54,30.48], [22.54,0.00,-22.54], [-2.92,-19.10,-14.61], [22.47,6.25,21.72], [15.00,-1.00,-10.00]]), + (8, [[296.50,-121.20,-0.60], [-170.98,-102.19,-18.39], [10.95,-16.42,-25.54], [-9.48,-6.06,-2.33], [14.12,-21.29,19.73], [8.00,-11.00,-13.00]]), + (9, [[169.80,-73.40,-33.50], [-42.47,101.91,-24.43], [1.54,-16.94,-27.72], [-7.96,5.07,-1.75], [-18.03,-23.55,13.36], [4.00,-12.00,-12.00]]) + ] ), + + 'userAnnotationGroups': [ + { + '_AnnotationGroup': True, + 'dimension': 1, + 'identifierRanges': '1-8', + 'name': get_colon_term('colon')[0], + 'ontId': get_colon_term('colon')[1] + }, + { + '_AnnotationGroup': True, + 'dimension': 1, + 'identifierRanges': '1-2', + 'name': get_colon_term('ascending colon')[0], + 'ontId': get_colon_term('ascending colon')[1] + }, + { + '_AnnotationGroup': True, + 'dimension': 1, + 'identifierRanges': '3-5', + 'name': get_colon_term('transverse colon')[0], + 'ontId': get_colon_term('transverse colon')[1] + }, + { + '_AnnotationGroup': True, + 'dimension': 1, + 'identifierRanges': '6-8', + 'name': get_colon_term('descending colon')[0], + 'ontId': get_colon_term('descending colon')[1] + }] + }) + elif "Human 3" in parameterSetName: + return ScaffoldPackage(MeshType_1d_network_layout1, { 'scaffoldSettings': { "Structure": "1-2-3-4-5-6-7-8-9-10-11-12-13-14-15-16-17-18-19-20-21-22-23-24-25-26-27-28-29-30-31-32-" "33-34-35-36-37-38-39-40-41-42-43-44-45-46-47-48-49" @@ -308,8 +210,103 @@ class MeshType_3d_colon1(Scaffold_base): 'name': get_colon_term('descending colon')[0], 'ontId': get_colon_term('descending colon')[1] }] - }), - 'Mouse 1': ScaffoldPackage(MeshType_1d_network_layout1, { + }) + + elif 'Cattle 1' in parameterSetName: + return ScaffoldPackage(MeshType_1d_network_layout1, { + 'scaffoldSettings': { + "Structure": "1-2-3-4-5-6-7-8-9-10-11-12-13-14-15-16-17-18-19-20-21-22-23-24-25-26-27-28-29-30-31-32-" + "33-34-35-36-37-38-39-40-41-42-43-44-45-46-47-48-49-50-51-52-53" + }, + 'meshEdits': exnode_string_from_nodeset_field_parameters( + [ Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3 ], [ + (1, [[-245.30,444.60,-49.10], [-267.70,-53.10,-20.20], [0.00,0.00,38.02], [0.00,0.00,-4.41], [-7.40,37.29,0.00], [0.00,0.00,-4.41]]), + (2, [[-380.30,484.80,-45.00], [24.50,102.70,15.70], [0.00,0.00,34.49], [0.00,0.00,-2.65], [33.55,-8.00,0.00], [0.00,0.00,-2.65]]), + (3, [[-298.10,510.40,-36.80], [73.60,9.90,-16.40], [0.00,0.00,32.36], [-12.52,-3.10,-14.34], [4.31,-32.07,0.00], [-12.52,-3.10,-14.34]]), + (4, [[-213.10,527.90,-22.50], [-1.00,-10.80,125.60], [-29.16,-7.23,1.80], [-4.10,-6.11,-25.37], [7.07,-29.15,-2.45], [-4.10,-6.11,-25.37]]), + (5, [[-315.50,570.20,18.90], [-107.90,9.30,21.90], [-2.95,-13.63,-23.41], [14.35,4.82,-10.40], [0.73,-23.58,13.64], [14.35,4.82,-10.40]]), + (6, [[-417.40,555.00,14.60], [-83.00,-41.30,-0.80], [4.80,1.33,-24.41], [0.54,4.88,0.73], [11.08,-22.29,0.97], [0.54,4.88,0.73]]), + (7, [[-497.30,488.90,13.60], [-44.60,-81.60,10.00], [-1.80,-2.76,-22.33], [-2.12,-0.60,2.13], [19.79,-10.85,-0.25], [-2.12,-0.60,2.13]]), + (8, [[-527.00,392.50,2.70], [47.40,-82.00,-7.90], [0.00,0.00,-20.22], [0.68,1.04,1.96], [17.50,10.12,0.00], [0.68,1.04,1.96]]), + (9, [[-461.20,345.90,-0.80], [56.90,-44.50,2.40], [0.00,0.00,-18.40], [0.00,0.00,1.09], [11.33,14.49,0.00], [0.00,0.00,1.09]]), + (10, [[-415.60,293.80,3.90], [93.20,-62.60,3.10], [0.00,0.00,-17.93], [0.00,0.00,0.43], [9.99,14.89,0.00], [0.00,0.00,0.43]]), + (11, [[-232.20,264.90,0.20], [140.10,58.20,-1.00], [0.00,0.00,-17.60], [0.00,0.00,0.25], [-6.75,16.25,0.00], [0.00,0.00,0.25]]), + (12, [[-168.40,357.20,1.30], [10.10,78.60,-3.20], [0.00,0.00,-17.40], [0.00,0.00,0.15], [-17.26,2.21,0.00], [0.00,0.00,0.15]]), + (13, [[-185.30,419.10,-0.70], [-45.10,57.10,-0.90], [0.00,0.00,-17.29], [0.00,0.00,0.13], [-13.57,-10.71,0.00], [0.00,0.00,0.13]]), + (14, [[-253.20,466.70,-0.30], [-63.40,24.70,0.20], [0.00,0.00,-17.15], [0.00,0.00,0.13], [-6.23,-15.98,0.00], [0.00,0.00,0.13]]), + (15, [[-323.80,482.50,0.10], [-68.20,2.90,-1.20], [0.00,0.00,-17.02], [0.00,0.00,0.12], [-0.72,-17.01,0.00], [0.00,0.00,0.12]]), + (16, [[-387.50,485.40,-0.20], [-44.20,-17.10,-1.00], [0.00,0.00,-16.91], [0.00,0.00,0.12], [6.10,-15.77,0.00], [0.00,0.00,0.12]]), + (17, [[-435.60,433.50,3.30], [3.40,-109.50,1.40], [0.00,0.00,-16.78], [0.00,0.00,0.14], [16.77,0.52,0.00], [0.00,0.00,0.14]]), + (18, [[-370.60,376.30,-1.10], [66.90,-29.20,-0.90], [0.00,0.00,-16.62], [0.00,0.00,0.12], [6.65,15.23,0.00], [0.00,0.00,0.12]]), + (19, [[-313.00,357.90,-0.10], [40.00,-33.50,9.60], [0.00,0.00,-16.52], [0.00,0.00,0.10], [10.61,12.67,0.00], [0.00,0.00,0.10]]), + (20, [[-259.20,340.70,2.10], [48.90,6.40,1.40], [0.00,0.00,-16.42], [0.00,0.00,0.09], [-2.13,16.28,0.00], [0.00,0.00,0.09]]), + (21, [[-246.50,380.30,-0.80], [-29.70,33.60,-0.70], [0.00,0.00,-16.33], [0.00,0.00,0.09], [-12.23,-10.82,0.00], [0.00,0.00,0.09]]), + (22, [[-297.30,387.10,0.60], [-59.70,12.60,-0.00], [0.00,0.00,-16.24], [0.00,0.00,0.09], [-3.35,-15.89,0.00], [0.00,0.00,0.09]]), + (23, [[-340.20,415.60,-1.00], [-86.20,28.90,-2.90], [0.00,0.00,-16.15], [0.00,0.00,0.10], [-5.13,-15.31,0.00], [0.00,0.00,0.10]]), + (24, [[-398.30,443.10,-0.10], [10.60,82.10,-2.60], [0.00,0.00,-16.03], [0.00,0.00,0.12], [-15.90,2.06,0.00], [0.00,0.00,0.12]]), + (25, [[-329.80,449.10,-2.10], [53.20,14.00,-0.50], [0.00,0.00,-15.90], [0.00,0.00,0.14], [-4.05,15.38,0.00], [0.00,0.00,0.14]]), + (26, [[-251.30,425.90,-0.30], [43.90,-19.30,0.00], [0.00,0.00,-15.76], [0.00,0.00,0.11], [6.35,14.42,0.00], [0.00,0.00,0.11]]), + (27, [[-209.10,390.60,0.00], [26.00,-38.80,0.90], [0.00,0.00,-15.67], [0.00,0.00,0.08], [13.02,8.72,0.00], [0.00,0.00,0.08]]), + (28, [[-207.80,350.80,1.40], [-9.40,-43.60,1.80], [0.00,0.00,-15.59], [0.00,0.00,0.09], [15.24,-3.29,0.00], [0.00,0.00,0.09]]), + (29, [[-245.80,299.40,7.60], [-70.30,-36.00,1.40], [0.00,0.00,-15.48], [0.00,0.00,0.14], [7.06,-13.78,0.00], [0.00,0.00,0.14]]), + (30, [[-345.30,304.10,3.10], [-100.20,27.90,-1.90], [0.00,0.00,-15.31], [0.00,0.00,0.17], [-4.11,-14.75,0.00], [0.00,0.00,0.17]]), + (31, [[-418.40,361.10,-0.20], [-57.80,55.80,-1.70], [0.00,0.00,-15.15], [0.00,0.00,0.15], [-10.52,-10.90,0.00], [0.00,0.00,0.15]]), + (32, [[-479.20,415.60,2.20], [-8.80,73.10,-1.60], [0.00,0.00,-15.00], [0.00,0.00,0.15], [-14.89,-1.79,0.00], [0.00,0.00,0.15]]), + (33, [[-439.60,495.70,-2.10], [61.10,57.10,-1.30], [0.00,0.00,-14.84], [0.00,0.00,0.15], [-10.13,10.85,0.00], [0.00,0.00,0.15]]), + (34, [[-361.60,522.60,-3.00], [78.60,9.90,0.20], [0.00,0.00,-14.70], [0.00,0.00,0.15], [-1.84,14.59,0.00], [0.00,0.00,0.15]]), + (35, [[-270.10,506.50,-3.80], [103.60,-33.30,1.00], [0.00,0.00,-14.54], [0.00,0.00,0.19], [4.46,13.84,0.00], [0.00,0.00,0.19]]), + (36, [[-148.90,441.40,-2.10], [79.70,-91.50,2.80], [0.00,0.00,-14.30], [0.00,0.00,0.23], [10.79,9.39,0.00], [0.00,0.00,0.23]]), + (37, [[-130.90,313.30,4.00], [-4.00,-107.20,3.10], [0.00,0.00,-14.07], [0.00,0.00,0.18], [14.06,-0.52,0.00], [0.00,0.00,0.18]]), + (38, [[-183.90,251.00,3.80], [-65.50,-60.20,3.60], [0.00,0.00,-13.92], [0.00,0.00,0.16], [9.42,-10.25,0.00], [0.00,0.00,0.16]]), + (39, [[-280.30,213.00,3.40], [-165.10,-18.60,0.10], [0.00,0.00,-13.74], [0.00,0.00,0.20], [1.54,-13.65,0.00], [0.00,0.00,0.20]]), + (40, [[-400.80,247.50,6.80], [-127.10,36.80,1.30], [0.00,0.00,-13.53], [0.00,0.00,0.23], [-3.76,-13.00,0.00], [0.00,0.00,0.23]]), + (41, [[-530.50,290.70,5.20], [-89.00,86.50,0.30], [0.00,0.00,-13.29], [0.00,0.00,0.21], [-9.27,-9.52,0.00], [0.00,0.00,0.21]]), + (42, [[-568.80,392.30,6.90], [-77.40,67.70,-5.50], [0.00,0.00,-13.10], [0.00,0.00,0.23], [-8.63,-9.86,0.00], [0.00,0.00,0.23]]), + (43, [[-511.20,535.10,2.50], [86.20,111.40,-1.00], [0.00,0.00,-12.82], [0.00,0.00,0.25], [-10.14,7.85,0.00], [0.00,0.00,0.25]]), + (44, [[-405.00,601.70,6.40], [143.60,52.20,2.60], [0.00,0.00,-12.60], [1.49,-1.44,0.82], [-4.30,11.84,0.00], [1.49,-1.44,0.82]]), + (45, [[-238.80,615.90,16.60], [63.30,-9.10,19.10], [4.57,-4.41,-10.54], [-5.13,0.21,1.79], [2.73,11.44,-3.61], [-5.13,0.21,1.79]]), + (46, [[-146.20,605.90,36.50], [49.30,-9.90,-50.60], [-8.95,-1.40,-8.08], [-3.12,3.94,7.67], [0.13,11.93,-2.21], [-3.12,3.94,7.67]]), + (47, [[-218.40,585.30,-2.00], [-124.00,0.40,-37.50], [-4.06,6.01,9.60], [2.76,2.30,8.98], [1.78,10.41,-5.77], [2.76,2.30,8.98]]), + (48, [[-376.30,579.60,-40.80], [-189.20,-50.70,-8.80], [-2.47,1.63,11.71], [4.16,0.49,-2.60], [-2.97,11.49,-2.23], [4.16,0.49,-2.60]]), + (49, [[-557.90,493.90,-24.90], [-30.30,24.10,152.80], [8.24,8.85,0.92], [1.49,-2.48,-8.73], [-8.46,8.18,-2.97], [1.49,-2.48,-8.73]]), + (50, [[-484.80,594.40,0.70], [132.70,97.00,3.50], [4.32,-1.57,-11.27], [-2.78,-5.06,-5.12], [-6.74,9.35,-3.88], [-2.78,-5.06,-5.12]]), + (51, [[-318.10,641.90,-8.50], [166.70,17.60,5.50], [0.89,-3.82,-11.58], [-2.15,-0.82,-0.11], [-1.09,11.54,-3.89], [-2.15,-0.82,-0.11]]), + (52, [[-158.30,634.70,-1.90], [176.50,-14.00,10.80], [-1.43,-3.83,-11.56], [-0.81,0.27,-0.12], [1.15,11.54,-3.97], [-0.81,0.27,-0.12]]), + (53, [[32.70,611.70,13.60], [205.50,-32.20,20.00], [-1.01,-3.02,-11.90], [1.46,0.96,-0.42], [2.15,11.71,-3.15], [1.46,0.96,-0.42]]) + ] ), + + 'userAnnotationGroups': [ + { + '_AnnotationGroup': True, + 'dimension': 1, + 'identifierRanges': '1-52', + 'name': get_colon_term('colon')[0], + 'ontId': get_colon_term('colon')[1] + }, + { + '_AnnotationGroup': True, + 'dimension': 1, + 'identifierRanges': '1-8', + 'name': get_colon_term('right colon')[0], + 'ontId': get_colon_term('right colon')[1] + }, + { + '_AnnotationGroup': True, + 'dimension': 1, + 'identifierRanges': '9-46', + 'name': get_colon_term('transverse colon')[0], + 'ontId': get_colon_term('transverse colon')[1] + }, + { + '_AnnotationGroup': True, + 'dimension': 1, + 'identifierRanges': '47-52', + 'name': get_colon_term('left colon')[0], + 'ontId': get_colon_term('left colon')[1] + }] + }) + elif 'Mouse 1' in parameterSetName: + return ScaffoldPackage(MeshType_1d_network_layout1, { 'scaffoldSettings': { "Structure": "1-2-3-4-5-6-7-8" }, @@ -354,8 +351,9 @@ class MeshType_3d_colon1(Scaffold_base): 'name': get_colon_term('left colon')[0], 'ontId': get_colon_term('left colon')[1] }] - }), - 'Mouse 2': ScaffoldPackage(MeshType_1d_network_layout1, { + }) + elif 'Mouse 2' in parameterSetName: + return ScaffoldPackage(MeshType_1d_network_layout1, { 'scaffoldSettings': { "Structure": "1-2-3-4-5" }, @@ -397,8 +395,9 @@ class MeshType_3d_colon1(Scaffold_base): 'name': get_colon_term('left colon')[0], 'ontId': get_colon_term('left colon')[1] }] - }), - 'Pig 1': ScaffoldPackage(MeshType_1d_network_layout1, { + }) + elif 'Pig 1' in parameterSetName: + return ScaffoldPackage(MeshType_1d_network_layout1, { 'scaffoldSettings': { "Structure": "1-2-3-4-5-6-7-8-9-10-11-12-13-14-15-16-17-18-19-20-21-22-23-24-25-26-27-28-29-30-31-32-" "33-34-35-36-37-38-39-40" @@ -477,7 +476,16 @@ class MeshType_3d_colon1(Scaffold_base): 'ontId': get_colon_term('descending colon')[1] }] }) - } + + +class MeshType_3d_colon1(Scaffold_base): + ''' + Generates a 3-D colon mesh with variable numbers + of elements around, along the central line, and through wall. + The colon is created by a function that generates a colon + segment and uses tubemesh to map the segment along a central + line profile. + ''' @staticmethod def getName(): @@ -497,21 +505,6 @@ def getParameterSetNames(): @classmethod def getDefaultOptions(cls, parameterSetName='Default'): - if 'Human 2' in parameterSetName: - centralPathOption = cls.parameterSetStructureStrings['Human 2'] - elif 'Human 3' in parameterSetName: - centralPathOption = cls.parameterSetStructureStrings['Human 3'] - elif 'Cattle 1' in parameterSetName: - centralPathOption = cls.parameterSetStructureStrings['Cattle 1'] - elif 'Mouse 1' in parameterSetName: - centralPathOption = cls.parameterSetStructureStrings['Mouse 1'] - elif 'Mouse 2' in parameterSetName: - centralPathOption = cls.parameterSetStructureStrings['Mouse 2'] - elif 'Pig 1' in parameterSetName: - centralPathOption = cls.parameterSetStructureStrings['Pig 1'] - else: - centralPathOption = cls.parameterSetStructureStrings['Human 1'] - if 'Human 3' in parameterSetName: segmentProfileOption = ScaffoldPackage(MeshType_3d_colonsegment1, defaultParameterSetName='Human 2') elif 'Cattle' in parameterSetName: @@ -524,7 +517,7 @@ def getDefaultOptions(cls, parameterSetName='Default'): segmentProfileOption = ScaffoldPackage(MeshType_3d_colonsegment1, defaultParameterSetName='Human 1') options = { 'Base parameter set': parameterSetName, - 'Central path': copy.deepcopy(centralPathOption), + 'Network layout': getDefaultNetworkLayoutScaffoldPackage(cls, parameterSetName), 'Segment profile': segmentProfileOption, 'Number of segments': 30, 'Start phase': 0.0, @@ -564,7 +557,7 @@ def getDefaultOptions(cls, parameterSetName='Default'): @staticmethod def getOrderedOptionNames(): return [ - 'Central path', + 'Network layout', 'Segment profile', 'Number of segments', 'Start phase', @@ -580,7 +573,7 @@ def getOrderedOptionNames(): @classmethod def getOptionValidScaffoldTypes(cls, optionName): - if optionName == 'Central path': + if optionName == 'Network layout': return [MeshType_1d_network_layout1] if optionName == 'Segment profile': return [MeshType_3d_colonsegment1] @@ -588,8 +581,8 @@ def getOptionValidScaffoldTypes(cls, optionName): @classmethod def getOptionScaffoldTypeParameterSetNames(cls, optionName, scaffoldType): - if optionName == 'Central path': - return list(cls.parameterSetStructureStrings.keys()) + if optionName == 'Network layout': + return cls.getParameterSetNames() assert scaffoldType in cls.getOptionValidScaffoldTypes(optionName), \ cls.__name__ + '.getOptionScaffoldTypeParameterSetNames. ' + \ 'Invalid option \'' + optionName + '\' scaffold type ' + scaffoldType.getName() @@ -605,10 +598,10 @@ def getOptionScaffoldPackage(cls, optionName, scaffoldType, parameterSetName=Non assert parameterSetName in cls.getOptionScaffoldTypeParameterSetNames(optionName, scaffoldType), \ 'Invalid parameter set ' + str(parameterSetName) + ' for scaffold ' + str(scaffoldType.getName()) + \ ' in option ' + str(optionName) + ' of scaffold ' + cls.getName() - if optionName == 'Central path': + if optionName == 'Network layout': if not parameterSetName: - parameterSetName = list(cls.parameterSetStructureStrings.keys())[0] - return copy.deepcopy(cls.parameterSetStructureStrings[parameterSetName]) + parameterSetName = "Default" + return getDefaultNetworkLayoutScaffoldPackage(cls, parameterSetName) if optionName == 'Segment profile': if not parameterSetName: parameterSetName = scaffoldType.getParameterSetNames()[0] @@ -617,8 +610,8 @@ def getOptionScaffoldPackage(cls, optionName, scaffoldType, parameterSetName=Non @classmethod def checkOptions(cls, options): - if not options['Central path'].getScaffoldType() in cls.getOptionValidScaffoldTypes('Central path'): - options['Central path'] = cls.getOptionScaffoldPackage('Central path', MeshType_1d_network_layout1) + if not options['Network layout'].getScaffoldType() in cls.getOptionValidScaffoldTypes('Network layout'): + options['Network layout'] = cls.getOptionScaffoldPackage('Network layout', MeshType_1d_network_layout1) if not options['Segment profile'].getScaffoldType() in cls.getOptionValidScaffoldTypes('Segment profile'): options['Segment profile'] = cls.getOptionScaffoldPackage('Segment profile', MeshType_3d_colonsegment1) for key in [ @@ -651,7 +644,7 @@ def generateBaseMesh(cls, region, options): segmentSettings = segmentProfile.getScaffoldSettings() tcCount = segmentSettings['Number of tenia coli'] - geometricCentralPath = options['Central path'] + geometricCentralPath = options['Network layout'] if tcCount == 1: colonTermsAlong = ['colon', 'right colon', 'transverse colon', 'left colon'] elif tcCount == 2: diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_esophagus1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_esophagus1.py index 96eec051..c0c51929 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_esophagus1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_esophagus1.py @@ -25,27 +25,22 @@ from scaffoldmaker.utils.zinc_utils import exnode_string_from_nodeset_field_parameters,\ get_nodeset_path_field_parameters - -class MeshType_3d_esophagus1(Scaffold_base): - """ - Generates a 3-D esophagus mesh with variable numbers of elements around, along the central line, and through wall. - The esophagus is created by a function that generates an elliptical tube segment and uses tubemesh to map the - segment along a central path profile. - """ - - parameterSetStructureStrings = { - 'Human 1': ScaffoldPackage(MeshType_1d_network_layout1, { +def getDefaultNetworkLayoutScaffoldPackage(cls, parameterSetName): + assert parameterSetName in cls.getParameterSetNames() # make sure parameter set is in list of parameters of parent scaffold + if parameterSetName in ("Default", "Human 1"): + return ScaffoldPackage(MeshType_1d_network_layout1, { 'scaffoldSettings': { "Structure": "1-2-3-4-5" }, 'meshEdits': exnode_string_from_nodeset_field_parameters( - [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ - (1, [[0.394,-100.872,1402.818], [-0.035,12.367,-48.020], [8.730,-0.526,-0.142], [0.613,-0.153,-0.037], [-0.272,-4.224,-1.088], [-0.169,-1.491,-0.564]]), - (2, [[0.520,-86.043,1340.066], [0.501,16.682,-77.602], [9.142,-0.799,-0.113], [0.212,-0.392,0.096], [-0.465,-5.159,-1.112], [-0.215,-0.377,0.515]]), - (3, [[1.368,-67.733,1247.932], [0.235,-3.685,-89.672], [9.061,-1.366,0.080], [-0.833,-0.231,0.187], [-0.714,-4.722,0.192], [-0.167,0.445,1.659]]), - (4, [[0.361,-91.057,1165.531], [-2.499,-24.560,-49.102], [7.540,-1.290,0.261], [-0.809,1.514,2.095], [-0.806,-4.269,2.176], [0.001,0.896,0.910]]), - (5, [[11.750,-111.874,1127.887], [7.636,-5.715,-7.930], [5.678,1.265,4.556], [-8.397,13.092,24.878], [-0.708,-3.530,1.862], [-0.807,-7.995,7.596]]) - ]), + [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, + Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ + (1, [[0.394, -100.872, 1402.818], [-0.035, 12.367, -48.020], [8.730, -0.526, -0.142], [0.613, -0.153, -0.037], [-0.272, -4.224, -1.088], [-0.169, -1.491, -0.564]]), + (2, [[0.520, -86.043, 1340.066], [0.501, 16.682, -77.602], [9.142, -0.799, -0.113], [0.212, -0.392, 0.096], [-0.465, -5.159, -1.112], [-0.215, -0.377, 0.515]]), + (3, [[1.368, -67.733, 1247.932], [0.235, -3.685, -89.672], [9.061, -1.366, 0.080], [-0.833, -0.231, 0.187], [-0.714, -4.722, 0.192], [-0.167, 0.445, 1.659]]), + (4, [[0.361, -91.057, 1165.531], [-2.499, -24.560, -49.102], [7.540, -1.290, 0.261], [-0.809, 1.514, 2.095], [-0.806, -4.269, 2.176], [0.001, 0.896, 0.910]]), + (5, [[11.750, -111.874, 1127.887], [7.636, -5.715, -7.930], [5.678, 1.265, 4.556], [-8.397, 13.092, 24.878], [-0.708, -3.530, 1.862], [-0.807, -7.995, 7.596]]) + ]), 'userAnnotationGroups': [ { @@ -76,8 +71,15 @@ class MeshType_3d_esophagus1(Scaffold_base): 'name': get_esophagus_term('abdominal part of esophagus')[0], 'ontId': get_esophagus_term('abdominal part of esophagus')[1] }] - }) - } + }) + + +class MeshType_3d_esophagus1(Scaffold_base): + """ + Generates a 3-D esophagus mesh with variable numbers of elements around, along the central line, and through wall. + The esophagus is created by a function that generates an elliptical tube segment and uses tubemesh to map the + segment along a central path profile. + """ @staticmethod def getName(): @@ -91,9 +93,8 @@ def getParameterSetNames(): @classmethod def getDefaultOptions(cls, parameterSetName='Default'): - centralPathOption = cls.parameterSetStructureStrings['Human 1'] options = { - 'Central path': copy.deepcopy(centralPathOption), + 'Network layout': getDefaultNetworkLayoutScaffoldPackage(cls, parameterSetName), 'Number of elements around': 8, 'Number of elements along': 20, 'Number of elements through wall': 1, @@ -114,7 +115,7 @@ def getDefaultOptions(cls, parameterSetName='Default'): @staticmethod def getOrderedOptionNames(): return [ - 'Central path', + 'Network layout', 'Number of elements around', 'Number of elements along', 'Number of elements through wall', @@ -132,14 +133,14 @@ def getOrderedOptionNames(): @classmethod def getOptionValidScaffoldTypes(cls, optionName): - if optionName == 'Central path': + if optionName == 'Network layout': return [MeshType_1d_network_layout1] return [] @classmethod def getOptionScaffoldTypeParameterSetNames(cls, optionName, scaffoldType): - if optionName == 'Central path': - return list(cls.parameterSetStructureStrings.keys()) + if optionName == 'Network layout': + return cls.getParameterSetNames() assert scaffoldType in cls.getOptionValidScaffoldTypes(optionName), \ cls.__name__ + '.getOptionScaffoldTypeParameterSetNames. ' + \ 'Invalid option \'' + optionName + '\' scaffold type ' + scaffoldType.getName() @@ -155,16 +156,16 @@ def getOptionScaffoldPackage(cls, optionName, scaffoldType, parameterSetName=Non assert parameterSetName in cls.getOptionScaffoldTypeParameterSetNames(optionName, scaffoldType), \ 'Invalid parameter set ' + str(parameterSetName) + ' for scaffold ' + str(scaffoldType.getName()) + \ ' in option ' + str(optionName) + ' of scaffold ' + cls.getName() - if optionName == 'Central path': + if optionName == 'Network layout': if not parameterSetName: - parameterSetName = list(cls.parameterSetStructureStrings.keys())[0] - return copy.deepcopy(cls.parameterSetStructureStrings[parameterSetName]) + parameterSetName = "Default" + return getDefaultNetworkLayoutScaffoldPackage(cls, parameterSetName) assert False, cls.__name__ + '.getOptionScaffoldPackage: Option ' + optionName + ' is not a scaffold' @classmethod def checkOptions(cls, options): - if not options['Central path'].getScaffoldType() in cls.getOptionValidScaffoldTypes('Central path'): - options['Central path'] = cls.getOptionScaffoldPackage('Central path', MeshType_1d_network_layout1) + if not options['Network layout'].getScaffoldType() in cls.getOptionValidScaffoldTypes('Network layout'): + options['Network layout'] = cls.getOptionScaffoldPackage('Network layout', MeshType_1d_network_layout1) if options['Number of elements through wall'] != (1 or 4): options['Number of elements through wall'] = 4 for key in [ @@ -191,7 +192,7 @@ def generateBaseMesh(cls, region, options): nextElementIdentifier = 1 esophagusTermsAlong = ['esophagus', 'cervical part of esophagus', 'thoracic part of esophagus', 'abdominal part of esophagus'] - geometricCentralPath = options['Central path'] + geometricCentralPath = options['Network layout'] geometricCentralPath = EsophagusCentralPath(region, geometricCentralPath, esophagusTermsAlong) annotationGroups, nextNodeIdentifier, nextElementIdentifier = \ diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_gastrointestinaltract1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_gastrointestinaltract1.py index 824cb3d9..bf8bec26 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_gastrointestinaltract1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_gastrointestinaltract1.py @@ -29,15 +29,10 @@ from scaffoldmaker.utils.zinc_utils import exnode_string_from_nodeset_field_parameters -class MeshType_3d_gastrointestinaltract1(Scaffold_base): - ''' - Generates a 3-D gastrointestinal tract mesh with variable numbers of elements around, along the central line, - and through wall. The tract is created by following an annotated central path and calling scaffold function to - generate the respective segment along the central line profile. - ''' - - parameterSetStructureStrings = { - 'Human 1': ScaffoldPackage(MeshType_1d_network_layout1, { +def getDefaultNetworkLayoutScaffoldPackage(cls, parameterSetName): + assert parameterSetName in cls.getParameterSetNames() # make sure parameter set is in list of parameters of parent scaffold + if parameterSetName in ("Default", "Human 1"): + return ScaffoldPackage(MeshType_1d_network_layout1, { 'scaffoldSettings': { "Structure": "1-2-3-4-5-6-7.2, 8-9-10-11-7-12-13-14-15-16-17-18-19-20-21-22-23-24-25-26-27-28-29-30-31-" "32-33-34-35-36-37-38-39-40-41-42-43-44-45-46-47-48-49-50-51-52-53-54-55-56-57-58-59-60-" @@ -425,7 +420,14 @@ class MeshType_3d_gastrointestinaltract1(Scaffold_base): 'ontId': get_colon_term('descending colon')[1] }] }) - } + + +class MeshType_3d_gastrointestinaltract1(Scaffold_base): + ''' + Generates a 3-D gastrointestinal tract mesh with variable numbers of elements around, along the central line, + and through wall. The tract is created by following an annotated central path and calling scaffold function to + generate the respective segment along the central line profile. + ''' @staticmethod def getName(): @@ -439,13 +441,12 @@ def getParameterSetNames(): @classmethod def getDefaultOptions(cls, parameterSetName='Default'): - centralPathOption = cls.parameterSetStructureStrings['Human 1'] esophagusOption = ScaffoldPackage(MeshType_3d_esophagus1, defaultParameterSetName='Human 1') stomachOption = ScaffoldPackage(MeshType_3d_stomach1, defaultParameterSetName='Human 2') smallIntestineOption = ScaffoldPackage(MeshType_3d_smallintestine1, defaultParameterSetName='Human 1') cecumOption = ScaffoldPackage(MeshType_3d_cecum1, defaultParameterSetName='Human 2') colonOption = ScaffoldPackage(MeshType_3d_colon1, defaultParameterSetName='Human 3') - options = {'Central path': copy.deepcopy(centralPathOption), + options = {'Network layout': getDefaultNetworkLayoutScaffoldPackage(cls, parameterSetName), 'Esophagus': esophagusOption, 'Stomach': stomachOption, 'Small intestine': smallIntestineOption, @@ -462,7 +463,7 @@ def getDefaultOptions(cls, parameterSetName='Default'): @staticmethod def getOrderedOptionNames(): return [ - 'Central path', + 'Network layout', 'Esophagus', 'Stomach', 'Small intestine', @@ -475,7 +476,7 @@ def getOrderedOptionNames(): @classmethod def getOptionValidScaffoldTypes(cls, optionName): - if optionName == 'Central path': + if optionName == 'Network layout': return [MeshType_1d_network_layout1] if optionName == 'Esophagus': return [MeshType_3d_esophagus1] @@ -491,8 +492,8 @@ def getOptionValidScaffoldTypes(cls, optionName): @classmethod def getOptionScaffoldTypeParameterSetNames(cls, optionName, scaffoldType): - if optionName == 'Central path': - return list(cls.parameterSetStructureStrings.keys()) + if optionName == 'Network layout': + return cls.getParameterSetNames() assert scaffoldType in cls.getOptionValidScaffoldTypes(optionName), \ cls.__name__ + '.getOptionScaffoldTypeParameterSetNames. ' + \ 'Invalid option \'' + optionName + '\' scaffold type ' + scaffoldType.getName() @@ -508,10 +509,10 @@ def getOptionScaffoldPackage(cls, optionName, scaffoldType, parameterSetName=Non assert parameterSetName in cls.getOptionScaffoldTypeParameterSetNames(optionName, scaffoldType), \ 'Invalid parameter set ' + str(parameterSetName) + ' for scaffold ' + str(scaffoldType.getName()) + \ ' in option ' + str(optionName) + ' of scaffold ' + cls.getName() - if optionName == 'Central path': + if optionName == 'Network layout': if not parameterSetName: - parameterSetName = list(cls.parameterSetStructureStrings.keys())[0] - return copy.deepcopy(cls.parameterSetStructureStrings[parameterSetName]) + parameterSetName = "Default" + return getDefaultNetworkLayoutScaffoldPackage(cls, parameterSetName) if optionName == 'Esophagus': if not parameterSetName: parameterSetName = scaffoldType.getParameterSetNames()[0] @@ -536,8 +537,8 @@ def getOptionScaffoldPackage(cls, optionName, scaffoldType, parameterSetName=Non @classmethod def checkOptions(cls, options): - if not options['Central path'].getScaffoldType() in cls.getOptionValidScaffoldTypes('Central path'): - options['Central path'] = cls.getOptionScaffoldPackage('Central path', MeshType_1d_network_layout1) + if not options['Network layout'].getScaffoldType() in cls.getOptionValidScaffoldTypes('Network layout'): + options['Network layout'] = cls.getOptionScaffoldPackage('Network layout', MeshType_1d_network_layout1) if not options['Esophagus'].getScaffoldType() in cls.getOptionValidScaffoldTypes('Esophagus'): options['Esophagus'] = cls.getOptionScaffoldPackage('Esophagus', MeshType_3d_stomach1) if not options['Stomach'].getScaffoldType() in cls.getOptionValidScaffoldTypes('Stomach'): @@ -564,7 +565,7 @@ def generateBaseMesh(cls, region, options): :param options: Dict containing options. See getDefaultOptions(). :return: annotationGroups """ - centralPath = options['Central path'] + centralPath = options['Network layout'] esophagusOptions = options['Esophagus'] stomachOptions = options['Stomach'] smallIntestineOptions = options['Small intestine'] diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_ostium2.py b/src/scaffoldmaker/meshtypes/meshtype_3d_ostium2.py index d661c3af..e4871996 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_ostium2.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_ostium2.py @@ -25,23 +25,25 @@ get_nodeset_path_field_parameters - -class MeshType_3d_ostium2(Scaffold_base): - """ - Generates a 3-D single or double/common ostium inlet or outlet. - """ - parameterSetStructureStrings = { - 'Default': ScaffoldPackage(MeshType_1d_network_layout1, { +def getDefaultNetworkLayoutScaffoldPackage(cls, parameterSetName): + assert parameterSetName in cls.getParameterSetNames() # make sure parameter set is in list of parameters of parent scaffold + if parameterSetName in ("Default"): + return ScaffoldPackage(MeshType_1d_network_layout1, { 'scaffoldSettings': { "Structure": "1-2-3" }, 'meshEdits': exnode_string_from_nodeset_field_parameters( - [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ - (1, [[0.00,0.00,1.00], [0.00,0.00,-0.50], [0.00,0.50,0.00], [0.00,0.00,0.00], [1.00,0.00,0.00], [0.00,0.00,0.00]]), - (2, [[0.00,0.00,0.50], [0.00,0.00,-0.50], [0.00,1.00,0.00], [0.00,0.00,0.00], [1.00,0.00,0.00], [0.00,0.00,0.00]]), - (3, [[0.00,0.00,0.00], [0.00,0.00,-0.50], [0.00,1.00,0.00], [0.00,0.00,0.00], [2.00,0.00,0.00], [0.00,0.00,0.00]])]) + [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, + Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ + (1, [[0.00, 0.00, 1.00], [0.00, 0.00, -0.50], [0.00, 0.50, 0.00], [0.00, 0.00, 0.00], [1.00, 0.00, 0.00], [0.00, 0.00, 0.00]]), + (2, [[0.00, 0.00, 0.50], [0.00, 0.00, -0.50], [0.00, 1.00, 0.00], [0.00, 0.00, 0.00], [1.00, 0.00, 0.00], [0.00, 0.00, 0.00]]), + (3, [[0.00, 0.00, 0.00], [0.00, 0.00, -0.50], [0.00, 1.00, 0.00], [0.00, 0.00, 0.00], [2.00, 0.00, 0.00], [0.00, 0.00, 0.00]])]) }) - } + +class MeshType_3d_ostium2(Scaffold_base): + """ + Generates a 3-D single or double/common ostium inlet or outlet. + """ @staticmethod def getName(): @@ -49,9 +51,8 @@ def getName(): @classmethod def getDefaultOptions(cls, parameterSetName='Default'): - centralPathOption = cls.parameterSetStructureStrings['Default'] options = { - 'Central path': copy.deepcopy(centralPathOption), + 'Network layout': getDefaultNetworkLayoutScaffoldPackage(cls, parameterSetName), # 'Number of vessels': 1, # 'Number of elements across common': 2, 'Number of elements around ostium': 8, @@ -79,7 +80,7 @@ def getDefaultOptions(cls, parameterSetName='Default'): @staticmethod def getOrderedOptionNames(): return [ - 'Central path', + 'Network layout', # 'Number of vessels', # 'Number of elements across common', 'Number of elements around ostium', @@ -104,13 +105,13 @@ def getOrderedOptionNames(): @classmethod def getOptionValidScaffoldTypes(cls, optionName): - if optionName == 'Central path': + if optionName == 'Network layout': return [MeshType_1d_network_layout1] @classmethod def getOptionScaffoldTypeParameterSetNames(cls, optionName, scaffoldType): - if optionName == 'Central path': - return list(cls.parameterSetStructureStrings.keys()) + if optionName == 'Network layout': + return cls.getParameterSetNames() assert scaffoldType in cls.getOptionValidScaffoldTypes(optionName), \ cls.__name__ + '.getOptionScaffoldTypeParameterSetNames. ' + \ 'Invalid option \'' + optionName + '\' scaffold type ' + scaffoldType.getName() @@ -126,17 +127,17 @@ def getOptionScaffoldPackage(cls, optionName, scaffoldType, parameterSetName=Non assert parameterSetName in cls.getOptionScaffoldTypeParameterSetNames(optionName, scaffoldType), \ 'Invalid parameter set ' + str(parameterSetName) + ' for scaffold ' + str(scaffoldType.getName()) + \ ' in option ' + str(optionName) + ' of scaffold ' + cls.getName() - if optionName == 'Central path': + if optionName == 'Network layout': if not parameterSetName: - parameterSetName = list(cls.parameterSetStructureStrings.keys())[0] - return copy.deepcopy(cls.parameterSetStructureStrings[parameterSetName]) + parameterSetName = "Default" + return getDefaultNetworkLayoutScaffoldPackage(cls, parameterSetName) assert False, cls.__name__ + '.getOptionScaffoldPackage: Option ' + optionName + ' is not a scaffold' @classmethod def checkOptions(cls, options): dependentChanges = False - if not options['Central path'].getScaffoldType() in cls.getOptionValidScaffoldTypes('Central path'): - options['Central path'] = cls.getOptionScaffoldPackage('Central path', MeshType_1d_network_layout1) + if not options['Network layout'].getScaffoldType() in cls.getOptionValidScaffoldTypes('Network layout'): + options['Network layout'] = cls.getOptionScaffoldPackage('Network layout', MeshType_1d_network_layout1) # vesselsCount = options['Number of vessels'] # if vesselsCount != 1: # vesselsCount = options['Number of vessels'] = 1 @@ -197,7 +198,7 @@ def generateBaseMesh(cls, region, options): :return: [] empty list of AnnotationGroup, None """ unitScale = options['Unit scale'] - centralPath = options['Central path'] + centralPath = options['Network layout'] centralPath = CentralPath(region, centralPath, unitScale) # interVesselDistance = unitScale * options['Ostium inter-vessel distance'] diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_smallintestine1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_smallintestine1.py index 85c21aaf..fc335a8e 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_smallintestine1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_smallintestine1.py @@ -23,17 +23,206 @@ get_nodeset_path_field_parameters -class MeshType_3d_smallintestine1(Scaffold_base): - ''' - Generates a 3-D small intestine mesh with variable numbers - of elements around, along the central line, and through wall. - The small intestine is created by a function that generates - a small intestine segment and uses tubemesh to map the segment - along a central line profile. - ''' +def getDefaultNetworkLayoutScaffoldPackage(cls, parameterSetName): + assert parameterSetName in cls.getParameterSetNames() # make sure parameter set is in list of parameters of parent scaffold + if parameterSetName in ("Default", "Human 1"): + return ScaffoldPackage(MeshType_1d_network_layout1, { + 'scaffoldSettings': { + "Structure": "1-2-3-4-5-6-7-8-9-10-11-12-13-14-15-16-17-18-19-20-21-22-23-24-25-26-27-28-29-30-31-32-" + "33-34-35-36-37-38-39-40-41-42-43-44-45-46-47-48-49-50-51-52-53-54-55-56-57-58-59-60-61-" + "62-63-64-65-66-67-68-69-70-71-72-73-74-75-76-77-78-79-80-81-82-83-84-85-86-87-88-89-90-" + "91-92-93-94-95-96-97-98-99-100-101-102-103-104-105-106-107-108-109-110-111-112-113-114-" + "115-116-117-118-119-120-121-122-123-124-125-126-127-128-129-130-131-132-133-134-135-136-" + "137-138-139-140-141-142-143-144-145-146-147-148-149-150-151-152" + }, + 'meshEdits': exnode_string_from_nodeset_field_parameters( + [ Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3 ], [ + (1, [[-32.281,-136.261,1061.249], [-6.125,11.114,-0.493], [-5.735,-3.374,-4.823], [-2.070,-0.220,-4.520], [-4.630,-2.238,7.071], [-4.400,2.440,0.570]]), + (2, [[-40.674,-122.300,1060.850], [-5.403,7.321,-2.629], [-4.779,-4.249,-5.161], [2.360,-0.320,0.120], [-5.138,-1.668,6.875], [-0.250,2.080,-4.500]]), + (3, [[-48.346,-108.981,1049.574], [-6.840,19.440,-21.940], [-3.459,-4.108,-5.699], [0.900,0.690,1.570], [-7.043,0.777,3.341], [-0.760,2.950,-2.230]]), + (4, [[-43.450,-95.700,1015.590], [40.730,3.220,-44.800], [-5.240,-3.340,-4.990], [-0.380,4.380,-0.330], [-2.270,6.020,-1.640], [4.590,3.490,-0.790]]), + (5, [[26.760,-119.310,992.030], [58.860,-18.680,-8.450], [0.310,3.940,-6.600], [4.150,2.330,1.070], [2.230,5.490,3.380], [3.360,-4.080,2.370]]), + (6, [[63.862,-132.266,992.002], [9.680,-30.910,-18.900], [5.846,1.916,2.960], [-0.330,-6.200,3.780], [5.300,-1.090,4.490], [-3.680,-1.570,1.510]]), + (7, [[46.280,-139.940,982.680], [-22.680,-4.850,-10.940], [1.050,-7.060,0.970], [-0.930,-3.800,3.220], [-3.190,0.420,6.420], [-5.340,-0.640,-2.850]]), + (8, [[28.560,-141.070,974.610], [3.750,-10.520,-21.300], [1.560,-6.210,3.340], [-1.000,0.060,-0.070], [-6.850,-1.870,-0.290], [1.100,-0.530,-6.400]]), + (9, [[52.390,-146.130,971.400], [18.400,-3.700,0.670], [-1.440,-7.110,0.300], [-0.590,-0.290,-0.540], [0.190,-0.340,-7.250], [2.420,0.060,-1.890]]), + (10, [[63.130,-148.180,973.520], [10.490,-1.410,1.470], [-1.070,-7.160,0.770], [2.410,0.380,0.120], [0.880,-0.900,-7.160], [-2.030,-1.100,0.840]]), + (11, [[72.690,-148.910,974.300], [7.650,3.570,-7.080], [3.500,-6.340,0.580], [0.430,0.200,-1.420], [-3.880,-2.630,-5.520], [-3.490,0.080,4.650]]), + (12, [[71.050,-143.650,964.650], [-5.960,4.700,-11.040], [-0.810,-6.830,-2.470], [-2.360,-0.380,-1.140], [-6.400,-0.430,3.270], [0.270,0.950,6.070]]), + (13, [[61.060,-140.780,954.520], [-17.960,3.880,-6.220], [-1.070,-7.120,-1.370], [0.180,-0.250,1.370], [-2.560,-0.940,6.800], [3.840,0.270,2.130]]), + (14, [[37.990,-136.930,957.170], [-18.820,0.880,5.080], [-0.160,-7.340,0.670], [1.900,0.170,0.590], [1.940,0.610,7.070], [2.120,1.030,-0.120]]), + (15, [[24.260,-138.060,963.160], [-17.400,-6.040,8.510], [2.590,-6.900,0.380], [2.420,1.010,0.690], [2.780,1.420,6.690], [-2.180,-0.670,-0.740]]), + (16, [[6.500,-150.310,973.050], [-8.250,-16.440,-13.420], [4.890,-4.750,2.820], [-1.080,-0.490,-0.280], [-4.820,-1.850,5.240], [-4.270,-0.820,-2.180]]), + (17, [[15.970,-149.800,957.690], [-4.350,-1.250,-14.050], [0.990,-7.390,0.350], [-1.040,-0.780,-0.850], [-6.950,-0.830,2.230], [-0.480,0.190,-0.500]]), + (18, [[8.290,-150.980,954.250], [-3.340,-0.730,-8.150], [1.180,-7.370,0.180], [0.180,0.050,0.370], [-6.710,-1.000,2.840], [0.560,-0.430,-3.270]]), + (19, [[10.770,-150.880,946.760], [5.270,-0.050,-7.150], [1.370,-7.280,1.060], [-0.120,-0.030,0.050], [-5.800,-1.710,-4.270], [2.050,0.220,-4.830]]), + (20, [[18.300,-151.090,941.260], [7.790,0.880,-2.390], [0.880,-7.450,0.160], [0.050,-0.010,-0.900], [-2.150,-0.400,-7.160], [4.520,1.490,-0.770]]), + (21, [[24.850,-149.580,941.590], [5.320,0.620,3.020], [1.330,-7.350,-0.840], [-0.350,0.010,-0.650], [3.510,1.370,-6.460], [3.430,0.580,1.190]]), + (22, [[27.850,-149.810,945.920], [3.490,-0.550,3.990], [0.330,-7.390,-1.300], [-0.750,-0.040,-0.150], [5.610,1.090,-4.760], [-0.580,-0.160,-0.310]]), + (23, [[31.640,-150.640,949.370], [5.770,-0.500,1.810], [-0.280,-7.430,-1.160], [0.320,-0.010,0.320], [2.310,1.020,-7.080], [-4.590,-0.600,-0.740]]), + (24, [[38.160,-150.550,948.480], [5.400,1.270,-4.340], [1.280,-7.400,-0.560], [1.280,0.320,-0.530], [-4.630,-0.350,-5.870], [-4.440,-1.610,3.120]]), + (25, [[40.300,-148.530,942.170], [-0.500,2.450,-7.550], [2.420,-6.730,-2.350], [1.390,0.820,-0.980], [-7.020,-2.420,-0.320], [-0.570,-0.950,1.020]]), + (26, [[36.760,-146.190,935.090], [3.270,5.380,-6.440], [4.320,-5.620,-2.500], [0.260,-0.080,1.070], [-5.500,-2.170,-4.600], [3.600,1.240,-3.410]]), + (27, [[44.600,-142.080,934.770], [8.650,3.530,1.100], [2.850,-7.000,0.020], [-1.020,-0.770,1.000], [0.830,0.310,-7.530], [3.410,1.450,-1.300]]), + (28, [[53.340,-139.440,937.210], [8.310,2.340,2.220], [2.150,-7.250,-0.380], [-0.540,-0.170,-0.420], [1.710,0.890,-7.340], [0.070,0.370,0.030]]), + (29, [[61.180,-137.390,939.220], [8.230,1.720,1.430], [1.690,-7.360,-0.860], [-0.380,-0.100,-0.170], [1.060,1.120,-7.440], [-0.840,-0.070,-0.120]]), + (30, [[69.720,-136.030,940.040], [8.420,1.510,0.050], [1.350,-7.460,-0.740], [0.300,0.210,-0.630], [-0.090,0.740,-7.580], [-3.560,-0.970,1.730]]), + (31, [[77.280,-134.500,939.340], [4.490,4.180,-8.530], [2.310,-6.920,-2.180], [-0.290,0.070,-0.480], [-6.410,-0.930,-3.830], [-3.190,-0.950,5.530]]), + (32, [[71.890,-131.270,929.110], [-6.780,1.090,-6.790], [0.090,-7.530,-1.300], [-0.440,-0.260,1.250], [-5.410,-0.970,5.250], [0.240,0.450,2.900]]), + (33, [[66.110,-131.600,925.900], [-4.090,-0.450,-4.440], [0.540,-7.640,0.280], [0.080,0.050,1.400], [-5.560,-0.210,5.140], [-0.150,0.880,-0.160]]), + (34, [[63.930,-132.090,921.070], [-3.930,-1.160,-4.370], [0.320,-7.470,1.700], [0.720,0.300,0.950], [-5.720,0.870,4.920], [0.660,0.510,0.560]]), + (35, [[58.470,-133.890,917.960], [-6.670,-3.360,-3.670], [2.290,-6.970,2.210], [2.280,0.920,-0.110], [-3.960,0.750,6.500], [2.250,0.030,1.310]]), + (36, [[51.020,-139.090,914.020], [-6.630,-6.740,0.390], [5.400,-5.250,1.130], [1.070,0.420,-1.320], [-0.590,1.020,7.590], [3.120,0.370,0.200]]), + (37, [[46.770,-145.490,918.120], [-5.050,-4.370,2.870], [4.810,-5.920,-0.550], [-1.310,-0.890,-0.940], [2.680,1.520,7.030], [1.260,-0.680,-0.120]]), + (38, [[41.950,-147.920,919.780], [-5.030,-2.380,1.940], [2.900,-7.030,-1.100], [-1.320,-0.680,-0.330], [2.770,0.010,7.180], [-0.110,-1.000,0.120]]), + (39, [[36.760,-150.210,922.000], [-5.100,-1.680,1.580], [2.030,-7.330,-1.240], [-0.510,-0.220,0.810], [2.440,-0.560,7.300], [-0.450,0.500,0.130]]), + (40, [[31.890,-151.330,922.990], [-5.710,-1.250,1.560], [1.770,-7.500,0.460], [-0.570,-0.180,0.730], [1.840,0.880,7.450], [-2.050,0.330,0.030]]), + (41, [[25.550,-152.650,925.180], [-6.280,-0.560,-2.170], [0.700,-7.710,-0.030], [-0.690,-0.090,-0.620], [-2.500,-0.250,7.310], [-3.190,-0.780,-0.830]]), + (42, [[22.170,-152.270,920.060], [-4.850,0.300,-4.200], [0.270,-7.700,-0.850], [-0.240,-0.020,0.240], [-5.020,-0.810,5.760], [2.410,0.370,-0.060]]), + (43, [[16.600,-152.110,917.510], [-6.970,0.000,2.680], [0.200,-7.740,0.510], [-0.300,-0.030,0.600], [2.770,0.540,7.210], [5.780,0.370,-0.740]]), + (44, [[13.120,-152.320,924.900], [-3.730,0.410,7.150], [-0.450,-7.750,0.210], [-0.140,-0.020,-0.160], [6.780,-0.300,3.550], [-0.230,-0.180,0.200]]), + (45, [[9.440,-151.370,931.310], [-7.880,0.190,2.810], [-0.130,-7.780,0.170], [0.490,-0.010,0.120], [2.610,0.120,7.310], [-3.700,0.330,2.080]]), + (46, [[1.230,-152.170,928.310], [-8.130,-0.720,-1.080], [0.620,-7.760,0.490], [0.090,-0.010,-0.290], [-1.060,0.400,7.710], [1.430,-0.160,-0.650]]), + (47, [[-5.970,-152.740,928.930], [-5.640,-0.310,4.390], [0.170,-7.800,-0.330], [-0.930,0.040,0.090], [4.760,-0.160,6.120], [3.980,-0.840,-4.110]]), + (48, [[-8.050,-152.700,935.120], [0.840,0.430,7.280], [-1.310,-7.670,0.600], [-1.080,0.170,0.740], [7.520,-1.340,-0.790], [0.790,-0.430,-1.110]]), + (49, [[-4.180,-151.980,940.930], [-5.500,2.850,8.020], [-2.070,-7.440,1.220], [-0.370,0.070,-0.100], [6.170,-0.960,4.570], [-3.010,0.560,4.290]]), + (50, [[-15.920,-150.230,939.850], [-11.530,2.830,0.080], [-1.870,-7.620,-0.020], [0.120,0.150,0.780], [0.040,-0.030,7.840], [0.810,0.000,-1.160]]), + (51, [[-25.870,-146.770,940.970], [-2.690,4.150,9.230], [-1.800,-7.150,2.690], [0.690,0.200,1.480], [7.250,-0.880,2.510], [1.720,-1.410,-6.490]]), + (52, [[-19.430,-146.580,946.990], [7.700,1.830,5.130], [-0.490,-7.140,3.290], [1.240,-0.130,-0.090], [4.500,-2.940,-5.700], [-0.590,-0.040,-3.450]]), + (53, [[-11.610,-143.430,950.540], [5.250,2.520,5.680], [0.830,-7.420,2.520], [0.750,-0.240,-0.870], [5.910,-1.040,-5.000], [0.830,1.410,0.570]]), + (54, [[-9.220,-141.820,956.880], [3.600,1.580,5.200], [1.220,-7.660,1.480], [-0.050,-0.130,-0.420], [6.390,0.150,-4.470], [0.120,0.280,0.100]]), + (55, [[-4.880,-140.390,960.700], [3.780,1.360,4.900], [0.780,-7.720,1.540], [0.070,-0.060,-0.650], [6.230,-0.310,-4.720], [0.530,0.530,1.660]]), + (56, [[-1.980,-139.200,966.470], [0.650,0.130,7.290], [1.420,-7.780,0.010], [0.230,-0.060,-0.880], [7.610,1.390,-0.700], [0.660,0.740,3.140]]), + (57, [[-4.150,-140.360,973.960], [-2.380,-0.650,10.170], [1.190,-7.830,-0.220], [-0.650,-0.070,-0.200], [7.500,1.090,1.830], [-0.210,-0.700,2.000]]), + (58, [[-6.206,-140.381,984.826], [-3.997,1.953,8.625], [-0.240,-7.940,-0.400], [-0.770,0.020,-0.440], [7.090,-0.380,3.280], [-1.820,-1.020,2.460]]), + (59, [[-11.071,-137.239,990.534], [-6.502,2.564,3.616], [-0.730,-7.850,-1.030], [0.040,-0.000,-0.150], [4.330,-1.250,6.510], [-3.510,-0.150,2.180]]), + (60, [[-18.114,-135.562,991.751], [-6.821,0.865,-0.438], [-0.170,-7.940,-0.730], [0.590,-0.040,0.750], [-0.320,-0.720,7.930], [-4.070,0.690,0.160]]), + (61, [[-24.108,-135.469,989.949], [-5.560,-1.043,-2.740], [0.530,-7.940,0.630], [-0.080,0.160,1.480], [-4.270,0.240,6.690], [-3.140,0.950,-2.220]]), + (62, [[-28.764,-137.545,986.518], [-3.033,-3.486,-4.184], [-0.280,-7.620,2.380], [-1.430,0.310,0.610], [-7.020,1.290,3.320], [-0.940,0.180,-5.150]]), + (63, [[-29.636,-141.811,982.334], [1.634,-2.756,-5.189], [-2.170,-7.290,2.440], [-1.160,0.110,-0.290], [-7.100,1.030,-3.250], [0.490,-0.350,-4.870]]), + (64, [[-24.820,-145.190,978.580], [4.650,-2.180,-4.590], [-2.130,-7.580,1.440], [0.290,-0.260,-0.910], [-5.460,0.450,-5.750], [-0.330,0.230,1.000]]), + (65, [[-20.750,-146.910,974.010], [1.230,-0.700,-6.940], [-1.580,-7.840,0.510], [0.080,-0.090,-0.690], [-7.590,1.430,-1.480], [0.460,0.350,5.770]]), + (66, [[-23.390,-146.100,967.330], [-6.320,1.650,-4.010], [-2.030,-7.760,0.010], [-0.160,0.070,0.360], [-4.040,1.070,6.800], [4.830,-0.400,4.280]]), + (67, [[-30.600,-144.330,967.780], [-6.690,2.040,2.190], [-1.930,-7.690,1.270], [0.050,0.000,0.440], [2.650,0.580,7.550], [3.030,-0.350,0.340]]), + (68, [[-36.170,-142.250,971.340], [-6.590,1.940,2.270], [-1.940,-7.730,1.010], [0.040,-0.010,0.090], [2.700,0.310,7.560], [0.370,-0.020,-0.150]]), + (69, [[-43.400,-140.590,972.070], [-6.040,1.970,2.740], [-1.830,-7.710,1.480], [0.020,0.340,1.180], [3.470,0.560,7.230], [2.300,-0.410,-2.270]]), + (70, [[-47.620,-138.630,976.140], [-1.780,2.680,4.620], [-1.870,-7.070,3.390], [0.010,0.350,0.980], [7.300,-0.460,3.080], [1.720,-1.440,-3.710]]), + (71, [[-47.100,-135.980,980.160], [0.980,1.950,4.050], [-1.830,-6.900,3.760], [0.210,-0.140,-0.200], [7.550,-2.370,-0.680], [0.040,-0.760,-2.210]]), + (72, [[-45.780,-134.750,984.020], [1.920,1.940,5.580], [-1.460,-7.340,3.050], [-0.530,0.370,0.090], [7.430,-2.220,-1.790], [-0.240,0.260,1.070]]), + (73, [[-42.419,-130.149,990.122], [-1.920,7.780,7.360], [-3.780,-5.370,4.690], [-2.140,1.260,-0.060], [6.910,-1.720,3.610], [-3.470,2.540,4.150]]), + (74, [[-48.414,-118.983,992.238], [-8.280,6.980,-7.760], [-5.960,-5.080,1.790], [0.610,-1.110,-1.840], [-2.030,4.630,6.340], [-6.540,1.980,-0.430]]), + (75, [[-54.520,-122.570,980.900], [-5.100,0.460,-13.050], [-2.600,-7.660,0.750], [2.850,-1.090,0.850], [-7.020,2.660,2.840], [-2.860,-1.790,-2.310]]), + (76, [[-56.534,-121.929,967.273], [-3.400,-6.950,-12.830], [-2.036,-6.714,3.150], [-1.690,1.750,1.250], [-7.800,0.860,1.600], [1.210,-0.700,-4.510]]), + (77, [[-57.601,-134.069,961.014], [4.440,-11.120,-4.920], [-6.170,-3.970,3.410], [-1.800,0.340,-0.380], [-4.460,1.190,-6.700], [1.720,-0.860,-3.600]]), + (78, [[-53.650,-142.090,958.040], [8.150,-8.950,-3.450], [-4.950,-5.680,3.060], [2.040,-1.620,-0.110], [-3.750,-0.620,-7.230], [-0.920,-0.860,0.970]]), + (79, [[-43.780,-150.900,953.550], [6.860,-6.210,-10.820], [-1.570,-7.380,3.240], [0.100,-0.470,-1.480], [-6.930,-0.360,-4.180], [-0.500,1.880,6.120]]), + (80, [[-42.790,-151.920,940.920], [-10.160,7.350,-12.870], [-4.740,-6.680,-0.070], [-1.780,0.370,-1.940], [-4.810,3.350,5.710], [1.370,1.930,5.900]]), + (81, [[-59.560,-139.320,940.870], [-10.470,7.530,-10.550], [-4.670,-6.770,-0.210], [-0.780,0.740,0.770], [-4.390,2.820,6.370], [-0.630,1.740,-4.220]]), + (82, [[-61.190,-138.430,930.230], [-0.370,-2.040,-12.190], [-5.970,-5.520,1.110], [-0.860,0.960,0.960], [-5.640,5.920,-0.830], [0.650,-0.720,-6.690]]), + (83, [[-60.050,-143.370,918.840], [6.120,-9.410,-3.110], [-6.440,-4.780,1.790], [0.250,-0.370,-0.760], [-2.750,0.780,-7.780], [3.390,-3.100,-3.060]]), + (84, [[-54.810,-148.970,924.540], [7.070,-6.600,2.050], [-5.610,-6.050,-0.170], [0.760,-0.860,-0.330], [1.380,-1.050,-8.130], [-1.610,1.400,1.580]]), + (85, [[-48.000,-154.670,922.570], [3.540,-3.720,-7.480], [-4.830,-6.610,1.000], [1.210,-0.760,-0.140], [-5.850,3.580,-4.550], [-4.060,1.810,3.830]]), + (86, [[-49.390,-154.510,914.460], [0.270,0.350,-10.670], [-3.110,-7.640,-0.330], [1.860,-0.790,-0.480], [-7.540,3.070,-0.100], [1.640,-1.570,-0.540]]), + (87, [[-46.730,-154.010,904.000], [18.990,-1.890,-1.480], [-0.780,-8.190,0.400], [1.310,-0.300,0.500], [-0.670,-0.340,-8.190], [5.190,-2.310,-4.980]]), + (88, [[-31.900,-157.000,923.200], [20.270,-2.840,5.710], [-1.280,-8.040,0.540], [1.630,0.180,0.170], [2.100,-0.860,-7.850], [-3.210,-0.770,1.420]]), + (89, [[-17.040,-158.470,917.330], [10.690,1.600,-10.940], [1.940,-7.840,0.740], [0.870,0.010,-0.110], [-5.440,-1.880,-5.580], [-1.710,0.190,-0.090]]), + (90, [[-12.920,-154.880,905.590], [14.280,1.560,-5.120], [1.010,-8.000,0.370], [-0.980,-0.090,-0.580], [-2.650,-0.690,-7.580], [1.890,1.140,-1.150]]), + (91, [[0.790,-157.220,913.220], [17.050,-0.100,-3.500], [-0.160,-8.010,-0.530], [0.240,0.090,-0.240], [-1.610,0.550,-7.830], [0.100,0.160,0.010]]), + (92, [[11.370,-154.850,899.810], [20.470,4.340,-7.040], [1.620,-7.800,-0.100], [0.670,0.240,-0.620], [-2.500,-0.420,-7.540], [-1.600,0.070,0.920]]), + (93, [[35.280,-149.960,905.730], [15.010,5.710,-13.200], [0.800,-7.500,-2.330], [1.120,0.330,0.340], [-5.360,1.170,-5.590], [-1.050,-1.380,0.950]]), + (94, [[31.510,-148.900,893.070], [11.510,6.020,-14.640], [3.170,-7.130,-0.440], [1.650,0.510,0.450], [-5.440,-2.110,-5.150], [2.200,-0.030,-0.530]]), + (95, [[53.210,-142.180,892.150], [16.130,8.560,4.600], [3.960,-6.330,-2.130], [0.420,0.200,0.800], [0.580,2.810,-7.250], [3.440,1.000,-0.610]]), + (96, [[61.915,-135.512,899.756], [10.425,5.807,7.557], [4.220,-6.470,0.220], [-1.030,-0.530,1.150], [2.810,1.590,-7.040], [-2.200,-1.800,0.660]]), + (97, [[72.652,-131.499,906.138], [13.270,2.580,-11.410], [1.590,-7.520,0.150], [-0.630,-0.250,0.200], [-4.770,-1.120,-5.790], [-4.380,-1.930,4.880]]), + (98, [[70.933,-136.139,889.296], [-12.490,-8.250,-22.650], [3.260,-6.840,0.700], [0.840,0.360,-0.040], [-5.890,-2.380,4.110], [0.640,-0.370,7.040]]), + (99, [[47.820,-142.630,864.930], [-22.720,-8.470,-7.520], [2.750,-7.000,-0.430], [0.030,0.230,-1.270], [-1.940,-1.200,7.190], [5.330,1.350,0.110]]), + (100, [[33.710,-147.840,866.620], [-7.310,-5.020,5.800], [3.020,-6.590,-1.880], [-0.710,0.240,-1.450], [4.500,0.350,5.980], [2.350,2.560,-6.780]]), + (101, [[33.450,-149.550,870.080], [6.660,-2.670,8.620], [1.910,-6.380,-3.460], [-0.810,0.030,-0.860], [5.650,3.480,-3.300], [0.800,2.080,-6.770]]), + (102, [[48.500,-149.860,877.560], [8.440,-1.400,10.880], [1.840,-6.880,-2.310], [-0.550,-0.390,1.170], [5.590,2.820,-3.970], [-1.370,-2.160,5.890]]), + (103, [[49.170,-151.340,885.880], [-14.130,-2.760,6.710], [0.940,-7.250,-1.010], [-0.570,0.330,-0.410], [3.260,-0.510,6.640], [-3.090,-3.470,6.170]]), + (104, [[30.330,-151.820,877.700], [-17.160,1.530,-4.960], [0.920,-5.490,-4.890], [-1.510,-0.140,0.400], [-1.940,-4.930,5.180], [0.640,-0.130,0.130]]), + (105, [[16.360,-149.060,875.570], [-10.970,1.710,5.380], [-1.800,-6.980,-1.460], [-0.540,-0.730,1.970], [2.830,-2.080,6.450], [2.860,1.800,-0.060]]), + (106, [[11.690,-148.720,883.920], [-10.140,1.000,8.830], [-0.940,-7.280,-0.260], [0.660,-0.150,1.090], [4.710,-0.800,5.500], [-0.400,1.320,0.040]]), + (107, [[-3.830,-146.990,890.110], [-14.280,1.090,0.550], [-0.520,-7.220,0.830], [0.360,0.010,-0.260], [0.340,0.810,7.240], [-1.670,-0.060,0.660]]), + (108, [[-14.790,-146.520,886.710], [-10.850,0.220,0.510], [-0.160,-7.240,-0.380], [0.730,0.030,-0.300], [0.330,-0.390,7.230], [2.180,0.020,-0.940]]), + (109, [[-23.910,-146.550,890.530], [-7.400,-0.950,6.580], [0.980,-7.160,0.070], [-0.520,0.100,0.630], [4.680,0.690,5.370], [0.750,0.450,-0.150]]), + (110, [[-28.030,-148.180,898.370], [-13.610,2.900,3.800], [-1.230,-7.020,0.960], [-1.430,0.370,-0.840], [2.040,0.580,6.860], [-3.990,-0.650,0.170]]), + (111, [[-42.020,-140.320,889.270], [-9.930,7.700,-9.680], [-1.440,-6.120,-3.390], [0.840,-0.040,-0.890], [-5.330,-1.240,4.490], [-3.620,0.110,-4.100]]), + (112, [[-47.830,-133.820,880.590], [1.670,2.810,-9.020], [0.190,-6.800,-2.080], [0.020,-0.240,2.820], [-6.870,0.170,-1.220], [2.630,-0.650,-5.170]]), + (113, [[-43.360,-134.640,876.970], [7.370,-1.120,-1.770], [-0.610,-6.830,1.800], [-0.490,-0.090,1.490], [-1.840,-1.590,-6.650], [3.370,-0.420,-3.090]]), + (114, [[-34.800,-135.760,878.370], [7.330,-0.800,-0.160], [-0.760,-7.020,0.280], [-0.510,0.020,-0.710], [-0.180,-0.260,-7.060], [-2.440,1.360,1.660]]), + (115, [[-29.320,-136.240,877.180], [3.390,-0.800,-5.310], [-1.570,-6.870,0.040], [-0.230,0.050,0.030], [-5.670,1.270,-3.820], [-3.220,0.720,3.410]]), + (116, [[-30.610,-136.870,870.770], [-0.250,-0.250,-5.290], [-1.190,-6.910,0.380], [0.280,-0.030,-0.030], [-6.790,1.180,0.270], [0.350,-0.330,-1.210]]), + (117, [[-30.230,-136.860,867.080], [2.790,-0.450,-3.890], [-0.940,-6.950,0.140], [0.330,-0.030,-0.120], [-5.570,0.670,-4.070], [3.300,-0.630,-3.480]]), + (118, [[-25.370,-137.760,865.060], [8.760,-0.500,1.850], [-0.440,-6.980,0.180], [0.240,0.000,-0.170], [1.430,-0.270,-6.840], [3.730,-0.350,-1.770]]), + (119, [[-17.010,-136.930,873.250], [9.540,-0.880,-1.350], [-0.710,-6.910,-0.470], [-0.790,0.170,0.250], [-0.920,0.560,-6.870], [-3.990,0.940,2.860]]), + (120, [[-14.620,-138.100,867.370], [2.470,-1.150,-8.780], [-1.880,-6.660,0.340], [1.250,0.410,-0.040], [-6.320,1.680,-1.990], [-1.180,0.210,1.020]]), + (121, [[-13.210,-138.670,858.260], [15.020,8.840,-1.860], [3.370,-5.940,-1.020], [3.020,0.320,-0.460], [-1.140,0.510,-6.800], [4.300,-0.760,-2.960]]), + (122, [[-2.010,-129.090,875.920], [14.730,5.570,5.540], [2.300,-6.430,0.360], [-3.380,0.090,1.420], [2.260,0.450,-6.450], [-4.260,0.280,1.850]]), + (123, [[5.710,-128.310,873.450], [4.220,-3.800,-6.920], [-2.330,-6.100,1.930], [1.540,1.120,0.790], [-5.490,0.890,-3.830], [-2.900,-1.920,4.890]]), + (124, [[3.860,-133.450,867.510], [-1.780,-5.980,-7.590], [4.850,-4.160,2.140], [1.960,0.650,1.010], [-4.520,-3.360,3.710], [0.300,-2.100,1.250]]), + (125, [[2.440,-139.690,858.800], [7.020,-5.190,-6.230], [0.110,-5.150,4.400], [-1.690,-0.890,0.210], [-5.060,-2.920,-3.280], [2.220,0.250,-4.490]]), + (126, [[11.980,-140.150,859.350], [17.700,2.250,-1.140], [0.950,-6.060,2.790], [1.390,-0.390,-2.080], [-0.040,-2.820,-6.130], [2.190,0.110,-1.390]]), + (127, [[35.300,-132.990,854.910], [8.740,9.550,-15.220], [4.050,-5.230,-0.960], [0.820,0.890,-2.820], [-4.430,-2.650,-4.200], [-1.330,-1.300,4.050]]), + (128, [[29.930,-128.550,843.920], [-12.950,5.120,-19.360], [3.680,-4.210,-3.570], [-1.410,0.000,-0.870], [-4.190,-4.930,1.490], [1.700,-0.300,5.110]]), + (129, [[9.390,-125.790,820.060], [-27.750,1.440,5.840], [-0.470,-6.580,-0.630], [-1.270,-0.920,1.780], [1.320,-0.720,6.460], [4.740,2.190,-0.360]]), + (130, [[4.650,-126.740,840.920], [-6.020,1.180,15.730], [0.130,-6.590,0.550], [-0.730,0.090,0.190], [6.110,0.310,2.320], [-2.110,0.210,1.570]]), + (131, [[0.040,-125.010,849.260], [-9.240,1.850,1.000], [-1.260,-6.450,0.320], [0.680,0.070,-0.540], [0.750,0.180,6.550], [-5.740,-0.820,-0.600]]), + (132, [[-4.440,-124.790,843.150], [-5.020,0.460,-16.660], [1.260,-6.430,-0.560], [1.980,0.080,-0.420], [-6.090,-1.340,1.790], [-4.270,-1.020,-2.570]]), + (133, [[-4.100,-124.240,817.800], [-14.820,-5.980,-12.690], [2.230,-6.130,0.290], [-0.080,-0.020,0.180], [-3.880,-1.170,5.070], [6.330,1.590,-0.020]]), + (134, [[-13.820,-128.400,823.840], [-7.490,-1.580,13.510], [1.550,-6.330,0.120], [-0.550,0.000,0.710], [5.490,1.400,3.200], [4.920,1.220,-2.010]]), + (135, [[-15.540,-126.400,839.810], [-2.260,3.630,12.780], [1.060,-6.110,1.920], [-1.860,0.050,-0.360], [6.210,1.310,0.730], [-0.950,-1.430,1.430]]), + (136, [[-17.860,-122.190,848.910], [-6.970,2.290,6.400], [-1.900,-6.170,0.140], [0.210,-0.110,-0.730], [4.060,-1.150,4.850], [-5.500,-0.820,1.290]]), + (137, [[-24.460,-122.950,849.040], [-11.050,-2.260,-14.690], [1.030,-6.350,0.200], [1.600,-0.050,0.470], [-5.050,-0.700,3.900], [-6.400,0.950,-0.750]]), + (138, [[-23.980,-124.710,821.700], [-13.900,-3.450,-17.210], [-1.090,-5.980,2.080], [-0.110,-0.110,-0.760], [-4.880,2.110,3.530], [5.050,-0.430,0.870]]), + (139, [[-38.600,-127.220,820.180], [-12.580,-0.430,8.780], [-0.020,-6.390,-0.330], [-0.170,-0.020,-0.170], [3.670,-0.290,5.240], [4.860,-1.540,-2.070]]), + (140, [[-42.520,-125.650,832.780], [1.330,2.910,14.250], [-1.250,-6.100,1.370], [-0.030,0.210,1.190], [6.110,-1.310,-0.300], [1.080,-0.260,-3.490]]), + (141, [[-35.800,-121.920,845.730], [4.200,3.780,10.200], [0.010,-5.960,2.200], [-0.160,0.230,0.570], [5.880,-0.780,-2.130], [0.090,0.030,0.690]]), + (142, [[-33.620,-118.720,852.840], [0.500,3.010,6.470], [-0.930,-5.650,2.700], [-0.790,-0.030,-0.570], [6.150,-1.010,0.000], [-0.330,-0.030,2.500]]), + (143, [[-34.440,-116.110,858.280], [-2.640,1.810,5.040], [-1.710,-5.940,1.230], [0.580,-0.290,-1.410], [5.320,-0.890,3.110], [-1.830,0.370,2.710]]), + (144, [[-38.380,-115.330,862.170], [-6.050,-0.340,2.350], [0.220,-6.280,-0.340], [1.370,-0.090,-0.250], [2.280,-0.240,5.850], [-4.210,0.450,0.940]]), + (145, [[-44.500,-116.930,861.580], [-11.590,-3.810,-10.160], [1.110,-6.090,1.020], [0.440,0.120,0.610], [-4.130,0.030,4.700], [-4.540,0.050,-0.790]]), + (146, [[-51.780,-120.720,839.030], [-15.880,-5.450,-10.360], [1.830,-5.970,0.320], [-1.360,0.270,0.870], [-3.220,-0.700,5.310], [4.290,0.490,0.090]]), + (147, [[-64.650,-124.350,841.480], [-11.510,0.420,9.850], [0.150,-6.190,0.440], [-0.550,0.330,1.540], [3.970,0.430,4.630], [4.380,-0.520,-2.900]]), + (148, [[-69.370,-119.950,854.330], [5.110,4.210,16.620], [-1.330,-5.740,1.870], [0.690,0.270,0.730], [5.670,-1.740,-1.310], [0.560,-1.580,-4.180]]), + (149, [[-55.630,-118.570,867.170], [8.190,15.700,8.570], [-2.415,-2.636,3.160], [0.890,1.630,1.440], [4.280,-1.310,-1.700], [0.130,0.200,0.140]]), + (150, [[-52.380,-100.900,869.760], [4.760,24.010,12.610], [-3.169,0.219,3.447], [-0.280,-0.300,-1.610], [4.600,-0.510,-0.770], [-2.290,1.100,4.280]]), + (151, [[-41.730,-76.290,892.900], [-14.020,14.240,19.650], [-3.750,-3.589,-1.622], [3.240,-2.890,0.750], [1.930,-2.620,3.270], [-5.090,5.860,6.610]]), + (152, [[-60.630,-80.530,895.250], [-6.170,-10.100,-5.870], [2.660,0.730,-4.050], [2.380,0.990,-1.140], [3.310,-2.970,1.640], [2.380,0.990,-1.140]]) + ] ), - parameterSetStructureStrings = { - 'Cattle 1': ScaffoldPackage(MeshType_1d_network_layout1, { + 'userAnnotationGroups': [ + { + '_AnnotationGroup': True, + 'dimension': 1, + 'identifierRanges': '1-150', + 'name': get_smallintestine_term('small intestine')[0], + 'ontId': get_smallintestine_term('small intestine')[1] + }, + { + '_AnnotationGroup': True, + 'dimension': 1, + 'identifierRanges': '1-5', + 'name': get_smallintestine_term('duodenum')[0], + 'ontId': get_smallintestine_term('duodenum')[1] + }, + { + '_AnnotationGroup': True, + 'dimension': 1, + 'identifierRanges': '6-82', + 'name': get_smallintestine_term('jejunum')[0], + 'ontId': get_smallintestine_term('jejunum')[1] + }, + { + '_AnnotationGroup': True, + 'dimension': 1, + 'identifierRanges': '83-150', + 'name': get_smallintestine_term('ileum')[0], + 'ontId': get_smallintestine_term('ileum')[1] + }] + }) + elif "Cattle 1" in parameterSetName: + return ScaffoldPackage(MeshType_1d_network_layout1, { 'scaffoldSettings': { "Structure": "1-2-3-4-5-6-7-8-9-10-11-12-13-14-15-16-17-18-19-20-21-22-23-24-25-26-27-28-29-30-31-32-" "33-34-35-36-37-38-39-40-41-42-43-44-45-46-47-48-49-50-51-52-53-54-55-56-57-58-59-60-61-" @@ -630,204 +819,10 @@ class MeshType_3d_smallintestine1(Scaffold_base): 'name': get_smallintestine_term('ileum')[0], 'ontId': get_smallintestine_term('ileum')[1] }] - }), - 'Human 1': ScaffoldPackage(MeshType_1d_network_layout1, { - 'scaffoldSettings': { - "Structure": "1-2-3-4-5-6-7-8-9-10-11-12-13-14-15-16-17-18-19-20-21-22-23-24-25-26-27-28-29-30-31-32-" - "33-34-35-36-37-38-39-40-41-42-43-44-45-46-47-48-49-50-51-52-53-54-55-56-57-58-59-60-61-" - "62-63-64-65-66-67-68-69-70-71-72-73-74-75-76-77-78-79-80-81-82-83-84-85-86-87-88-89-90-" - "91-92-93-94-95-96-97-98-99-100-101-102-103-104-105-106-107-108-109-110-111-112-113-114-" - "115-116-117-118-119-120-121-122-123-124-125-126-127-128-129-130-131-132-133-134-135-136-" - "137-138-139-140-141-142-143-144-145-146-147-148-149-150-151-152" - }, - 'meshEdits': exnode_string_from_nodeset_field_parameters( - [ Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3 ], [ - (1, [[-32.281,-136.261,1061.249], [-6.125,11.114,-0.493], [-5.735,-3.374,-4.823], [-2.070,-0.220,-4.520], [-4.630,-2.238,7.071], [-4.400,2.440,0.570]]), - (2, [[-40.674,-122.300,1060.850], [-5.403,7.321,-2.629], [-4.779,-4.249,-5.161], [2.360,-0.320,0.120], [-5.138,-1.668,6.875], [-0.250,2.080,-4.500]]), - (3, [[-48.346,-108.981,1049.574], [-6.840,19.440,-21.940], [-3.459,-4.108,-5.699], [0.900,0.690,1.570], [-7.043,0.777,3.341], [-0.760,2.950,-2.230]]), - (4, [[-43.450,-95.700,1015.590], [40.730,3.220,-44.800], [-5.240,-3.340,-4.990], [-0.380,4.380,-0.330], [-2.270,6.020,-1.640], [4.590,3.490,-0.790]]), - (5, [[26.760,-119.310,992.030], [58.860,-18.680,-8.450], [0.310,3.940,-6.600], [4.150,2.330,1.070], [2.230,5.490,3.380], [3.360,-4.080,2.370]]), - (6, [[63.862,-132.266,992.002], [9.680,-30.910,-18.900], [5.846,1.916,2.960], [-0.330,-6.200,3.780], [5.300,-1.090,4.490], [-3.680,-1.570,1.510]]), - (7, [[46.280,-139.940,982.680], [-22.680,-4.850,-10.940], [1.050,-7.060,0.970], [-0.930,-3.800,3.220], [-3.190,0.420,6.420], [-5.340,-0.640,-2.850]]), - (8, [[28.560,-141.070,974.610], [3.750,-10.520,-21.300], [1.560,-6.210,3.340], [-1.000,0.060,-0.070], [-6.850,-1.870,-0.290], [1.100,-0.530,-6.400]]), - (9, [[52.390,-146.130,971.400], [18.400,-3.700,0.670], [-1.440,-7.110,0.300], [-0.590,-0.290,-0.540], [0.190,-0.340,-7.250], [2.420,0.060,-1.890]]), - (10, [[63.130,-148.180,973.520], [10.490,-1.410,1.470], [-1.070,-7.160,0.770], [2.410,0.380,0.120], [0.880,-0.900,-7.160], [-2.030,-1.100,0.840]]), - (11, [[72.690,-148.910,974.300], [7.650,3.570,-7.080], [3.500,-6.340,0.580], [0.430,0.200,-1.420], [-3.880,-2.630,-5.520], [-3.490,0.080,4.650]]), - (12, [[71.050,-143.650,964.650], [-5.960,4.700,-11.040], [-0.810,-6.830,-2.470], [-2.360,-0.380,-1.140], [-6.400,-0.430,3.270], [0.270,0.950,6.070]]), - (13, [[61.060,-140.780,954.520], [-17.960,3.880,-6.220], [-1.070,-7.120,-1.370], [0.180,-0.250,1.370], [-2.560,-0.940,6.800], [3.840,0.270,2.130]]), - (14, [[37.990,-136.930,957.170], [-18.820,0.880,5.080], [-0.160,-7.340,0.670], [1.900,0.170,0.590], [1.940,0.610,7.070], [2.120,1.030,-0.120]]), - (15, [[24.260,-138.060,963.160], [-17.400,-6.040,8.510], [2.590,-6.900,0.380], [2.420,1.010,0.690], [2.780,1.420,6.690], [-2.180,-0.670,-0.740]]), - (16, [[6.500,-150.310,973.050], [-8.250,-16.440,-13.420], [4.890,-4.750,2.820], [-1.080,-0.490,-0.280], [-4.820,-1.850,5.240], [-4.270,-0.820,-2.180]]), - (17, [[15.970,-149.800,957.690], [-4.350,-1.250,-14.050], [0.990,-7.390,0.350], [-1.040,-0.780,-0.850], [-6.950,-0.830,2.230], [-0.480,0.190,-0.500]]), - (18, [[8.290,-150.980,954.250], [-3.340,-0.730,-8.150], [1.180,-7.370,0.180], [0.180,0.050,0.370], [-6.710,-1.000,2.840], [0.560,-0.430,-3.270]]), - (19, [[10.770,-150.880,946.760], [5.270,-0.050,-7.150], [1.370,-7.280,1.060], [-0.120,-0.030,0.050], [-5.800,-1.710,-4.270], [2.050,0.220,-4.830]]), - (20, [[18.300,-151.090,941.260], [7.790,0.880,-2.390], [0.880,-7.450,0.160], [0.050,-0.010,-0.900], [-2.150,-0.400,-7.160], [4.520,1.490,-0.770]]), - (21, [[24.850,-149.580,941.590], [5.320,0.620,3.020], [1.330,-7.350,-0.840], [-0.350,0.010,-0.650], [3.510,1.370,-6.460], [3.430,0.580,1.190]]), - (22, [[27.850,-149.810,945.920], [3.490,-0.550,3.990], [0.330,-7.390,-1.300], [-0.750,-0.040,-0.150], [5.610,1.090,-4.760], [-0.580,-0.160,-0.310]]), - (23, [[31.640,-150.640,949.370], [5.770,-0.500,1.810], [-0.280,-7.430,-1.160], [0.320,-0.010,0.320], [2.310,1.020,-7.080], [-4.590,-0.600,-0.740]]), - (24, [[38.160,-150.550,948.480], [5.400,1.270,-4.340], [1.280,-7.400,-0.560], [1.280,0.320,-0.530], [-4.630,-0.350,-5.870], [-4.440,-1.610,3.120]]), - (25, [[40.300,-148.530,942.170], [-0.500,2.450,-7.550], [2.420,-6.730,-2.350], [1.390,0.820,-0.980], [-7.020,-2.420,-0.320], [-0.570,-0.950,1.020]]), - (26, [[36.760,-146.190,935.090], [3.270,5.380,-6.440], [4.320,-5.620,-2.500], [0.260,-0.080,1.070], [-5.500,-2.170,-4.600], [3.600,1.240,-3.410]]), - (27, [[44.600,-142.080,934.770], [8.650,3.530,1.100], [2.850,-7.000,0.020], [-1.020,-0.770,1.000], [0.830,0.310,-7.530], [3.410,1.450,-1.300]]), - (28, [[53.340,-139.440,937.210], [8.310,2.340,2.220], [2.150,-7.250,-0.380], [-0.540,-0.170,-0.420], [1.710,0.890,-7.340], [0.070,0.370,0.030]]), - (29, [[61.180,-137.390,939.220], [8.230,1.720,1.430], [1.690,-7.360,-0.860], [-0.380,-0.100,-0.170], [1.060,1.120,-7.440], [-0.840,-0.070,-0.120]]), - (30, [[69.720,-136.030,940.040], [8.420,1.510,0.050], [1.350,-7.460,-0.740], [0.300,0.210,-0.630], [-0.090,0.740,-7.580], [-3.560,-0.970,1.730]]), - (31, [[77.280,-134.500,939.340], [4.490,4.180,-8.530], [2.310,-6.920,-2.180], [-0.290,0.070,-0.480], [-6.410,-0.930,-3.830], [-3.190,-0.950,5.530]]), - (32, [[71.890,-131.270,929.110], [-6.780,1.090,-6.790], [0.090,-7.530,-1.300], [-0.440,-0.260,1.250], [-5.410,-0.970,5.250], [0.240,0.450,2.900]]), - (33, [[66.110,-131.600,925.900], [-4.090,-0.450,-4.440], [0.540,-7.640,0.280], [0.080,0.050,1.400], [-5.560,-0.210,5.140], [-0.150,0.880,-0.160]]), - (34, [[63.930,-132.090,921.070], [-3.930,-1.160,-4.370], [0.320,-7.470,1.700], [0.720,0.300,0.950], [-5.720,0.870,4.920], [0.660,0.510,0.560]]), - (35, [[58.470,-133.890,917.960], [-6.670,-3.360,-3.670], [2.290,-6.970,2.210], [2.280,0.920,-0.110], [-3.960,0.750,6.500], [2.250,0.030,1.310]]), - (36, [[51.020,-139.090,914.020], [-6.630,-6.740,0.390], [5.400,-5.250,1.130], [1.070,0.420,-1.320], [-0.590,1.020,7.590], [3.120,0.370,0.200]]), - (37, [[46.770,-145.490,918.120], [-5.050,-4.370,2.870], [4.810,-5.920,-0.550], [-1.310,-0.890,-0.940], [2.680,1.520,7.030], [1.260,-0.680,-0.120]]), - (38, [[41.950,-147.920,919.780], [-5.030,-2.380,1.940], [2.900,-7.030,-1.100], [-1.320,-0.680,-0.330], [2.770,0.010,7.180], [-0.110,-1.000,0.120]]), - (39, [[36.760,-150.210,922.000], [-5.100,-1.680,1.580], [2.030,-7.330,-1.240], [-0.510,-0.220,0.810], [2.440,-0.560,7.300], [-0.450,0.500,0.130]]), - (40, [[31.890,-151.330,922.990], [-5.710,-1.250,1.560], [1.770,-7.500,0.460], [-0.570,-0.180,0.730], [1.840,0.880,7.450], [-2.050,0.330,0.030]]), - (41, [[25.550,-152.650,925.180], [-6.280,-0.560,-2.170], [0.700,-7.710,-0.030], [-0.690,-0.090,-0.620], [-2.500,-0.250,7.310], [-3.190,-0.780,-0.830]]), - (42, [[22.170,-152.270,920.060], [-4.850,0.300,-4.200], [0.270,-7.700,-0.850], [-0.240,-0.020,0.240], [-5.020,-0.810,5.760], [2.410,0.370,-0.060]]), - (43, [[16.600,-152.110,917.510], [-6.970,0.000,2.680], [0.200,-7.740,0.510], [-0.300,-0.030,0.600], [2.770,0.540,7.210], [5.780,0.370,-0.740]]), - (44, [[13.120,-152.320,924.900], [-3.730,0.410,7.150], [-0.450,-7.750,0.210], [-0.140,-0.020,-0.160], [6.780,-0.300,3.550], [-0.230,-0.180,0.200]]), - (45, [[9.440,-151.370,931.310], [-7.880,0.190,2.810], [-0.130,-7.780,0.170], [0.490,-0.010,0.120], [2.610,0.120,7.310], [-3.700,0.330,2.080]]), - (46, [[1.230,-152.170,928.310], [-8.130,-0.720,-1.080], [0.620,-7.760,0.490], [0.090,-0.010,-0.290], [-1.060,0.400,7.710], [1.430,-0.160,-0.650]]), - (47, [[-5.970,-152.740,928.930], [-5.640,-0.310,4.390], [0.170,-7.800,-0.330], [-0.930,0.040,0.090], [4.760,-0.160,6.120], [3.980,-0.840,-4.110]]), - (48, [[-8.050,-152.700,935.120], [0.840,0.430,7.280], [-1.310,-7.670,0.600], [-1.080,0.170,0.740], [7.520,-1.340,-0.790], [0.790,-0.430,-1.110]]), - (49, [[-4.180,-151.980,940.930], [-5.500,2.850,8.020], [-2.070,-7.440,1.220], [-0.370,0.070,-0.100], [6.170,-0.960,4.570], [-3.010,0.560,4.290]]), - (50, [[-15.920,-150.230,939.850], [-11.530,2.830,0.080], [-1.870,-7.620,-0.020], [0.120,0.150,0.780], [0.040,-0.030,7.840], [0.810,0.000,-1.160]]), - (51, [[-25.870,-146.770,940.970], [-2.690,4.150,9.230], [-1.800,-7.150,2.690], [0.690,0.200,1.480], [7.250,-0.880,2.510], [1.720,-1.410,-6.490]]), - (52, [[-19.430,-146.580,946.990], [7.700,1.830,5.130], [-0.490,-7.140,3.290], [1.240,-0.130,-0.090], [4.500,-2.940,-5.700], [-0.590,-0.040,-3.450]]), - (53, [[-11.610,-143.430,950.540], [5.250,2.520,5.680], [0.830,-7.420,2.520], [0.750,-0.240,-0.870], [5.910,-1.040,-5.000], [0.830,1.410,0.570]]), - (54, [[-9.220,-141.820,956.880], [3.600,1.580,5.200], [1.220,-7.660,1.480], [-0.050,-0.130,-0.420], [6.390,0.150,-4.470], [0.120,0.280,0.100]]), - (55, [[-4.880,-140.390,960.700], [3.780,1.360,4.900], [0.780,-7.720,1.540], [0.070,-0.060,-0.650], [6.230,-0.310,-4.720], [0.530,0.530,1.660]]), - (56, [[-1.980,-139.200,966.470], [0.650,0.130,7.290], [1.420,-7.780,0.010], [0.230,-0.060,-0.880], [7.610,1.390,-0.700], [0.660,0.740,3.140]]), - (57, [[-4.150,-140.360,973.960], [-2.380,-0.650,10.170], [1.190,-7.830,-0.220], [-0.650,-0.070,-0.200], [7.500,1.090,1.830], [-0.210,-0.700,2.000]]), - (58, [[-6.206,-140.381,984.826], [-3.997,1.953,8.625], [-0.240,-7.940,-0.400], [-0.770,0.020,-0.440], [7.090,-0.380,3.280], [-1.820,-1.020,2.460]]), - (59, [[-11.071,-137.239,990.534], [-6.502,2.564,3.616], [-0.730,-7.850,-1.030], [0.040,-0.000,-0.150], [4.330,-1.250,6.510], [-3.510,-0.150,2.180]]), - (60, [[-18.114,-135.562,991.751], [-6.821,0.865,-0.438], [-0.170,-7.940,-0.730], [0.590,-0.040,0.750], [-0.320,-0.720,7.930], [-4.070,0.690,0.160]]), - (61, [[-24.108,-135.469,989.949], [-5.560,-1.043,-2.740], [0.530,-7.940,0.630], [-0.080,0.160,1.480], [-4.270,0.240,6.690], [-3.140,0.950,-2.220]]), - (62, [[-28.764,-137.545,986.518], [-3.033,-3.486,-4.184], [-0.280,-7.620,2.380], [-1.430,0.310,0.610], [-7.020,1.290,3.320], [-0.940,0.180,-5.150]]), - (63, [[-29.636,-141.811,982.334], [1.634,-2.756,-5.189], [-2.170,-7.290,2.440], [-1.160,0.110,-0.290], [-7.100,1.030,-3.250], [0.490,-0.350,-4.870]]), - (64, [[-24.820,-145.190,978.580], [4.650,-2.180,-4.590], [-2.130,-7.580,1.440], [0.290,-0.260,-0.910], [-5.460,0.450,-5.750], [-0.330,0.230,1.000]]), - (65, [[-20.750,-146.910,974.010], [1.230,-0.700,-6.940], [-1.580,-7.840,0.510], [0.080,-0.090,-0.690], [-7.590,1.430,-1.480], [0.460,0.350,5.770]]), - (66, [[-23.390,-146.100,967.330], [-6.320,1.650,-4.010], [-2.030,-7.760,0.010], [-0.160,0.070,0.360], [-4.040,1.070,6.800], [4.830,-0.400,4.280]]), - (67, [[-30.600,-144.330,967.780], [-6.690,2.040,2.190], [-1.930,-7.690,1.270], [0.050,0.000,0.440], [2.650,0.580,7.550], [3.030,-0.350,0.340]]), - (68, [[-36.170,-142.250,971.340], [-6.590,1.940,2.270], [-1.940,-7.730,1.010], [0.040,-0.010,0.090], [2.700,0.310,7.560], [0.370,-0.020,-0.150]]), - (69, [[-43.400,-140.590,972.070], [-6.040,1.970,2.740], [-1.830,-7.710,1.480], [0.020,0.340,1.180], [3.470,0.560,7.230], [2.300,-0.410,-2.270]]), - (70, [[-47.620,-138.630,976.140], [-1.780,2.680,4.620], [-1.870,-7.070,3.390], [0.010,0.350,0.980], [7.300,-0.460,3.080], [1.720,-1.440,-3.710]]), - (71, [[-47.100,-135.980,980.160], [0.980,1.950,4.050], [-1.830,-6.900,3.760], [0.210,-0.140,-0.200], [7.550,-2.370,-0.680], [0.040,-0.760,-2.210]]), - (72, [[-45.780,-134.750,984.020], [1.920,1.940,5.580], [-1.460,-7.340,3.050], [-0.530,0.370,0.090], [7.430,-2.220,-1.790], [-0.240,0.260,1.070]]), - (73, [[-42.419,-130.149,990.122], [-1.920,7.780,7.360], [-3.780,-5.370,4.690], [-2.140,1.260,-0.060], [6.910,-1.720,3.610], [-3.470,2.540,4.150]]), - (74, [[-48.414,-118.983,992.238], [-8.280,6.980,-7.760], [-5.960,-5.080,1.790], [0.610,-1.110,-1.840], [-2.030,4.630,6.340], [-6.540,1.980,-0.430]]), - (75, [[-54.520,-122.570,980.900], [-5.100,0.460,-13.050], [-2.600,-7.660,0.750], [2.850,-1.090,0.850], [-7.020,2.660,2.840], [-2.860,-1.790,-2.310]]), - (76, [[-56.534,-121.929,967.273], [-3.400,-6.950,-12.830], [-2.036,-6.714,3.150], [-1.690,1.750,1.250], [-7.800,0.860,1.600], [1.210,-0.700,-4.510]]), - (77, [[-57.601,-134.069,961.014], [4.440,-11.120,-4.920], [-6.170,-3.970,3.410], [-1.800,0.340,-0.380], [-4.460,1.190,-6.700], [1.720,-0.860,-3.600]]), - (78, [[-53.650,-142.090,958.040], [8.150,-8.950,-3.450], [-4.950,-5.680,3.060], [2.040,-1.620,-0.110], [-3.750,-0.620,-7.230], [-0.920,-0.860,0.970]]), - (79, [[-43.780,-150.900,953.550], [6.860,-6.210,-10.820], [-1.570,-7.380,3.240], [0.100,-0.470,-1.480], [-6.930,-0.360,-4.180], [-0.500,1.880,6.120]]), - (80, [[-42.790,-151.920,940.920], [-10.160,7.350,-12.870], [-4.740,-6.680,-0.070], [-1.780,0.370,-1.940], [-4.810,3.350,5.710], [1.370,1.930,5.900]]), - (81, [[-59.560,-139.320,940.870], [-10.470,7.530,-10.550], [-4.670,-6.770,-0.210], [-0.780,0.740,0.770], [-4.390,2.820,6.370], [-0.630,1.740,-4.220]]), - (82, [[-61.190,-138.430,930.230], [-0.370,-2.040,-12.190], [-5.970,-5.520,1.110], [-0.860,0.960,0.960], [-5.640,5.920,-0.830], [0.650,-0.720,-6.690]]), - (83, [[-60.050,-143.370,918.840], [6.120,-9.410,-3.110], [-6.440,-4.780,1.790], [0.250,-0.370,-0.760], [-2.750,0.780,-7.780], [3.390,-3.100,-3.060]]), - (84, [[-54.810,-148.970,924.540], [7.070,-6.600,2.050], [-5.610,-6.050,-0.170], [0.760,-0.860,-0.330], [1.380,-1.050,-8.130], [-1.610,1.400,1.580]]), - (85, [[-48.000,-154.670,922.570], [3.540,-3.720,-7.480], [-4.830,-6.610,1.000], [1.210,-0.760,-0.140], [-5.850,3.580,-4.550], [-4.060,1.810,3.830]]), - (86, [[-49.390,-154.510,914.460], [0.270,0.350,-10.670], [-3.110,-7.640,-0.330], [1.860,-0.790,-0.480], [-7.540,3.070,-0.100], [1.640,-1.570,-0.540]]), - (87, [[-46.730,-154.010,904.000], [18.990,-1.890,-1.480], [-0.780,-8.190,0.400], [1.310,-0.300,0.500], [-0.670,-0.340,-8.190], [5.190,-2.310,-4.980]]), - (88, [[-31.900,-157.000,923.200], [20.270,-2.840,5.710], [-1.280,-8.040,0.540], [1.630,0.180,0.170], [2.100,-0.860,-7.850], [-3.210,-0.770,1.420]]), - (89, [[-17.040,-158.470,917.330], [10.690,1.600,-10.940], [1.940,-7.840,0.740], [0.870,0.010,-0.110], [-5.440,-1.880,-5.580], [-1.710,0.190,-0.090]]), - (90, [[-12.920,-154.880,905.590], [14.280,1.560,-5.120], [1.010,-8.000,0.370], [-0.980,-0.090,-0.580], [-2.650,-0.690,-7.580], [1.890,1.140,-1.150]]), - (91, [[0.790,-157.220,913.220], [17.050,-0.100,-3.500], [-0.160,-8.010,-0.530], [0.240,0.090,-0.240], [-1.610,0.550,-7.830], [0.100,0.160,0.010]]), - (92, [[11.370,-154.850,899.810], [20.470,4.340,-7.040], [1.620,-7.800,-0.100], [0.670,0.240,-0.620], [-2.500,-0.420,-7.540], [-1.600,0.070,0.920]]), - (93, [[35.280,-149.960,905.730], [15.010,5.710,-13.200], [0.800,-7.500,-2.330], [1.120,0.330,0.340], [-5.360,1.170,-5.590], [-1.050,-1.380,0.950]]), - (94, [[31.510,-148.900,893.070], [11.510,6.020,-14.640], [3.170,-7.130,-0.440], [1.650,0.510,0.450], [-5.440,-2.110,-5.150], [2.200,-0.030,-0.530]]), - (95, [[53.210,-142.180,892.150], [16.130,8.560,4.600], [3.960,-6.330,-2.130], [0.420,0.200,0.800], [0.580,2.810,-7.250], [3.440,1.000,-0.610]]), - (96, [[61.915,-135.512,899.756], [10.425,5.807,7.557], [4.220,-6.470,0.220], [-1.030,-0.530,1.150], [2.810,1.590,-7.040], [-2.200,-1.800,0.660]]), - (97, [[72.652,-131.499,906.138], [13.270,2.580,-11.410], [1.590,-7.520,0.150], [-0.630,-0.250,0.200], [-4.770,-1.120,-5.790], [-4.380,-1.930,4.880]]), - (98, [[70.933,-136.139,889.296], [-12.490,-8.250,-22.650], [3.260,-6.840,0.700], [0.840,0.360,-0.040], [-5.890,-2.380,4.110], [0.640,-0.370,7.040]]), - (99, [[47.820,-142.630,864.930], [-22.720,-8.470,-7.520], [2.750,-7.000,-0.430], [0.030,0.230,-1.270], [-1.940,-1.200,7.190], [5.330,1.350,0.110]]), - (100, [[33.710,-147.840,866.620], [-7.310,-5.020,5.800], [3.020,-6.590,-1.880], [-0.710,0.240,-1.450], [4.500,0.350,5.980], [2.350,2.560,-6.780]]), - (101, [[33.450,-149.550,870.080], [6.660,-2.670,8.620], [1.910,-6.380,-3.460], [-0.810,0.030,-0.860], [5.650,3.480,-3.300], [0.800,2.080,-6.770]]), - (102, [[48.500,-149.860,877.560], [8.440,-1.400,10.880], [1.840,-6.880,-2.310], [-0.550,-0.390,1.170], [5.590,2.820,-3.970], [-1.370,-2.160,5.890]]), - (103, [[49.170,-151.340,885.880], [-14.130,-2.760,6.710], [0.940,-7.250,-1.010], [-0.570,0.330,-0.410], [3.260,-0.510,6.640], [-3.090,-3.470,6.170]]), - (104, [[30.330,-151.820,877.700], [-17.160,1.530,-4.960], [0.920,-5.490,-4.890], [-1.510,-0.140,0.400], [-1.940,-4.930,5.180], [0.640,-0.130,0.130]]), - (105, [[16.360,-149.060,875.570], [-10.970,1.710,5.380], [-1.800,-6.980,-1.460], [-0.540,-0.730,1.970], [2.830,-2.080,6.450], [2.860,1.800,-0.060]]), - (106, [[11.690,-148.720,883.920], [-10.140,1.000,8.830], [-0.940,-7.280,-0.260], [0.660,-0.150,1.090], [4.710,-0.800,5.500], [-0.400,1.320,0.040]]), - (107, [[-3.830,-146.990,890.110], [-14.280,1.090,0.550], [-0.520,-7.220,0.830], [0.360,0.010,-0.260], [0.340,0.810,7.240], [-1.670,-0.060,0.660]]), - (108, [[-14.790,-146.520,886.710], [-10.850,0.220,0.510], [-0.160,-7.240,-0.380], [0.730,0.030,-0.300], [0.330,-0.390,7.230], [2.180,0.020,-0.940]]), - (109, [[-23.910,-146.550,890.530], [-7.400,-0.950,6.580], [0.980,-7.160,0.070], [-0.520,0.100,0.630], [4.680,0.690,5.370], [0.750,0.450,-0.150]]), - (110, [[-28.030,-148.180,898.370], [-13.610,2.900,3.800], [-1.230,-7.020,0.960], [-1.430,0.370,-0.840], [2.040,0.580,6.860], [-3.990,-0.650,0.170]]), - (111, [[-42.020,-140.320,889.270], [-9.930,7.700,-9.680], [-1.440,-6.120,-3.390], [0.840,-0.040,-0.890], [-5.330,-1.240,4.490], [-3.620,0.110,-4.100]]), - (112, [[-47.830,-133.820,880.590], [1.670,2.810,-9.020], [0.190,-6.800,-2.080], [0.020,-0.240,2.820], [-6.870,0.170,-1.220], [2.630,-0.650,-5.170]]), - (113, [[-43.360,-134.640,876.970], [7.370,-1.120,-1.770], [-0.610,-6.830,1.800], [-0.490,-0.090,1.490], [-1.840,-1.590,-6.650], [3.370,-0.420,-3.090]]), - (114, [[-34.800,-135.760,878.370], [7.330,-0.800,-0.160], [-0.760,-7.020,0.280], [-0.510,0.020,-0.710], [-0.180,-0.260,-7.060], [-2.440,1.360,1.660]]), - (115, [[-29.320,-136.240,877.180], [3.390,-0.800,-5.310], [-1.570,-6.870,0.040], [-0.230,0.050,0.030], [-5.670,1.270,-3.820], [-3.220,0.720,3.410]]), - (116, [[-30.610,-136.870,870.770], [-0.250,-0.250,-5.290], [-1.190,-6.910,0.380], [0.280,-0.030,-0.030], [-6.790,1.180,0.270], [0.350,-0.330,-1.210]]), - (117, [[-30.230,-136.860,867.080], [2.790,-0.450,-3.890], [-0.940,-6.950,0.140], [0.330,-0.030,-0.120], [-5.570,0.670,-4.070], [3.300,-0.630,-3.480]]), - (118, [[-25.370,-137.760,865.060], [8.760,-0.500,1.850], [-0.440,-6.980,0.180], [0.240,0.000,-0.170], [1.430,-0.270,-6.840], [3.730,-0.350,-1.770]]), - (119, [[-17.010,-136.930,873.250], [9.540,-0.880,-1.350], [-0.710,-6.910,-0.470], [-0.790,0.170,0.250], [-0.920,0.560,-6.870], [-3.990,0.940,2.860]]), - (120, [[-14.620,-138.100,867.370], [2.470,-1.150,-8.780], [-1.880,-6.660,0.340], [1.250,0.410,-0.040], [-6.320,1.680,-1.990], [-1.180,0.210,1.020]]), - (121, [[-13.210,-138.670,858.260], [15.020,8.840,-1.860], [3.370,-5.940,-1.020], [3.020,0.320,-0.460], [-1.140,0.510,-6.800], [4.300,-0.760,-2.960]]), - (122, [[-2.010,-129.090,875.920], [14.730,5.570,5.540], [2.300,-6.430,0.360], [-3.380,0.090,1.420], [2.260,0.450,-6.450], [-4.260,0.280,1.850]]), - (123, [[5.710,-128.310,873.450], [4.220,-3.800,-6.920], [-2.330,-6.100,1.930], [1.540,1.120,0.790], [-5.490,0.890,-3.830], [-2.900,-1.920,4.890]]), - (124, [[3.860,-133.450,867.510], [-1.780,-5.980,-7.590], [4.850,-4.160,2.140], [1.960,0.650,1.010], [-4.520,-3.360,3.710], [0.300,-2.100,1.250]]), - (125, [[2.440,-139.690,858.800], [7.020,-5.190,-6.230], [0.110,-5.150,4.400], [-1.690,-0.890,0.210], [-5.060,-2.920,-3.280], [2.220,0.250,-4.490]]), - (126, [[11.980,-140.150,859.350], [17.700,2.250,-1.140], [0.950,-6.060,2.790], [1.390,-0.390,-2.080], [-0.040,-2.820,-6.130], [2.190,0.110,-1.390]]), - (127, [[35.300,-132.990,854.910], [8.740,9.550,-15.220], [4.050,-5.230,-0.960], [0.820,0.890,-2.820], [-4.430,-2.650,-4.200], [-1.330,-1.300,4.050]]), - (128, [[29.930,-128.550,843.920], [-12.950,5.120,-19.360], [3.680,-4.210,-3.570], [-1.410,0.000,-0.870], [-4.190,-4.930,1.490], [1.700,-0.300,5.110]]), - (129, [[9.390,-125.790,820.060], [-27.750,1.440,5.840], [-0.470,-6.580,-0.630], [-1.270,-0.920,1.780], [1.320,-0.720,6.460], [4.740,2.190,-0.360]]), - (130, [[4.650,-126.740,840.920], [-6.020,1.180,15.730], [0.130,-6.590,0.550], [-0.730,0.090,0.190], [6.110,0.310,2.320], [-2.110,0.210,1.570]]), - (131, [[0.040,-125.010,849.260], [-9.240,1.850,1.000], [-1.260,-6.450,0.320], [0.680,0.070,-0.540], [0.750,0.180,6.550], [-5.740,-0.820,-0.600]]), - (132, [[-4.440,-124.790,843.150], [-5.020,0.460,-16.660], [1.260,-6.430,-0.560], [1.980,0.080,-0.420], [-6.090,-1.340,1.790], [-4.270,-1.020,-2.570]]), - (133, [[-4.100,-124.240,817.800], [-14.820,-5.980,-12.690], [2.230,-6.130,0.290], [-0.080,-0.020,0.180], [-3.880,-1.170,5.070], [6.330,1.590,-0.020]]), - (134, [[-13.820,-128.400,823.840], [-7.490,-1.580,13.510], [1.550,-6.330,0.120], [-0.550,0.000,0.710], [5.490,1.400,3.200], [4.920,1.220,-2.010]]), - (135, [[-15.540,-126.400,839.810], [-2.260,3.630,12.780], [1.060,-6.110,1.920], [-1.860,0.050,-0.360], [6.210,1.310,0.730], [-0.950,-1.430,1.430]]), - (136, [[-17.860,-122.190,848.910], [-6.970,2.290,6.400], [-1.900,-6.170,0.140], [0.210,-0.110,-0.730], [4.060,-1.150,4.850], [-5.500,-0.820,1.290]]), - (137, [[-24.460,-122.950,849.040], [-11.050,-2.260,-14.690], [1.030,-6.350,0.200], [1.600,-0.050,0.470], [-5.050,-0.700,3.900], [-6.400,0.950,-0.750]]), - (138, [[-23.980,-124.710,821.700], [-13.900,-3.450,-17.210], [-1.090,-5.980,2.080], [-0.110,-0.110,-0.760], [-4.880,2.110,3.530], [5.050,-0.430,0.870]]), - (139, [[-38.600,-127.220,820.180], [-12.580,-0.430,8.780], [-0.020,-6.390,-0.330], [-0.170,-0.020,-0.170], [3.670,-0.290,5.240], [4.860,-1.540,-2.070]]), - (140, [[-42.520,-125.650,832.780], [1.330,2.910,14.250], [-1.250,-6.100,1.370], [-0.030,0.210,1.190], [6.110,-1.310,-0.300], [1.080,-0.260,-3.490]]), - (141, [[-35.800,-121.920,845.730], [4.200,3.780,10.200], [0.010,-5.960,2.200], [-0.160,0.230,0.570], [5.880,-0.780,-2.130], [0.090,0.030,0.690]]), - (142, [[-33.620,-118.720,852.840], [0.500,3.010,6.470], [-0.930,-5.650,2.700], [-0.790,-0.030,-0.570], [6.150,-1.010,0.000], [-0.330,-0.030,2.500]]), - (143, [[-34.440,-116.110,858.280], [-2.640,1.810,5.040], [-1.710,-5.940,1.230], [0.580,-0.290,-1.410], [5.320,-0.890,3.110], [-1.830,0.370,2.710]]), - (144, [[-38.380,-115.330,862.170], [-6.050,-0.340,2.350], [0.220,-6.280,-0.340], [1.370,-0.090,-0.250], [2.280,-0.240,5.850], [-4.210,0.450,0.940]]), - (145, [[-44.500,-116.930,861.580], [-11.590,-3.810,-10.160], [1.110,-6.090,1.020], [0.440,0.120,0.610], [-4.130,0.030,4.700], [-4.540,0.050,-0.790]]), - (146, [[-51.780,-120.720,839.030], [-15.880,-5.450,-10.360], [1.830,-5.970,0.320], [-1.360,0.270,0.870], [-3.220,-0.700,5.310], [4.290,0.490,0.090]]), - (147, [[-64.650,-124.350,841.480], [-11.510,0.420,9.850], [0.150,-6.190,0.440], [-0.550,0.330,1.540], [3.970,0.430,4.630], [4.380,-0.520,-2.900]]), - (148, [[-69.370,-119.950,854.330], [5.110,4.210,16.620], [-1.330,-5.740,1.870], [0.690,0.270,0.730], [5.670,-1.740,-1.310], [0.560,-1.580,-4.180]]), - (149, [[-55.630,-118.570,867.170], [8.190,15.700,8.570], [-2.415,-2.636,3.160], [0.890,1.630,1.440], [4.280,-1.310,-1.700], [0.130,0.200,0.140]]), - (150, [[-52.380,-100.900,869.760], [4.760,24.010,12.610], [-3.169,0.219,3.447], [-0.280,-0.300,-1.610], [4.600,-0.510,-0.770], [-2.290,1.100,4.280]]), - (151, [[-41.730,-76.290,892.900], [-14.020,14.240,19.650], [-3.750,-3.589,-1.622], [3.240,-2.890,0.750], [1.930,-2.620,3.270], [-5.090,5.860,6.610]]), - (152, [[-60.630,-80.530,895.250], [-6.170,-10.100,-5.870], [2.660,0.730,-4.050], [2.380,0.990,-1.140], [3.310,-2.970,1.640], [2.380,0.990,-1.140]]) - ] ), - - 'userAnnotationGroups': [ - { - '_AnnotationGroup': True, - 'dimension': 1, - 'identifierRanges': '1-150', - 'name': get_smallintestine_term('small intestine')[0], - 'ontId': get_smallintestine_term('small intestine')[1] - }, - { - '_AnnotationGroup': True, - 'dimension': 1, - 'identifierRanges': '1-5', - 'name': get_smallintestine_term('duodenum')[0], - 'ontId': get_smallintestine_term('duodenum')[1] - }, - { - '_AnnotationGroup': True, - 'dimension': 1, - 'identifierRanges': '6-82', - 'name': get_smallintestine_term('jejunum')[0], - 'ontId': get_smallintestine_term('jejunum')[1] - }, - { - '_AnnotationGroup': True, - 'dimension': 1, - 'identifierRanges': '83-150', - 'name': get_smallintestine_term('ileum')[0], - 'ontId': get_smallintestine_term('ileum')[1] - }] - }), + }) - 'Mouse 1': ScaffoldPackage(MeshType_1d_network_layout1, { + elif "Mouse 1" in parameterSetName: + return ScaffoldPackage(MeshType_1d_network_layout1, { 'scaffoldSettings': { "Structure": "1-2-3-4-5-6-7-8-9-10-11-12-13-14-15-16-17-18-19-20-21-22-23-24-25-26-27-28-29-30-31-32-" "33-34-35-36-37-38-39-40-41-42-43-44-45-46" @@ -911,8 +906,17 @@ class MeshType_3d_smallintestine1(Scaffold_base): 'name': get_smallintestine_term('ileum')[0], 'ontId': get_smallintestine_term('ileum')[1] }] - } ) - } + }) + + +class MeshType_3d_smallintestine1(Scaffold_base): + ''' + Generates a 3-D small intestine mesh with variable numbers + of elements around, along the central line, and through wall. + The small intestine is created by a function that generates + a small intestine segment and uses tubemesh to map the segment + along a central line profile. + ''' @staticmethod def getName(): @@ -928,14 +932,8 @@ def getParameterSetNames(): @classmethod def getDefaultOptions(cls, parameterSetName='Default'): - if 'Cattle 1' in parameterSetName: - centralPathOption = cls.parameterSetStructureStrings['Cattle 1'] - elif 'Mouse 1' in parameterSetName: - centralPathOption = cls.parameterSetStructureStrings['Mouse 1'] - else: - centralPathOption = cls.parameterSetStructureStrings['Human 1'] options = { - 'Central path': copy.deepcopy(centralPathOption), + 'Network layout': getDefaultNetworkLayoutScaffoldPackage(cls, parameterSetName), 'Number of segments': 80, 'Number of elements around': 12, 'Number of elements along segment': 3, @@ -966,7 +964,7 @@ def getDefaultOptions(cls, parameterSetName='Default'): @staticmethod def getOrderedOptionNames(): return [ - 'Central path', + 'Network layout', 'Number of segments', 'Number of elements around', 'Number of elements along segment', @@ -985,14 +983,14 @@ def getOrderedOptionNames(): @classmethod def getOptionValidScaffoldTypes(cls, optionName): - if optionName == 'Central path': + if optionName == 'Network layout': return [ MeshType_1d_network_layout1 ] return [] @classmethod def getOptionScaffoldTypeParameterSetNames(cls, optionName, scaffoldType): - if optionName == 'Central path': - return list(cls.parameterSetStructureStrings.keys()) + if optionName == 'Network layout': + return cls.getParameterSetNames() assert scaffoldType in cls.getOptionValidScaffoldTypes(optionName), \ cls.__name__ + '.getOptionScaffoldTypeParameterSetNames. ' + \ 'Invalid option \'' + optionName + '\' scaffold type ' + scaffoldType.getName() @@ -1008,16 +1006,16 @@ def getOptionScaffoldPackage(cls, optionName, scaffoldType, parameterSetName=Non assert parameterSetName in cls.getOptionScaffoldTypeParameterSetNames(optionName, scaffoldType), \ 'Invalid parameter set ' + str(parameterSetName) + ' for scaffold ' + str(scaffoldType.getName()) + \ ' in option ' + str(optionName) + ' of scaffold ' + cls.getName() - if optionName == 'Central path': + if optionName == 'Network layout': if not parameterSetName: - parameterSetName = list(cls.parameterSetStructureStrings.keys())[0] - return copy.deepcopy(cls.parameterSetStructureStrings[parameterSetName]) + parameterSetName = "Default" + return getDefaultNetworkLayoutScaffoldPackage(cls, parameterSetName) assert False, cls.__name__ + '.getOptionScaffoldPackage: Option ' + optionName + ' is not a scaffold' @classmethod def checkOptions(cls, options): - if not options['Central path'].getScaffoldType() in cls.getOptionValidScaffoldTypes('Central path'): - options['Central path'] = cls.getOptionScaffoldPackage('Central path', MeshType_1d_network_layout1) + if not options['Network layout'].getScaffoldType() in cls.getOptionValidScaffoldTypes('Network layout'): + options['Network layout'] = cls.getOptionScaffoldPackage('Network layout', MeshType_1d_network_layout1) for key in [ 'Number of segments', 'Number of elements around', @@ -1043,7 +1041,7 @@ def generateBaseMesh(cls, region, options): nextNodeIdentifier = 1 nextElementIdentifier = 1 smallIntestineTermsAlong = ['small intestine', 'duodenum', 'jejunum', 'ileum'] - geometricCentralPath = options['Central path'] + geometricCentralPath = options['Network layout'] geometricCentralPath = SmallIntestineCentralPath(region, geometricCentralPath, smallIntestineTermsAlong) annotationGroups, nextNodeIdentifier, nextElementIdentifier = \ diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py index c99b0fe8..20ecc908 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py @@ -39,16 +39,10 @@ mesh_destroy_elements_and_nodes_by_identifiers, get_nodeset_path_ordered_field_parameters, \ get_nodeset_path_field_parameters - -class MeshType_3d_stomach1(Scaffold_base): - """ - Generates a 3-D stomach mesh with variable numbers of elements around the esophagus and duodenum, - along the central line, and through wall. The stomach is created using a central path as the longitudinal axis - of the stomach. D2 of the central path points to the greater curvature of the stomach and magnitude of D2 and D3 - are the radii of the stomach in the respective direction. - """ - parameterSetStructureStrings = { - 'Human 1': ScaffoldPackage(MeshType_1d_network_layout1, { +def getDefaultNetworkLayoutScaffoldPackage(cls, parameterSetName): + assert parameterSetName in cls.getParameterSetNames() # make sure parameter set is in list of parameters of parent scaffold + if parameterSetName in ("Default", "Human 1"): + return ScaffoldPackage(MeshType_1d_network_layout1, { 'scaffoldSettings': { "Structure": "1-2-3.2, 4-5-6-7-8-3-9-10-11-12-13-14-15" }, @@ -121,9 +115,10 @@ class MeshType_3d_stomach1(Scaffold_base): 'name': get_stomach_term('duodenum part of stomach')[0], 'ontId': get_stomach_term('duodenum part of stomach')[1] }] - }), - 'Human 2': ScaffoldPackage(MeshType_1d_network_layout1, { - 'scaffoldSettings': { + }) + elif "Human 2" in parameterSetName: + return ScaffoldPackage(MeshType_1d_network_layout1, { + 'scaffoldSettings': { "Structure": "1-2-3.2, 4-5-6-7-3-8-9-10-11-12-13-14-15" }, 'meshEdits': exnode_string_from_nodeset_field_parameters( @@ -195,8 +190,9 @@ class MeshType_3d_stomach1(Scaffold_base): 'name': get_stomach_term('duodenum part of stomach')[0], 'ontId': get_stomach_term('duodenum part of stomach')[1] }] - }), - 'Mouse 1': ScaffoldPackage(MeshType_1d_network_layout1, { + }) + elif "Mouse 1" in parameterSetName: + return ScaffoldPackage(MeshType_1d_network_layout1, { 'scaffoldSettings': { "Structure": "1-2-3.2, 4-5-6-7-8-9-3-10-11-12-13-14" }, @@ -268,8 +264,9 @@ class MeshType_3d_stomach1(Scaffold_base): 'name': get_stomach_term('duodenum part of stomach')[0], 'ontId': get_stomach_term('duodenum part of stomach')[1] }] - }), - 'Pig 1': ScaffoldPackage(MeshType_1d_network_layout1, { + }) + elif "Pig 1" in parameterSetName: + return ScaffoldPackage(MeshType_1d_network_layout1, { 'scaffoldSettings': { "Structure": "1-2-3.2, 4-5-6-7-3-8-9-10-11-12-13" }, @@ -340,82 +337,84 @@ class MeshType_3d_stomach1(Scaffold_base): 'name': get_stomach_term('duodenum part of stomach')[0], 'ontId': get_stomach_term('duodenum part of stomach')[1] }] - }), - 'Rat 1': ScaffoldPackage(MeshType_1d_network_layout1, { + }) + elif "Rat 1" in parameterSetName: + return ScaffoldPackage(MeshType_1d_network_layout1, { 'scaffoldSettings': { - "Structure": "1-2-3.2, 4-5-6-7-8-9-3-10-11-12-13-14-15" - }, - 'meshEdits': exnode_string_from_nodeset_field_parameters( - [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ - (1, [[-0.011,0.636,0.000], [0.012,-0.116,0.000], [0.057,0.000,0.000], [0.122,-0.056,0.000], [-0.000,0.000,0.057], [0.000,0.000,0.076]]), - (2, [[-0.001,0.419,-0.000], [0.008,-0.318,0.000], [0.108,0.000,0.000], [0.101,-0.066,0.000], [0.000,0.000,0.108], [0.000,0.000,0.084]]), - (3, [[0.000,0.000,0.000], [[-0.200,0.002,0.000],[-0.006,-0.520,0.000]], [[0.005,-0.420,0.000],[0.108,0.000,0.000]], [[-0.156,0.003,0.000],[-0.156,0.003,0.000]], [[0.000,0.000,0.360],[0.000,0.000,0.108]], [[0.000,0.000,-0.009],[0.000,0.000,-0.009]]]), - (4, [[0.601,0.602,0.000], [-0.027,-0.056,0.000], [0.077,-0.036,0.000], [0.122,-0.056,0.000], [0.000,0.000,0.080], [0.000,0.000,0.076]]), - (5, [[0.564,0.524,0.000], [-0.047,-0.100,-0.000], [0.189,-0.097,0.000], [0.101,-0.066,0.000], [0.000,0.000,0.160], [0.000,0.000,0.084]]), - (6, [[0.507,0.402,0.000], [-0.071,-0.139,-0.000], [0.273,-0.171,0.000], [0.062,-0.070,-0.000], [0.000,0.000,0.250], [0.000,0.000,0.073]]), - (7, [[0.420,0.248,0.000], [-0.097,-0.137,-0.000], [0.307,-0.237,0.000], [-0.011,-0.067,-0.000], [0.000,0.000,0.300], [0.000,0.000,0.039]]), - (8, [[0.315,0.129,0.000], [-0.125,-0.109,-0.000], [0.256,-0.304,0.000], [-0.080,-0.076,0.000], [0.000,0.000,0.330], [0.000,0.000,0.030]]), - (9, [[0.171,0.034,0.000], [-0.161,-0.066,0.000], [0.144,-0.389,0.000], [-0.125,-0.058,0.000], [0.000,0.000,0.360], [0.000,0.000,0.015]]), - (10, [[-0.218,0.048,0.000], [-0.208,0.094,0.000], [-0.173,-0.374,0.000], [-0.152,0.079,0.000], [0.000,0.000,0.340], [0.000,0.000,-0.015]]), - (11, [[-0.404,0.184,0.000], [-0.142,0.162,0.000], [-0.299,-0.260,0.000], [-0.044,0.113,0.000], [0.000,0.000,0.330], [0.000,0.000,-0.025]]), - (12, [[-0.497,0.356,0.000], [-0.049,0.209,0.000], [-0.255,-0.188,0.000], [0.077,0.107,0.000], [0.000,0.000,0.290], [0.000,0.000,-0.111]]), - (13, [[-0.490,0.587,0.000], [-0.018,0.189,-0.000], [-0.152,-0.045,0.000], [0.069,0.049,0.000], [0.000,0.000,0.120], [0.000,0.000,-0.073]]), - (14, [[-0.523,0.730,0.000], [-0.032,0.116,0.000], [-0.111,-0.036,0.000], [0.003,-0.002,0.000], [0.000,0.000,0.120], [0.000,0.000,0.018]]), - (15, [[-0.552,0.820,0.000], [-0.026,0.063,0.000], [-0.132,-0.045,0.000], [-0.045,-0.016,0.000], [0.000,0.000,0.150], [0.000,0.000,0.042]]) - ]), - - 'userAnnotationGroups': [ - { - '_AnnotationGroup': True, - 'dimension': 1, - 'identifierRanges': '1-14', - 'name': get_stomach_term('stomach')[0], - 'ontId': get_stomach_term('stomach')[1] - }, - { - '_AnnotationGroup': True, - 'dimension': 1, - 'identifierRanges': '1-2', - 'name': get_stomach_term('esophagus part of stomach')[0], - 'ontId': get_stomach_term('esophagus part of stomach')[1] - }, - { - '_AnnotationGroup': True, - 'dimension': 1, - 'identifierRanges': '3-8', - 'name': get_stomach_term('fundus of stomach')[0], - 'ontId': get_stomach_term('fundus of stomach')[1] + "Structure": "1-2-3.2, 4-5-6-7-8-9-3-10-11-12-13-14-15" }, - { - '_AnnotationGroup': True, - 'dimension': 1, - 'identifierRanges': '9-11', - 'name': get_stomach_term('body of stomach')[0], - 'ontId': get_stomach_term('body of stomach')[1] - }, - { - '_AnnotationGroup': True, - 'dimension': 1, - 'identifierRanges': '12', - 'name': get_stomach_term('pyloric antrum')[0], - 'ontId': get_stomach_term('pyloric antrum')[1] - }, - { - '_AnnotationGroup': True, - 'dimension': 1, - 'identifierRanges': '13', - 'name': get_stomach_term('pyloric canal')[0], - 'ontId': get_stomach_term('pyloric canal')[1] - }, - { - '_AnnotationGroup': True, - 'dimension': 1, - 'identifierRanges': '14', - 'name': get_stomach_term('duodenum part of stomach')[0], - 'ontId': get_stomach_term('duodenum part of stomach')[1] - }] - }), - 'Material': ScaffoldPackage(MeshType_1d_network_layout1, { + 'meshEdits': exnode_string_from_nodeset_field_parameters( + [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ + (1, [[-0.011,0.636,0.000], [0.012,-0.116,0.000], [0.057,0.000,0.000], [0.122,-0.056,0.000], [-0.000,0.000,0.057], [0.000,0.000,0.076]]), + (2, [[-0.001,0.419,-0.000], [0.008,-0.318,0.000], [0.108,0.000,0.000], [0.101,-0.066,0.000], [0.000,0.000,0.108], [0.000,0.000,0.084]]), + (3, [[0.000,0.000,0.000], [[-0.200,0.002,0.000],[-0.006,-0.520,0.000]], [[0.005,-0.420,0.000],[0.108,0.000,0.000]], [[-0.156,0.003,0.000],[-0.156,0.003,0.000]], [[0.000,0.000,0.360],[0.000,0.000,0.108]], [[0.000,0.000,-0.009],[0.000,0.000,-0.009]]]), + (4, [[0.601,0.602,0.000], [-0.027,-0.056,0.000], [0.077,-0.036,0.000], [0.122,-0.056,0.000], [0.000,0.000,0.080], [0.000,0.000,0.076]]), + (5, [[0.564,0.524,0.000], [-0.047,-0.100,-0.000], [0.189,-0.097,0.000], [0.101,-0.066,0.000], [0.000,0.000,0.160], [0.000,0.000,0.084]]), + (6, [[0.507,0.402,0.000], [-0.071,-0.139,-0.000], [0.273,-0.171,0.000], [0.062,-0.070,-0.000], [0.000,0.000,0.250], [0.000,0.000,0.073]]), + (7, [[0.420,0.248,0.000], [-0.097,-0.137,-0.000], [0.307,-0.237,0.000], [-0.011,-0.067,-0.000], [0.000,0.000,0.300], [0.000,0.000,0.039]]), + (8, [[0.315,0.129,0.000], [-0.125,-0.109,-0.000], [0.256,-0.304,0.000], [-0.080,-0.076,0.000], [0.000,0.000,0.330], [0.000,0.000,0.030]]), + (9, [[0.171,0.034,0.000], [-0.161,-0.066,0.000], [0.144,-0.389,0.000], [-0.125,-0.058,0.000], [0.000,0.000,0.360], [0.000,0.000,0.015]]), + (10, [[-0.218,0.048,0.000], [-0.208,0.094,0.000], [-0.173,-0.374,0.000], [-0.152,0.079,0.000], [0.000,0.000,0.340], [0.000,0.000,-0.015]]), + (11, [[-0.404,0.184,0.000], [-0.142,0.162,0.000], [-0.299,-0.260,0.000], [-0.044,0.113,0.000], [0.000,0.000,0.330], [0.000,0.000,-0.025]]), + (12, [[-0.497,0.356,0.000], [-0.049,0.209,0.000], [-0.255,-0.188,0.000], [0.077,0.107,0.000], [0.000,0.000,0.290], [0.000,0.000,-0.111]]), + (13, [[-0.490,0.587,0.000], [-0.018,0.189,-0.000], [-0.152,-0.045,0.000], [0.069,0.049,0.000], [0.000,0.000,0.120], [0.000,0.000,-0.073]]), + (14, [[-0.523,0.730,0.000], [-0.032,0.116,0.000], [-0.111,-0.036,0.000], [0.003,-0.002,0.000], [0.000,0.000,0.120], [0.000,0.000,0.018]]), + (15, [[-0.552,0.820,0.000], [-0.026,0.063,0.000], [-0.132,-0.045,0.000], [-0.045,-0.016,0.000], [0.000,0.000,0.150], [0.000,0.000,0.042]]) + ]), + + 'userAnnotationGroups': [ + { + '_AnnotationGroup': True, + 'dimension': 1, + 'identifierRanges': '1-14', + 'name': get_stomach_term('stomach')[0], + 'ontId': get_stomach_term('stomach')[1] + }, + { + '_AnnotationGroup': True, + 'dimension': 1, + 'identifierRanges': '1-2', + 'name': get_stomach_term('esophagus part of stomach')[0], + 'ontId': get_stomach_term('esophagus part of stomach')[1] + }, + { + '_AnnotationGroup': True, + 'dimension': 1, + 'identifierRanges': '3-8', + 'name': get_stomach_term('fundus of stomach')[0], + 'ontId': get_stomach_term('fundus of stomach')[1] + }, + { + '_AnnotationGroup': True, + 'dimension': 1, + 'identifierRanges': '9-11', + 'name': get_stomach_term('body of stomach')[0], + 'ontId': get_stomach_term('body of stomach')[1] + }, + { + '_AnnotationGroup': True, + 'dimension': 1, + 'identifierRanges': '12', + 'name': get_stomach_term('pyloric antrum')[0], + 'ontId': get_stomach_term('pyloric antrum')[1] + }, + { + '_AnnotationGroup': True, + 'dimension': 1, + 'identifierRanges': '13', + 'name': get_stomach_term('pyloric canal')[0], + 'ontId': get_stomach_term('pyloric canal')[1] + }, + { + '_AnnotationGroup': True, + 'dimension': 1, + 'identifierRanges': '14', + 'name': get_stomach_term('duodenum part of stomach')[0], + 'ontId': get_stomach_term('duodenum part of stomach')[1] + }] + }) + elif "Material" in parameterSetName: + return ScaffoldPackage(MeshType_1d_network_layout1, { 'scaffoldSettings': { "Structure": "1-2-3.2, 4-5-6-7-8-9-3-10-11-12-13-14-15-16-17-18" }, @@ -491,8 +490,16 @@ class MeshType_3d_stomach1(Scaffold_base): 'name': get_stomach_term('duodenum part of stomach')[0], 'ontId': get_stomach_term('duodenum part of stomach')[1] }] - }), - } + }) + + +class MeshType_3d_stomach1(Scaffold_base): + """ + Generates a 3-D stomach mesh with variable numbers of elements around the esophagus and duodenum, + along the central line, and through wall. The stomach is created using a central path as the longitudinal axis + of the stomach. D2 of the central path points to the greater curvature of the stomach and magnitude of D2 and D3 + are the radii of the stomach in the respective direction. + """ ostiumDefaultScaffoldPackages = { 'Human 1': ScaffoldPackage(MeshType_3d_ostium2, { @@ -635,26 +642,20 @@ def getParameterSetNames(): @classmethod def getDefaultOptions(cls, parameterSetName='Default'): if 'Human 2' in parameterSetName: - centralPathOption = cls.parameterSetStructureStrings['Human 2'] ostiumOption = cls.ostiumDefaultScaffoldPackages['Human 2'] elif 'Mouse 1' in parameterSetName: - centralPathOption = cls.parameterSetStructureStrings['Mouse 1'] ostiumOption = cls.ostiumDefaultScaffoldPackages['Mouse 1'] elif 'Pig 1' in parameterSetName: - centralPathOption = cls.parameterSetStructureStrings['Pig 1'] ostiumOption = cls.ostiumDefaultScaffoldPackages['Pig 1'] elif 'Rat 1' in parameterSetName: - centralPathOption = cls.parameterSetStructureStrings['Rat 1'] ostiumOption = cls.ostiumDefaultScaffoldPackages['Rat 1'] elif 'Material' in parameterSetName: - centralPathOption = cls.parameterSetStructureStrings['Material'] ostiumOption = cls.ostiumDefaultScaffoldPackages['Material'] else: - centralPathOption = cls.parameterSetStructureStrings['Human 1'] ostiumOption = cls.ostiumDefaultScaffoldPackages['Human 1'] options = { - 'Central path': copy.deepcopy(centralPathOption), + 'Network layout': getDefaultNetworkLayoutScaffoldPackage(cls, parameterSetName), 'Number of elements around esophagus': 8, 'Number of elements around duodenum': 16, 'Number of elements along': 14, @@ -711,7 +712,7 @@ def getDefaultOptions(cls, parameterSetName='Default'): @staticmethod def getOrderedOptionNames(): return [ - 'Central path', + 'Network layout', 'Number of elements around esophagus', 'Number of elements around duodenum', 'Number of elements along', @@ -731,7 +732,7 @@ def getOrderedOptionNames(): @classmethod def getOptionValidScaffoldTypes(cls, optionName): - if optionName == 'Central path': + if optionName == 'Network layout': return [MeshType_1d_network_layout1] if optionName == 'Gastro-esophageal junction': return [MeshType_3d_ostium2] @@ -739,8 +740,8 @@ def getOptionValidScaffoldTypes(cls, optionName): @classmethod def getOptionScaffoldTypeParameterSetNames(cls, optionName, scaffoldType): - if optionName == 'Central path': - return list(cls.parameterSetStructureStrings.keys()) + if optionName == 'Network layout': + return cls.getParameterSetNames() if optionName == 'Gastro-esophageal junction': return list(cls.ostiumDefaultScaffoldPackages.keys()) assert scaffoldType in cls.getOptionValidScaffoldTypes(optionName), \ @@ -758,10 +759,10 @@ def getOptionScaffoldPackage(cls, optionName, scaffoldType, parameterSetName=Non assert parameterSetName in cls.getOptionScaffoldTypeParameterSetNames(optionName, scaffoldType), \ 'Invalid parameter set ' + str(parameterSetName) + ' for scaffold ' + str(scaffoldType.getName()) + \ ' in option ' + str(optionName) + ' of scaffold ' + cls.getName() - if optionName == 'Central path': + if optionName == 'Network layout': if not parameterSetName: - parameterSetName = list(cls.parameterSetStructureStrings.keys())[0] - return copy.deepcopy(cls.parameterSetStructureStrings[parameterSetName]) + parameterSetName = "Default" + return getDefaultNetworkLayoutScaffoldPackage(cls, parameterSetName) if optionName == 'Gastro-esophageal junction': if not parameterSetName: parameterSetName = list(cls.ostiumDefaultScaffoldPackages.keys())[0] @@ -770,8 +771,8 @@ def getOptionScaffoldPackage(cls, optionName, scaffoldType, parameterSetName=Non @classmethod def checkOptions(cls, options): - if not options['Central path'].getScaffoldType() in cls.getOptionValidScaffoldTypes('Central path'): - options['Central path'] = cls.getOptionScaffoldPackage('Central path', MeshType_1d_network_layout1) + if not options['Network layout'].getScaffoldType() in cls.getOptionValidScaffoldTypes('Network layout'): + options['Network layout'] = cls.getOptionScaffoldPackage('Network layout', MeshType_1d_network_layout1) if not options['Gastro-esophageal junction'].getScaffoldType() in cls.getOptionValidScaffoldTypes( 'Gastro-esophageal junction'): options['Gastro-esophageal junction'] = cls.getOptionScaffoldPackage('Gastro-esophageal junction', @@ -832,8 +833,8 @@ def generateBaseMesh(cls, region, options): :return: list of AnnotationGroup, None """ cls.updateSubScaffoldOptions(options) - geometricCentralPath = options['Central path'] - materialCentralPath = cls.parameterSetStructureStrings['Material'] + geometricCentralPath = options['Network layout'] + materialCentralPath = getDefaultNetworkLayoutScaffoldPackage(cls, 'Material') limitingRidge = options['Limiting ridge'] elementsCountThroughWall = options['Number of elements through wall'] From f9709e32edfff569a8e1b9cbee0c7c3f4d2b1591 Mon Sep 17 00:00:00 2001 From: mlin865 Date: Thu, 22 Feb 2024 15:26:51 +1300 Subject: [PATCH 20/24] Remove preview of ostium2 subscaffold from stomach and cecum scaffold on the UI --- .../meshtypes/meshtype_3d_cecum1.py | 132 ++++------ .../meshtypes/meshtype_3d_stomach1.py | 241 +++++------------- 2 files changed, 106 insertions(+), 267 deletions(-) diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_cecum1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_cecum1.py index ddcea32d..f7af9406 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_cecum1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_cecum1.py @@ -17,7 +17,7 @@ from scaffoldmaker.meshtypes.meshtype_1d_network_layout1 import MeshType_1d_network_layout1 from scaffoldmaker.meshtypes.meshtype_3d_colonsegment1 import ColonSegmentTubeMeshOuterPoints, \ getFullProfileFromHalfHaustrum, getTeniaColi, createNodesAndElementsTeniaColi -from scaffoldmaker.meshtypes.meshtype_3d_ostium2 import MeshType_3d_ostium2, generateOstiumMesh +from scaffoldmaker.meshtypes.meshtype_3d_ostium2 import generateOstiumMesh from scaffoldmaker.meshtypes.scaffold_base import Scaffold_base from scaffoldmaker.scaffoldpackage import ScaffoldPackage from scaffoldmaker.utils import interpolation as interp @@ -127,20 +127,12 @@ def getDefaultNetworkLayoutScaffoldPackage(cls, parameterSetName): 'ontId': get_cecum_term('ileum part of cecum')[1] }] }) - -class MeshType_3d_cecum1(Scaffold_base): - ''' - Generates a 3-D cecum mesh with variable numbers of elements around, along the central line, and through wall. The - cecum is created by a function that generates a cecum segment and uses tubemesh to map the segment along a network - layout. The proximal end of the cecum is closed up with an apex plate. An ostium is included to generate the - ileo-cecal junction. - ''' - - ostiumDefaultScaffoldPackages = { - 'Human 1': ScaffoldPackage(MeshType_3d_ostium2, { - 'scaffoldSettings': { - 'Number of elements around ostium': 8, +def getDefaultOstiumSettings(): + """ + Generate list of default options for ostium. + """ + options = { 'Number of elements around ostium': 8, 'Number of elements along': 2, 'Number of elements through wall': 1, 'Unit scale': 1.0, @@ -155,28 +147,42 @@ class MeshType_3d_cecum1(Scaffold_base): 'Refine': False, 'Refine number of elements around': 4, 'Refine number of elements along': 4, - 'Refine number of elements through wall': 1 - }, - }), - 'Pig 1': ScaffoldPackage(MeshType_3d_ostium2, { - 'scaffoldSettings': { - 'Number of elements around ostium': 8, - 'Number of elements along': 2, - 'Number of elements through wall': 1, - 'Unit scale': 1.0, - 'Outlet': False, - 'Ostium wall thickness': 2.0, - 'Use linear through ostium wall': True, - 'Vessel wall thickness': 2.0, - 'Use linear through vessel wall': True, - 'Use cross derivatives': False, - 'Refine': False, - 'Refine number of elements around': 4, - 'Refine number of elements along': 4, - 'Refine number of elements through wall': 1 - }, - }) - } + 'Refine number of elements through wall': 1} + + return options + +def updateOstiumOptions(options, ostiumOptions): + """ + Update ostium sub-scaffold options which depend on parent options. + """ + ostiumOptions['Ostium wall thickness'] = options['Wall thickness'] + ostiumOptions['Vessel wall thickness'] = options['Ileum wall thickness'] + elementsCountThroughWall = options['Number of elements through wall'] + ostiumOptions['Number of elements through wall'] = elementsCountThroughWall + ostiumOptions['Use linear through ostium wall'] = options['Use linear through wall'] + ostiumOptions['Use linear through vessel wall'] = options['Use linear through wall'] + if elementsCountThroughWall == 1: + ostiumOptions['Ostium wall relative thicknesses'] = [1.0] + ostiumOptions['Vessel wall relative thicknesses'] = [1.0] + else: + mucosaRelThickness = options['Mucosa relative thickness'] + submucosaRelThickness = options['Submucosa relative thickness'] + circularRelThickness = options['Circular muscle layer relative thickness'] + longRelThickness = options['Longitudinal muscle layer relative thickness'] + relThicknesses = [mucosaRelThickness, submucosaRelThickness, circularRelThickness, longRelThickness] + ostiumOptions['Ostium wall relative thicknesses'] = relThicknesses + ostiumOptions['Vessel wall relative thicknesses'] = relThicknesses + + return ostiumOptions + + +class MeshType_3d_cecum1(Scaffold_base): + ''' + Generates a 3-D cecum mesh with variable numbers of elements around, along the central line, and through wall. The + cecum is created by a function that generates a cecum segment and uses tubemesh to map the segment along a network + layout. The proximal end of the cecum is closed up with an apex plate. An ostium is included to generate the + ileo-cecal junction. + ''' @staticmethod def getName(): @@ -192,13 +198,6 @@ def getParameterSetNames(): @classmethod def getDefaultOptions(cls, parameterSetName='Default'): - if 'Human 2' in parameterSetName: - ostiumOption = cls.ostiumDefaultScaffoldPackages['Human 1'] - elif 'Pig 1' in parameterSetName: - ostiumOption = cls.ostiumDefaultScaffoldPackages['Pig 1'] - else: - ostiumOption = cls.ostiumDefaultScaffoldPackages['Human 1'] - options = { 'Network layout': getDefaultNetworkLayoutScaffoldPackage(cls, parameterSetName), 'Number of segments': 1, @@ -217,11 +216,11 @@ def getDefaultOptions(cls, parameterSetName='Default'): 'End tenia coli width derivative': 3.3, 'Tenia coli thickness': 0.5, 'Wall thickness': 1.6, + 'Ileum wall thickness': 1.6, 'Mucosa relative thickness': 0.55, 'Submucosa relative thickness': 0.15, 'Circular muscle layer relative thickness': 0.25, 'Longitudinal muscle layer relative thickness': 0.05, - 'Ileocecal junction': copy.deepcopy(ostiumOption), 'Use cross derivatives': False, 'Use linear through wall': True, 'Refine': False, @@ -250,9 +249,9 @@ def getDefaultOptions(cls, parameterSetName='Default'): options['End tenia coli width'] = 5.0 options['End tenia coli width derivative'] = 0.0 options['Wall thickness'] = 2.0 + options['Ileum wall thickness'] = 2.0 options['Base parameter set'] = parameterSetName - cls.updateSubScaffoldOptions(options) return options @staticmethod @@ -275,11 +274,11 @@ def getOrderedOptionNames(): 'End tenia coli width derivative', 'Tenia coli thickness', 'Wall thickness', + 'Ileum wall thickness', 'Mucosa relative thickness', 'Submucosa relative thickness', 'Circular muscle layer relative thickness', 'Longitudinal muscle layer relative thickness', - 'Ileocecal junction', 'Use cross derivatives', 'Use linear through wall', 'Refine', @@ -291,16 +290,12 @@ def getOrderedOptionNames(): def getOptionValidScaffoldTypes(cls, optionName): if optionName == 'Network layout': return [ MeshType_1d_network_layout1 ] - if optionName == 'Ileocecal junction': - return [ MeshType_3d_ostium2 ] return [] @classmethod def getOptionScaffoldTypeParameterSetNames(cls, optionName, scaffoldType): if optionName == 'Network layout': return cls.getParameterSetNames() - if optionName == 'Ileocecal junction': - return list(cls.ostiumDefaultScaffoldPackages.keys()) assert scaffoldType in cls.getOptionValidScaffoldTypes(optionName), cls.__name__ + '.getOptionScaffoldTypeParameterSetNames. ' + \ 'Invalid option \'' + optionName + '\' scaffold type ' + scaffoldType.getName() return scaffoldType.getParameterSetNames() @@ -318,18 +313,12 @@ def getOptionScaffoldPackage(cls, optionName, scaffoldType, parameterSetName=Non if not parameterSetName: parameterSetName = "Default" return getDefaultNetworkLayoutScaffoldPackage(cls, parameterSetName) - if optionName == 'Ileocecal junction': - if not parameterSetName: - parameterSetName = list(cls.ostiumDefaultScaffoldPackages.keys())[0] - return copy.deepcopy(cls.ostiumDefaultScaffoldPackages[parameterSetName]) assert False, cls.__name__ + '.getOptionScaffoldPackage: Option ' + optionName + ' is not a scaffold' @classmethod def checkOptions(cls, options): if not options['Network layout'].getScaffoldType() in cls.getOptionValidScaffoldTypes('Network layout'): options['Network layout'] = cls.getOptionScaffoldPackage('Network layout', MeshType_1d_network_layout1) - if not options['Ileocecal junction'].getScaffoldType() in cls.getOptionValidScaffoldTypes('Ileocecal junction'): - options['Ileocecal junction'] = cls.getOptionScaffoldPackage('Ileocecal junction', MeshType_3d_ostium2) for key in [ 'Number of segments', 'Refine number of elements around', @@ -359,32 +348,6 @@ def checkOptions(cls, options): options['Number of elements along segment'] = options['Number of elements along segment'] // 4 * 4 if options['Number of elements through wall'] != (1 or 4): options['Number of elements through wall'] = 4 - cls.updateSubScaffoldOptions(options) - - @classmethod - def updateSubScaffoldOptions(cls, options): - ''' - Update ostium sub-scaffold options which depend on parent options. - ''' - wallThickness = options['Wall thickness'] - ostiumOptions = options['Ileocecal junction'] - ostiumSettings = ostiumOptions.getScaffoldSettings() - ostiumSettings['Ostium wall thickness'] = wallThickness - elementsCountThroughWall = options['Number of elements through wall'] - ostiumSettings['Number of elements through wall'] = elementsCountThroughWall - ostiumSettings['Use linear through ostium wall'] = options['Use linear through wall'] - ostiumSettings['Use linear through vessel wall'] = options['Use linear through wall'] - if elementsCountThroughWall == 1: - ostiumSettings['Ostium wall relative thicknesses'] = [1.0] - ostiumSettings['Vessel wall relative thicknesses'] = [1.0] - else: - mucosaRelThickness = options['Mucosa relative thickness'] - submucosaRelThickness = options['Submucosa relative thickness'] - circularRelThickness = options['Circular muscle layer relative thickness'] - longRelThickness = options['Longitudinal muscle layer relative thickness'] - relThicknesses = [mucosaRelThickness, submucosaRelThickness, circularRelThickness, longRelThickness] - ostiumSettings['Ostium wall relative thicknesses'] = relThicknesses - ostiumSettings['Vessel wall relative thicknesses'] = relThicknesses @classmethod def generateBaseMesh(cls, region, options): @@ -397,7 +360,6 @@ def generateBaseMesh(cls, region, options): nextNodeIdentifier = 1 nextElementIdentifier = 1 - cls.updateSubScaffoldOptions(options) geometricCentralPath = options['Network layout'] cecumTermsAlong = ['caecum', 'ileum part of cecum'] geometricCentralPath = CecumCentralPath(region, geometricCentralPath, cecumTermsAlong) @@ -700,8 +662,8 @@ def createCecumMesh3d(region, options, centralPath, nodeIdentifier, elementIdent elementsCountAlong = int(elementsCountAlongSegment * segmentCount) elementsCountAround = (elementsCountAroundTC + elementsCountAroundHaustrum) * tcCount - ostiumOptions = options['Ileocecal junction'] - ostiumSettings = ostiumOptions.getScaffoldSettings() + ostiumOptions = getDefaultOstiumSettings() + ostiumSettings = updateOstiumOptions(options, ostiumOptions) zero = [0.0, 0.0, 0.0] firstNodeIdentifier = nodeIdentifier diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py index 20ecc908..131451b9 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py @@ -23,7 +23,7 @@ from scaffoldmaker.annotation.smallintestine_terms import get_smallintestine_term from scaffoldmaker.annotation.stomach_terms import get_stomach_term from scaffoldmaker.meshtypes.meshtype_1d_network_layout1 import MeshType_1d_network_layout1 -from scaffoldmaker.meshtypes.meshtype_3d_ostium2 import MeshType_3d_ostium2, generateOstiumMesh +from scaffoldmaker.meshtypes.meshtype_3d_ostium2 import generateOstiumMesh from scaffoldmaker.meshtypes.scaffold_base import Scaffold_base from scaffoldmaker.scaffoldpackage import ScaffoldPackage from scaffoldmaker.utils import interpolation as interp @@ -490,139 +490,64 @@ def getDefaultNetworkLayoutScaffoldPackage(cls, parameterSetName): 'name': get_stomach_term('duodenum part of stomach')[0], 'ontId': get_stomach_term('duodenum part of stomach')[1] }] - }) - - -class MeshType_3d_stomach1(Scaffold_base): + }) + +def getDefaultOstiumSettings(): """ - Generates a 3-D stomach mesh with variable numbers of elements around the esophagus and duodenum, - along the central line, and through wall. The stomach is created using a central path as the longitudinal axis - of the stomach. D2 of the central path points to the greater curvature of the stomach and magnitude of D2 and D3 - are the radii of the stomach in the respective direction. + Generate list of default options for ostium. """ - - ostiumDefaultScaffoldPackages = { - 'Human 1': ScaffoldPackage(MeshType_3d_ostium2, { - 'scaffoldSettings': { - 'Number of elements around ostium': 8, + options = { 'Number of elements around ostium': 8, 'Number of elements along': 3, 'Number of elements through wall': 4, - 'Unit scale': 0.0105, - 'Outlet': False, - 'Ostium wall thickness': 5.0, - 'Ostium wall relative thicknesses': [0.55, 0.15, 0.25, 0.05], - 'Use linear through ostium wall': True, - 'Vessel wall thickness': 3.0, - 'Vessel wall relative thicknesses': [0.55, 0.15, 0.25, 0.05], - 'Use linear through vessel wall': True, - 'Use cross derivatives': False, - 'Refine': False, - 'Refine number of elements around': 4, - 'Refine number of elements along': 4, - 'Refine number of elements through wall': 1 - }, - }), - 'Human 2': ScaffoldPackage(MeshType_3d_ostium2, { - 'scaffoldSettings': { - 'Number of elements around ostium': 8, - 'Number of elements along': 3, - 'Number of elements through wall': 1, - 'Unit scale': 0.0105 * 101, + 'Unit scale': 1.0, 'Outlet': False, - 'Ostium wall thickness': 5.0, + 'Ostium wall thickness': 0.0525, 'Ostium wall relative thicknesses': [0.55, 0.15, 0.25, 0.05], 'Use linear through ostium wall': True, - 'Vessel wall thickness': 3.0, + 'Vessel wall thickness': 0.0315, 'Vessel wall relative thicknesses': [0.55, 0.15, 0.25, 0.05], 'Use linear through vessel wall': True, 'Use cross derivatives': False, 'Refine': False, 'Refine number of elements around': 4, 'Refine number of elements along': 4, - 'Refine number of elements through wall': 1 - }, - }), - 'Mouse 1': ScaffoldPackage(MeshType_3d_ostium2, { - 'scaffoldSettings': { - 'Number of elements around ostium': 8, - 'Number of elements along': 3, - 'Number of elements through wall': 4, - 'Unit scale': 0.147, - 'Outlet': False, - 'Ostium wall thickness': 0.35, - 'Ostium wall relative thicknesses': [0.75, 0.05, 0.15, 0.05], - 'Use linear through ostium wall': True, - 'Vessel wall thickness': 0.2, - 'Vessel wall relative thicknesses': [0.75, 0.05, 0.15, 0.05], - 'Use linear through vessel wall': True, - 'Use cross derivatives': False, - 'Refine': False, - 'Refine number of elements around': 4, - 'Refine number of elements along': 4, - 'Refine number of elements through wall': 1 - }, - }), - 'Pig 1': ScaffoldPackage(MeshType_3d_ostium2, { - 'scaffoldSettings': { - 'Number of elements around ostium': 8, - 'Number of elements along': 3, - 'Number of elements through wall': 4, - 'Unit scale': 0.0118, - 'Outlet': False, - 'Ostium wall thickness': 5.0, - 'Ostium wall relative thicknesses': [0.47, 0.1, 0.33, 0.1], - 'Use linear through ostium wall': True, - 'Vessel wall thickness': 3.0, - 'Vessel wall relative thicknesses': [0.47, 0.1, 0.33, 0.1], - 'Use linear through vessel wall': True, - 'Use cross derivatives': False, - 'Refine': False, - 'Refine number of elements around': 4, - 'Refine number of elements along': 4, - 'Refine number of elements through wall': 1 - }, - }), - 'Rat 1': ScaffoldPackage(MeshType_3d_ostium2, { - 'scaffoldSettings': { - 'Number of elements around ostium': 8, - 'Number of elements along': 3, - 'Number of elements through wall': 4, - 'Unit scale': 0.043, - 'Outlet': False, - 'Ostium wall thickness': 0.5, - 'Ostium wall relative thicknesses': [0.65, 0.12, 0.18, 0.05], - 'Use linear through ostium wall': True, - 'Vessel wall thickness': 0.3, - 'Vessel wall relative thicknesses': [0.65, 0.12, 0.18, 0.05], - 'Use linear through vessel wall': True, - 'Use cross derivatives': False, - 'Refine': False, - 'Refine number of elements around': 4, - 'Refine number of elements along': 4, - 'Refine number of elements through wall': 1 - }, - }), - 'Material': ScaffoldPackage(MeshType_3d_ostium2, { - 'scaffoldSettings': { - 'Number of elements around ostium': 8, - 'Number of elements along': 3, - 'Number of elements through wall': 4, - 'Unit scale': 1.0, - 'Outlet': False, - 'Ostium wall thickness': 0.05, - 'Ostium wall relative thicknesses': [0.25, 0.25, 0.25, 0.25], - 'Use linear through ostium wall': True, - 'Vessel wall thickness': 0.03, - 'Vessel wall relative thicknesses': [0.25, 0.25, 0.25, 0.25], - 'Use linear through vessel wall': True, - 'Use cross derivatives': False, - 'Refine': False, - 'Refine number of elements around': 4, - 'Refine number of elements along': 4, - 'Refine number of elements through wall': 1 - }, - }), - } + 'Refine number of elements through wall': 1} + + return options + +def updateOstiumOptions(options, ostiumOptions): + """ + Update ostium sub-scaffold options which depend on parent options. + """ + ostiumOptions['Number of elements around ostium'] = options['Number of elements around esophagus'] + ostiumOptions['Ostium wall thickness'] = options['Wall thickness'] + ostiumOptions['Vessel wall thickness'] = options['Esophagus wall thickness'] + elementsCountThroughWall = options['Number of elements through wall'] + ostiumOptions['Number of elements through wall'] = elementsCountThroughWall + ostiumOptions['Use linear through ostium wall'] = options['Use linear through wall'] + ostiumOptions['Use linear through vessel wall'] = options['Use linear through wall'] + if elementsCountThroughWall == 1: + ostiumOptions['Ostium wall relative thicknesses'] = [1.0] + ostiumOptions['Vessel wall relative thicknesses'] = [1.0] + else: + mucosaRelThickness = options['Mucosa relative thickness'] + submucosaRelThickness = options['Submucosa relative thickness'] + circularRelThickness = options['Circular muscle layer relative thickness'] + longRelThickness = options['Longitudinal muscle layer relative thickness'] + relThicknesses = [mucosaRelThickness, submucosaRelThickness, circularRelThickness, longRelThickness] + ostiumOptions['Ostium wall relative thicknesses'] = relThicknesses + ostiumOptions['Vessel wall relative thicknesses'] = relThicknesses + + return ostiumOptions + + +class MeshType_3d_stomach1(Scaffold_base): + """ + Generates a 3-D stomach mesh with variable numbers of elements around the esophagus and duodenum, + along the central line, and through wall. The stomach is created using a central path as the longitudinal axis + of the stomach. D2 of the central path points to the greater curvature of the stomach and magnitude of D2 and D3 + are the radii of the stomach in the respective direction. + """ @staticmethod def getName(): @@ -641,19 +566,6 @@ def getParameterSetNames(): @classmethod def getDefaultOptions(cls, parameterSetName='Default'): - if 'Human 2' in parameterSetName: - ostiumOption = cls.ostiumDefaultScaffoldPackages['Human 2'] - elif 'Mouse 1' in parameterSetName: - ostiumOption = cls.ostiumDefaultScaffoldPackages['Mouse 1'] - elif 'Pig 1' in parameterSetName: - ostiumOption = cls.ostiumDefaultScaffoldPackages['Pig 1'] - elif 'Rat 1' in parameterSetName: - ostiumOption = cls.ostiumDefaultScaffoldPackages['Rat 1'] - elif 'Material' in parameterSetName: - ostiumOption = cls.ostiumDefaultScaffoldPackages['Material'] - else: - ostiumOption = cls.ostiumDefaultScaffoldPackages['Human 1'] - options = { 'Network layout': getDefaultNetworkLayoutScaffoldPackage(cls, parameterSetName), 'Number of elements around esophagus': 8, @@ -661,12 +573,12 @@ def getDefaultOptions(cls, parameterSetName='Default'): 'Number of elements along': 14, 'Number of elements through wall': 4, 'Wall thickness': 0.0525, + 'Esophagus wall thickness': 0.0315, 'Mucosa relative thickness': 0.55, 'Submucosa relative thickness': 0.15, 'Circular muscle layer relative thickness': 0.25, 'Longitudinal muscle layer relative thickness': 0.05, 'Limiting ridge': False, - 'Gastro-esophageal junction': copy.deepcopy(ostiumOption), 'Use linear through wall': True, 'Refine': False, 'Refine number of elements surface': 4, @@ -677,8 +589,10 @@ def getDefaultOptions(cls, parameterSetName='Default'): options['Number of elements around duodenum'] = 12 options['Number of elements through wall'] = 1 options['Wall thickness'] = 3.0 + options['Esophagus wall thickness'] = 3.0 elif 'Mouse 1' in parameterSetName: options['Wall thickness'] = 0.05145 + options['Esophagus wall thickness'] = 0.01029 options['Mucosa relative thickness'] = 0.75 options['Submucosa relative thickness'] = 0.05 options['Circular muscle layer relative thickness'] = 0.15 @@ -686,6 +600,7 @@ def getDefaultOptions(cls, parameterSetName='Default'): options['Limiting ridge'] = True elif 'Pig 1' in parameterSetName: options['Wall thickness'] = 0.059 + options['Esophagus wall thickness'] = 0.0354 options['Mucosa relative thickness'] = 0.47 options['Submucosa relative thickness'] = 0.1 options['Circular muscle layer relative thickness'] = 0.33 @@ -693,6 +608,7 @@ def getDefaultOptions(cls, parameterSetName='Default'): options['Limiting ridge'] = False elif 'Rat 1' in parameterSetName: options['Wall thickness'] = 0.0215 + options['Esophagus wall thickness'] = 0.0129 options['Mucosa relative thickness'] = 0.65 options['Submucosa relative thickness'] = 0.12 options['Circular muscle layer relative thickness'] = 0.18 @@ -700,12 +616,12 @@ def getDefaultOptions(cls, parameterSetName='Default'): options['Limiting ridge'] = True elif 'Material' in parameterSetName: options['Wall thickness'] = 0.05 + options['Esophagus wall thickness'] = 0.03 options['Mucosa relative thickness'] = 0.25 options['Submucosa relative thickness'] = 0.25 options['Circular muscle layer relative thickness'] = 0.25 options['Longitudinal muscle layer relative thickness'] = 0.25 options['Limiting ridge'] = False - cls.updateSubScaffoldOptions(options) return options @@ -718,12 +634,12 @@ def getOrderedOptionNames(): 'Number of elements along', 'Number of elements through wall', 'Wall thickness', + 'Esophagus wall thickness', 'Mucosa relative thickness', 'Submucosa relative thickness', 'Circular muscle layer relative thickness', 'Longitudinal muscle layer relative thickness', 'Limiting ridge', - 'Gastro-esophageal junction', 'Use linear through wall', 'Refine', 'Refine number of elements surface', @@ -734,16 +650,12 @@ def getOrderedOptionNames(): def getOptionValidScaffoldTypes(cls, optionName): if optionName == 'Network layout': return [MeshType_1d_network_layout1] - if optionName == 'Gastro-esophageal junction': - return [MeshType_3d_ostium2] return [] @classmethod def getOptionScaffoldTypeParameterSetNames(cls, optionName, scaffoldType): if optionName == 'Network layout': return cls.getParameterSetNames() - if optionName == 'Gastro-esophageal junction': - return list(cls.ostiumDefaultScaffoldPackages.keys()) assert scaffoldType in cls.getOptionValidScaffoldTypes(optionName), \ cls.__name__ + '.getOptionScaffoldTypeParameterSetNames. ' + \ 'Invalid option \'' + optionName + '\' scaffold type ' + scaffoldType.getName() @@ -763,20 +675,12 @@ def getOptionScaffoldPackage(cls, optionName, scaffoldType, parameterSetName=Non if not parameterSetName: parameterSetName = "Default" return getDefaultNetworkLayoutScaffoldPackage(cls, parameterSetName) - if optionName == 'Gastro-esophageal junction': - if not parameterSetName: - parameterSetName = list(cls.ostiumDefaultScaffoldPackages.keys())[0] - return copy.deepcopy(cls.ostiumDefaultScaffoldPackages[parameterSetName]) assert False, cls.__name__ + '.getOptionScaffoldPackage: Option ' + optionName + ' is not a scaffold' @classmethod def checkOptions(cls, options): if not options['Network layout'].getScaffoldType() in cls.getOptionValidScaffoldTypes('Network layout'): options['Network layout'] = cls.getOptionScaffoldPackage('Network layout', MeshType_1d_network_layout1) - if not options['Gastro-esophageal junction'].getScaffoldType() in cls.getOptionValidScaffoldTypes( - 'Gastro-esophageal junction'): - options['Gastro-esophageal junction'] = cls.getOptionScaffoldPackage('Gastro-esophageal junction', - MeshType_3d_ostium2) if options['Number of elements around esophagus'] < 8: options['Number of elements around esophagus'] = 8 if options['Number of elements around duodenum'] < 12: @@ -796,34 +700,6 @@ def checkOptions(cls, options): if options[key] < 1: options[key] = 1 - cls.updateSubScaffoldOptions(options) - - @classmethod - def updateSubScaffoldOptions(cls, options): - """ - Update ostium sub-scaffold options which depend on parent options. - """ - ostiumOptions = options['Gastro-esophageal junction'] - ostiumSettings = ostiumOptions.getScaffoldSettings() - ostiumSettings['Number of elements around ostium'] = options['Number of elements around esophagus'] - wallThickness = options['Wall thickness'] / ostiumSettings['Unit scale'] - ostiumSettings['Ostium wall thickness'] = wallThickness - elementsCountThroughWall = options['Number of elements through wall'] - ostiumSettings['Number of elements through wall'] = elementsCountThroughWall - ostiumSettings['Use linear through ostium wall'] = options['Use linear through wall'] - ostiumSettings['Use linear through vessel wall'] = options['Use linear through wall'] - if elementsCountThroughWall == 1: - ostiumSettings['Ostium wall relative thicknesses'] = [1.0] - ostiumSettings['Vessel wall relative thicknesses'] = [1.0] - else: - mucosaRelThickness = options['Mucosa relative thickness'] - submucosaRelThickness = options['Submucosa relative thickness'] - circularRelThickness = options['Circular muscle layer relative thickness'] - longRelThickness = options['Longitudinal muscle layer relative thickness'] - relThicknesses = [mucosaRelThickness, submucosaRelThickness, circularRelThickness, longRelThickness] - ostiumSettings['Ostium wall relative thicknesses'] = relThicknesses - ostiumSettings['Vessel wall relative thicknesses'] = relThicknesses - @classmethod def generateBaseMesh(cls, region, options): """ @@ -832,7 +708,7 @@ def generateBaseMesh(cls, region, options): :param options: Dict containing options. See getDefaultOptions(). :return: list of AnnotationGroup, None """ - cls.updateSubScaffoldOptions(options) + geometricCentralPath = options['Network layout'] materialCentralPath = getDefaultNetworkLayoutScaffoldPackage(cls, 'Material') limitingRidge = options['Limiting ridge'] @@ -1400,8 +1276,9 @@ def findCurvatureAlongLine(nx, nd, radialVectors): def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotationGroups, centralPath, options, - nodeIdentifier, elementIdentifier, elementsAlongSections = [], materialCoordinates=False, - nodeIdProximalEso=[], xProximalEso=[], d1ProximalEso=[], d2ProximalEso=[], d3ProximalEso=[]): + nodeIdentifier, elementIdentifier, elementsAlongSections = [], + materialCoordinates=False, nodeIdProximalEso=[], xProximalEso=[], d1ProximalEso=[], + d2ProximalEso=[], d3ProximalEso=[]): """ Generates a stomach scaffold in the region using a central path and parameter options. :param region: Region to create elements in. @@ -1431,8 +1308,8 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio useCrossDerivatives = False useCubicHermiteThroughWall = not (options['Use linear through wall']) - GEJOptions = options['Gastro-esophageal junction'] - GEJSettings = GEJOptions.getScaffoldSettings() + ostiumOptions = getDefaultOstiumSettings() + GEJSettings = updateOstiumOptions(options, ostiumOptions) elementsAlongEsophagus = GEJSettings['Number of elements along'] elementsThroughEsophagusWall = GEJSettings['Number of elements through wall'] ostiumRadius = vector.magnitude(centralPath.cd2Groups[-1][1]) From 68ffa5b28ff336533c2131ecd9c0580e078da7b8 Mon Sep 17 00:00:00 2001 From: mlin865 Date: Thu, 14 Mar 2024 13:00:04 +1300 Subject: [PATCH 21/24] Update tests --- tests/test_cecum.py | 6 +----- tests/test_colon.py | 5 ++--- tests/test_gastrointestinaltract1.py | 2 +- tests/test_smallintestine.py | 4 ++-- tests/test_stomach.py | 9 --------- 5 files changed, 6 insertions(+), 20 deletions(-) diff --git a/tests/test_cecum.py b/tests/test_cecum.py index d97e41ee..701998a6 100644 --- a/tests/test_cecum.py +++ b/tests/test_cecum.py @@ -25,7 +25,7 @@ def test_cecum1(self): self.assertEqual(parameterSetNames, ["Default", "Human 1", "Human 2", "Pig 1"]) options = MeshType_3d_cecum1.getDefaultOptions("Human 2") - centralPath = options.get("Central path") + centralPath = options.get("Network layout") centralPathSettings = centralPath.getScaffoldSettings() self.assertEqual("1-2-3.2, 4-3-5", centralPathSettings["Structure"]) @@ -41,10 +41,6 @@ def test_cecum1(self): self.assertEqual(10.0, options.get("Start tenia coli width")) self.assertEqual(0.0, options.get("End tenia coli width derivative")) self.assertEqual(1.6, options.get("Wall thickness")) - ostiumOptions = options['Ileocecal junction'] - ostiumSettings = ostiumOptions.getScaffoldSettings() - self.assertEqual(8, ostiumSettings.get("Number of elements around ostium")) - self.assertEqual(1, ostiumSettings.get("Number of elements through wall")) context = Context("Test") region = context.getDefaultRegion() diff --git a/tests/test_colon.py b/tests/test_colon.py index ef51bad8..4cc4d486 100644 --- a/tests/test_colon.py +++ b/tests/test_colon.py @@ -76,7 +76,7 @@ def test_colon1(self): segmentProfileOption = ScaffoldPackage(MeshType_3d_colonsegment1, defaultParameterSetName='Human 1') options = { 'Base parameter set': 'Human 1', - 'Central path': copy.deepcopy(centralPathOption), + 'Network layout': copy.deepcopy(centralPathOption), 'Segment profile': segmentProfileOption, 'Number of segments': 3, 'Start phase': 0.0, @@ -91,7 +91,7 @@ def test_colon1(self): 'Refine number of elements through wall': 1 } self.assertEqual(14, len(options)) - centralPath = options['Central path'] + centralPath = options['Network layout'] segmentProfile = options.get("Segment profile") segmentSettings = segmentProfile.getScaffoldSettings() self.assertEqual(8, segmentSettings.get("Number of elements around haustrum")) @@ -151,7 +151,6 @@ def test_colon1(self): flatCoordinates = fieldmodule.findFieldByName("flat coordinates").castFiniteElement() self.assertTrue(flatCoordinates.isValid()) minimums, maximums = evaluateFieldNodesetRange(flatCoordinates, nodes) - print(minimums, maximums) assertAlmostEqualList(self, minimums, [0.0, 0.0, 0.0], 1.0E-6) assertAlmostEqualList(self, maximums, [377.06179507784395, 561.3383898388232, 2.2], 1.0E-6) diff --git a/tests/test_gastrointestinaltract1.py b/tests/test_gastrointestinaltract1.py index b65d3fb2..3625ec53 100644 --- a/tests/test_gastrointestinaltract1.py +++ b/tests/test_gastrointestinaltract1.py @@ -29,7 +29,7 @@ def test_gastrointestinaltract1(self): self.assertEqual(parameterSetNames, ['Default', 'Human 1']) options = scaffold.getDefaultOptions("Default") self.assertEqual(10, len(options)) - centralPathOptions = options['Central path'] + centralPathOptions = options['Network layout'] centralPathSettings = centralPathOptions.getScaffoldSettings() self.assertEqual("1-2-3-4-5-6-7.2, 8-9-10-11-7-12-13-14-15-16-17-18-19-20-21-22-23-24-25-26-27-28-29-30-31-32-" "33-34-35-36-37-38-39-40-41-42-43-44-45-46-47-48-49-50-51-52-53-54-55-56-57-58-59-60-61-62-63-" diff --git a/tests/test_smallintestine.py b/tests/test_smallintestine.py index e2fd47e9..c3733945 100644 --- a/tests/test_smallintestine.py +++ b/tests/test_smallintestine.py @@ -70,10 +70,10 @@ def test_smallintestine1(self): } centralPathOption = parameterSetStructureStrings['Test line'] options = MeshType_3d_smallintestine1.getDefaultOptions("Mouse 1") - options['Central path'] = copy.deepcopy(centralPathOption) + options['Network layout'] = copy.deepcopy(centralPathOption) options['Number of segments'] = 3 self.assertEqual(16, len(options)) - centralPath = options['Central path'] + centralPath = options['Network layout'] self.assertEqual(3, options.get("Number of segments")) self.assertEqual(8, options.get("Number of elements around")) self.assertEqual(3, options.get("Number of elements along segment")) diff --git a/tests/test_stomach.py b/tests/test_stomach.py index d2f076ae..de11e342 100644 --- a/tests/test_stomach.py +++ b/tests/test_stomach.py @@ -33,15 +33,6 @@ def test_stomach1(self): self.assertEqual(14, options.get("Number of elements along")) self.assertEqual(0.0215, options.get("Wall thickness")) self.assertEqual(True, options.get("Limiting ridge")) - ostiumOptions = options['Gastro-esophageal junction'] - ostiumSettings = ostiumOptions.getScaffoldSettings() - self.assertEqual(8, ostiumSettings.get("Number of elements around ostium")) - self.assertEqual(4, ostiumSettings.get("Number of elements through wall")) - self.assertEqual(None, ostiumSettings.get("Ostium diameter")) - self.assertEqual(0.5, ostiumSettings.get("Ostium wall thickness")) - self.assertEqual([0.65, 0.12, 0.18, 0.05], ostiumSettings.get("Ostium wall relative thicknesses")) - self.assertEqual(0.3, ostiumSettings.get("Vessel wall thickness")) - self.assertEqual([0.65, 0.12, 0.18, 0.05], ostiumSettings.get("Vessel wall relative thicknesses")) context = Context("Test") region = context.getDefaultRegion() From 8708c3920f99c4ddb1bd55fd09b95ee10a033960 Mon Sep 17 00:00:00 2001 From: mlin865 Date: Thu, 14 Mar 2024 17:35:49 +1300 Subject: [PATCH 22/24] Force sub-scaffolds to use 1 element through wall --- .../meshtype_3d_gastrointestinaltract1.py | 29 +++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_gastrointestinaltract1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_gastrointestinaltract1.py index bf8bec26..cffdd405 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_gastrointestinaltract1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_gastrointestinaltract1.py @@ -540,7 +540,7 @@ def checkOptions(cls, options): if not options['Network layout'].getScaffoldType() in cls.getOptionValidScaffoldTypes('Network layout'): options['Network layout'] = cls.getOptionScaffoldPackage('Network layout', MeshType_1d_network_layout1) if not options['Esophagus'].getScaffoldType() in cls.getOptionValidScaffoldTypes('Esophagus'): - options['Esophagus'] = cls.getOptionScaffoldPackage('Esophagus', MeshType_3d_stomach1) + options['Esophagus'] = cls.getOptionScaffoldPackage('Esophagus', MeshType_3d_esophagus1) if not options['Stomach'].getScaffoldType() in cls.getOptionValidScaffoldTypes('Stomach'): options['Stomach'] = cls.getOptionScaffoldPackage('Stomach', MeshType_3d_stomach1) if not options['Small intestine'].getScaffoldType() in cls.getOptionValidScaffoldTypes('Small intestine'): @@ -554,8 +554,32 @@ def checkOptions(cls, options): 'Refine number of elements through wall']: if options[key] < 1: options[key] = 1 + cls.updateSubScaffoldOptions(options) + + + @classmethod + def updateSubScaffoldOptions(cls, options): + ''' + Update sub-scaffold options which depend on parent options. + ''' + esoOptions = options['Esophagus'] + esoSettings = esoOptions.getScaffoldSettings() + esoSettings['Number of elements through wall'] = 1 + stomachOptions = options['Stomach'] + stomachSettings = stomachOptions.getScaffoldSettings() + stomachSettings['Number of elements through wall'] = 1 + smallIntestineOptions = options['Small intestine'] + smallIntestineSettings = smallIntestineOptions.getScaffoldSettings() + smallIntestineSettings['Number of elements through wall'] = 1 + cecumOptions = options['Cecum'] + cecumSettings = cecumOptions.getScaffoldSettings() + cecumSettings['Number of elements through wall'] = 1 + colonOptions = options['Colon'] + colonSettings = colonOptions.getScaffoldSettings() + colonSegmentOptions = colonSettings['Segment profile'] + colonSegmentSettings = colonSegmentOptions.getScaffoldSettings() + colonSegmentSettings['Number of elements through wall'] = 1 - # cls.updateSubScaffoldOptions(options) @classmethod def generateBaseMesh(cls, region, options): @@ -565,6 +589,7 @@ def generateBaseMesh(cls, region, options): :param options: Dict containing options. See getDefaultOptions(). :return: annotationGroups """ + cls.updateSubScaffoldOptions(options) centralPath = options['Network layout'] esophagusOptions = options['Esophagus'] stomachOptions = options['Stomach'] From c9ff5e46e08902f0a1775f0b04f969e2fa13a0db Mon Sep 17 00:00:00 2001 From: mlin865 Date: Fri, 15 Mar 2024 11:17:46 +1300 Subject: [PATCH 23/24] Replace variable central path with network layout --- .../meshtypes/meshtype_3d_cecum1.py | 76 ++++++++-------- .../meshtypes/meshtype_3d_colon1.py | 50 +++++----- .../meshtypes/meshtype_3d_colonsegment1.py | 8 +- .../meshtypes/meshtype_3d_esophagus1.py | 52 +++++------ .../meshtype_3d_gastrointestinaltract1.py | 49 +++++----- .../meshtypes/meshtype_3d_smallintestine1.py | 46 +++++----- .../meshtypes/meshtype_3d_stomach1.py | 78 ++++++++-------- tests/test_cecum.py | 6 +- tests/test_colon.py | 91 +++++++++---------- tests/test_gastrointestinaltract1.py | 6 +- tests/test_smallintestine.py | 12 +-- 11 files changed, 236 insertions(+), 238 deletions(-) diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_cecum1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_cecum1.py index f7af9406..09d961be 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_cecum1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_cecum1.py @@ -360,11 +360,11 @@ def generateBaseMesh(cls, region, options): nextNodeIdentifier = 1 nextElementIdentifier = 1 - geometricCentralPath = options['Network layout'] + geometricNetworkLayout = options['Network layout'] cecumTermsAlong = ['caecum', 'ileum part of cecum'] - geometricCentralPath = CecumCentralPath(region, geometricCentralPath, cecumTermsAlong) + geometricNetworkLayout = CecumNetworkLayout(region, geometricNetworkLayout, cecumTermsAlong) annotationGroups, nextNodeIdentifier, nextElementIdentifier = \ - createCecumMesh3d(region, options, geometricCentralPath, nextNodeIdentifier, + createCecumMesh3d(region, options, geometricNetworkLayout, nextNodeIdentifier, nextElementIdentifier)[0:3] return annotationGroups, None @@ -619,13 +619,13 @@ def findDerivativeBetweenPoints(v1, v2): return d -def createCecumMesh3d(region, options, centralPath, nodeIdentifier, elementIdentifier, nodeIdProximalIleum=[], +def createCecumMesh3d(region, options, networkLayout, nodeIdentifier, elementIdentifier, nodeIdProximalIleum=[], xProximalIleum=[], d1ProximalIleum=[], d2ProximalIleum=[], d3ProximalIleum=[]): """ Generates a cecum scaffold in the region using a network layout and parameter options. :param region: Region to create elements in. :param options: Parameter options for scaffold. - :param centralPath: Central path through the axis of the cecum scaffold. + :param networkLayout: Network layout through the axis of the cecum scaffold. :param nodeIdentifier: First node identifier. :param elementIdentifier: First element identifier. :param nodeIdProximalIleum: Node identifiers of nodes around starting nodes for ileum. @@ -704,22 +704,22 @@ def createCecumMesh3d(region, options, centralPath, nodeIdentifier, elementIdent annotationGroupsThroughWall = [[mucosaGroup], [submucosaGroup], [circularMuscleGroup], [longitudinalMuscleGroup]] - # Sample central path along cecum - # print(len(centralPath.cxGroups)) - cecumLength = centralPath.arcLengthOfGroupsAlong[0] - cx = centralPath.cxGroups[0] - cd1 = centralPath.cd1Groups[0] - cd2 = centralPath.cd2Groups[0] - cd12 = centralPath.cd12Groups[0] + # Sample network layout along cecum + # print(len(networkLayout.cxGroups)) + cecumLength = networkLayout.arcLengthOfGroupsAlong[0] + cx = networkLayout.cxGroups[0] + cd1 = networkLayout.cd1Groups[0] + cd2 = networkLayout.cd2Groups[0] + cd12 = networkLayout.cd12Groups[0] - cxIleum = centralPath.cxGroups[1] - cd1Ileum = centralPath.cd1Groups[1] - cd2Ileum = centralPath.cd2Groups[1] - cd3Ileum = centralPath.cd3Groups[1] - cd12Ileum = centralPath.cd12Groups[1] + cxIleum = networkLayout.cxGroups[1] + cd1Ileum = networkLayout.cd1Groups[1] + cd2Ileum = networkLayout.cd2Groups[1] + cd3Ileum = networkLayout.cd3Groups[1] + cd12Ileum = networkLayout.cd12Groups[1] - d2BranchPt = centralPath.d2BranchPt - d3BranchPt = centralPath.d3BranchPt + d2BranchPt = networkLayout.d2BranchPt + d3BranchPt = networkLayout.d3BranchPt sxCecum, sd1Cecum, se, sxi, ssf = interp.sampleCubicHermiteCurves(cx, cd1, elementsCountAlong) sd2Cecum, sd12Cecum = interp.interpolateSampleCubicHermite(cd2, cd12, se, sxi, ssf) @@ -811,7 +811,7 @@ def createCecumMesh3d(region, options, centralPath, nodeIdentifier, elementIdent for n in range(len(xToWarp)): xToWarp[n][2] = xToWarp[n][2] - minZ - # Project reference point for warping onto central path + # Project reference point for warping onto network layout sxRefList, sd1RefList, sd2ProjectedListRef, zRefList = \ tubemesh.getPlaneProjectionOnCentralPath(xToWarp, elementsCountAround, elementsCountAlong, cecumLength, sxCecum, sd1Cecum, sd2Cecum, sd12Cecum) @@ -923,9 +923,9 @@ def createCecumMesh3d(region, options, centralPath, nodeIdentifier, elementIdent # element.setNodesByIdentifier(eft, [nodeIdentifierCecum + e, nodeIdentifierCecum + 1 + e]) # elementIdentifier = elementIdentifier + 1 # - # cx = centralPath.cxGroups[1] - # cd1 = centralPath.cd1Groups[1] - # cd2 = centralPath.cd2Groups[1] + # cx = networkLayout.cxGroups[1] + # cd1 = networkLayout.cd1Groups[1] + # cd2 = networkLayout.cd2Groups[1] # # nodeIdentifierIleum = nextNodeIdentifier # for n2 in range(len(cx)): @@ -961,7 +961,7 @@ def createCecumMesh3d(region, options, centralPath, nodeIdentifier, elementIdent startIdxElementsAround = int((elementsCountAroundHaustrum + elementsCountAroundTC) * sectorIdx + elementsCountAroundTC * 0.5) - segmentIdx = int(centralPath.arcLengthToBranchPt // segmentLength) + segmentIdx = int(networkLayout.arcLengthToBranchPt // segmentLength) baseNodesIdx = (elementsCountThroughWall + 1) + \ + (elementsCountAround * (elementsCountThroughWall + 1) + @@ -1061,7 +1061,7 @@ def createCecumMesh3d(region, options, centralPath, nodeIdentifier, elementIdent xTol = 1.0E-6 arcStart = 0.0 - arcEnd = centralPath.arcLengthOfGroupsAlong[1] + arcEnd = networkLayout.arcLengthOfGroupsAlong[1] nearestPosition = trackSurfaceOstium.findNearestPosition(cxIleum[0]) xNearestStart = trackSurfaceOstium.evaluateCoordinates(nearestPosition, derivatives=False) distStart = vector.magnitude([cxIleum[0][c] - xNearestStart[c] for c in range(3)]) @@ -1138,10 +1138,10 @@ def createCecumMesh3d(region, options, centralPath, nodeIdentifier, elementIdent d12Path = [cd2Ileum[0], [0.0, 0.0, 0.0]] d13Path = [cd3Ileum[0], [0.0, 0.0, 0.0]] - centralPathIleum = CustomCentralPath(xPath, d1Path, d2Path, d3Path, d12Path, d13Path) + networkLayoutIleum = CustomNetworkLayout(xPath, d1Path, d2Path, d3Path, d12Path, d13Path) nextNodeIdentifier, nextElementIdentifier, (o1_x, o1_d1, o1_d2, o1_d3, o1_NodeId, o1_Positions) = \ - generateOstiumMesh(region, ostiumSettings, trackSurfaceOstium, centralPathIleum, + generateOstiumMesh(region, ostiumSettings, trackSurfaceOstium, networkLayoutIleum, startNodeIdentifier=nextNodeIdentifier, startElementIdentifier=nextElementIdentifier, nodeIdProximal=nodeIdProximalIleum, xProximal=xProximalIleum, d1Proximal=d1ProximalIleum, d2Proximal=d2ProximalIleum, d3Proximal=d3ProximalIleum, @@ -1161,7 +1161,7 @@ def createCecumMesh3d(region, options, centralPath, nodeIdentifier, elementIdent e1Right = 0 e2Top = 0 e2Bottom = elementsAlongTrackSurface - sf = vector.magnitude(centralPathIleum.cd2Path[-1]) * 0.35 + sf = vector.magnitude(networkLayoutIleum.cd2Path[-1]) * 0.35 for n1 in range(elementsCountAroundOstium): normD2 = vector.normalise(o1_d2[-1][n1]) d1AnnulusNorm.append(normD2) @@ -2130,20 +2130,20 @@ def createCecumMesh3d(region, options, centralPath, nodeIdentifier, elementIdent d2Distal, d3Distal -class CecumCentralPath: +class CecumNetworkLayout: """ - Generates sampled central path for cecum scaffold. + Generates sampled network layout for cecum scaffold. """ - def __init__(self, region, centralPath, termsAlong=[None], ileumSegmentIdx=0, cecumSegmentIdx=[1,2]): + def __init__(self, region, networkLayout, termsAlong=[None], ileumSegmentIdx=0, cecumSegmentIdx=[1,2]): """ :param region: Zinc region to define model in. - :param centralPath: Central path subscaffold from meshtype_1d_path1 - :param termsAlong: Annotation terms along length of central path + :param networkLayout: Network layout subscaffold from meshtype_1d_networklayout1 + :param termsAlong: Annotation terms along length of network layout :param ileumSegmentIdx: Segment index of ileum branch. :param cecumSegmentIdx: Segment index of body of cecum. """ - # Extract length of each group along cecum from central path + # Extract length of each group along cecum from network layout arcLengthOfGroupsAlong = [] cxGroups = [] cd1Groups = [] @@ -2153,8 +2153,8 @@ def __init__(self, region, centralPath, termsAlong=[None], ileumSegmentIdx=0, ce cd13Groups = [] tmpRegion = region.createRegion() - centralPath.generate(tmpRegion) - pathNetworkMesh = centralPath.getConstructionObject() + networkLayout.generate(tmpRegion) + pathNetworkMesh = networkLayout.getConstructionObject() tmpFieldmodule = tmpRegion.getFieldmodule() tmpNodes = tmpFieldmodule.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES) tmpCoordinates = tmpFieldmodule.findFieldByName('coordinates') @@ -2257,9 +2257,9 @@ def __init__(self, region, centralPath, termsAlong=[None], ileumSegmentIdx=0, ce self.d3BranchPt = d3branchpt self.arcLengthToBranchPt = arcLengthToBranchPt -class CustomCentralPath: +class CustomNetworkLayout: """ - Generates sampled central path for part of central path. + Generates sampled network layout for part of network layout. """ def __init__(self, cx, cd1, cd2, cd3, cd12, cd13): self.cxPath = cx diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_colon1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_colon1.py index 358f2ee8..944116cb 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_colon1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_colon1.py @@ -211,7 +211,7 @@ def getDefaultNetworkLayoutScaffoldPackage(cls, parameterSetName): 'ontId': get_colon_term('descending colon')[1] }] }) - + elif 'Cattle 1' in parameterSetName: return ScaffoldPackage(MeshType_1d_network_layout1, { 'scaffoldSettings': { @@ -365,7 +365,7 @@ def getDefaultNetworkLayoutScaffoldPackage(cls, parameterSetName): (4, [[-14.00,-1.00,-10.00], [1.00,1.00,-17.00], [0.00,-1.25,0.00], [0.00,0.08,0.00], [-1.25,-0.00,-0.00], [0.00,0.00,0.50]]), (5, [[-14.00,0.00,-28.00], [0.00,0.00,-11.00], [0.00,-1.25,0.00], [0.00,-0.08,0.00], [-1.25,-0.00,0.00], [0.00,0.00,0.50]]) ] ), - + 'userAnnotationGroups': [ { '_AnnotationGroup': True, @@ -445,7 +445,7 @@ def getDefaultNetworkLayoutScaffoldPackage(cls, parameterSetName): (39, [[-47.60,33.90,-112.20], [32.60,30.70,-27.80], [-10.59,-0.41,-1.32], [-7.25,2.76,-6.03], [-4.75,2.85,9.12], [-8.97,3.42,-7.45]]), (40, [[19.60,96.00,-167.50], [19.90,19.10,-18.40], [-8.87,0.91,-5.71], [9.97,-0.68,-0.89], [-3.77,7.41,6.56], [12.30,-0.82,-1.11]]) ] ), - + 'userAnnotationGroups': [ { '_AnnotationGroup': True, @@ -476,7 +476,7 @@ def getDefaultNetworkLayoutScaffoldPackage(cls, parameterSetName): 'ontId': get_colon_term('descending colon')[1] }] }) - + class MeshType_3d_colon1(Scaffold_base): ''' @@ -644,7 +644,7 @@ def generateBaseMesh(cls, region, options): segmentSettings = segmentProfile.getScaffoldSettings() tcCount = segmentSettings['Number of tenia coli'] - geometricCentralPath = options['Network layout'] + geometricNetworkLayout = options['Network layout'] if tcCount == 1: colonTermsAlong = ['colon', 'right colon', 'transverse colon', 'left colon'] elif tcCount == 2: @@ -652,10 +652,10 @@ def generateBaseMesh(cls, region, options): elif tcCount == 3: colonTermsAlong = ['colon', 'ascending colon', 'transverse colon', 'descending colon'] - geometricCentralPath = ColonCentralPath(region, geometricCentralPath, colonTermsAlong) + geometricNetworkLayout = ColonNetworkLayout(region, geometricNetworkLayout, colonTermsAlong) annotationGroups, nextNodeIdentifier, nextElementIdentifier = \ - createColonMesh3d(region, options, geometricCentralPath, nextNodeIdentifier, + createColonMesh3d(region, options, geometricNetworkLayout, nextNodeIdentifier, nextElementIdentifier, flatCoordinates=True, materialCoordinates=True)[0:3] return annotationGroups, None @@ -702,14 +702,14 @@ def defineFaceAnnotations(cls, region, options, annotationGroups): get_colon_term("luminal surface of the colonic mucosa")) mucosaInnerSurface.getMeshGroup(mesh2d).addElementsConditional(is_mucosaInnerSurface) -def createColonMesh3d(region, options, centralPath, nextNodeIdentifier, nextElementIdentifier, +def createColonMesh3d(region, options, networkLayout, nextNodeIdentifier, nextElementIdentifier, flatCoordinates=False, materialCoordinates=False, nodeIdProximal=[], xProximal=[], d1Proximal=[], d2Proximal=[], d3Proximal=[]): """ - Generates a colon scaffold in the region using a central path and parameter options. + Generates a colon scaffold in the region using a network layout and parameter options. :param region: Region to create elements in. :param options: Parameter options for creating scaffold. - :param centralPath: Central path through the path of the colon. + :param networkLayout: Network layout through the path of the colon. :param nextNodeIdentifier: Next node identifier to use. :param nextElementIdentifier: Next element identifier to use. :param flatCoordinates: Generate flat coordinates if True. @@ -758,7 +758,7 @@ def createColonMesh3d(region, options, centralPath, nextNodeIdentifier, nextElem teniaColiThicknessToDiameterRatio = 0.25 * wallThicknessToDiameterRatio relativeThicknessListColonCoordinates = [1.0 / elementsCountThroughWall for n3 in range(elementsCountThroughWall)] - # Central path + # Network layout if tcCount == 1: colonTermsAlong = ['colon', 'right colon', 'transverse colon', 'left colon'] elif tcCount == 2: @@ -766,12 +766,12 @@ def createColonMesh3d(region, options, centralPath, nextNodeIdentifier, nextElem elif tcCount == 3: colonTermsAlong = ['colon', 'ascending colon', 'transverse colon', 'descending colon'] - centralPathLength = centralPath.arcLengthOfGroupsAlong[0] - cx = centralPath.cxGroups[0] - cd1 = centralPath.cd1Groups[0] - cd2 = centralPath.cd2Groups[0] - cd12 = centralPath.cd12Groups[0] - arcLengthOfGroupsAlong = centralPath.arcLengthOfGroupsAlong + networkLayoutLength = networkLayout.arcLengthOfGroupsAlong[0] + cx = networkLayout.cxGroups[0] + cd1 = networkLayout.cd1Groups[0] + cd2 = networkLayout.cd2Groups[0] + cd12 = networkLayout.cd12Groups[0] + arcLengthOfGroupsAlong = networkLayout.arcLengthOfGroupsAlong # find arclength of colon length = 0.0 @@ -784,11 +784,11 @@ def createColonMesh3d(region, options, centralPath, nextNodeIdentifier, nextElem length += arcLength segmentLength = length / segmentCount - # Sample central path + # Sample network layout sx, sd1, se, sxi, ssf = interp.sampleCubicHermiteCurves(cx, cd1, elementsCountAlong) sd2, sd12 = interp.interpolateSampleCubicHermite(cd2, cd12, se, sxi, ssf) - elementAlongLength = centralPathLength / elementsCountAlong + elementAlongLength = networkLayoutLength / elementsCountAlong elementsCountAlongGroups = [] groupLength = 0.0 @@ -910,7 +910,7 @@ def createColonMesh3d(region, options, centralPath, nextNodeIdentifier, nextElem xOuter, d1Outer, d2Outer, transitElementList, segmentAxis, annotationGroupsAround \ = colonSegmentTubeMeshOuterPoints.getColonSegmentTubeMeshOuterPoints(nSegment) - # Project reference point for warping onto central path + # Project reference point for warping onto network layout start = nSegment * elementsCountAlongSegment end = (nSegment + 1) * elementsCountAlongSegment + 1 sxRefList, sd1RefList, sd2ProjectedListRef, zRefList = \ @@ -1007,15 +1007,15 @@ def createColonMesh3d(region, options, centralPath, nextNodeIdentifier, nextElem return annotationGroups, nextNodeIdentifier, nextElementIdentifier, nodesIdDistal, xDistal, d1Distal, d2Distal, \ d3Distal -class ColonCentralPath: +class ColonNetworkLayout: - def __init__(self, region, centralPath, termsAlong=[None]): + def __init__(self, region, networkLayout, termsAlong=[None]): """ :param region: Zinc region to define model in. - :param centralPath: Central path subscaffold from meshtype_1d_network_layout1 + :param networkLayout: Network layout subscaffold from meshtype_1d_network_layout1 :param termsAlong: Annotation terms along length of colon """ - # Extract length of each group along colon from central path + # Extract length of each group along colon from network layout cxGroups = [] cd1Groups = [] cd2Groups = [] @@ -1024,7 +1024,7 @@ def __init__(self, region, centralPath, termsAlong=[None]): cd13Groups = [] tmpRegion = region.createRegion() - centralPath.generate(tmpRegion) + networkLayout.generate(tmpRegion) tmpFieldmodule = tmpRegion.getFieldmodule() tmpNodes = tmpFieldmodule.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES) tmpCoordinates = tmpFieldmodule.findFieldByName('coordinates') diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_colonsegment1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_colonsegment1.py index 6fc7b8be..24688dd4 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_colonsegment1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_colonsegment1.py @@ -277,13 +277,13 @@ def generateBaseMesh(cls, region, options): firstNodeIdentifier = 1 firstElementIdentifier = 1 - # Central path + # Network layout cx = [[0.0, 0.0, 0.0], [segmentLength, 0.0, 0.0]] cd1 = [[segmentLength, 0.0, 0.0], [segmentLength, 0.0, 0.0]] cd2 = [[0.0, 1.0, 0.0], [0.0, 1.0, 0.0]] cd12 = [[0.0, 0.0, 0.0], [0.0, 0.0, 0.0]] - # Sample central path + # Sample network layout sx, sd1, se, sxi, ssf = interp.sampleCubicHermiteCurves(cx, cd1, elementsCountAlongSegment) sd2, sd12 = interp.interpolateSampleCubicHermite(cd2, cd12, se, sxi, ssf) @@ -325,7 +325,7 @@ def generateBaseMesh(cls, region, options): xOuter, d1Outer, d2Outer, transitElementList, segmentAxis, annotationGroupsAround = \ colonSegmentTubeMeshOuterPoints.getColonSegmentTubeMeshOuterPoints(nSegment) - # Project reference point for warping onto central path + # Project reference point for warping onto network layout sxRefList, sd1RefList, sd2ProjectedListRef, zRefList = \ tubemesh.getPlaneProjectionOnCentralPath(xOuter, elementsCountAround, elementsCountAlongSegment, segmentLength, sx, sd1, sd2, sd12) @@ -526,7 +526,7 @@ def getColonSegmentOuterPoints(region, elementsCountAroundTC, elementsCountAroun tcWidthSegmentList, startPhase): """ Generates a 3-D colon segment mesh with variable numbers of tenia coli, - numbers of elements around, along the central path, and through wall. + numbers of elements around, along the network layout, and through wall. Colon segment with one "tenia coli" (mouse) has a circular profile along its length. Colon segment with two tenia coli (pig) has a circular profile at the inter-haustral septa, and a bowtie profile in the intra-haustral diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_esophagus1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_esophagus1.py index c0c51929..d25b3ec6 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_esophagus1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_esophagus1.py @@ -78,7 +78,7 @@ class MeshType_3d_esophagus1(Scaffold_base): """ Generates a 3-D esophagus mesh with variable numbers of elements around, along the central line, and through wall. The esophagus is created by a function that generates an elliptical tube segment and uses tubemesh to map the - segment along a central path profile. + segment along a network layout profile. """ @staticmethod @@ -192,11 +192,11 @@ def generateBaseMesh(cls, region, options): nextElementIdentifier = 1 esophagusTermsAlong = ['esophagus', 'cervical part of esophagus', 'thoracic part of esophagus', 'abdominal part of esophagus'] - geometricCentralPath = options['Network layout'] - geometricCentralPath = EsophagusCentralPath(region, geometricCentralPath, esophagusTermsAlong) + geometricNetworkLayout = options['Network layout'] + geometricNetworkLayout = EsophagusNetworkLayout(region, geometricNetworkLayout, esophagusTermsAlong) annotationGroups, nextNodeIdentifier, nextElementIdentifier = \ - createEsophagusMesh3d(region, options, geometricCentralPath, nextNodeIdentifier, nextElementIdentifier, + createEsophagusMesh3d(region, options, geometricNetworkLayout, nextNodeIdentifier, nextElementIdentifier, flatCoordinates=True, materialCoordinates=True)[:3] return annotationGroups, None @@ -243,13 +243,13 @@ def defineFaceAnnotations(cls, region, options, annotationGroups): get_esophagus_term("luminal surface of esophagus")) mucosaInnerSurface.getMeshGroup(mesh2d).addElementsConditional(is_mucosaInnerSurface) -def createEsophagusMesh3d(region, options, centralPath, nextNodeIdentifier, nextElementIdentifier, +def createEsophagusMesh3d(region, options, networkLayout, nextNodeIdentifier, nextElementIdentifier, flatCoordinates=False, materialCoordinates=False): """ - Generates an esophagus scaffold in the region using a central path and parameter options. + Generates an esophagus scaffold in the region using a network layout and parameter options. :param region: Region to create elements in. :param options: Parameter options for esophagus scaffold. - :param centralPath: Central path describing path of the esophagus. + :param networkLayout: Network layout describing path of the esophagus. :param nextNodeIdentifier: Next node identifier to use. :param nextElementIdentifier: Next element identifier to use. :param flatCoordinates: Create flat coordinates if True. @@ -275,21 +275,21 @@ def createEsophagusMesh3d(region, options, centralPath, nextNodeIdentifier, next esophagusTermsAlong =\ ['esophagus', 'cervical part of esophagus', 'thoracic part of esophagus', 'abdominal part of esophagus'] - centralPathLength = centralPath.arcLengthOfGroupsAlong[0] - cx = centralPath.cxGroups[0] - cd1 = centralPath.cd1Groups[0] - cd2 = centralPath.cd2Groups[0] - cd12 = centralPath.cd12Groups[0] - cd3 = centralPath.cd3Groups[0] - cd13 = centralPath.cd13Groups[0] - arcLengthOfGroupsAlong = centralPath.arcLengthOfGroupsAlong + networkLayoutLength = networkLayout.arcLengthOfGroupsAlong[0] + cx = networkLayout.cxGroups[0] + cd1 = networkLayout.cd1Groups[0] + cd2 = networkLayout.cd2Groups[0] + cd12 = networkLayout.cd12Groups[0] + cd3 = networkLayout.cd3Groups[0] + cd13 = networkLayout.cd13Groups[0] + arcLengthOfGroupsAlong = networkLayout.arcLengthOfGroupsAlong - # Sample central path + # Sample network layout 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) - elementAlongLength = centralPathLength / elementsCountAlong + elementAlongLength = networkLayoutLength / elementsCountAlong elementsCountAlongGroups = [] groupLength = 0.0 @@ -436,10 +436,10 @@ def createEsophagusMesh3d(region, options, centralPath, nextNodeIdentifier, next xiFace.append(xi) xiList.append(xiFace) - # Project reference point for warping onto central path + # Project reference point for warping onto network layout sxRefList, sd1RefList, sd2ProjectedListRef, zRefList = \ tubemesh.getPlaneProjectionOnCentralPath(xToWarp, elementsCountAround, elementsCountAlong, - centralPathLength, sx, sd1, sd2, sd12) + networkLayoutLength, sx, sd1, sd2, sd12) # Warp points segmentAxis = [0.0, 0.0, 1.0] @@ -549,17 +549,17 @@ def createEsophagusMesh3d(region, options, centralPath, nextNodeIdentifier, next return annotationGroups, nodeIdentifier, elementIdentifier, nodeIdDistal, xDistal, d1Distal, d2Distal, d3Distal -class EsophagusCentralPath: +class EsophagusNetworkLayout: """ - Generates sampled central path for esophagus scaffold. + Generates sampled network layout for esophagus scaffold. """ - def __init__(self, region, centralPath, termsAlong=[None]): + def __init__(self, region, networkLayout, termsAlong=[None]): """ :param region: Zinc region to define model in. - :param centralPath: Central path subscaffold from meshtype_1d_network_layout1 - :param termsAlong: Annotation terms along length of central path + :param networkLayout: Network layout subscaffold from meshtype_1d_network_layout1 + :param termsAlong: Annotation terms along length of network layout """ - # Extract length of each group along esophagus from central path + # Extract length of each group along esophagus from network layout cxGroups = [] cd1Groups = [] cd2Groups = [] @@ -568,7 +568,7 @@ def __init__(self, region, centralPath, termsAlong=[None]): cd13Groups = [] tmpRegion = region.createRegion() - centralPath.generate(tmpRegion) + networkLayout.generate(tmpRegion) tmpFieldmodule = tmpRegion.getFieldmodule() tmpNodes = tmpFieldmodule.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES) tmpCoordinates = tmpFieldmodule.findFieldByName('coordinates') diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_gastrointestinaltract1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_gastrointestinaltract1.py index cffdd405..7c778235 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_gastrointestinaltract1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_gastrointestinaltract1.py @@ -16,13 +16,13 @@ from scaffoldmaker.annotation.smallintestine_terms import get_smallintestine_term from scaffoldmaker.annotation.stomach_terms import get_stomach_term from scaffoldmaker.meshtypes.meshtype_1d_network_layout1 import MeshType_1d_network_layout1 -from scaffoldmaker.meshtypes.meshtype_3d_cecum1 import MeshType_3d_cecum1, createCecumMesh3d, CecumCentralPath -from scaffoldmaker.meshtypes.meshtype_3d_colon1 import MeshType_3d_colon1, createColonMesh3d, ColonCentralPath +from scaffoldmaker.meshtypes.meshtype_3d_cecum1 import MeshType_3d_cecum1, createCecumMesh3d, CecumNetworkLayout +from scaffoldmaker.meshtypes.meshtype_3d_colon1 import MeshType_3d_colon1, createColonMesh3d, ColonNetworkLayout from scaffoldmaker.meshtypes.meshtype_3d_esophagus1 import MeshType_3d_esophagus1, createEsophagusMesh3d, \ - EsophagusCentralPath + EsophagusNetworkLayout from scaffoldmaker.meshtypes.meshtype_3d_smallintestine1 import MeshType_3d_smallintestine1, \ - createSmallIntestineMesh3d, SmallIntestineCentralPath -from scaffoldmaker.meshtypes.meshtype_3d_stomach1 import MeshType_3d_stomach1, createStomachMesh3d, StomachCentralPath + createSmallIntestineMesh3d, SmallIntestineNetworkLayout +from scaffoldmaker.meshtypes.meshtype_3d_stomach1 import MeshType_3d_stomach1, createStomachMesh3d, StomachNetworkLayout from scaffoldmaker.meshtypes.scaffold_base import Scaffold_base from scaffoldmaker.scaffoldpackage import ScaffoldPackage from scaffoldmaker.utils import interpolation as interp @@ -425,7 +425,7 @@ def getDefaultNetworkLayoutScaffoldPackage(cls, parameterSetName): class MeshType_3d_gastrointestinaltract1(Scaffold_base): ''' Generates a 3-D gastrointestinal tract mesh with variable numbers of elements around, along the central line, - and through wall. The tract is created by following an annotated central path and calling scaffold function to + and through wall. The tract is created by following an annotated network layout and calling scaffold function to generate the respective segment along the central line profile. ''' @@ -590,7 +590,7 @@ def generateBaseMesh(cls, region, options): :return: annotationGroups """ cls.updateSubScaffoldOptions(options) - centralPath = options['Network layout'] + networkLayout = options['Network layout'] esophagusOptions = options['Esophagus'] stomachOptions = options['Stomach'] smallIntestineOptions = options['Small intestine'] @@ -612,9 +612,9 @@ def generateBaseMesh(cls, region, options): nextElementIdentifier = 1 tmpRegion = region.createRegion() - centralPath.generate(tmpRegion) + networkLayout.generate(tmpRegion) - # Central path + # Network layout gastroTermsAlong = [['esophagus', 'cervical part of esophagus', 'thoracic part of esophagus', 'abdominal part of esophagus'], ['stomach', 'fundus of stomach', 'body of stomach', 'pyloric antrum', 'pyloric canal', @@ -629,20 +629,20 @@ def generateBaseMesh(cls, region, options): allAnnotationGroups = [] if gastroTermsAlong[section][0] == 'esophagus': - esoCentralPath = EsophagusCentralPath(region, centralPath, gastroTermsAlong[section]) + esoNetworkLayout = EsophagusNetworkLayout(region, networkLayout, gastroTermsAlong[section]) annotationGroupsEsophagus, nextNodeIdentifier, nextElementIdentifier, nodesIdEsoDistal,\ xEsoDistal, d1EsoDistal, d2EsoDistal, d3EsoDistal = \ - createEsophagusMesh3d(region, esophagusSettings, esoCentralPath, nextNodeIdentifier, + createEsophagusMesh3d(region, esophagusSettings, esoNetworkLayout, nextNodeIdentifier, nextElementIdentifier) elif gastroTermsAlong[section][0] == 'stomach': - stomachCentralPath = StomachCentralPath(region, centralPath, gastroTermsAlong[section], esoSegmentIdx=0, - stomachSegmentIdx=[1,2]) + stomachNetworkLayout = StomachNetworkLayout(region, networkLayout, gastroTermsAlong[section], + esoSegmentIdx=0, stomachSegmentIdx=[1,2]) annotationGroupsStomach, nextNodeIdentifier, nextElementIdentifier, _, nodesIdStomachDistal,\ xStomachDistal, d1StomachDistal, d2StomachDistal, d3StomachDistal, arclengthCPStomachDistal, xPrev, \ d2Prev = \ createStomachMesh3d(region, fm, coordinates, gastroTermsAlong[section], - allAnnotationGroups, stomachCentralPath, + allAnnotationGroups, stomachNetworkLayout, options=stomachSettings, nodeIdentifier=nextNodeIdentifier, elementIdentifier=nextElementIdentifier, nodeIdProximalEso=nodesIdEsoDistal, xProximalEso=xEsoDistal, @@ -652,12 +652,13 @@ def generateBaseMesh(cls, region, options): annotationGroupsStomach.remove(nearLCGroup) elif gastroTermsAlong[section][0] == 'small intestine': - smallIntestineCentralPath = SmallIntestineCentralPath(region, centralPath, gastroTermsAlong[section]) + smallIntestineNetworkLayout = SmallIntestineNetworkLayout(region, networkLayout, + gastroTermsAlong[section]) annotationGroupsSmallIntestine, nextNodeIdentifier, nextElementIdentifier, \ nodesIdSmallIntestineDistal, xSmallIntestineDistal, d1SmallIntestineDistal, d2SmallIntestineDistal, \ d3SmallIntestineDistal, xNext, d2Next = \ - createSmallIntestineMesh3d(region, smallIntestineSettings, smallIntestineCentralPath, + createSmallIntestineMesh3d(region, smallIntestineSettings, smallIntestineNetworkLayout, nextNodeIdentifier, nextElementIdentifier, nodeIdProximal=nodesIdStomachDistal, xProximal=xStomachDistal, d1Proximal=d1StomachDistal, d2Proximal=d2StomachDistal, @@ -677,20 +678,20 @@ def generateBaseMesh(cls, region, options): coordinates.setNodeParameters(cache, -1, Node.VALUE_LABEL_D_DS2, 1, newD2) elif gastroTermsAlong[section][0] == 'caecum': - cecumCentralPath = CecumCentralPath(region, centralPath, gastroTermsAlong[section], + cecumNetworkLayout = CecumNetworkLayout(region, networkLayout, gastroTermsAlong[section], ileumSegmentIdx=2, cecumSegmentIdx=[3,4]) annotationGroupsCecum, nextNodeIdentifier, nextElementIdentifier, nodesIdCecumDistal, \ xCecumDistal, d1CecumDistal, d2CecumDistal, d3CecumDistal = \ - createCecumMesh3d(region, cecumSettings, cecumCentralPath, nextNodeIdentifier, + createCecumMesh3d(region, cecumSettings, cecumNetworkLayout, nextNodeIdentifier, nextElementIdentifier, nodeIdProximalIleum=nodesIdSmallIntestineDistal, xProximalIleum=xSmallIntestineDistal, d1ProximalIleum=d1SmallIntestineDistal, d2ProximalIleum=d2SmallIntestineDistal, d3ProximalIleum=d3SmallIntestineDistal) elif gastroTermsAlong[section][0] == 'colon': - colonCentralPath = ColonCentralPath(region, centralPath, gastroTermsAlong[section]) + colonNetworkLayout = ColonNetworkLayout(region, networkLayout, gastroTermsAlong[section]) annotationGroupsColon, nextNodeIdentifier, nextElementIdentifier, \ nodesIdColonDistal, xColonDistal, d1ColonDistal, d2ColonDistal, d3ColonDistal = \ - createColonMesh3d(region, colonSettings, colonCentralPath, nextNodeIdentifier, + createColonMesh3d(region, colonSettings, colonNetworkLayout, nextNodeIdentifier, nextElementIdentifier, nodeIdProximal=nodesIdCecumDistal, xProximal=xCecumDistal, d1Proximal=d1CecumDistal, d2Proximal=d2CecumDistal, d3Proximal=d3CecumDistal) @@ -718,15 +719,15 @@ def refineMesh(cls, meshrefinement, options): refineElementsCountThroughWall) return -class SectionCentralPath: +class SectionNetworkLayout: """ - Generates sampled central path for GI Tract scaffold. + Generates sampled network layout for GI Tract scaffold. """ def __init__(self, arcLengthOfGroupsAlong, cxGroups, cd1Groups, cd2Groups,cd3Groups, cd12Groups, cd13Groups): """ :param region: Zinc region to define model in. - :param centralPath: Central path subscaffold from meshtype_1d_path1 - :param stomachTermsAlong: Annotation terms along length of central path + :param networkLayout: Network layout subscaffold from meshtype_1d_networklayout1 + :param stomachTermsAlong: Annotation terms along length of network layout """ self.arcLengthOfGroupsAlong = arcLengthOfGroupsAlong self.cxGroups = cxGroups diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_smallintestine1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_smallintestine1.py index fc335a8e..d4fabe59 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_smallintestine1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_smallintestine1.py @@ -1041,11 +1041,11 @@ def generateBaseMesh(cls, region, options): nextNodeIdentifier = 1 nextElementIdentifier = 1 smallIntestineTermsAlong = ['small intestine', 'duodenum', 'jejunum', 'ileum'] - geometricCentralPath = options['Network layout'] - geometricCentralPath = SmallIntestineCentralPath(region, geometricCentralPath, smallIntestineTermsAlong) + geometricNetworkLayout = options['Network layout'] + geometricNetworkLayout = SmallIntestineNetworkLayout(region, geometricNetworkLayout, smallIntestineTermsAlong) annotationGroups, nextNodeIdentifier, nextElementIdentifier = \ - createSmallIntestineMesh3d(region, options, geometricCentralPath, nextNodeIdentifier, + createSmallIntestineMesh3d(region, options, geometricNetworkLayout, nextNodeIdentifier, nextElementIdentifier, flatCoordinates=True, materialCoordinates=True)[0:3] return annotationGroups, None @@ -1102,20 +1102,20 @@ def defineFaceAnnotations(cls, region, options, annotationGroups): "luminal surface of duodenum")) duodenumLuminal.getMeshGroup(mesh2d).addElementsConditional(is_duodenumLuminal) -def createSmallIntestineMesh3d(region, options, centralPath, nextNodeIdentifier, nextElementIdentifier, +def createSmallIntestineMesh3d(region, options, networkLayout, nextNodeIdentifier, nextElementIdentifier, flatCoordinates=False, materialCoordinates=False, nodeIdProximal=[], xProximal=[], d1Proximal=[], d2Proximal=[], d3Proximal=[], arclengthCPProximal=0.0): """ - Generates a small intestine scaffold in the region using a central path and parameter options. + Generates a small intestine scaffold in the region using a network layout and parameter options. :param region: Region to create elements in. :param options: Parameter options for small intestine scaffold. - :param centralPath: Central path describing path of small intestine. + :param networkLayout: Network layout describing path of small intestine. :param nextNodeIdentifier: Next node identifier to use. :param nextElementIdentifier: Next element identifier to use. :param flatCoordinates: Create flat coordinates if True. :param nodeIdProximal, xProximal, d1Proximal, d2Proximal, d3Proximal: Identifier, coordinates and derivatives of nodes to use on proximal end of small intestine. - :param arclengthCPProximal: Arc length of central path in the element leading up to the start of the small + :param arclengthCPProximal: Arc length of network layout in the element leading up to the start of the small intestine. :param materialCoordinates: Create material coordinates if True. :return annotationGroups, nextNodeIdentifier, nextElementIdentifier, nodesIdDistal, xDistal, d1Distal, d2Distal, @@ -1143,12 +1143,12 @@ def createSmallIntestineMesh3d(region, options, centralPath, nextNodeIdentifier, smallIntestineTermsAlong = ['small intestine', 'duodenum', 'jejunum', 'ileum'] - centralPathLength = centralPath.arcLengthOfGroupsAlong[0] - cx = centralPath.cxGroups[0] - cd1 = centralPath.cd1Groups[0] - cd2 = centralPath.cd2Groups[0] - cd12 = centralPath.cd12Groups[0] - arcLengthOfGroupsAlong = centralPath.arcLengthOfGroupsAlong + networkLayoutLength = networkLayout.arcLengthOfGroupsAlong[0] + cx = networkLayout.cxGroups[0] + cd1 = networkLayout.cd1Groups[0] + cd2 = networkLayout.cd2Groups[0] + cd12 = networkLayout.cd12Groups[0] + arcLengthOfGroupsAlong = networkLayout.arcLengthOfGroupsAlong # find arclength of colon length = 0.0 @@ -1164,7 +1164,7 @@ def createSmallIntestineMesh3d(region, options, centralPath, nextNodeIdentifier, elementAlongLength = length / elementsCountAlong # print('Length = ', length) - # Sample central path + # Sample network layout startLength = 0.0 lengthFraction = 1.0 if xProximal: @@ -1183,7 +1183,7 @@ def createSmallIntestineMesh3d(region, options, centralPath, nextNodeIdentifier, outerRadiusList, dOuterRadiusList = interp.interpolateSampleCubicHermite( outerRadiusListCP, dOuterRadiusListCP, se, sxi, ssf) - elementAlongLength = centralPathLength / elementsCountAlong + elementAlongLength = networkLayoutLength / elementsCountAlong elementsCountAlongGroups = [] groupLength = 0.0 @@ -1266,7 +1266,7 @@ def createSmallIntestineMesh3d(region, options, centralPath, nextNodeIdentifier, xOuter, d1Outer, d2Outer, transitElementList, segmentAxis, radiusAlongSegmentList = \ smallIntestineSegmentTubeMeshOuterPoints.getCylindricalSegmentTubeMeshOuterPoints(nSegment) - # Project reference point for warping onto central path + # Project reference point for warping onto network layout start = nSegment*elementsCountAlongSegment end = (nSegment + 1)*elementsCountAlongSegment + 1 sxRefList, sd1RefList, sd2ProjectedListRef, zRefList = \ @@ -1363,17 +1363,17 @@ def createSmallIntestineMesh3d(region, options, centralPath, nextNodeIdentifier, return annotationGroups, nextNodeIdentifier, nextElementIdentifier, nodesIdDistal, xDistal, d1Distal, d2Distal, \ d3Distal, xNext, d2Next -class SmallIntestineCentralPath: +class SmallIntestineNetworkLayout: """ - Generates sampled central path for small intestine scaffold. + Generates sampled network layout for small intestine scaffold. """ - def __init__(self, region, centralPath, termsAlong=[None]): + def __init__(self, region, networkLayout, termsAlong=[None]): """ :param region: Zinc region to define model in. - :param centralPath: Central path subscaffold from meshtype_1d_network_layout1 - :param termsAlong: Annotation terms along length of central path + :param networkLayout: Network layout subscaffold from meshtype_1d_network_layout1 + :param termsAlong: Annotation terms along length of network layout """ - # Extract length of each group along small intestine from central path + # Extract length of each group along small intestine from network layout cxGroups = [] cd1Groups = [] cd2Groups = [] @@ -1382,7 +1382,7 @@ def __init__(self, region, centralPath, termsAlong=[None]): cd13Groups = [] tmpRegion = region.createRegion() - centralPath.generate(tmpRegion) + networkLayout.generate(tmpRegion) tmpFieldmodule = tmpRegion.getFieldmodule() tmpNodes = tmpFieldmodule.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES) tmpCoordinates = tmpFieldmodule.findFieldByName('coordinates') diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py index 131451b9..8afc63a9 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_stomach1.py @@ -544,8 +544,8 @@ def updateOstiumOptions(options, ostiumOptions): class MeshType_3d_stomach1(Scaffold_base): """ Generates a 3-D stomach mesh with variable numbers of elements around the esophagus and duodenum, - along the central line, and through wall. The stomach is created using a central path as the longitudinal axis - of the stomach. D2 of the central path points to the greater curvature of the stomach and magnitude of D2 and D3 + along the central line, and through wall. The stomach is created using a network layout as the longitudinal axis + of the stomach. D2 of the network layout points to the greater curvature of the stomach and magnitude of D2 and D3 are the radii of the stomach in the respective direction. """ @@ -709,8 +709,8 @@ def generateBaseMesh(cls, region, options): :return: list of AnnotationGroup, None """ - geometricCentralPath = options['Network layout'] - materialCentralPath = getDefaultNetworkLayoutScaffoldPackage(cls, 'Material') + geometricNetworkLayout = options['Network layout'] + materialNetworkLayout = getDefaultNetworkLayoutScaffoldPackage(cls, 'Material') limitingRidge = options['Limiting ridge'] elementsCountThroughWall = options['Number of elements through wall'] @@ -723,11 +723,11 @@ def generateBaseMesh(cls, region, options): fm = region.getFieldmodule() coordinates = find_or_create_field_coordinates(fm) - geometricCentralPath = StomachCentralPath(region, geometricCentralPath, stomachTermsAlong) + geometricNetworkLayout = StomachNetworkLayout(region, geometricNetworkLayout, stomachTermsAlong) allAnnotationGroups, nextNodeIdentifier, nextElementIdentifier, elementsAlongGroups = \ createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, - allAnnotationGroups, centralPath=geometricCentralPath, + allAnnotationGroups, networkLayout=geometricNetworkLayout, options=options, nodeIdentifier=1, elementIdentifier=1)[0:4] # Material coordinates @@ -738,12 +738,12 @@ def generateBaseMesh(cls, region, options): with ChangeManager(tmp_fm): tmp_stomach_coordinates = find_or_create_field_coordinates(tmp_fm, name="stomach coordinates") - materialCentralPath = StomachCentralPath(tmp_region, materialCentralPath, stomachTermsAlong) + materialNetworkLayout = StomachNetworkLayout(tmp_region, materialNetworkLayout, stomachTermsAlong) allAnnotationGroupsMaterial, nextNodeIdentifier, nextElementIdentifier = \ createStomachMesh3d(tmp_region, tmp_fm, tmp_stomach_coordinates, stomachTermsAlong, allAnnotationGroupsMaterial, - centralPath=materialCentralPath, options=options, nodeIdentifier=1, + networkLayout=materialNetworkLayout, options=options, nodeIdentifier=1, elementIdentifier=1, elementsAlongSections=elementsAlongGroups, materialCoordinates=True)[:3] @@ -1093,19 +1093,19 @@ def defineFaceAnnotations(cls, region, options, annotationGroups): annotationGroups.remove(nearLCGroup) -class StomachCentralPath: +class StomachNetworkLayout: """ - Generates sampled central path for stomach scaffold. + Generates sampled network layout for stomach scaffold. """ - def __init__(self, region, centralPath, stomachTermsAlong=[None], esoSegmentIdx=0, stomachSegmentIdx=[1,2]): + def __init__(self, region, networkLayout, stomachTermsAlong=[None], esoSegmentIdx=0, stomachSegmentIdx=[1,2]): """ :param region: Zinc region needed to create path region to define path in. - :param centralPath: Central path subscaffold from meshtype_1d_network_layout1 + :param networkLayout: Network layout subscaffold from meshtype_1d_network_layout1 :param stomachTermsAlong: Annotation terms along length of stomach :param esoSegmentIdx: Segment index of esophagus branch. :param stomachSegmentIdx: Segment index of the body of stomach. """ - # Extract length of each group along stomach from central path + # Extract length of each group along stomach from network layout arcLengthOfGroupsAlong = [] cxGroups = [] cd1Groups = [] @@ -1115,8 +1115,8 @@ def __init__(self, region, centralPath, stomachTermsAlong=[None], esoSegmentIdx= cd13Groups = [] tmpRegion = region.createRegion() - centralPath.generate(tmpRegion) - pathNetworkMesh = centralPath.getConstructionObject() + networkLayout.generate(tmpRegion) + pathNetworkMesh = networkLayout.getConstructionObject() tmpFieldmodule = tmpRegion.getFieldmodule() tmpNodes = tmpFieldmodule.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES) tmpCoordinates = tmpFieldmodule.findFieldByName('coordinates') @@ -1275,18 +1275,18 @@ def findCurvatureAlongLine(nx, nd, radialVectors): return curvature -def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotationGroups, centralPath, options, +def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotationGroups, networkLayout, options, nodeIdentifier, elementIdentifier, elementsAlongSections = [], materialCoordinates=False, nodeIdProximalEso=[], xProximalEso=[], d1ProximalEso=[], d2ProximalEso=[], d3ProximalEso=[]): """ - Generates a stomach scaffold in the region using a central path and parameter options. + Generates a stomach scaffold in the region using a network layout and parameter options. :param region: Region to create elements in. :param fm: Zinc fieldModule to create elements in. :param coordinates: Coordinate field to define nodes and elements. :param stomachTermsAlong: Annotation terms along length of stomach. :param allAnnotationGroups: List of annotation groups. - :param centralPath: Central path through the axis of the stomach scaffold. + :param networkLayout: Network layout through the axis of the stomach scaffold. :param options: Parameter options for stomach scaffold. :param nodeIdentifier: First node identifier. :param elementIdentifier: First element identifier. @@ -1312,7 +1312,7 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio GEJSettings = updateOstiumOptions(options, ostiumOptions) elementsAlongEsophagus = GEJSettings['Number of elements along'] elementsThroughEsophagusWall = GEJSettings['Number of elements through wall'] - ostiumRadius = vector.magnitude(centralPath.cd2Groups[-1][1]) + ostiumRadius = vector.magnitude(networkLayout.cd2Groups[-1][1]) limitingRidge = options['Limiting ridge'] wallThickness = options['Wall thickness'] GEJSettings['Use linear through ostium wall'] = options['Use linear through wall'] @@ -1371,11 +1371,11 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio # Create annotation groups for stomach sections arcLengthRatioForGroupsFromFundusApex = [] - arcLengthOfGroupsAlong = centralPath.arcLengthOfGroupsAlong - stomachCentralPathLength = arcLengthOfGroupsAlong[0] + arcLengthOfGroupsAlong = networkLayout.arcLengthOfGroupsAlong + stomachNetworkLayoutLength = arcLengthOfGroupsAlong[0] for i in range(1, len(stomachTermsAlong) - 1): - arcLengthRatio = arcLengthOfGroupsAlong[i] / stomachCentralPathLength + arcLengthRatio = arcLengthOfGroupsAlong[i] / stomachNetworkLayoutLength arcLengthRatioForGroupsFromFundusApex.append(arcLengthRatio) stomachGroup = AnnotationGroup(region, get_stomach_term("stomach")) @@ -1405,7 +1405,7 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio [circularMuscleGroup], [longitudinalMuscleGroup]] - # Break central path into elements allocation to each group + # Break network layout into elements allocation to each group cxSections = [] cd1Sections = [] cd2Sections = [] @@ -1422,12 +1422,12 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio targetLengthTS = 0.025 for i in (list(range(1, len(stomachTermsAlong) - 2)) + [0]): # start from body, go back to fundus - cxGroup = centralPath.cxGroups[i + 1] - cd1Group = centralPath.cd1Groups[i + 1] - cd2Group = centralPath.cd2Groups[i + 1] - cd3Group = centralPath.cd3Groups[i + 1] - cd12Group = centralPath.cd12Groups[i + 1] - cd13Group = centralPath.cd13Groups[i + 1] + cxGroup = networkLayout.cxGroups[i + 1] + cd1Group = networkLayout.cd1Groups[i + 1] + cd2Group = networkLayout.cd2Groups[i + 1] + cd3Group = networkLayout.cd3Groups[i + 1] + cd12Group = networkLayout.cd12Groups[i + 1] + cd13Group = networkLayout.cd13Groups[i + 1] # for n2 in range(len(cxGroup)): # node = nodes.createNode(nodeIdentifier, nodetemplate) @@ -1597,11 +1597,11 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio # nodeIdentifier, elementIdentifier = trackSurfaceStomach.generateMesh(region) # Set up gastro-esophageal junction with network layout - cxEso = centralPath.cxGroups[-1] - cd1Eso = centralPath.cd1Groups[-1] - cd2Eso = centralPath.cd2Groups[-1] - cd3Eso = centralPath.cd3Groups[-1] - cd12Eso = centralPath.cd12Groups[-1] + cxEso = networkLayout.cxGroups[-1] + cd1Eso = networkLayout.cd1Groups[-1] + cd2Eso = networkLayout.cd2Groups[-1] + cd3Eso = networkLayout.cd3Groups[-1] + cd12Eso = networkLayout.cd12Groups[-1] # Find centre position # track along esophagus path and since cxEso[1] could be above or below the track surface, we check both side to @@ -1610,7 +1610,7 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio xTol = 1.0E-6 arcStart = 0.0 - arcEnd = centralPath.arcLengthOfGroupsAlong[-1] + arcEnd = networkLayout.arcLengthOfGroupsAlong[-1] nearestPosition = trackSurfaceStomach.findNearestPosition(cxEso[0]) xNearestStart = trackSurfaceStomach.evaluateCoordinates(nearestPosition, derivatives=False) distStart = vector.magnitude([cxEso[0][c] - xNearestStart[c] for c in range(3)]) @@ -1686,10 +1686,10 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio d12Path = [cd2Eso[0], [0.0, 0.0, 0.0]] d13Path = [cd3Eso[0], [0.0, 0.0, 0.0]] - centralPathEso = CustomCentralPath(xPath, d1Path, d2Path, d3Path, d12Path, d13Path) + networkLayoutEso = CustomNetworkLayout(xPath, d1Path, d2Path, d3Path, d12Path, d13Path) nextNodeIdentifier, nextElementIdentifier, (o1_x, o1_d1, o1_d2, o1_d3, o1_NodeId, o1_Positions) = \ - generateOstiumMesh(region, GEJSettings, trackSurfaceStomach, centralPathEso, + generateOstiumMesh(region, GEJSettings, trackSurfaceStomach, networkLayoutEso, nodeIdentifier, elementIdentifier, nodeIdProximal=nodeIdProximalEso, xProximal=xProximalEso, d1Proximal=d1ProximalEso, d2Proximal=d2ProximalEso, d3Proximal=d3ProximalEso, @@ -2875,9 +2875,9 @@ def createStomachMesh3d(region, fm, coordinates, stomachTermsAlong, allAnnotatio xDistal, d1Distal, d2Distal, d3Distal, arclengthDuodenumCP, xPrev, d2Prev -class CustomCentralPath: +class CustomNetworkLayout: """ - Generates sampled central path for part of central path. + Generates sampled network layout for part of network layout. """ def __init__(self, cx, cd1, cd2, cd3, cd12, cd13): self.cxPath = cx diff --git a/tests/test_cecum.py b/tests/test_cecum.py index 701998a6..578e127e 100644 --- a/tests/test_cecum.py +++ b/tests/test_cecum.py @@ -25,9 +25,9 @@ def test_cecum1(self): self.assertEqual(parameterSetNames, ["Default", "Human 1", "Human 2", "Pig 1"]) options = MeshType_3d_cecum1.getDefaultOptions("Human 2") - centralPath = options.get("Network layout") - centralPathSettings = centralPath.getScaffoldSettings() - self.assertEqual("1-2-3.2, 4-3-5", centralPathSettings["Structure"]) + networkLayout = options.get("Network layout") + networkLayoutSettings = networkLayout.getScaffoldSettings() + self.assertEqual("1-2-3.2, 4-3-5", networkLayoutSettings["Structure"]) self.assertEqual(29, len(options)) self.assertEqual(1, options.get("Number of segments")) diff --git a/tests/test_colon.py b/tests/test_colon.py index 4cc4d486..00ddd0b6 100644 --- a/tests/test_colon.py +++ b/tests/test_colon.py @@ -29,54 +29,53 @@ def test_colon1(self): self.assertEqual(parameterSetNames, ["Default", "Cattle 1", "Human 1", "Human 2", "Human 3", "Mouse 1", "Mouse 2", "Pig 1"]) - parameterSetStructureStrings = { - 'Test line': ScaffoldPackage(MeshType_1d_network_layout1, { - 'scaffoldSettings': { - "Structure": "1-2-3-4" + testNetworkLayout = ScaffoldPackage(MeshType_1d_network_layout1, { + 'scaffoldSettings': { + "Structure": "1-2-3-4" + }, + 'meshEdits': exnode_string_from_nodeset_field_parameters( + [Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, + Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ + (1, [[0.00, 0.00, 0.00], [-50.70, 178.20, 0.00], [-37.97, -9.49, -18.98], [-6.86, -11.39, -2.36], [-18.61, -3.98, 39.12], [-14.00, -1.00, -12.00]]), + (2, [[-47.40, 188.60, 0.00], [-19.30, 177.10, 0.00], [-35.79, -6.51, -13.01], [11.23, 17.36, 14.31], [-12.66, -3.99, 36.28], [-4.00, 19.00, 22.00]]), + (3, [[-4.40, 396.50, 0.00], [206.00, 40.10, 0.00], [-13.89, 27.78, 11.11], [13.54, -1.87, 21.51], [-6.05, -12.50, 29.93], [-6.00, 0.00, 51.00]]), + (4, [[130.00, 384.10, 0.00], [130.80, -40.50, 0.00], [-5.35, 4.28, 31.06], [5.83, -8.41, 8.86], [-15.28, -27.78, 2.51], [0.00, 1.00, 24.00]])]), + + 'userAnnotationGroups': [ + { + '_AnnotationGroup': True, + 'dimension': 1, + 'identifierRanges': '1-3', + 'name': get_colon_term('colon')[0], + 'ontId': get_colon_term('colon')[1] }, - 'meshEdits': exnode_string_from_nodeset_field_parameters( - [ Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3], [ - (1, [ [ 0.00, 0.00, 0.00 ], [ -50.70, 178.20, 0.00 ], [ -37.97, -9.49, -18.98 ], [ -6.86, -11.39, -2.36 ], [ -18.61, -3.98, 39.12 ], [ -14.00, -1.00, -12.00] ] ), - (2, [ [ -47.40, 188.60, 0.00 ], [ -19.30, 177.10, 0.00 ], [ -35.79, -6.51, -13.01 ], [ 11.23, 17.36, 14.31 ], [ -12.66, -3.99, 36.28 ], [ -4.00, 19.00, 22.00] ] ), - (3, [ [ -4.40, 396.50, 0.00 ], [ 206.00, 40.10, 0.00 ], [ -13.89, 27.78, 11.11 ], [ 13.54, -1.87, 21.51 ], [ -6.05, -12.50, 29.93 ], [ -6.00, 0.00, 51.00] ] ), - (4, [ [ 130.00, 384.10, 0.00 ], [ 130.80, -40.50, 0.00 ], [ -5.35, 4.28, 31.06 ], [ 5.83, -8.41, 8.86 ], [ -15.28, -27.78, 2.51 ], [ 0.00, 1.00, 24.00] ] ) ] ), - - 'userAnnotationGroups': [ - { - '_AnnotationGroup': True, - 'dimension': 1, - 'identifierRanges': '1-3', - 'name': get_colon_term('colon')[0], - 'ontId': get_colon_term('colon')[1] - }, - { - '_AnnotationGroup': True, - 'dimension': 1, - 'identifierRanges': '1', - 'name': get_colon_term('ascending colon')[0], - 'ontId': get_colon_term('ascending colon')[1] - }, - { - '_AnnotationGroup': True, - 'dimension': 1, - 'identifierRanges': '2', - 'name': get_colon_term('transverse colon')[0], - 'ontId': get_colon_term('transverse colon')[1] - }, - { - '_AnnotationGroup': True, - 'dimension': 1, - 'identifierRanges': '3', - 'name': get_colon_term('descending colon')[0], - 'ontId': get_colon_term('descending colon')[1] - }] - }) - } - centralPathOption = parameterSetStructureStrings['Test line'] + { + '_AnnotationGroup': True, + 'dimension': 1, + 'identifierRanges': '1', + 'name': get_colon_term('ascending colon')[0], + 'ontId': get_colon_term('ascending colon')[1] + }, + { + '_AnnotationGroup': True, + 'dimension': 1, + 'identifierRanges': '2', + 'name': get_colon_term('transverse colon')[0], + 'ontId': get_colon_term('transverse colon')[1] + }, + { + '_AnnotationGroup': True, + 'dimension': 1, + 'identifierRanges': '3', + 'name': get_colon_term('descending colon')[0], + 'ontId': get_colon_term('descending colon')[1] + }] + }) + segmentProfileOption = ScaffoldPackage(MeshType_3d_colonsegment1, defaultParameterSetName='Human 1') options = { 'Base parameter set': 'Human 1', - 'Network layout': copy.deepcopy(centralPathOption), + 'Network layout': testNetworkLayout, 'Segment profile': segmentProfileOption, 'Number of segments': 3, 'Start phase': 0.0, @@ -91,7 +90,7 @@ def test_colon1(self): 'Refine number of elements through wall': 1 } self.assertEqual(14, len(options)) - centralPath = options['Network layout'] + networkLayout = options['Network layout'] segmentProfile = options.get("Segment profile") segmentSettings = segmentProfile.getScaffoldSettings() self.assertEqual(8, segmentSettings.get("Number of elements around haustrum")) @@ -111,7 +110,7 @@ def test_colon1(self): self.assertTrue(region.isValid()) tmpRegion = region.createRegion() - centralPath.generate(tmpRegion) + networkLayout.generate(tmpRegion) tmpFieldmodule = tmpRegion.getFieldmodule() cx = get_nodeset_path_field_parameters( tmpFieldmodule.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES), diff --git a/tests/test_gastrointestinaltract1.py b/tests/test_gastrointestinaltract1.py index 3625ec53..442360f8 100644 --- a/tests/test_gastrointestinaltract1.py +++ b/tests/test_gastrointestinaltract1.py @@ -29,8 +29,8 @@ def test_gastrointestinaltract1(self): self.assertEqual(parameterSetNames, ['Default', 'Human 1']) options = scaffold.getDefaultOptions("Default") self.assertEqual(10, len(options)) - centralPathOptions = options['Network layout'] - centralPathSettings = centralPathOptions.getScaffoldSettings() + networkLayoutOptions = options['Network layout'] + networkLayoutSettings = networkLayoutOptions.getScaffoldSettings() self.assertEqual("1-2-3-4-5-6-7.2, 8-9-10-11-7-12-13-14-15-16-17-18-19-20-21-22-23-24-25-26-27-28-29-30-31-32-" "33-34-35-36-37-38-39-40-41-42-43-44-45-46-47-48-49-50-51-52-53-54-55-56-57-58-59-60-61-62-63-" "64-65-66-67-68-69-70-71-72-73-74-75-76-77-78-79-80-81-82-83-84-85-86-87-88-89-90-91-92-93-94-" @@ -40,7 +40,7 @@ def test_gastrointestinaltract1(self): "165-166-167-168-169-170-171-172.2, 173-172-174-175-176-177-178-179-180-181-182-183-184-185-" "186-187-188-189-190-191-192-193-194-195-196-197-198-199-200-201-202-203-204-205-206-207-208-" "209-210-211-212-213-214-215-216-217-218-219-220-221-222", - centralPathSettings.get("Structure")) + networkLayoutSettings.get("Structure")) esoOptions = options['Esophagus'] esoSettings = esoOptions.getScaffoldSettings() self.assertEqual(8, esoSettings['Number of elements around']) diff --git a/tests/test_smallintestine.py b/tests/test_smallintestine.py index c3733945..cfdc069b 100644 --- a/tests/test_smallintestine.py +++ b/tests/test_smallintestine.py @@ -25,8 +25,7 @@ def test_smallintestine1(self): """ parameterSetNames = MeshType_3d_smallintestine1.getParameterSetNames() self.assertEqual(parameterSetNames, ["Default", "Cattle 1", "Human 1", "Mouse 1"]) - parameterSetStructureStrings = { - 'Test line': ScaffoldPackage(MeshType_1d_network_layout1, { + testNetworkLayout = ScaffoldPackage(MeshType_1d_network_layout1, { 'scaffoldSettings': { "Structure": "1-2-3-4" }, @@ -67,13 +66,12 @@ def test_smallintestine1(self): 'ontId': get_smallintestine_term('ileum')[1] }] }) - } - centralPathOption = parameterSetStructureStrings['Test line'] + options = MeshType_3d_smallintestine1.getDefaultOptions("Mouse 1") - options['Network layout'] = copy.deepcopy(centralPathOption) + options['Network layout'] = testNetworkLayout options['Number of segments'] = 3 self.assertEqual(16, len(options)) - centralPath = options['Network layout'] + networkLayout = options['Network layout'] self.assertEqual(3, options.get("Number of segments")) self.assertEqual(8, options.get("Number of elements around")) self.assertEqual(3, options.get("Number of elements along segment")) @@ -87,7 +85,7 @@ def test_smallintestine1(self): self.assertTrue(region.isValid()) tmpRegion = region.createRegion() - centralPath.generate(tmpRegion) + networkLayout.generate(tmpRegion) tmpFieldmodule = tmpRegion.getFieldmodule() cx = get_nodeset_path_field_parameters( tmpFieldmodule.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES), From b9bbc50f4fcc51cb6b092c263ffc21af5bea46db Mon Sep 17 00:00:00 2001 From: mlin865 Date: Fri, 15 Mar 2024 11:41:53 +1300 Subject: [PATCH 24/24] Replace findCurvature functions with getCurvaturesAlongCurve --- .../meshtypes/meshtype_3d_cecum1.py | 24 +++---- src/scaffoldmaker/utils/interpolation.py | 64 ++++++++----------- 2 files changed, 37 insertions(+), 51 deletions(-) diff --git a/src/scaffoldmaker/meshtypes/meshtype_3d_cecum1.py b/src/scaffoldmaker/meshtypes/meshtype_3d_cecum1.py index 09d961be..58db44f4 100644 --- a/src/scaffoldmaker/meshtypes/meshtype_3d_cecum1.py +++ b/src/scaffoldmaker/meshtypes/meshtype_3d_cecum1.py @@ -1190,7 +1190,7 @@ def createCecumMesh3d(region, options, networkLayout, nodeIdentifier, elementIde for n in range(elementsCountAroundOstium): d3 = vector.normalise(vector.crossproduct3(vector.normalise(d2AnnulusOuter[n]), d1AnnulusNorm[n])) d3Annulus.append(d3) - annulusD2Curvature = interp.findCurvatureAroundLoop(xAnnulusOuter, d2AnnulusOuter, d3Annulus) + annulusD2Curvature = interp.getCurvaturesAlongCurve(xAnnulusOuter, d2AnnulusOuter, d3Annulus, loop=True) # # Visualise annulus # for n1 in range(len(xAnnulusOuter)): @@ -1555,14 +1555,14 @@ def createCecumMesh3d(region, options, networkLayout, nodeIdentifier, elementIde for n2 in range(1 if segmentIdx == 0 else 0, elementsCountAlongSegment + 1): if n2 < startRowIdx or n2 > endRowIdx: #== elementsCountAlongSegment: - d1Curvature.append(interp.findCurvatureAlongLine(xAroundAlong[n2], d1AroundAlongOriginal[n2], + d1Curvature.append(interp.getCurvaturesAlongCurve(xAroundAlong[n2], d1AroundAlongOriginal[n2], d3UnitAroundAlong[n2])) else: - d1CurvatureLeft = interp.findCurvatureAlongLine(xAroundAlong[n2][:int(0.5 * len(xAroundAlong[n2]))], + d1CurvatureLeft = interp.getCurvaturesAlongCurve(xAroundAlong[n2][:int(0.5 * len(xAroundAlong[n2]))], d1AroundAlongOriginal[n2][:int(0.5 * len(xAroundAlong[n2]))], d3UnitAroundAlong[n2][:int(0.5 * len(xAroundAlong[n2]))]) - d1CurvatureRight = interp.findCurvatureAlongLine(xAroundAlong[n2][int(0.5 * len(xAroundAlong[n2])):], + d1CurvatureRight = interp.getCurvaturesAlongCurve(xAroundAlong[n2][int(0.5 * len(xAroundAlong[n2])):], d1AroundAlongOriginal[n2][int(0.5 * len(xAroundAlong[n2])):], d3UnitAroundAlong[n2][int(0.5 * len(xAroundAlong[n2])):]) d1Curvature.append(d1CurvatureLeft + d1CurvatureRight) @@ -1585,7 +1585,7 @@ def createCecumMesh3d(region, options, networkLayout, nodeIdentifier, elementIde for n2 in range(elementsCountAlongSegment): d3UnitAlong.append(d3UnitAroundAlong[n2][n1]) d3UnitAlong.append(d3UnitAroundAlong[n2 + 1][n1]) - d2CurvatureAlong = interp.findCurvatureAlongLine(xAlong, d2Along, d3UnitAlong) + d2CurvatureAlong = interp.getCurvaturesAlongCurve(xAlong, d2Along, d3UnitAlong) for n2 in range(len(d2CurvatureAlong)): d2Curvature[n2][n1] = d2CurvatureAlong[n2] @@ -1594,7 +1594,7 @@ def createCecumMesh3d(region, options, networkLayout, nodeIdentifier, elementIde for n2 in range(elementsCountAlongSegment): d3UnitAlong.append(d3UnitAroundAlong[n2][n1]) d3UnitAlong.append(d3UnitAroundAlong[n2 + 1][n1]) - d2CurvatureAlong = interp.findCurvatureAlongLine(xAlong[:startRowIdx + 1], nd2AlongBottomLHS, + d2CurvatureAlong = interp.getCurvaturesAlongCurve(xAlong[:startRowIdx + 1], nd2AlongBottomLHS, d3UnitAlong[:startRowIdx + 1]) # Curvature of nodes along LHS annulus @@ -1602,7 +1602,7 @@ def createCecumMesh3d(region, options, networkLayout, nodeIdentifier, elementIde d2CurvatureAlong.append(d1Curvature[m + startRowIdx + 1][n1]) # From annulus to distal end - d2CurvatureAlong += interp.findCurvatureAlongLine(xAlong[endRowIdx:], nd2AlongTopLHS, + d2CurvatureAlong += interp.getCurvaturesAlongCurve(xAlong[endRowIdx:], nd2AlongTopLHS, d3UnitAlong[endRowIdx:]) for n2 in range(len(d2CurvatureAlong)): @@ -1616,7 +1616,7 @@ def createCecumMesh3d(region, options, networkLayout, nodeIdentifier, elementIde # From apex to annulus for n2 in range(len(pxAlongMidLine)): d3UnitAlong.append(d3UnitAroundAlong[n2][n1]) - d2CurvatureAlong = interp.findCurvatureAlongLine(pxAlongMidLine, pd2AlongMidLine, d3UnitAlong) + d2CurvatureAlong = interp.getCurvaturesAlongCurve(pxAlongMidLine, pd2AlongMidLine, d3UnitAlong) d2CurvatureAnnulusZero = d2CurvatureAlong[-1] for n2 in range(len(d2CurvatureAlong) - 1): d2Curvature[n2][n1] = d2CurvatureAlong[n2] @@ -1624,7 +1624,7 @@ def createCecumMesh3d(region, options, networkLayout, nodeIdentifier, elementIde d3UnitAlong = [] for n in range(len(pxAlongMidLineBottom)): d3UnitAlong.append(d3UnitAroundAlong[n + endRowIdx][n1]) - d2CurvatureAlong = interp.findCurvatureAlongLine(pxAlongMidLineBottom, pd2AlongMidLineBottom, d3UnitAlong) + d2CurvatureAlong = interp.getCurvaturesAlongCurve(pxAlongMidLineBottom, pd2AlongMidLineBottom, d3UnitAlong) d2CurvatureAlongHalfOstium = d2CurvatureAlong[0] for n in range(1, len(pd2AlongMidLineBottom)): nIdx = n + endRowIdx @@ -1635,7 +1635,7 @@ def createCecumMesh3d(region, options, networkLayout, nodeIdentifier, elementIde for n2 in range(elementsCountAlongSegment): d3UnitAlong.append(d3UnitAroundAlong[n2][n1 + (0 if (n2 < startRowIdx or n2 > endRowIdx) else -1)]) d3UnitAlong.append(d3UnitAroundAlong[n2 + 1][n1]) - d2CurvatureAlong = interp.findCurvatureAlongLine(xAlong[:startRowIdx + 1], nd2AlongBottomRHS, + d2CurvatureAlong = interp.getCurvaturesAlongCurve(xAlong[:startRowIdx + 1], nd2AlongBottomRHS, d3UnitAlong[:startRowIdx + 1]) # Curvature of nodes along LHS annulus @@ -1643,7 +1643,7 @@ def createCecumMesh3d(region, options, networkLayout, nodeIdentifier, elementIde d2CurvatureAlong.append(d1Curvature[m + startRowIdx + 1][n1 - 1]) # From annulus to distal end - d2CurvatureAlong += interp.findCurvatureAlongLine(xAlong[endRowIdx:], nd2AlongTopRHS, + d2CurvatureAlong += interp.getCurvaturesAlongCurve(xAlong[endRowIdx:], nd2AlongTopRHS, d3UnitAlong[endRowIdx:]) for n2 in range(len(d2CurvatureAlong)): @@ -1661,7 +1661,7 @@ def createCecumMesh3d(region, options, networkLayout, nodeIdentifier, elementIde for n2 in range(elementsCountAlongSegment): d3UnitAlong.append(d3UnitAroundAlong[n2][n1 + (0 if (n2 < startRowIdx or n2 > endRowIdx) else -1)]) d3UnitAlong.append(d3UnitAroundAlong[n2 + 1][n1]) - d2CurvatureAlong = interp.findCurvatureAlongLine(xAlong, d2Along, d3UnitAlong) + d2CurvatureAlong = interp.getCurvaturesAlongCurve(xAlong, d2Along, d3UnitAlong) # Adjust for corners if n1 == elementsCountAroundHalfHaustrum: diff --git a/src/scaffoldmaker/utils/interpolation.py b/src/scaffoldmaker/utils/interpolation.py index da94d2e8..967426dd 100644 --- a/src/scaffoldmaker/utils/interpolation.py +++ b/src/scaffoldmaker/utils/interpolation.py @@ -1474,42 +1474,28 @@ def getNearestLocationBetweenCurves(nx, nd1, ox, od1, nLoop=False, oLoop=False, 'closeness in xi', mag_dxi) return location, otherLocation, False - -def findCurvatureAroundLoop(nx, nd, radialVectors): - """ - Calculate curvature for points lying along a loop. - :param nx: points on loop - :param nd: derivative of points on loop - :param radialVectors: radial direction, assumed normal to curve tangent at point - :return: curvatures along points on loop - """ - curvature = [] - for n in range(len(nx)): - prevIdx = n - 1 if n > 0 else -1 - nextIdx = n + 1 if n < len(nx) - 1 else 0 - kappam = getCubicHermiteCurvature(nx[prevIdx], nd[prevIdx], nx[n], nd[n], radialVectors[n], 1.0) - kappap = getCubicHermiteCurvature(nx[n], nd[n], nx[nextIdx], nd[nextIdx], radialVectors[n], 0.0) - curvature.append(0.5 * (kappam + kappap)) - - return curvature - -def findCurvatureAlongLine(nx, nd, radialVectors): - """ - Calculate curvature for points lying along a line. - :param nx: points on line - :param nd: derivative of points on line - :param radialVectors: radial direction, assumed normal to curve tangent at point - :return: curvatures along points on line - """ - curvature = [] - for n in range(len(nx)): - if n == 0: - curvature.append(getCubicHermiteCurvature(nx[n], nd[n], nx[n + 1], nd[n + 1], radialVectors[n], 0.0)) - elif n == len(nx) - 1: - curvature.append(getCubicHermiteCurvature(nx[n - 1], nd[n - 1], nx[n], nd[n], radialVectors[n], 1.0)) - else: - curvature.append(0.5 * ( - getCubicHermiteCurvature(nx[n], nd[n], nx[n + 1], nd[n + 1], radialVectors[n], 0.0) + - getCubicHermiteCurvature(nx[n - 1], nd[n - 1], nx[n], nd[n], radialVectors[n], 1.0))) - - return curvature +def getCurvaturesAlongCurve(cx, cd, radialVectors, loop=False): + """ + Calculate curvatures for points lying along a curve. + :param cx: coordinates on curve + :param cd: derivative of coordinates on curve + :param radialVectors: radial direction, assumed normal to curve tangent at coordinate + :param loop: True if curve is a closed loop + :return: curvatures along coordinates on curve + """ + curvatures = [] + cCount = len(cx) + for c in range(cCount): + kappa = None + if (c > 0) or loop: + cm = c - 1 + kappa = getCubicHermiteCurvature(cx[cm], cd[cm], cx[c], cd[c], radialVectors[c], 1.0) + if (c < (cCount - 1)) or loop: + cp = c + 1 - cCount + kappap = getCubicHermiteCurvature(cx[c], cd[c], cx[cp], cd[cp], radialVectors[c], 0.0) + if kappa is None: + kappa = kappap + else: + kappa = 0.5 * (kappa + kappap) + curvatures.append(kappa) + return curvatures