Skip to content

Commit

Permalink
Created visibility map from trapezoids - not yet used
Browse files Browse the repository at this point in the history
new: create_visibility_map, test_visibility_map,
test_monotonate_trapezoids2
  • Loading branch information
jahting committed Jul 31, 2014
1 parent 4c69a31 commit 2b22fd0
Show file tree
Hide file tree
Showing 4 changed files with 377 additions and 0 deletions.
59 changes: 59 additions & 0 deletions build/pnltri.js
Original file line number Diff line number Diff line change
Expand Up @@ -1885,6 +1885,65 @@ PNLTRI.Trapezoider.prototype = {
return this.queryStructure.find_first_inside();
},

create_visibility_map: function () {
var TR_UL = 0, TR_UM = 1, TR_ULR = 2, TR_UR = 3;
var TR_DR = 4, TR_DM = 5, TR_DLR = 6, TR_DL = 7;

var myQs = this.queryStructure;
var myVertices = this.polyData.vertices; // TODO: replace

var myExternalNeighbors = new Array(myVertices.length);
var myVisibleNeighbors = [];
for ( var i=0; i<myVertices.length; i++ ) {
myVisibleNeighbors.push( { // CCW
tr: new Array(TR_DL+1),
vList: [],
} );
}
for (var i=0,j=myQs.trapArray.length; i<j; i++) {
var thisTrap = myQs.trapArray[i];
var highPos = thisTrap.uL ?
( thisTrap.uR ? TR_DM : TR_DL ) :
( thisTrap.uR ? TR_DR : TR_DLR );
var lowPos = thisTrap.dL ?
( thisTrap.dR ? TR_UM : TR_UL ) :
( thisTrap.dR ? TR_UR : TR_ULR );

if ( ( thisTrap.depth % 2 ) == 1 ) { // inside ?
if ( ( highPos == TR_DM ) || ( lowPos == TR_UM ) ||
( ( highPos == TR_DL ) && ( lowPos == TR_UR ) ) ||
( ( highPos == TR_DR ) && ( lowPos == TR_UL ) ) ) {
myVisibleNeighbors[thisTrap.vHigh.id].tr[highPos] = thisTrap.vLow;
myVisibleNeighbors[thisTrap.vLow.id].tr[lowPos] = thisTrap.vHigh;
}
} else {
if ( thisTrap.vHigh.id != null ) myExternalNeighbors[thisTrap.vHigh.id] = highPos;
if ( thisTrap.vLow.id != null ) myExternalNeighbors[thisTrap.vLow.id] = lowPos;
}
}
for ( i=0; i<myVisibleNeighbors.length; i++ ) {
var otherVertIds = [];
var thisVert = myVisibleNeighbors[i];

var firstElem = myExternalNeighbors[i];
if ( firstElem == null ) { // eg. skipped vertices (zero length, co-linear
// console.log( "ERR create_visibility_map: no external trapezoids for vertex "+i);
continue;
}
var j = firstElem;
do {
if ( j++ > TR_DL ) j = TR_UL;
if ( thisVert.tr[j] ) thisVert.vList.push( thisVert.tr[j] );
} while ( j != firstElem )
}

var result = [];
for ( i=0; i<myVisibleNeighbors.length; i++ ) {
result[i] = myVisibleNeighbors[i].vList.map( function (vertex) { return vertex.id } );
}
return result;
},

/*
* Mathematics helper methods
*/
Expand Down
59 changes: 59 additions & 0 deletions src/Trapezoider.js
Original file line number Diff line number Diff line change
Expand Up @@ -1040,6 +1040,65 @@ PNLTRI.Trapezoider.prototype = {
return this.queryStructure.find_first_inside();
},

create_visibility_map: function () {
var TR_UL = 0, TR_UM = 1, TR_ULR = 2, TR_UR = 3;
var TR_DR = 4, TR_DM = 5, TR_DLR = 6, TR_DL = 7;

var myQs = this.queryStructure;
var myVertices = this.polyData.vertices; // TODO: replace

var myExternalNeighbors = new Array(myVertices.length);
var myVisibleNeighbors = [];
for ( var i=0; i<myVertices.length; i++ ) {
myVisibleNeighbors.push( { // CCW
tr: new Array(TR_DL+1),
vList: [],
} );
}
for (var i=0,j=myQs.trapArray.length; i<j; i++) {
var thisTrap = myQs.trapArray[i];
var highPos = thisTrap.uL ?
( thisTrap.uR ? TR_DM : TR_DL ) :
( thisTrap.uR ? TR_DR : TR_DLR );
var lowPos = thisTrap.dL ?
( thisTrap.dR ? TR_UM : TR_UL ) :
( thisTrap.dR ? TR_UR : TR_ULR );

if ( ( thisTrap.depth % 2 ) == 1 ) { // inside ?
if ( ( highPos == TR_DM ) || ( lowPos == TR_UM ) ||
( ( highPos == TR_DL ) && ( lowPos == TR_UR ) ) ||
( ( highPos == TR_DR ) && ( lowPos == TR_UL ) ) ) {
myVisibleNeighbors[thisTrap.vHigh.id].tr[highPos] = thisTrap.vLow;
myVisibleNeighbors[thisTrap.vLow.id].tr[lowPos] = thisTrap.vHigh;
}
} else {
if ( thisTrap.vHigh.id != null ) myExternalNeighbors[thisTrap.vHigh.id] = highPos;
if ( thisTrap.vLow.id != null ) myExternalNeighbors[thisTrap.vLow.id] = lowPos;
}
}
for ( i=0; i<myVisibleNeighbors.length; i++ ) {
var otherVertIds = [];
var thisVert = myVisibleNeighbors[i];

var firstElem = myExternalNeighbors[i];
if ( firstElem == null ) { // eg. skipped vertices (zero length, co-linear
// console.log( "ERR create_visibility_map: no external trapezoids for vertex "+i);
continue;
}
var j = firstElem;
do {
if ( j++ > TR_DL ) j = TR_UL;
if ( thisVert.tr[j] ) thisVert.vList.push( thisVert.tr[j] );
} while ( j != firstElem )
}

var result = [];
for ( i=0; i<myVisibleNeighbors.length; i++ ) {
result[i] = myVisibleNeighbors[i].vList.map( function (vertex) { return vertex.id } );
}
return result;
},

/*
* Mathematics helper methods
*/
Expand Down
178 changes: 178 additions & 0 deletions test/MonoSplitterTest.js
Original file line number Diff line number Diff line change
Expand Up @@ -936,6 +936,147 @@ function test_MonoSplitter() {
}


function test_monotonate_trapezoids2( inDataName, inDebug ) {
PNLTRI.Math.randomTestSetup(); // set specific random seed for repeatable testing
// for random-error detection - default seed: 73
// PNLTRI.Math.myRandom( 1 ); // 3: 1 missing; 4,8: 2 missing; 10,11: nur weniger Chains
// PNLTRI.Math.random = PNLTRI.Math.myRandom;
// PNLTRI.Math.random = Math.random;
//
var myPolygonData = new PNLTRI.PolygonData( testData.get_polygon_with_holes( inDataName ) );
//
var myMono = new PNLTRI.MonoSplitter( myPolygonData );
//
// Main Test
//
myMono.monotonate_trapezoids(); // implicitly creates trapezoids
if ( inDebug > 0 ) {
// showDataStructure( myPolygonData.getVertices(), [ 'sprev', 'snext', 'vertTo', 'segOut' ] );
// showDataStructure( myPolygonData.getSegments(), [ 'sprev', 'snext', 'mprev', 'mnext', 'vertTo', 'segOut' ] );
// showDataStructure( myPolygonData.getMonoSubPolys(), [ 'sprev', 'snext', 'mprev', 'vertTo', 'segOut' ] );
//
// showDataStructure( myPolygonData.monotone_chains_2_polygons() );
drawPolygonLayers( { "mono": myPolygonData.monotone_chains_2_polygons() }, inDebug );
//
var myQsRoot = myMono.getQsRoot();
// showDataStructure( myQsRoot );
drawTrapezoids( myQsRoot, false, inDebug );
}

var myTrapezoider = myMono.trapezoider;
var vMap = myTrapezoider.create_visibility_map();

var myVertices = myPolygonData.getVertices();
for ( var i=0; i<myVertices.length; i++ ) {
var vertOutSegs = myVertices[i].outSegs;
if ( vertOutSegs.length == 0 ) continue;
var vertVisible = vMap[i];
equal( vertVisible.length+1, vertOutSegs.length, "monotonate_trapezoids2 ("+inDataName+"): equal length("+i+")" );
if ( vertVisible.length == 0 ) continue;
if ( vertVisible.length == 1 ) {
equal( vertVisible[0], vertOutSegs[1].vertTo.id, "monotonate_trapezoids2 ("+inDataName+"): equal id("+i+",0(1))" );
} else if ( vertVisible.length == 2 ) {
if ( vertVisible[0] != vertOutSegs[2].vertTo.id ) {
var tmp = vertOutSegs[2];
vertOutSegs[2] = vertOutSegs[1];
vertOutSegs[1] = tmp;
}
equal( vertVisible[0], vertOutSegs[2].vertTo.id, "monotonate_trapezoids2 ("+inDataName+"): equal id("+i+",0(2))" );
equal( vertVisible[1], vertOutSegs[1].vertTo.id, "monotonate_trapezoids2 ("+inDataName+"): equal id("+i+",1(2))" );
} else if ( vertVisible.length == 3 ) {
if ( vertVisible[0] != vertOutSegs[3].vertTo.id ) {
if ( vertVisible[0] != vertOutSegs[2].vertTo.id ) {
var tmp = vertOutSegs[3];
vertOutSegs[3] = vertOutSegs[1];
vertOutSegs[1] = tmp;
} else {
var tmp = vertOutSegs[3];
vertOutSegs[3] = vertOutSegs[2];
vertOutSegs[2] = tmp;
}
}
if ( vertVisible[1] != vertOutSegs[2].vertTo.id ) {
var tmp = vertOutSegs[2];
vertOutSegs[2] = vertOutSegs[1];
vertOutSegs[1] = tmp;
}
equal( vertVisible[0], vertOutSegs[3].vertTo.id, "monotonate_trapezoids2 ("+inDataName+"): equal id("+i+",0(3))" );
equal( vertVisible[1], vertOutSegs[2].vertTo.id, "monotonate_trapezoids2 ("+inDataName+"): equal id("+i+",1(3))" );
equal( vertVisible[2], vertOutSegs[1].vertTo.id, "monotonate_trapezoids2 ("+inDataName+"): equal id("+i+",2(3))" );
} else {
ok( false, "monotonate_trapezoids2 ("+inDataName+"): length("+i+") <= 3" );
}
var firstIdx = vertOutSegs.length-1;
var firstSegOut = vertOutSegs[firstIdx].segOut;
// pure mono segment
ok( !firstSegOut.snext, "monotonate_trapezoids2 ("+inDataName+"): no snext("+i+",first)" );
ok( !firstSegOut.sprev, "monotonate_trapezoids2 ("+inDataName+"): no sprev("+i+",first)" );
// prev segment is original polygon/hole segment
var prevSegOut = firstSegOut.mprev;
ok( ( prevSegOut.mnext == firstSegOut ), "monotonate_trapezoids2 ("+inDataName+"): mprev->mnext->this("+i+",first)" );
ok( prevSegOut.vFrom.outSegs[0].segOut == prevSegOut, "monotonate_trapezoids2 ("+inDataName+"): mprev.vertTo-> this("+i+",first)" );
ok( prevSegOut.vFrom.outSegs[0].vertTo == myVertices[i], "monotonate_trapezoids2 ("+inDataName+"): mprev.vertTo-> this("+i+",first)" );
// reverse mono segment
var reverseOutSeg = find_outseg_to( vertOutSegs[firstIdx].vertTo, myVertices[i] );
ok( reverseOutSeg, "monotonate_trapezoids2 ("+inDataName+"): reverseOutSeg("+i+",first)" );
var reverseSegOut = reverseOutSeg.segOut;
//
if ( --firstIdx == 0 ) {
var lastSegOut = vertOutSegs[0].segOut;
ok( ( reverseSegOut.mnext == lastSegOut ), "monotonate_trapezoids2 ("+inDataName+"): reverseSegOut.mnext->lastSegOut("+i+",first)" );
ok( ( reverseSegOut == lastSegOut.mprev ), "monotonate_trapezoids2 ("+inDataName+"): lastSegOut.mprev->reverseSegOut("+i+",first)" );
} else {
// second mono segment
var secondSegOut = vertOutSegs[firstIdx].segOut;
// pure mono segment
ok( !secondSegOut.snext, "monotonate_trapezoids2 ("+inDataName+"): no snext("+i+",second)" );
ok( !secondSegOut.sprev, "monotonate_trapezoids2 ("+inDataName+"): no sprev("+i+",second)" );
// prev mono segment is reverse( first segment )
ok( ( reverseSegOut.mnext == secondSegOut ), "monotonate_trapezoids2 ("+inDataName+"): reverseSegOut.mnext->this("+i+",second)" );
ok( ( reverseSegOut == secondSegOut.mprev ), "monotonate_trapezoids2 ("+inDataName+"): this.mprev->reverseSegOut("+i+",second)" );
// reverse mono segment
reverseOutSeg = find_outseg_to( vertOutSegs[firstIdx].vertTo, myVertices[i] );
ok( reverseOutSeg, "monotonate_trapezoids2 ("+inDataName+"): reverseOutSeg("+i+",second)" );
reverseSegOut = reverseOutSeg.segOut;
//
if ( --firstIdx == 0 ) {
var lastSegOut = vertOutSegs[0].segOut;
ok( ( reverseSegOut.mnext == lastSegOut ), "monotonate_trapezoids2 ("+inDataName+"): reverseSegOut.mnext->lastSegOut("+i+",second)" );
ok( ( reverseSegOut == lastSegOut.mprev ), "monotonate_trapezoids2 ("+inDataName+"): lastSegOut.mprev->reverseSegOut("+i+",second)" );
} else {
// third mono segment
var thirdSegOut = vertOutSegs[firstIdx].segOut;
// pure mono segment
ok( !thirdSegOut.snext, "monotonate_trapezoids2 ("+inDataName+"): no snext("+i+",third)" );
ok( !thirdSegOut.sprev, "monotonate_trapezoids2 ("+inDataName+"): no sprev("+i+",third)" );
// prev mono segment is reverse( first segment )
ok( ( reverseSegOut.mnext == thirdSegOut ), "monotonate_trapezoids2 ("+inDataName+"): reverseSegOut.mnext->this("+i+",third)" );
ok( ( reverseSegOut == thirdSegOut.mprev ), "monotonate_trapezoids2 ("+inDataName+"): this.mprev->reverseSegOut("+i+",third)" );
// reverse mono segment
reverseOutSeg = find_outseg_to( vertOutSegs[firstIdx].vertTo, myVertices[i] );
ok( reverseOutSeg, "monotonate_trapezoids2 ("+inDataName+"): reverseOutSeg("+i+",third)" );
reverseSegOut = reverseOutSeg.segOut;
//
if ( --firstIdx == 0 ) {
var lastSegOut = vertOutSegs[0].segOut;
ok( ( reverseSegOut.mnext == lastSegOut ), "monotonate_trapezoids2 ("+inDataName+"): reverseSegOut.mnext->lastSegOut("+i+",third)" );
ok( ( reverseSegOut == lastSegOut.mprev ), "monotonate_trapezoids2 ("+inDataName+"): lastSegOut.mprev->reverseSegOut("+i+",third)" );
} else {
ok( false, "monotonate_trapezoids2 ("+inDataName+"): no 4th segment("+i+")" );
}
}
}
}

function find_outseg_to( inVertexFrom, inVertexTo ) {
for (var i=0; i<inVertexFrom.outSegs.length; i++) {
if ( inVertexFrom.outSegs[i].vertTo == inVertexTo ) return inVertexFrom.outSegs[i];
}
return null;
}
}


test( "Polygon Monotone Splitter", function() {
// contour: CCW; no hole
// no diagonal
Expand Down Expand Up @@ -980,6 +1121,43 @@ function test_MonoSplitter() {
test_monotonate_trapezoids( "two_polygons#1", 14, 0 ); // 0.5; 6.Error, integrating into Three.js ("i")
test_monotonate_trapezoids( "two_polygons#2", 2, 0 ); // 1; my#6: two trivial polygons
test_monotonate_trapezoids( "polygons_inside_hole", 5, 0 ); // 0.7; my#7: square with unregular hole with two polygons inside

//

test_monotonate_trapezoids2( "article_poly", 0 ); // 1.5; from article Sei91
test_monotonate_trapezoids2( "square_3triangholes", 0 ); // 5; from "Narkhede A. and Manocha D.", data_1
test_monotonate_trapezoids2( "trap_2up_2down", 0 ); // 4; trapezoid with 2 upper and 2 lower neighbors
test_monotonate_trapezoids2( "pt_3_diag_max", 0 ); // 4: vertex (6,6) with 3 additional diagonals (max)
test_monotonate_trapezoids2( "many_ears", 0 ); // 2; from slides3.pdf
test_monotonate_trapezoids2( "y_monotone", 0 ); // 2.5; from slides3.pdf
test_monotonate_trapezoids2( "for_sweep1", 0 ); // 2; from slides3.pdf
test_monotonate_trapezoids2( "for_sweep2", 0 ); // 2; from slides3.pdf
test_monotonate_trapezoids2( "for_sweep3", 0 ); // 2; from slides3.pdf
test_monotonate_trapezoids2( "xy_bad_saw", 0 ); // 2: very inconvenient contour in X- and Y-direction

test_monotonate_trapezoids2( "hole_short_path", 0 ); // 0.8; shortest path to hole is outside polygon
test_monotonate_trapezoids2( "star_eight", 0 ); // 10; symmetric 8-pointed star
test_monotonate_trapezoids2( "unregular_hole", 0 ); // 10; unregular hole
test_monotonate_trapezoids2( "with_unregular_hole", 0 ); // 0.7; square with unregular hole
test_monotonate_trapezoids2( "with_unreg_and_star_hole", 0 ); // 0.7; square with unregular and star hole
test_monotonate_trapezoids2( "colinear#1", 0 ); // 1; 4 touching co-linear lines
test_monotonate_trapezoids2( "colinear#2", 0 ); // 1; 4 touching co-linear lines & 4 touching colinear holes
test_monotonate_trapezoids2( "tree_error#1", 0 ); // 1; from Triangulation Error of Tree (TODO: Source)
test_monotonate_trapezoids2( "tree_full", 0 ); // 0.22; from Triangulation Error of Tree (TODO: Source)

test_monotonate_trapezoids2( "three_error#1", 0 ); // 1; 1.Error, integrating into Three.js
test_monotonate_trapezoids2( "three_error#2", 0 ); // 0.7; 2.Error, integrating into Three.js (letter "1")
test_monotonate_trapezoids2( "three_error#3", 0 ); // 3000; 3.Error, integrating into Three.js (logbuffer)
test_monotonate_trapezoids2( "three_error#4", 0 ); // 1; 4.Error, integrating into Three.js (USA Maine)
test_monotonate_trapezoids2( "three_error#4b", 0 ); // 0.04; 4.Error, integrating into Three.js (USA Maine)
test_monotonate_trapezoids2( "hole_first", 0 ); // 0.5; 5.Error, integrating into Three.js ("R")
test_monotonate_trapezoids2( "two_polygons#1", 0 ); // 0.5; 6.Error, integrating into Three.js ("i")
test_monotonate_trapezoids2( "two_polygons#2", 0 ); // 1; my#6: two trivial polygons
test_monotonate_trapezoids2( "polygons_inside_hole", 0 ); // 0.7; my#7: square with unregular hole with two polygons inside
//
test_monotonate_trapezoids2( "squares_perftest_min", 0 ); // 1: 3x3 squares in square, performance test
// test_monotonate_trapezoids2( "squares_perftest_mid", 1 ); // 1: 15x15 squares in square, performance test
// test_monotonate_trapezoids2( "squares_perftest_max", 1 ); // 1: 40x40 squares in square, performance test
});
}

Loading

0 comments on commit 2b22fd0

Please sign in to comment.