0001: /*
0002: * Created on 12.01.2005
0003: *
0004: * SVN header information:
0005: * $Author: mentaer $
0006: * $Rev: 902 $
0007: * $Date: 2007-07-30 09:51:46 -0700 (Mon, 30 Jul 2007) $
0008: * $Id: FeatureCollectionTools.java 902 2007-07-30 16:51:46Z mentaer $s
0009: */
0010: package de.fho.jump.pirol.utilities.apiTools;
0011:
0012: import java.util.ArrayList;
0013: import java.util.Date;
0014: import java.util.HashMap;
0015: import java.util.HashSet;
0016: import java.util.List;
0017: import java.util.Map;
0018: import java.util.Set;
0019:
0020: import com.vividsolutions.jts.geom.Coordinate;
0021: import com.vividsolutions.jts.geom.Envelope;
0022: import com.vividsolutions.jts.geom.Geometry;
0023: import com.vividsolutions.jts.geom.GeometryFactory;
0024: import com.vividsolutions.jump.feature.AttributeType;
0025: import com.vividsolutions.jump.feature.BasicFeature;
0026: import com.vividsolutions.jump.feature.Feature;
0027: import com.vividsolutions.jump.feature.FeatureCollection;
0028: import com.vividsolutions.jump.feature.FeatureDataset;
0029: import com.vividsolutions.jump.feature.FeatureSchema;
0030: import com.vividsolutions.jump.workbench.model.Layer;
0031: import com.vividsolutions.jump.workbench.plugin.PlugInContext;
0032: import com.vividsolutions.jump.workbench.ui.EditTransaction;
0033:
0034: import de.fho.jump.pirol.utilities.FeatureCollection.PirolFeatureCollection;
0035: import de.fho.jump.pirol.utilities.FormulaParsing.FormulaValue;
0036: import de.fho.jump.pirol.utilities.attributes.AttributeInfo;
0037: import de.fho.jump.pirol.utilities.comparisonAndSorting.ObjectComparator;
0038: import de.fho.jump.pirol.utilities.debugOutput.DebugUserIds;
0039: import de.fho.jump.pirol.utilities.debugOutput.PersonalLogger;
0040: import de.fho.jump.pirol.utilities.metaData.MetaInformationHandler;
0041:
0042: /**
0043: * Class to speed up handling of FeatureCollections (or lists of features) during progamming by implementing
0044: * a set of common tasks.
0045: * Most functions can be used in a static way, but on the other hand for each FeatureCollection a instance of this class can be invoked.
0046: * This might be more convenient, if there is more than one thing to do with the same feature collection.
0047: *
0048: * @author Ole Rahn
0049: * <br>
0050: * <br>FH Osnabrück - University of Applied Sciences Osnabrück,
0051: * <br>Project: PIROL (2005),
0052: * <br>Subproject: Daten- und Wissensmanagement
0053: *
0054: * @version $Rev: 902 $
0055: */
0056:
0057: public class FeatureCollectionTools extends ToolToMakeYourLifeEasier {
0058:
0059: protected FeatureCollection fc = null;
0060: protected List<Feature> featureList;
0061: private HashMap<Integer, Feature> fid2Object = new HashMap<Integer, Feature>();
0062:
0063: protected static PersonalLogger logger = new PersonalLogger(
0064: DebugUserIds.ALL);
0065:
0066: public FeatureCollectionTools(FeatureCollection fc) {
0067: super ();
0068: this .fc = fc;
0069: this .featureList = this .fc.getFeatures();
0070: }
0071:
0072: public FeatureCollectionTools(List<Feature> fcl) {
0073: super ();
0074: this .featureList = fcl;
0075: }
0076:
0077: /**
0078: * gets the Feature with the given FID.
0079: *@param fid FID to look for
0080: *@return the feature
0081: */
0082: public Feature getFeature(int fid) {
0083: Integer FID = new Integer(fid);
0084: if (!this .fid2Object.containsKey(FID)) {
0085: this .fid2Object.put(FID, FeatureCollectionTools
0086: .getFeatureFromCollection(this .featureList, fid));
0087: }
0088:
0089: return (Feature) this .fid2Object.get(FID);
0090: }
0091:
0092: /**
0093: * Get the feature with the specified ID from the List
0094: *@param features array with Feature objects
0095: *@param fid the feature ID we are looking for
0096: *@return feature with specified FID if exists, else null
0097: */
0098: public static Feature getFeatureFromCollection(
0099: List<Feature> features, int fid) {
0100: return FeatureCollectionTools.getFeatureFromCollection(
0101: (Feature[]) features.toArray(new Feature[0]), fid);
0102: }
0103:
0104: /**
0105: * Get the feature with the specified ID from the array
0106: *@param features array with Feature objects
0107: *@param fid the feature ID we are looking for
0108: *@return feature with specified FID if exists, else null
0109: */
0110: public static Feature getFeatureFromCollection(Feature[] features,
0111: int fid) {
0112: Feature feat;
0113:
0114: for (int i = 0; i < features.length; i++) {
0115: feat = features[i];
0116:
0117: if (feat.getID() == fid) {
0118: return feat;
0119: }
0120: }
0121: return null;
0122: }
0123:
0124: /**
0125: * deep copies a the FeatureSchema, the Features and their Geometries
0126: * @param fc the FeatureCollection to copy
0127: * @return the new copied FeatureCollection
0128: */
0129: public final static PirolFeatureCollection cloneFeatureCollection(
0130: FeatureCollection fc) {
0131: FeatureSchema clonedSchema = (FeatureSchema) fc
0132: .getFeatureSchema().clone();
0133: FeatureDataset newFc = new FeatureDataset(clonedSchema);
0134:
0135: Feature[] featuresToCopy = FeatureCollection2FeatureArray(fc);
0136: Feature newFeat = null;
0137: AttributeType attrType = null;
0138:
0139: for (int i = 0; i < featuresToCopy.length; i++) {
0140: newFeat = new BasicFeature(clonedSchema);
0141:
0142: for (int attr = 0; attr < clonedSchema.getAttributeCount(); attr++) {
0143: attrType = clonedSchema.getAttributeType(attr);
0144: /**
0145: * FIX for Null Values.
0146: * Added by mweller 24.07.2007
0147: */
0148: if (featuresToCopy[i].getAttribute(attr) != null) {
0149: if (attrType.equals(AttributeType.DOUBLE)) {
0150: newFeat.setAttribute(attr, new Double(
0151: ((Double) featuresToCopy[i]
0152: .getAttribute(attr))
0153: .doubleValue()));
0154: } else if (attrType.equals(AttributeType.INTEGER)) {
0155: newFeat.setAttribute(attr,
0156: new Integer(
0157: ((Integer) featuresToCopy[i]
0158: .getAttribute(attr))
0159: .intValue()));
0160: } else if (attrType.equals(AttributeType.STRING)) {
0161: newFeat.setAttribute(attr,
0162: ((String) featuresToCopy[i]
0163: .getAttribute(attr)).trim());
0164: } else if (attrType.equals(AttributeType.GEOMETRY)) {
0165: newFeat.setAttribute(attr,
0166: ((Geometry) featuresToCopy[i]
0167: .getAttribute(attr)).clone());
0168: } else if (attrType.equals(AttributeType.DATE)) {
0169: newFeat.setAttribute(attr,
0170: ((Date) featuresToCopy[i]
0171: .getAttribute(attr)).clone());
0172: } else if (attrType.equals(AttributeType.OBJECT)) {
0173: logger.printError("not implemented!");
0174: newFeat.setAttribute(attr, (featuresToCopy[i]
0175: .getAttribute(attr)));
0176: }
0177: } else {
0178: newFeat.setAttribute(attr, null);
0179: }
0180: }
0181:
0182: newFc.add(newFeat);
0183: }
0184: return MetaInformationHandler
0185: .createPirolFeatureCollection(newFc);
0186: }
0187:
0188: /**
0189: * Get the feature with the specified ID from the FeatureCollection
0190: *@param features array with Feature objects
0191: *@param fid the feature ID we are looking for
0192: *@return feature with specified FID if exists, else null
0193: */
0194: public static Feature getFeatureFromCollection(
0195: FeatureCollection features, int fid) {
0196: return FeatureCollectionTools.getFeatureFromCollection(features
0197: .getFeatures(), fid);
0198: }
0199:
0200: /**
0201: *@param features list of features to calculate the mean for
0202: *@param attr name of attribute to calculate the mean for
0203: *@return the mean (double because a mean of integers will very likely be a double)
0204: */
0205: public static double getAritmeticMiddleForAttribute(
0206: Feature[] features, String attr) {
0207:
0208: if (features == null || features.length == 0)
0209: return Double.NaN;
0210:
0211: Feature f = features[0];
0212: FeatureSchema fs = f.getSchema();
0213: int attrInd = fs.getAttributeIndex(attr);
0214: return FeatureCollectionTools.getAritmeticMiddleForAttribute(
0215: features, attrInd);
0216: }
0217:
0218: /**
0219: * Method to calculate means (or modes) for the attributes given. If means or modes
0220: * are calulated depends on the attribute type of each given given attribute.
0221: * This method is hopefully faster, than calculation each mean (mode) in an extra loop,
0222: * if there are more means (modes) to calculate than one...
0223: *@param features list of features to calculate mean/modes for
0224: *@param attrs array of attribute names to calculate mean/modes for
0225: *@return array of objects, representing means (or modes) --> e.g. Double, Integer or String objects.
0226: */
0227: public static Object[] getMeanOrModeForAttributes(
0228: Feature[] features, String[] attrs) {
0229: if (features == null || features.length == 0)
0230: return null;
0231:
0232: int numVals = features.length;
0233: int numAttrs = attrs.length;
0234:
0235: FeatureSchema fs = features[0].getSchema();
0236: Object[] meansOrModes = new Object[numAttrs];
0237: AttributeType[] ats = new AttributeType[numAttrs];
0238:
0239: Object[] sumsOrMaps = new Object[numAttrs];
0240: boolean[] atIsNumeric = new boolean[numAttrs];
0241:
0242: for (int i = 0; i < numAttrs; i++) {
0243: ats[i] = fs.getAttributeType(attrs[i]);
0244: atIsNumeric[i] = FeatureCollectionTools
0245: .isAttributeTypeNumeric(ats[i]);
0246: if (atIsNumeric[i]) {
0247: sumsOrMaps[i] = new Double(0);
0248: } else {
0249: // Map; no. of max. occurances; modus value
0250: sumsOrMaps[i] = new Object[] { new HashMap(),
0251: new Integer(0), null };
0252: }
0253: }
0254:
0255: Feature currFeat;
0256: Double sum;
0257: Object value, modus;
0258: Map<Object, Object> map;
0259:
0260: Feature[] featArray = features;
0261:
0262: Integer maxOcc;
0263: int occ = 0;
0264:
0265: for (int i = 0; i < featArray.length; i++) {
0266: currFeat = featArray[i];
0267: for (int j = 0; j < numAttrs; j++) {
0268: if (atIsNumeric[j]) {
0269: sum = ((Double) sumsOrMaps[j]);
0270: if (currFeat.getAttribute(attrs[j]) != null) {
0271: sumsOrMaps[j] = new Double(
0272: sum.doubleValue()
0273: + ObjectComparator
0274: .getDoubleValue(currFeat
0275: .getAttribute(attrs[j])));
0276: } else {
0277: // value is skipped
0278: FeatureCollectionTools.logger
0279: .printMinorError("skipped a value (NULL), when calculating mean for "
0280: + attrs[j]);
0281: }
0282: } else {
0283: value = currFeat.getAttribute(attrs[j]);
0284:
0285: if (value.getClass().equals(String.class)) {
0286: ((String) value).trim();
0287: }
0288:
0289: map = (Map) ((Object[]) sumsOrMaps[j])[0];
0290: maxOcc = (Integer) ((Object[]) sumsOrMaps[j])[1];
0291: modus = ((Object[]) sumsOrMaps[j])[2];
0292:
0293: if (map.containsKey(value)) {
0294: occ = ((Integer) map.get(value)).intValue();
0295: occ += 1;
0296: map.remove(value);
0297: } else {
0298: occ = 1;
0299: }
0300: map.put(value, new Integer(occ));
0301:
0302: if (occ > maxOcc.intValue()) {
0303: maxOcc = new Integer(occ);
0304: modus = value;
0305: }
0306:
0307: sumsOrMaps[j] = new Object[] { map, maxOcc, modus };
0308:
0309: }
0310: }
0311: }
0312:
0313: for (int i = 0; i < meansOrModes.length; i++) {
0314: if (atIsNumeric[i]) {
0315: meansOrModes[i] = new Double(((Double) sumsOrMaps[i])
0316: .doubleValue()
0317: / ((double) numVals));
0318: } else {
0319: meansOrModes[i] = ((Object[]) sumsOrMaps[i])[2];
0320: }
0321: }
0322:
0323: return meansOrModes;
0324: }
0325:
0326: /**
0327: * Creates an envelope object for the features in the given array. This is an easy way
0328: * to get an envelope for a subset of a layer's features.
0329: *@param features array of Feature object to create an envelope for
0330: *@return the envelope containing the given features
0331: */
0332: public static Envelope getEnvelopeForFeatures(Feature[] features) {
0333: Envelope env = null;
0334: Feature feat;
0335:
0336: for (int i = 0; i < features.length; i++) {
0337: feat = features[i];
0338: if (env == null) {
0339: env = new Envelope(feat.getGeometry().getCoordinate());
0340: } else {
0341: env.expandToInclude(feat.getGeometry().getCoordinate());
0342: }
0343: }
0344:
0345: return env;
0346: }
0347:
0348: /**
0349: *@param features list of features to calculate the mean for
0350: *@param attr index of attribute to calculate the mean for
0351: *@return the mean (double because a mean of integers will very likely be a double)
0352: */
0353: public static double getAritmeticMiddleForAttribute(
0354: List<Feature> features, int attr) {
0355: return FeatureCollectionTools.getAritmeticMiddleForAttribute(
0356: (Feature[]) features.toArray(new Feature[0]), attr);
0357: }
0358:
0359: /**
0360: *@param featArray array of features to calculate the mean for
0361: *@param attr index of attribute to calculate the mean for
0362: *@return the mean (double because a mean of integers will very likely be a double)
0363: */
0364: public static double getAritmeticMiddleForAttribute(
0365: Feature[] featArray, int attr) {
0366: double sumVals = 0;
0367: int numVals = 0;
0368:
0369: if (featArray.length == 0) {
0370: logger
0371: .printWarning("no features in list - return value will be NAN!");
0372: return Double.NaN;
0373: }
0374:
0375: Feature f = featArray[0];
0376: FeatureSchema fs = f.getSchema();
0377:
0378: if (FeatureCollectionTools.isAttributeTypeNumeric(fs
0379: .getAttributeType(attr))) {
0380:
0381: //Iterator iter = features.iterator();
0382: Feature feat;
0383: double value;
0384:
0385: for (int i = 0; i < featArray.length; i++) {
0386: feat = featArray[i];
0387: value = ObjectComparator.getDoubleValue(feat
0388: .getAttribute(attr));
0389:
0390: sumVals += value;
0391: numVals++;
0392: }
0393: }
0394:
0395: return (sumVals / (double) numVals);
0396: }
0397:
0398: /**
0399: * Calculates the center of mass for the gives features' geometries.
0400: * It's like getCentroid(), but puts out one center of mass for N features instead of N centers for N features.
0401: *@param features the features
0402: *@return the point, representing the center of mass
0403: */
0404: public static Geometry getCenterOfMass(Feature[] features) {
0405: double sumX = 0, sumY = 0;
0406: GeometryFactory gf = new GeometryFactory();
0407:
0408: if (features == null || features.length == 0)
0409: return null;
0410:
0411: Feature feat;
0412:
0413: for (int i = 0; i < features.length; i++) {
0414: feat = features[i];
0415: sumX += feat.getGeometry().getCoordinate().x;
0416: sumY += feat.getGeometry().getCoordinate().y;
0417: }
0418:
0419: double newX = sumX / (double) features.length;
0420: double newY = sumY / (double) features.length;
0421:
0422: return gf.createPoint(new Coordinate(newX, newY));
0423: }
0424:
0425: /**
0426: *@param features list of features
0427: *@param attr name of attribute
0428: *@return number of differnt values in the given features attributes or -1 if an error occurs
0429: */
0430: public static Set getSetOfDifferentAttributeValues(
0431: Feature[] features, String attr) {
0432: Feature f = features[0];
0433: FeatureSchema fs = f.getSchema();
0434: int attrInd = fs.getAttributeIndex(attr);
0435: return FeatureCollectionTools.getSetOfDifferentAttributeValues(
0436: features, attrInd);
0437: }
0438:
0439: /**
0440: *@param features list of features
0441: *@param attr index of attribute
0442: *@return number of differnt values in the given features attributes or -1 if an error occurs
0443: */
0444: public static Set<Object> getSetOfDifferentAttributeValues(
0445: Feature[] features, int attr) {
0446: Feature[] featArray = features;
0447: int numFeats = featArray.length;
0448:
0449: HashSet<Object> differentValues = new HashSet<Object>();
0450: Object val;
0451:
0452: for (int i = numFeats - 1; i >= 0; i--) {
0453:
0454: val = featArray[i].getAttribute(attr);
0455: //if (!differentValues.contains(val))
0456: differentValues.add(val);
0457: }
0458:
0459: return differentValues;
0460: }
0461:
0462: /**
0463: *@param features list of features
0464: *@param attr name of attribute
0465: *@return number of differnt values in the given features attributes or -1 if an error occurs
0466: */
0467: public static int getNumOfDifferentAttributeValues(
0468: Feature[] features, String attr) {
0469: Feature f = features[0];
0470: FeatureSchema fs = f.getSchema();
0471: int attrInd = fs.getAttributeIndex(attr);
0472: return FeatureCollectionTools.getNumOfDifferentAttributeValues(
0473: features, attrInd);
0474: }
0475:
0476: /**
0477: *@param features list of features
0478: *@param attr index of attribute
0479: *@return number of differnt values in the given features attributes or -1 if an error occurs
0480: */
0481: public static int getNumOfDifferentAttributeValues(
0482: Feature[] features, int attr) {
0483: return FeatureCollectionTools.getSetOfDifferentAttributeValues(
0484: features, attr).size();
0485: }
0486:
0487: /**
0488: *@param features list of features to calculate the mode for
0489: *@param attr name of attribute to calculate the mode for
0490: *@return the mode
0491: */
0492: public static Object getModusForAttribute(Feature[] features,
0493: String attr) {
0494: Feature f = features[0];
0495: FeatureSchema fs = f.getSchema();
0496: int attrInd = fs.getAttributeIndex(attr);
0497: return FeatureCollectionTools.getModusForAttribute(features,
0498: attrInd);
0499: }
0500:
0501: /**
0502: * Counts the number of appearances of each value of the given attributes within the given features.
0503: * (Somewhat like a histogram for each given attribute, but each histogram class is just a single value.)
0504: * @param features array of Features to count value appearances for
0505: * @param attrs array of attribute indices of attributes to count value appearances for
0506: * @return Array of mappings of values to number of appearances
0507: */
0508: public final static HashMap<Object, Integer>[] getValueAppearancesCount(
0509: Feature[] features, int[] attrs) {
0510: HashMap<Object, Integer>[] value2NumAppearanceMaps = new HashMap[attrs.length];
0511:
0512: for (int i = 0; i < attrs.length; i++) {
0513: value2NumAppearanceMaps[i] = new HashMap<Object, Integer>();
0514: }
0515:
0516: Feature feat;
0517: Object value;
0518:
0519: for (int i = 0; i < features.length; i++) {
0520: feat = features[i];
0521:
0522: for (int attInd = 0; attInd < attrs.length; attInd++) {
0523: value = feat.getAttribute(attrs[attInd]);
0524:
0525: if (!value2NumAppearanceMaps[attInd].containsKey(value)) {
0526: value2NumAppearanceMaps[attInd].put(value, 1);
0527: } else {
0528: value2NumAppearanceMaps[attInd].put(value,
0529: value2NumAppearanceMaps[attInd].get(value)
0530: .intValue() + 1);
0531: }
0532:
0533: }
0534:
0535: }
0536:
0537: return value2NumAppearanceMaps;
0538: }
0539:
0540: /**
0541: *@param features list of features to calculate the mode for
0542: *@param attr index of attribute to calculate the mode for
0543: *@return the mode
0544: */
0545: public static Object getModusForAttribute(Feature[] features,
0546: int attr) {
0547: HashMap<Object, Integer> map = new HashMap<Object, Integer>();
0548: Object modus = null;
0549: int maxNr = 0;
0550:
0551: if (features == null || features.length == 0)
0552: return null;
0553:
0554: Feature[] featArray = features;
0555: Feature feat;
0556: Object value;
0557: int occ, numFeats = featArray.length;
0558:
0559: for (int i = 0; i < numFeats; i++) {
0560: feat = featArray[i];
0561:
0562: value = feat.getAttribute(attr);
0563:
0564: if (value.getClass().getName().equals(
0565: String.class.getName())) {
0566: ((String) value).trim();
0567: }
0568:
0569: if (map.containsKey(value)) {
0570: occ = ((Integer) map.get(value)).intValue();
0571: occ += 1;
0572: map.remove(value);
0573: } else {
0574: occ = 1;
0575: }
0576: map.put(value, new Integer(occ));
0577:
0578: if (occ > maxNr) {
0579: maxNr = occ;
0580: modus = value;
0581: }
0582: }
0583:
0584: return modus;
0585: }
0586:
0587: /**
0588: * deletes the given features from the map. It thereby creates an EditTransaction that
0589: * enables the user to undo the deletion.
0590: *@param features features to be deleted
0591: *@param context curr. PlugIn context
0592: */
0593: public static void deleteFeatures(List<Feature> features,
0594: PlugInContext context) {
0595: Map layer2FeatList = LayerTools.getLayer2FeatureMap(features,
0596: context);
0597:
0598: Layer[] layersWithFeatures = (Layer[]) layer2FeatList.keySet()
0599: .toArray(new Layer[0]);
0600: Feature[] selFeatsOfLayer;
0601:
0602: for (int i = 0; i < layersWithFeatures.length; i++) {
0603: EditTransaction edtr = new EditTransaction(new ArrayList(),
0604: "delete features", layersWithFeatures[i], true,
0605: true, context.getLayerViewPanel());
0606:
0607: selFeatsOfLayer = (Feature[]) ((List) layer2FeatList
0608: .get(layersWithFeatures[i]))
0609: .toArray(new Feature[0]);
0610:
0611: for (int j = 0; j < selFeatsOfLayer.length; j++) {
0612: edtr.deleteFeature(selFeatsOfLayer[j]);
0613: }
0614:
0615: edtr.commit();
0616: edtr.clearEnvelopeCaches();
0617: }
0618: }
0619:
0620: /**
0621: * "deep copys" the given Feature
0622: *@param feat the feature to be copied
0623: *@return copy of the feature
0624: */
0625: public static Feature copyFeature(Feature feat) {
0626: Feature newFeat = new BasicFeature(feat.getSchema());
0627:
0628: int numAttr = feat.getSchema().getAttributeCount();
0629:
0630: for (int i = 0; i < numAttr; i++) {
0631: newFeat.setAttribute(feat.getSchema().getAttributeName(i),
0632: feat.getAttribute(i));
0633: }
0634:
0635: newFeat.setGeometry((Geometry) feat.getGeometry());
0636:
0637: return newFeat;
0638: }
0639:
0640: /**
0641: * "deep copys" the given Feature and thereby sets the given feature schema
0642: *@param feat the feature to be copied
0643: *@param newFs the new feature schema
0644: *@return copy of the feature
0645: */
0646: public static Feature copyFeatureAndSetFeatureSchema(Feature feat,
0647: FeatureSchema newFs) {
0648: feat = feat.clone(true);
0649: FeatureSchema fs = feat.getSchema();
0650:
0651: Feature newFeat = new BasicFeature(newFs);
0652: int numAttr = feat.getSchema().getAttributeCount();
0653:
0654: for (int i = 0; i < numAttr; i++) {
0655: newFeat.setAttribute(fs.getAttributeName(i), feat
0656: .getAttribute(fs.getAttributeName(i)));
0657: }
0658:
0659: newFeat.setGeometry((Geometry) feat.getGeometry());
0660:
0661: return newFeat;
0662: }
0663:
0664: public String getUniqueAttributeName(String attr) {
0665: return FeatureCollectionTools.getUniqueAttributeName(this .fc,
0666: attr);
0667: }
0668:
0669: public static String getUniqueAttributeName(FeatureCollection fc,
0670: String attr) {
0671: FeatureSchema fs = fc.getFeatureSchema();
0672: String newName = new String(attr);
0673: String suffix = "";
0674:
0675: for (int i = 2; FeatureCollectionTools.attributeExistsInSchema(
0676: fs, newName + suffix); i++) {
0677: suffix = " (" + i + ")";
0678: }
0679:
0680: return newName + suffix;
0681: }
0682:
0683: protected static boolean attributeExistsInSchema(FeatureSchema fs,
0684: String attr) {
0685: try {
0686: int index = fs.getAttributeIndex(attr);
0687: return (index >= 0);
0688: } catch (RuntimeException e) {
0689: return false;
0690: }
0691: }
0692:
0693: public PirolFeatureCollection addAttributeToFeatureCollection(
0694: String attr, AttributeType at, Object defaultVal) {
0695: if (this .fc != null)
0696: return FeatureCollectionTools
0697: .addAttributeToFeatureCollection(this .fc, attr, at,
0698: defaultVal, true);
0699: return null;
0700: }
0701:
0702: public static boolean isAttributeTypeNumeric(AttributeType at) {
0703: return (at.equals(AttributeType.DOUBLE) || at
0704: .equals(AttributeType.INTEGER));
0705: }
0706:
0707: /**
0708: * Method to apply a given formula to the given, new attribute of the given featureCollection
0709: *@param oldFc old FeatureCollection that will be replaced by the new one
0710: *@param attrInfo information for the new attribute
0711: *@param formula the parsed formula
0712: *@return FeatureCollection containing the new attribute
0713: */
0714: public static PirolFeatureCollection applyFormulaToFeatureCollection(
0715: FeatureCollection oldFc, AttributeInfo attrInfo,
0716: FormulaValue formula, boolean clearOldFeatureCollection) {
0717:
0718: PirolFeatureCollection newFc = FeatureCollectionTools
0719: .addAttributeToFeatureCollection(oldFc, attrInfo,
0720: clearOldFeatureCollection);
0721:
0722: Feature[] features = (Feature[]) newFc.getFeatures().toArray(
0723: new Feature[0]);
0724: Feature feat;
0725: int numFeats = features.length, attrInd = newFc
0726: .getFeatureSchema().getAttributeIndex(
0727: attrInfo.getUniqueAttributeName());
0728:
0729: for (int i = 0; i < numFeats; i++) {
0730: feat = features[i];
0731: feat.setAttribute(attrInd, new Double(formula
0732: .getValue(feat)));
0733:
0734: if (i % 500 == 0)
0735: logger.printDebug("done: " + i);
0736: }
0737: return newFc;
0738: }
0739:
0740: public static PirolFeatureCollection addAttributeToFeatureCollection(
0741: FeatureCollection fc, AttributeInfo attrInfo) {
0742: return FeatureCollectionTools.addAttributeToFeatureCollection(
0743: fc, attrInfo.getUniqueAttributeName(), attrInfo
0744: .getAttributeType(), attrInfo.getNullValue(),
0745: true);
0746: }
0747:
0748: public static PirolFeatureCollection addAttributeToFeatureCollection(
0749: FeatureCollection fc, AttributeInfo attrInfo,
0750: boolean clearOldFeatureCollection) {
0751: return FeatureCollectionTools.addAttributeToFeatureCollection(
0752: fc, attrInfo.getUniqueAttributeName(), attrInfo
0753: .getAttributeType(), attrInfo.getNullValue(),
0754: clearOldFeatureCollection);
0755: }
0756:
0757: /**
0758: * Method to add a new attribute to an existing FeatureCollection. Since there is no "legal" way to
0759: * add an attribute to a FeatureCollection, this method creates (and returns) a new FeatureCollection with a new
0760: * FeatureSchema to do this operation. If a layer is to be manipulated the new FeatureCollection has to be set
0761: * as THE FeatureCollection for the layer...
0762: *@param fc the old feature collection
0763: *@param attr name of the new attribute
0764: *@param at type of the new attribute
0765: *@param defaultVal the initial value for the attribute, since we do not want NULL values in the attribute table
0766: *@param clearOldFeatureCollection if true the old feature collection will be erased to save RAM
0767: *@return new FeatureCollection with a new FeatureSchema including the new attribute
0768: */
0769: public static PirolFeatureCollection addAttributeToFeatureCollection(
0770: FeatureCollection fc, String attr, AttributeType at,
0771: Object defaultVal, boolean clearOldFeatureCollection) {
0772: FeatureSchema fs = (FeatureSchema) fc.getFeatureSchema()
0773: .clone();
0774: fs.addAttribute(attr, at);
0775:
0776: MetaInformationHandler mih = new MetaInformationHandler(
0777: MetaInformationHandler.createPirolFeatureCollection(fc));
0778:
0779: PirolFeatureCollection newFc = MetaInformationHandler
0780: .createPirolFeatureCollection(new FeatureDataset(fs));
0781:
0782: if (mih.containsMetaInformation()) {
0783: newFc.setMetaInformation(mih
0784: .getExistentMetaInformationMap());
0785: }
0786: mih = null;
0787:
0788: Feature feat, newFeat;
0789:
0790: if (at.equals(AttributeType.INTEGER)) {
0791: if (Double.class.isInstance(defaultVal)) {
0792: defaultVal = new Integer(((Double) defaultVal)
0793: .intValue());
0794: }
0795: }
0796:
0797: Feature[] featArray = (Feature[]) fc.getFeatures().toArray(
0798: new Feature[0]);
0799:
0800: if (clearOldFeatureCollection)
0801: fc.clear();
0802:
0803: int featuresDone = 0;
0804:
0805: for (int i = featArray.length - 1; i >= 0; i--, featuresDone++) {
0806: feat = featArray[i];
0807:
0808: newFeat = FeatureCollectionTools
0809: .copyFeatureAndSetFeatureSchema(feat, fs);
0810: newFeat.setAttribute(attr, defaultVal);
0811: newFc.add(newFeat);
0812:
0813: if (i % 10000 == 0 && i != 0) {
0814: featArray = (Feature[]) FeatureCollectionTools
0815: .resizeArray(featArray, featArray.length
0816: - featuresDone);
0817: featuresDone = 0;
0818: if (i % 50000 == 0) {
0819: System.gc();
0820: }
0821: }
0822: }
0823:
0824: featArray = null;
0825:
0826: return newFc;
0827: }
0828:
0829: /**
0830: * Method to add a new attribute to an existing FeatureCollection. Since there is no "legal" way to
0831: * add an attribute to a FeatureCollection, this method creates (and returns) a new FeatureCollection with a new
0832: * FeatureSchema to do this operation. If a layer is to be manipulated the new FeatureCollection has to be set
0833: * as THE FeatureCollection for the layer...
0834: *@param fc the old feature collection
0835: *@param attr name of the new attribute
0836: *@param at type of the new attribute
0837: *@param defaultVal the initial value for the attribute, since we do not want NULL values in the attribute table
0838: *@return new FeatureCollection with a new FeatureSchema including the new attribute
0839: */
0840: public static PirolFeatureCollection addAttributeToFeatureCollection(
0841: FeatureCollection fc, String attr, AttributeType at,
0842: Object defaultVal) {
0843: return FeatureCollectionTools.addAttributeToFeatureCollection(
0844: fc, attr, at, defaultVal, true);
0845: }
0846:
0847: /**
0848: * Adds multiple attributes to the FeatureCollection
0849: *@param attributeInfos list containing the attributes (as AttributeInfo objects) to be added
0850: *@return a new FeatureCollection containing the old and the new attributes
0851: *
0852: *@see AttributeInfo
0853: */
0854: public PirolFeatureCollection addAttributesToFeatureCollection(
0855: List attributeInfos) {
0856: return FeatureCollectionTools.addAttributesToFeatureCollection(
0857: this .fc, attributeInfos);
0858: }
0859:
0860: /**
0861: * Adds multiple attributes to a FeatureCollection
0862: *@param fc the source feature collection
0863: *@param attributeInfos list containing the attributes (as AttributeInfo objects) to be added
0864: *@return a new FeatureCollection containing the old and the new attributes
0865: *
0866: *@see AttributeInfo
0867: */
0868: public static PirolFeatureCollection addAttributesToFeatureCollection(
0869: FeatureCollection fc, List<AttributeInfo> attributeInfos) {
0870: return FeatureCollectionTools.addAttributesToFeatureCollection(
0871: fc, (AttributeInfo[]) attributeInfos
0872: .toArray(new AttributeInfo[0]));
0873: }
0874:
0875: public static PirolFeatureCollection addAttributesToFeatureCollection(
0876: FeatureCollection fc, AttributeInfo[] attributeInfos) {
0877: return FeatureCollectionTools.addAttributesToFeatureCollection(
0878: fc, attributeInfos, true);
0879: }
0880:
0881: /**
0882: * Adds multiple attributes to a FeatureCollection
0883: *@param fc the source feature collection
0884: *@param attributeInfos array containing the attributes to be added
0885: *@param clearOriginalFeatureCollection set true, if you want to save RAM by
0886: *clearing the original FeatureCollection, false if you still want to use it.
0887: *@return a new FeatureCollection containing the old and the new attributes
0888: */
0889: public static PirolFeatureCollection addAttributesToFeatureCollection(
0890: FeatureCollection fc, AttributeInfo[] attributeInfos,
0891: boolean clearOriginalFeatureCollection) {
0892: FeatureSchema fs = (FeatureSchema) fc.getFeatureSchema()
0893: .clone();
0894:
0895: MetaInformationHandler mih = new MetaInformationHandler(
0896: MetaInformationHandler.createPirolFeatureCollection(fc));
0897:
0898: AttributeInfo attrInfo;
0899:
0900: for (int i = 0; i < attributeInfos.length; i++) {
0901: attrInfo = attributeInfos[i];
0902: fs.addAttribute(attrInfo.getUniqueAttributeName(), attrInfo
0903: .getAttributeType());
0904: }
0905:
0906: PirolFeatureCollection newFc = MetaInformationHandler
0907: .createPirolFeatureCollection(new FeatureDataset(fs));
0908:
0909: if (mih.containsMetaInformation()) {
0910: newFc.setMetaInformation(mih
0911: .getExistentMetaInformationMap());
0912: }
0913: mih = null;
0914:
0915: Feature feat, newFeat;
0916:
0917: Feature[] featArray = (Feature[]) fc.getFeatures().toArray(
0918: new Feature[0]);
0919:
0920: if (clearOriginalFeatureCollection)
0921: fc.clear();
0922:
0923: int featuresDone = 0;
0924:
0925: for (int i = featArray.length - 1; i >= 0; i--, featuresDone++) {
0926: feat = featArray[i];
0927:
0928: newFeat = FeatureCollectionTools
0929: .copyFeatureAndSetFeatureSchema(feat, fs);
0930:
0931: for (int j = 0; j < attributeInfos.length; j++) {
0932: attrInfo = attributeInfos[j];
0933: newFeat.setAttribute(attrInfo.getUniqueAttributeName(),
0934: attrInfo.getNullValue());
0935: }
0936:
0937: newFc.add(newFeat);
0938:
0939: if (i % 10000 == 0 && i != 0) {
0940: featArray = (Feature[]) FeatureCollectionTools
0941: .resizeArray(featArray, featArray.length
0942: - featuresDone);
0943: featuresDone = 0;
0944: if (i % 50000 == 0) {
0945: System.gc();
0946: }
0947: logger
0948: .printDebug("adding attribute, features left to do "
0949: + i);
0950: }
0951: }
0952: featArray = null;
0953:
0954: return newFc;
0955: }
0956:
0957: /**
0958: * Reallocates an array with a new size, and copies the contents
0959: * of the old array to the new array.
0960: * @param oldArray the old array, to be reallocated.
0961: * @param newSize the new array size.
0962: * @return A new array with the same contents.
0963: */
0964: public static Object resizeArray(Object oldArray, int newSize) {
0965: int oldSize = java.lang.reflect.Array.getLength(oldArray);
0966: Class elementType = oldArray.getClass().getComponentType();
0967: Object newArray = java.lang.reflect.Array.newInstance(
0968: elementType, newSize);
0969: int preserveLength = Math.min(oldSize, newSize);
0970: if (preserveLength > 0)
0971: System.arraycopy(oldArray, 0, newArray, 0, preserveLength);
0972: return newArray;
0973: }
0974:
0975: public static double[] getMinMaxAttributeValue(Feature[] featArray,
0976: FeatureSchema fs, String attr) {
0977: double[] minmax = new double[] { Double.MAX_VALUE,
0978: -Double.MAX_VALUE };
0979:
0980: if (fs.getAttributeType(attr) == AttributeType.INTEGER
0981: || fs.getAttributeType(attr) == AttributeType.DOUBLE) {
0982:
0983: Feature feat;
0984: double value;
0985:
0986: for (int i = featArray.length - 1; i >= 0; i--) {
0987: feat = featArray[i];
0988:
0989: if (feat.getAttribute(attr) != null) {
0990: value = ObjectComparator.getDoubleValue(feat
0991: .getAttribute(attr));
0992:
0993: if (value < minmax[0]) {
0994: minmax[0] = value;
0995: }
0996: if (value > minmax[1]) {
0997: minmax[1] = value;
0998: }
0999: } else {
1000: FeatureCollectionTools.logger
1001: .printMinorError("skipped value (NULL), when checking min./max. values for Attribute "
1002: + attr);
1003: }
1004: }
1005: }
1006:
1007: return minmax;
1008: }
1009:
1010: public static double[] getMinMaxAttributeValue(
1011: FeatureCollection features, String attr) {
1012: return FeatureCollectionTools.getMinMaxAttributeValue(
1013: FeatureCollectionTools
1014: .FeatureCollection2FeatureArray(features),
1015: features.getFeatureSchema(), attr);
1016: }
1017:
1018: /**
1019: * Converts a given FeatureCollection into an array of Feature, that can - by far - be faster iterated.
1020: *@param fc the feature Collection
1021: *@return an array of the features of the feature collection
1022: */
1023: public static Feature[] FeatureCollection2FeatureArray(
1024: FeatureCollection fc) {
1025: return (Feature[]) fc.getFeatures().toArray(new Feature[0]);
1026: }
1027:
1028: /**
1029: * Converts a given list of features into an array of Feature, that can - by far - be faster iterated.
1030: *@param features list of features
1031: *@return an array of the features of the feature list
1032: */
1033: public static Feature[] FeatureCollection2FeatureArray(
1034: List<Feature> features) {
1035: return (Feature[]) features.toArray(new Feature[0]);
1036: }
1037: }
|