I want to render volume(X.volume()) and cube(X.cube()) on one scene. For testing I use your volume files from lessons.
Case 1:
var r = new X.renderer3D();
r.init();
var volume = new X.volume();
volume.center = [0, 0, 0];
volume.file = 'http://x.babymri.org/?avf.nrrd';
var cube = new X.cube();
cube.lengthX = cube.lengthY = cube.lengthZ = 20;
cube.center = [0, 0, 0];
cube.color = [1, 1, 1];
r.add(volume);
r.add(cube);
r.render();
This case works fine, as expected:case 1.
Case 2:
var r = new X.renderer3D();
r.init();
var volume = new X.volume();
volume.center = [0, 0, 0];
volume.file = 'http://x.babymri.org/?vol.nrrd';
var cube = new X.cube();
cube.lengthX = cube.lengthY = cube.lengthZ = 20;
cube.center = [0, 0, 0];
cube.color = [1, 1, 1];
r.add(volume);
r.add(cube);
r.render();
This case works unexpected, cube center is shifted: case 2.
What is the difference of this two files?
As far as I remember, 'center' is not actually used for the volume.
The volume is displayed in the 'ANATOMICAL COORDINATE SYSTEM'.
http://www.slicer.org/slicerWiki/index.php/Coordinate_systems#Anatomical_coordinate_system
Practically, it means that avf.nrrd was actually centered on 0-0-0 when the data was acquired, whereas vol.nrrd was not.
Calling 'center' on the volume has NO effect.
As for now, the best workaround it to display the cube in the volume's center directly.
Related
The figure font size doubled unexpectedly between knits. Restarting R did not fix the issue. I ended up decreasing font size by 50% to fix the problem. Has this happened to anyone else? My theme is shown below.
style <- theme(plot.title = element_text(face = "bold", size = 30),
plot.subtitle = element_text(size = 30),
axis.title = element_text(size = 25, face="italic"),
axis.text = element_text(size = 25),
legend.text = element_text(size = 25),
legend.title = element_text(face = "bold", size = 25),
legend.position = "bottom",
panel.background = element_rect(fill = NA),
panel.grid.major = element_line(colour = "grey88"),
axis.ticks = element_line(color=NA),
axis.title.y = element_text(margin = margin(t = 0, r = 20, b = 0, l = 0)),
axis.title.x = element_text(margin = margin(t = 20, r = 0, b = 0, l = 0)))
If it changes between knits, maybe you were zoomed in on your web browser and didn't know it. it also might depend on your knit R chunks. if you can't replicate the issue, it might just be a random issue.
Hy I have made an AIR application that uses the flash.desktop.NativeProcess to start an c++ a* pathsolver. The reason being - Flash needs too much time to solve 250 * 250 open grid.
The AIR app is fine. It can start the c++ exe file
The exe fine works on its own
The problem is. They don't work in pair :(
When flash sends the arguments the c++ part just dies silently
char buf[ 256 ]; std::cin.getline( buf, 256 );
I just havent mannaged to find wat is going on. If i use arguments insted of standard imput i get some strange characters. Any idea ?
Well then. You will find the working (furthermore, working fast) wave pathfinding demo below. There are two test cases:
32x32 predesigned dungeon, loops 256 times, runs 0.12s - 0.13s
320x320 big, empty, entrance and exit are at opposite corners, runs 0.03s - 0.04s
So, the problem with the tutorials and algorithms that they are ideal for clean small tutorial cases. When there are a lot of data, well, not so much. If you'd followed that tutorial, it leaves you with that Node class of getters and setters. Each time you refer a getter or setter, you invoke a function call, which is a relatively heavy operation. One time, ten times, hundred times - no problem, but there you have 64K of those nodes, that builds the performance momentum. Even if you didn't go for getter/setter picture, there are still a lot of node instances, you pull their properties... you get the picture, right?
When I first did that wave pathfinding in 2009, I too did blunder into the mess of node instances and their properties. Then 2-dimensional array of ints, no good. Then I thought of BitmapData class which could quite literally represent the map and hold 32 bits of data per cell/pixel. Every one idea turned out to still be too slow.
I might've possibly thought of 1-dimensional representation faster, but the thing is, I worked with hexagonal map so each cell had 6 ways out, not just 4, a bit confusing.
Yet, in the end, I came up with the whole idea of mapping the area into 1-dimensional array and navigating it with +1, -1, +width and -width shifts (well, 2 more for hexagonal topography). I had no need of complicated things back then (and I don't think you need them either) like path weights, just to find the shortest path in an UX-acceptable time frame.
If you look at the algorithms pathfinding part, it's so simple. No x and y coordinates. No border checks. No node objects, no properties, no additional function calls. Just the simplest math and a few operations per each cell - as few as it possible. That's why it is so fast and efficient.
The mentioned Log class, you can grab it at my repo.
package
{
import flash.utils.getTimer;
import flash.display.Sprite;
import ru.delimiter.utils.Log;
/**
* ...
* #author Dmitry Yamaykin
*/
public class PathFinding extends Sprite
{
public function PathFinding()
{
super();
// Log is a debug output panel which allows you
// to see things if traces are unavailable
// or/and suppressed by the release build.
Log.create(this, true);
Log.log("[PathFinding] starts!");
testBig();
testSmall();
}
// The main data array that keeps obstacles,
// empty cells and those already passed by the wave.
private var map:Vector.<int> = new Vector.<int>;
// The front of the wave and the next front.
private var wave:Vector.<int> = new Vector.<int>;
private var froth:Vector.<int> = new Vector.<int>;
// Mapping the map back to the original data. Just for
// this demo, you probably won't need it with the real thing.
private var route:Vector.<int> = new Vector.<int>;
// Be extra careful with the 'w' argument, if you fumble with
// the width of the row, the whole thing will totally go astray.
private function findPath(source:Array, w:int, h:int):Array
{
var length:int = source.length;
var begin:int;
var end:int;
var i:int;
var steps:int;
var windex:int;
var findex:int;
var mindex:int;
map.fixed = false;
wave.fixed = false;
froth.fixed = false;
route.fixed = false;
// The brilliance of it: working with just a few instances
// that are set up in the very beginning and fixed to a
// certain amount of memory. No memory management while
// finding paths, no creating and disposing of instances,
// no Garbage Collector to kick in and do its thing.
map.length = length;
wave.length = w + h;
froth.length = w + h;
route.length = length;
map.fixed = true;
wave.fixed = true;
froth.fixed = true;
route.fixed = true;
// The main idea behind fast wave is mapping the source
// 2-dimensional data into 1-dimensional array of int
// values. Your position is indicated by a single
// index, +1 is 'go right', -1 is 'go left',
// +width and -width are 'go down' and 'go up' respectively.
// Just don't forget to add a solid impassable top and bottom
// lines (to avoid 'out of range' array errors) and a solid
// wall at the right (at least) so you don't flip over the
// data while going right from the rightmost position
// and left from the leftmost. It's far more efficient this
// way than additional code checks for borders.
for (i = 0; i < length; i++)
{
switch (source[i])
{
case '.':
map[mindex] = 0;
route[mindex] = i;
mindex++;
break;
case '#':
map[mindex] = -1;
route[mindex] = i;
mindex++;
break;
case 'X':
map[mindex] = -1;
route[mindex] = i;
end = mindex;
mindex++;
break;
case 'Y':
// We need it to be passable
// for wave to wash in there.
map[mindex] = 0;
route[mindex] = i;
begin = mindex;
mindex++;
break;
}
}
// Be careful with logging. It duplicates the output to the
// standard trace, which includes writing to a file
// (Flash thing, not my fault) which is really,
// like REALLY slow operation to do.
// Log.log(begin, '>', end);
// With just fixed [1, -1, w, -w] it will work a bit faster,
// bit the algorithm will prefer going in the straight lines,
// rather than wandering in diagonals and cutting the corners.
var AWX:int = 0;
var AWAY:Array;
var WAYS:Array =
[
[1, -1, w, -w],
[w, -w, 1, -1],
[-1, w, 1, -w],
[-w, 1, w, -1],
[1, -1, -w, w],
[w, -w, -1, 1],
[-1, 1, -w, w],
[w, -w, -1, 1],
[1, w, -1, -w],
[w, -1, -w, 1],
[-1, 1, w, -w],
[-w, w, 1, -1],
[1, -w, -1, w],
[w, 1, -w, -1],
[-1, -w, 1, w],
[w, -1, -w, 1],
];
// Lets the party begin.
wave[0] = end;
windex = 1;
// Repeat while wave front is not empty.
while (windex)
{
// Pick the next pattern of motion preferences.
if (--AWX < 0) AWX = WAYS.length - 1;
AWAY = WAYS[AWX];
// Go through all the points on the current wave front.
while (windex--)
{
var anindex:int = wave[windex];
// Try to move into the all
// possible directions from it.
for each (var ashift:int in AWAY)
{
// This value will be used a few times
// so it's better to calculate it once and store.
var awindex:int = anindex + ashift;
// Either -1 (impassable) or 1+
// (wave's been here already) means
// this spot is of no interest to us.
if (map[awindex]) continue;
// The 'path is found' routine.
if (awindex == begin)
{
// Log.log("THE WAY");
// The following code is just a dummy demo.
var result:Array = source.slice();
while (anindex != end)
{
result[route[anindex]] = '*';
anindex = map[anindex];
}
return result;
/**
* The main idea behind the result code
* is to unwind the calculated path,
* which is pretty easy because each
* affected map cell contains
* the index of the previous
* cell all the way back
* to the center of
* the wave.
*
result = [begin];
while (anindex != end)
{
result.push(anindex);
anindex = map[anindex];
}
result.push(end);
*
**/
}
// Add the empty cell to the
// next front line of the wave.
map[awindex] = anindex;
froth[findex++] = awindex;
}
}
// The next front line is formed,
// time to move on to the next iteration.
var xchange:Vector.<int> = froth;
var xindex:int = findex;
froth = wave;
findex = 0;
wave = xchange;
windex = xindex;
//Log.log(windex, wave);
}
// If we're here, that means the wave started
// at the 'end' point never hit the 'begin'.
trace("NO WAY");
return null;
}
// Tests pathfinding in a smaller dungeon: a multiple times.
private function testSmall():void
{
var X:XML = <root><![CDATA[
##################################
#.............#................#Y#
#.....#.......#.......#........#.#
#.....#.......#.......#........#.#
#.....#.......#.......#........#.#
#.....#.......#.......#........#.#
#.....#.......#.......#........#.#
#.....#.......#.......#........#.#
#.....#.......#.......#........#.#
#.....#.......#.......#........#.#
#.....#...............#..........#
#.....############################
#................................#
#................................#
#................................#
#................................#
#######..........................#
#................................#
#...####.........................#
#................................#
#................................#
#................................#
#................................#
#................................#
#................................#
#................................#
##################...............#
#................#...............#
#................#...............#
#...######.......#...............#
#........#.......#...............#
#........#.......#...............#
#........#.......#...............#
#X.......#.......................#
##################################
]]></root>;
var D:String = X.children()[0].toString().split("\r").join("");
var A:Array = D.split("");
var aTime:int = getTimer();
var R:Array;
for (var i:int = 255; i >= 0; i--)
{
R = findPath(A, 34, 34);
}
Log.log("");
Log.log("32 x 32, pre-designed, not empty, 256 times.");
Log.log("Elapsed", getTimer() - aTime, "ms.");
if (R) Log.log(R.join(""));
}
// Tests pathfinding in a big empty dungeon.
private function testBig():void
{
var D:String = "";
// Lets form a biiig empty field with
// entrance and exit at the opposite corners.
var TB:String = G("#", 322);
var TX:String = "#" + G(".", 319) + "X#";
var TY:String = "#Y" + G(".", 319) + "#";
var TE:String = "#" + G(".", 320) + "#";
D += TB;
D += TX;
for (var i:int = 0; i < 318; i++)
{
D += TE;
}
D += TY;
D += TB;
var A:Array = D.split("");
var aTime:int = getTimer();
var R:Array = findPath(A, 320, 320);
Log.log("");
Log.log("320 x 320, empty.");
Log.log("Elapsed", getTimer() - aTime, "ms.");
}
private function G(char:String, repeat:int):String
{
var result:String = char;
while (result.length < repeat)
{
result += result;
}
result = result.substr(0, repeat);
return result;
}
}
}
Ugly hack, but does the job :D
var f = File.documentsDirectory.resolvePath("command.txt");
var stream = new FileStream();
stream.open(f, FileMode.WRITE);
stream.writeUTFBytes(nextQuery.command + "/" + nextQuery.data);
stream.close();
You can guess the c++ side
std::stringstream strmap;
strmap << my_documents << "/command.txt" ;
std::ifstream myfile (strmap.str().c_str());
I call it the
black market algorytm
I have a list of buttons(currently images) and i want to change the image color depending on the value that is taken from the list
buttons = {"btn1","btn2","btn3","btn4"}
local buttonSheetData = {
width = 150,
height = 150,
numFrames = 2,
sheetContentWidth = 300,
sheetcontentheight = 150,
}
local buttonSheet = graphics.newImageSheet("image/buttonSS.png", buttonSheetData)
local sequenceData = {
{name = "black", start = 1, count = 1},
{name = "red", start = 2, count = 1}
}
local btn1 = display.newSprite(buttonSheet, sequenceData)
btn1.x = 100
btn1.y = 90
local btn2 = display.newSprite(buttonSheet, sequenceData)
btn2.x = 200
btn2.y = 230
local btn3 = display.newSprite(buttonSheet, sequenceData)
btn3.x = 300
btn3.y = 90
local btn4 = display.newSprite(buttonSheet, sequenceData)
btn4.x = 400
btn4.y = 230
x = buttons[math.random(#buttons)]
x:setFrame(2)
The circles are currently black. every time i run the code i want it to take a random value from the list and change the color to red. so there is a different red circle when i run the code
I keep getting the error:
"Attemp to call method 'setSequence' (a nill value)"
You're code is treating strings and variable names as if they are interchangeable. The first line:
buttons = {"btn1","btn2","btn3","btn4"}
creates a table of strings, so the line:
x = buttons[math.random(#buttons)]
will set x to be a random entry of buttons which are strings so the next line (x:setFrame(2)) is calling a method that doesn't exist on a string.
Instead, create a table of your buttons:
buttons = {btn1,btn2,btn3,btn4} -- creates a table of buttons
x = buttons[math.random(#buttons)] -- x is a random entry of buttons (a button)
I'm attempting to create a btBvhTriangleMeshShape out of a large mesh in my application and use it as a Rigid Body. This Rigid Body will make up the 'ground plane' which is static and never moves. The problem is everything falls straight through like it's not even there. Here's the current source:
btTriangleMesh* tMesh = new btTriangleMesh();
irr::scene::IMeshBuffer* MB = WorldNode1->getMesh()->getMeshBuffer(1);
irr::video::S3DVertex* Vertices = (irr::video::S3DVertex*)MB->getVertices();
irr::u16* Indices = MB->getIndices();
for (irr::u32 i = 0; i < MB->getIndexCount(); i+=3)
{
irr::core::vector3df Tri1Pos = Vertices[Indices[i]].Pos;
irr::core::vector3df Tri2Pos = Vertices[Indices[i+1]].Pos;
irr::core::vector3df Tri3Pos = Vertices[Indices[i+2]].Pos;
tMesh->addTriangle(btVector3(Tri1Pos.X, Tri1Pos.Y, Tri1Pos.Z), btVector3(Tri2Pos.X, Tri2Pos.Y, Tri2Pos.Z), btVector3(Tri3Pos.X, Tri3Pos.Y, Tri3Pos.Z));
}
btCollisionShape* groundShape = new btBvhTriangleMeshShape(tMesh, false);
btDefaultMotionState* groundMotionState = new btDefaultMotionState(btTransform(btQuaternion(0, 0, 0, 1), btVector3(0, -1, 0)));
PH->CreateRigidBody(0, groundMotionState, groundShape);
PH->CreateRigidBody() is just a helper function to quickly create rigid bodies, I know this function works properly since other objects use it and collide just fine.
Any insight into the issue here would be greatly appreciated. Thank you all very much for your time.
EDIT:
After hooking up the debug drawer here is what it displays (this is a shot from under the mesh):
And for clarification here is an above shot:
I don't know if it's an issue with the mesh itself or with the code that iterates through the vertices to create the physics mesh
When iterating through the triangles provided via the Irrlicht Mesh Buffer I needed to iterate through ALL the mesh buffers present on the model like so:
btTriangleMesh* tMesh = new btTriangleMesh();
irr::u32 MBCount = WorldMesh1->getMeshBufferCount();
for (irr::u32 m = 0; m < MBCount; m++)
{
irr::scene::IMeshBuffer* MB = WorldNode1->getMesh()->getMeshBuffer(m);
irr::video::S3DVertex* Vertices = (irr::video::S3DVertex*)MB->getVertices();
irr::u16* Indices = MB->getIndices();
for (irr::u32 i = 0; i < MB->getIndexCount(); i += 3)
{
irr::core::vector3df Tri1Pos = Vertices[Indices[i]].Pos;
irr::core::vector3df Tri2Pos = Vertices[Indices[i + 1]].Pos;
irr::core::vector3df Tri3Pos = Vertices[Indices[i + 2]].Pos;
tMesh->addTriangle(btVector3(Tri1Pos.X, Tri1Pos.Y, Tri1Pos.Z), btVector3(Tri2Pos.X, Tri2Pos.Y, Tri2Pos.Z), btVector3(Tri3Pos.X, Tri3Pos.Y, Tri3Pos.Z));
}
}
I would like to get the coordinates of a mouse event in Raphael's paper coordinates. I would like those to be accurate even when I have used setViewBox.
Please see http://jsfiddle.net/CEnBN/
The following creates a 10x10 green box and then zooms way in - with the center of that box at the view's origin.
var paper = Raphael(10, 50, 320, 200);
var rect = paper.rect(0, 0, 10, 10);
rect.attr('fill', 'green');
rect.mousedown(function (event, a, b) {
$('#here').text([a, b]);
console.log(event);
});
paper.setViewBox(5, 5, 10, 10);
I would like to receive click coordinates that reflect their position in the box. ie. they should range from ([5-10], [5-10]).
Note: much later, and I have migrated to D3.js - which has generally made me a lot happier.
Edited: simplified by using clientX/Y of the mouse event - remove need to get element offset
Here is what I came up with. Basically, correct the mouse position to be relative to the paper by using the client rect of the paper and clientX/Y of the mouse event. Then compare the corrected positions to the client rect's width/height, then factor the results by original paper dimensions:
var paper = Raphael(10, 50, 320, 200);
var rect = paper.rect(0, 0, 10, 10);
rect.attr('fill', 'green');
rect.mousedown(function (event, a, b) {
// get bounding rect of the paper
var bnds = event.target.getBoundingClientRect();
// adjust mouse x/y
var mx = event.clientX - bnds.left;
var my = event.clientY - bnds.top;
// divide x/y by the bounding w/h to get location %s and apply factor by actual paper w/h
var fx = mx/bnds.width * rect.attrs.width
var fy = my/bnds.height * rect.attrs.height
// cleanup output
fx = Number(fx).toPrecision(3);
fy = Number(fy).toPrecision(3);
$('#here').text('x: ' + fx + ', y: ' + fy);
});
paper.setViewBox(5, 5, 10, 10);
An updated fiddle link is here:
http://jsfiddle.net/CEnBN/3/
more compact version of mouse down func:
rect.mousedown(function (event, a, b) {
var bnds = event.target.getBoundingClientRect();
var fx = (event.clientX - bnds.left)/bnds.width * rect.attrs.width
var fy = (event.clientY - bnds.top)/bnds.height * rect.attrs.height
$('#here').text('x: ' + fx + ', y: ' + fy);
});
You need to offset the result, something like this:
var posx, posy;
var paper = Raphael("canvas", 320, 200);
var rect = paper.rect(0, 0, 10, 10);
rect.attr('fill', 'green');
rect.mousedown(function (e, a, b) {
posx = e.pageX - $(document).scrollLeft() - $('#canvas').offset().left;
posy = e.pageY - $(document).scrollTop() - $('#canvas').offset().top;
$('#here').text([posx, posy]);
console.log(e);
});
paper.setViewBox(5, 5, 10, 10);
I added an element for Raphaeljs to target, have a look at this update to your jsfiddle
The answer by gthmb is very good, but missing a detail - the position of the rectangle on the paper. This version is only working, if the rectangle is at position (0,0). To support also the situation where it is translated, add the position of the rectangle to the result:
function mouseEvent_handler(e) {
var bnds = event.target.getBoundingClientRect();
var bbox = this.getBBox();
var fx = (event.clientX - bnds.left)/bnds.width * rect.attrs.width + bbox.x;
var fy = (event.clientY - bnds.top)/bnds.height * rect.attrs.height + bbox.y;
$('#here').text('x: ' + fx + ', y: ' + fy);
}
Here the modified version of the fiddle: http://jsfiddle.net/zJu8b/1/