Related
I am trying to trace quadratic bezier curves, placing "markers" at a given step length distance. Tried to do it a naive way:
const p = toPoint(map, points[section + 1]);
const p2 = toPoint(map, points[section]);
const {x: cx, y: cy} = toPoint(map, cp);
const ll1 = toLatLng(map, p),
ll2 = toLatLng(map, p2),
llc = toLatLng(map, { x: cx, y: cy });
const lineLength = quadraticBezierLength(
ll1.lat,
ll1.lng,
llc.lat,
llc.lng,
ll2.lat,
ll2.lng
);
for (let index = 0; index < Math.floor(lineLength / distance); index++) {
const t = distance / lineLength;
const markerPoint = getQuadraticPoint(
t * index,
p.x,
p.y,
cx,
cy,
p2.x,
p2.y
);
const markerLatLng = toLatLng(map, markerPoint);
markers.push(markerLatLng);
}
This approach does not work since the correlation of a quadratic curve between t and L is not linear. I could not find a formula, that would give me a good approximation, so looking at solving this problem using numeric methods [Newton]. One simple option that I am considering is to split the curve into x [for instance 10] times more pieces than needed. After that, using the same quadraticBezierLength() function calculate the distance to each of those points. After this, chose the point so that the length is closest to the distance * index.
This however would be a huge overkill in terms of algorithm complexity. I could probably start comparing points for index + 1 from the subset after/without the point I selected already, thus skipping the beginning of the set. This would lower the complexity some, yet still very inefficient.
Any ideas and/or suggestions?
Ideally, I want a function that would take d - distance along the curve, p0, cp, p1 - three points defining a quadratic bezier curve and return an array of coordinates, implemented with the least complexity possible.
OK I found analytic formula for 2D quadratic bezier curve in here:
Calculate the length of a segment of a quadratic bezier
So the idea is simply binary search the parameter t until analytically obtained arclength matches wanted length...
C++ code:
//---------------------------------------------------------------------------
float x0,x1,x2,y0,y1,y2; // control points
float ax[3],ay[3]; // coefficients
//---------------------------------------------------------------------------
void get_xy(float &x,float &y,float t) // get point on curve from parameter t=<0,1>
{
float tt=t*t;
x=ax[0]+(ax[1]*t)+(ax[2]*tt);
y=ay[0]+(ay[1]*t)+(ay[2]*tt);
}
//---------------------------------------------------------------------------
float get_l_naive(float t) // get arclength from parameter t=<0,1>
{
// naive iteration
float x0,x1,y0,y1,dx,dy,l=0.0,dt=0.001;
get_xy(x1,y1,t);
for (int e=1;e;)
{
t-=dt; if (t<0.0){ e=0; t=0.0; }
x0=x1; y0=y1; get_xy(x1,y1,t);
dx=x1-x0; dy=y1-y0;
l+=sqrt((dx*dx)+(dy*dy));
}
return l;
}
//---------------------------------------------------------------------------
float get_l(float t) // get arclength from parameter t=<0,1>
{
// analytic fomula from: https://stackoverflow.com/a/11857788/2521214
float ax,ay,bx,by,A,B,C,b,c,u,k,cu,cb;
ax=x0-x1-x1+x2;
ay=y0-y1-y1+y2;
bx=x1+x1-x0-x0;
by=y1+y1-y0-y0;
A=4.0*((ax*ax)+(ay*ay));
B=4.0*((ax*bx)+(ay*by));
C= (bx*bx)+(by*by);
b=B/(2.0*A);
c=C/A;
u=t+b;
k=c-(b*b);
cu=sqrt((u*u)+k);
cb=sqrt((b*b)+k);
return 0.5*sqrt(A)*((u*cu)-(b*cb)+(k*log(fabs((u+cu))/(b+cb))));
}
//---------------------------------------------------------------------------
float get_t(float l0) // get parameter t=<0,1> from arclength
{
float t0,t,dt,l;
for (t=0.0,dt=0.5;dt>1e-10;dt*=0.5)
{
t0=t; t+=dt;
l=get_l(t);
if (l>l0) t=t0;
}
return t;
}
//---------------------------------------------------------------------------
void set_coef() // compute coefficients from control points
{
ax[0]= ( x0);
ax[1]= +(2.0*x1)-(2.0*x0);
ax[2]=( x2)-(2.0*x1)+( x0);
ay[0]= ( y0);
ay[1]= +(2.0*y1)-(2.0*y0);
ay[2]=( y2)-(2.0*y1)+( y0);
}
//---------------------------------------------------------------------------
Usage:
set control points x0,y0,...
then you can use t=get_t(wanted_arclength) freely
In case you want to use get_t_naive and or get_xy you have to call set_coef first
In case you want to tweak speed/accuracy you can play with the target accuracy of binsearch currently set to1e-10
Here optimized (merged get_l,get_t functions) version:
//---------------------------------------------------------------------------
float get_t(float l0) // get parameter t=<0,1> from arclength
{
float t0,t,dt,l;
float ax,ay,bx,by,A,B,C,b,c,u,k,cu,cb,cA;
// precompute get_l(t) constants
ax=x0-x1-x1+x2;
ay=y0-y1-y1+y2;
bx=x1+x1-x0-x0;
by=y1+y1-y0-y0;
A=4.0*((ax*ax)+(ay*ay));
B=4.0*((ax*bx)+(ay*by));
C= (bx*bx)+(by*by);
b=B/(2.0*A);
c=C/A;
k=c-(b*b);
cb=sqrt((b*b)+k);
cA=0.5*sqrt(A);
// bin search t so get_l == l0
for (t=0.0,dt=0.5;dt>1e-10;dt*=0.5)
{
t0=t; t+=dt;
// l=get_l(t);
u=t+b; cu=sqrt((u*u)+k);
l=cA*((u*cu)-(b*cb)+(k*log(fabs((u+cu))/(b+cb))));
if (l>l0) t=t0;
}
return t;
}
//---------------------------------------------------------------------------
For now, I came up with the below:
for (let index = 0; index < Math.floor(numFloat * times); index++) {
const t = distance / lineLength / times;
const l1 = toLatLng(map, p), lcp = toLatLng(map, new L.Point(cx, cy));
const lutPoint = getQuadraticPoint(
t * index,
p.x,
p.y,
cx,
cy,
p2.x,
p2.y
);
const lutLatLng = toLatLng(map, lutPoint);
const length = quadraticBezierLength(l1.lat, l1.lng, lcp.lat, lcp.lng, lutLatLng.lat, lutLatLng.lng);
lut.push({t: t * index, length});
}
const lut1 = lut.filter(({length}) => !isNaN(length));
console.log('lookup table:', lut1);
for (let index = 0; index < Math.floor(numFloat); index++) {
const t = distance / lineLength;
// find t closest to distance * index
const markerT = lut1.reduce((a, b) => {
return a.t && Math.abs(b.length - distance * index) < Math.abs(a.length - distance * index) ? b.t : a.t || 0;
});
const markerPoint = getQuadraticPoint(
markerT,
p.x,
p.y,
cx,
cy,
p2.x,
p2.y
);
const markerLatLng = toLatLng(map, markerPoint);
}
I think only that my Bezier curve length is not working as I expected.
function quadraticBezierLength(x1, y1, x2, y2, x3, y3) {
let a, b, c, d, e, u, a1, e1, c1, d1, u1, v1x, v1y;
v1x = x2 * 2;
v1y = y2 * 2;
d = x1 - v1x + x3;
d1 = y1 - v1y + y3;
e = v1x - 2 * x1;
e1 = v1y - 2 * y1;
c1 = a = 4 * (d * d + d1 * d1);
c1 += b = 4 * (d * e + d1 * e1);
c1 += c = e * e + e1 * e1;
c1 = 2 * Math.sqrt(c1);
a1 = 2 * a * (u = Math.sqrt(a));
u1 = b / u;
a = 4 * c * a - b * b;
c = 2 * Math.sqrt(c);
return (
(a1 * c1 + u * b * (c1 - c) + a * Math.log((2 * u + u1 + c1) / (u1 + c))) /
(4 * a1)
);
}
I believe that the full curve length is correct, but the partial length that is being calculated for the lookup table is wrong.
If I am right, you want points at equally spaced points in terms of curvilinear abscissa (rather than in terms of constant Euclidean distance, which would be a very different problem).
Computing the curvilinear abscissa s as a function of the curve parameter t is indeed an option, but that leads you to the resolution of the equation s(t) = Sk/n for integer k, where S is the total length (or s(t) = kd if a step is imposed). This is not convenient because s(t) is not available as a simple function and is transcendental.
A better method is to solve the differential equation
dt/ds = 1/(ds/dt) = 1/√(dx/dt)²+(dy/dt)²
using your preferred ODE solver (RK4). This lets you impose your fixed step on s and is computationally efficient.
I have been scratching my head for days understanding how to fully describe a block to insert in DXF. For background I am interested in the rules and behaviour of how to do this, not simply trying to find an existing library.
I can create a block in dxf, lets say this is a simple cube. I can then in the Entities section insert this block.
To do this I enter the coordinates relative to the object coordinate system codes:(10, 20, 30), and the normal vector of the object codes:(210,220,230). There is also a value to rotate about the normal vector code: 50.
So there are two things to do:
Calculate the normal vector for my object
Calculate the object co-ordinates, given the world coordinates for the object.
To calculate the normal vector, I use quaternions to calculate the rotation applied to the world z-axis (0,0,1) if a yaw, pitch, or roll angle is applied (if not, I simply use the world z-axis). I can use the same quaternions to calculate the arbitrary x and y axis using the same rotation for each of the real world x and y axes.
For those looking for more info, this link has a very clear explanation of how to calculate them.
https://danceswithcode.net/engineeringnotes/quaternions/quaternions.html
To help you, this calculator can help confirm if this has been implemented correctly or not by checking the results:
Rotation calculator
Then to calculate the object co-ordinates I simply cross multiply the world coordinate with each of the arbitrary axes/normal axes.
For most scenarios this appears to work. However I am left at a loss for additional rules and requirements which I cannot see documented anywhere:
If only a yaw angle is applied (rotation about z), then the normal is still (0,0,1). We need to apply a rotation about z in the scenario that pitch and roll are zero.
If I alter the pitch, the normal vector can change from a negative y-coordinate to a positive one. This change in slope appears to affect the direction the vector is headed and if positive, requires a rotation about the normal of 180 degrees to correct it.
For some unknown reason when I apply a roll angle, my object is rotated around the normal by 90 degrees, and I need to apply a correction here.
I am struggling to find any more clear direction on this online. Does anyone have any thorough explanations that describe the behaviour above, or any pointer material?
As suggested in another topic, a little matrix calculus can solve this issue.
Shortly, they are mainly two ways to describe the same Euler angles:
Tait-Bryan angles (yaw, pitch, roll) rotations about X, Y, Z axis;
Proper Euler angles (precession, nutation, intrisic rotation) rotations about Z, X, Z axis;
AutoCAD uses the second one to describe a bloc orientation. The combination of precession and nutation provides the OCS transformation matrix and the intrinsic rotation is the rotation value of the block.
A little F# example with 3x3 matrices to describe 3d rotations.
type vector = float list
module Vector =
// Computes the dot product of two vectors
let dotProduct (v1: vector) (v2: vector) = List.map2 (*) v1 v2 |> List.sum
type matrix(rows: vector list) =
// Gets the row vectors
member _.Rows = rows
// Transposes a matrix
member _.Transpose = List.transpose rows |> matrix
// Applies a matrix to a vector
static member (*)(m: matrix, v: vector) =
List.map (Vector.dotProduct v) m.Rows
// Multipies two matrices
static member (*)(m: matrix, q: matrix) =
let trp = q.Transpose
List.map (fun r -> trp * r) m.Rows |> matrix
// Describes a coordinate system data
type CoordinateSystem =
{ WcsToOcs: matrix
Normal: vector
Rotation: float }
// Matrix 3x3
module Matrix3x3 =
// Gets the identity matrix
let identity =
matrix [ [ 1.0; 0.0; 0.0 ]
[ 0.0; 1.0; 0.0 ]
[ 0.0; 0.0; 1.0 ] ]
// Gets the rotation matrix about X axis
let xRotation a =
matrix [ [ 1.0; 0.0; 0.0 ]
[ 0.0; cos a; -sin a ]
[ 0.0; sin a; cos a ] ]
// Gets the rotation matrix about Y axis
let yRotation a =
matrix [ [ cos a; 0.0; sin a ]
[ 0.0; 1.0; 0.0 ]
[ -sin a; 0.0; cos a ] ]
// Gets the rotation matrix about Z axis
let zRotation a =
matrix [ [ cos a; -sin a; 0.0 ]
[ sin a; cos a; 0.0 ]
[ 0.0; 0.0; 1.0 ] ]
// Creates the matrix according to Yaw, Pitch and Roll values
let createFromYawPitchRoll yaw pitch roll =
zRotation yaw * yRotation pitch * xRotation roll
// Gets the coordinate system data from a matrix 3x3
let getCoordinateSystem (mat: matrix) =
match mat.Rows with
| [ [ m00; m01; m02 ]; [ m10; m11; m12 ]; [ m20; m21; m22 ] ] ->
let nutation = acos m22
if abs nutation < 1e-8 then
{ WcsToOcs = identity
Normal = [ 0.0; 0.0; 1.0 ]
Rotation = atan2 m10 m11 }
else
let precession = atan2 m02 -m12
let spin = atan2 m20 m21
let xform =
(zRotation precession * xRotation nutation)
.Transpose
let normal = xform.Rows.Item 2
{ WcsToOcs = xform
Normal = normal
Rotation = spin }
| _ -> invalidArg "mat" "Invalid 3x3 matrix"
// Testing
module test =
let radians x = x * System.Math.PI / 180.0
// Input yaw, pitch, roll angles and WCS point
let yaw = radians 10.0
let pitch = radians 20.0
let roll = radians 30.0
let wcsPoint = [ 8.0; 5.0; 3.0 ]
// Computation of the coordinate system
let ocs =
Matrix3x3.createFromYawPitchRoll yaw pitch roll
|> Matrix3x3.getCoordinateSystem
let ocsPoint = ocs.WcsToOcs * wcsPoint
// Print results
printfn "Normal X (210): %f" (ocs.Normal.Item 0)
printfn "Normal Y (220): %f" (ocs.Normal.Item 1)
printfn "Normal Z (230): %f" (ocs.Normal.Item 2)
printfn "Rotation (50): %f" ocs.Rotation
printfn "OCS point X (10): %f" (ocsPoint.Item 0)
printfn "OCS point Y (20): %f" (ocsPoint.Item 1)
printfn "OCS point Z (30): %f" (ocsPoint.Item 2)
A C# implementation:
using static System.Math;
using static System.Console;
namespace CsharpMatrix3d
{
class Program
{
/// <summary>
/// Console testing
/// </summary>
static void Main()
{
double yaw = D2R(10.0);
double pitch = D2R(20.0);
double roll = D2R(30.0);
var wcsPoint = new Vector(8.0, 5.0, 3.0);
var ocs = ObjectCoordinateSystem.FromYawPitchRoll(yaw, pitch, roll);
var ocsPoint = ocs.WorldToPlane * wcsPoint;
WriteLine($"Normal X (210): {ocs.Normal.X}");
WriteLine($"Normal Y (220): {ocs.Normal.Y}");
WriteLine($"Normal Z (230): {ocs.Normal.Z}");
WriteLine($"Rotation (50): {ocs.Rotation}");
WriteLine($"OCS point X (10): {ocsPoint.X}");
WriteLine($"OCS point Y (20): {ocsPoint.Y}");
WriteLine($"OCS point Z (30): {ocsPoint.Z}");
}
static double D2R(double x) => x * PI / 180.0;
}
/// <summary>
/// Provides properties and method for an object coordinate system
/// </summary>
struct ObjectCoordinateSystem
{
public ObjectCoordinateSystem(Matrix3x3 m)
{
double nutation = Acos(m.Row2.Z);
if (Abs(nutation) < 1e-8)
{
Normal = new Vector(0.0, 0.0, 1.0);
Rotation = Atan2(m.Row1.X, m.Row1.Y);
WorldToPlane = Matrix3x3.Identity;
}
else
{
var precession = Atan2(m.Row0.Z, -m.Row1.Z);
WorldToPlane = (Matrix3x3.ZRotate(precession) * Matrix3x3.XRotate(nutation)).Transpose();
Normal = WorldToPlane.Row2;
Rotation = Atan2(m.Row2.X, m.Row2.Y);
}
}
public Vector Normal { get; }
public Matrix3x3 WorldToPlane { get; }
public double Rotation { get; }
public static ObjectCoordinateSystem FromYawPitchRoll(double yaw, double pitch, double roll) =>
new ObjectCoordinateSystem(
Matrix3x3.ZRotate(yaw) *
Matrix3x3.YRotate(pitch) *
Matrix3x3.XRotate(roll));
}
/// <summary>
/// Provides methods for vector calculus
/// </summary>
struct Vector
{
public Vector(double x, double y, double z)
{ X = x; Y = y; Z = z; }
public double X { get; }
public double Y { get; }
public double Z { get; }
public double DotProduct(Vector v) =>
X * v.X + Y * v.Y + Z * v.Z;
public static Vector operator *(Matrix3x3 m, Vector v) =>
new Vector(m.Row0.DotProduct(v), m.Row1.DotProduct(v), m.Row2.DotProduct(v));
}
/// <summary>
/// Provides methods for matrix calculus
/// </summary>
struct Matrix3x3
{
public Matrix3x3(Vector row0, Vector row1, Vector row2)
{ Row0 = row0; Row1 = row1; Row2 = row2; }
public Vector Row0 { get; }
public Vector Row1 { get; }
public Vector Row2 { get; }
public static Matrix3x3 Identity =>
new Matrix3x3(
new Vector(1.0, 0.0, 0.0),
new Vector(0.0, 1.0, 0.0),
new Vector(0.0, 0.0, 1.0));
public Matrix3x3 Transpose() =>
new Matrix3x3(
new Vector(Row0.X, Row1.X, Row2.X),
new Vector(Row0.Y, Row1.Y, Row2.Y),
new Vector(Row0.Z, Row1.Z, Row2.Z));
public static Matrix3x3 XRotate(double a) =>
new Matrix3x3(
new Vector(1.0, 0.0, 0.0),
new Vector(0.0, Cos(a), -Sin(a)),
new Vector(0.0, Sin(a), Cos(a)));
public static Matrix3x3 YRotate(double a) =>
new Matrix3x3(
new Vector(Cos(a), 0.0, Sin(a)),
new Vector(0.0, 1.0, 0.0),
new Vector(-Sin(a), 0.0, Cos(a)));
public static Matrix3x3 ZRotate(double a) =>
new Matrix3x3(
new Vector(Cos(a), -Sin(a), 0.0),
new Vector(Sin(a), Cos(a), 0.0),
new Vector(0.0, 0.0, 1.0));
public static Matrix3x3 operator *(Matrix3x3 a, Matrix3x3 b)
{
var trp = b.Transpose();
return new Matrix3x3(trp * a.Row0, trp * a.Row1, trp * a.Row2);
}
}
}
I am trying to get more comfortable with the math behind fractal coloring and understanding the coloring algorithms much better. I am the following paper:
http://jussiharkonen.com/files/on_fractal_coloring_techniques%28lo-res%29.pdf
The paper gives specific parameters to each of the functions, however when I use the same, my results are not quite right. I have no idea what could be going on though.
I am using the iteration count coloring algorithm to start and using the following julia set:
c = 0.5 + 0.25i and p = 2
with the coloring algorithm:
The coloring function simply returns the number of
elements in the truncated orbit divided by 20
And the palette function:
I(u) = k(u − u0),
where k = 2.5 and u0 = 0, was used.
And with a palette being white at 0 and 1, and interpolating to black in-between.
and following this algorithm:
Set z0 to correspond to the position of the pixel in the complex plane.
Calculate the truncated orbit by iterating the formula zn = f(zn−1) starting
from z0 until either
• |zn| > M, or
• n = Nmax,
where Nmax is the maximum number of iterations.
Using the coloring and color index functions, map the resulting truncated
orbit to a color index value.
Determine an RGB color of the pixel by using the palette function
Using this my code looks like the following:
float izoom = pow(1.001, zoom );
vec2 z = focusPoint + (uv * 4.0 - 2.0) * 1.0 / izoom;
vec2 c = vec2(0.5f, 0.25f) ;
const float B = 2.0;
float l;
for( int i=0; i<100; i++ )
{
z = vec2( z.x*z.x - z.y*z.y, 2.0*z.x*z.y ) + c;
if( length(z)>10.0) break;
l++;
}
float ind = basicindex(l);
vec4 col = color(ind);
and have the following index and coloring functions:
float basicindex(float val){
return val / 20.0;
}
vec4 color(float index){
float r = 2.5 * index;
float g = r;
float b = g;
vec3 v = 0.5 - 0.5 * sin(3.14/2.0 + 3.14 * vec3(r, g, b));
return vec4(1.0 - v, 1.0) ;
}
The paper provides the following image:
https://imgur.com/YIZMhaa
While my code produces:
https://imgur.com/OrxdMsN
I get the correct results by using k = 1.0 instead of 2.5, however I would prefer to understand why my results are incorrect. When extending this to the smooth coloring algorithms, my results are still incorrect so I would like to figure this out first.
Let me know if this isn't the correct place for this kind of question and I can move it to the math stack exchange. I wasn't sure which place was more appropriate.
Your image is perfectly implemented for Figure 3.3 in the paper. The other image you posted uses a different routine.
Your figure seems to have that bit of perspective code there at top, but remove that and they should be the same.
If your objection is the color extremes you set that with the "0.5 - 0.5 * ..." part of your code. This makes the darkest black originally 0.5 when in the example image you're trying to duplicate the darkest black should be 1 and the lightest white should be 0.
You're making the whiteness equal to the distance from 0.5
If you ignore the fractal all together you are getting a bunch of values that can be normalized between 0 and 1 and you're coloring those in some particular ways. Clearly the image you are duplicating is linear between 0 and 1 so putting black as 0.5 cannot be correct.
o = {
length : 500,
width : 500,
c : [.5, .25], // c = x + iy will be [x, y]
maxIterate : 100,
canvas : null
}
function point(pos, color){
var c = 255 - Math.round((1 + Math.log(color)/Math.log(o.maxIterate)) * 255);
c = c.toString(16);
if (c.length == 1) c = '0'+c;
o.canvas.fillStyle="#"+c+c+c;
o.canvas.fillRect(pos[0], pos[1], 1, 1);
}
function conversion(x, y, R){
var m = R / o.width;
var x1 = m * (2 * x - o.width);
var y2 = m * (o.width - 2 * y);
return [x1, y2];
}
function f(z, c){
return [z[0]*z[0] - z[1] * z[1] + c[0], 2 * z[0] * z[1] + c[1]];
}
function abs(z){
return Math.sqrt(z[0]*z[0] + z[1]*z[1]);
}
function init(){
var R = (1 + Math.sqrt(1+4*abs(o.c))) / 2,
z, x, y, i;
o.canvas = document.getElementById('a').getContext("2d");
for (x = 0; x < o.width; x++){
for (y = 0; y < o.length; y++){
i = 0;
z = conversion(x, y, R);
while (i < o.maxIterate && abs(z) < R){
z = f(z, o.c);
if (abs(z) > R) break;
i++;
}
if (i) point([x, y], i / o.maxIterate);
}
}
}
init();
<canvas id="a" width="500" height="500"></canvas>
via: http://jsfiddle.net/3fnB6/29/
I have a DICOM series, with following origin, spacing and extent:
int nExtent[6];
double dSpacing[3];
double dOrigin[3];
m_pReader->GetOutputInformation(0)->Get(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT(), nExtent);
m_pReader->GetOutput()->GetSpacing(dSpacing);
m_pReader->GetOutput()->GetOrigin(dOrigin);
where m_pReader is vtkDICOMReader object ...
dOrigin is 0, 0, 0;
dSpacing id 0.447266, 0.447266, 3.998718;
nExtent is 0, 511, 0, 511, 0, 43;
the series is AXIAL.
Now, if I slice the series through AXIAL plan, I could slice the series by 44 slices, like that:
double deltaY = 0.0;
delta += 1.0;
pReslice->Update();
double dSliceSpacing = pReslice->GetOutput()->GetSpacing()[2];
vtkMatrix4x4* pMatrix = pReslice->GetResliceAxes();
// move the dCenter dPoint that we are slicing through
double dPoint[4];
double dCenter[4];
dPoint[0] = 0.0;
dPoint[1] = 0.0;
dPoint[2] = dSliceSpacing * deltaY;
dPoint[3] = 1.0;
pMatrix->MultiplyPoint(dPoint, dCenter);
pMatrix->SetElement(0, 3, dCenter[0]);
pMatrix->SetElement(1, 3, dCenter[1]);
pMatrix->SetElement(2, 3, dCenter[2]);
Everything is allright ...
The problem: if I slice the series through CORONAL plan, the slices number are not 44 !! But how many ? How can I know the slice number if the plan is CORONAL or SAGITTAL ?
On Coronal and Sagittal slicing its more about position instead of slice index.
You need to calculate your min/max origin for each axis (x,y,z)
e.g.
myOriginMax.X = myOrigin.X + ((ImageDimension.SizeX - 1) * mySpacing.X);
You can compute your new origin in your slicing Event, where _positionDelta is your inc/dec value. (more or less pseudo code)
e.g.
double[] _origin = myImageReslice.GetResliceAxesOrigin();
if(_view == "SAGITTAL")
{
_origin[0] = Math.Min(_origin[0] + _positionDelta * mySpacing.X, myOriginMax.X);
}
else if(_view == "CORONAL")
{
_origin[1] = Math.Min(_origin[1] + _positionDelta * mySpacing.Y, myOriginMax.Y);
}
else //AXIAL
{
_origin[2] = Math.Min(_origin[2] + _positionDelta * mySpacing.Z, myOriginMax.Z);
}
myImageReslice.SetReliceAxesOrigin(_origin[0], _origin[1], _origin[2]);
Render();
Yes, it is another compute method ... in my case I have m_pReslice for axial plan, m_pReslice2 for coronal plan, and m_pReslice3 for sagittal plan ... I don't know if is the proper architecture, but applying your algorithm I arrive in the same place :)
m_pReslice->GetResliceAxesOrigin(dOrigin);
int nSizeX = nExtent[0] + nExtent[1];
int nSizeY = nExtent[2] + nExtent[3];
int nSizeZ = nExtent[4] + nExtent[5];
double dOriginMax[3];
dOriginMax[0] = dOrigin[0] + ((nSizeX - 1) * dSpacing[0]);
dOriginMax[1] = dOrigin[1] + ((nSizeY - 1) * dSpacing[1]);
dOriginMax[2] = dOrigin[2] + ((nSizeZ - 1) * dSpacing[2]);
dOrigin[0] = min(dOrigin[0] + 1.0 * dSpacing[0], dOriginMax[0]);
dOrigin[1] = min(dOrigin[1] + 1.0 * dSpacing[1], dOriginMax[1]);
dOrigin[2] = min(dOrigin[2] + 1.0 * dSpacing[2], dOriginMax[2]);
m_pReslice->SetResliceAxesOrigin(dOrigin);
this is the case for m_pReslice (axial plan) ... if I apply the algorithm for m_pReslice2 (coronal) and for m_pReslice3 (sagittal), I still don't know how may slices I have in coronal case (or sagittal) ...
I'm trying to calculate (in VBA Excel) the Average and StDev of an array with more than 65536 elements. Something like this:
Mitja = worksheetfunction.Average(array())
DesvTip = worksheetfunction.StDev(array())
While the dimension of the array is smaller than 65536 there is no problem but, when it's bigger it gives me an error!
I know that this VBA functions can't work with more than 65536 data so, how can I obtain this parameters in VBA?
Apreciate your comments. Thanks a lot! :))
You can calculate mean and standard deviation without having to store all the values. Just keep a running total of sum, sum of squares, and number of points. You can have as many points as integer number of points will allow that way.
Here's how I'd do it in Java. Feel free to crib.
package statistics;
/**
* Statistics
* #author Michael
* #link http://stackoverflow.com/questions/11978667/online-algorithm-for-calculating-standrd-deviation/11978689#11978689
* #link http://mathworld.wolfram.com/Variance.html
* #since 8/15/12 7:34 PM
*/
public class Statistics {
private int n;
private double sum;
private double sumsq;
public void reset() {
this.n = 0;
this.sum = 0.0;
this.sumsq = 0.0;
}
public synchronized void addValue(double x) {
++this.n;
this.sum += x;
this.sumsq += x*x;
}
public synchronized double calculateMean() {
double mean = 0.0;
if (this.n > 0) {
mean = this.sum/this.n;
}
return mean;
}
public synchronized double calculateVariance() {
double variance = 0.0;
if (this.n > 0) {
variance = Math.sqrt(this.sumsq-this.sum*this.sum/this.n)/this.n;
}
return variance;
}
public synchronized double calculateStandardDeviation() {
double deviation = 0.0;
if (this.n > 1) {
deviation = Math.sqrt((this.sumsq-this.sum*this.sum/this.n)/(this.n-1));
}
return deviation;
}
}
Use the following algorithm if the data is stored in an array x(1 to N, 1 to 1), where N is the number of data points
sum = 0# : sumsq = 0#
for i=1 to N
sum = sum + x(i,1)
sumsq = sumsq + x(i,1)^2
next i
average = sum/N
stddev = Sqr( sumsq/N^2 - sum^2/N^3 )
:Note:
To fill the array use the notation
Dim r as Range, x() as Variant
Set r = Range("A1").Resize(N,1)
x = r.Value
Thanks for both comments. Finally we did something similar. I hope it will be usefull for someone with the same problem. Our code:
sum = 0
sumq = 0
For i = 0 To ((2 * N) - 1)
sum = sum + h_normal(i)
Next i
media = sum / (2 * N)
For j = 0 To ((2 * N) - 1)
sumsq = sumsq + (h_normal(j) - media) ^ 2
Next j
desviaci(h - 1) = Math.Sqr(sumsq / ((2 * N) - 1))