Draw linear gradient at a certain angle - 2d

I'm trying to draw linear gradients with libpixman using the pixman_image_create_linear_gradient() function. It works fine for drawing gradients that run from left to right and from top to bottom but I don't see how I can draw gradients at a specific angle (0-360 degrees) like they're possible in CSS. For example, a linear gradient that is rotated by 45 degrees.
I think one has to use the arguments p1 and p2 for this because they define the gradient direction but there is no documentation at all and I can't really figure out how to use these two parameters to rotate the gradient.
For vertical gradients I simply set them to
p1.x = 0; p1.y = 0;
p2.x = 0; p2.y = height - 1;
And for horizontal gradients I use
p1.x = 0; p1.y = 0;
p2.x = width - 1; p2.y = 0;
But which values should I use for arbitrary rotation? Simply applying a 2D rotation matrix to the points doesn't look right, e.g. when drawing a gradient that is 640x480 and rotating this by 45 degrees I end up with the points
p1.x = 81; p1.y = 560;
p2.x = 559; p2.y = 559;
which draws the gradient in the right direction but there are about 80 pixels of blank space on either side of the gradient so I must be doing something wrong.
Could anybody tell me how to get this right?
Thanks!

I guess that Pixman implements linear gradients in the same way that Cairo does, given that Cairo's image backend uses Pixman, so look at some docs for Cairo. For example, in http://www.cairographics.org/tutorial/ in the section "Drawing with Cairo", subsection "Preparing and Selecting a Source" there is an explanation of linear gradients.
For your 45 degree rotation, I would try the following (one point in the top left corner, the other one in the bottom right one):
p1.x = 0; p1.y = 0;
p2.x = width - 1; p2.y = height - 1;
P.S.: No, I do not know how gradients with an angle are specified in CSS.

Related

Rotation of coordinate system with rectangle leads to parallelogram

In my Flutter app, I have drawn a rectangle in one coordinate system on a Google Map and I want to rotate this coordinate system around the coordinate (0,0). How this can be done is described here: Rotation matrix. I have implemented the rotation of coordinates like this in my app:
class Coordinate {
Coordinate(this.x, this.y);
double x;
double y;
void rotate(double angle) {
// angle is in degrees, convert to radians
final double angleInRadians = angle * (math.pi / 180);
final double oldX = x;
final double oldY = y;
final double newX = oldX * math.cos(angleInRadians) - oldY * math.sin(angleInRadians);
final double newY = oldX * math.sin(angleInRadians) + oldY * math.cos(angleInRadians);
x = newX;
y = newY;
}
}
Using this to rotate four corners of a rectangle works fine for some places in the world, like Australia and a place near (0,0). In this picture, you can see the rotation of the red rectangle on the top around the point (0,0) (bottom left) to the rotated red rectangle on the bottom right:
Please ignore all the markers and non-red lines. The next to images show a rectangle like the one in the picture above which I again rotate around (0,0) using the code above, but as you can see in the second image, the red rectangle is not a rectangle anymore, but a parallelogram instead.
I cannot find an explanation for this. The questions I ask myself are: Why does the code work for some places but not for others? Why does the rectangle transform to a perfect parallelogram instead of whatever other shape with the points possibly all around the world? As it is working for some locations, the problem cannot be that I have mixed up some of the coordinates or something like that, it has to do something with the calculation of the edges of the rotated rectangle. But I cannot find out what I did wrong here.
REMINDER: IGNORE ALL MARKERS AND NON-RED LINES

How to disable linear filtering for drawImage on canvas in javafx

I'm trying to draw scaled image on canvas in javafx. Using this code:
Image image = ...;
canvas.setWidth(scale * width);
canvas.setHeight(scale * height);
GraphicsContext gc = canvas.getGraphicsContext2D();
gc.drawImage(image, 0, 0, scale * width, scale * height);
// this gives same result
// gc.scale(scale, scale);
// gc.drawImage(editableImage, 0, 0, width, height);
It works really fast but makes blurred images like this:
This is not what I'd like to see. Instead I want to get this picture:
Which can be drawn by manually setting each pixel color with such code:
PixelReader reader = image.getPixelReader();
PixelWriter writer = gc.getPixelWriter();
for (int y = 0; y < scale * height; ++y) {
for (int x = 0; x < scale * width; ++x) {
writer.setArgb(x, y, reader.getArgb(x / scale, y / scale));
}
}
But I cannot use this approach as it's too slow. It took couple of seconds to draw 1Kb image scaled 8 times. So I ask if there's any way to disable this blurry effect for drawing on canvas?
UPD 10/07/2019:
Looks like the issue is fixed! Now GraphicsContext should have property "image smoothing" controlling this behavior.
INITIAL ANSWER
I guess I've found answer to my question. As this issue says that there's no way to specify filtering options in graphics context.
Description:
When drawing an image in a GraphicsContext using the drawImage()
method to enlarge a small image to a larger canvas, the image is being
interpolated (possibly using a bilinear or bicubic algorithm). But
there are times like when rendering color maps (temperature,
zooplancton, salinity, etc.) or some geographical data (population
concentration, etc.) where we want to have no interpolation at all
(ie: use the nearest neighbor algorithm instead) in order to represent
accurate data and shapes.
In Java2D, this is possible by setting the appropriate
RenderingHints.KEY_RENDERING on the Graphics2D at hand. Currently on
JavaFX's GraphicsContext there is no such way to specify how the image
is to be interpolated.
The same applies when shrinking images too.
This could be expanded to support a better form of smoothing for the
"smooth" value that is available in both Image and ImageView and that
does not seem to work very well currently (at least on Windows).
The issue was created in 2013 but it's still untouched so unlikely it will be resolved soon.

Morph circle to oval in openscad

I am trying to create a fan duct in openscad, flattening the duct from circular to oval. Is there a way to do this in openscad? If not, is there any other programmatic way to generate this type of 3d model?
Thanks
Dennis
Assuming by 'oval' you mean elipse, then the following creates a solid tapering from a circle to an ellipse:
Delta=0.01;
module connector (height,radius,eccentricity) {
hull() {
linear_extrude(height=Delta)
circle(r=radius);
translate([0,0,height - Delta])
linear_extrude(height=Delta)
scale([1,eccentricity])
circle(r=radius);
}
}
connector(20,6,0.6);
You could make the tube by subtracting a smaller version:
module tube(height, radius, eccentricity=1, thickness) {
difference() {
connector(height,radius,eccentricity);
translate([0,0,-(Delta+thickness)])
connector(height + 2* (Delta +thickness) ,radius-thickness, eccentricity);
}
}
tube(20,8,0.6,2);
but the wall thickness will not be uniform. To make a uniform wall, use minkowski to add the wall:
module tube(height, radius, eccentricity=1, thickness) {
difference() {
minkowski() {
connector(height,radius,eccentricity);
cylinder(height=height,r=thickness);
}
translate([0,0,-(Delta+thickness)])
connector(height + 2* (Delta +thickness) ,radius, eccentricity);
}
}
tube(20,8,0.6,2);
There is another way by using the „scale“-parameter of linear_extrude(). It „scales the 2D shape by this value over the height of the extrusion. Scale can be a scalar or a vector“ (Documentation). Using a vector with x- and y-scalefactor, you get the modification, you wanted:
d = 2; // height of ellipsoid, diameter of bottom circle
t = 0.25; // wall thickness
w = 4; // width of ellipsoid
l = 10; // length of extrusion
module ellipsoid(diameter, width, height) {
linear_extrude(height = height, scale = [width/diameter,1]) circle(d = diameter);
}
difference() {
ellipsoid(d,w,l);
ellipsoid(d-2*t,w-2*t,l);
}
I like Chris Wallace answer but there was a bug in the Minkwoski, it should be h=Delta.
module tube(height, radius, eccentricity=1, thickness) {
difference() {
minkowski() {
connector(height,radius,eccentricity);
cylinder(h=Delta,r=thickness);
}
translate([0,0,-(Delta+thickness)])
connector(height + 2* (Delta +thickness) ,radius, eccentricity);
}
}
tube(20,8,0.6,2);
I don't know of a way to do it directly, but I can imagine approximating it with a series of stacked slices.
Start with a circle, and have a loop that changes the scale factor smoothly from circle to oval as you add slices to the stack. This will give you a stepped surface. If this is for a 3D printing application, if you make your slice thickness the same as your layer height, you might not even notice.

Image Rotate 3D in Flex, but display another image on back of this image?

i want to rotate 3D an Image called img1 in Flex. I want to rotate it around y axis 180 degree. I can do this by using 3D effect already built in Flex but i want to do a bit more different.
I want during rotating, there's another image called img2 appear on back of img1 (in default case, the image appear on the back is img1) and when rotating finish, the image will be img2.
How can i do this ?
Thank you.
If you need no perspective effect, it's quite easy to do. A rough implementation (not tested!):
// Event.ENTER_FRAME event listener
void on_enter_frame(event:Event):void
{
// m_angle is a member of the class/flex component where on_enter_frame is declared
// ANGLE_DELTA is just a constant
m_angle += ANGLE_DELTA;
// Angle clamping to the range [0, PI * 2)
m_angle %= Math.PI * 2;
if (m_angle < 0)
m_angle += Math.PI * 2;
// If we currently look at the front side...
if (m_angle < Math.PI)
{
img1.visible = true;
img2.visible = false;
img1.scaleX = Math.cos(m_angle);
}
else
{
img1.visible = false;
img2.visible = true;
// If you omit negation, the back-side image will be mirrored
img2.scaleX = -Math.cos(m_angle);
}
}
So every frame we increase the rotation angle, clamp it to the range [0, PI * 2). Then depending on the value of the rotation angle, we hide/show the pair of your images, and then perform x-scaling of the visible image.
Thank you, now i found a solution. Please check it here, it's very easy to do.
http://forums.adobe.com/thread/921258

Choosing circle radius to fully fill a rectangle

the pixman image library can draw radial color gradients between two circles. I'd like the radial gradient to fill a rectangular area defined by "width" and "height" completely. Now my question, how should I choose the radius of the outer circle?
My current parameters are the following:
A) inner circle (start of gradient)
center pointer of inner circle: (width*0.5|height*0.5)
radius of inner circle: 1
color: black
B) outer circle (end of gradient)
center pointer of outer circle: (width*0.5|height*0.5)
radius of outer circle: ???
color: white
How should I choose the radius of the outer circle to make sure that the outer circle will entirely fill my bounding rectangle defined by width*height. There shall be no empty areas in the corners, the area shall be completely covered by the circle. In other words, the bounding rectangle width,height must fit entirely into the outer circle. Choosing
outer_radius = max(width, height) * 0.5
as the radius for the outer circle is obviously not enough. It must be bigger, but how much bigger?
Thanks!
The diameter of the circle should be the diagonal of the rectangle, which you can easily calculate from Pythagoras' Theorem. ie:
outer_radius = 0.5 * sqrt(width * width + height * height)
It's just Pythagoras:
outer_radius = sqrt((width / 2)^2 + (height / 2)^2);
or more simply:
outer_radius = sqrt(width^2 + height^2) / 2;
Your question isn't clear, but perhaps you want sqrt(w^2 + h^2) / 2
This is the distance from the center of the rectangle to its corner.
Use Pythagoras:
outer_radius = sqrt(width*width + height*height)*0.5
You want the length of the hypotenuse of a right triangle with sides equal width/2 and height/2. Alternatively, 1/2 the length of the diagonal of the rectangle.
Square root of (h/2 ^ 2 + w/2 ^ 2)
or 1/2 * Square root of (h^2 + w^2)
Make a little sketch, and apply Pythagoras's Theorem:
[sketch image used to go here; link is broken, and the host is flagged as malware now anyway]
In code:
outer_radius = sqrt(0.25 * (width*width + height*height))

Resources