I'm searching a script to get inner ring from a polygon in the shapefile using dotspatial. Below is my script to get all coordinate(ignoring outer/inner ring) from a shapefile.
string shapeFilePath = #"\example.shp";
shapeFilePath = location + shapeFilePath;
Shapefile indexMapFile = Shapefile.OpenFile(shapeFilePath);
indexMapFile.Reproject(KnownCoordinateSystems.Geographic.Australia.GeocentricDatumofAustralia1994);
for (int i = 0; i < indexMapFile.DataTable.Rows.Count; i++)
{
IFeature feature = indexMapFile.Features.ElementAt(i);
var arr = feature.Coordinates.ToArray();
foreach (var det in arr)
{
DotSpatial.Topology.Coordinate det_cor = det;
string X = det_cor.X.ToString();
string Y = det_cor.Y.ToString();
}
}
i found the answer, this is my code, how to get inner ring from polygon
string shapeFilePath = #"\example.shp";
shapeFilePath = location + shapeFilePath;
Shapefile indexMapFile = Shapefile.OpenFile(shapeFilePath);
indexMapFile.Reproject(KnownCoordinateSystems.Geographic.Australia.GeocentricDatumofAustralia1994);
for (int i = 0; i < indexMapFile.DataTable.Rows.Count; i++)
{
IFeature feature = indexMapFile.Features.ElementAt(i);
IPolygon bp = feature.GetBasicGeometryN(0) as IPolygon;
var all_polygon = bp.GetGeometryN(0);//include outer and inner ring, see this link -> https://stackoverflow.com/questions/8139739/wkt-how-do-you-define-polygons-with-3-rings-2-holes
var outer_ring = bp.Shell.GetGeometryN(0);
int idx_hole = 0;
foreach (var hole in bp.Holes)
{
//get inner ring/hole from polygon
Response.Write(bp.GetInteriorRingN(idx_hole));
idx_hole++;
}
}
I have a list of Vectors which represent points on three different floors in three.js.
I am trying to group these vectors according to the floor they belong to. Is there a good formula to do this? Perhaps find height from on vector or something. Not sure how to go about this. Any help would be appreciated.
Thanks,
Rob
As Wilt said... Can't really help you without more info.
Still, if your floors are even and all stand on the xz plane (in my example), You may indeed check the points' height (position.y) against the floors'.
var container, renderer, scene, camera, controls;
var floors = [];
var points = [], materials = [], heights = [];
init();
animate();
function init() {
// renderer
renderer = new THREE.WebGLRenderer({
antialias: true,
alpha: true
});
renderer.setSize(window.innerWidth, window.innerHeight);
container = document.createElement('div');
document.body.appendChild(container);
container.appendChild(renderer.domElement);
// scene
scene = new THREE.Scene();
// camera + controls
camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 10000);
camera.position.set(0, 50, 750);
camera.lookAt(scene.position);
controls = new THREE.OrbitControls(camera, renderer.domElement);
controls.autoRotate = true;
//floors
for(i=0; i<3; i++) {
var planeGeometry = new THREE.BoxGeometry(500, 500, 10, 10);
var planeMaterial = new THREE.MeshBasicMaterial({
color: 0xffffff * Math.random(),
side: THREE.DoubleSide,
transparent: true,
opacity : 0.3,
depthWrite : false //get rid of coplanar glitches wall/floor
});
materials.push(planeMaterial);
var plane = new THREE.Mesh(planeGeometry, planeMaterial);
plane.rotation.x = Math.PI / 2;
//plane.rotation.y = Math.PI / 8; //Uncomment to see this doesn't work if the floors move, i.e. changing rotation/position. If this is what you need, just raycast from point to floor in the animation loop and count how many floors the ray goes through (intersects.length)
plane.position.y = 75*i;
heights.push(plane.position.y);
floors.push(plane);
scene.add(plane);
}
//wall
var height = heights[2];
var planeGeometry = new THREE.BoxGeometry(500, height+100, 10, 10);
var planeMaterial = new THREE.MeshBasicMaterial({
color: 0xffffff * Math.random(),
side: THREE.DoubleSide,
transparent: true,
opacity:0.3,
depthWrite : false //get rid of coplanar glitches wall/floor
});
materials.push(planeMaterial);
var plane = new THREE.Mesh(planeGeometry, planeMaterial);
plane.position.y = heights[1]+45;
plane.position.z = -510/2;
scene.add(plane);
// points
for (i=0; i<200; i++) {
var sphereGeometry = new THREE.SphereGeometry(3, 32, 16);
var sphere = new THREE.Mesh(sphereGeometry);
sphere.position.x = Math.random() * 500 - 250;
sphere.position.y = Math.random() * 300 - 100;
sphere.position.z = Math.random() * 500 - 250;
scene.add(sphere);
points.push(sphere);
}
// events
window.addEventListener('resize', onWindowResize, false);
}
function onWindowResize(event) {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
function addSpheres() {
//addSpheres
for (i=0;i<200;i++) {
var that = points[i].position.y;
points[i].position.y = ( that < heights[0] ) ? 200 : that - 0.5;
if ( that > heights[0] && that < heights[1] ) points[i].material = materials[0];
if ( that < heights[2] && that > heights[1] ) points[i].material = materials[1];
if ( that > heights[2] ) points[i].material = materials[2];
points[i].material.needsUpdate = true;
}
}
function animate() {
controls.update();
addSpheres();
renderer.render(scene, camera);
requestAnimationFrame(animate);
}
<script src="http://threejs.org/build/three.min.js"></script>
<script src="http://threejs.org/examples/js/controls/OrbitControls.js"></script>
Now, feel free to "group" these points according to your needs.
Please note that "vectors" are different from "points". Read more about the difference.
Raycasting would be the way to go if you had a more complex scene (moving floors/different planes, points moving in different directions).
I'm a social science person increasingly getting into web programming for data vis work so apologies if this question is dumb. I'm working on a polymaps implementation to visualize country level data over time. I reads in json temporal data and a geojson world map and spits out a quantile chloropleth map that iterates over monthly entries. The heart of this is a country formating function that binds a colorbrewer class to the country geojson objects (see below). This works find for the animation portion. The problem is that I am using a custom d3 layer that displays the date of the data currently displayed and acts as a mouseover control to stop the animation and choose a date or to choose a date once the animation is through. It does this by creating an blank svg element that uses the d3.scale() function to round mouse input to an integer that matches the index of the month desired. I've front loaded all the other calculations on load so that the only thing that happens at mouse over is the change of svg class (this is basically the same as Tom Carden's wealth of nations implementation on Bostock's d3 page here). Unfortunately, this still overloads the browser pretty quickly. Is there another way to do this that I'm totally missing? I admit im new to geojson so maybe some way to construct an array of classes with in the class attribute of the geojson object? Thanks a ton of any help.
function foo(local, geojson){
for(var x=0;x<geojson.length;x++){
var n = geojson[x].data.properties.name;
n$(geojson[x].element)
.attr("class", geojson[x].data.formats[local])
.add("svg:title");
}
}
EDIT: I'm adding the full script below.
<meta charset="utf-8">
<script src="scripts/d3.v3.js"></script>
<script src="scripts/polymaps.js"></script>
<script src="scripts/nns.js"></script>
<script>
//Polymaps namespace
var po = org.polymaps;
//Chart dimensions
var margin = {top: 20, right: 20, bottom: 20, left: 20};
var w = 960 - margin.right;
var h = 500 - margin.top - margin.bottom;
// Create the map object, add it to #map div
var map = po.map()
.container(d3.select("#map").append("svg:svg").attr("width", w + margin.left + margin.right).attr("height",h +margin.top + margin.bottom).node())
.center({lat: 28, lon: 0})
.zoom(1.85)
.zoomRange([1.5, 4.5])
.add(po.interact());
// Add the CloudMade image tiles as a base layer…
map.add(po.image()
.url(po.url("http://{S}tile.cloudmade.com"
+ "/1a1b06b230af4efdbb989ea99e9841af" // http://cloudmade.com/register
+ "/20760/256/{Z}/{X}/{Y}.png")
.hosts(["a.", "b.", "c.", ""])));
//Import contribution data
d3.json("assets/contributionsTCC1990-1991.json", function(data){
//find length of json data object and loop over it at interval
var dataLength = Object.keys(data).length;
//Create date key/value array using construtor
function date_array_constructor() {
var dateArray = {};
for(var i = 0; i < dataLength; i++) {
var d = i + 1;
dateArray[d] = data[i].date;
}
return dateArray;
}
var dateArray = date_array_constructor();
// Insert date label/control layer and add SVG elements that take on attributes determined by load function
var labelLayer = d3.select("#map svg").insert("svg:g");
map.add(po.geoJson()
.url("assets/world.json")
.tile(false)
.zoom(3)
.on("load", load));
map.container().setAttribute("class", "Blues");
map.add(po.compass()
.pan("none"));
function find_max(data, dataLength) {
var max = 0;
for(var i in data) {
if(data[i] > max) {
max = data[i] + 1;
}
}
return max;
}
function max_array_constructor(data, dataLength) {
var maxArray = {};
for(var i=0;i<dataLength;i++) {
var d = i+1;
maxArray[d] = find_max(data[i].contributions);
}
return maxArray;
}
var maxArray = max_array_constructor(data, dataLength);
function contribution_array_constructor(data, dataLength, tccName, feature) {
var contributions = {};
//iterate over date entries
for(var i=0;i<dataLength;i++) {
//contribution iterator
contributions[i+1] = 0;
for(x in data[i].contributions){
if(x == tccName) {
contributions[i+1] = data[i].contributions[x];
}
}
}
return contributions;
}
function format_array_constructor(data, dataLength, maxArray, feature) {
var formats = {};
// console.log(feature.data.contributions);
//iterate over date entries
for(var i=0;i<dataLength;i++) {
var percentile = feature.data.contributions[i+1] / maxArray[i+1];
if(percentile != 0){
var v = "q" + ((~~(percentile*7)) + 2) + "-" + 9;
}else{
var v = "countries";
}
formats[i+1] = v;
}
return formats;
}
///////////////////////////////
//load function
///////////////////////////////
function load(e) {
//Bind geojson and json
var geojson = e.features;
console.log(geojson);
geojson.dates = dateArray;
for(var x = 0; x < geojson.length; x++) {
// var tccID = geojson[x].data.id;
var tccName = geojson[x].data.properties.name;
geojson[x].data.contributions = contribution_array_constructor(data, dataLength, tccName, geojson[x]);
geojson[x].data.formats = format_array_constructor(data, dataLength, maxArray, geojson[x]);
}
//Insert date label
var dateLabel = labelLayer.append("text")
.attr("class", "date label")
.attr("text-anchor", "end")
.attr("x", w-670)
.attr("y", h )
.text(dateArray[1]);
//Add interactive overlay for date label
var box = dateLabel.node().getBBox();
var overlay = labelLayer.append("rect")
.attr("class", "overlay")
.attr("x", box.x)
.attr("y", box.y)
.attr("opacity",0)
.attr("width", box.width)
.attr("height", box.height)
.on("mouseover",enable_interaction);
function country_class_constructor(local, geojson){
for(var x=0;x<geojson.length;x++){
var n = geojson[x].data.properties.name;
n$(geojson[x].element)
.attr("class", geojson[x].data.formats[local])
.add("svg:title");
}
}
function foo(local, geojson){
for(var x=0;x<geojson.length;x++){
var n = geojson[x].data.properties.name;
n$(geojson[x].element)
.attr("class", geojson[x].data.formats[local])
.add("svg:title");
}
}
//incrementor function
function incrementor(local, geojson, dateArray) {
setTimeout(function() {
//set date label to current iteration
d3.transition(dateLabel).text(dateArray[local]);
//construct country classes
country_class_constructor(local, geojson);
// console.log(geojson);
}, 500*local);
}
///////////////////////////////
//Increment on load
///////////////////////////////
country_class_constructor(1, geojson)
for(var i=1; i< dataLength; i++) {
//Set incrementer as local variable
var local = i+1;
var timer = incrementor(local, geojson, dateArray);
}
///////////////////////////////
//interaction element
///////////////////////////////
function enable_interaction(){
var dateScale = d3.scale.linear()
.domain([1,Object.keys(dateArray).length])
.range([box.x + 10, box.x + box.width - 10])
.clamp(true);
timer = null;
overlay
.on("mouseover", mouse_over)
.on("mouseout",mouse_out)
.on("mousemove",mouse_move)
.on("touchmove",mouse_move);
function mouse_over() {
dateLabel.classed("active", true);
}
function mouse_out() {
dateLabel.classed("active", false);
}
function mouse_move() {
update_map(dateScale.invert(d3.mouse(this)[0]),data);
// displayYear(dateScale.invert(d3.mouse(this)[0]));
}
function update_map(userInput) {
var date = Math.floor(userInput);
d3.transition(dateLabel).text(dateArray[date]);
// console.log(date);
// country_class_constructor(date, geojson);
foo(date, geojson);
}
}
}
});
</script>
Edit 2: I forgot to add the JSON format. See below for two months of data:
[
{"date":"11/90",
"contributions":{
"Algeria":7,
"Argentina":39,
"Australia":41,
"Austria":967,
"Bangladesh":5,
"Belgium":4,
"Brazil":27,
"Canada":1002,
"Chile":7,
"China":5,
"Colombia":12,
"Czech Republic":6,
"Denmark":374,
"Ecuador":21,
"Fiji":719,
"Finland":992,
"France":525,
"Germany":13,
"Ghana":892,
"Hungary":15,
"India":40,
"Indonesia":5,
"Ireland":814,
"Italy":79,
"Jordan":6,
"Kenya":7,
"Malaysia":15,
"Nepal":851,
"Netherlands":15,
"New Zealand":22,
"Nigeria":2,
"Norway":924,
"Poland":165,
"Republic of the Congo":6,
"Russia":35,
"Senegal":4,
"Serbia":17,
"Spain":63,
"Sweden":738,
"Switzerland":5,
"Turkey":2,
"United Kingdom":769,
"United States":33,
"Uruguay":10,
"Venezuela":23,
"Zambia":6
}
},
{"date":"12/90",
"contributions":{
"Algeria":7,
"Argentina":39,
"Australia":41,
"Austria":967,
"Bangladesh":5,
"Belgium":4,
"Brazil":27,
"Canada":1002,
"Chile":7,
"China":5,
"Colombia":12,
"Czech Republic":6,
"Denmark":374,
"Ecuador":21,
"Fiji":719,
"Finland":992,
"France":525,
"Germany":13,
"Ghana":892,
"Hungary":15,
"India":40,
"Indonesia":5,
"Ireland":814,
"Italy":79,
"Jordan":6,
"Kenya":7,
"Malaysia":15,
"Nepal":851,
"Netherlands":15,
"New Zealand":22,
"Nigeria":2,
"Norway":924,
"Poland":165,
"Republic of the Congo":6,
"Russia":35,
"Senegal":4,
"Serbia":17,
"Spain":63,
"Sweden":738,
"Switzerland":5,
"Turkey":2,
"United Kingdom":769,
"United States":33,
"Uruguay":10,
"Venezuela":23,
"Zambia":6
}
}
]
After hours of debugging, it turns out that the nns.js library was causing me problems. Each iteration of the animation was creating a new set of DOM objects which started to max out the browser at 25,000. The solution was to use nss to create the initial state and then using the following function to change the class of each svg element.
function country_class_constructor(local, geojson){
for(var x=0;x<geojson.length;x++){
var n = geojson[x].data.properties.name;
element = document.getElementById(n);
element.className["animVal"] = geojson[x].data.formats[local];
element.className["baseVal"] = geojson[x].data.formats[local];
}
I haven't been able to make a character selection in ActionScript 2 so what is an example that, if I click on this button, a movieclip comes out in this frame?
Frame 1:
movieClip1.alpha = 0;
movieClip1.stop();
movieClip2.alpha = 0;
movieClip2.stop();
movieClip3.alpha = 0;
movieClip3.stop();
button1.onPress = function() {
movieClip1.alpha = 100;
movieClip1.play();
}
button2.onPress = function() {
movieClip2.alpha = 100;
movieClip2.play();
}
button3.onPress = function() {
movieClip3.alpha = 100;
movieClip3.play();
}
try something like the below. I haven;t tested this so it prob won;t compile but it'll be very close. Basically put this on a single empty frame on the main timeline. make sure you have button and character movieclips all with export settings and linkage identifiers set. Modify code below and see what happens.
var numButtons:Number = 10; //number of buttons you want
var buttonMovieClipName:String = "button"; //linkage identifier of button
var startX:Number = 10; //start x position
var startY:Number = 500; //start y position
var dist:Number = 10; //distance between buttons
var characters:Array = {"A","B","C","D"}; //linkage names of your characters
var currentChar:MovieClip = null;
for(var i:Number = 0; i < numButtons; i++)
{
this.attachMovie("button", "button"+i, this.getNextHighestDepth());
this["button"+i]._x = startX + (i*(dist+this["button"+i]._width]));
this["button"+i]._y = startY;
this["button"+i].character = characters[i];
this["button"+i].onPress = displayCharacter;
}
function displayCharacter():void
{
var par = this._parent;
//remove previous character on stage
if(currentChar != null)
{
removeMovieClip(par[currentChar]);
}
par.attachMovie(this.character, this.character, par.getNextHighestDepth()); //atach character
par[this.character]._x = 400; //set to whatever
par[this.character]._y = 300; //set to whatever
currentChar = this.character; //set current character to this
}
In ActionScript I have string as
str="subject,r1,r2:a,b:1,2:3,4";
dynamically i have split this string and build array collection as given below
arraycoll.addItem({subject:a ,r1:1,r2:3});
this example of one set
the arraycollection should be built dynamic i have tried but not successful
var str:String ="subject,r1,r2:a,b:1,2:3,4";
var parts:Array = str.split(":");
var props:Array = parts[0].split(",");
var count:Number = parts[1].split(",").length;
var items:Array = [];
var values:Array = [];
var i:Number, j:Number;
for(i = 0; i < props.length; i++)
values.push(parts[i + 1].split(","));
for(i = 0; i < count; i++)
{
items.push({});
for(var j = 0; j < props.length; j++)
{
items[i][props[j]] = values[j][i];
}
}
var arCol:ArrayCollection = new ArrayCollection(items);