Change line thickness of gtk_render_line - gtk3

I'd like to use gtk_render_line instead of cairo_line_to.
I've replaced the calls but kept cairo_set_line_width(cc,2) and the lines have changed to 1px wide.
Because gtk_render_line uses the style context, I guess I have to set a CSS property that will control that.
What is the name of the property that controls the line thickness rendered by gtk_render_line ?

Based on the source of gtk_render_line the actual drawing is done by gtk_do_render_line, the source of which looks like this:
gtk_do_render_line (GtkStyleContext *context,
cairo_t *cr,
gdouble x0,
gdouble y0,
gdouble x1,
gdouble y1)
{
const GdkRGBA *color;
cairo_save (cr);
color = _gtk_css_rgba_value_get_rgba (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_COLOR));
cairo_set_line_cap (cr, CAIRO_LINE_CAP_SQUARE);
cairo_set_line_width (cr, 1); /* <----------------- Relevant for this question */
cairo_move_to (cr, x0 + 0.5, y0 + 0.5);
cairo_line_to (cr, x1 + 0.5, y1 + 0.5);
gdk_cairo_set_source_rgba (cr, color);
cairo_stroke (cr);
cairo_restore (cr);
}
In here we can see that the width of the line is not determined by any CSS attribute, it is just fixed to a width of 1. So there is no attribute or other way to change it directly within Gtk...

Related

How to draw an ellipse in GWT?

There is no context2d.ellipse in GWT, so how can I draw an ellipse? The underlying HTML5 canvas supports it, so I thought I would try and access that using a native method using the following (but it does not work)...
ellipse(context.getCanvas(),(double)x,(double)y,50.,80.,0.,0.,Math.PI*2);
...
public final native void ellipse(CanvasElement e, double x, double y, double rx, double ry, double ro, double sa, double ea)
/*-{
e.getContext("2d").ellipse(x, y, rx, ry, ro, sa, ea, false);
}-*/;
ideas / solutions?
If there is no implementation you can draw it using lines, just needs a bit of trigonometry...
function drawEllipse(x, y, rx, ry) {
ctx.beginPath();
for (i = 0; i <= 360; i++) {
a = i * Math.PI / 180
px = rx * Math.sin(a) + x
py = ry * Math.cos(a) + y
ctx.lineTo(px, py);
}
ctx.stroke();
}
var canvas = document.querySelector('canvas');
var ctx = canvas.getContext('2d');
drawEllipse(100, 100, 90, 30);
drawEllipse(100, 100, 50, 90);
drawEllipse(100, 100, 50, 25);
<canvas id=canvas width=200 height=200></canvas>

Draw a circle smoothly transforming to a line

I faced the problem in my Flutter app that I can't draw this kind of a shape for my Slider
What I have now is:
final paint = Paint()
..color = Colors.black
..style = PaintingStyle.fill;
final rect = Rect.fromCircle(center: center, radius: thumbRadius);
final rrect = RRect.fromRectAndRadius(
Rect.fromPoints(
Offset(rect.left - 5, rect.top),
Offset(rect.right + 5, rect.bottom),
),
Radius.circular(thumbRadius + 2),
);
canvas.drawRRect(rrect, paint);
Also, it would be great to change height of all bar, because next code changes only the size after player
SliderTheme(
data: SliderThemeData(
trackHeight: 2,
thumbShape: CustomSliderPlayer(),
),
child: Slider(...)
From the comments it looks like you are not familiar with quadratic bezier curves, they are very simple, I would recommend you to start on a Javascript canvas, they are easier to test that way and logic is the same, we move to the starting point then we draw the curve, see sample snippet below
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
function dobleQuad(x, y, w, h) {
ctx.beginPath();
ctx.moveTo(x - w, y);
ctx.quadraticCurveTo(x, y - h, x + w, y);
ctx.moveTo(x - w, y);
ctx.quadraticCurveTo(x, y + h, x + w, y);
ctx.fill();
}
function drawSlider(x, y) {
ctx.moveTo(0, y - 2);
ctx.fillRect(0, y - 2, canvas.width, 4);
dobleQuad(x, y, 20, 22)
}
drawSlider(50, 50)
canvas.addEventListener('mousemove', function(evt) {
ctx.clearRect(0, 0, canvas.width, canvas.height)
var rect = canvas.getBoundingClientRect();
drawSlider( evt.clientX - rect.left, 50 )
})
<canvas id="canvas"></canvas>
Just keep in mind that in JS it's quadraticCurveTo but in flutter quadraticBezierTo
https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/quadraticCurveTo
void ctx.quadraticCurveTo(cpx, cpy, x, y);
cpx, cpy
The coordinates of the control point.
x, y
The coordinates of the end point.
https://api.flutter.dev/flutter/dart-ui/Path/quadraticBezierTo.html
void quadraticBezierTo(
double x1, double y1,
double x2, double y2
)
Adds a quadratic bezier segment that curves from the current point
to the given point (x2,y2), using the control point (x1,y1).

Failing to overwrite antialiased pixels in Cairo

While using Cairo 1.14.6 for display purposes, I found that overwriting the very same path with another color does not necessarily overwrite all pixels, and leaves undesirable artifacts behind.
As evidence of my claim I offer this output from a short self-contained example, the source for which follows further below.
An explanation of the six parts of the image, from left to right:
Original shape stroked in blue.
Original shape overwritten in RGBA white.
Original shape overwritten in RGB white.
Original shape overwritten in RGBA white with CAIRO_OPERATOR_SOURCE mode.
Original shape overwritten in RGBA white with CAIRO_OPERATOR_SOURCE mode and CAIRO_ANTIALIAS_NONE.
Original shape overwritten in RGBA white with CAIRO_OPERATOR_SOURCE mode and CAIRO_ANTIALIAS_BEST.
The image was generated from the following code:
#include "cairo/cairo.h"
#define M_PI 3.14159265358979323846
void draw_shape(cairo_t* cr, int x, int y) {
cairo_arc(cr, 50 + x, 50 + y, 48, -M_PI, -M_PI / 2);
cairo_stroke(cr);
cairo_move_to(cr, x + 2, y + 2);
cairo_line_to(cr, x + 48, y + 48);
cairo_stroke(cr);
}
int main(int argc, char** argv) {
int x = 0;
int y = 0;
cairo_surface_t* surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 300, 50);
cairo_t* cr = cairo_create(surface);
/* Draw a white background and a few shapes to overwrite */
cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 1.0);
cairo_paint(cr);
cairo_set_source_rgba(cr, 0.0, 0.0, 1.0, 1.0);
draw_shape(cr, x, y); x += 50;
draw_shape(cr, x, y); x += 50;
draw_shape(cr, x, y); x += 50;
draw_shape(cr, x, y); x += 50;
draw_shape(cr, x, y); x += 50;
draw_shape(cr, x, y); x += 50;
x = 50;
/* Leftmost shape is left unchanged for reference */
/* Stroke in RGBA opaque white */
cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 1.0);
draw_shape(cr, x, y); x += 50;
/* Stroke in RGB white */
cairo_set_source_rgb(cr, 1.0, 1.0, 1.0);
draw_shape(cr, x + 0, y); x += 50;
/* Stroke in opaque white without blending */
cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 1.0);
cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
draw_shape(cr, x, y); x += 50;
/* Stroke in opaque white without blending, with no antialiasing */
cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 1.0);
cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
cairo_set_antialias(cr, CAIRO_ANTIALIAS_NONE);
draw_shape(cr, x, y); x += 50;
/* Stroke in opaque white without blending, with best antialiasing */
cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 1.0);
cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
cairo_set_antialias(cr, CAIRO_ANTIALIAS_BEST);
draw_shape(cr, x, y); x += 50;
/* Write the results to a file */
cairo_surface_write_to_png(surface, "output.png");
return 0;
}
It doesn't make intuitive sense to me that overwriting the very same shape would not overwrite all of its pixels, especially if I force it into non-blending CAIRO_OPERATOR_SOURCE mode. The results are the same on the framebuffer that constitutes my actual surface, so this is not an issue with the backend.
Cairo is usually so good at what it does that I'm very surprised at this. Is there no way to overwrite an anti-aliased shape exactly in Cairo?
What I was trying to do is apparently not possible. I posted my question to the Cairo mailing list and was offered two options:
Keep a copy of the original pixels before drawing over them: "Anti-aliasing involves blending. If you don’t want anti-aliasing, turn it off." (Link)
Draw at a much higher resolution: "The only real solution is to draw a much higher resolution with coverage rounded to exactly zero or one for each pixel." (Link)
More specifically:
All that is stored in the pixel from the first drawing is what
percentage of the pixel was covered by the shape. It does not remember
exactly what parts of the pixel are covered.
Since antialiasing necessarily involves blending, and since Cairo does not remember what part of a subpixel led to the blending, it has no way of knowing how to undo that blending.

Textured layers randomly switch position

In my project I want to create 5 textured layers.
Each layer is made out of 4 textured rectangles each. These four parts of a layer are arranged so that it looks like one big texture.
The layers are partly transparent and are arranged in front of each other to create a three dimensional look.
When I run the project with only one layer enabled, everything looks fine, but as soon as I add a second (or more) layers everything gets chaotic.
Some parts go missing, other parts have a completely wrong z-Coordinate (the value itself looks fine, but the background layer is suddenly the foremost layer). Some parts even shift their x-Coordinate (this one looks good as well on setup, if I use NSLog to output all the square coordinates).
This is my setupVBOs function where I write the object coordinates into the VBOs (I have only one Index VBO because every square is the same, but an array of 5x4 VBOs to hold the coordinates for every single part of the layers.)
- (void)setupVBOs {
glGenBuffers(1, &_indexBufferLayer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indexBufferLayer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(IndicesLayer), IndicesLayer, GL_STATIC_DRAW);
for (int layerNo = 1; layerNo < LAYER_COUNT + 1; ++layerNo)
{
for (int layerPart = 1; layerPart < LAYER_PARTS + 1; ++layerPart)
{
glGenBuffers(1, &_vertexBufferLayer[layerNo][layerPart]);
GLfloat x = -3.0 + (2.0 * (layerPart - 1));
GLfloat z = 0.0 + (50.0 * (layerNo - 1));
NSLog(#"Layer %d, Part %d: x=%f, z=%f", layerNo, layerPart, x, z);
// Alter the Texture slightly to
// remove errors from compression (x-Coord.)
Vertex Vertices[] = {
{{x + 1.0, -1.0, z}, {0.9865, 1.0}},
{{x + 1.0, +1.0, z}, {0.9865, 0}},
{{x - 1.0, +1.0, z}, {0.01, 0}},
{{x - 1.0, -1.0, z}, {0.01, 1.0}}
};
glBindBuffer(GL_ARRAY_BUFFER, _vertexBufferLayer[layerNo][layerPart]);
glBufferData(GL_ARRAY_BUFFER, sizeof(Vertices), Vertices, GL_STATIC_DRAW);
x = z = 0;
}
}
}
This is my render Function where I draw everything and add the textures.
- (void)render: (CADisplayLink*)displayLink {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
CC3GLMatrix *projection = [CC3GLMatrix matrix];
float h = 4.0f * self.frame.size.height / self.frame.size.width;
[projection populateFromFrustumLeft:-1 andRight:1 andBottom:-h/4 andTop:h/4 andNear:2 andFar:500];
CC3GLMatrix *modelView = [CC3GLMatrix matrix];
// Translate the Modelviewmatrix
[modelView populateFromTranslation:CC3VectorMake(_cameraX, _cameraY, -5.0)];
// Rotate the Modelviewmatrix
[modelView rotateBy:CC3VectorMake(_currentRotation, 0, 90)];
[modelView translateByZ:_cameraZoom];
//
// Draw all layers
//
for (int layerNo = 1; layerNo < LAYER_COUNT + 1; layerNo++)
{
GLfloat layerFactor = (LAYER_COUNT + 1 - layerNo) * 22.0;
GLfloat scaleFactor = 100.0 + layerFactor;
[modelView scaleByX:scaleFactor];
[modelView scaleByY:scaleFactor];
for (int layerPart = 1; layerPart < LAYER_PARTS + 1; layerPart++)
{
glUniformMatrix4fv(_modelViewUniform, 1, 0, modelView.glMatrix);
glUniformMatrix4fv(_projectionUniform, 1, 0, projection.glMatrix);
GLuint uniformTexture = glGetUniformLocation(programHandle, "Texture");
// Bind Buffer and Texture
glBindBuffer(GL_ARRAY_BUFFER, _vertexBufferLayer[layerNo][layerPart]);
// Activate Texturing Pipeline and Bind Texture
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, _layers[layerNo][layerPart][0]);
glUniform1i(uniformTexture, 0);
// Vertex Shader calls
glVertexAttribPointer(_positionSlot, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*) 0);
glVertexAttribPointer(_texCoordSlot, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*) (sizeof(float) * 3));
glEnableVertexAttribArray(_positionSlot);
glEnableVertexAttribArray(_texCoordSlot);
glDrawElements(GL_TRIANGLES, sizeof(IndicesLayer)/sizeof(IndicesLayer[0]), GL_UNSIGNED_BYTE, 0);
glDisableVertexAttribArray(_texCoordSlot);
glDisableVertexAttribArray(_positionSlot);
}
[modelView scaleByX:1/scaleFactor];
[modelView scaleByY:1/scaleFactor];
}
[_context presentRenderbuffer:GL_RENDERBUFFER];
}
Use:
glenable(GL_TEXTURE_2D)
And also:
glActiveTexture — select active texture unit

middlePoint in CGContextAddArc?

i am drawing Arc through CGCOntext.I want to draw a string in the center Point of Arc.how can i fond the center point in the Arc which has been drawn through CGContext.
CGContextSetAlpha(ctx, 0.5);
CGContextSetRGBFillColor(ctx, color.red, color.green, color.blue, color.alpha );
CGContextMoveToPoint(ctx, cX, cY);
CGContextAddArc(ctx, cX, cY, radious+10, (startDeg-90)*M_PI/180.0, (endDeg-90)*M_PI/180.0, 0);
CGContextClosePath(ctx);
CGContextFillPath(ctx);
The 2nd and 3rd arguments to CGContextAddArc are the x and y coordinates for the center of the arc. Therefore, in this code, the center is at the point (cX,cY).
Edit
This code will give the coordinates for the point directly between the starting and ending points of the arc as x and y.
CGFloat x = cX + (radious+10) * (cos((startDeg-90)*M_PI/180.0) + cos((endDeg-90)*M_PI/180.0)) / 2;
CGFloat y = cY + (radious+10) * (sin((startDeg-90)*M_PI/180.0) + sin((endDeg-90)*M_PI/180.0)) / 2;