source: GTP/trunk/Lib/Vis/Preprocessing/src/mixkit/MxPropSlim.cxx @ 1097

Revision 1097, 11.2 KB checked in by mattausch, 18 years ago (diff)
Line 
1/************************************************************************
2
3  MxPropSlim
4
5  Copyright (C) 1998 Michael Garland.  See "COPYING.txt" for details.
6 
7  $Id: MxPropSlim.cxx,v 1.1 2002/09/24 16:53:54 wimmer Exp $
8
9 ************************************************************************/
10
11#include "stdmix.h"
12#include "MxPropSlim.h"
13#include "MxGeom3D.h"
14
15typedef MxQuadric Quadric;
16
17MxPropSlim::MxPropSlim(MxStdModel *m0)
18    : MxStdSlim(m0),
19      __quadrics(m0->vert_count()),
20      edge_links(m0->vert_count())
21{
22    consider_color();
23    consider_texture();
24    consider_normals();
25
26    D = compute_dimension(m);
27
28    will_decouple_quadrics = false;
29}
30
31void MxPropSlim::consider_color(bool will)
32{
33    use_color = will && (m->color_binding() == MX_PERVERTEX);
34    D = compute_dimension(m);
35}
36
37void MxPropSlim::consider_texture(bool will)
38{
39    use_texture = will && (m->texcoord_binding() == MX_PERVERTEX);
40    D = compute_dimension(m);
41}
42
43void MxPropSlim::consider_normals(bool will)
44{
45    use_normals = will && (m->normal_binding() == MX_PERVERTEX);
46    D = compute_dimension(m);
47}
48
49uint MxPropSlim::compute_dimension(MxStdModel *m)
50{
51    uint d = 3;
52
53    if( use_color )  d += 3;
54    if( use_texture )  d += 2;
55    if( use_normals )  d += 3;
56
57    return d;
58}
59
60void MxPropSlim::pack_to_vector(MxVertexID id, MxVector& v)
61{
62    SanityCheck( v.dim() == D );
63    SanityCheck( id < m->vert_count() );
64
65    v[0] = m->vertex(id)[0];
66    v[1] = m->vertex(id)[1];
67    v[2] = m->vertex(id)[2];
68
69    uint i = 3;
70    if( use_color )
71    {
72        v[i++] = m->color(id).R();
73        v[i++] = m->color(id).G();
74        v[i++] = m->color(id).B();
75    }
76    if( use_texture )
77    {
78        v[i++] = m->texcoord(id)[0];
79        v[i++] = m->texcoord(id)[1];
80    }
81    if( use_normals )
82    {
83        v[i++] = m->normal(id)[0];
84        v[i++] = m->normal(id)[1];
85        v[i++] = m->normal(id)[2];
86    }
87}
88
89void MxPropSlim::pack_prop_to_vector(MxVertexID id, MxVector& v, uint target)
90{
91    if( target == 0 )
92    {
93        v[0] = m->vertex(id)[0];
94        v[1] = m->vertex(id)[1];
95        v[2] = m->vertex(id)[2];
96        return;
97    }
98
99    uint i = 3;
100    target--;
101
102    if( use_color )
103    {
104        if( target == 0 )
105        {
106            v[i]   = m->color(id).R();
107            v[i+1] = m->color(id).G();
108            v[i+2] = m->color(id).B();
109            return;
110        }
111        i += 3;
112        target--;
113    }
114    if( use_texture )
115    {
116        if( target == 0 )
117        {
118            v[i]   = m->texcoord(id)[0];
119            v[i+1] = m->texcoord(id)[1];
120            return;
121        }
122        i += 2;
123        target--;
124    }
125    if( use_normals )
126    {
127        if( target == 0 )
128        {
129            v[i]   = m->normal(id)[0];
130            v[i+1] = m->normal(id)[1];
131            v[i+2] = m->normal(id)[2];
132            return;
133        }
134    }
135}
136
137static inline void CLAMP(double& v, double lo, double hi)
138{
139    if( v<lo ) v = lo;
140    if( v>hi ) v = hi;
141}
142
143void MxPropSlim::unpack_from_vector(MxVertexID id, MxVector& v)
144{
145    SanityCheck( v.dim() == D );
146    SanityCheck( id < m->vert_count() );
147
148    m->vertex(id)[0] = v[0];
149    m->vertex(id)[1] = v[1];
150    m->vertex(id)[2] = v[2];
151
152    uint i = 3;
153    if( use_color )
154    {
155        CLAMP(v[i], 0, 1);
156        CLAMP(v[i+1], 0, 1);
157        CLAMP(v[i+2], 0, 1);
158        m->color(id).set(v[i], v[i+1], v[i+2]);
159        i += 3;
160    }
161    if( use_texture )
162    {
163        m->texcoord(id)[0] = v[i++];
164        m->texcoord(id)[1] = v[i++];
165    }
166    if( use_normals )
167    {
168        float n[3];  n[0]=v[i++];  n[1]=v[i++];  n[2]=v[i++];
169        mxv_unitize(n, 3);
170        m->normal(id).set(n[0], n[1], n[2]);
171    }
172}
173
174void MxPropSlim::unpack_prop_from_vector(MxVertexID id,MxVector& v,uint target)
175{
176    if( target == 0 )
177    {
178        m->vertex(id)[0] = v[0];
179        m->vertex(id)[1] = v[1];
180        m->vertex(id)[2] = v[2];
181        return;
182    }
183
184    uint i=3;
185    target--;
186
187    if( use_color )
188    {
189        if( target == 0 )
190        {
191            m->color(id).set(v[i], v[i+1], v[i+2]);
192            return;
193        }
194        i+=3;
195        target--;
196    }
197    if( use_texture )
198    {
199        if( target == 0 )
200        {
201            m->texcoord(id)[0] = v[i];
202            m->texcoord(id)[1] = v[i+1];
203            return;
204        }
205        i += 2;
206        target--;
207    }
208    if( use_normals )
209    {
210        if( target == 0 )
211        {
212            float n[3];  n[0]=v[i];  n[1]=v[i+1];  n[2]=v[i+2];
213            mxv_unitize(n, 3);
214            m->normal(id).set(n[0], n[1], n[2]);
215            return;
216        }
217    }
218}
219
220
221uint MxPropSlim::prop_count()
222{
223    uint i = 1;
224
225    if( use_color ) i++;
226    if( use_texture) i++;
227    if( use_normals ) i++;
228
229    return i;
230}
231
232void MxPropSlim::compute_face_quadric(MxFaceID i, MxQuadric& Q)
233{
234    MxFace& f = m->face(i);
235
236    MxVector v1(dim());
237    MxVector v2(dim());
238    MxVector v3(dim());
239
240    if( will_decouple_quadrics )
241    {
242        Q.clear();
243
244        for(uint p=0; p<prop_count(); p++)
245        {
246            v1=0.0;  v2=0.0;  v3=0.0;
247
248            pack_prop_to_vector(f[0], v1, p);
249            pack_prop_to_vector(f[1], v2, p);
250            pack_prop_to_vector(f[2], v3, p);
251
252            // !!BUG: Will count area multiple times (once per property)
253            MxQuadric Q_p(v1, v2, v3, m->compute_face_area(i));
254
255            // !!BUG: Need to only extract the relevant block of the matrix.
256            //        Adding the whole thing gives us extraneous stuff.
257            Q += Q_p;
258        }
259    }
260    else
261    {
262        pack_to_vector(f[0], v1);
263        pack_to_vector(f[1], v2);
264        pack_to_vector(f[2], v3);
265
266        Q = MxQuadric(v1, v2, v3, m->compute_face_area(i));
267    }
268}
269
270void MxPropSlim::collect_quadrics()
271{
272    for(uint j=0; j<quadric_count(); j++)
273        __quadrics[j] = new MxQuadric(dim());
274
275    for(MxFaceID i=0; i<m->face_count(); i++)
276    {
277        MxFace& f = m->face(i);
278
279        MxQuadric Q(dim());
280        compute_face_quadric(i, Q);
281
282//      if( weight_by_area )
283//          Q *= Q.area();
284
285        quadric(f[0]) += Q;
286        quadric(f[1]) += Q;
287        quadric(f[2]) += Q;
288    }
289}
290
291void MxPropSlim::initialize()
292{
293    collect_quadrics();
294
295    if( boundary_weight > 0.0 )
296        constrain_boundaries();
297
298
299    collect_edges();
300
301    is_initialized = true;
302}
303
304void MxPropSlim::compute_target_placement(edge_info *info)
305{
306    MxVertexID i=info->v1, j=info->v2;
307
308    const MxQuadric &Qi=quadric(i), &Qj=quadric(j);
309    MxQuadric Q=Qi;  Q+=Qj;
310
311    double err;
312
313    if( Q.optimize(info->target) )
314    {
315        err = Q(info->target);
316    }
317    else
318    {
319        // Fall back only on endpoints
320
321        MxVector v_i(dim()), v_j(dim());
322
323        pack_to_vector(i, v_i);
324        pack_to_vector(j, v_j);
325
326        double e_i = Q(v_i);
327        double e_j = Q(v_j);
328
329        if( e_i<=e_j )
330        {
331            info->target = v_i;
332            err = e_i;
333        }
334        else
335        {
336            info->target = v_j;
337            err = e_j;
338        }
339    }
340
341//     if( weight_by_area )
342//      err / Q.area();
343    info->heap_key(-err);
344}
345
346bool MxPropSlim::decimate(uint target)
347{
348    MxPairContraction conx;
349
350    while( valid_faces > target )
351    {
352        edge_info *info = (edge_info *)heap.extract();
353        if( !info )  return false;
354
355        MxVertexID v1=info->v1, v2=info->v2;
356
357        if( m->vertex_is_valid(v1) && m->vertex_is_valid(v2) )
358        {
359            m->compute_contraction(v1, v2, &conx);
360
361            conx.dv1[X] = info->target[X] - m->vertex(v1)[X];
362            conx.dv1[Y] = info->target[Y] - m->vertex(v1)[Y];
363            conx.dv1[Z] = info->target[Z] - m->vertex(v1)[Z];
364            conx.dv2[X] = info->target[X] - m->vertex(v2)[X];
365            conx.dv2[Y] = info->target[Y] - m->vertex(v2)[Y];
366            conx.dv2[Z] = info->target[Z] - m->vertex(v2)[Z];
367
368            apply_contraction(conx, info);
369        }
370
371        delete info;
372    }
373
374    return true;
375}
376
377
378
379////////////////////////////////////////////////////////////////////////
380//
381// This is *very* close to the code in MxEdgeQSlim
382
383void MxPropSlim::create_edge(MxVertexID i, MxVertexID j)
384{
385    edge_info *info = new edge_info(dim());
386
387    edge_links(i).add(info);
388    edge_links(j).add(info);
389
390    info->v1 = i;
391    info->v2 = j;
392
393    compute_edge_info(info);
394}
395
396void MxPropSlim::discontinuity_constraint(MxVertexID i, MxVertexID j,
397                                          const MxFaceList& faces)
398{
399    for(uint f=0; f<faces.length(); f++)
400    {
401        Vec3 org(m->vertex(i)), dest(m->vertex(j));
402        Vec3 e = dest - org;
403
404        Vec3 v1(m->vertex(m->face(faces(f))(0)));
405        Vec3 v2(m->vertex(m->face(faces(f))(1)));
406        Vec3 v3(m->vertex(m->face(faces(f))(2)));
407        Vec3 n = triangle_normal(v1,v2,v3);
408
409        Vec3 n2 = e ^ n;
410        unitize(n2);
411
412        MxQuadric3 Q3(n2, -(n2*org));
413        Q3 *= boundary_weight;
414
415        MxQuadric Q(Q3, dim());
416
417        quadric(i) += Q;
418        quadric(j) += Q;
419    }
420}
421
422void MxPropSlim::apply_contraction(const MxPairContraction& conx,
423                                   edge_info *info)
424{
425    valid_verts--;
426    valid_faces -= conx.dead_faces.length();
427    quadric(conx.v1) += quadric(conx.v2);
428
429    update_pre_contract(conx);
430
431    m->apply_contraction(conx);
432
433    unpack_from_vector(conx.v1, info->target);
434
435    // Must update edge_info here so that the meshing penalties
436    // will be computed with respect to the new mesh rather than the old
437    for(uint i=0; i<edge_links(conx.v1).length(); i++)
438        compute_edge_info(edge_links(conx.v1)[i]);
439}
440
441
442
443////////////////////////////////////////////////////////////////////////
444//
445// These were copied *unmodified* from MxEdgeQSlim
446// (with some unsupported features commented out).
447//
448
449void MxPropSlim::collect_edges()
450{
451    MxVertexList star;
452
453    for(MxVertexID i=0; i<m->vert_count(); i++)
454    {
455        star.reset();
456        m->collect_vertex_star(i, star);
457
458        for(uint j=0; j<star.length(); j++)
459            if( i < star(j) )  // Only add particular edge once
460                create_edge(i, star(j));
461    }
462}
463
464void MxPropSlim::constrain_boundaries()
465{
466    MxVertexList star;
467    MxFaceList faces;
468
469    for(MxVertexID i=0; i<m->vert_count(); i++)
470    {
471        star.reset();
472        m->collect_vertex_star(i, star);
473
474        for(uint j=0; j<star.length(); j++)
475            if( i < star(j) )
476            {
477                faces.reset();
478                m->collect_edge_neighbors(i, star(j), faces);
479                if( faces.length() == 1 )
480                    discontinuity_constraint(i, star(j), faces);
481            }
482    }
483}
484
485void MxPropSlim::compute_edge_info(edge_info *info)
486{
487    compute_target_placement(info);
488
489//     if( will_normalize_error )
490//     {
491//         double e_max = Q_max(info->vnew);
492//         if( weight_by_area )
493//             e_max /= Q_max.area();
494
495//         info->heap_key(info->heap_key() / e_max);
496//     }
497
498    finalize_edge_update(info);
499}
500
501void MxPropSlim::finalize_edge_update(edge_info *info)
502{
503//     if( meshing_penalty > 1.0 )
504//         apply_mesh_penalties(info);
505
506    if( info->is_in_heap() )
507        heap.update(info);
508    else
509        heap.insert(info);
510}
511
512void MxPropSlim::update_pre_contract(const MxPairContraction& conx)
513{
514    MxVertexID v1=conx.v1, v2=conx.v2;
515    uint i, j;
516
517    star.reset();
518    m->collect_vertex_star(v1, star);
519
520    for(i=0; i<edge_links(v2).length(); i++)
521    {
522        edge_info *e = edge_links(v2)(i);
523        MxVertexID u = (e->v1==v2)?e->v2:e->v1;
524        SanityCheck( e->v1==v2 || e->v2==v2 );
525        SanityCheck( u!=v2 );
526
527        if( u==v1 || star.find(u) )
528        {
529            // This is a useless link --- kill it
530            bool found = edge_links(u).find(e, &j);
531            assert( found );
532            edge_links(u).remove(j);
533            heap.remove(e);
534            if( u!=v1 ) delete e; // (v1,v2) will be deleted later
535        }
536        else
537        {
538            // Relink this to v1
539            e->v1 = v1;
540            e->v2 = u;
541            edge_links(v1).add(e);
542        }
543    }
544
545    edge_links(v2).reset();
546}
Note: See TracBrowser for help on using the repository browser.