How to place the hours in a clock dynamically? - algorithm

I made an svg clock using Java by drawing a circle and three animated lines into an svg file. This is how my clock looks like.
Now I want to add the hours to the clock like the following.
How can I do the calculations given the cx, cy, r, and stroke-width of the circle ? I want the user to supply these values and I draw the rest including the hour, minute, and second hand. I am not worried about the clock hands, I can figure that out, but I am not sure how to place the hours in the clock dynamically. I don't want to place them manually.
Here is my SVG file.
<svg xmlns = 'http://www.w3.org/2000/svg' version = '1.1' width="500.0" height="500.0">
<circle cx="100.0" cy="100.0" r="50.0" stroke="none" stroke-width="1.0" fill="rgba(102,205,170,0.4)"/>
<line x1="100" y1="100" x2="100" y2="62" stroke="red" stroke-width="2.0" stroke-linecap="round">
<animateTransform attributeName="transform" type="rotate" from="0 100 100" to="360 100 100" dur="500ms" repeatCount="indefinite"></animateTransform>
</line>
<line x1="100" y1="100" x2="100" y2="62" stroke="black" stroke-width="2.0" stroke-linecap="round">
<animateTransform attributeName="transform" type="rotate" from="0 100 100" to="360 100 100" dur="3s" repeatCount="indefinite"></animateTransform>
</line>
<line x1="100" y1="100" x2="100" y2="75" stroke="black" stroke-width="4.0" stroke-linecap="round">
<animateTransform attributeName="transform" type="rotate" from="0 100 100" to="360 100 100" dur="40s" repeatCount="indefinite"></animateTransform>
</line>
</svg>
How do I do this and what are the variables that I need as part of the calculations ? I'm pretty much looking for a formula in order to place the hours correctly.
Update: The answer by Michaël Lhomme is given me the best drawings
How can I make the hours go inside the circle? They are very close but I would want them inside.
Thanks!

You need to use cos and sin functions to calculate the coordinates of each point on the circle :
/*
* #param radius The clock radius
* #param cx X coordinates of the clock's center
* #param cy Y coordinates of the clock's center
*/
void drawHours(int radius, int cx, int cy) {
for(int i = 1; i <= 12; i++) {
double x = radius * Math.cos(Math.PI / -2 + (2 * i * Math.PI) / 12) + cx
double y = radius * Math.sin(Math.PI / -2 + (2 * i * Math.PI) / 12) + cy
String text = Integer.toString(i);
//draw text at [x, y] using style 'text-anchor' set to 'middle' and 'alignment-baseline' set to 'middle'
}
}
To adjust the locations of the text use svg alignment properties 'text-anchor' and 'alignment-baseline'

Start at the center of your circle, and use sin and cos trig functions to calculate the center of the point at which you are going to display a given numeral for the hour.
To calculate the center point for each numeral, something like this might work (untested):
// This will calculate the center point for the location at which a
// label for the given hour should be:
Point2D.Double getHourLocation(int hour, int clockDiameter)
{
double radians;
double x;
double y;
// assume 360 degrees, so range needs to be 0..360:
// first, adjust hour so 0 is at the top, 15s is at 3 o'clock, etc
// 360/12 = 30, so
hour *= 30;
// calculate x, y angle points relative to center
radians = Math.toRadians(hour * Math.PI / 180);
x = Math.cos(radians);
y = Math.sin(radians);
// sin() and cos() will be between -1.0 and 1.0 so adjust for that
x *= 100;
y *= 100;
// x, y points should now be relative to center of clock
x += clockDiameter;
y += clockDiameter;
return new Point2D.Double(x, y);
}
Once you have calculated this location, you'll have to adjust for your font characteristics. For example, assume that you know that the "12" text should be centered at (-50,50) - you'll need to adjust the x,y coordinates to factor in the text width and height to determine where to actually begin drawing.

Related

How to move a-entities relative to center of the viewport [with object3D.position.set(x, y, z) ]

I'm using a-frame to create a scene with a box that moves according to a sine function, but the box doesn't show up inside the viewport.
I already tried to update the box position by changing the "position" attribute and resetting the box.object3D.position.
HTML file
<a-scene log="hello scene">
<a-assets>
<img id="boxTexture" src="https://i.imgur.com/mYmmbrp.jpg">
</a-assets>
<a-box src="#boxTexture" position="0 0 -5" rotation="0 45 45" scale="0.5 0.5 0.5">
<!-- <a-animation attribute="position" to="0 2.2 -5" direction="alternate" dur="2000"
repeat="indefinite"></a-animation> -->
<a-animation attribute="scale" begin="mouseenter" dur="300" to="2.3 2.3 2.3"></a-animation>
<a-animation attribute="scale" begin="mouseleave" dur="300" to="0.5 0.5 0.5"></a-animation>
<a-animation attribute="rotation" begin="click" dur="2000" to="360 405 45"></a-animation>
</a-box>
<a-camera>
<a-cursor></a-cursor>
</a-camera>
JavaScript file
// low frequency oscillator
function lfo(amp, freq, phase) {
var date = new Date();
var millis = 0.001 * date.getMilliseconds();
var value = amp * Math.sin(millis * freq + phase);
return value;
}
var boxes = document.querySelectorAll('a-box');
function moveBoxes() {
// loop through all the boxes in the document
for (var i = 0; i < boxes.length; i++) {
let x = lfo(1, 1, 0);
let y = lfo(1, 1, 0.2);
let z = lfo(1, 1, 0.7);
boxes[i].object3D.position.set(x, y, z);
//boxes[i].setAttribute("position", x+" "+y+" "+z);
}
}
I'd except to see the box either on center of the scene or at least at the upper-left corner, but it's neither.
The 2D viewport does not map to the 3D positions within the 3D scene.
The A-Frame mouse cursor maps mouse clicks to in-3D clicks. I'm not sure, but you might be able to use this sort of method to convert 2D X/Y coordinate to 3D coordinate at your specified distance: https://github.com/aframevr/aframe/blob/master/src/components/cursor.js#L213
But otherwise, I would just make something a child of the camera.
<a-entity camera>
<a-box move-sin-wave-or-whatever-animation position="0 0 -1"></a-box>
</a-entity>

Processing - creating circles from current pixels

I'm using processing, and I'm trying to create a circle from the pixels i have on my display.
I managed to pull the pixels on screen and create a growing circle from them.
However i'm looking for something much more sophisticated, I want to make it seem as if the pixels on the display are moving from their current location and forming a turning circle or something like this.
This is what i have for now:
int c = 0;
int radius = 30;
allPixels = removeBlackP();
void draw {
loadPixels();
for (int alpha = 0; alpha < 360; alpha++)
{
float xf = 350 + radius*cos(alpha);
float yf = 350 + radius*sin(alpha);
int x = (int) xf;
int y = (int) yf;
if (radius > 200) {radius =30;break;}
if (c> allPixels.length) {c= 0;}
pixels[y*700 +x] = allPixels[c];
updatePixels();
}
radius++;
c++;
}
the function removeBlackP return an array with all the pixels except for the black ones.
This code works for me. There is an issue that the circle only has the numbers as int so it seems like some pixels inside the circle won't fill, i can live with that. I'm looking for something a bit more complex like I explained.
Thanks!
Fill all pixels of scanlines belonging to the circle. Using this approach, you will paint all places inside the circle. For every line calculate start coordinate (end one is symmetric). Pseudocode:
for y = center_y - radius; y <= center_y + radius; y++
dx = Sqrt(radius * radius - y * y)
for x = center_x - dx; x <= center_x + dx; x++
fill a[y, x]
When you find places for all pixels, you can make correlation between initial pixels places and calculated ones and move them step-by-step.
For example, if initial coordinates relative to center point for k-th pixel are (x0, y0) and final coordinates are (x1,y1), and you want to make M steps, moving pixel by spiral, calculate intermediate coordinates:
calc values once:
r0 = Sqrt(x0*x0 + y0*y0) //Math.Hypot if available
r1 = Sqrt(x1*x1 + y1*y1)
fi0 = Math.Atan2(y0, x0)
fi1 = Math.Atan2(y1, x1)
if fi1 < fi0 then
fi1 = fi1 + 2 * Pi;
for i = 1; i <=M ; i++
x = (r0 + i / M * (r1 - r0)) * Cos(fi0 + i / M * (fi1 - fi0))
y = (r0 + i / M * (r1 - r0)) * Sin(fi0 + i / M * (fi1 - fi0))
shift by center coordinates
The way you go about drawing circles in Processing looks a little convoluted.
The simplest way is to use the ellipse() function, no pixels involved though:
If you do need to draw an ellipse and use pixels, you can make use of PGraphics which is similar to using a separate buffer/"layer" to draw into using Processing drawing commands but it also has pixels[] you can access.
Let's say you want to draw a low-res pixel circle circle, you can create a small PGraphics, disable smoothing, draw the circle, then render the circle at a higher resolution. The only catch is these drawing commands must be placed within beginDraw()/endDraw() calls:
PGraphics buffer;
void setup(){
//disable sketch's aliasing
noSmooth();
buffer = createGraphics(25,25);
buffer.beginDraw();
//disable buffer's aliasing
buffer.noSmooth();
buffer.noFill();
buffer.stroke(255);
buffer.endDraw();
}
void draw(){
background(255);
//draw small circle
float circleSize = map(sin(frameCount * .01),-1.0,1.0,0.0,20.0);
buffer.beginDraw();
buffer.background(0);
buffer.ellipse(buffer.width / 2,buffer.height / 2, circleSize,circleSize);
buffer.endDraw();
//render small circle at higher resolution (blocky - no aliasing)
image(buffer,0,0,width,height);
}
If you want to manually draw a circle using pixels[] you are on the right using the polar to cartesian conversion formula (x = cos(angle) * radius, y = sin(angle) * radius).Even though it's focusing on drawing a radial gradient, you can find an example of drawing a circle(a lot actually) using pixels in this answer

How do you add a swirl to an image (image distortion)?

I was trying to figure out how to make a swirl in the photo, tried looking everywhere for what exactly you do to the pixels. I was talking with a friend and we kinda talked about using sine functions for the redirection of pixels?
Let's say you define your swirl using 4 parameters:
X and Y co-ordinates of the center of the swirl
Swirl radius in pixels
Number of twists
Start with a source image and create a destination image with the swirl applied. For each pixel (in the destination image), you need to adjust the pixel co-ordinates based on the swirl and then read a pixel from the source image. To apply the swirl, figure out the distance of the pixel from the center of the swirl and it's angle. Then adjust the angle by an amount based on the number of twists that fades out the further you get from the center until it gets to zero when you get to the swirl radius. Use the new angle to compute the adjusted pixel co-ordinates to read from. In pseudo code it's something like this:
Image src, dest
float swirlX, swirlY, swirlRadius, swirlTwists
for(int y = 0; y < dest.height; y++)
{
for(int x = 0; x < dest.width; x++)
{
// compute the distance and angle from the swirl center:
float pixelX = (float)x - swirlX;
float pixelY = (float)y - swirlY;
float pixelDistance = sqrt((pixelX * pixelX) + (pixelY * pixelY));
float pixelAngle = arc2(pixelY, pixelX);
// work out how much of a swirl to apply (1.0 in the center fading out to 0.0 at the radius):
float swirlAmount = 1.0f - (pixelDistance / swirlRadius);
if(swirlAmount > 0.0f)
{
float twistAngle = swirlTwists * swirlAmount * PI * 2.0;
// adjust the pixel angle and compute the adjusted pixel co-ordinates:
pixelAngle += twistAngle;
pixelX = cos(pixelAngle) * pixelDistance;
pixelY = sin(pixelAngle) * pixelDistance;
}
// read and write the pixel
dest.setPixel(x, y, src.getPixel(swirlX + pixelX, swirlY + pixelY));
}
}

How to make clock ticks stuck to the clock border?

I try to make a clock, in swift, but now i want to make something strange. I want make border radius settable. This is the easy part (is easy because I already did that). I drew 60 ticks around the clock. The problem is that 60 ticks are a perfect circle. If I change the border radius I obtain this clock:
All ticks are made with NSBezierPath, and code for calculate position for every tick is :
tickPath.moveToPoint(CGPoint(
x: center.x + cos(angle) * point1 ,
y: center.y + sin(angle) * point1
))
tickPath.lineToPoint(CGPoint(
x: center.x + cos(angle) * point2,
y: center.y + sin(angle) * point2
))
point1 and point2 are points for 12 clock tick.
My clock background is made with bezier path:
let bezierPath = NSBezierPath(roundedRect:self.bounds, xRadius:currentRadius, yRadius:currentRadius)
currentRadius - is a settable var , so my background cam be, from a perfect circle (when corner radius = height / 2) to a square (when corner radius = 0 ).
Is any formula to calculate position for every tick so, for any border radius , in the end all ticks to be at same distance to border ?
The maths is rather complicated to explain without recourse to graphics diagrams, but basically if you consider a polar coordinates approach with the origin at the clock centre then there are two cases:
where the spoke from the origin hits the straight side of the square - easy by trigonometry
where it hits the circle arc at the corner - we use the cosine rule to solve the triangle formed by the centre of the clock, the centre of the corner circle and the point where the spoke crosses the corner. The origin-wards angle of that triangle is 45º - angleOfSpoke, and two of the sides are of known length. Solve the cosine equation as a quadratic and you have it.
This function does it:
func radiusAtAngle(angleOfSpoke: Double, radius: Double, cornerRadius: Double) -> Double {
// radius is the half-width of the square, = the full radius of the circle
// cornerRadius is, of course, the corner radius.
// angleOfSpoke is the (maths convention) angle of the spoke
// the function returns the radius of the spoke.
let theta = atan((radius - cornerRadius) / radius) // This determines which case
let modAngle = angleOfSpoke % M_PI_2 // By symmetry we need only consider the first quadrant
if modAngle <= theta { // it's on the vertical flat
return radius / cos(modAngle)
} else if modAngle > M_PI_2 - theta { // it's on the horizontal flat
return radius / cos(M_PI_2 - modAngle)
} else { // it's on the corner arc
// We are using the cosine rule to solve the triangle formed by
// the clock centre, the curved corner's centre,
// and the point of intersection of the spoke.
// Then use quadratic solution to solve for the radius.
let diagonal = hypot(radius - cornerRadius, radius - cornerRadius)
let rcosa = diagonal * cos(M_PI_4 - modAngle)
let sqrTerm = rcosa * rcosa - diagonal * diagonal + cornerRadius * cornerRadius
if sqrTerm < 0.0 {
println("Aaargh - Negative term") // Doesn't happen - use assert in production
return 0.0
} else {
return rcosa + sqrt(sqrTerm) // larger of the two solutions
}
}
}
In the diagram OP = diagonal, OA = radius, PS = PB = cornerRadius, OS = function return, BÔX = theta, SÔX = angleOfSpoke

Given aspect ratio of a rectangle, find maximum scale and angle to fit it inside another rectangle

I've read a few dozen questions on this topic, but none seem to be exactly what I'm looking for, so I'm hoping this isn't a duplicate.
I have an image, whose aspect ratio I want to maintain, because it's an image.
I want to find the largest scale factor, and corresponding angle between 0 and 90 degrees inclusive, such that the image will fit wholly inside a given rectangle.
Example 1: If the image and rectangle are the same ratio, the angle will be 0, and the scale factor will be the ratio of the rectangle's width to the image's width. (Or height-to-height.)
Example 2: If the image and rectangle ratios are the inverse of each other, the scale factor will be the same as the first example, but the angle will be 90 degrees.
So, for the general case, given image.width, image.height, rect.width, rect.height, how do I find image.scale and image.angle?
OK, I figured it out on my own.
First, calculate the aspect ratio. If your image is 1:1, there's no point in this, because the angle is always zero, and the scale is always min(Width, Height). Degeneration.
Otherwise, you can use this:
// assuming below that Width and Height are the rectangle's
_imageAspect = _image.width / _image.height;
if (_imageAspect == 1) { // div by zero implied
trace( "square image...this does not lend itself to rotation ;)" );
return;
}
_imageAspectSq = Math.pow( _imageAspect, 2 );
var rotate:Float;
var newHeight:Float;
if (Width > Height && Width / Height > _imageAspect) { // wider aspect than the image
newHeight = Height;
rotate = 0;
} else if (Height > Width && Height / Width > _imageAspect) { // skinnier aspect than the image rotated 90 degrees
newHeight = Width;
rotate = Math.PI / 2;
} else {
var hPrime = (_imageAspect * Width - _imageAspectSq * Height) / ( 1 - _imageAspectSq );
var wPrime = _imageAspect * (Height - hPrime);
rotate = Math.atan2( hPrime, wPrime );
var sine = Math.sin(rotate);
if (sine == 0) {
newHeight = Height;
} else {
newHeight = (Width - wPrime) / sine;
}
}
The first two cases are also degenerate: the image's aspect ratio is less than the rectangle. This is similar to the square-within-a-rectangle case, except that in that case, the square is always degenerate.
The code assumes radians instead of degrees, but it's not hard to convert.
(Also I'm a bit shocked that my browser's dictionary didn't have 'radians'.)

Resources