How to specify a rectangle from the CGPoint Start and End? - xamarin

I have a rectangle bounds (10, 20, 100, 200) and the CGPoints are StartPoint (0.5, 0.5) and EndPoints as (1, 1). From these points how needs to calculate the segments bounds ? I need to apply this bounds for CGGradient for start point and end points.
Eg Code :
GradientColor gradientColor1 = new GradientColor(){StartPoint = new CGPoint(0.5, 0), EndPoint= new CGPoint(0.5, 1)};
GradientStop stop1 = new GradientStop() { Color = UIColor.Red, Offset = 0.1f };
GradientStop stop2 = new GradientStop() { Color = UIColor.Blue, Offset = 0.9f };
can you please help me out of this?

Here an an example that will create a left to right linear gradient within the current CGContext.
using (var context = UIGraphics.GetCurrentContext ()) {
context.SaveState();
var startPoint = new CGPoint(rect.Left, 0);
var endPoint = new CGPoint(rect.Right, 0);
var components = new CGColor[] { UIColor.Red.CGColor, UIColor.Blue.CGColor };
using (var rgb = CGColorSpace.CreateDeviceRGB()) {
var gradient = new CGGradient(rgb, components);
context.DrawLinearGradient(gradient, startPoint, endPoint, CGGradientDrawingOptions.DrawsBeforeStartLocation);
};
context.RestoreState();
}
Changing the start and end points you can have the gradient paint right to left, up/down, diagonal, etc..

Related

Three.js: Rotate object with lookAt() while located at the current lookAt() position

I'm trying to implement a simple turn-around-and-move feature with Three.js. On mouse click, the object is supposed to first turn around and then move to the clicked location.
Codepen
The rotation is achieved with raycasting and lookAt(). It works by itself and it always works on the first click. If you remove the translation, it works continuously. The issue occurs when rotation and translation are implemented together. If you click a second time, after the object has moved to the previous clicked location, it doesn't rotate as expected. Depending on the mouse location it can flip to the other side without rotating at all.
Clarification: When you click the first time, notice how the object slowly and steadily turns around to face that direction? But the second time, after the object has moved, the rotation is quicker and/or flimsier or it simply flips over and there is no rotation at all. It depends on where you click in relation to the object.
I believe the issue stems from trying to implement lookAt while being located at the current lookAt location? If I stop the translation half way, the next rotation will work better. But of course I need it to go all the way.
I'm somewhat lost on how to proceed with this issue. Any help would be appreciated.
/*** Setup scene ***/
let width = 800
let height = 600
let scene
let renderer
let worldAxis
let box
let angle
let boxAxes
scene = new THREE.Scene()
worldAxis = new THREE.AxesHelper(200);
scene.add(worldAxis);
// Setup renderer
renderer = new THREE.WebGLRenderer({alpha: true, antialias: true})
renderer.setPixelRatio(window.devicePixelRatio)
renderer.setSize(width, height)
document.body.appendChild(renderer.domElement)
// Setup camera
const camera = new THREE.OrthographicCamera(
width / - 2, // left
width / 2, // right
height / 2, // top
height / - 2, // bottom
0, // near
1000 ); // far
camera.position.set(0, 0, 500)
camera.updateProjectionMatrix()
// Setup box
let geometry = new THREE.BoxGeometry( 15, 15, 15 );
let material = new THREE.MeshBasicMaterial( { color: "grey" } );
box = new THREE.Mesh( geometry, material );
box.position.set(100, 150, 0)
box.lookAt(getPointOfIntersection(new THREE.Vector2(0, 0)))
addAngle()
boxAxes = new THREE.AxesHelper(50);
box.add(boxAxes)
scene.add(box)
renderer.render(scene, camera);
/*** Setup animation ***/
let animate = false
let currentlyObservedPoint = new THREE.Vector2();
let rotationIncrement = {}
let translationIncrement = {}
let frameCount = 0
document.addEventListener('click', (event) => {
let mousePosForRotate = getMousePos(event.clientX, event.clientY)
rotationIncrement.x = (mousePosForRotate.x - currentlyObservedPoint.x)/100
rotationIncrement.y = (mousePosForRotate.y - currentlyObservedPoint.y)/100
let mousePosForTranslate = getMousePosForTranslate(event)
translationIncrement.x = (mousePosForTranslate.x - box.position.x)/100
translationIncrement.y = (mousePosForTranslate.y - box.position.y)/100
animate = true
})
function animationLoop() {
if (animate === true) {
if (frameCount < 100) {
rotate()
} else if (frameCount < 200) {
translate()
} else {
animate = false
frameCount = 0
}
frameCount++
renderer.render(scene, camera)
}
requestAnimationFrame(animationLoop)
}
function rotate() {
currentlyObservedPoint.x += rotationIncrement.x
currentlyObservedPoint.y += rotationIncrement.y
let pointOfIntersection = getPointOfIntersection(currentlyObservedPoint)
box.lookAt(pointOfIntersection)
addAngle()
}
function translate() {
box.position.x += translationIncrement.x
box.position.y += translationIncrement.y
}
function getMousePos(x, y) {
let mousePos = new THREE.Vector3(
(x / width) * 2 - 1,
- (y / height) * 2 + 1,
0)
return mousePos
}
function getMousePosForTranslate(event) {
let rect = event.target.getBoundingClientRect();
let mousePos = { x: event.clientX - rect.top, y: event.clientY - rect.left }
let vec = getMousePos(mousePos.x, mousePos.y)
vec.unproject(camera);
vec.sub(camera.position).normalize();
let distance = - camera.position.z / vec.z;
let pos = new THREE.Vector3(0, 0, 0);
pos.copy(camera.position).add(vec.multiplyScalar(distance));
return pos
}
function getPointOfIntersection(mousePos) {
let plane = new THREE.Plane(new THREE.Vector3(0, 0, 1), 0);
let pointOfIntersection = new THREE.Vector3()
const raycaster = new THREE.Raycaster();
raycaster.setFromCamera(mousePos, camera)
raycaster.ray.intersectPlane(plane, pointOfIntersection)
return pointOfIntersection
}
function addAngle() {
let angle = box.rotation.x - 32
box.rotation.x = angle
}
animationLoop()
<script src='https://cdnjs.cloudflare.com/ajax/libs/three.js/105/three.min.js'></script>

Skia / SkiaSharp - Rotating shapes around their own vertical axis

I generate the scene above using the OnDraw method below:
protected override void OnDraw(SKCanvas canvas, int width, int height)
{
int i = 0;
int step = 0;
List<SKRect> rects = new List<SKRect>();
// get the 2D equivalent of the 3D matrix
var rotationMatrix = rotationView.Matrix;
// get the properties of the rectangle
var length = Math.Min(width / 6, height / 6);
canvas.Clear(EffectMedia.Colors.XamarinLightBlue);
foreach (var n in numbers)
{
var rect = new SKRect(0 + step, 0, 100 + step, 100);
rects.Add(rect);
step += 120;
}
//var sideHoriz = rotationMatrix.MapPoint(new SKPoint(0, 1)).Y > 0;
var sideVert = rotationMatrix.MapPoint(new SKPoint(1, 0)).X > 0;
var paint = new SKPaint
{
Color = sideVert ? EffectMedia.Colors.XamarinPurple : EffectMedia.Colors.XamarinGreen,
Style = SKPaintStyle.Fill,
IsAntialias = true
};
// first do 2D translation to the center of the screen
canvas.Translate((width - (120 * numbers.Count)) / 2, height / 2);
// The following line is disabled because it makes the whole canvas rotate!
// canvas.Concat(ref rotationMatrix);
foreach (var n in numbers)
{
canvas.RotateDegrees((float)-3);
canvas.DrawRoundRect(rects[i], 30, 30, paint);
var shadow = SKShader.CreateLinearGradient(
new SKPoint(0, 0), new SKPoint(0, length * 2),
new[] { paint.Color.WithAlpha(127), paint.Color.WithAlpha(0) },
null,
SKShaderTileMode.Clamp);
var paintShadow = new SKPaint
{
Shader = shadow,
Style = SKPaintStyle.Fill,
IsAntialias = true,
BlendMode = SKBlendMode.SoftLight
};
foreach (var r in rects)
{
r.Offset(0, 105);
canvas.DrawRoundRect(r, 30, 30, paintShadow);
}
i++;
}
}
The idea is to make all those rounded boxes rotate (vertically) around their own axis.
I tried using SKPath + Transform, saving&restoring the rotationMatrix and/or the canvas but I can't find a way to have 6 rotating boxes ( canvas.Concat(ref rotationMatrix); makes the whole canvas rotate [*]).
Do you have any hint on how that can be achieved?
Note [*]: there's a call to rotationView.RotateYDegrees(5) every X milliseconds to update the rotationMatrix used by OnDraw.
This is what I'd like to achieve, any hints / directions would be really appreciated... :-)
The following piece of code rotates those shapes around their Z-axis:
canvas.Save();
canvas.RotateDegrees(degrees, rects[i].MidX, rects[i].MidY);
canvas.DrawRoundRect(rects[i], 30, 30, paint);
canvas.Restore();
Thanks

Object rotating while travelling along a curve path

I am creating a flight animation, I have objects (airplanes) moving along a curve path. My problem is some of my objects are rotating while travelling along the curve path.
Screenshot
function createPlane(image) {
return new THREE.Mesh(
new THREE.PlaneGeometry(5, 5),
new THREE.MeshPhongMaterial({ map: new THREE.TextureLoader().load('textures/planes/' + image), side: THREE.DoubleSide, transparent: true })
);
}
// this is how we get the line.vertices
// var curve = new THREE.Curve();
// line.vertices = curve.getPoints(50);
function animatePlane(plane, line, key) {
if (key > 1) {
key = 1;
} else {
key = Math.round(key * 100) / 100;
}
var curve = new THREE.CatmullRomCurve3(line.vertices), up = new THREE.Vector3(0, 1, 0), axis = new THREE.Vector3();
var angle, duration = 300, position = curve.getPointAt(key), tangent = curve.getTangentAt(key).normalize();
// rotation
axis.crossVectors(up, tangent).normalize();
angle = Math.acos(up.dot(tangent));
plane.quaternion.setFromAxisAngle(axis, angle);
// position
new TWEEN.Tween(plane.position)
.to({ x: position.x, y: position.y, z: position.z }, duration)
.onUpdate(function() {
plane.position.set(this.x, this.y, this.z);
})
.onComplete(function() {
if (key < 1) {
key += 0.02;
} else {
key = 0;
}
animatePlane(plane, line, key);
})
.start();
}
// lines
var point = latLongToVector3(14.512274, 121.016508, radius, 0), // Philippines
line1 = createCurveLine(createSphereArc(point, latLongToVector3(2.745364, 101.707079, radius, 0), 0.3), green, 'MALAYSIA');
animatePlane(createPlane('airplane.png'), line1, 0);
The above code is how I create and what moves my objects along the curve path.
Note that curve paths were dynamically created, from the screenshot above it is from Philippines going to other countries but it could be from other countries.
Curve paths may lie in different part of the earth, for example, from Australia (which is at the bottom part of the earth) going to other countries.
Is there anything I can do to always keep my airplane upright as it is moving along the curve path?
I got it working now by using Frenet–Serret formulas (TNB Frame).
I used Tangent, Normal, and Binormal to create a matrix (Matrix4) then used that matrix to set the rotation of planes by using .setRotationFromMatrix().
This is now the code to animate the planes:
function animatePlane(plane, line, key) {
if (key > 1) {
key = 1;
} else {
key = Math.round(key * 100) / 100;
}
var curve = new THREE.CatmullRomCurve3(line.vertices), matrix = new THREE.Matrix4();
var duration = 300, position = curve.getPointAt(key);
if ((key > 0) && (key < 1)) {
var D = curve.getPointAt(1).normalize(), X = plane.position.clone().normalize();
var T = position.clone().normalize(), B = curve.getTangentAt(key), N = new THREE.Vector3();
N.crossVectors(D, T).normalize();
matrix.set(
N.x, B.x, T.x, X.x,
N.y, B.y, T.y, X.y,
N.z, B.z, T.z, X.z,
0, 0, 0, 1
);
plane.setRotationFromMatrix(matrix);
}
new TWEEN.Tween(plane.position)
.to({ x: position.x, y: position.y, z: position.z }, duration)
.onUpdate(function() {
plane.position.set(this.x, this.y, this.z);
})
.onComplete(function() {
if (key < 1) {
key += 0.02;
} else {
key = 0;
}
animatePlane(plane, line, key);
})
.start();
}
and added this to make the plane above the curve path:
var plane1 = createPlane('airplane.png');
plane1.renderOrder = 1;
plane1.onBeforeRender = function(renderer) {
renderer.clearDepth();
}
animatePlane(plane1, line1, 0);

How to rotate Object3d around X,Y & Z axis without having the axes to flip or cause gimbal lock?

Probably threejs's rotation question no 9000 , i simply want to have 3 UI buttons to incrementally rotate an object 90 degrees in either x,y & z direction with every click on each, how hard could it be ?
Using regular rotation methods which uses euler will cause gimbal lock, and using quanternions the axes will flip randomly in which z-axis will be y-axis at one point or another.
please have a look at my working demo : http://grutex.com/webgl/demos/help/
Edit: here is the rotation functions part :
function z_rotate(){
var startAngle = 0;
var start = {angle: startAngle};
var end = {angle: startAngle + 90};
var lastAngle=0;
var tween = new TWEEN.Tween(start)
.to(end, 400)
.easing( TWEEN.Easing.Quadratic.Out )
.onUpdate(function(){
startAngle=this.angle;
my_object.rotateOnAxis(new THREE.Vector3(0,0,1),degreeToRadians(startAngle-lastAngle));
lastAngle=startAngle;
})
.start();
}
function x_rotate(){
var startAngle = 0;
var start = {angle: startAngle};
var end = {angle: startAngle + 90};
var lastAngle=0;
var tween = new TWEEN.Tween(start)
.to(end, 400)
.easing( TWEEN.Easing.Quadratic.Out )
.onUpdate(function(){
startAngle=this.angle;
my_object.rotateOnAxis(new THREE.Vector3(1,0,0),degreeToRadians(startAngle-lastAngle));
lastAngle=startAngle;
})
.start();
}
function y_rotate(){
var startAngle = 0;
var start = {angle: startAngle};
var end = {angle: startAngle + 90};
var lastAngle=0;
var tween = new TWEEN.Tween(start)
.to(end, 400)
.easing( TWEEN.Easing.Quadratic.Out )
.onUpdate(function(){
startAngle=this.angle;
my_object.rotateOnAxis(new THREE.Vector3(0,1,0),degreeToRadians(startAngle-lastAngle));
lastAngle=startAngle;
})
.start();
}
As #WestLangley pointed out, i should attach and detach the 3d object to a parent pivot point (THREE.Object3D), attaching the 3d object to the pivot point before the tween start and detaching the pivot point after tween completion and resetting its rotation to (0,0,0)
#WestLangley answer : Three.js: Adding and Removing Children of Rotated Objects
New modified rotation function :
var axis_x = new THREE.Vector3( 1, 0, 0 ).normalize();
function x_rotate(){
pivot_attach();
var startAngle = 0;
var start = {angle: degreeToRadians(startAngle)};
var end = {angle: degreeToRadians(startAngle + 90)};
var lastAngle=0;
var tween = new TWEEN.Tween(start)
.to(end, 400)
.easing( TWEEN.Easing.Quadratic.Out )
.onUpdate(function(){
startAngle=this.angle;
pivot.rotateOnAxis(axis_x,startAngle-lastAngle);
lastAngle=startAngle;
})
.start().onComplete(pivot_detach);
}
function pivot_attach() {
pivot.updateMatrixWorld();
THREE.SceneUtils.attach( my_object, scene, pivot );
}
function pivot_detach() {
pivot.updateMatrixWorld();
my_object.updateMatrixWorld(); // if not done by the renderer
THREE.SceneUtils.detach( my_object, pivot, scene );
pivot.rotation.set( 0, 0, 0 );
}
and don't forget to add the pivot to the scene "scene.add(pivot);"

XNA 4 VertexPositionTexture triangleStrip sporadically disappearing

I am drawing a traingleStrip using VertexPositionTexture and BasicEffect that extends from the first person perspective of the screen out a certain distance on the Z axis.
In a loop I pass start and end vectors to this code to create my vertices.
public VertexPositionTexture[] vertices = new VertexPositionTexture[4];
private int xPos = 4;
public waypointLineSegment(Vector3 startPoint, Vector3 endPoint)
{
this.texture = texture1;
vertices[0].Position = new Vector3(endPoint.X - xPos, endPoint.Y, endPoint.Z); //Upper Left Point
vertices[0].TextureCoordinate = new Vector2(0, 1);
vertices[1].Position = new Vector3(startPoint.X - xPos, endPoint.Y, startPoint.Z); //Lower Left point
vertices[1].TextureCoordinate = new Vector2(0, 0);
vertices[2].Position = new Vector3(endPoint.X + xPos, endPoint.Y, endPoint.Z); //Upper Right Point
vertices[2].TextureCoordinate = new Vector2(1, 1);
vertices[3].Position = new Vector3(startPoint.X + xPos, endPoint.Y, startPoint.Z); //Lower Right Point
vertices[3].TextureCoordinate = new Vector2(1, 0);
}
I initialize like this:
protected override void Initialize()
{
graphics.GraphicsDevice.RasterizerState = RasterizerState.CullNone;
basicEffect = new BasicEffect(graphics.GraphicsDevice);
base.Initialize();
}
I render the plane in this way:
Vector3 transformedReference = Vector3.Transform(new Vector3(0, 0, 10), aRotationInt);
Vector3 cameraLookat = firstPersonVector + transformedReference;
view = Matrix.CreateLookAt(firstPersonVector, cameraLookat, Vector3.Up);
basicEffect.View = view;
foreach (EffectPass pass in basicEffect.CurrentTechnique.Passes)
{
pass.Apply();
graphics.GraphicsDevice.DrawUserPrimitives(PrimitiveType.TriangleStrip, allVertices, 0, 2);
}
This works great. But, when I apply a rotation to the view, the strip will disappear every once in a while. Then it will reappear with a single degree of more or less rotation applied.
I cannot find a pattern. It might happen at 37 degrees or 315 etc. I have set the GraphicsDevice RasterizerState to CullMode.None. Can anyone help?:

Resources