Statistics
| Revision:

root / org.gvsig.toolbox / trunk / org.gvsig.toolbox / org.gvsig.toolbox.algorithm / src / main / java / es / unex / sextante / vectorTools / vectorCluster / VectorClusterAlgorithm.java @ 59

History | View | Annotate | Download (8.84 KB)

1

    
2

    
3
package es.unex.sextante.vectorTools.vectorCluster;
4

    
5
import java.util.ArrayList;
6
import java.util.Arrays;
7

    
8
import es.unex.sextante.additionalInfo.AdditionalInfoNumericalValue;
9
import es.unex.sextante.additionalInfo.AdditionalInfoVectorLayer;
10
import es.unex.sextante.core.GeoAlgorithm;
11
import es.unex.sextante.core.Sextante;
12
import es.unex.sextante.dataObjects.IFeature;
13
import es.unex.sextante.dataObjects.IFeatureIterator;
14
import es.unex.sextante.dataObjects.IVectorLayer;
15
import es.unex.sextante.dataObjects.vectorFilters.BoundingBoxFilter;
16
import es.unex.sextante.exceptions.GeoAlgorithmExecutionException;
17
import es.unex.sextante.exceptions.RepeatedParameterNameException;
18
import es.unex.sextante.outputs.IOutputChannel;
19
import es.unex.sextante.outputs.Output;
20
import es.unex.sextante.outputs.OutputVectorLayer;
21
import es.unex.sextante.shapesTools.ShapesTools;
22

    
23

    
24
public class VectorClusterAlgorithm
25
         extends
26
            GeoAlgorithm {
27

    
28
   public static final String NUMCLASS      = "NUMCLASS";
29
   public static final String LAYER         = "LAYER";
30
   public static final String FIELDS        = "FIELDS";
31
   public static final String RESULT        = "RESULT";
32

    
33
   private ValueAndClass[]    m_Classes;
34
   private int                m_iFields[];
35
   private double             m_dMean[][];
36
   private int                m_iClasses;
37
   private int                m_iThreshold;
38
   private IVectorLayer       m_LayerIn;
39

    
40
   private static double      NO_DATA       = Double.NEGATIVE_INFINITY;
41
   private static int         NO_DATA_CLASS = Integer.MAX_VALUE;
42

    
43

    
44
   @Override
45
   public boolean processAlgorithm() throws GeoAlgorithmExecutionException {
46

    
47
      int i;
48
      final Class[] types = { Integer.class };
49
      final String[] sFields = { Sextante.getText("Class") };
50

    
51
      m_iClasses = m_Parameters.getParameterValueAsInt(NUMCLASS);
52
      m_LayerIn = m_Parameters.getParameterValueAsVectorLayer(LAYER);
53
      if (!m_bIsAutoExtent) {
54
         m_LayerIn.addFilter(new BoundingBoxFilter(m_AnalysisExtent));
55
      }
56
      m_iFields = getFields(m_Parameters.getParameterValueAsString(FIELDS));
57

    
58
      if (m_iFields == null) {
59
         return false;
60
      }
61

    
62
      m_Classes = new ValueAndClass[m_LayerIn.getShapesCount()];
63
      final IFeatureIterator iter = m_LayerIn.iterator();
64
      i = 0;
65
      while (iter.hasNext()) {
66
         final IFeature feature = iter.next();
67
         final Object[] values = feature.getRecord().getValues();
68
         m_Classes[i] = new ValueAndClass(m_iFields.length);
69
         for (int j = 0; j < m_iFields.length; j++) {
70
            try {
71
               m_Classes[i].dValue[j] = Double.parseDouble(values[m_iFields[j]].toString());
72
            }
73
            catch (final NumberFormatException nfe) {
74
               m_Classes[i].dValue[j] = NO_DATA;
75
            }
76
         }
77
         i++;
78
      }
79

    
80
      classify();
81

    
82
      final Object[][] values = new Object[1][m_LayerIn.getShapesCount()];
83
      for (i = 0; i < m_Classes.length; i++) {
84
         values[0][i] = new Integer(m_Classes[i].iClass);
85
      }
86
      final IOutputChannel channel = getOutputChannel(RESULT);
87
      final Output out = new OutputVectorLayer();
88
      out.setDescription(Sextante.getText("Result"));
89
      out.setName(RESULT);
90
      out.setOutputChannel(channel);
91
      out.setOutputObject(ShapesTools.addFields(m_OutputFactory, m_LayerIn, channel, sFields, values, types));
92
      addOutputObject(out);
93

    
94
      return !m_Task.isCanceled();
95

    
96
   }
97

    
98

    
99
   private int[] getFields(final String s) {
100

    
101

    
102
      final ArrayList indices = new ArrayList();
103

    
104
      final String[] sFields = s.split(",");
105

    
106
      try {
107
         for (int i = 0; i < sFields.length; i++) {
108
            final int iIndex = getFieldIndexByName(sFields[i].trim());
109
            if (iIndex != -1) {
110
               indices.add(new Integer(iIndex));
111
            }
112
         }
113

    
114
         final int iFields[] = new int[indices.size()];
115
         for (int i = 0; i < sFields.length; i++) {
116
            iFields[i] = ((Integer) indices.get(i)).intValue();
117
         }
118

    
119
         return iFields;
120
      }
121
      catch (final Exception e) {
122
         Sextante.addErrorToLog(e);
123
         return null;
124
      }
125

    
126
   }
127

    
128

    
129
   private int getFieldIndexByName(final String sName) {
130

    
131
      final String[] sNames = m_LayerIn.getFieldNames();
132
      for (int i = 0; i < sNames.length; i++) {
133
         if (sNames[i].equals(sName)) {
134
            return i;
135
         }
136
      }
137

    
138
      return -1;
139

    
140

    
141
   }
142

    
143

    
144
   @Override
145
   public void defineCharacteristics() {
146

    
147
      setName(Sextante.getText("Cluster"));
148
      setGroup(Sextante.getText("Tools_for_vector_layers"));
149
      setUserCanDefineAnalysisExtent(true);
150

    
151
      try {
152
         m_Parameters.addInputVectorLayer(LAYER, Sextante.getText("Layer"), AdditionalInfoVectorLayer.SHAPE_TYPE_ANY, true);
153
         m_Parameters.addString("FIELDS", Sextante.getText("fields"), "");
154
         m_Parameters.addNumericalValue(NUMCLASS, Sextante.getText("Number_of_classes"),
155
                  AdditionalInfoNumericalValue.NUMERICAL_VALUE_INTEGER, 3, 2, Integer.MAX_VALUE);
156
         addOutputVectorLayer(RESULT, Sextante.getText("Result"));
157
      }
158
      catch (final RepeatedParameterNameException e) {
159
         Sextante.addErrorToLog(e);
160
      }
161

    
162
   }
163

    
164

    
165
   private void initValues() {
166

    
167
      int i;
168
      int iValues = 0;
169
      boolean bNoData;
170
      double dStep;
171
      double dValue;
172
      final double dMin[] = new double[m_iFields.length];
173
      final double dMax[] = new double[m_iFields.length];
174

    
175
      for (i = 0; i < m_iFields.length; i++) {
176
         dMin[i] = Double.MAX_VALUE;
177
         dMax[i] = Double.NEGATIVE_INFINITY;
178
      }
179

    
180
      for (i = 0; i < m_Classes.length; i++) {
181
         bNoData = false;
182
         for (int j = 0; j < m_Classes[i].dValue.length; j++) {
183
            dValue = m_Classes[i].dValue[j];
184
            if (dValue != NO_DATA) {
185
               dMin[j] = Math.min(dMin[j], dValue);
186
               dMax[j] = Math.max(dMax[j], dValue);
187
            }
188
            else {
189
               bNoData = true;
190
            }
191
         }
192
         if (bNoData) {
193
            m_Classes[i].iClass = NO_DATA_CLASS;
194
         }
195
         else {
196
            iValues++;
197
            m_Classes[i].iClass = 0;
198
         }
199
      }
200

    
201
      m_dMean = new double[m_iClasses][m_iFields.length];
202

    
203
      for (i = 0; i < m_iFields.length; i++) {
204
         dStep = (dMax[i] - dMin[i]) / ((m_iClasses + 2));
205
         for (int j = 0; j < m_iClasses; j++) {
206
            m_dMean[j][i] = dMin[i] + dStep * (j + 1);
207
         }
208
      }
209

    
210
      m_iThreshold = (int) (iValues * 0.02);
211

    
212
   }
213

    
214

    
215
   private boolean classify() {
216

    
217
      int i, j;
218
      int iChangedCells;
219
      int iPrevClass;
220
      int iClass;
221
      final int iCells[] = new int[m_iClasses];
222
      double dNewMean[][];
223
      double swap[][];
224

    
225
      initValues();
226

    
227
      dNewMean = new double[m_iClasses][m_iFields.length];
228

    
229
      do {
230
         Arrays.fill(iCells, 0);
231
         iChangedCells = 0;
232

    
233
         for (i = 0; i < m_iClasses; i++) {
234
            Arrays.fill(dNewMean[i], 0.0);
235
         }
236
         for (i = 0; i < m_Classes.length; i++) {
237
            iPrevClass = m_Classes[i].iClass;
238
            if (iPrevClass != NO_DATA_CLASS) {
239
               iClass = getClass(m_Classes[i].dValue);
240
               m_Classes[i].iClass = iClass;
241
               for (j = 0; j < m_iFields.length; j++) {
242
                  dNewMean[iClass][j] += m_Classes[i].dValue[j];
243
               }
244
               iCells[iClass]++;
245
               if (iClass != iPrevClass) {
246
                  iChangedCells++;
247
               }
248
            }
249
         }
250

    
251
         for (i = 0; i < m_iFields.length; i++) {
252
            for (j = 0; j < m_iClasses; j++) {
253
               dNewMean[j][i] /= iCells[j];
254
            }
255
         }
256

    
257
         swap = m_dMean;
258
         m_dMean = dNewMean;
259
         dNewMean = swap;
260

    
261
         setProgressText(Sextante.getText("Modified_classes") + Integer.toString(iChangedCells));
262

    
263
         if (m_Task.isCanceled()) {
264
            return false;
265
         }
266

    
267
      }
268
      while (iChangedCells > m_iThreshold);
269

    
270
      return true;
271

    
272
   }
273

    
274

    
275
   private int getClass(final double[] dValues) {
276

    
277
      int iClass = 0;
278
      double dMinDist = Double.MAX_VALUE;
279
      double dDist;
280
      double dDif;
281

    
282
      for (int i = 0; i < m_iClasses; i++) {
283
         dDist = 0;
284
         for (int j = 0; j < dValues.length; j++) {
285
            dDif = m_dMean[i][j] - dValues[j];
286
            dDist += (dDif * dDif);
287
         }
288
         if (dDist < dMinDist) {
289
            dMinDist = dDist;
290
            iClass = i;
291
         }
292
      }
293

    
294
      return iClass;
295
   }
296

    
297
   private class ValueAndClass {
298

    
299
      public double dValue[];
300
      public int    iClass;
301

    
302

    
303
      public ValueAndClass(final int i) {
304

    
305
         dValue = new double[i];
306

    
307
      }
308

    
309
   }
310

    
311

    
312
}