PDA

View Full Version : Rotating an edge straight (2D vector calc. using arctan)


DeadlyNightshade
12-10-2012, 02:10 PM
This is the function I use to orient a shell by calculating the angle of a vector (2 UV points) and then rotating the shell accordingly. At the bottom is the function for the arc tangent calculation.
global proc orientEdge()
{
global float $angle;
global float $pointLeft[];
global string $selUVs[];

// Check for valid selection
selCheckUVorEdges();

// Convert selection to UVs in case selection is edges
PolySelectConvert 4;

// Calculate arc tangent in degrees
calcArcTanAngle();

// Reduce arctan angle to 4 decimals only
$angle = `cutDecimals($angle)`;


// Determine rotation type based on arc tangent
// arctan range is -90 deg to +90 deg

global int $invertVal;

if ($angle == 0.0000 || $angle == 90.0000 || $angle == -90.0000)
{
// Type 0 - No rotation
$angle = 0;

} else if ($angle >= -44.9999 && $angle <= 44.9999)
{
// Type A - Invert arctan
$invertVal = 1;

} else if ($angle >= 45.0001 && $angle <= 89.9999)
{
// Type B - Subtract arctan from 90
$angle = 90 - $angle;
$invertVal = 0;

} else if ($angle <= -45.0001 && $angle >= -89.9999)
{
// Type C - Add 45 to arctan
$angle = $angle + 45;
$invertVal = 0;

} else {
// Type D - 45 degrees vector
$angle = 45;
$invertVal = 0;

}

int $invertVal;
if ($invertVal == 1) $angle = -$angle;


// Select the shell and rotate it correctly
SelectUVShell ;
polyEditUV -pivotU $pointLeft[0] -pivotV $pointLeft[1] -angle $angle ;

// Select the original selection
select $selUVs;
}

// Calculate arc tangent angle
// Used for the orientEdge

global proc float calcArcTanAngle()
{
global float $angle;
global float $pointLeft[];
global string $selUVs[];

// Flatten selected UVs
$selUVs = `ls -sl -fl`;

// Get point coordinates
select $selUVs[0];
float $pointA[] = `polyEditUV -q`;
select $selUVs[1];
float $pointB[] = `polyEditUV -q`;

// Get U and V dist
float $uDist, $vDist, $pointLeft[];

// Find left point
if ($pointA[0] >= $pointB[0])
{
$pointLeft = $pointA;
$uDist = ($pointA[0] - $pointB[0]);
$vDist = ($pointA[1] - $pointB[1]);
} else {
$pointLeft = $pointB;
$uDist = ($pointB[0] - $pointA[0]);
$vDist = ($pointB[1] - $pointA[1]);
}

// Calculate arc tangent in degrees
$angle = `atan2d $vDist $uDist`;
return ($angle);
}
But it's not entirely functional. It works most of the time, but I'm having a problem with vectors that go in a SSE to NNW direction (or vice versa). I also sometimes get wrong orientations when the vector is close to 0, 90, -90 or 180

zoharl
12-10-2012, 05:48 PM
You should specify what you are trying to accomplish, and exactly what happens when your code doesn't behave correctly. But first please check your code:

} else {
// Type D - 45 degrees vector
$angle = 45;
$invertVal = 0;
}

Meaning add a test in the spirit of:

} else {
if abs($angle - 45) > 0.001
print "Something is wrong\n";

// Type D - 45 degrees vector
$angle = 45;
$invertVal = 0;
}

DeadlyNightshade
12-11-2012, 02:51 PM
The script orients a selected vector (2 selected UVs) straight so it's orientation is along the U or V -axis. Comments are in the code explaining each step.

I have no use of "prints" for error reporting as of now, because there is nothing wrong with the code flow. The issue instead is that I do not get the correct orientation when calculating vectors that runs in a north-northeast to south-southwest direction (or vice versa).

By using arctan, the calculated vector is always within the range of 180 to -180 degrees in a polar coordinate system. Then, depending on the return value of calcArcTanAngle(), a shell orientation takes place (rotating the UV shell).

But the issue is that I get an incorrect rotation when calcArcTanAngle(); results in anything between -89.9999 and -45 (type C orientation in the script)

zoharl
12-11-2012, 03:31 PM
1. You didn't finish giving your objective: When do you synch the vector with the u-axis and when with the v-axis?
2. I hope that before you gave me your interesting story about needing/not needing a print, you actually performed my test and ruled out numerical errors. Your 'if' isn't fool proof, and you decide at the end that it's a 45 degrees, while it can be something close to 90. You deal with floats and it's a bad habit to compare the way you do.
3. You didn't supply a specific point where it failed to produce what you want. Also please throw your compass into the sea, and simply supply the angle with the x-axis (u-axis?).
Moreover I can't see why you are not able to simply debug this. Take a problematic point and watch your variables value at each line of your code. Since you know for each line what value to expect, you should soon find the bug. If you chose to program in mel and you don't have a debugger, add a print after each line of code (and spare me the print stories, just delete these lines afterwards). In a nutshell: Please debug your code and be more specific regarding your problem (e.g. I supply 100 to line 32 and get 120 instead of 20).

bk3d
12-11-2012, 07:27 PM
hmm looks kinda familiar

global proc NinjaUV_AlignUVShellEdge(string $Direction)
{
PolySelectConvert 4;
string $Sel_UVs[] = `ls -sl -fl`;

float $Start_PointU[];
float $Start_PointV[];
float $End_PointU[];
float $End_PointV[];
select $Sel_UVs[0];
float $PointA[] = `polyEditUV -q`;
select $Sel_UVs[1];
float $PointB[] = `polyEditUV -q`;

float $DistU;
float $DistV;
float $Left_Point[];

if ($PointA[0] < $PointB[0])
{
$Left_Point = $PointA;
$DistU = ($PointB[0] - $PointA[0]);
$DistV = ($PointB[1] - $PointA[1]);

}

else
{
$Left_Point = $PointB;
$DistU = ($PointA[0] - $PointB[0] );
$DistV = ($PointA[1] - $PointB[1]);
}


$angle = `atan2d $DistV $DistU`;
//$angle = `abs $angle`;
if ($angle > 0 )
{
$angle = ($angle * -1);
}

if ($angle < 0 && $DistV < 0)
{
$angle = ($angle * -1);
}

//print ("angle= " + $angle);
SelectUVShell;
polyEditUV -pu $Left_Point[0] -pv $Left_Point[1] -a $angle ;

if ($Direction == "Vertical")
{
polyEditUV -pu $Left_Point[0] -pv $Left_Point[1] -a -90 ;
}
select $Sel_UVs;

}

CGTalk Moderation
12-11-2012, 07:27 PM
This thread has been automatically closed as it remained inactive for 12 months. If you wish to continue the discussion, please create a new thread in the appropriate forum.