Okay, so for an assignment I have to make a function crop() that will crop a picture in test_crop(). Here's the code.
def crop(pict, startX, startY, endX, endY):
width = endX - startX + 1
height = endY - startY + 1
canvas = makeEmptyPicture(width, height)
targetX = 100
for sourceX in range(45,200):
targetY = 100
for sourceY in range(25,200):
color = getColor(getPixel(pict, sourceX, sourceY))
setColor(getPixel(canvas, targetX, targetY), color)
targetY = targetY + 1
targetX = targetX + 1
show(pict)
show(canvas)
return canvas
def test_crop():
setMediaPath()
pict = makePicture("redMotorcycle.jpg")
croppedPict = crop(pict, 100, 100, 700, getHeight(pict)/2)
show(pict)
show(croppedPict)
The error occurs on this piece of code:
setColor(getPixel(canvas, targetX, targetY), color)
It says "Inappropriate argument (of correct type. An error occured attempting to pass an argument to a function."
Can someone please tell me what is wrong with it? It is the same code from the textbook.
This works. I cannot work out why you are getting that error, it may be in how you are getting your values for startX, startY, endX, endY in
def crop(pict, startX, startY, endX, endY):
def crop(pict):
width = getWidth(pict)
height = getHeight(pict)
canvas = makeEmptyPicture(width, height)
targetX = 100
for sourceX in range(45,200):
targetY = 100
for sourceY in range(25,200):
color = getColor(getPixel(pict, sourceX, sourceY))
setColor(getPixel(canvas, targetX, targetY),color)
targetY = targetY + 1
targetX = targetX + 1
show(pict)
show(canvas)
return canvas
The original image:
The cropped image:
This works, beyond this, you will need to provide more information about your code.
Related
The problem is follow:
when the object has a positive angle and if negative angle is clicked - it follows logic and makes a counterclockwise rotation instead of clockwise rotation like it requires and vice versa. It doesn`t look like rotation of a unit in RTS games. How to fix it?
`
var object = document.createElement("div");
object.style.backgroundColor = "red";
object.style.width = "50px";
object.style.height = "50px";
object.style.position = "absolute";
object.style.transition = "transform 3s";
document.body.appendChild(object);
function action(event){
mousePosition = {
x : event.clientX - (object.offsetWidth/2),
y : event.clientY - (object.offsetHeight/2)
};
let unitBoundingRect = object.getBoundingClientRect();
let unitCenter = {
x: unitBoundingRect.left + unitBoundingRect.width/2,
y: unitBoundingRect.top + unitBoundingRect.height/2
}
let angle = Math.atan2(event.pageX - unitCenter.x, - (event.pageY - unitCenter.y))*(180 / Math.PI);
object.style.transform = "translate(" + mousePosition.x + "px," + mousePosition.y + "px) rotate(" + angle + "deg)";
object.innerText = Math.floor(angle);
}
window.addEventListener("click",action,false);
`
I know Rectangle is axis aligned, that's fine, I just can't figure out how to create a rectangle so it is always encompassing the entire sprite, regardless of rotation. I have been looking everywhere for an answer but I can't get a straight one anywhere.
For example:
Assuming the origin point is the middle of the texture, how can I go about this?
EDIT
Fiddling around with it a little, I've gotten this far:
public Rectangle BoundingBox
{
get
{
var cos = Math.Cos(SpriteAngle);
var sin = Math.Cos(SpriteAngle);
var t1_opp = Width * cos;
var t1_adj = Math.Sqrt(Math.Pow(Width, 2) - Math.Pow(t1_opp, 2));
var t2_opp = Height * sin;
var t2_adj = Math.Sqrt(Math.Pow(Height, 2) - Math.Pow(t2_opp, 2));
int w = Math.Abs((int)(t1_opp + t2_opp));
int h = Math.Abs((int)(t1_adj + t2_adj));
int x = Math.Abs((int)(Position.X) - (w / 2));
int y = Math.Abs((int)(Position.Y) - (h / 2));
return new Rectangle(x, y, w, h);
}
}
(doing this off the top of my head.. but the principle should work)
Create a matrix to rotate around the center of the rectangle - that is a translate of -(x+width/2), -(y+height/2)
followed by a rotation of angle
followed by a translate of (x+width/2), (y+height/2)
Use Vector2.Transform to transform each corner of the original rectangle
Then make a new rectangle with
x = min(p1.x, p2.x, p3.x, p4.x)
width = max(p1.x, p2.x, p3.x, p4.x) - x
similar for y
Sorry this is coming so late, but I figured this out a while ago and forgot to post an answer.
public virtual Rectangle BoundingBox
{
get
{
int x, y, w, h;
if (Angle != 0)
{
var cos = Math.Abs(Math.Cos(Angle));
var sin = Math.Abs(Math.Sin(Angle));
var t1_opp = Width * cos;
var t1_adj = Math.Sqrt(Math.Pow(Width, 2) - Math.Pow(t1_opp, 2));
var t2_opp = Height * sin;
var t2_adj = Math.Sqrt(Math.Pow(Height, 2) - Math.Pow(t2_opp, 2));
w = (int)(t1_opp + t2_opp);
h = (int)(t1_adj + t2_adj);
x = (int)(Position.X - (w / 2));
y = (int)(Position.Y - (h / 2));
}
else
{
x = (int)Position.X;
y = (int)Position.Y;
w = Width;
h = Height;
}
return new Rectangle(x, y, w, h);
}
}
This is it here. In my work in the edit, I accidentally had Math.Cos in the sin variable, which didn't help.
So it's just basic trigonometry. If the textures angle is something other than zero, calculate the sides of the two triangles formed by the width and the height, and use the sides as the values for the width and the height, then center the rectangle around the texture. If that makes sense.
Here's a picture to help explain:
Here's a gif of the final result:
I have an svg with multiple objects in it. On selecting a checkbox i would like to zoom into the appropriate objects. I've come to something like the code below but zooming and positions are still not accurate. Can some point me out how i could accomplish this?
d3.selectAll('g.active')
.each(function(d, i) {
var bounds = this.getBoundingClientRect();
boundsLeft.push(bounds.left);
boundsRight.push(bounds.right);
boundsTop.push(bounds.top);
boundsBottom.push(bounds.bottom);
});
var top = Math.min.apply(Math, boundsTop);
var bottom = Math.max.apply(Math, boundsBottom) ;
var right = Math.max.apply(Math, boundsRight) ;
var left = Math.min.apply(Math, boundsLeft);
var bounds = [[left, top], [right, bottom]],
dx = bounds[1][0] - bounds[0][0],
dy = bounds[1][1] - bounds[0][1],
x = (bounds[0][0] + bounds[1][0]) / 2,
y = (bounds[0][1] + bounds[1][1]) / 2,
scale = Math.max(0.6, Math.min(8, 0.9 / Math.max(dx / width, dy / height))),
translate = [(width / 2) - (scale * x), (height / 2) - (scale * y)];
vis.transition()
.duration(750)
.call(zoom.translate([((dx * -scale) + (width / 2)), ((dy * -scale) + height / 2)]).scale(scale).event);
I'm making a top-down shooter and the player's gun is offset from the coordinates of the object. I'm using GameMaker:Studio, so the x and y coords are the center of the object. The offset of the image is set here:
bullet_offset_x = 30;
bullet_offset_y = 28;
And here is the code for shooting the gun:
var xpos = x + (bullet_offset_x * cos(degtorad(direction))) - (bullet_offset_y * sin(degtorad(direction)));
var ypos = y + (bullet_offset_x * sin(degtorad(direction))) + (bullet_offset_y * cos(degtorad(direction)));
var flash = instance_create(xpos, ypos, obj_flash);
with (flash){
direction = other.direction;
image_angle = other.direction;
}
I'm using the following formula for placing the muzzle flash:
x' = xcos(angle) - ysin(angle)
y' = xsin(angle) + ycos(angle)
Therefore:
xpos = x + x' and ypos = x + y'
However, when I run the code, the muzzle flash is correctly positioned when the angle is 0/360, but is off otherwise. Am I calculating this wrong?
IMAGES:
Correct
Incorrect
You need to use lengthdir_x and lengthdir_y functions, like:
var xpos = x + lengthdir_x(offset_distance, offset_angle + image_angle); // or direction
var ypos = y + lengthdir_y(offset_distance, offset_angle + image_angle);
var flash = instance_create(xpos, ypos, obj_flash);
flash.direction = direction;
flash.image_angle = direction;
little example here
To calculate the values to be substituted into the formula, you can use this program.
Originally it was made in Russian, but I have translated it into English. My English is terrible, but I hope you will be able to understand it.
upd: Example with offsets:
var delta_x = 60;
var delta_y = -70;
var angle = point_direction(0, 0, delta_x, delta_y);
var distance = point_distance(0, 0, delta_x, delta_y);
var xpos = x + lengthdir_x(distance, image_angle + angle);
var ypos = y + lengthdir_y(distance, image_angle + angle);
var obj = instance_create(xpos, ypos, obj_flash);
obj.image_angle = image_angle;
When your sprite has an angle of 0, your muzzle flash still at an angle of invtan(28/30) in relation to the sprite. Therefore, the angle that the flash must be placed at in relation to the rotation of the sprite can be given by
flashRotation = spriteRotationDegrees - invtan(28/30) \\you can change this to radians
Once that is found, the positions can be found by:
var x_pos = sprite_x_pos + Math.Sqrt(28^2 + 30^2)cos(flashRotation);
var y_pos = sprite_y_pos + Math.Sqrt(28^2 + 30^2)sin(flashRotation);
The actual angle of rotation of the flash (which way it points) will be the same angle as the sprite.
You may need to play with the flashRotaion equation depending upon which way is counted as a positive rotation.
I designed a web app with html5 canvas. To export an image, the code will be below:
var img = canvas.toDataURL("image/png");
Is there any way to export a 2x image?
It is for hdpi display like apple retina display.
Yes there are a few ways but every time you stretch a non vector image you will get some pixel distortion. However if its only two times the size you could get away with it using nearest neighbor. The below example shows two different methods, one is just stretching the image, the other uses nearest neighbor with a zoom factor of two.
Live Demo
var canvas = document.getElementById("canvas"),
ctx = canvas.getContext("2d"),
canvas2 = document.getElementById("canvas2"),
ctx2 = canvas2.getContext("2d"),
tempCtx = document.createElement('canvas').getContext('2d'),
img = document.getElementById("testimg"),
zoom = 2;
tempCtx.drawImage(img, 0, 0);
var imgData = tempCtx.getImageData(0, 0, img.width, img.height).data;
canvas.width = img.width * zoom;
canvas.height = img.height * zoom;;
// nearest neighbor
for (var x = 0; x < img.width; ++x) {
for (var y = 0; y < img.height; ++y) {
var i = (y * img.width + x) * 4;
var r = imgData[i];
var g = imgData[i + 1];
var b = imgData[i + 2];
var a = imgData[i + 3];
ctx.fillStyle = "rgba(" + r + "," + g + "," + b + "," + (a / 255) + ")";
ctx.fillRect(x * zoom, y * zoom, zoom, zoom);
}
}
// stretched
ctx2.drawImage(img, 0, 0, 140, 140);
#phrogz has a great example of this here as well, showing a few different ways you can accomplish image re-sizing.