File indexing completed on 2024-04-28 03:40:49
0001 /************************************************************************************* 0002 * Copyright (C) 2012 by Percy Camilo T. Aucahuasi <percy.camilo.ta@gmail.com> * 0003 * * 0004 * This program is free software; you can redistribute it and/or * 0005 * modify it under the terms of the GNU General Public License * 0006 * as published by the Free Software Foundation; either version 2 * 0007 * of the License, or (at your option) any later version. * 0008 * * 0009 * This program is distributed in the hope that it will be useful, * 0010 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 0011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 0012 * GNU General Public License for more details. * 0013 * * 0014 * You should have received a copy of the GNU General Public License * 0015 * along with this program; if not, write to the Free Software * 0016 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA * 0017 *************************************************************************************/ 0018 0019 #include "marchingsquares.h" 0020 #include <QDebug> 0021 #include <QPolygon> 0022 #include <QVector2D> 0023 0024 sMarching_Square MarchingSquares::evaluar_cubo(const Square& cubo) 0025 { 0026 sMarching_Square res; 0027 res.centro = cubo.center(); 0028 res.medio_lado = cubo.halfEdge(); 0029 0030 double x = res.centro.x(); 0031 double y = res.centro.y(); 0032 double hedge = res.medio_lado; 0033 0034 res.vertices[0] = evalScalarField(x-hedge, y-hedge); 0035 res.vertices[1] = evalScalarField(x-hedge, y+hedge); 0036 res.vertices[2] = evalScalarField(x+hedge, y-hedge); 0037 res.vertices[3] = evalScalarField(x+hedge, y+hedge); 0038 0039 0040 // ----- 0041 // |1|3| 0042 // ----- 0043 // |0|2| 0044 // ----- 0045 0046 res.tipo = 0; 0047 0048 if (res.vertices[1]>0) 0049 res.tipo += 8; 0050 0051 if (res.vertices[3]>0) 0052 res.tipo += 4; 0053 0054 if (res.vertices[2]>0) 0055 res.tipo += 2; 0056 0057 if (res.vertices[0]>0) 0058 res.tipo += 1; 0059 0060 return res; 0061 } 0062 0063 QList<Square> MarchingSquares::breadth_rec(int cubos_lado) { 0064 Square cubo; 0065 sMarching_Square m_cubo; 0066 bool salir = false; 0067 QList<Square> cubos; 0068 cubo.setHalfEdge(largo_mundo/(2*cubos_lado)); 0069 0070 double x = 0; 0071 double y = 0; 0072 0073 static const double iteration_square_val = 0.5; 0074 0075 for(double i=mundo.minX; i<=mundo.maxX; i+=iteration_square_val) 0076 { 0077 x = (2*i+1)*cubo.halfEdge(); 0078 0079 for(double j=mundo.minY; j<=mundo.maxY; j+=iteration_square_val) 0080 { 0081 y = (2*j+1)*cubo.halfEdge(); 0082 cubo.setCenter(x,y); 0083 m_cubo = evaluar_cubo(cubo); 0084 if(m_cubo.tipo != 0 && m_cubo.tipo != 15) { 0085 //Esta dentro del cubo. Detener busqueda 0086 salir = true; 0087 cubos.append(cubo); 0088 } 0089 } 0090 } 0091 0092 if(!salir && 2*cubo.halfEdge() > min_grid) 0093 cubos.append(breadth_rec(cubos_lado*2)); 0094 0095 return cubos; 0096 } 0097 0098 QList<sMarching_Square> MarchingSquares::depth_rec(Quadtree *arbol, QNode *nodo) { 0099 QList<sMarching_Square> cubos; 0100 sMarching_Square m_cubo; 0101 0102 m_cubo = evaluar_cubo(nodo->cubo); 0103 0104 if(m_cubo.tipo != 0 && m_cubo.tipo != 15) { 0105 if(m_cubo.medio_lado*2 > min_grid) { 0106 arbol->bajarNivel(nodo); 0107 for(unsigned int i=0; i<4; i++) { 0108 cubos.append(depth_rec(arbol,nodo->nodos[i])); 0109 } 0110 } else { 0111 cubos.append(m_cubo); 0112 } 0113 } 0114 return cubos; 0115 } 0116 0117 MarchingSquares::MarchingSquares(/*double min_grid, double arista_mundo, sLimitesEspacio2D limites*/ 0118 0119 ) { 0120 } 0121 0122 MarchingSquares::~MarchingSquares() { 0123 } 0124 0125 QList<sMarching_Square> MarchingSquares::ejecutar() { 0126 QList<sMarching_Square> cubos; 0127 QList<Square> encontrados; 0128 Square iterador; 0129 Quadtree *arbol; 0130 0131 encontrados = breadth_rec(largo_mundo); 0132 if(encontrados.isEmpty()) { 0133 return cubos; 0134 } 0135 0136 foreach(iterador, encontrados) { 0137 arbol = new Quadtree(iterador); 0138 cubos.append(depth_rec(arbol, arbol->get_raiz())); 0139 delete arbol; 0140 } 0141 0142 return cubos; 0143 } 0144 0145 void MarchingSquares::_addTri(const QPointF& a, const QPointF& b) 0146 { 0147 QPair<QPointF,QPointF> _f = qMakePair(a,b); 0148 _faces_.append(_f); 0149 0150 } 0151 0152 QList<sArista2D> MarchingSquares::calcular_cortes(const sMarching_Square &cubo) { 0153 QList<sArista2D> aristas; 0154 sArista2D temp; 0155 // ----- 0156 // |1|3| 0157 // ----- 0158 // |0|2| 0159 // ----- 0160 0161 //0-1 0162 if(signo_opuesto(cubo.vertices[0],cubo.vertices[1])) { 0163 //al primero luego sumale 0164 temp.corte = QPointF(cubo.centro.x()-cubo.medio_lado, 0165 cubo.centro.y()-cubo.medio_lado+2*cubo.medio_lado*lineal(cubo.vertices[0],cubo.vertices[1])); 0166 temp.vertices[0] = 0; 0167 temp.vertices[1] = 1; 0168 aristas.append(temp); 0169 } 0170 0171 //1-3 0172 if(signo_opuesto(cubo.vertices[1],cubo.vertices[3])) { 0173 temp.corte = QPointF(cubo.centro.x()-cubo.medio_lado+2*cubo.medio_lado*lineal(cubo.vertices[1],cubo.vertices[3]), 0174 cubo.centro.y()+cubo.medio_lado); 0175 temp.vertices[0] = 1; 0176 temp.vertices[1] = 3; 0177 aristas.append(temp); 0178 } 0179 0180 //2-3 0181 if(signo_opuesto(cubo.vertices[2],cubo.vertices[3])) { 0182 temp.corte = QPointF(cubo.centro.x()+cubo.medio_lado, 0183 cubo.centro.y()-cubo.medio_lado+2*cubo.medio_lado*lineal(cubo.vertices[2],cubo.vertices[3])); 0184 temp.vertices[0] = 2; 0185 temp.vertices[1] = 3; 0186 aristas.append(temp); 0187 } 0188 0189 // ----- 0190 // |1|3| 0191 // ----- 0192 // |0|2| 0193 // ----- 0194 0195 //0-2 0196 if(signo_opuesto(cubo.vertices[0],cubo.vertices[2])) { 0197 temp.corte = QPointF(cubo.centro.x()-cubo.medio_lado+2*cubo.medio_lado*lineal(cubo.vertices[0],cubo.vertices[2]), 0198 cubo.centro.y()-cubo.medio_lado); 0199 temp.vertices[0] = 0; 0200 temp.vertices[1] = 2; 0201 aristas.append(temp); 0202 } 0203 0204 return aristas; 0205 } 0206 0207 bool MarchingSquares::signo_opuesto(double a, double b) { 0208 return ((a > 0 && b <= 0) || (a <= 0 && b > 0)); 0209 } 0210 0211 double MarchingSquares::lineal(double vert_1, double vert_2) { 0212 return qAbs(vert_1/(vert_1 - vert_2)); 0213 } 0214 0215 void MarchingSquares::agregar_triangulos(QList<QPointF> &lista_triangulos) { 0216 0217 for(int i=0; i<lista_triangulos.count(); i+=2) { 0218 0219 if (lista_triangulos.size()-2 < i) 0220 continue; 0221 0222 _addTri(lista_triangulos.at(i),lista_triangulos.at(i+1)); 0223 0224 } 0225 } 0226 0227 void MarchingSquares::identificar_tipo(const sMarching_Square &cubo) { 0228 0229 QList<sArista2D> aristas; 0230 QList<unsigned int> vertices; 0231 0232 aristas = calcular_cortes(cubo); 0233 0234 unsigned short int type = cubo.tipo; 0235 0236 switch (type) 0237 { 0238 case 1: 0239 case 2: 0240 case 3: 0241 case 4: 0242 case 6: 0243 case 7: 0244 case 8: 0245 case 9: 0246 case 11: 0247 case 12: 0248 case 13: 0249 case 14: 0250 { 0251 tipo01(aristas); 0252 0253 break; 0254 } 0255 case 5: 0256 case 10: 0257 { 0258 tipo05(aristas, cubo); 0259 0260 break; 0261 } 0262 } 0263 } 0264 0265 void MarchingSquares::tipo01(QList<sArista2D> aristas) 0266 { 0267 0268 if (aristas.size()<2) return; 0269 0270 QList<QPointF> triangulos; 0271 0272 triangulos << aristas[0].corte << aristas[1].corte; 0273 0274 agregar_triangulos(triangulos); 0275 } 0276 0277 void MarchingSquares::tipo05(QList<sArista2D> aristas,const sMarching_Square &cubo) 0278 { 0279 if (aristas.isEmpty()) return; 0280 0281 QList<QPointF> triangulos; 0282 0283 // ----- 0284 // |1|3| 0285 // ----- 0286 // |0|2| 0287 // ----- 0288 0289 0290 if (cubo.tipo == 5) 0291 triangulos << aristas[0].corte << aristas[2].corte; 0292 else if (cubo.tipo == 10) 0293 triangulos << aristas[1].corte << aristas[3].corte; 0294 0295 agregar_triangulos(triangulos); 0296 } 0297 void MarchingSquares::buildGeometry() 0298 { 0299 _faces_.clear(); 0300 0301 QList<sMarching_Square> cubos; 0302 sMarching_Square cubo; 0303 0304 cubos = ejecutar(); 0305 0306 foreach(cubo,cubos) { 0307 identificar_tipo(cubo); 0308 } 0309 0310 } 0311 void MarchingSquares::setWorld(double minx, double maxx, double miny, double maxy) 0312 { 0313 sLimitesEspacio2D _esp; 0314 0315 _esp.minX = minx; 0316 _esp.maxX = maxx; 0317 _esp.minY = miny; 0318 _esp.maxY = maxy; 0319 0320 largo_mundo = 1; 0321 0322 min_grid = qMin(fabs(maxx-minx), fabs(maxy-miny))/256; 0323 0324 if (min_grid>0.05 && min_grid < 1) 0325 min_grid = 0.05; 0326 0327 mundo = _esp; 0328 }