1 /**
2  * Copyright 2007-2021 IMP Inventors. All rights reserved.
3  */
4 
5 #include <boost/lexical_cast.hpp>
6 #include <exception>
7 #include <iostream>
8 #include <sstream>
9 #include <string>
10 
11 #include "RMF/FileConstHandle.h"
12 #include "RMF/FileHandle.h"
13 #include "RMF/ID.h"
14 #include "RMF/NodeHandle.h"
15 #include "RMF/Vector.h"
16 #include "RMF/decorator/physics.h"
17 #include "RMF/decorator/shape.h"
18 #include "RMF/infrastructure_macros.h"
19 #include "RMF/log.h"
20 #include "RMF/types.h"
21 #include "RMF/utility.h"
22 #include "common.h"
23 
24 #define RMF_TRANSFORM(f, Name, attribute)       \
25   if (f.get_is(nh)) {                           \
26     RMF::decorator::Name d = f.get(nh);         \
27     RMF::Vector3 cs = d.get_##attribute();      \
28     for (unsigned int i = 0; i < 3; ++i) {      \
29       cs[i] = scale * (cs[i] + translation[i]); \
30     }                                           \
31     d.set_##attribute(cs);                      \
32   }
33 
34 #define RMF_TRANSFORM_LIST(f, Name, attribute)          \
35   if (f.get_is(nh)) {                                   \
36     RMF::decorator::Name d = f.get(nh);                 \
37     RMF::Vector3s cs = d.get_##attribute();             \
38     for (unsigned int j = 0; j < cs.size(); ++j) {      \
39       for (unsigned int i = 0; i < 3; ++i) {            \
40         cs[j][i] = scale * (cs[j][i] + translation[i]); \
41       }                                                 \
42     }                                                   \
43     d.set_##attribute(cs);                              \
44   }
45 
46 namespace {
47 std::string description(
48     "Transform an rmf file in place. IntermediateParticle, Ball, Cylinder, "
49     "Segment, RigidParticle and ReferenceFrame nodes are handled.");
50 
transform(RMF::NodeHandle nh,RMF::decorator::IntermediateParticleFactory ipf,RMF::decorator::RigidParticleFactory rpf,RMF::decorator::ReferenceFrameFactory rff,RMF::decorator::BallFactory bf,RMF::decorator::CylinderFactory cf,RMF::decorator::SegmentFactory sf,double scale,const RMF::Floats & translation)51 void transform(RMF::NodeHandle nh,
52                RMF::decorator::IntermediateParticleFactory ipf,
53                RMF::decorator::RigidParticleFactory rpf,
54                RMF::decorator::ReferenceFrameFactory rff,
55                RMF::decorator::BallFactory bf,
56                RMF::decorator::CylinderFactory cf,
57                RMF::decorator::SegmentFactory sf, double scale,
58                const RMF::Floats& translation) {
59   RMF_TRANSFORM(ipf, IntermediateParticle, coordinates)
60   else RMF_TRANSFORM(rpf, RigidParticle, coordinates);
61   if (ipf.get_is(nh)) {
62     RMF::decorator::IntermediateParticle d = ipf.get(nh);
63     d.set_radius(scale * d.get_radius());
64   }
65   RMF_TRANSFORM(rff, ReferenceFrame, translation);
66   RMF_TRANSFORM(bf, Ball, coordinates);
67   RMF_TRANSFORM_LIST(cf, Cylinder, coordinates_list);
68   RMF_TRANSFORM_LIST(sf, Segment, coordinates_list);
69   RMF::NodeHandles children = nh.get_children();
70   for (unsigned int i = 0; i < children.size(); ++i) {
71     transform(children[i], ipf, rpf, rff, bf, cf, sf, scale, translation);
72   }
73 }
74 }
75 
main(int argc,char ** argv)76 int main(int argc, char** argv) {
77   try {
78     double scale = 1;
79     std::string translation_str;
80     options.add_options()("scale,s",
81                           boost::program_options::value<double>(&scale),
82                           "What to scale the model by")(
83         "translation,t",
84         boost::program_options::value<std::string>(&translation_str),
85         "What to translate the model by as \"x y z\"");
86     RMF_ADD_INPUT_FILE("rmf");
87     RMF_ADD_OUTPUT_FILE("rmf");
88     process_options(argc, argv);
89     RMF::Floats translation;
90     if (!translation_str.empty()) {
91       std::istringstream iss(translation_str);
92       for (unsigned int i = 0; i < 3; ++i) {
93         double c;
94         iss >> c;
95         if (!iss) {
96           std::cerr << "Bad translation" << std::endl;
97           print_help_and_exit(argv);
98         }
99         translation.push_back(c);
100       }
101     } else {
102       translation = RMF::Floats(0, 3);
103     }
104     RMF_INFO("Scaling model by " << scale);
105     RMF_INFO("Translating model by " << translation[0] << " " << translation[1]
106                                      << " " << translation[2]);
107 
108     RMF::FileConstHandle rhi = RMF::open_rmf_file_read_only(input);
109     RMF::FileHandle rh = RMF::create_rmf_file(output);
110     RMF::clone_file_info(rhi, rh);
111     RMF::clone_hierarchy(rhi, rh);
112     RMF::clone_static_frame(rhi, rh);
113     RMF::decorator::IntermediateParticleFactory ipf(rh);
114     RMF::decorator::RigidParticleFactory rpf(rh);
115     RMF::decorator::ReferenceFrameFactory rff(rh);
116     RMF::decorator::BallFactory bf(rh);
117     RMF::decorator::CylinderFactory cf(rh);
118     RMF::decorator::SegmentFactory sf(rh);
119     RMF_FOREACH(RMF::FrameID frame, rhi.get_frames()) {
120       RMF::clone_loaded_frame(rhi, rh);
121       RMF_INFO("Processing frame " << frame);
122       rh.set_current_frame(frame);
123       transform(rh.get_root_node(), ipf, rpf, rff, bf, cf, sf, scale,
124                 translation);
125     }
126     return 0;
127   }
128   catch (const std::exception& e) {
129     std::cerr << "Error: " << e.what() << std::endl;
130     print_help_and_exit(argv);
131   }
132 }
133