Skip to content

Instantly share code, notes, and snippets.

@milkbread
Last active December 18, 2015 18:59
Show Gist options
  • Save milkbread/5829814 to your computer and use it in GitHub Desktop.
Save milkbread/5829814 to your computer and use it in GitHub Desktop.
JavaScript: RKAggregation - all versions of these functions
function RKAggregation_version(){
return "0.0.1"
}
//***********************
//Aggregation - 'Objects'
//object that defines and administrates a polygonal feature
//Object-definition -- Feature-Object ... contains all necessary functions and variables of one feature:
//Type, ID, PROPERTIES, GEOMETRY, getArcsPure(), getGeometry(), getNeighbors()
function featureObj(feature_){
//this.feature = feature_;
this.type = feature_.type;
this.id = feature_.id;
this.properties = feature_.properties;
this.geometry = feature_.arcs;
this.clipped = false;
this.removed_multi_parts = [];
this.removed_multi_parts_aggregated_to = [];
this.aggregatedFeatures = [];
var has_hole = [];
//check if geometry has holes
if(this.type=='Polygon'){
if (this.geometry.length==2) has_hole[0] = true;
else has_hole[0] = false;
}
else if(this.type=='MultiPolygon'){
this.geometry.forEach(function(polygonGeom,i){
if(polygonGeom.length==2) has_hole.push(true);
else has_hole.push(false);
})
}
this.has_hole = has_hole;
//***FUNCTIONS***
//get all neighbors of this feature ... fundamentally based on 'getNeighborsOfFeature()'
this.getNeighbors=getNeighbors;
function getNeighbors(arcCollection__, index){
//console.log("These are some aggregated features, that have to be observed for the neighbor detection: ",this.aggregatedFeatures)
if(this.type=='Polygon') return getNeighborsOfFeature(this.getArcsPure()[0], this.id, arcCollection__, this.aggregatedFeatures)
else if (this.type=='MultiPolygon') return getNeighborsOfFeature(this.getArcsPure_multipoly(index)[0], this.id, arcCollection__, this.aggregatedFeatures)
}
//get all arcs (pure) in one array...'arcs'
this.getArcsPure_multipoly=getArcsPure_multipoly;
function getArcsPure_multipoly(index_){
//console.log("Compare geometries: ", this.geometry, " vs. ",this.geometry[index_])
var pure_arcs = readPoly(this.geometry[index_],'arcs');
return pure_arcs;
}
//get all arcs (pure) in one array...'arcs'
this.getArcsPure=getArcsPure;
function getArcsPure(){
var pure_arcs = [], pure_arcs_index = [];
if(this.type=='Polygon'){
var cache = readPoly(this.geometry,'arcs');
pure_arcs = cache[0];
pure_arcs_index = cache[1];
}
else if (this.type=='MultiPolygon') {
this.geometry.forEach(function(polygon0, k){
var cache = readPoly(polygon0,'arcs', k);
pure_arcs=pure_arcs.concat(cache[0]);
pure_arcs_index=pure_arcs_index.concat(cache[1])
})
}
return [pure_arcs, pure_arcs_index];
}
//get polygons singulary...'single'
this.getSingleGeometries=getSingleGeometries;
function getSingleGeometries(){
var single_geoms = [];
if(this.type=='Polygon')single_geoms = readPoly(this.geometry,'single');
else if (this.type=='MultiPolygon') {
this.geometry.forEach(function(polygon0){single_geoms.push(readPoly(polygon0,'single')); })
}
return single_geoms;
}
function readPoly(polygon_parts, origin, multi_index){
if(origin=='arcs'){
var arcs = [], arcs_index = [];
polygon_parts.forEach(function(polygon,i){
polygon.forEach(function(arc,j){arcs.push(arc);
if(multi_index == undefined)arcs_index.push([i,j])
else arcs_index.push([multi_index,i,j])
})
})
return [arcs, arcs_index];
}
else if(origin=='single'){
//var single = [];
//console.log(polygon_parts);
//polygon_parts.forEach(function(part){single.push(part)})
//TODO: needs an additional processing for the holes of a polygon --> polygon_parts[1] - polygon_parts[length-1]
//use only the outer ring
return polygon_parts[0];
}
}
//aggregate a feature with this
this.aggregateFeature=aggregateFeature;
function aggregateFeature(remFeature, neighArc, additionalNeighborsArcs_, arcCollection_){
//console.log("This is my -add to- feature: ",this)
//console.log("This is my -add to- geometry: ", this.geometry," ... this is the -origin- geometry: ", remFeature.geometry," ... and this is the neighbor arc: ",neighArc)
//console.log("Hole in the -add to- geometry? ", this.has_hole," ... hole in the -origin- geometry: ", remFeature.has_hole)
//console.log("Type of the -add to- geometry ", this.type, "Type of the -origin- geometry ", remFeature.type)
var reformPolygonCache = reformPolygonArcs2(neighArc.direction, neighArc.arc_id, remFeature);
var reformedGeom = reformPolygonCache[0].slice();
var reformedGeomOrigin = reformPolygonCache[1];
//console.log("This is the reformed -origin- geometry: ",reformedGeom, " ... and this is the geometry that was reformed: ",reformedGeomOrigin)
if (neighArc.direction == 1)var replace_id = neighArc.arc_id;
else if (neighArc.direction == -1)var replace_id = (neighArc.arc_id+1)*(-1);
if(this.type=='Polygon'){
//this.geometry.forEach(function(d){console.log(d)})
var arcIndex = this.geometry[0].indexOf(replace_id)
//console.log("This is the index of the arc (",replace_id,"), in the -add to- geometry: ",arcIndex," ... proof it: ", this.geometry)
var new_composition = reCombinateArcs(this.geometry[0], arcIndex, reformedGeom)
//console.log("This is the re-combined outer ring of this geometry (polygon): ",new_composition)
//now...remove the additional, redundant arcs, as they are not needed
new_composition = removeRedundantArcs2(new_composition, additionalNeighborsArcs_);
//console.log(new_composition, new_composition.length)
this.geometry[0]=new_composition; //just replace the outer ring ... by that we simply keep the holes
//add the holes of the -origin- geometry to the reformed geometry...if some exist
if(remFeature.has_hole[0]==true){
for(var i=1;i<reformedGeomOrigin.length;i++){
this.geometry.push(reformedGeomOrigin[i])
}
}
}
else {
var found = false, x = 0, index__;
//console.log("This is a MultiPolygon: ",this.geometry, x, this.geometry[x][0].indexOf(replace_id), this.geometry.length, replace_id)
//console.log("These are the arcs of the feature: ",this.getArcsPure(), " ... does it contain the replaced arc? ",this.getArcsPure()[0].indexOf(replace_id))
var indexOfReplace_id = this.getArcsPure()[0].indexOf(replace_id)
if(indexOfReplace_id != -1){
index__ = this.getArcsPure()[1][indexOfReplace_id][0]
var arcIndex = this.getArcsPure()[1][indexOfReplace_id][2]
} else{
//console.log("Ah...stupid problem...it tries to aggregate a multipoly element, that was already removed!")
//console.log(remFeature.id)
//console.log(this)
}
/*while(found==false){
if(x >= this.geometry.length){
console.log("D'oh...this is a stupid problem, but has to be solved...")
//naaaaahhh...shit...this is a stupid problem, but has to be solved...by using the first arc in the array and take it's other member
console.log(this.id, this.geometry[0][0][0], arcCollection_[this.geometry[0][0][0]].members)
}
var arcIndex = this.geometry[x][0].indexOf(replace_id)
console.log("This is the index of the arc (",replace_id,"), in this.geometry[",x,"] -add to- geometry: ",arcIndex," ... proof it: ", this.geometry)
if(arcIndex!=-1)found=true; index__=x;
x++;
}*/
//console.log(this.geometry, index__)
//console.log(this.geometry[index__][0], arcIndex, reformedGeom)
var new_composition = reCombinateArcs(this.geometry[index__][0], arcIndex, reformedGeom)
//console.log("This is the re-combined outer ring of corresponding geometry (polygon): ",new_composition)
//now...remove the additional, redundant arcs, as they are not needed
new_composition = removeRedundantArcs2(new_composition);
this.geometry[index__][0]=new_composition; //just replace the outer ring ... by that we simply keep the holes
//add the holes of the -origin- geometry to the reformed geometry...if some exist
if(remFeature.has_hole[index__]==true){
for(var i=1;i<reformedGeomOrigin.length;i++){
this.geometry[index__].push(reformedGeomOrigin[i])
}
}
}
this.clipped=true;
this.aggregatedFeatures.push(remFeature.id)
//No more neede...as arc will not be removed from arcCollection
//var result = replace_id;
//if (result<0)result=(result*(-1))-1
//return origin of the reformed geometry ... to remove only this one from the
return replace_id;
}
function removeRedundantArcs2(new_composition_, redundant_neighbors){
var new_composition__ = new_composition_.slice(0);
var wordArray= new Array();
for (var t=0;t<new_composition__.length;t++){
var this_arc = new_composition__[t];
if(this_arc<0)this_arc=(this_arc*(-1))-1
var indexOfWord = getAllValues(wordArray).indexOf(this_arc);
if(indexOfWord==-1){
var newWord = new word(this_arc, 1);
newWord.indizes.push(t);
wordArray.push(newWord);
}else{
wordArray[indexOfWord].frequency++;
wordArray[indexOfWord].indizes.push(t)
}
}
//console.log(wordArray)
var allIndizes = []
wordArray.forEach(function(d){if(d.frequency>1)allIndizes=allIndizes.concat(d.indizes) })
//console.log(allIndizes)
//sort the found indizes of the found redundant arcs ... because ... delete them DESC, otherwise I would get problems with the indizes
allIndizes.sort(function sortfunction(a, b){return (b - a)})
//console.log("These are the allIndizes: ",allIndizes)
//delete the redundant arcs by using the indizes
allIndizes.forEach(function(index){
//console.log(new_composition__[index]);
new_composition__.splice(index,1)})
//console.log(new_composition__)
return new_composition__;
function word(value, frequency)
{
this.value = value;
this.frequency = frequency;
this.indizes = [];
}
function getAllValues(array_of_objects){
return array_of_objects.map(function(d){return d.value;})
}
}
//add the reformed ('redi_geom_') geometry to the -add to- geometry ('feature')
function reCombinateArcs(feature, arc_index_, redi_geom_){
//when at position 0 --> [reformed arcs, original arcs {1...End}]
if (arc_index_ == 0){
var new_composition_ = redi_geom_;
new_composition_ = new_composition_.concat( feature.slice(1));
//when at any position X --> [original arcs {0...X-1}, reformed arcs, original arcs {X+1...End}]
}else { var new_composition_ = feature.slice(0,arc_index_);
new_composition_ = new_composition_.concat( redi_geom_);
new_composition_ = new_composition_.concat(feature.slice(arc_index_+1));
}
return new_composition_
}
}
//object for removed features
function remFeatures(removeCandidate, id_new_){
this.id=removeCandidate.id;
this.id_new=id_new_; //this is the id of the feature, where this was aggregated to
//this.index=index_;
this.type = undefined;
}
//object to store and administrate all removed features
function remFeatureStorage(){
this.removedFeatures = [];
var removedFeaturesIndizes = [];
this.addRemFeat=addRemFeat;
function addRemFeat(remFeature_, id_new_, type_){
var remFeature = new remFeatures(remFeature_, id_new_);
remFeature.type=type_;
this.removedFeatures.push(remFeature);
}
this.getIndizes=getIndizes;
function getIndizes(){
removedFeaturesIndizes = this.removedFeatures.map(function(d){return d.id});
return removedFeaturesIndizes;
}
}
//object to store and administrate all feature features
function featureObjStorage(){
this.featureObjects = [];
var featureObjectsIndizes = [];
this.addFeatObj=addFeatObj;
function addFeatObj(feature){
var feature_obj = new featureObj(feature);
this.featureObjects.push(feature_obj);
}
this.getIndizes=getIndizes;
function getIndizes(){
featureObjectsIndizes = this.featureObjects.map(function(d){return d.id});
return featureObjectsIndizes;
}
this.removeFeatObj=removeFeatObj;
function removeFeatObj(featureObject_, removedFeatureStorage_, addToCandidate_, fixed_multiPolyIndex__){
if(featureObject_.type=='Polygon'){
var originIndex_ = featureObjectsIndizes.indexOf(featureObject_.id)
var removed=this.featureObjects.splice(originIndex_,1)
removedFeatureStorage_.addRemFeat(featureObject_, addToCandidate_.id, 'Polygon');
//console.log("This is the storage of removed features ... is the new one here?! ",removedFeatureStorage_.removedFeatures)
}
else if(featureObject_.type=='MultiPolygon'){
//console.log("now!",featureObject_.geometry.length)
if(featureObject_.geometry.length>1 ){
featureObject_.geometry.splice(fixed_multiPolyIndex__,1)
featureObject_.removed_multi_parts.push(fixed_multiPolyIndex__) //!!!Maybe necessary to have an info within the featureObject that/which part of the multipolygon was removed
featureObject_.removed_multi_parts_aggregated_to.push(addToCandidate_.id)
removedFeatureStorage_.addRemFeat(featureObject_, addToCandidate_.id, "MultiPoly_part");
}
else {
var originIndex_ = featureObjectsIndizes.indexOf(featureObject_.id)
var removed=this.featureObjects.splice(originIndex_,1)
//add removed feature to the storage of removed features
removedFeatureStorage_.addRemFeat(featureObject_, addToCandidate_.id, "MultiPoly_full");
//console.log("This is the storage of removed features ... is the new one here?! ",removedFeatureStorage_.removedFeatures)
}
}
}
}
//***********************
//Aggregation - Functions
//function that removes the redundant arc from a feature's geometry and reforms it, when arc is surrounded by other arcs
function reformPolygonArcs2(direction, arc_id, feature){
if (direction == -1)var replace_id0 = arc_id;
else if (direction == 1)var replace_id0 = (arc_id+1)*(-1);
var found = false, x = 0, index__=-1;
if(feature.type=='Polygon')var arcs = feature.geometry;
else if (feature.type=='MultiPolygon') { //find the corresponding Polygon in the Multi-array
while(found==false){
var arcIndex = feature.geometry[x][0].indexOf(replace_id0)
//console.log("This is the index of the arc (",replace_id0,"), in remFeature.geometry[",x,"] -origin- geometry: ",arcIndex," ... proof it: ", feature.geometry)
if(arcIndex!=-1)found=true; index__=x;
x++;
}
var arcs = feature.geometry[index__];
}
return [editPolygon_(replace_id0, arcs),arcs];
function editPolygon_(id, arcs){
//get the indizes ...
var poly_index = 0, //poly_index=0--> we only need the outer ring
arc_index = arcs[poly_index].indexOf(id); //arc_index is the position of the arc in the array of the outer ring
//console.log(id, arcs[poly_index],arcs[poly_index][arc_index])
if (arc_index == 0)var de_composition = arcs[poly_index].slice(1);
else { var de_composition = arcs[poly_index].slice(arc_index+1);
de_composition = de_composition.concat(arcs[poly_index].slice(0,arc_index));
}
//console.log("de_composition of arcs: ",de_composition)
return de_composition
}
}
//was 'findLongestArc2' before renaming
function sortArcs(neigh_arcs, arcCollection_){
var list = neigh_arcs.map(function(a){
//a.length =arcCollection_[a.arc_id].length;
return a;})
list.sort(function sortfunction(a, b){return (arcCollection_[b.arc_id].length - arcCollection_[a.arc_id].length)})
//console.log('list-sorted: ', list)
return list;
}
function checkForRedundantFeatures(neighbors, prefered_neighbor){
var redundant_ids = [], neighbor_id = prefered_neighbor.id;
neighbors.forEach(function(neighbor,i){
if(neighbor.id==neighbor_id && prefered_neighbor.arc_id != neighbor.arc_id)redundant_ids.push(i);
})
var all_ids = neighbors.map(function(d){return d.id})
//console.log("All neighbor ids: ",all_ids)
//if(redundant_ids.length>0)console.log("The detected neighbor has more than one arc as neighbor, that are the additional indizes: ",redundant_ids, " ... proof it: ",neighbors)
//else console.log("Did not detect another arc for that id: ", neighbor_id)
var additional_neighbors = redundant_ids.map(function(id){return neighbors[id]})
return additional_neighbors;
}
function checkNeighborExistence2(id_origin, arcCollection_, removedFeatureStorage_, sorted_neighbors_, featureObjects_, featuresObjectsIndizes_){
var longest_neigh = sorted_neighbors_[0];
var id_ = longest_neigh.id, id_cache = longest_neigh.id;
console.log("I am the longest neighbor: ", longest_neigh,"...longest_neigh.arc_id: ", longest_neigh.arc_id)
console.log("object existence: ",featuresObjectsIndizes_.indexOf(id_))
//initial check on existence
var existence = (removedFeatureStorage_.getIndizes().indexOf(id_)==-1);
var removed_ = (featuresObjectsIndizes_.indexOf(id_)==-1)
console.log("Do I exist? ", existence, removed_)
//if not get the one, where it was aggregated to
if(existence==false && removed_==true){
id_ = getNewID(removedFeatureStorage_, id_);
console.log("Where will I get aggregated to? ",id_)
}
if(id_origin==id_){ //it can happen, that we get the same feature as aggregation partner (this comes from how I make neighbor analysis...'members' knows only the initial arcs, not the aggregated version)
console.log("This time...I'd like to aggregate a feature with itself!")
//get the corresponding arc...as origin_id and id are identic, the detected neighbor-arc is/can be wrong, we need the other member of the arc
var this_arc_members = arcCollection_[longest_neigh.arc_id].members;
//console.log(this_arc_members)
//the other member of the arc, is the one we began to analyse at this point...so we cached it at the beginning and use this one (id_cache) now
if(this_arc_members[0].id!=id_cache)id_=this_arc_members[0].id
else if(this_arc_members[1].id!=id_cache)id_=this_arc_members[1].id
//change the direction of the longest neighbor...as we are using now the other member of the arc
longest_neigh.direction = longest_neigh.direction * (-1)
//sad but true...this newly found neighbor can be already removed as well...so we have to find the feature where it was aggregated to
if(removedFeatureStorage_.getIndizes().indexOf(id_)!=-1)id_ = getNewID(removedFeatureStorage_, id_);
}
var indexOfLongestNeighbor = featuresObjectsIndizes_.indexOf(id_);
var longestNeighborFeature = featureObjects_[indexOfLongestNeighbor]
if(longest_neigh.direction == -1)var arc_id = (longest_neigh.arc_id+1) * (-1)
else var arc_id = longest_neigh.arc_id
console.log(longestNeighborFeature, arc_id)
if(longestNeighborFeature.getArcsPure()[0].indexOf(arc_id) == -1){ //when arc_id of potential neigh is not in the feature, which we would like to aggregate
//console.log("Oha...this is not the right neighbor! ... we have to find the right one!")
//console.log("This is the id of the feature, that is not correct: ", id_)
//there has to be another part of the multipolygon ... let's get all indizes
var allIndizes=[],i=-1;
while((i=removedFeatureStorage_.getIndizes().indexOf(id_cache, i+1)) >= 0) allIndizes.push(i);
allIndizes.shift() //remove the first one directly...we have analysed it already and it is not working
//console.log("These are the indizes of all parts: ",allIndizes)
var existence2=false, x=0;
while(existence2==false){
id_ = getNewID2(removedFeatureStorage_, allIndizes[x]);
//console.log(id_)
var indexOfTest = featuresObjectsIndizes_.indexOf(id_);
var test_existence = featureObjects_[indexOfTest];
//console.log("test_existence: ",test_existence)
x++;
existence2=true;
}
}
//console.log(getNeighborsOfFeature(thisFeature.getArcsPure()[0], thisFeature.id, arcCollection_, thisFeature.aggregatedFeatures))
//console.log(sorted_neighbors_)
/* console.log("Which type am I of? ", longestNeighborFeature.type)
if(longestNeighborFeature.type=='MultiPolygon'){
if(longestNeighborFeature.removed_multi_parts_aggregated_to.length>0){ //are there elements in the array that tells me where parts were aggregated to
//console.log("aha...there was already something removed!")
var potential_new_neighbors = longestNeighborFeature.removed_multi_parts_aggregated_to;
console.log("potential_new_neighbors: ",potential_new_neighbors)
var pureArcs = longestNeighborFeature.getArcsPure();
//console.log(pureArcs, pureArcs[0].indexOf(longest_neigh.arc_id))
if(pureArcs[0].indexOf(longest_neigh.arc_id)==-1){ //arc_id cannot be found in remaining arcs...we have
console.log("TODO: This was solved too simple...I have to check each element in this array!")
id_ = potential_new_neighbors[0];
//can also be already removed
if(removedFeatureStorage_.getIndizes().indexOf(id_)!=-1)id_ = getNewID(removedFeatureStorage_, id_);
}else console.log("Does this happen???")
}
}*/
longest_neigh.id = id_;
return longest_neigh;
function getNewID(removedFeatureStorage__, id__){
var stop_ = false, id = id__;
while(stop_==false){
id = removedFeatureStorage__.removedFeatures[removedFeatureStorage__.getIndizes().indexOf(id)].id_new;
//console.log("intermediate steps: ",id)
var removedIndex_ = removedFeatureStorage__.getIndizes().indexOf(id);
if(removedIndex_==-1) stop_ = true; //the new one does exist ... else go on!
}
return id;
}
function getNewID2(removedFeatureStorage__, index_){
var stop_ = false;
var id = removedFeatureStorage__.removedFeatures[index_].id_new;
var removedIndex_ = removedFeatureStorage__.getIndizes().indexOf(id);
if(removedIndex_==-1) stop_ = true;
while(stop_==false){
id = removedFeatureStorage__.removedFeatures[removedFeatureStorage__.getIndizes().indexOf(id)].id_new;
//console.log("intermediate steps: ",id)
removedIndex_ = removedFeatureStorage__.getIndizes().indexOf(id);
if(removedIndex_==-1) stop_ = true; //the new one does exist ... else go on!
}
return id;
}
}
function checkNeighborExistence(removedFeatureStorage_, sorted_neighbors_){
var was_removed = false, stop=false; i=0;
while(stop==false){
var longest_neigh = sorted_neighbors_[i];
//console.log("This is the longest neighbor: ",longest_neigh, " ...as it is the first in an DESC-sorted array")
var removedIndex = removedFeatureStorage_.getIndizes().indexOf(longest_neigh.id)
if(removedIndex != -1)was_removed=true
else { stop=true; was_removed=false};
//console.log("Was this feature already removed? ",was_removed, removedIndex)
i++;
//stop the loop when there is no more neighbor
if(sorted_neighbors_[i]==undefined){stop=true; longest_neigh = undefined;}
}
return longest_neigh;
}
function checkNeighborExistence_alternative(removedFeatureStorage, featuresObjectsIndizes, longest_neigh_id){
var cacheIndex = removedFeatureStorage.getIndizes().indexOf(longest_neigh_id); //the index in the removed features array
var cacheOrigin = removedFeatureStorage.removedFeatures[cacheIndex]; //the removed feature object ... it tells us where it was aggregated to by *.id_new
addToCandidateIndex = featuresObjectsIndizes.indexOf(cacheOrigin.id_new); //use this id to get the new aggregate that contains the searched feature
return addToCandidateIndex;
}
//#################################################################################################################################
//***Old and unused functions or versions of functions
function reformPolygonArcs(direction, arc_id, arcs, type){
if (direction == -1)var replace_id0 = arc_id;
else if (direction == 1)var replace_id0 = (arc_id+1)*(-1);
if (type==undefined)type='Polygon';
if(type=='Polygon'){
return editPolygon_(replace_id0, arcs);
}else if(type=='MultiPolygon'){
alert('Reforming MultiPolygonal Features is not implemented, so far!')
stop();
}
function editPolygon_(id, arcs){
var found = false;
var poly_index, arc_index;
//find the indizes
arcs.forEach(function(arc,i){
if (arc.indexOf(id) != -1){
poly_index = i, arc_index = arc.indexOf(id);
found = true;
}
})
if(found===true){
//console.log(id, arcs[poly_index],arcs[poly_index][arc_index])
if (arc_index == 0)var de_composition = arcs[poly_index].slice(1);
else { var de_composition = arcs[poly_index].slice(arc_index+1);
de_composition = de_composition.concat(arcs[poly_index].slice(0,arc_index));
}
//console.log("de_composition of arcs: ",de_composition)
return de_composition
}
}
}
function findLongestArc(neigh_arcs, arcCollection_){
var longest = {}, longest_neigh_ = {}, test = false, list = [];
neigh_arcs.forEach(function(e){
if (test == false){test=true; longest=arcCollection_[e.arc_id]; longest_neigh_=e;}
else if(arcCollection_[e.arc_id].length>longest.length){longest = arcCollection_[e.arc_id];longest_neigh_=e;}
})
return longest_neigh_;
}
//get the length of a polygon only from the lengths of each arcs, which it consists of ... arcs have to include length property
function getPolyLengthFromArcs(arcs_, arcCollection_){
//console.log(arcs_)
var length_ = 0;
for (var i=0; i<arcs_.length; i++){
var arc_id = arcs_[i];
if(arc_id<0)arc_id=(arc_id*(-1))-1;
length_ = length_ + arcCollection_[arc_id].length;
}
return length_;
}
//clip the reformed arcs of the 'to-clip-feature' to the 'clip-to-feature'
function clipArcs(direction, arc_id, corresp_feat_, redi_geom_){
console.log(direction, arc_id, corresp_feat_, redi_geom_)
var arcGeom = corresp_feat_.arcs;
for(var u=0;u<arc_id.length;u++){
//re-define the arc-id...to find it
if (direction[u] == 1)var replace_id = arc_id[u];
else if (direction[u] == -1)var replace_id = (arc_id[u]+1)*(-1);
//if 'clip-to-feature' is a POLYGON
if (corresp_feat_.type == 'Polygon'){
var poly_index, arc_index, polygon = arcGeom;//old version: corresp_feat_.arcs;
getPolygonIndizes(polygon); //called without index = POLYGON
var new_composition = reCombinateArcs(polygon[poly_index], arc_index)
//console.log("new_composition: ",new_composition)
polygon[poly_index]=new_composition;
//console.log("polygon: ",polygon)
//return polygon
//define the arcs of the geometry
arcGeom = polygon;
//if 'clip-to-feature' is a MULTIPOLYGON
}else if (corresp_feat_.type == 'MultiPolygon'){
var multi_poly_index, poly_index, arc_index, multi_poly = arcGeom;//old version: corresp_feat_.arcs;
//console.log(corresp_feat_.arcs);
var found = false;
multi_poly.forEach(function(poly,count){
if (found===true)return;
//console.log(poly);
found = getPolygonIndizes(poly, count); //called withindex = MULTIPOLYGON
})
//console.log("final multi indizes: ",multi_poly_index, poly_index, arc_index)
var new_composition = reCombinateArcs(multi_poly[multi_poly_index][poly_index], arc_index)
//console.log("new_composition: ",new_composition)
multi_poly[multi_poly_index][poly_index]=new_composition;
//console.log("multi_polygon: ",multi_poly)
//return multi_poly
//define the arcs of the geometry
arcGeom = multi_poly;
}
}
return arcGeom;
//function to find the positions, where the redundant arc can be found
function getPolygonIndizes(polygon_, index){ //index...is needed for the differentiation between MULTI- & POLYGON
var found_ = false;
polygon_.forEach(function(d,i){
if (found_===true)return;
if(d.indexOf(replace_id)!=-1){
//console.log("rest: ",replace_id,d, d.indexOf(replace_id), d[d.indexOf(replace_id)])
poly_index = i, arc_index = d.indexOf(replace_id);
if (index!=undefined)multi_poly_index = index;
found_=true;
}
})
return found_;
}
//add the reformed arcs to the 'clip-to-feature'
function reCombinateArcs(feature, arc_index_){
//when at position 0 --> [reformed arcs, original arcs {1...End}]
if (arc_index_ == 0){
var new_composition_ = redi_geom_;
new_composition_ = new_composition_.concat( feature.slice(1));
//when at any position X --> [original arcs {0...X-1}, reformed arcs, original arcs {X+1...End}]
}else { var new_composition_ = feature.slice(0,arc_index_);
new_composition_ = new_composition_.concat( redi_geom_);
new_composition_ = new_composition_.concat(feature.slice(arc_index_+1));
}
return new_composition_
}
}
function removeRedundantArcs(new_composition_, redundant_neighbors){
//TODO: works not 100% correct, has a failure when feature includes a hole
//loop over all arcs and check for redundancy
var new_composition__ = new_composition_.slice(0)
var splice_indizes = [];
for (var t=0;t<new_composition__.length;t++){
var this_arc = new_composition__[t];
if(this_arc<0)this_arc=(this_arc*(-1))-1
new_composition__.forEach(function(d,i){
var test = d;
if(test<0)test=(test*(-1))-1
//found redundancy...push the index to an array
if(test==this_arc && i!=t)splice_indizes.push(t)
})
}
//sort the found indizes of the found redundant arcs ... because ... delete them DESC, otherwise I would get problems with the indizes
splice_indizes.sort(function sortfunction(a, b){return (b - a)})
//console.log("These are the splice indizes: ",splice_indizes)
//console.log("These are found redundant neighbors: ",redundant_neighbors)
//delete the redundant arcs by using the indizes
splice_indizes.forEach(function(index){
//console.log(new_composition__[index]);
new_composition__.splice(index,1)})
return new_composition__;
}
function RKAggregation_version(){
return "0.1.0"
}
//***********************
//Aggregation - 'Objects'
//object that defines and administrates a polygonal feature
//Object-definition -- Feature-Object ... contains all necessary functions and variables of one feature:
//Type, ID, PROPERTIES, GEOMETRY, getArcsPure(), getGeometry(), getNeighbors()
function featureObj(feature_){
//this.feature = feature_;
this.type = feature_.type;
this.id = feature_.id;
this.properties = feature_.properties;
this.geometry = feature_.arcs;
this.original_geometry = feature_.arcs.slice();
this.clipped = false;
this.removed_multi_parts = [];
this.removed_multi_parts_aggregated_to = [];
this.aggregatedFeatures = [];
var has_hole = [];
//check if geometry has holes
if(this.type=='Polygon'){
if (this.geometry.length==2) has_hole[0] = true;
else has_hole[0] = false;
}
else if(this.type=='MultiPolygon'){
this.geometry.forEach(function(polygonGeom,i){
if(polygonGeom.length==2) has_hole.push(true);
else has_hole.push(false);
})
}
this.has_hole = has_hole;
//***FUNCTIONS***
//get all neighbors of this feature ... fundamentally based on 'getNeighborsOfFeature()'
this.getNeighbors=getNeighbors;
function getNeighbors(arcCollection__, index){
//console.log("These are some aggregated features, that have to be observed for the neighbor detection: ",this.aggregatedFeatures)
if(this.type=='Polygon') return getNeighborsOfFeature(this.getArcsPure()[0], this.id, arcCollection__, this.aggregatedFeatures)
else if (this.type=='MultiPolygon') return getNeighborsOfFeature(this.getArcsPure_multipoly(index)[0], this.id, arcCollection__, this.aggregatedFeatures)
}
//get all arcs (pure) in one array...'arcs'
this.getArcsPure_multipoly=getArcsPure_multipoly;
function getArcsPure_multipoly(index_){
//console.log("Compare geometries: ", this.geometry, " vs. ",this.geometry[index_])
var pure_arcs = readPoly(this.geometry[index_],'arcs');
return pure_arcs;
}
//get all arcs (pure) in one array...'arcs'
this.getArcsPure=getArcsPure;
function getArcsPure(){
var pure_arcs = [], pure_arcs_index = [];
if(this.type=='Polygon'){
var cache = readPoly(this.geometry,'arcs');
pure_arcs = cache[0];
pure_arcs_index = cache[1];
}
else if (this.type=='MultiPolygon') {
this.geometry.forEach(function(polygon0, k){
var cache = readPoly(polygon0,'arcs', k);
pure_arcs=pure_arcs.concat(cache[0]);
pure_arcs_index=pure_arcs_index.concat(cache[1])
})
}
return [pure_arcs, pure_arcs_index];
}
//get polygons singulary...'single'
this.getSingleGeometries=getSingleGeometries;
function getSingleGeometries(){
var single_geoms = [];
if(this.type=='Polygon')single_geoms = readPoly(this.geometry,'single');
else if (this.type=='MultiPolygon') {
this.geometry.forEach(function(polygon0){single_geoms.push(readPoly(polygon0,'single')); })
}
return single_geoms;
}
function readPoly(polygon_parts, origin, multi_index){
if(origin=='arcs'){
var arcs = [], arcs_index = [];
polygon_parts.forEach(function(polygon,i){
polygon.forEach(function(arc,j){arcs.push(arc);
if(multi_index == undefined)arcs_index.push([i,j])
else arcs_index.push([multi_index,i,j])
})
})
return [arcs, arcs_index];
}
else if(origin=='single'){
//var single = [];
//console.log(polygon_parts);
//polygon_parts.forEach(function(part){single.push(part)})
//TODO: needs an additional processing for the holes of a polygon --> polygon_parts[1] - polygon_parts[length-1]
//use only the outer ring
return polygon_parts[0];
}
}
}
//object for removed features
function remFeatures(removeCandidate, id_new_){
this.id=removeCandidate.id;
this.id_new=id_new_; //this is the id of the feature, where this was aggregated to
//this.index=index_;
this.type = undefined;
}
//object to store and administrate all removed features
function remFeatureStorage(){
this.removedFeatures = [];
var removedFeaturesIndizes = [];
this.addRemFeat=addRemFeat;
function addRemFeat(remFeature_, id_new_){
var remFeature = new remFeatures(remFeature_, id_new_);
this.removedFeatures.push(remFeature);
}
this.getIndizes=getIndizes;
function getIndizes(){
removedFeaturesIndizes = this.removedFeatures.map(function(d){return d.id});
return removedFeaturesIndizes;
}
}
//object to store and administrate all feature features
function featureObjStorage(){
this.featureObjects = [];
var featureObjectsIndizes = [];
this.addFeatObj=addFeatObj;
function addFeatObj(feature){
var feature_obj = new featureObj(feature);
this.featureObjects.push(feature_obj);
}
this.getIndizes=getIndizes;
function getIndizes(){
featureObjectsIndizes = this.featureObjects.map(function(d){return d.id});
return featureObjectsIndizes;
}
this.removeFeatObj=removeFeatObj;
function removeFeatObj(featureObject_, removedFeatureStorage_, addToCandidate_, indexOfMultiPolyPart__){
if(featureObject_.type=='Polygon'){
var originIndex_ = featureObjectsIndizes.indexOf(featureObject_.id)
var removed=this.featureObjects.splice(originIndex_,1)
removedFeatureStorage_.addRemFeat(featureObject_, addToCandidate_.id);
//console.log("This is the storage of removed features ... is the new one here?! ",removedFeatureStorage_.removedFeatures)
}
else if(featureObject_.type=='MultiPolygon'){
featureObject_.geometry.splice(indexOfMultiPolyPart__,1)
featureObject_.removed_multi_parts.push(indexOfMultiPolyPart__) //!!!Maybe necessary to have an info within the featureObject that/which part of the multipolygon was removed
featureObject_.removed_multi_parts_aggregated_to.push(addToCandidate_.id)
featureObject_.original_geometry[indexOfMultiPolyPart__] = addToCandidate_.id
//console.log("control feature removement: ", featureObject_)
removedFeatureStorage_.addRemFeat(featureObject_, addToCandidate_.id);
}
}
}
//End of 'Objects'
//***********************
//Aggregation - 'Functions'
function aggregateFeatures(analysedFeature_, aggregationPartnerARC_, aggregationPartnerFeature_, arcCollection_, neighType_){
//change value of the arc_id of the aggregationPartnerARC, in dependence of it's direction as the analysedFeature needs the oposit of its aggregationPartner
if (aggregationPartnerARC_.direction == 1)var replace_id = aggregationPartnerARC_.arc_id;
else if (aggregationPartnerARC_.direction == -1)var replace_id = (aggregationPartnerARC_.arc_id+1)*(-1);
//differ between 'holes' and 'mesh_elements'
if(neighType_=='mesh_element'){ //features that are part of the topologic mesh
//reform the geometry of the analysed feature --> 'analysedFeature_'
var reformPolygonCache = reformPolygonArcs2(aggregationPartnerARC_.direction, aggregationPartnerARC_.arc_id, analysedFeature_);
//alocate the reformed and the original geometry to a variable
var reformedGeom = reformPolygonCache[0].slice();
var reformedGeomOrigin = reformPolygonCache[1]; //needed for final 'adding of holes'
//position and geometry finding depends of geometry type
if(aggregationPartnerFeature_.type=='Polygon'){
//find the position ('arcIndex') of the aggregationPartnerARC in the geometry of the 'aggregationPartnerFeature'
var arcIndex = aggregationPartnerFeature_.geometry[0].indexOf(replace_id)
//!ToDo: Would be better to use the initial index that is comming with the neighboring arc!!!
//set the geometry of the aggregationPartner --> go on with that geometry
var aggregationPartnerGeometry = aggregationPartnerFeature_.geometry;
}
else {
//find the position ('arcIndex') of the aggregationPartnerARC by searching through all multipolygon-parts --> result: 'index__'
var indexOfReplace_id = aggregationPartnerFeature_.getArcsPure()[0].indexOf(replace_id)
if(indexOfReplace_id == -1)console.log("D'oh...the stupid problem happened again...it cannot find the arc in the geometries!")
var index__ = aggregationPartnerFeature_.getArcsPure()[1][indexOfReplace_id][0]
//set the position ('arcIndex') of the aggregationPartnerARC in the detected multipolygon-part
var arcIndex = aggregationPartnerFeature_.getArcsPure()[1][indexOfReplace_id][2]
//!ToDo: Would be better to use the initial index that is comming with the neighboring arc!!!
//set the geometry of the multipolygon-part --> go on with that geometry
var aggregationPartnerGeometry = aggregationPartnerFeature_.geometry[index__];
}
//create the aggregated geometry by replacing the arc_id in the geometry of the aggregation partner with ... the reformed geometry of analysed feature
var new_composition = reCombinateArcs2(aggregationPartnerGeometry[0], arcIndex, reformedGeom) //(partner geometry, position of arc, reformed geometry of analysed feature)
//test for and remove redundant arcs, as they are not needed
new_composition = removeRedundantArcs3(new_composition);
//replace the corresponging geometry with the aggregated geometry
aggregationPartnerGeometry[0]=new_composition; //just replace the outer ring ... by that we simply keep the holes
//add the holes of the analysed feature to the aggregation partner...if some exist
//console.log("Hole pushing test_before: ",aggregationPartnerGeometry)
if(analysedFeature_.has_hole[index__]==true){
for(var i=1;i<reformedGeomOrigin.length;i++){
console.log("Test: ",i)
aggregationPartnerGeometry.push(reformedGeomOrigin[i])
}
}
//console.log("Hole pushing test_after: ",aggregationPartnerGeometry)
}
else if (neighType_=='hole'){ //features, that are a hole in a polygon ... holes are not part of the topologic mesh
var multiPoly_holeIndex, multipoly_partIndex;
//console.log("Before hole remove: ", aggregationPartnerFeature_.geometry)
if(aggregationPartnerFeature_.type=='MultiPolygon'){
aggregationPartnerFeature_.geometry.forEach(function(part, j){
for(var i=1;i<part.length;i++){
if(part[i].indexOf(replace_id)!=-1) {multiPoly_holeIndex=i; multipoly_partIndex=j;}
}
})
var cache = aggregationPartnerFeature_.geometry[multipoly_partIndex].splice(multiPoly_holeIndex,1); //remove the hole from the 'aggregationPartner'
}else if (aggregationPartnerFeature_.type=='Polygon'){
for(var i=1;i<aggregationPartnerFeature_.geometry.length;i++){
if(aggregationPartnerFeature_.geometry[i].indexOf(replace_id)!=-1){ multiPoly_holeIndex=i;}
}
var cache = aggregationPartnerFeature_.geometry.splice(multiPoly_holeIndex,1); //remove the hole from the 'aggregationPartner'
}
console.log("Removed a hole from a feature...currently there is no method to finally store this removing!")
//console.log("After hole remove: ", aggregationPartnerFeature_.geometry)
} else console.log("For any reason...there is no neighbor definition given!")
aggregationPartnerFeature_.clipped=true; //let everybody know this feature (aggregationPartner) has aggregated another feature
aggregationPartnerFeature_.aggregatedFeatures.push(analysedFeature_.id) //...let them also know who was aggregated
return replace_id;
}
//function that removes the redundant arc from a feature's geometry and reforms it, when arc is surrounded by other arcs
function reformPolygonArcs2(direction, arc_id, feature){
if (direction == -1)var replace_id0 = arc_id;
else if (direction == 1)var replace_id0 = (arc_id+1)*(-1);
var found = false, x = 0, index__=-1;
if(feature.type=='Polygon')var arcs = feature.geometry;
else if (feature.type=='MultiPolygon') { //find the corresponding Polygon in the Multi-array
while(found==false){
var arcIndex = feature.geometry[x][0].indexOf(replace_id0)
if(arcIndex!=-1){found=true; index__=x;}
x++;
}
var arcs = feature.geometry[index__];
}
return [editPolygon_(replace_id0, arcs),arcs];
function editPolygon_(id, arcs){
//get the indizes ...
var poly_index = 0, //poly_index=0--> we only need the outer ring
arc_index = arcs[poly_index].indexOf(id); //arc_index is the position of the arc in the array of the outer ring
if (arc_index == 0)var de_composition = arcs[poly_index].slice(1);
else { var de_composition = arcs[poly_index].slice(arc_index+1);
de_composition = de_composition.concat(arcs[poly_index].slice(0,arc_index));
}
//console.log("de_composition of arcs: ",de_composition)
return de_composition
}
}
//add the reformed ('redi_geom_') geometry to the -add to- geometry ('feature')
function reCombinateArcs2(feature, arc_index_, redi_geom_){
//when at position 0 --> [reformed arcs, original arcs {1...End}]
if (arc_index_ == 0){
var new_composition_ = redi_geom_;
new_composition_ = new_composition_.concat( feature.slice(1));
//when at any position X --> [original arcs {0...X-1}, reformed arcs, original arcs {X+1...End}]
}else { var new_composition_ = feature.slice(0,arc_index_);
new_composition_ = new_composition_.concat( redi_geom_);
new_composition_ = new_composition_.concat(feature.slice(arc_index_+1));
}
return new_composition_
}
//check for redundant arcs and remove them
//ToDO: I think this works not clean 100% ... you can see 'funny' holes when aggregated geometries surround a not-aggregated feature
function removeRedundantArcs3(new_composition_){
var new_composition__ = new_composition_.slice(0);
var valueArray= new Array();
for (var t=0;t<new_composition__.length;t++){
var this_arc = new_composition__[t];
if(this_arc<0)this_arc=(this_arc*(-1))-1
var indexOfWord = getAllValues(valueArray).indexOf(this_arc);
if(indexOfWord==-1){
var newValue = new data(this_arc, 1);
newValue.indizes.push(t);
valueArray.push(newValue);
}else{
valueArray[indexOfWord].frequency++;
valueArray[indexOfWord].indizes.push(t)
}
}
var allIndizes = []
valueArray.forEach(function(d){if(d.frequency>1)allIndizes=allIndizes.concat(d.indizes) })
//sort the found indizes of the found redundant arcs ... because ... delete them DESC, otherwise I would get problems with the indizes
allIndizes.sort(function sortfunction(a, b){return (b - a)})
//delete the redundant arcs by using the indizes
allIndizes.forEach(function(index){
new_composition__.splice(index,1)})
return new_composition__;
function data(value, frequency)
{
this.value = value;
this.frequency = frequency;
this.indizes = [];
}
function getAllValues(array_of_objects){
return array_of_objects.map(function(d){return d.value;})
}
}
//sort neighbors, in relation to the length of their arc
function sortArcs(neigh_arcs, arcCollection_){
var list = neigh_arcs.map(function(a){
//a.length =arcCollection_[a.arc_id].length;
return a;})
list.sort(function sortfunction(a, b){return (arcCollection_[b.arc_id].length - arcCollection_[a.arc_id].length)})
//console.log('list-sorted: ', list)
return list;
}
//analyse the set of neighbors and return a 'neighborType'...possible values: isle, hole, mesh_element, undefined
function analyseNeighbors(neighbors_, type_, analysed_geometry_){
var neighType_ = undefined;
if(neighbors_.length==0)neighType_='isle';
else if (neighbors_.length==1 && analysed_geometry_.length == 1 && type_=='MultiPolygon')neighType_='hole';
else {
var neighIDs = [], neighIDCounter = [];
neighbors_.forEach(function(neighbor){
//when it does not exist...push to arrays of IDs and IDCounters
if(neighIDs.indexOf(neighbor.id)==-1){neighIDs.push(neighbor.id); neighIDCounter.push(1);}
//when it exists...inkrement the corresponding counter
else neighIDCounter[neighIDs.indexOf(neighbor.id)]++;
})
//when there is only one id...this is also a hole
if(neighIDs.length==1 && analysed_geometry_.length == neighIDCounter.length && type_=='MultiPolygon')neighType_='hole';
else if(neighIDs.length==1 && type_=='Polygon')neighType_='mesh_element';
else if(neighIDs.length > 1)neighType_='mesh_element';
else if (neighIDs.length==1)neighType_='mesh_element';
else console.log("Neighbor analysis throws an error!");
}
return neighType_;
}
//control if a feature exists and correct the feature-id of the neighbor, when it does not exist
function controlExistenceAndCorrect(id_origin, aggregationPartner_, arcCollection_, removedFeatureStorage_, sorted_neighbors_, featureObjects_, featuresObjectsIDs_, indexOfMultiPolyPart_, neighType_){
//Controll existence...loops until it found an existing feature (1.)...that is a polygon or an existing multipolygon-part (2.)...and has non-identic id with original feature (3.)
var exists = false, finished = false, aggPartID = aggregationPartner_.id, aggPartIndex = -1, id_cache = aggregationPartner_.id, endlessLoopAvoider = 0;
while (exists==false || finished==false){
//++++++++1.1. CHECK EXISTENCE OF AGGREGATION PARTNER+++++++++++++++
aggPartIndex = featuresObjectsIDs_.indexOf(aggPartID);
//++++++++1.2. REPLACE ID WITH ID OF AGGREGATED FEATURE+++++++++++++++
if(aggPartIndex==-1){ //does not exist in the array of 'allFeatures'
aggPartID = getNewID(removedFeatureStorage_, featuresObjectsIDs_, aggPartID); //this function has also a 'while'-loop integrated
aggPartIndex = featuresObjectsIDs_.indexOf(aggPartID)
aggregationPartner_.id = aggPartID;
} else exists=true; //exists in the array of 'allFeatures' --> set boolean to 'true'
//++++++++GET THE COMPLETE NEIGHBOR FEATURE+++++++++++++++
var aggPartFeature = featureObjects_[aggPartIndex];
var arcID = aggregationPartner_.arc_id;
if(aggregationPartner_.direction==-1)arcID=(arcID+1)*(-1)
//++++++++2. DIFFER BETWEEEN THE GEOMETRY TYPES OF THE NEIGHBOR FEATURE+++++++++++++++
if(aggPartFeature.type=='Polygon')finished=true; //when it is a polygon --> directly go on!
else if(aggPartFeature.type=='MultiPolygon'){ //control if the the relevant part of the MultiPolygon does exist
var indexOfMultiPart = 1// = aggregationPartner_.index[0]; //the index of the multipoly-part is the first entry in the array
//1st of all...we have to find the right part of the multipolygon...we do this by evaluating each part
var testARCExistence = []; //-1 = number, 1 = object, without the searched arc, 0 = success, object with arc
aggPartFeature.original_geometry.forEach(function(part){
if( typeof(part)=='number')testARCExistence.push(-1) //it is a number! - then it was replaced and the number indicates the id of the feature where it was aggregated to
else if( typeof(part)=='object'){ //it is an object! - good then we can search the corresponding arc in there
if(neighType_=='mesh_element') {
var arcIndex = part[0].indexOf(arcID);
if(arcIndex==-1)testARCExistence.push(1) //no...the arc is not within that part
else testARCExistence.push(0) //yes...the arc is within that part
}else if(neighType_=='hole'){
console.log("Does this ever happen?")
var tester = false;
for(var j=1;j<part.length;j++){
var arcIndex = part[j].indexOf(arcID);
if(arcIndex!=-1){
testARCExistence.push(0) //yes...the arc is within that part
tester==true;
}
}
if(tester == false)testARCExistence.push(1); //no...the arc is not within that part
}
}
})
//console.log("Finally: ", testARCExistence)
if(testARCExistence.indexOf(0)!=-1){ //cool...we found a multipoly-part that still exists and has the arc inside
indexOfMultiPart = testARCExistence.indexOf(0);
//console.log("Success! This is the right position: ",testARCExistence.indexOf(0),indexOfMultiPart)
}
else { //damn...we did not found a multipoly-part that still exists and has the arc inside
console.log("Oh no! All parts or the necessary one were replaced!")
var replacedParts = [];
//lets get all IDs of the already aggregated parts...as we have to search within them
testARCExistence.forEach(function(d,i){if(d==-1)replacedParts.push([aggPartFeature.original_geometry[i],i])})
var found_ = -1;
//loop through all of them...get the corresponding arcs...and find the searched arc
replacedParts.forEach(function(d,i){
var featIndex = featuresObjectsIDs_.indexOf(d[0]);
if (featIndex==-1){ //nobody at home...this feature was already removed
var interID = getNewID(removedFeatureStorage_, featuresObjectsIDs_, d[0]); //get the new id
featIndex = featuresObjectsIDs_.indexOf(interID); //get the correct index using the new id
}
var feat = featureObjects_[featIndex]
if(feat.getArcsPure()[0].indexOf(arcID)!=-1)found_=d[1];
})
if(found_!=-1)indexOfMultiPart=found_; //Yeah...we found it already at the next level
else { //Damn...we did not find it at the next level...we have to go deeper!
console.log("It is not enough to simply search for replaced multipolgon-parts...you have to implement a rekursive search!!!")
}
}
var aggPartFeature_MultiPart = aggPartFeature.original_geometry[indexOfMultiPart]; //get the corresponding part of the multipolygonal aggregation partner
//control existence of this part
if (typeof (aggPartFeature_MultiPart) == 'object')finished=true; //was not removed --> go on!
else if (typeof (aggPartFeature_MultiPart) == 'number'){ //was already removed_--> find new ID and begin the loop again
aggPartID = aggPartFeature_MultiPart; //replace the cached id
aggregationPartner_.id = aggPartID; //replace the id of the 'aggregationPartner'
//console.log("aggregationPartner_.id: ",aggregationPartner_.id)
}
else if (aggPartFeature_MultiPart == undefined) console.log("was not")
else console.log("Something went wrong within the 'control existence and correction of the aggregation partner!'")
}
//++++++++3. CHECK IF THE NEWLY FOUND ('aggPartID') ID IS DIFFERENT FROM THE ID OF THE ORIGINAL FEATURE ('id_origin')+++++++++++++++
if(id_origin==aggPartID){
console.log("Watchout! Identic ID's have been detected...maybe you don't like how it is currently implemented!!! Here they are: ", id_origin, aggPartID, id_cache)
var this_arc_members = arcCollection_[aggregationPartner_.arc_id].members;
//the other member of the arc, is the one we began to analyse at this point...so we cached it at the beginning and use this one (id_cache) now
if(this_arc_members[0].id!=id_cache)aggPartID=this_arc_members[0].id
else if(this_arc_members[1].id!=id_cache)aggPartID=this_arc_members[1].id
//change the direction of the longest neighbor...as we are using now the other member of the arc
aggregationPartner_.direction = aggregationPartner_.direction * (-1)
aggregationPartner_.id = aggPartID;
finished=false;
}
endlessLoopAvoider++;
if(endlessLoopAvoider>=100){finished=true; aggregationPartner_ = undefined; console.log("Stopped the endless Loop in 'controlExistenceAndCorrect'!!!")}
}
return aggregationPartner_;
}
//get the new ID of a removed feature
function getNewID(removedFeatureStorage__, featuresObjectsIDs__, id__){
var stop_ = false, id = id__, endlessLoopAvoider = 0;
while(stop_==false){
//console.log("intermediate steps1: ",removedFeatureStorage__.removedFeatures[removedFeatureStorage__.getIndizes().indexOf(id)].id_new)
id = removedFeatureStorage__.removedFeatures[removedFeatureStorage__.getIndizes().indexOf(id)].id_new;
//console.log("intermediate steps2: ",id)
var removedIndex_ = featuresObjectsIDs__.indexOf(id);
if(removedIndex_!=-1) stop_ = true; //the new one does exist ... else go on!
endlessLoopAvoider++;
if(endlessLoopAvoider>=1000){stop_=true; console.log("Endless Loop in 'getNewID'!!!")}
}
return id;
}
function getNeighborCopy(neigh){
var aggregationPartner_ = {};
aggregationPartner_.id = neigh.id;
aggregationPartner_.direction = neigh.direction;
aggregationPartner_.arc_id = neigh.arc_id;
aggregationPartner_.index = neigh.index;
return aggregationPartner_;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment