How to draw an arc between two known points in Qt? - c++

I want to draw an arc between point B to point D and it should touch to point E. ( I want to draw AND gate symbol )
I tried this way
QPainterPath path;
path.arcTo(60,30,46,100,30*16,120*16); // ( x,y,width,height, startAngle,spanAngle)
But it is drawing full circle and not in proper place.
Currently it is looking like this
After getting suggestion I tried like this :
path.moveTo(106, 80);
path.arcTo(76.0, 30.0, 60.0, 100.0, 90.0, -180.0);
How to get rid of that vertical line ( inside AND gate ) ?
Why it is appearing ?

I think you misunderstood the parameters for arcTo, especially the bounding rectangle.
Given your image, you should move path to (106, 80) (center of the bounding rectangle)
path.moveTo(106, 80);
The bounding rectangle of the arc should look like this:
x: 76
y: 30
width: 60
height: 100
The arc itsel should have a start angle at 90° and should span 180° in negative direction.
This results in:
path.arcTo(76.0, 30.0, 60.0, 100.0, 90.0, -180.0);
Update
arcTo
path.moveTo(106, 30);
path.cubicTo(QPointF(156.0, 30.0), QPointF(156.0, 130.0), QPointF(106.0, 130.0));

Related

QT Rotating object problems

I am currently working on a project that has a spinning object. The object's rotation speed is changed and its direction of rotation is changed (forwards/backward). After doing some research I came across RotationAnimator on the QT documentation, it seems to have everything I need and I can easily reverse direction. The only problem is that is in QML. My program is entirely in Qt's C++.
I tried an attempt at using QVariantAnimation (documentation here)but every way I have tried there is always some problem. Changing speed is relatively easy, just fooAnimation->setLoop(-1) (loop indefinitely) and change the duration of the animation. The problem I run into is looping forwards AND backward. Or in other terms, changing direction. I have attempted to change the direction of the animation using fooAnimation->setDirection(<Direction goes here>), but if I run the animation in reverse long enough it will stop the animation entirely. It will only loop forwards. That's the key part of the problem.
So I tried alternative ways to change the direction. One idea was changing the endValue from 360 degrees to -360 using fooAnimation->setEndValue(<value goes here>) when I want to reverse, but this has an adverse effect. If I were to swap the direction, the current rotation: let's say it's 110, will be inverted. So now it suddenly jumps to -110 and starts from there. This leads to very jittery rotation as every time a direction swap happens it teleports the rotation of the object.
This seems like a pretty simple thing to implement, rotating an object that can have its rotation speed and direction changed, but I just can't wrap my head around how I could implement it with animations.
A side note here is that all this is being done in Qt 3D so I can grab rotation and other properties from the rotating object (or in this case its QTransform)
There are multiple ways to achieve this effect. On this Qt/QML demo, I used an approach based on NumberAnimation to rotate the cube.
These are the key ideas behind it:
The cube has a Transform component that defines the 4x4 matrix that Qt3D uses to place the cube in the world using predefined rotation and scale values. The NumberAnimation simply changes the rotation angle used on this transform to make the cube rotate on the screen;
The rotation speed is defined by the duration property of that NumberAnimation: a smaller value makes the cube rotate faster. The cube takes 5 seconds to rotate from 0 to 360 degrees;
Changing the rotation speed means recalculating the duration of the animation based on how far away from 0 degrees the current rotation angle is. The animation needs to be restarted whenever we change ANY NumberAnimation properties;
When the direction of the rotation is changed, we store the current rotation angle in cubeTransform.startAngle and update the to and from properties of NumberAnimation along with duration so the cube can be rotated in a new direction starting from the current angle.
I added a few buttons to the UI to change the direction and speed in runtime:
main.qml:
import QtQuick 2.12 as QQ2
import QtQuick.Controls 2.12
import QtQuick.Scene3D 2.12
import Qt3D.Core 2.0
import Qt3D.Render 2.0
import Qt3D.Input 2.0
import Qt3D.Extras 2.0
import Qt3D.Logic 2.0
QQ2.Item {
id: windowId
width: 800
height: 800
property real cubeScale: 100.0
property int rotationSpeed: 5000
property real speedFactor: 1.0
property bool clockwiseRotation: true
Scene3D {
id: scene3D
anchors.fill: parent
aspects: ["input", "logic"]
focus: true
cameraAspectRatioMode: Scene3D.AutomaticAspectRatio
Entity {
id: rootEntity
Camera {
id: camera
projectionType: CameraLens.PerspectiveProjection
fieldOfView: 45
nearPlane : 0.1
farPlane : 100000.0
position: Qt.vector3d(0.0, 0.0, 500.0)
viewCenter: Qt.vector3d(0.0, 0.0, 0.0)
upVector: Qt.vector3d( 0.0, 1.0, 0.0 )
}
components: [
RenderSettings {
activeFrameGraph: ForwardRenderer {
camera: camera
clearColor: "silver"
}
},
InputSettings { }
]
Entity {
id: lightEntity
enabled: true
DirectionalLight {
id: infiniteLight
color: "white"
intensity: 1.0
worldDirection: Qt.vector3d(0, 0, 0)
}
Transform {
id: infiniteLightTransform
translation: Qt.vector3d(0.0, 0.0, 500.0)
}
components: [ infiniteLight, infiniteLightTransform ]
}
Entity {
id: cubeEntity
CuboidMesh {
id: cubeMesh
}
PhongMaterial {
id: cubeMaterial
ambient: "red"
diffuse: Qt.rgba(1.0, 1.0, 1.0, 1.0)
}
Transform {
id: cubeTransform
property real angle: 0.0
property real startAngle: 0.0
matrix: {
var m = Qt.matrix4x4();
m.rotate(cubeTransform.angle, Qt.vector3d(0, 1, 0));
m.translate(Qt.vector3d(0, 0, 0));
m.scale(windowId.cubeScale, windowId.cubeScale, windowId.cubeScale);
return m;
}
}
components: [ cubeMesh, cubeMaterial, cubeTransform ]
}
QQ2.NumberAnimation {
id: cubeAnimation
property int startPos: {
if (cubeTransform.startAngle === 0)
{
if (windowId.clockwiseRotation === true)
return 0;
return 360;
}
return cubeTransform.startAngle;
}
property int endPos: (windowId.clockwiseRotation === true) ? 360 : 0
target: cubeTransform
property: "angle"
duration: windowId.rotationSpeed / windowId.speedFactor
from: cubeAnimation.startPos
to: cubeAnimation.endPos
loops: 1
running: true
onStarted: {
console.log("onStarted");
}
onFinished: {
console.log("onFinished");
// reset the starting angle
cubeTransform.startAngle = 0;
// reset the duration of the animation
cubeAnimation.duration = windowId.rotationSpeed / windowId.speedFactor;
// the animation is currently stopped, run it again
cubeAnimation.running = true;
}
}
}
}
QQ2.Row {
anchors.fill: parent
Button {
text: "Change Direction"
onClicked: {
// pause the animation
cubeAnimation.pause();
// invert rotation
windowId.clockwiseRotation = !windowId.clockwiseRotation;
// store current angle as the starting angle for the rotation
cubeTransform.startAngle = cubeTransform.angle;
// update the remaining time to avoid changing the rotation speed
let progressPercentage = cubeTransform.startAngle / 360.0;
if (windowId.clockwiseRotation)
progressPercentage = 1.0 - progressPercentage;
cubeAnimation.duration = (windowId.rotationSpeed / windowId.speedFactor) * progressPercentage;
// restart the animation from this angle using a new direction
cubeAnimation.restart();
}
}
Button {
text: "1x"
highlighted: (windowId.speedFactor === 1.0)
onClicked: changeSpeed(1.0)
}
Button {
text: "2x"
highlighted: (windowId.speedFactor === 2.0)
onClicked: changeSpeed(2.0)
}
}
function changeSpeed(newSpeed) {
windowId.speedFactor = newSpeed;
// pause the animation
cubeAnimation.pause();
// store current angle as the starting angle for the rotation
cubeTransform.startAngle = cubeTransform.angle;
// update the remaining time to avoid changing the rotation speed
let progressPercentage = cubeTransform.startAngle / 360.0;
if (windowId.clockwiseRotation)
progressPercentage = 1.0 - progressPercentage;
cubeAnimation.duration = (windowId.rotationSpeed / windowId.speedFactor) * progressPercentage;
// restart the animation from this angle using a new direction
cubeAnimation.restart();
}
}

CAShapeLayer / CGPath - Draw Donut

How can I draw a perfect donut with inner and outer radius with a CAShapeLayer?
Or better to ask: How to draw a Circle with a hole in it, so that the stroke is two seperate lines. One on the inner and one on the outer circle. All I've achieved so far is that the stroke of the inner and outer circle is connected, which I want to avoid:
CGPathAddArc( _path, NULL, _center.x, _center.y, 100, 0, M_PI * 2.0f, NO);
CGPathRef temp = CGPathCreateCopyByStrokingPath(_path, &_transform, 10, kCGLineCapButt, kCGLineJoinMiter, 10);
_path = CGPathCreateMutableCopy(temp);
You can create a path that has two circles (the outer and the inner radius) added to it. Then you can set the fillMode of the shape layer to kCAFillRuleEvenOdd.

Parent coordinate given a CCNode local coordinate

Is there any cocos2d function that returns the parent coordinate given a node local coordinate? It must be quite a common use case, but I've not found any native cocos2d function. Is there any?
I guess it's something like this. NOTE, I haven't tested this one. ;)
-(CGPoint) nodeToParent: (CGPoint) localPoint
{
CGFloat phi = -self.rotation * B2_pi / 180;
return ccpAdd(self.position, ccpRotateByAngle(localPoint, ccp(0, 0), phi));
}
As m.ding said ... parent->ConvertToNodeSpace() .....
Here's explanation for you so you know when to do what ?
convertToWorldSpace(const CCPoint& nodePoint) converts on-node coords to SCREEN coordinates.
Lets we have layerA with anchor point and position (0,0) attached to screen and have a sprite on this layer at point (100, 100).
What will be SCREEN coords of sprite? - (100, 100)
Lets we moved layerA to point (- 50, - 20). What will be SCREEN coords of sprite? - (100 - 50, 100 - 20), i.e. (50, 80) - that's what convertToWorldSpace returns to us if we call layerA->convertToWorldSpace(ccp(100, 100)).
As for convertToWorldSpaceAR - will return the position relatevely to anchor point: so if our scene - root layer has AP (0.5f, 0.5f) - default, convertToWorldSpaceAR should return position relatively to screen center. I have used convertToNodeSpace
convertToNodeSpace(const CCPoint& worldPoint) - converts SCREEN coords to NODE's local. I.e. if for our example with moved layer call:
layerA->convertToNodeSpace(ccp(50, 80)) - that should return (100, 100) - our sprite on-node coords.
convertToNodeSpaceAR - the same logic as for convertToWorldSpaceAR
assume your parent node is
CCSprite* parent;
you can use:
parent->convertToNodeSpace();
I guess that
-(CGPoint) convertToWorldSpace:(CGPoint)pt
could do the trick, take a look here.
It looks like you are on the right track. [node position] should give the position of the node in the parent's coordinate space, so if you have a local point that is offset from the [node position] then you need to do add the offset like you have done. I'm not sure the ccpRotateByAngle is the right method to do that but you'll just have to test it and find out!

Raphael.js - scale an element over time

Very new to using Raphael.js
I'm looking at the tutorials and I am able to create a circle.
But how would I scale the circle to double the size over two seconds.
Assuming your circle is created like:
var circle = paper.circle(50, 40, 10);
You can scale it up over two seconds like:
circle.animate({
transform: 's2'
}, 2000, 'easeIn');
You could also just double its radius if it is fixed.

Can't create an OgreBullet Trimesh

I'm using Ogre and Bullet for a project and I currently have a first person camera set up with a Capsule Collision Shape. I've created a model of a cave (which will serve as the main part of the level) and imported it into my game. I'm now trying to create an OgreBulletCollisions::TriangleMeshCollisionShape of the cave.
The code I've got so far is this but it isn't working. It compiles but the Capsule shape passes straight through the cave shape. Also I have debug outlines on and there are none being drawn around the cave mesh.
Entity *cave = mSceneMgr->createEntity("Cave", "pCube1.mesh");
SceneNode *caveNode = mSceneMgr->getRootSceneNode()->createChildSceneNode();
caveNode->setPosition(0, 10, 250);
caveNode->setScale(10, 10, 10);
caveNode->rotate(Quaternion(0.5, 0.5, -0.5, 0.5));
caveNode->attachObject(cave);
OgreBulletCollisions::StaticMeshToShapeConverter *smtsc = new OgreBulletCollisions::StaticMeshToShapeConverter();
smtsc->addEntity(cave);
OgreBulletCollisions::TriangleMeshCollisionShape *tri = smtsc->createTrimesh();
OgreBulletDynamics::RigidBody *caveBody = new OgreBulletDynamics::RigidBody("cave", mWorld);
caveBody->setStaticShape(tri, 0.1, 0.8);
mShapes.push_back(tri);
mBodies.push_back(caveBody);
Any suggestions are welcome.
To clarify. It compiles but the Capsule shape passes straight through the cave shape. Also I have debug outlines on and there are none being drawn around the cave mesh
I used your code and got exactly the same result - my vehicle passed right through the trimesh.
Looking at the examples in:
ogrebullet/Demos/src/OgreBulletListener.cpp
it would seem to be that instead of calling:
caveBody->setStaticShape(tri, 0.1, 0.8);
you instead need to invoke:
caveBody->setStaticShape(caveNode, tri, 0.1, 0.8, Ogre::Vector3( position_x, position_y, position_z ));`
When I made this change, the collisions work as expected
In the end I had to use a btScaledBvhTriangleMeshShape. So my code now looks like
OgreBulletCollisions::StaticMeshToShapeConverter *smtsc =
new OgreBulletCollisions::StaticMeshToShapeConverter();
smtsc->addEntity(cave);
OgreBulletCollisions::TriangleMeshCollisionShape *tri = smtsc->createTrimesh();
OgreBulletDynamics::RigidBody *caveBody = new OgreBulletDynamics::RigidBody("cave", mWorld);
btScaledBvhTriangleMeshShape *triShape = new btScaledBvhTriangleMeshShape((btBvhTriangleMeshShape*)(tri->getBulletShape()), btVector3(150, 150, 150));
caveBody->setStaticShape(triShape, 0.0, 5, Vector3::ZERO, rotationQuaternion);
caveBody->setDebugDisplayEnabled(true);