Difficulty with SICP Picture Language - Image Scaling Example - vector-graphics

The picture language example in the SICP book discusses the notion of a frame:
A frame can be described by
three vectors—an origin vector and two edge vectors. The origin vector
specifies the offset of the frame’s origin from some absolute origin in
the plane, and the edge vectors specify the offsets of the frame’s corners
from its origin.
The book then goes on to say that if we have an image described in terms of points in the unit square, we can map a given point, (x, y), to a point within a new frame, f, using the following formula:
origin(f) + x * edge1(f) + y * edge2(f)
where + and * are defined as vector arithmetic operators:
(x1, y1) + (x2, y2) = (x1 + x2, y1 + y2) and
k * (x, y) = (kx, ky).
Using this formula, if I define a frame as
origin = (1, 1); edge1 = (3, 1); edge2 = (1, 3)
the point (1, 1) from the unit square maps to (5, 5); whereas it seems like it ought to be `(3, 3).
What am I not getting?

First, let's review the definition of frame:
A frame can be described by three vectors -- an origin vector and two edge vectors. The origin vector specifies the offset of the frame's origin from some absolute origin in the plane, and the edge vectors specify the offsets of the frame's corners from its origin.
And the point of above definition is :
edge vectors are measured based on origin vector of the frame, not the absolute origin in the plane.
So, when you choose three vectors (1, 1); (3, 1); (1, 3), the coordinate of the frame is actually
origin = (1, 1);
edge1 = (3, 1) - (1, 1) = (2, 0)
edge2 = (1, 3) - (1, 1) = (0, 2)
Back to your question, if you define the frame as origin = (1, 1); edge1 = (3, 1); edge2 = (1, 3), then the absolute coordinates are (1, 1); (4, 2); (2, 4).
The point (1, 1) of a painter specified in the unit square maps to (5, 5), not (3, 3) for the frame isn't a rectangular, just a more general parallelogram.

Related

How to find 3D points coordinates in a perpendicular plane to a given vector

I have two points in a 3d space, one point is (x,0,z) and the other one is the origin (0,0,0), through those points there is a passing line with length L that is starting from the first point and continuing after the origin point, in the end of this line there is a perpendicular (to the line) flat board with dimensions of W x H, the line ends in the middle of this board.
Assume that x,z,L,H,W are given, I need a way to find all the 3D points coordinates where those points forming a pixels image over the board (meaning each point has a distance of 1 from its left, right, top, bottom neighboring points).
Attached a pretty ugly drawing :) I made trying to illustrate the problem (I marked the pixels points with two question marks but I need them all).
Thanks.
It is possible to define that plane. But there is no selected direction to build a grid uniquelly.
Let we choose OY direction as base (because normal has zero Y-component).
So we have:
Normal vector N = (xx, 0, zz) //I renamed values to avoid confusion with coordinate
variables
Unit normal vector n = (nx, 0, nz), where
nx = xx / Sqrt(xx*xx+zz*zz)
nz = zz / Sqrt(xx*xx+zz*zz)
Base point
B = (bx, 0, bz) = (xx - nx * L, 0, zz - nz * L)
Unit base vector in the plane
dy = (0, 1, 0)
Another base vector
dc = dy x n //vector product
= (-bz, 0, bx)
Now it is possible to generate a grid, using integer indexes i, j in ranges (-W/2..W/2) and (-H/2.. H/2). Grid nodes coordinates:
x(i, j) = bx - j * bz
y(i, j) = 0 + i
z(i, j) = bz + j * bx

How to find a point in 3-D at an arbitrary perpendicular line given distance to the point

I have a line AB. I would like to draw a line BC, perpendicular to AB. I know xyz of the points A and B, I also know the distance N between B and C. How can I find an arbitrary point C which fits into the given parameters? The calculations should be done in 3-D. Any point, perpendicular to AB can be the point C, if its distance to B equals N.
An almost identical question is given here, but I would like to know how the same thing is done in 3-D: How do you find a point at a given perpendicular distance from a line?
The calculation that works for me in 2-D was given in the link above:
dx = A.x-B.x
dy = A.y-B.y
dist = sqrt(dx*dx + dy*dy)
dx /= dist
dy /= dist
C.x = B.x + N*dy
C.y = B.y - N*dx
I tried adding Z axis to it like this:
dz = A.z - B.z
dist = sqrt(dx*dx + dy*dy + dz*dz)
dz /=dist
C.z = .... at this point it becomes a mystery to me
If I put something like "C.z - N*dz" into C.z, the distance is accurate only in some rotation angles, I would like to know the correct solution. I can imagine that in 3-D it is calculated in a completely different manner.
Clarification
Point C is not unique. It can be any point on a circle with its
centre at B and radius N. The circle is perpendicular to AB
If the desired point C can be any of the infinitely-many points fitting your requirements, here is one method.
Choose any vector that is not parallel or anti-parallel to vector AB. You could try the vector (1, 0, 0), and if that is parallel you could use (0, 1, 0) instead. Then take the cross-product of vector AB and the chosen vector. That cross-product is perpendicular to vector AB. Divide that cross-product by its length then multiply by the desired length N. Finally extend that vector from point B to find your desired point C.
Here is code in Python 3 that follows that algorithm. This code is somewhat non-pythonic to make it easier to convert to other languages. (If I really did this for myself I would use the numpy module to avoid coordinates completely and shorten this code.) But it does treat the points as tuples of 3 values: many languages will require you to handle each coordinate separately. Any real-life code would need to check for "near zero" rather than "zero" and to check that the sqrt calculation does not result in zero. I'll leave those additional steps to you. Ask if you have more questions.
from math import sqrt
def pt_at_given_distance_from_line_segment_and_endpoint(a, b, dist):
"""Return a point c such that line segment bc is perpendicular to
line segment ab and segment bc has length dist.
a and b are tuples of length 3, dist is a positive float.
"""
vec_ab = (b[0]-a[0], b[1]-a[1], b[2]-a[2])
# Find a vector not parallel or antiparallel to vector ab
if vec_ab[1] != 0 or vec_ab[2] != 0:
vec = (1, 0, 0)
else:
vec = (0, 1, 0)
# Find the cross product of the vectors
cross = (vec_ab[1] * vec[2] - vec_ab[2] * vec[1],
vec_ab[2] * vec[0] - vec_ab[0] * vec[2],
vec_ab[0] * vec[1] - vec_ab[1] * vec[0])
# Find the vector in the same direction with length dist
factor = dist / sqrt(cross[0]**2 + cross[1]**2 + cross[2]**2)
newvec = (factor * cross[0], factor * cross[1], factor * cross[2])
# Find point c such that vector bc is that vector
c = (b[0] + newvec[0], b[1] + newvec[1], b[2] + newvec[2])
# Done!
return c
The resulting output from the command
print(pt_at_given_distance_from_line_segment_and_endpoint((1, 2, 3), (4, 5, 6), 2))
is
(4.0, 6.414213562373095, 4.585786437626905)

How to find points along arc if given initial point, ending point, random point + precision?

the precision is the number of points I want for my vector, from 0, the initial point of my arc, to the precision I want minus 1.
Code example in c++:
int precision = 20;
double pointInit[3] = {2,5,2};
double pointRandom[3] = {3,7,1};
double pointInit[3] = {0,-3,1};
std::vector<std::array<double,3>> pointArc;
std::array<double, 3> currentPoint;
// Fill the pointArc vector, from 0 (initial point) to precision -1 (ending point)
for (int i = 0 ; i < precision; i++)
{
// Find the value of the current point
// currentPoint[0] = ????;
// currentPoint[1] = ????;
// currentPoint[2] = ????;
pointArc.push_back(currentPoint);
}
EDIT : The arc I'm looking for is a circular arc
Use atan2() to find the angles of the endpoints with respect to the center, subtend the angle between them precision - 1 times, and convert the polar coordinates (use one of the endpoints to get the distance from the center) to rectangular form.
1) translate the three points so that P0 comes to the origin
2) consider the vectors P0P1 and P0P2 and form an orthonormal basis by the Gram-Schmidt process (this is easy)
3) in this new basis, the coordinates of the three points are (0, 0, 0), (X1, 0, 0), (X2, Y2, 0), and you have turned the 3D problem to 2D. (Actually X1=d(P0,P1) and X2, Y2 are obtained from the dot and cross products of P0P2 with P0P1 / X1)
The equation of a 2D circle through the origin is
x² + y² = 2Xc.x + 2Yc.y
Plugging the above coordinates, you easily solve the 2x2 system for Xc and Yc.
X1² = 2Xc.X1
X2² + Y2² = 2Xc.X2 + 2Yc.Y2
4) The parametric equation of the circle is
x = Xc + R cos(t)
y = Yc + R sin(t)
where R²=Xc²+Yc².
You can find the angles t0 and t2 corresponding to the endpoints with tan(t) = (y - Yc) / (x - Xc).
5) interpolate on the angle t0.(1-i/n) + t2.i/n, compute the reduced coordinates x, y from the parametric equation and apply the inverse transforms of 2) and 1).

Vector Projection Confusion

If I have a vector (0, 0, 9) and I want to project it onto the vector (0, 0.7, 0.7) shouldn't that give me a vector of (0, 9, 9).
I am using the following formula
Vector3.Dot (vector, normal) * normal.magnitude * normal;
which is returning (0, 0.45, 0.45). What have I missed, isn't the returned vector z suppose to end at the same z position as the projected vector. Like this
When you project a vector onto another vector, the result's magnitude is always less than or equal to the magnitude of the original vector.
Given a normalized vector u, project v onto u with the formula:
proju v = 〈u, v〉u
Or, in code,
Vector3.Dot(vector, normal) * normal
The result of projecting (0, 0, 9) onto (0, √1/2, √1/2) is (0, 4.5, 4.5).
Note that normal.magnitude is always 1, unless normal is not "normal" (in which case you named your variable wrong); and if it's not normal, you need to divide by the squared magnitude, not multiply.
Vector3.Dot(vector, direction) * direction
* (1.0 / direction.magnitude_squared)

How to convert Parametric equation to Cartesian form

I need to convert a plane's equation from Parametric form to Cartesian form.
For example:
(1, 2, -1) + s(1, -2, 3) + t(1, 2, 3)
to:
ax+yb+cz+d=0
So basically, my question is: how do I find the a, b, c and d, and what's the logic behind the conversion.
Calculate normal vector to this plane :
N = s x t (vector product of two vectors belonging to plane)
Now you have coefficients a, b, c:
N = (a, b, c)
then substitute base point (in general - any point in the plane)
(1, 2, -1) to equation ax+yb+cz+d=0
a+2b-c+d=0
and find d

Resources