Developer Documentation
FileHeightFieldImage.cc
1 /*===========================================================================*\
2  * *
3  * OpenFlipper *
4  * Copyright (c) 2001-2015, RWTH-Aachen University *
5  * Department of Computer Graphics and Multimedia *
6  * All rights reserved. *
7  * www.openflipper.org *
8  * *
9  *---------------------------------------------------------------------------*
10  * This file is part of OpenFlipper. *
11  *---------------------------------------------------------------------------*
12  * *
13  * Redistribution and use in source and binary forms, with or without *
14  * modification, are permitted provided that the following conditions *
15  * are met: *
16  * *
17  * 1. Redistributions of source code must retain the above copyright notice, *
18  * this list of conditions and the following disclaimer. *
19  * *
20  * 2. Redistributions in binary form must reproduce the above copyright *
21  * notice, this list of conditions and the following disclaimer in the *
22  * documentation and/or other materials provided with the distribution. *
23  * *
24  * 3. Neither the name of the copyright holder nor the names of its *
25  * contributors may be used to endorse or promote products derived from *
26  * this software without specific prior written permission. *
27  * *
28  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *
29  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *
30  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
31  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER *
32  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, *
33  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, *
34  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR *
35  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
36  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING *
37  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS *
38  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
39  * *
40 \*===========================================================================*/
41 
42 #include "FileHeightFieldImage.hh"
43 #include "ImageDialog.hh"
44 
45 #include <QImageReader>
46 #include <QThread>
47 
49 }
50 
52  QList<QByteArray> imageFormats = QImageReader::supportedImageFormats();
53  QString formats;
54 
55  if ( imageFormats.contains("jpeg")) {
56  formats += "*.jpeg *.jpg ";
57  }
58 
59  if ( imageFormats.contains("tiff")) {
60  formats += "*.tiff ";
61  }
62 
63  if ( imageFormats.contains("tif")) {
64  formats += "*.tif ";
65  }
66 
67  if ( imageFormats.contains("png")) {
68  formats += "*.png";
69  }
70 
71  return QString( tr("HeightField PNG files ( ")+ formats + ")" );
72 };
73 
75  return QString( "" );
76 };
77 
80  return type;
81 }
82 
83 bool FileHeightFieldPNGPlugin::showImageDialog(const QImage& _image, int* _minX, int* _maxX, int* _minY, int* _maxY, double* _height)
84 {
85  ImageDialog imageDialog(_image);
86  imageDialog.heightValue->setValue(*_height);
87 
88  int result = imageDialog.exec();
89 
90  if ( result == QDialog::Accepted) {
91  *_minX = imageDialog.minX->value();
92  *_maxX = imageDialog.maxX->value();
93  *_minY = imageDialog.minY->value();
94  *_maxY = imageDialog.maxY->value();
95  *_height = imageDialog.heightValue->value();
96  } else {
97  return false;
98  }
99  return true;
100 }
101 
102 
103 int FileHeightFieldPNGPlugin::loadObject(QString _filename)
104 {
105 
106  QFile file(_filename);
107  if ( !file.exists() ) {
108  emit log(LOGERR,tr("Unable to load file: ") + _filename);
109  return -1;
110  }
111 
112  QImage image(_filename);
113 
114  // Prepare for taking specific regions from the file (defaults to full size)
115  int minX = 0;
116  int maxX = image.width();
117 
118  int minY = 0;
119  int maxY = image.height();
120 
121  // Try to calculate a reasonable height
122  double height = image.height() / 100;
123 
124  if ( OpenFlipper::Options::gui() ) {
125 
126  bool ret = false;
127  QMetaObject::invokeMethod(this,"showImageDialog",
128  // execute widget in main thread
129  (QThread::currentThread() != QApplication::instance()->thread()) ? Qt::BlockingQueuedConnection: Qt::DirectConnection,
130  Q_RETURN_ARG(bool, ret),
131  Q_ARG(const QImage&, image),
132  Q_ARG(int*,&minX),
133  Q_ARG(int*,&maxX),
134  Q_ARG(int*,&minY),
135  Q_ARG(int*,&maxY),
136  Q_ARG(double*,&height));
137  if (!ret)
138  return -1;
139  }
140 
141 
142  int id = -1;
143  emit addEmptyObject( DATA_TRIANGLE_MESH, id );
144 
145  TriMeshObject* object = 0;
146  if(PluginFunctions::getObject( id, object))
147  {
148  TriMesh* mesh = object->mesh();
149 
150  if ( mesh ) {
151 
152 
153  // Load the data into the mesh.
154  loadImageAsTriangleMesh(image,mesh,minX ,maxX , minY ,maxY, height);
155 
156  // Make sure everything is ready
157  emit updatedObject(object->id(), UPDATE_ALL);
158 
159  // Tell core about update
160  emit openedFile( id );
161 
162  }
163  }
164 
165  return id;
166 }
167 
168 void FileHeightFieldPNGPlugin::loadImageAsTriangleMesh(QImage& _image,TriMesh* _mesh,int _minX , int _maxX , int _minY , int _maxY, double _height) {
169 
170  const int mWidth = _maxY - _minY;
171  const int mHeigth = _maxX - _minX;
172 
173  // Reserve to get reasonable memory usage
174  _mesh->reserve( mWidth*mHeigth, mWidth*mHeigth * 4, mWidth*mHeigth * 2 );
175 
176  for ( int i = _minX ; i < _maxX ; ++i ) {
177  for ( int j = _minY ; j < _maxY ; ++j ) {
178  const QColor currentColor = _image.pixel(i,j);
179  double value = std::max(currentColor.redF(),currentColor.blueF());
180  value = std::max(currentColor.greenF(),value);
181  TriMesh::VertexHandle vh = _mesh->add_vertex(TriMesh::Point(i,j,-value * _height));
182  _mesh->set_color(vh,TriMesh::Color(currentColor.redF(),currentColor.greenF(),currentColor.blueF(),1.0f));
183  }
184  }
185 
186  // Triangulate
187  for ( int i = 0 ; i < mHeigth - 1 ; ++i ) {
188  const int upperStart = mWidth * i;
189  const int lowerStart = mWidth * (i + 1);
190 
191  for ( int j = 0 ; j < mWidth -1 ; ++j ) {
192  std::vector<TriMesh::VertexHandle> handles;
193  handles.push_back( _mesh->vertex_handle(upperStart + j) );
194  handles.push_back( _mesh->vertex_handle(lowerStart + j + 1) );
195  handles.push_back( _mesh->vertex_handle(lowerStart + j) );
196 
197 
198  _mesh->add_face(handles);
199 
200  handles.clear();
201 
202  handles.push_back( _mesh->vertex_handle(upperStart + j) );
203  handles.push_back( _mesh->vertex_handle(upperStart + j + 1) );
204  handles.push_back( _mesh->vertex_handle(lowerStart + j + 1) );
205 
206  _mesh->add_face(handles);
207  }
208  }
209 
210  //Calculate some normals
211  _mesh->update_normals();
212 }
213 
214 
215 bool FileHeightFieldPNGPlugin::saveObject(int _id, QString _filename) {
216  return false;
217 }
218 
219 
220 
#define DATA_TRIANGLE_MESH
Definition: TriangleMesh.hh:60
const UpdateType UPDATE_ALL(UpdateTypeSet(1))
Identifier for all updates.
DataType supportedType()
Return your supported object type( e.g. DATA_TRIANGLE_MESH )
Kernel::Color Color
Color type.
Definition: PolyMeshT.hh:116
Kernel::Point Point
Coordinate type.
Definition: PolyMeshT.hh:112
bool getObject(const int _identifier, BaseObject *&_object)
Get the object which has the given identifier.
void initializePlugin()
Initialize Plugin.
Predefined datatypes.
Definition: DataTypes.hh:83
int id() const
Definition: BaseObject.cc:190
Type for a MeshObject containing a triangle mesh.
Definition: TriangleMesh.hh:67
Kernel::VertexHandle VertexHandle
Handle for referencing the corresponding item.
Definition: PolyMeshT.hh:136