Merges Boundaries of a relation

@param relation The relation of boundary
@return A List of Coordinates for the Boundary, first and last element are the same.
968896
private Coordinate[] mergeBoundary(Relation relation) {
        List<List<Long>> bounds = new ArrayList<>();
        for (RelationMember relationMember : relation.getMembers()) {
            if (relationMember.getMemberType().equals(EntityType.Way)
                    && "outer".equalsIgnoreCase(relationMember.getMemberRole())) {
                List<Long> waynodes = writer.findWayNodesByWayID(relationMember.getMemberId());
                if (waynodes != null && !waynodes.isEmpty()) {
                    bounds.add(waynodes);
                    continue;
                }
                LOGGER.finer("\n---> Member not found | Membertype= " + relationMember.getMemberType().name()
                        + ", Memberrole= " + relationMember.getMemberRole() + "\n");
                continue;
            }
            LOGGER.finer("\n---> Member not accepted | Membertype= " + relationMember.getMemberType().name()
                    + ", Memberrole= " + relationMember.getMemberRole() + "\n");
        }
        //Merge bound nodes (There's may a simpler method)
        if (bounds.isEmpty()) {
            return null;
        }
        LOGGER.fine("Administrative: " + writer.getTagValue(relation.getTags(), "name")
                + " #Members: " + relation.getMembers().size()
                + " #Segments: " + bounds.size());

        //Iterate through given list
        final double threshold = 20; //In meters;
        for (int i = 1; i < bounds.size(); i++) {
            //Create second list, to compare values
            List<Long> I = bounds.get(i);
            List<Long> check = I;
            long nIa = I.get(0);
            long nIb = I.get(I.size() - 1);
            LatLong Ia = writer.findNodeByID(I.get(0));
            LatLong Ib = writer.findNodeByID(I.get(I.size() - 1));
            for (int j = 0; j < bounds.size(); j++) {
                if (i == j) continue;
                //LOGGER.info("j: "+ j+"; i: "+i);
                List<Long> J = bounds.get(j);
                long nJa = J.get(0);
                long nJb = J.get(J.size() - 1);
                LatLong Ja = writer.findNodeByID(J.get(0));
                LatLong Jb = writer.findNodeByID(J.get(J.size() - 1));
                if (Ia == null || Ib == null || Ja == null || Jb == null) return null;
                //If first of I and last of J matches: merge
                if (Ia.sphericalDistance(Jb) < threshold) {
                    I.remove(0);
                    J.addAll(I);
                    bounds.set(j, J);
                    bounds.remove(i);
                    i--;
                    LOGGER.finest("matches: " + Ia.latitude + ", " + Ia.longitude
                            + "; Ids: " + nIa + ", " + nJb);
                    break;
                } else if (Ib.sphericalDistance(Jb) < threshold) {
                    //If list I is reversed
                    I = Lists.reverse(I);
                    I.remove(0);
                    J.addAll(I);
                    bounds.set(j, J);
                    bounds.remove(i);
                    i--;
                    LOGGER.finest("reverse I matches: " + Ib.latitude + ", " + Ib.longitude
                            + "; Ids: " + nIb + ", " + nJb);
                    break;
                } else if (Ia.sphericalDistance(Ja) < threshold) {
                    //If list J is reversed
                    J = Lists.reverse(J);
                    I.remove(0);
                    J.addAll(I);
                    bounds.set(j, J);
                    bounds.remove(i);
                    i--;
                    LOGGER.finest("reverse J matches: " + Ia.latitude + ", " + Ia.longitude
                            + "; Ids: " + nIa + ", " + nJb);
                    break;
                } else if (Ib.sphericalDistance(Ja) < threshold) {
                    //If both are reversed
                    J = Lists.reverse(J);
                    I = Lists.reverse(I);
                    I.remove(0);
                    J.addAll(I);
                    bounds.set(j, J);
                    bounds.remove(i);
                    i--;
                    LOGGER.finest("reverse Both matches: " + Ib.latitude + ", " + Ib.longitude
                            + "; Ids: " + nIb + ", " + nJa);
                    break;
                }
            }
            //One path does'not match, so return
            if (bounds.contains(check) && bounds.size() > 1) {
                LOGGER.finer("Merging failed");
                return null; //continue if you want to add all calculatated boundary parts.
            }
        }
        LOGGER.finer("Bound merging finished; Size= " + bounds.size());
        //Check the result
        //TODO Calculate areas which have more than 1 circle bound. (Simple cover func.)
        if (bounds.size() != 1) {
            return null;
        }
        LOGGER.finer("Bound has right size; ");

        Long[] area = bounds.get(0).toArray(new Long[bounds.get(0).size()]);
        LatLong node = writer.findNodeByID(area[0]);
        if (node == null || node.sphericalDistance(writer.findNodeByID(area[area.length - 1])) >= threshold) {
            return null;
        }
        area[0] = area[area.length - 1];
        LOGGER.finer("Last node is first node; ");
        // Convert the way to a JTS polygon
        Coordinate[] coordinates = new Coordinate[area.length];
        for (int j = 0; j < area.length; j++) {
            LatLong wayNode = writer.findNodeByID(area[j]);
            if (wayNode == null) return null;
            coordinates[j] = new Coordinate(wayNode.longitude, wayNode.latitude);
        }

        return coordinates;
    }
110428
public static int dimensionality(Relation<? extends SpatialComparable> relation) {
    final SimpleTypeInformation<? extends SpatialComparable> type = relation.getDataTypeInformation();
    if(type instanceof FieldTypeInformation) {
      return ((FieldTypeInformation) type).getDimensionality();
    }
    return -1;
  }
558706
public OutlierResult run(Relation<V> relation) {
    final int dim = RelationUtil.dimensionality(relation);
    final int size = relation.size();
    ArrayList<ArrayList<DBIDs>> ranges = buildRanges(relation);

    ArrayList<int[]> Rk;
    // Build a list of all subspaces
    FiniteProgress prog = LOG.isVerbose() ? new FiniteProgress("Subspace size", k, LOG) : null;
    // R1 initial one-dimensional subspaces.
    Rk = new ArrayList<>();
    // Set of all dim*phi ranges
    ArrayList<IntIntPair> q = new ArrayList<>();
    for(int i = 0; i < dim; i++) {
      for(int j = 0; j < phi; j++) {
        q.add(new IntIntPair(i, j));
        Rk.add(new int[] { i, j });
      }
    }
    LOG.incrementProcessed(prog);

    // build Ri
    for(int i = 2; i <= k; i++) {
      ArrayList<int[]> Rnew = new ArrayList<>();

      for(int j = 0; j < Rk.size(); j++) {
        int[] c = Rk.get(j);
        for(IntIntPair pair : q) {
          boolean invalid = false;
          for(int t = 0; t < c.length; t += 2) {
            if(c[t] == pair.first) {
              invalid = true;
              break;
            }
          }
          if(!invalid) {
            int[] neu = Arrays.copyOf(c, c.length + 2);
            neu[c.length] = pair.first;
            neu[c.length + 1] = pair.second;
            Rnew.add(neu);
          }
        }
      }
      Rk = Rnew;
      LOG.incrementProcessed(prog);
    }
    if(prog != null) {
      prog.setProcessed(k, LOG);
    }
    LOG.ensureCompleted(prog);

    WritableDoubleDataStore sparsity = DataStoreUtil.makeDoubleStorage(relation.getDBIDs(), DataStoreFactory.HINT_HOT | DataStoreFactory.HINT_STATIC);
    // calculate the sparsity coefficient
    for(int[] sub : Rk) {
      DBIDs ids = computeSubspace(sub, ranges);
      final double sparsityC = sparsity(ids.size(), size, k, phi);

      if(sparsityC < 0) {
        for(DBIDIter iter = ids.iter(); iter.valid(); iter.advance()) {
          double prev = sparsity.doubleValue(iter);
          if(Double.isNaN(prev) || sparsityC < prev) {
            sparsity.putDouble(iter, sparsityC);
          }
        }
      }
    }
    DoubleMinMax minmax = new DoubleMinMax();
    for(DBIDIter iditer = relation.iterDBIDs(); iditer.valid(); iditer.advance()) {
      double val = sparsity.doubleValue(iditer);
      if(Double.isNaN(val)) {
        sparsity.putDouble(iditer, 0.0);
        val = 0.0;
      }
      minmax.put(val);
    }
    DoubleRelation scoreResult = new MaterializedDoubleRelation("AggarwalYuNaive", "aggarwal-yu-outlier", sparsity, relation.getDBIDs());
    OutlierScoreMeta meta = new InvertedOutlierScoreMeta(minmax.getMin(), minmax.getMax(), Double.NEGATIVE_INFINITY, 0.0);
    return new OutlierResult(meta, scoreResult);
  }
484473
public void setPartitions(Relation<V> relation) throws IllegalArgumentException {
    if((FastMath.log(partitions) / FastMath.log(2)) != (int) (FastMath.log(partitions) / FastMath.log(2))) {
      throw new IllegalArgumentException("Number of partitions must be a power of 2!");
    }

    final int dimensions = RelationUtil.dimensionality(relation);
    final int size = relation.size();
    splitPositions = new double[dimensions][partitions + 1];

    for(int d = 0; d < dimensions; d++) {
      double[] tempdata = new double[size];
      int j = 0;
      for(DBIDIter iditer = relation.iterDBIDs(); iditer.valid(); iditer.advance()) {
        tempdata[j] = relation.get(iditer).doubleValue(d);
        j += 1;
      }
      Arrays.sort(tempdata);

      for(int b = 0; b < partitions; b++) {
        int start = (int) (b * size / (double) partitions);
        splitPositions[d][b] = tempdata[start];
      }
      // make sure that last object will be included
      splitPositions[d][partitions] = tempdata[size - 1] + 0.000001;
    }
  }
542728
private String formatRelationList(List<Relation> value)
   {
      String result = null;

      if (value != null && value.size() != 0)
      {
         StringBuilder sb = new StringBuilder();
         for (Relation relation : value)
         {
            if (sb.length() != 0)
            {
               sb.append(m_delimiter);
            }

            sb.append(formatRelation(relation));
         }

         result = sb.toString();
      }

      return (result);
   }
1185770
public function relationIsJoined($relation)
    {
        if ($this->_joinedTables === null) {
            $this->_joinedTables = $this->getJoinedTables();
        }

        return in_array($this->getRelatedTable($relation), $this->_joinedTables, true);
    }
1124213
public static LinkRelation parse(String relation) {

		return LINK_RELATIONS.stream() //
				.filter(it -> it.value().equalsIgnoreCase(relation)) //
				.findFirst() //
				.orElseThrow(() -> new IllegalArgumentException(relation + " is not a valid IANA link relation!"));
	}
597254
public function together($relation)
    {
        if (is_string($relation)) {
            $relation = explode(',', $relation);
        }

        $this->together = $relation;

        $this->checkAutoRelationWrite();

        return $this;
    }
1011803
public List<Relation> getRelations(Collection<Long> relationIds)
	{
		if(relationIds.isEmpty()) return Collections.emptyList();
		return getSomeElements(RELATION + "s?" + RELATION + "s=" + toCommaList(relationIds), Relation.class);
	}
134529
private void mergeTwoOrderVariations(Predicate<RelationService> p1, Predicate<RelationService> p2) {
		/*
		 *  t1 --r1--> t2 --r2--> t3
		 *  t1 --rtrans--> t3
		 */

		terminology.terms(TermProperty.FREQUENCY.getComparator(true))
		.forEach(t1 -> {
			final Map<Term, Relation> r1Set = new HashMap<>();

			t1.variations().forEach(r1 -> {
				if(p1.test(r1))
					r1Set.put(r1.getTo().getTerm(), r1.getRelation());
			});
			
			final Set<Relation> rem = new HashSet<>();
			
			r1Set.keySet().forEach(t2-> {
				terminology
					.outboundRelations(t2, RelationType.VARIATION)
					.filter(p2)
					.filter(r2 -> r1Set.containsKey(r2.getTo()))
					.forEach(r2 -> {
						Term t3 = r2.getTo().getTerm();
						
						Relation rtrans = r1Set.get(t3);
						if(logger.isTraceEnabled()) {
							logger.trace("Found order-2 relation in variation set {}-->{}-->{}", t1, t2, t3);
							logger.trace("Removing {}", rtrans);
						}
						watchRemoval(t1.getTerm(), t2, t3, rtrans);
						rem.add(rtrans);
					})
				;
			});
			
			rem.forEach(rel -> {
				terminology.removeRelation(rel);
			});
		});

	}
610141
private String formatRelation(Relation relation)
   {
      String result = null;

      if (relation != null)
      {
         StringBuilder sb = new StringBuilder(relation.getTargetTask().getID().toString());

         Duration duration = relation.getLag();
         RelationType type = relation.getType();
         double durationValue = duration.getDuration();

         if ((durationValue != 0) || (type != RelationType.FINISH_START))
         {
            String[] typeNames = LocaleData.getStringArray(m_locale, LocaleData.RELATION_TYPES);
            sb.append(typeNames[type.getValue()]);
         }

         if (durationValue != 0)
         {
            if (durationValue > 0)
            {
               sb.append('+');
            }

            sb.append(formatDuration(duration));
         }

         result = sb.toString();
      }

      m_eventManager.fireRelationWrittenEvent(relation);
      return (result);
   }
1363404
public List<Link> getLinks(LinkRelation relation) {

		Assert.notNull(relation, "Link relation must not be null!");

		return getLinks(relation.value());
	}
346315
public Clustering<Model> run(Relation<O> relation) {
    final int size = relation.size();
    if(size < minpts) {
      Clustering<Model> result = new Clustering<>("DBSCAN Clustering", "dbscan-clustering");
      result.addToplevelCluster(new Cluster<Model>(relation.getDBIDs(), true, ClusterModel.CLUSTER));
      return result;
    }

    RangeQuery<O> rangeQuery = QueryUtil.getRangeQuery(relation, getDistanceFunction());
    resultList = new ArrayList<>();
    noise = DBIDUtil.newHashSet();
    runDBSCAN(relation, rangeQuery);

    double averagen = ncounter / (double) relation.size();
    LOG.statistics(new DoubleStatistic(DBSCAN.class.getName() + ".average-neighbors", averagen));
    if(averagen < 1 + 0.1 * (minpts - 1)) {
      LOG.warning("There are very few neighbors found. Epsilon may be too small.");
    }
    if(averagen > 100 * minpts) {
      LOG.warning("There are very many neighbors found. Epsilon may be too large.");
    }

    Clustering<Model> result = new Clustering<>("DBSCAN Clustering", "dbscan-clustering");
    for(ModifiableDBIDs res : resultList) {
      result.addToplevelCluster(new Cluster<Model>(res, ClusterModel.CLUSTER));
    }
    result.addToplevelCluster(new Cluster<Model>(noise, true, ClusterModel.CLUSTER));
    return result;
  }
74811
RelationImpl buildRelation(EdgeElement edge) {
        return getOrBuildConcept(edge, (e) -> RelationImpl.create(RelationEdge.get(edge)));
    }
1001381
private void merge(final GeometryFunction callback) {
		GeometryOperationService operationService = new GeometryOperationServiceImpl();
		UnionInfo unionInfo = new UnionInfo();
		unionInfo.setUsePrecisionAsBuffer(true);
		unionInfo.setPrecision(precision);
		operationService.union(geometries, unionInfo, new Callback<Geometry, Throwable>() {

			public void onSuccess(Geometry result) {
				callback.execute(result);
			}

			public void onFailure(Throwable reason) {
				reason.printStackTrace();
			}
		});
	}
894762
protected function nestedRelations( $relation )
	{
		$nested = [];

		// We are basically looking for any relationships that are nested deeper than
		// the given top-level relationship. We will just check for any relations
		// that start with the given top relations and adds them to our arrays.
		foreach ( $this->eagerLoad as $name => $constraints )
		{
			if ( $this->isNested( $name, $relation ) )
			{
				$nested[substr( $name, strlen( $relation . '.' ) )] = $constraints;
			}
		}

		return $nested;
	}
1052949
protected function getRelationshipValue(string $relation)
    {
        $value = $this->getEntityAttribute($relation);

        if (is_scalar($value)) {
            throw new MappingException("Entity's attribute $relation should be array, object, collection or null");
        }

        return $value;
    }