Last active
December 18, 2015 18:59
-
-
Save milkbread/5829814 to your computer and use it in GitHub Desktop.
JavaScript: RKAggregation - all versions of these functions
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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__; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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