Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add surface shape performance test #701

Open
wants to merge 25 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
5934d9e
Initial surface shapes functional test
zglueck May 17, 2018
80b9d56
Update layout
zglueck May 17, 2018
b289002
Merge branch 'develop' into feature/#694-surface-shape-testing
zglueck May 17, 2018
bc3ff94
Refactor common utilities to helper class
zglueck May 17, 2018
7f28f21
Refactor navigation to use redraw callbacks instead of timeouts
zglueck May 17, 2018
b78772e
Add notional frame rate output display
zglueck May 17, 2018
23a1cff
Refine notional statistics output
zglueck May 17, 2018
087f0b4
Update movement utility
zglueck May 18, 2018
e3f35a2
Refactor function layout
zglueck May 18, 2018
ec27bb2
Update layout
zglueck May 18, 2018
f155427
Update static shape generation region
zglueck May 18, 2018
8ddf26c
Add initial copy to clipboard functionality
zglueck May 18, 2018
f67f896
Refactor status and results output to utility class
zglueck May 21, 2018
5ca89e7
Add dynamic shapes
zglueck May 21, 2018
6f7e9d7
Refactor status results output
zglueck May 21, 2018
c93abf0
Add comments
zglueck May 21, 2018
b45810f
Merge branch 'develop' into feature/#694-surface-shape-testing
zglueck May 21, 2018
75e6ba6
Add PRNG and comments
zglueck May 21, 2018
b4434b4
Fix path case
zglueck May 22, 2018
932c17e
Merge branch 'develop' into feature/#694-surface-shape-testing
pdavidc May 23, 2018
eee4352
Registered the functionalTest folder as a WebStorm test root
pdavidc May 23, 2018
3f7dcf9
Change file names
zglueck May 23, 2018
0d432f2
Change directory structure to mimic src
zglueck May 23, 2018
928342b
Change directory structure to mimic src
zglueck May 23, 2018
6c46e5a
Remove frame time distribution plot
zglueck May 23, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .idea/WebWorldWind.iml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

78 changes: 78 additions & 0 deletions functionalTest/SurfaceShapes.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
<!doctype html>
<html lang="en">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.1/css/bootstrap.min.css" integrity="sha384-WskhaSGFgHYWDcbwN70/dfYBj47jz9qbsMId/iRN3ewGhXQFZCSftd1LZCfmhktB" crossorigin="anonymous">

<title>Surface Shape Performance Functional Test</title>

<style>
#globe {
background-color: black;
width: 100%;
height: 100vh;
}
textarea {
width: 100%;
padding: 5px;
}
</style>
</head>
<body>
<div class="container-fluid">
<div class="row">

<!-- Globe Column -->
<div class="col-xl-8 col-lg-12">
<canvas id="globe">
Browser Does Not Support HTML5
</canvas>
</div>

<!-- User Interface, Status, and Result Output -->
<div class="col-xl-4 col-lg-12">

<!-- Test Description/Controls -->
<div>
<h2>
Surface Shape Performance Tests
</h2>
<p>
Reload the page between tests. Once the test has been completed, a statistical summary of the frame
times and a distribution of the frame times grouped by five second durations is displayed. Below the
frame time distribution plot, a text area with the actual frame times is displayed as well as a
button which automates copying of the data to the clipboard.
</p>
</div>
<div id="buttons">
<h3>Available Tests:</h3>
<button id="navigate-button" type="button" class="btn btn-secondary">No Shapes</button>
<button id="static-button" type="button" class="btn btn-secondary">Static Shapes</button>
<button id="dynamic-button" type="button" class="btn btn-secondary">Dynamic Shapes</button>
</div>
<hr>

<!-- Status and Results Output -->
<div>
<div id="status-output">

</div>
<hr>
<div id="results-output">

</div>
</div>
</div>
</div>
</div>

<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min.js" integrity="sha384-ZMP7rVo3mIykV+2+9J3UJ46jBk0WLaUAdn689aCwoqbBJiSnjAK/l8WvCWPIPm49" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.1/js/bootstrap.min.js" integrity="sha384-smHYKdLADwkXOn1EmN1qk/HfnUcbVRZyYmZ4qpPea6sjB/pTJ0euyQp0Mk8ck+5T" crossorigin="anonymous"></script>
<script data-main="SurfaceShapes" src="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.5/require.min.js" integrity="sha256-0SGl1PJNDyJwcV5T+weg2zpEMrh7xvlwO4oXgvZCeZk=" crossorigin="anonymous"></script>
</body>
</html>
277 changes: 277 additions & 0 deletions functionalTest/SurfaceShapes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,277 @@
requirejs([
'../src/WorldWind',
'./Util'
],
function (WorldWind, Util) {
"use strict";

// Define shape counts for testing
var dynamicShapeCount = 100; // of each type of shape (circle, ellipse, etc.)
var staticShapeCount = 1000; // of each type of shape (circle, ellipse, etc.)

// Initialize Globe
var wwd = Util.initializeLowResourceWorldWindow("globe");
var testLayer = new WorldWind.RenderableLayer("Test Layer");
wwd.addLayer(testLayer);
var util = new Util(wwd);

util.setStatusMessage("Globe loaded, ready for testing...");

// Navigation Moves for Testing
var moveZero = {
latitude: {
goal: wwd.navigator.lookAtLocation.latitude,
step: Number.MAX_VALUE
},
longitude: {
goal: wwd.navigator.lookAtLocation.longitude,
step: Number.MAX_VALUE
},
tilt: {
goal: 0,
step: Number.MAX_VALUE
},
heading: {
goal: 0,
step: Number.MAX_VALUE
},
range: {
goal: wwd.navigator.range,
step: Number.MAX_VALUE
}
};

var moveOne = {
range: {
goal: 8e5,
step: 5e4
},
tilt: {
goal: 75,
step: 0.75
},
onComplete: function () {
util.setStatusMessage("First move complete...");
}
};

var moveTwo = {
heading: {
goal: 90,
step: 0.75
},
onComplete: function () {
util.setStatusMessage("Second move complete");
}
};

var moveThree = {
latitude: {
goal: wwd.navigator.lookAtLocation.latitude,
step: 1
},
longitude: {
goal: -70,
step: 0.5
},
onComplete: function () {
util.stopMetricCapture();
util.setStatusMessage("Move Complete");

// output metrics
var stats = util.frameStats.map(function (frameStat) {
return frameStat.frameTime;
});
stats.shift();
stats.pop();
util.setOutputMessage(Util.generateResultsSummary(stats, "Frame Times"));
stats = util.frameStats.map(function (frameStat) {
return frameStat.layerRenderingTime;
});
}
};

// Utility functions

// This is a pseudo random number generator which allows a seed, providing repeatable conditions
var nextFloat = function (seed) {
seed = seed % 2147483647;
return function () {
seed = seed * 16807 % 2147483647;
return (seed - 1) / 2147483646;
};
};
// Assign the PRNG to the function which will be used by the testing for content generation
var rand = nextFloat(1234);

var generateShapeAttributes = function () {
var sa = new WorldWind.ShapeAttributes();
var r = rand();

sa.drawInterior = false;
sa.drawOutline = false;

if (r < 0.3333) {
sa.drawInterior = true;
sa.interiorColor = new WorldWind.Color(rand(), rand(), rand(), rand());
} else if (r < 0.6666) {
sa.drawOutline = true;
sa.outlineColor = new WorldWind.Color(rand(), rand(), rand(), rand());
} else {
sa.drawInterior = true;
sa.interiorColor = new WorldWind.Color(rand(), rand(), rand(), rand());
sa.drawOutline = true;
sa.outlineColor = new WorldWind.Color(rand(), rand(), rand(), rand());
}

return sa;
};

var generateLocation = function () {
var lat = 180 * rand() - 90;
var lon = 360 * rand() - 180;

return new WorldWind.Location(lat, lon);
};

var generateShapes = function (count) {
var sa, shape, sector, radius, topLocation, lat, lon, locations, minorAxis, majorAxis, heading, i, j;

// Surface Circles
for (i = 0; i < count; i++) {
sa = generateShapeAttributes();
radius = rand() * 1000000;
shape = new WorldWind.SurfaceCircle(generateLocation(), radius, sa);
testLayer.addRenderable(shape);
}

// Surface Ellipse
for (i = 0; i < count; i++) {
sa = generateShapeAttributes();
majorAxis = rand() * 1000000;
minorAxis = rand() * 500000;
heading = rand() * 360;
shape = new WorldWind.SurfaceEllipse(generateLocation(), majorAxis, minorAxis, heading, sa);
testLayer.addRenderable(shape);
}

// Surface Polygon
for (i = 0; i < count; i++) {
sa = generateShapeAttributes();
topLocation = generateLocation();
locations = [];
locations.push(topLocation);
for (j = 0; j < 2; j++) {
lat = Math.min(90, Math.max(-90, topLocation.latitude - rand() * 8));
lon = Math.min(180, Math.max(-180, topLocation.longitude - rand() * 8));
locations.push(new WorldWind.Location(lat, lon));
}
shape = new WorldWind.SurfacePolygon(locations, sa);
testLayer.addRenderable(shape);
}

// Surface Polyline
for (i = 0; i < count; i++) {
sa = generateShapeAttributes();
topLocation = generateLocation();
locations = [];
locations.push(topLocation);
for (j = 0; j < 2; j++) {
lat = Math.min(90, Math.max(-90, topLocation.latitude - rand() * 8));
lon = Math.min(180, Math.max(-180, topLocation.longitude - rand() * 8));
locations.push(new WorldWind.Location(lat, lon));
}
shape = new WorldWind.SurfacePolyline(locations, sa);
testLayer.addRenderable(shape);
}

// Surface Rectangle
for (i = 0; i < count; i++) {
sa = generateShapeAttributes();
majorAxis = 1000000 * rand();
minorAxis = 500000 * rand();
heading = 360 * rand();
shape = new WorldWind.SurfaceRectangle(generateLocation(), majorAxis, minorAxis, heading, sa);
testLayer.addRenderable(shape);
}

// Surface Sector
for (i = 0; i < count; i++) {
sa = generateShapeAttributes();
topLocation = generateLocation();
majorAxis = 8 * rand();
minorAxis = 4 * rand();
sector = new WorldWind.Sector(topLocation.latitude, topLocation.latitude + majorAxis,
topLocation.longitude, topLocation.longitude + minorAxis);
shape = new WorldWind.SurfaceSector(sector, sa);
testLayer.addRenderable(shape);
}

wwd.redraw();
};

// Click Event Callbacks
var onMoveClick = function () {
if (!util.isMoving()) {
util.startMetricCapture();
util.move([moveZero, moveOne, moveTwo, moveThree]);
}
};

var onStaticShapesClick = function () {
generateShapes(1000);
wwd.redraw();
onMoveClick();
};

var onDynamicShapesClick = function () {
generateShapes(100);

var onRedrawMoveShapes = function (worldwindow, stage) {
if (stage === WorldWind.AFTER_REDRAW) {
var idx = worldwindow.layers.indexOf(testLayer);

if (idx >= 0) {
var count = worldwindow.layers[idx].renderables.length;

for (var i = 0; i < count; i++) {
var shape = worldwindow.layers[idx].renderables[i];

if (shape instanceof WorldWind.SurfaceCircle || shape instanceof WorldWind.SurfaceEllipse
|| shape instanceof WorldWind.SurfaceRectangle) {
var center = shape.center;
center.latitude += rand() * 0.5 - 0.25;
center.longitude += rand() * 0.5 - 0.25;
shape.center = center;
} else if (shape instanceof WorldWind.SurfacePolygon
|| shape instanceof WorldWind.SurfacePolyline) {
var boundaries = shape.boundaries;
boundaries[0].latitude += rand() * 0.5 - 0.25;
boundaries[0].longitude += rand() * 0.5 - 0.25;
shape.boundaries = boundaries;
} else if (shape instanceof WorldWind.SurfaceSector) {
var sector = shape.sector;
sector.minLongitude += rand() * 0.5 - 0.25;
sector.minLatitude += rand() * 0.5 - 0.25;
shape.sector = sector;
}

}
}
}
};

wwd.redrawCallbacks.push(onRedrawMoveShapes);
wwd.redraw();
onMoveClick();
};

// Click Event Assignments
var navigateButton = document.getElementById("navigate-button");
var staticShapesButton = document.getElementById("static-button");
var dynamicShapesButton = document.getElementById("dynamic-button");

navigateButton.addEventListener("click", onMoveClick);
staticShapesButton.addEventListener("click", onStaticShapesClick);
dynamicShapesButton.addEventListener("click", onDynamicShapesClick);
});
Loading