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
83bool 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
103int 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
168void 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 float value = std::max((float)currentColor.redF(),(float)currentColor.blueF());
180 value = std::max((float)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
215bool FileHeightFieldPNGPlugin::saveObject(int _id, QString _filename) {
216 return false;
217}
218
219
220
@ LOGERR
#define DATA_TRIANGLE_MESH
Definition: TriangleMesh.hh:60
int id() const
Definition: BaseObject.cc:188
Predefined datatypes.
Definition: DataTypes.hh:83
void initializePlugin()
Initialize Plugin.
DataType supportedType()
Return your supported object type( e.g. DATA_TRIANGLE_MESH )
Kernel::VertexHandle VertexHandle
Handle for referencing the corresponding item.
Definition: PolyMeshT.hh:136
Kernel::Point Point
Coordinate type.
Definition: PolyMeshT.hh:112
Kernel::Color Color
Color type.
Definition: PolyMeshT.hh:116
Type for a MeshObject containing a triangle mesh.
Definition: TriangleMesh.hh:67
const UpdateType UPDATE_ALL(UpdateTypeSet(1))
Identifier for all updates.
bool getObject(const int _identifier, BaseObject *&_object)
Get the object which has the given identifier.