Is it possible to draw a SplineSeries like in this example, but there'd be just the spline, no other components of the chart view (axis, background etc.)? Or do I have to use canvas or something similar? In that case what would be the best possibility here? I have my x, y values, so if I just could place the SplineSeries itself to my layout like this, but that's probably not possible:
ColumnLayout {
SplineSeries {
name: "spline"
XYPoint { x: 0; y: 0.0 }
XYPoint { x: 1.1; y: 3.2 }
XYPoint { x: 1.9; y: 2.4 }
XYPoint { x: 2.1; y: 2.1 }
}
}
Related
I'm trying to draw points on the window, using the PolyPoint XCB request.
Note that I'm using the crate "xcb" in Rust.
Here is my function :
fn set_pixels(&mut self, pixels: Vec<(usize, usize, u32)>) {
self.connection.send_request(
&x::PolyPoint {
coordinate_mode: x::CoordMode::Origin,
drawable: x::Drawable::Window(self.handle.unwrap()),
gc: self.gc.unwrap(),
points: pixels.into_iter().map(|(x, y, colour)| {
x::Point {
x: x as i16,
y: y as i16,
}
})
.collect::<Vec<x::Point>>().as_slice(),
}
);
}
At first, I'm not sure if this part is the easiest way to get a slice of x::Point from the vector :
pixels.into_iter().map(|(x, y, colour)| {
x::Point {
x: x as i16,
y: y as i16,
}
})
.collect::<Vec<x::Point>>().as_slice(),
Well, as we can see, we got a "colour" for each pixel, and I would like to use x::PolyPoint with a colour for each point I want to draw.
I know I can use ChangeGc to set a drawing colour :
self.connection.send_request(
&x::ChangeGc {
gc: self.gc.unwrap(),
value_list: &[
x::Gc::Foreground(/* hex colour */),
],
}
);
But this would set the same colour for all the pixels.
How can I use "PolyPoint" to set pixels of different colours ? Without passing by a loop that would ChangeGC then just after use PolyPoint for one single pixel (this solution is too slow).
Earlier, I was doing a loop calling this function, to set pixels one by one. But this is too slow :
fn set_pixel(&mut self, x: usize, y: usize, hex_colour: u32) {
self.connection.send_request(
&x::ChangeGc {
gc: self.gc.unwrap(),
value_list: &[
x::Gc::Foreground(hex_colour),
],
}
);
self.connection.send_request(
&x::PolyPoint {
coordinate_mode: x::CoordMode::Origin,
drawable: x::Drawable::Window(self.handle.unwrap()),
gc: self.gc.unwrap(),
points: &[
x::Point {
x: x as i16,
y: y as i16,
}
]
}
)
}
You cannot set different colors for a single drawing request in X11. I think this is not even possible with the RENDER extension. So, all the options you have are the ones you or others already mention.
Well, one more idea: If you usually have few different colors, you could group things by color. Your input seems to be Vec<(usize, usize, u32)>. You could transform this into a HashMap<u32, Vec<(usize,usize)>> and then use that to draw all pixels of a single color at once. Of course, this does not make sense if you expect few pixels of each color.
I'm now working with the double-buffering method.
A simple way is to draw on a x::Pixmap object, and then create an update() function for the window's structure :
/// Copies the `self.pixmap` area to the window.
fn update(&mut self) {
self.connection.send_and_check_request(
&x::CopyArea {
src_drawable: x::Drawable::Pixmap(self.pixmap.unwrap()),
dst_drawable: x::Drawable::Window(self.window.unwrap()),
gc: self.gc.unwrap(),
src_x: 0,
src_y: 0,
dst_x: 0,
dst_y: 0,
width: self.width as u16,
height: self.height as u16,
}
)
.expect("double buffering: unable to copy the buffer to the window");
}
Here is my set_pixels method (renamed to draw_points :
fn draw_points(&mut self, coordinates: &Vec<(isize, isize)>, colour: u32) {
self.change_draw_colour(colour);
// Creates an `x::Point` vector.
let points = coordinates.into_iter().map(|coordinate: &(isize, isize)| {
x::Point {
x: coordinate.0 as i16,
y: coordinate.1 as i16,
}
})
.collect::<Vec<x::Point>>();
self.connection.send_and_check_request(
&x::PolyPoint {
coordinate_mode: x::CoordMode::Origin,
drawable: x::Drawable::Pixmap(self.pixmap.unwrap()),
gc: self.gc.unwrap(),
points: points.as_slice(),
}
)
.expect("unable to draw points on the pixmap");
}
For external reasons that I won't go into, I'm not directly using a vector of x::Point, there is why I transform my coordinates value to a Vec<x::Point>.
For optimisation, I'm also saving the previous colour to avoid changing colour to the same colour :
fn change_draw_colour(&mut self, colour: u32) {
if self.previous_colour == Some(colour) {
return;
}
self.connection.send_and_check_request(
&x::ChangeGc {
gc: self.gc.unwrap(),
value_list: &[
x::Gc::Foreground(colour),
],
}
)
.expect("unable to change the graphics context colour");
self.previous_colour = Some(colour);
}
I wanted to implement zooming in my 2d bevy game. After some code browsing I found out that Camera2dBundle uses OrthographicProjection by default and can not zoom in as required.
I tried using Camera3dBundle which does define projection: PerspectiveProjection by default but my sprite seems to disappear from the scene.
Could you give me some pointers to what I'm doing wrong? I have included some test code below.
Thanks
use bevy::prelude::*;
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_startup_system(setup)
.add_system(zoom_in)
.run();
}
fn setup(
mut commands: Commands
) {
commands.spawn_bundle(Camera3dBundle {
transform: Transform::from_xyz(0., 0., 1000.).looking_at(Vec3::ZERO, Vec3::Z),
..Default::default()
});
commands.spawn_bundle(SpriteBundle {
sprite: Sprite { custom_size: Some(Vec2 { x: 50., y: 50. }), ..Default::default()},
..Default::default()
});
}
pub fn zoom_in(mut query: Query<&mut Transform, With<Camera>>, time: Res<Time>) {
for mut transform in query.iter_mut() {
transform.translation.z -= 100. * time.delta_seconds();
warn!("{}", transform.translation.z);
}
}
You do not see the sprite, because you apparently look at it from the wrong side. If you have a 2D scene I would advise you to stick to the Camera2DBundle.
Contrary to what you stated in your question, in order to zoom you can set the scale of OrthographicProjection like so:
use bevy::prelude::*;
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_startup_system(setup)
.add_system(zoom_in)
.run();
}
fn setup(
mut commands: Commands
) {
commands.spawn_bundle(Camera2dBundle::default());
commands.spawn_bundle(SpriteBundle {
sprite: Sprite { custom_size: Some(Vec2 { x: 50., y: 50. }), ..Default::default()},
..Default::default()
});
}
pub fn zoom_in(mut query: Query<&mut OrthographicProjection, With<Camera>>, time: Res<Time>) {
for mut projection in query.iter_mut() {
projection.scale -= 0.1 * time.delta_seconds();
println!("Current zoom scale: {}", projection.scale);
}
}
Note that you might want to implement logarithmic zoom, so that your zoom does "feel" linear and does not speed up approaching infinity when the scale approaches zero.
Here is a sample using logarithmic zoom:
use bevy::prelude::*;
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_startup_system(setup)
.add_system(zoom_in)
.run();
}
fn setup(
mut commands: Commands
) {
commands.spawn_bundle(Camera2dBundle::default());
commands.spawn_bundle(SpriteBundle {
sprite: Sprite { custom_size: Some(Vec2 { x: 50., y: 50. }), ..Default::default()},
..Default::default()
});
}
pub fn zoom_in(mut query: Query<&mut OrthographicProjection, With<Camera>>, time: Res<Time>) {
for mut projection in query.iter_mut() {
let mut log_scale = projection.scale.ln();
log_scale -= 0.1 * time.delta_seconds();
projection.scale = log_scale.exp();
println!("Current zoom scale: {}", projection.scale);
}
}
I want an object, need it to fellow a complex path and move as an animation.
The path is included line and curve. just like a train.
Two solution: 1. PathAnimation or 2. states with multi-animation
Problem of solution 1:
The train maybe stop at a random time-point(pause the animation), and go reverse back to the start position(play animation reversely).
So i want know any way to play PathAnimation reversely?
I think QML doesn't have that functionality.
You could set a new path whenever you need a new one. I.e, when you animation ends.
Here you have an example:
import QtQuick 2.3
import QtQuick.Controls 1.1
ApplicationWindow {
visible: true
width: 350
height: 300
Rectangle {
id: window
width: 350
height: 300
Canvas {
id: canvas
anchors.fill: parent
antialiasing: true
onPaint: {
var context = canvas.getContext("2d")
context.clearRect(0, 0, width, height)
context.strokeStyle = "black"
context.path = pathAnim.path
context.stroke()
}
}
SequentialAnimation {
id: mySeqAnim
running: true
PauseAnimation { duration: 1000 }
PathAnimation {
id: pathAnim
duration: 2000
easing.type: Easing.InQuad
target: box
orientation: PathAnimation.RightFirst
anchorPoint: Qt.point(box.width/2, box.height/2)
path: myPath1
}
onStopped: {
console.log("test")
pathAnim.path = myPath2;
mySeqAnim.start();
}
}
Path {
id: myPath1
startX: 50; startY: 100
PathLine { x: 300; y: 100 }
onChanged: canvas.requestPaint()
}
Path {
id: myPath2
startX: 300; startY: 100
PathLine { x: 50; y: 100 }
onChanged: canvas.requestPaint()
}
Rectangle {
id: box
x: 25; y: 75
width: 50; height: 50
border.width: 1
antialiasing: true
Text {
anchors.centerIn: parent
}
}
}
}
For my project I need to place QtQuick.Scene3D within QtQuick.Component
Scene is successfully created, but when I try to dispose component I get segfault at
0 Qt3D::QCamera::position() const 0xb7226e6b
1 Qt3D::QCamera::translate(QVector3D const&, Qt3D::QCamera::CameraTranslationOption) 0xb7226fa4
It seems that objects are deleted in wrong order. So, there is a question: should I implement whole object graph in C++, or there is a correct way to make Scene3D re-creatable?
There is my component qml file:
import Qt3D 2.0
import Qt3D.Renderer 2.0
import QtQuick.Scene3D 2.0
import QtQuick 2.0 as QQ2
import CeGui 1.0;
import VectorPlot 1.0;
QQ2.Component {
QQ2.Item {
Scene3D {
anchors.fill: parent
id: rootscene
aspects: "input"
Entity {
id: sceneRoot
Camera {
id: camera
projectionType: CameraLens.PerspectiveProjection
fieldOfView: 45
aspectRatio: 16/9
nearPlane : 0.1
farPlane : 1000.0
position: Qt.vector3d( 25.0, -25.0, 25.0 )
upVector: Qt.vector3d( 0.0, 0.0, 1.0 )
viewCenter: Qt.vector3d( 0.0, 0.0, 0.0 )
}
Configuration {
id: cfg
controlledCamera: camera
}
Viewport {
id: viewport
rect: Qt.rect(0.0, 0.0, 1.0, 1.0) // From Top Left
clearColor: Qt.rgba(0, 0.5, 1, 1)
CameraSelector {
id : cameraSelector
camera: camera
ClearBuffer {
buffers : ClearBuffer.ColorDepthBuffer
}
}
}
components: [
FrameGraph {
id: framgraph
activeFrameGraph: viewport
}
]
BarChartScene {
id: bcs
model: GlobalViewModel.harmonicsEditModel
}
}
}
}
}
I use Qt 5.5 for 32-bit gcc in Linux
It seems that it is known bug, which will be fixed in upcoming releases
What is the correct way of asking the bounds of Flickable.contentY? I need that for a scrollbar.
Experimentally I have discovered that
offsetY <= contentY <= offsetY + contentHeight - height
where offsetY can be calculated as
var offsetY = contentY-Math.round(visibleArea.yPosition*contentHeight)
offsetY is zero at the start of the application and seems to be constant unless Flickable is resized.
This formula works in general, but there probably should be a dedicated function for it.
I did a scrollbar easily without offset :
// ScrollBar.qml
import QtQuick 2.0
Rectangle {
id: scrollbar;
color: "#3C3C3C";
visible: (flicker.visibleArea.heightRatio < 1.0);
property Flickable flicker : null;
width: 20;
anchors {
top: flicker.top;
right: flicker.right;
bottom: flicker.bottom;
}
Rectangle {
id: handle;
height: (scrollbar.height * flicker.visibleArea.heightRatio);
color: "#5E5E5E";
border {
width: 1;
color: "white";
}
anchors {
left: parent.left;
right: parent.right;
}
Binding { // Calculate handle's x/y position based on the content position of the Flickable
target: handle;
property: "y";
value: (flicker.visibleArea.yPosition * scrollbar.height);
when: (!dragger.drag.active);
}
Binding { // Calculate Flickable content position based on the handle x/y position
target: flicker;
property: "contentY";
value: (handle.y / scrollbar.height * flicker.contentHeight);
when: (dragger.drag.active);
}
MouseArea {
id: dragger;
anchors.fill: parent;
drag {
target: handle;
minimumX: handle.x;
maximumX: handle.x;
minimumY: 0;
maximumY: (scrollbar.height - handle.height);
axis: Drag.YAxis;
}
}
}
}
Just use it like this :
Flickable {
id: myFlick;
}
ScrollBar {
flicker: myFlick;
}
It can be moved with mouse, and moves automatically when Flickable is scrolled.