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