| 1 | from mantid.kernel import * |
|---|
| 2 | from mantid.api import * |
|---|
| 3 | |
|---|
| 4 | # Author: E. Farhi <farhi@ill.fr> |
|---|
| 5 | # Date: June 19th 2014 |
|---|
| 6 | # Description: IDF to PLY/OFF converter |
|---|
| 7 | |
|---|
| 8 | class IDF_to_PLY(PythonAlgorithm): |
|---|
| 9 | |
|---|
| 10 | def category(self): |
|---|
| 11 | return 'Utilities' |
|---|
| 12 | |
|---|
| 13 | def PyInit(self): |
|---|
| 14 | # Declare properties |
|---|
| 15 | self.declareProperty(FileProperty(name="InputFile",defaultValue="", |
|---|
| 16 | action=FileAction.Load, extensions = ["xml","hdf","nxs"]), |
|---|
| 17 | doc="An input file with associated instrument definition (IDF/XML in MANTIDPATH/instrument, NeXus or HDF)") |
|---|
| 18 | |
|---|
| 19 | # output direction specified explicitly |
|---|
| 20 | self.declareProperty(FileProperty(name="OutputFile",defaultValue="instrument_Description", |
|---|
| 21 | action=FileAction.Save, extensions = ["off","ply"]), |
|---|
| 22 | doc="The output file name where the geometry will be saved") |
|---|
| 23 | |
|---|
| 24 | # the type of Data File generated |
|---|
| 25 | self.declareProperty("OutputFormat","OFF", StringListValidator(["OFF","PLY"])) |
|---|
| 26 | |
|---|
| 27 | def PyExec(self): |
|---|
| 28 | # Run the algorithm |
|---|
| 29 | |
|---|
| 30 | # Load the Instrument Definition File (IDF) e.g. XML or from NXS |
|---|
| 31 | ws = Load(Filename=self.getPropertyValue("InputFile")) |
|---|
| 32 | |
|---|
| 33 | inst = ws.getInstrument() |
|---|
| 34 | |
|---|
| 35 | nhist = ws.getNumberHistograms() |
|---|
| 36 | |
|---|
| 37 | self.log().information( "IDF_to_PLY: Opening instrument " + inst.getName() + " definition from file " + self.getPropertyValue("InputFile") + " with " + str(nhist) + " pixels.") |
|---|
| 38 | |
|---|
| 39 | name = self.getPropertyValue("OutputFile") |
|---|
| 40 | fid = open(name, "w") |
|---|
| 41 | |
|---|
| 42 | self.log().information( "IDF_to_PLY: Generating output file " + self.getPropertyValue("OutputFile") ) |
|---|
| 43 | |
|---|
| 44 | # Mantid::Geometry::OCGeometryGenerator |
|---|
| 45 | # methods: getNumberOfPoints, getNumberOfTriangles, getTriangleFaces, getTriangleVertices |
|---|
| 46 | |
|---|
| 47 | nb_vertices = 0 |
|---|
| 48 | nb_polygons = 0 |
|---|
| 49 | vout = "" |
|---|
| 50 | pout = "" |
|---|
| 51 | |
|---|
| 52 | # traverse all detector pixels |
|---|
| 53 | for i in range(nhist): |
|---|
| 54 | det = ws.getDetector(i); |
|---|
| 55 | if not det.isMonitor(): |
|---|
| 56 | # det.getPos() is the position of the detector object, whatever be its internal shape and definition of origin |
|---|
| 57 | # we thus prefer to use the shape and its bounding box |
|---|
| 58 | |
|---|
| 59 | BBox = det.shape().getBoundingBox() # use .centrePoint() and .width() which are V3D objects |
|---|
| 60 | # create a cuboid from the boundingBox. centerPoint is really at the center of the max-min |
|---|
| 61 | # so we add the +/- width/2 |
|---|
| 62 | pos = BBox.centrePoint() - inst.getSample().getPos() # shift from sample |
|---|
| 63 | x0 = pos.X() |
|---|
| 64 | y0 = pos.Y() |
|---|
| 65 | z0 = pos.Z() |
|---|
| 66 | dx = BBox.width().X()/2.0 |
|---|
| 67 | dy = BBox.width().Y()/2.0 |
|---|
| 68 | dz = BBox.width().Z()/2.0 |
|---|
| 69 | |
|---|
| 70 | i = nb_vertices # offset for vertices index |
|---|
| 71 | |
|---|
| 72 | # write the X Y Z coordinate of Detector BBox position wrt sample |
|---|
| 73 | vout += '%g %g %g\n' % (x0+dx, y0-dy, z0-dz) |
|---|
| 74 | vout += '%g %g %g\n' % (x0-dx, y0+dy, z0-dz) |
|---|
| 75 | vout += '%g %g %g\n' % (x0-dx, y0-dy, z0+dz) |
|---|
| 76 | vout += '%g %g %g\n' % (x0-dx, y0-dy, z0-dz) |
|---|
| 77 | vout += '%g %g %g\n' % (x0+dx, y0-dy, z0+dz) |
|---|
| 78 | vout += '%g %g %g\n' % (x0+dx, y0+dy, z0-dz) |
|---|
| 79 | vout += '%g %g %g\n' % (x0+dx, y0+dy, z0+dz) |
|---|
| 80 | vout += '%g %g %g\n' % (x0-dx, y0+dy, z0+dz) |
|---|
| 81 | nb_vertices += 8 |
|---|
| 82 | |
|---|
| 83 | # write the connections after the vertices |
|---|
| 84 | pout += '%i %i %i %i %i\n' % (4, 0+i, 5+i, 6+i, 4+i) |
|---|
| 85 | pout += '%i %i %i %i %i\n' % (4, 1+i, 5+i, 6+i, 7+i) |
|---|
| 86 | pout += '%i %i %i %i %i\n' % (4, 2+i, 4+i, 6+i, 7+i) |
|---|
| 87 | pout += '%i %i %i %i %i\n' % (4, 3+i, 0+i, 4+i, 2+i) |
|---|
| 88 | pout += '%i %i %i %i %i\n' % (4, 3+i, 0+i, 5+i, 1+i) |
|---|
| 89 | pout += '%i %i %i %i %i\n' % (4, 3+i, 1+i, 7+i, 2+i) |
|---|
| 90 | nb_polygons += 6 |
|---|
| 91 | |
|---|
| 92 | # get the file type to export, write the file content |
|---|
| 93 | if self.getPropertyValue("InputFile") == 'OFF': |
|---|
| 94 | fid.write("OFF\n") # 1st line, mandatory |
|---|
| 95 | fid.write("# This is an Object File Format (geomview). Use e.g. Meshlab to view it.\n") |
|---|
| 96 | fid.write("# nb points, nb faces, void\n") |
|---|
| 97 | fid.write("# List point coordinates\n") |
|---|
| 98 | fid.write("%i %i 0\n" % (nb_vertices,nb_polygons)) # nb points, nb faces, void |
|---|
| 99 | fid.write(vout) |
|---|
| 100 | fid.write("# List faces, all rectangular\n") |
|---|
| 101 | fid.write(pout) |
|---|
| 102 | else: |
|---|
| 103 | fid.write("ply\n") |
|---|
| 104 | fid.write("format ascii 1.0\n") |
|---|
| 105 | fid.write("comment " + inst.getName() + " geometry (Mantid IDF) from file " + self.getPropertyValue("InputFile") + "\n") |
|---|
| 106 | fid.write("comment This is an PLY File Format. Use e.g. Meshlab to view it.\n") |
|---|
| 107 | fid.write("element vertex %i\n" % (nb_vertices)) |
|---|
| 108 | fid.write("property float32 x\n") |
|---|
| 109 | fid.write("property float32 y\n") |
|---|
| 110 | fid.write("property float32 z\n") |
|---|
| 111 | fid.write("element face %i\n" % (nb_polygons)) |
|---|
| 112 | fid.write("property list uint8 int32 vertex_indices\n") |
|---|
| 113 | fid.write("end_header\n") |
|---|
| 114 | fid.write(vout) |
|---|
| 115 | fid.write(pout) |
|---|
| 116 | |
|---|
| 117 | self.log().information( "IDF_to_PLY: " + inst.getName() + " written to " + self.getPropertyValue("OutputFile") + " with %i vertices and %i polygons" % (nb_vertices, nb_polygons) ) |
|---|
| 118 | #deleteWorkspace(ws) |
|---|
| 119 | # The above line deletes is supposed to delete the workspace, however causes the Algorithm to crash, so it has been commented out. |
|---|
| 120 | |
|---|
| 121 | # Register algorithm with Mantid |
|---|
| 122 | AlgorithmFactory.subscribe(IDF_to_PLY) |
|---|