Statistics
| Revision:

svn-gvsig-desktop / branches / Mobile_Compatible_Hito_1 / libFMap_mobile_shp_driver / src-test / org / gvsig / data / datastores / vectorial / file / shp / FilterTest.java @ 21927

History | View | Annotate | Download (18.4 KB)

1
/**
2
 * 
3
 */
4
package org.gvsig.data.datastores.vectorial.file.shp;
5

    
6
import java.io.File;
7
import java.io.StringWriter;
8
import java.util.Date;
9
import java.util.HashSet;
10
import java.util.Iterator;
11

    
12
import junit.framework.TestCase;
13

    
14
import org.apache.log4j.FileAppender;
15
import org.apache.log4j.Level;
16
import org.apache.log4j.Logger;
17
import org.apache.log4j.PatternLayout;
18
import org.gvsig.compatible.StringUtil;
19
import org.gvsig.data.CloseException;
20
import org.gvsig.data.DataCollection;
21
import org.gvsig.data.DataManager;
22
import org.gvsig.data.DataStoreParameters;
23
import org.gvsig.data.InitializeException;
24
import org.gvsig.data.OpenException;
25
import org.gvsig.data.ReadException;
26
import org.gvsig.data.datastores.vectorial.file.ResourceReader;
27
import org.gvsig.data.datastores.vectorial.file.Utils;
28
import org.gvsig.data.datastores.vectorial.file.shp_jni.JNISHPRegister;
29
import org.gvsig.data.datastores.vectorial.file.shp_jni.JNISHPStore;
30
import org.gvsig.data.datastores.vectorial.file.shp_mem.MemSHPRegister;
31
import org.gvsig.data.datastores.vectorial.file.shp_mem.MemSHPStore;
32
import org.gvsig.data.datastores.vectorial.file.shp_util.IGeometricDataStore;
33
import org.gvsig.data.datastores.vectorial.file.shp_util.NewShpFeatureID;
34
import org.gvsig.data.vectorial.Feature;
35
import org.gvsig.data.vectorial.FeatureAttributeDescriptor;
36
import org.gvsig.data.vectorial.FeatureType;
37
import org.gvsig.data.vectorial.filter.FilterFactory2Impl;
38
import org.gvsig.data.vectorial.filter.FilterToSQL;
39
import org.gvsig.data.vectorial.filter.FilterToSQLException;
40
import org.opengis.filter.Filter;
41
import org.opengis.filter.FilterFactory2;
42
import org.opengis.filter.expression.Expression;
43
import org.opengis.filter.sort.SortBy;
44
import org.opengis.filter.sort.SortOrder;
45

    
46
/**
47
 * @author jcarras
48
 *
49
 */
50
public class FilterTest  extends TestCase {
51
        
52
        private static Logger logger;;
53
        
54
        private File fileNormal =
55
                ResourceReader.getResourceFile("testdata", "prueba.shp");
56

    
57
        private IGeometricDataStore ioStore;
58
        private IGeometricDataStore jniStore;
59
        private IGeometricDataStore memStore;
60
        
61
        public static void main(String[] args) { //
62
                junit.textui.TestRunner.run(FilterTest.class);
63
        } 
64
        
65
        public FilterTest() {
66
                registerDataStores();
67
                initLogger();
68
                
69
                if (Utils.USING_PDA) {
70
                        fileNormal = ResourceReader.getPdaTestFile(PerformanceTest.SD_FOLDER, "testdata", "prueba.shp");
71
                } else {
72
                        fileNormal = ResourceReader.getResourceFile("testdata", "prueba.shp");
73
                }
74
                
75
        }
76

    
77
        protected void setUp() throws Exception {
78
                super.setUp();
79
                doInitialize();
80
        }
81

    
82
        private void initLogger() {
83

    
84
                        Date now = new Date(System.currentTimeMillis());
85
                        String nowstr = now.toString();
86
                        
87
                        nowstr = StringUtil.replaceAllString(nowstr, " ", "_");
88
                        nowstr = StringUtil.replaceAllString(nowstr, ":", "_") + ".txt";
89
                        
90
                        
91
                        String outlogpath = "";
92
                        
93
                        if (Utils.USING_PDA) {
94
                                outlogpath = ResourceReader.getPdaTestFile(PerformanceTest.SD_FOLDER, "testdata", "filter_test_" + nowstr).getAbsolutePath();
95
                        } else {
96
                                outlogpath = ResourceReader.getResourceFile("testdata", "filter_test_" + nowstr).getAbsolutePath();
97
                        }
98

    
99
                        System.out.println("Log file: " + outlogpath);
100

    
101
                        try {
102
                            PatternLayout l = new PatternLayout("%5p [%t] - %m%n");
103
                            FileAppender fa = new FileAppender(l, outlogpath, false);
104
                            // ConsoleAppender ca = new ConsoleAppender(l);
105
                            Logger.getRootLogger().setLevel(Level.DEBUG);
106
                            Logger.getRootLogger().addAppender(fa);
107
                            // Logger.getRootLogger().addAppender(ca);
108
                        } catch (Exception ex) {
109
                                System.err.println("Error while initializing log4j: " + ex.getMessage());
110
                        }
111
                        logger = Logger.getLogger(FilterTest.class);
112

    
113
        }
114

    
115
        private void registerDataStores() {
116
                Register.selfRegister();
117
                MemSHPRegister.selfRegister();
118
                JNISHPRegister.selfRegister();
119
        }
120
        
121
        public void doInitialize() {
122
                DataManager manager = DataManager.getManager();
123

    
124
                // ===============================================
125
                SHPStoreParameters shpParameters1 = null;
126
                shpParameters1 =(SHPStoreParameters) manager.createDataStoreParameters(SHPStore.DATASTORE_NAME);
127
                shpParameters1.setFile(fileNormal);
128
                shpParameters1.setDataStoreName(SHPStore.DATASTORE_NAME);
129
                try {
130
                        ioStore = (SHPStore) manager.createDataStore((DataStoreParameters) shpParameters1);
131
                } catch (InitializeException e) {
132
                        logger.error("While creating datastore: " + e.getMessage());
133
                }
134
                // ===============================================
135
                SHPStoreParameters shpParameters2 = null;
136
                shpParameters2 =(SHPStoreParameters) manager.createDataStoreParameters(JNISHPStore.DATASTORE_NAME);
137
                shpParameters2.setFile(fileNormal);
138
                shpParameters2.setDataStoreName(JNISHPStore.DATASTORE_NAME);
139
                try {
140
                        jniStore = (JNISHPStore) manager.createDataStore((DataStoreParameters) shpParameters2);
141
                } catch (InitializeException e) {
142
                        logger.error("While creating datastore: " + e.getMessage());
143
                }
144
                // ===============================================
145
                SHPStoreParameters shpParameters3 = null;
146
                shpParameters3 =(SHPStoreParameters) manager.createDataStoreParameters(MemSHPStore.DATASTORE_NAME);
147
                shpParameters3.setFile(fileNormal);
148
                shpParameters3.setDataStoreName(MemSHPStore.DATASTORE_NAME);
149
                try {
150
                        memStore = (MemSHPStore) manager.createDataStore((DataStoreParameters) shpParameters3);
151
                } catch (InitializeException e) {
152
                        logger.error("While creating datastore: " + e.getMessage());
153
                }
154
        }
155
        
156
        
157
        public void initialize() {
158
                
159
        }
160
        
161
        public void doTests() {
162
                
163
                try {
164
                        setUp(); testOrder();
165
                        setUp(); testGT();
166
                        setUp(); testGT_string();
167
                        setUp(); testGTE();
168
                        setUp(); testLT();
169
                        setUp(); testLTE();
170
                        setUp(); testEquals();
171
                        setUp(); testEquals_String();
172
                        setUp(); testNotEquals();
173
                        setUp(); testNot();
174
                        setUp(); testBetween();
175
                        setUp(); testLike();
176
                        setUp(); testFId();
177
                        setUp(); testBBOX();
178
                        setUp(); testAnd();
179
                        setUp(); testOr();
180
                        setUp(); testAdd();
181
                        setUp(); testSubstract();
182
                        setUp(); testMultiply();
183
                        setUp(); testDivide();
184
                } catch (Exception ex) {
185
                        logger.error("While doing tests: " + ex.getMessage());
186
                }
187
                logger.debug("FIN.");
188
                
189
        }
190
        
191
        public void testOrder(){
192
                System.out.println("testOrder");
193
                initialize();
194
                SortBy[] order = new SortBy[2];
195
                order[0]=new FilterFactory2Impl().sort("TIPO", SortOrder.ASCENDING);
196
                order[1]=new FilterFactory2Impl().sort("AREA", SortOrder.ASCENDING);
197
                assertEquals(9,testshp(null, order, ioStore));
198
//                assertEquals(9,testshp(null, order, jniStore));
199
//                assertEquals(9,testshp(null, order, memStore));
200
        }
201
        
202
        public void testGT(){
203
                System.out.println("testGT");
204
                initialize();
205
                FilterFactory2 fact = new FilterFactory2Impl();
206
                Expression exp1 = fact.property("AREA");
207
                Expression exp2 = fact.literal(30000000);
208
                Filter filter = fact.greater(exp1, exp2);
209
                assertEquals(4,testshp(filter, null, ioStore));
210
//                assertEquals(4,testshp(filter, null, jniStore));
211
//                assertEquals(4,testshp(filter, null, memStore));
212
        }
213
        
214
        public void testGT_string(){
215
                System.out.println("testGT_string");
216
                initialize();
217
                FilterFactory2 fact = new FilterFactory2Impl();
218
                Expression exp1 = fact.property("NOMBRE");
219
                Expression exp2 = fact.literal("PEDREGUER");
220
                Filter filter = fact.greater(exp1, exp2);
221
                assertEquals(2,testshp(filter, null, ioStore));
222
                assertEquals(2,testshp(filter, null, memStore));
223
                assertEquals(2,testshp(filter, null, jniStore));
224
        }
225

    
226
        public void testGTE(){
227
                System.out.println("testGTE");
228
                initialize();
229
                FilterFactory2 fact = new FilterFactory2Impl();
230
                Expression exp1 = fact.property("NOMBRE");
231
                Expression exp2 = fact.literal("PEDREGUER");
232
                Filter filter = fact.greaterOrEqual(exp1, exp2);
233
                assertEquals(3,testshp(filter, null, ioStore));
234
                assertEquals(3,testshp(filter, null, memStore));
235
                assertEquals(3,testshp(filter, null, jniStore));
236
        }
237
        
238
        public void testLT(){
239
                System.out.println("testLT");
240
                initialize();
241
                FilterFactory2 fact = new FilterFactory2Impl();
242
                Expression exp1 = fact.property("AREA");
243
                Expression exp2 = fact.literal(30000000);
244
                Filter filter = fact.less(exp1, exp2);
245
                assertEquals(5,testshp(filter, null, ioStore));
246
                assertEquals(5,testshp(filter, null, memStore));
247
                assertEquals(5,testshp(filter, null, jniStore));
248
        }
249
        
250
        public void testLTE(){
251
                System.out.println("testLTE");
252
                initialize();
253
                FilterFactory2 fact = new FilterFactory2Impl();
254
                Expression exp1 = fact.property("NOMBRE");
255
                Expression exp2 = fact.literal("PEDREGUER");
256
                Filter filter = fact.lessOrEqual(exp1, exp2);
257
                assertEquals(7,testshp(filter, null, ioStore));
258
                assertEquals(7,testshp(filter, null, memStore));
259
                assertEquals(7,testshp(filter, null, jniStore));
260
        }        
261

    
262
        public void testEquals(){
263
                System.out.println("testEquals");
264
                initialize();
265
                FilterFactory2 fact = new FilterFactory2Impl();
266
                Expression exp1 = fact.property("INE");
267
                Expression exp2 = fact.literal(3125);
268
                Filter filter = fact.equals(exp1, exp2);
269
                assertEquals(1,testshp(filter, null, ioStore));
270
                assertEquals(1,testshp(filter, null, jniStore));
271
                assertEquals(1,testshp(filter, null, memStore));
272
        }        
273

    
274
        public void testEquals_String(){
275
                System.out.println("testEquals");
276
                initialize();
277
                FilterFactory2 fact = new FilterFactory2Impl();
278
                Expression exp1 = fact.property("NOMBRE");
279
                Expression exp2 = fact.literal("PEDREGUER");
280
                Filter filter = fact.equals(exp1, exp2);
281
                assertEquals(1,testshp(filter, null, ioStore));
282
                assertEquals(1,testshp(filter, null, memStore));
283
                assertEquals(1,testshp(filter, null, jniStore));
284
        }        
285

    
286
        public void testNotEquals(){
287
                System.out.println("testNotEquals");
288
                initialize();
289
                FilterFactory2 fact = new FilterFactory2Impl();
290
                Expression exp1 = fact.property("NOMBRE");
291
                Expression exp2 = fact.literal("PEDREGUER");
292
                Filter filter = fact.notEqual(exp1, exp2,true);
293
                assertEquals(8,testshp(filter, null, ioStore));
294
                assertEquals(8,testshp(filter, null, memStore));
295
                assertEquals(8,testshp(filter, null, jniStore));
296
        }        
297
        
298
        public void testNot(){
299
                System.out.println("testNot");
300
                initialize();
301
                FilterFactory2 fact = new FilterFactory2Impl();
302
                Expression exp1 = fact.property("NOMBRE");
303
                Expression exp2 = fact.literal("PEDREGUER");
304
                Filter filter = fact.equals(exp1, exp2);
305
                filter = fact.not(filter);
306
                assertEquals(8,testshp(filter, null, ioStore));
307
                assertEquals(8,testshp(filter, null, jniStore));
308
                assertEquals(8,testshp(filter, null, memStore));
309
        }        
310
        
311
        /**
312
         * Current shp driver fails when using a shapefile 
313
         * with null values 
314
         */
315
//        public void testIsNull() {
316
//                System.out.println("testIsNull");
317
//                initialize();
318
//                FilterFactory2 fact = new FilterFactory2Impl();
319
//                Expression exp1 = fact.property("OTRO_IDIOM");
320
//                Filter filter = fact.not(fact.isNull(exp1));
321
//                assertEquals(7,testshp(filter, null, ioStore));
322
//                assertEquals(7,testshp(filter, null, jniStore));
323
//                assertEquals(7,testshp(filter, null, memStore));
324
//        }        
325

    
326
        public void testBetween(){
327
                System.out.println("Between");
328
                initialize();
329
                FilterFactory2 fact = new FilterFactory2Impl();
330
                Expression exp1 = fact.literal(25000000.0);
331
                Expression exp3 = fact.literal(40000000);
332
                Expression exp2 = fact.property("AREA");
333
                Filter filter = fact.between(exp1, exp2, exp3);
334
                assertEquals(2,testshp(filter, null, ioStore));
335
                assertEquals(2,testshp(filter, null, memStore));
336
                assertEquals(2,testshp(filter, null, jniStore));
337
        }        
338
        
339
        public void testLike(){
340
                System.out.println("testLike");
341
                initialize();
342
                FilterFactory2 fact = new FilterFactory2Impl();
343
                Expression exp1 = fact.property("NOMBRE");
344
                Filter filter = fact.like(exp1, "%I_A%");
345
                assertEquals(2,testshp(filter, null, ioStore));
346
                assertEquals(2,testshp(filter, null, jniStore));
347
                assertEquals(2,testshp(filter, null, memStore));
348
        }        
349

    
350
        public void testFId(){
351
                System.out.println("testId");
352
                initialize();
353
                FilterFactory2 fact = new FilterFactory2Impl();
354

    
355
                HashSet ids = null;
356
                Filter filter = null;
357
                
358
                ids = new HashSet();
359
                ids.add(new ShpFeatureID((SHPStore) ioStore, 3));
360
                ids.add(new ShpFeatureID((SHPStore) ioStore, 6));
361
                filter = fact.id(ids);
362
                assertEquals(2, testshp(filter, null, ioStore));
363
                
364
                ids = new HashSet();
365
                ids.add(new NewShpFeatureID(jniStore, 3));
366
                ids.add(new NewShpFeatureID(jniStore, 6));
367
                filter = fact.id(ids);
368
                assertEquals(2, testshp(filter, null, jniStore));
369
                
370
                ids = new HashSet();
371
                ids.add(new NewShpFeatureID(memStore, 3));
372
                ids.add(new NewShpFeatureID(memStore, 6));
373
                filter = fact.id(ids);
374
                assertEquals(2, testshp(filter, null, memStore));
375
        }
376

    
377
        public void testBBOX(){
378
                System.out.println("testBBOX");
379
                initialize();
380
                FilterFactory2 fact = new FilterFactory2Impl();
381
                Expression exp1 = fact.property("GEOMETRY");
382
                Filter filter = fact.bbox(exp1, 769009, 4291393, 772960, 4293701, null);
383
                assertEquals(4,testshp(filter, null, ioStore));
384
                assertEquals(4,testshp(filter, null, memStore));
385
                assertEquals(4,testshp(filter, null, jniStore));
386
        }
387
        
388
        public void testAnd(){
389
                System.out.println("testAnd");
390
                initialize();
391
                FilterFactory2 fact = new FilterFactory2Impl();
392
                Expression exp1 = fact.property("GEOMETRY");
393
                Filter filter1 = fact.bbox(exp1, 769009, 4291393, 772960, 4293701, null);
394
                Expression exp2 = fact.property("NOMBRE");
395
                Filter filter2 = fact.like(exp2, "B%");
396
                Filter filter = fact.and(filter1, filter2);
397
                assertEquals(1,testshp(filter, null, ioStore));
398
                assertEquals(1,testshp(filter, null, jniStore));
399
                assertEquals(1,testshp(filter, null, memStore));
400
        }
401

    
402
        public void testOr(){
403
                System.out.println("testOr");
404
                initialize();
405
                FilterFactory2 fact = new FilterFactory2Impl();
406
                
407
                Expression exp1 = fact.property("GEOMETRY");
408
                Filter filter1 = fact.bbox(exp1, 769009, 4291393, 772960, 4293701, null);
409
                
410
                Expression exp2 = fact.property("NOMBRE");
411
                Filter filter2 = fact.like(exp2, "B%");
412
                
413
                Filter filter = fact.or(filter1, filter2);
414
                
415
                assertEquals(5,testshp(filter, null, ioStore));
416
                assertEquals(5,testshp(filter, null, memStore));
417
                assertEquals(5,testshp(filter, null, jniStore));
418
        }
419
        
420
        /**
421
         * area + 3e7 > 6e7 --> area > 3e7
422
         */
423
        public void testAdd(){
424
                System.out.println("testAdd");
425
                initialize();
426
                FilterFactory2 fact = new FilterFactory2Impl();
427
                Expression exp1 = fact.property("AREA");
428
                Expression exp2 = fact.literal(30000000);
429
                Expression exp3 = fact.literal(60000000);
430
                Filter filter = fact.greater(fact.add(exp1, exp2),exp3);
431
                assertEquals(4,testshp(filter, null, ioStore));
432
                assertEquals(4,testshp(filter, null, jniStore));
433
                assertEquals(4,testshp(filter, null, memStore));
434
        }
435
        
436
        /**
437
         * area - 3e7 > 0 --> area > 3e7
438
         */
439
        public void testSubstract(){
440
                System.out.println("testSubstract");
441
                initialize();
442
                FilterFactory2 fact = new FilterFactory2Impl();
443
                Expression exp1 = fact.property("AREA");
444
                Expression exp2 = fact.literal(30000000);
445
                Expression exp3 = fact.literal(0);
446
                Filter filter = fact.greater(fact.subtract(exp1, exp2),exp3);
447
                assertEquals(4,testshp(filter, null, ioStore));
448
                assertEquals(4,testshp(filter, null, memStore));
449
                assertEquals(4,testshp(filter, null, jniStore));
450
        }
451

    
452
        /**
453
         * area * 2 > 6e7 --> area > 3e7
454
         */
455
        public void testMultiply(){
456
                System.out.println("testMultiply");
457
                initialize();
458
                FilterFactory2 fact = new FilterFactory2Impl();
459
                Expression exp1 = fact.property("AREA");
460
                Expression exp2 = fact.literal(2);
461
                Expression exp3 = fact.literal(60000000);
462
                Filter filter = fact.greater(fact.multiply(exp1, exp2),exp3);
463
                assertEquals(4,testshp(filter, null, ioStore));
464
                assertEquals(4,testshp(filter, null, jniStore));
465
                assertEquals(4,testshp(filter, null, memStore));
466
        }
467
        
468
        /**
469
         * area / 2 > 1.5e7 --> area > 3e7
470
         */
471
        public void testDivide(){
472
                System.out.println("testDivide");
473
                initialize();
474
                FilterFactory2 fact = new FilterFactory2Impl();
475
                Expression exp1 = fact.property("AREA");
476
                Expression exp2 = fact.literal(2);
477
                Expression exp3 = fact.literal(15000000);
478
                Filter filter = fact.greater(fact.divide(exp1, exp2),exp3);
479
                assertEquals(4,testshp(filter, null, ioStore));
480
                assertEquals(4,testshp(filter, null, memStore));
481
                assertEquals(4,testshp(filter, null, jniStore));
482
        }
483
        
484

    
485
        private int testshp(Filter filter, SortBy[] order, IGeometricDataStore st){
486

    
487
                try {
488
                        st.doOpen();
489
                } catch (OpenException e2) {
490
                        // TODO Auto-generated catch block
491
                        e2.printStackTrace();
492
                }
493

    
494
                FeatureType ft = st.getDefaultFeatureType();
495
                DataCollection featureCollection = null;
496
                
497
                try{
498
                        StringWriter out = new StringWriter();
499
                        FilterToSQL converter = new FilterToSQL(out);
500
                        converter.encode(filter);
501
                        System.out.println(out.toString());
502
                } catch (FilterToSQLException e){
503
                        e.printStackTrace();
504
                }
505
                
506
                try {
507
                        featureCollection = st.getDataCollection(ft,filter,order);
508
                } catch (ReadException e1) {
509
                        // TODO Auto-generated catch block
510
                        e1.printStackTrace();
511
                }
512
                Iterator iter = featureCollection.iterator();
513
                Iterator titlesIt=ft.iterator();
514
                System.out.print("ID");
515
                while (titlesIt.hasNext()) {
516
                        FeatureAttributeDescriptor descriptor = (FeatureAttributeDescriptor) titlesIt.next();
517
                        System.out.print("\t"+ descriptor.getName() + "(" + descriptor.getDataType().substring(0,3)+")");
518
                }
519
                System.out.println("");
520
                while (iter.hasNext()) {
521
                        Feature feature = (Feature)iter.next();
522
                        // System.out.print(feature.getID().toString());
523
                        //System.out.println("SHP Feature ------------------- ");
524
                        Iterator iterator=ft.iterator();
525
                        while (iterator.hasNext()) {
526
                                FeatureAttributeDescriptor descriptor = (FeatureAttributeDescriptor) iterator.next();
527
                                int i=descriptor.ordinal();
528
                                String type=descriptor.getDataType();
529
                                //System.out.println("****** "+ descriptor.getName());
530
                                if (type.equals(FeatureAttributeDescriptor.TYPE_BOOLEAN)){
531
                                        System.out.print("\t"+ feature.getBoolean(i));
532
                                }else if (type.equals(FeatureAttributeDescriptor.TYPE_BYTE)){
533
                                        System.out.print("\t"+ feature.getByte(i));
534
                                }else if (type.equals(FeatureAttributeDescriptor.TYPE_DATE)){
535
                                        try{
536
                                                System.out.print("\t"+ feature.getDate(i));
537
                                        } catch (Exception e){
538
                                                
539
                                        }
540
                                }else if (type.equals(FeatureAttributeDescriptor.TYPE_DOUBLE)){
541
                                        System.out.print("\t"+ feature.getDouble(i));
542
                                }else if (type.equals(FeatureAttributeDescriptor.TYPE_FLOAT)){
543
                                        System.out.print("\t"+ feature.getFloat(i));
544
                                }else if (type.equals(FeatureAttributeDescriptor.TYPE_INT)){
545
                                        System.out.print("\t"+ feature.getInt(i));
546
                                }else if (type.equals(FeatureAttributeDescriptor.TYPE_LONG)){
547
                                        System.out.print("\t"+ feature.getLong(i));
548
                                }else if (type.equals(FeatureAttributeDescriptor.TYPE_STRING)){
549
                                        System.out.print("\t"+ feature.getString(i));
550
                                }else if (type.equals(FeatureAttributeDescriptor.TYPE_GEOMETRY)){
551

    
552
                                        System.out.print("\tGeometry");
553
                                }
554
                        }
555
                        System.out.println("");
556
                }
557
                iter=null;
558
                int numFeat = featureCollection.size();
559
                featureCollection.dispose();
560

    
561
                try {
562
                        st.doClose();
563
                        st.doDispose();
564
                } catch (CloseException e) {
565
                        // TODO Auto-generated catch block
566
                        e.printStackTrace();
567
                }
568
                
569
                return numFeat;
570

    
571
        }
572

    
573
}