Leonidas-from-XIV / floatinghands

A watch, as a CoffeeScript jQuery plugin. Or somethin'
3 stars 0 forks source link

Figure out a way to make the bitmap coordinates resolution independent #7

Closed watchdesigner closed 13 years ago

watchdesigner commented 13 years ago

As mentioned previously, we might want to publish the same watch, meaning basically the same set of bitmaps, for different platforms in different resolutions. That means we would have more than one sets of bitmaps which are the same, only that in one set each bitmap is e.g. 200% the size of the respective bitmap in the other set.

As you can image, it would become tedious to write the Json code for each watch set over and over again with all the different coordinates for each bitmap size.

That is why I would like to be able to indicate the coordinates in [mm] plus indicate a [dpi] value so that code can automatically convert into pixels based on that dpi value. I am not saying that needs to be coded inside the library. It can be in the HTML or somewhere else.

Can you figure out a convenient way to accomplish for this? I think we need something like a couple of lines of JS that iterate over the Json structure and recompute all coordinate values before passing the data to the plugin.

Leonidas-from-XIV commented 13 years ago

Uhm, you you basically ask for something that is a simple... division and multiplication? And how are you going to determine the DPI of the viewers device?

watchdesigner commented 13 years ago

No with the DPI you got me wrong. I am not referring to the viewer's device. I'm just saying we might have e.g. a watch image at 200 x 300 pixels size for mobiles, but on a web site for desktops we might want to show the same watch model, but at a larger size, because there people have more bandwidth, cpu power etc.

By 'dpi' I mean the following: If the watch case has a certain width in pixels on the bitmap, and I know that the case in reality is 40 mm, then I can tell the 'dpi' of the bitmap. I know this does not at all accomplish for displaying the watch in true size on the viewer's display. I'm just looking for a way to calculate the pixel coordinates for different bitmaps that have been re-sampled to different sizes. And using that "true dpi" value is convenient, because I already have those values in the image database.

Apart from that, yes, I am looking for a simple multiplication/divison or so. I just don't know how to iterate over the Json data structure with JavaScript, that is all ;-)

Leonidas-from-XIV commented 13 years ago

Ok, uhm, something like this?

Btw, this is not an JSON structure anyway, because it includes references to functions as well as function calls.

watchdesigner commented 13 years ago

great solution, very elegant. Great.

Btw, I think "inches = mm / 25.4" would be a bit easier to read ;-)

Ok, now I want just one last thing: after the multiplication ("inches * dpi"), the mm function should add half of the width or height of the canvas. That might sound stupid, but the reason is the following: all watch images we have are exactly centered. So that means that the middle of the watch, where all the central hands come out of the dial, is exactly in the middle of the bitmap. So with that final computation, the coordinate of the central hands registration points would be (0|0) which is much simpler than the position realtive to the left upper corner, which very much depends on the cropping of the image and so.

The only problem with that is that the mm function cannot tell whether it is dealing with an X or Y coordinate, so it would not know whether to add 0.5*canvas.width or height. An intermediate solution might be creating tow functions like mm_x and mm_y or so. However, I think that the way we are indicating coordinates currently is a bit WET anyway. Like we have attributes like "x", "y", then "regX", "regY", and so forth. Wouldn't it be nicer to use tuples? Then we could extend the mm function to take two arguments and return a tuple. Using it would look like this: { reg: mm(0, 0) }

what do you think?

Leonidas-from-XIV commented 13 years ago

Well, I don't know whether we can just always assume that the images are centered, that's also why I actually quite like the registration point functionality.

And when you have a mm function that adds randomly values to the coordinates, it has to know the width and height of the canvas. Then everything is coupled with everything, which is not a good idea from software design standpoint.

And the reason we don't use tuples is because we filter out the keys from the objects and pass the remaining stuff directly ahead to EaselJS, so people are free to pass any additional stuff that they want to tell Easel. I quite like the idea.

Looking forward to your input.

watchdesigner commented 13 years ago

Well, first of all I should say this: I will have to prepare a lot of watch models for the plugin. The amount of time consumed for preparing one watch model is quite important for the project. I want the process of preparing a watch model to be quick and simple, and I want to avoid time-consuming repetitive tasks. I think this is the purpose of a software.

If preparing a model implies annoying and repetitive tasks, sooner or later that will make me want to write a script that takes the work from me. And I think it is pointless saying "I have to write script B because I don't want the code in script A". Especially when we are not actually changing anything on the library itself, but only adding comfort functions in the HTML (or later maybe in another JS file).

About the registration point: as to the main watch image, yes, this is always centered. I think that is a very reasonable convention. For the hands, well of course currently you cannot assume that they have their registration point right in the center. However, I could prepare the images so they fullfil that requirement. Actually I think it would be very beneficial if we assume that each hand has it's registration point in the center of its bitmap, and we only need to indicate if that is not so.

As said, I don't even want to mess with your library, just want to add comfort functions on top of that.

I understand your point on not changing the keys from the object, because you pass them to EaselJS. I don't really understand your concern about calculating with the canvas height and width. Currently you initialize the 'mm()' function with a certain DPI value. So you could pass canvas width and height as well.

How bout we create a comfort function which takes a dictionary that is like I want to write it, performs the desired calculations on it, and returns a dictionary the way the library expects it.

That could look somewhat like this: The line we currently have: {image: "sec.png", z: 7, x: 103, y: 213, regX: 103, regY: 213, updateFn: secondly},

assuming our "comfort function" was called "hand", or "h" for convenience, the line might look like this: h({image: "sec.png", z: 7, x: -7, y: 0, regX: 0, regY: 4, updateFn: secondly}),

and, let's say keys not given default to 0, it would look like this: h({image: "sec.png", z: 7, x: -7, regY: 4, updateFn: secondly}),

This is what the 'h' function will have to do:

The last one will probably be the hardest part, because it means we need to preload the images in order to be able to read the bitmaps' width and height values. However I am very confident that this task is not too hard for you ;-)

I know all of that probably seems weird to you. But I've really done quite some thinking about the process of preparing a watch, and the comfort function described above will save me a lot of hours in the long run, I believe.

Get back to me if anything is unclear. Thanks!

(In case you are interested, this is the benefits of the above approach: if you look at the little bitmaps we currently have that represent hands, they look basically the same: they are much higher than wide (because the hands point to 12h in the zero position), and they have the reg-point basically centered horizontally and almost at the bottom vertically. Now what I can do is just extend the bitmap to the bottom, adding some unnecessary white space, so that the reg-point goes right in the middle of the bitmap. That will not really add a lot to the file sizes, because the space I add to the image consists only of RGBA(0, 0, 0, 0) pixels which I believe should be compressed quite effectively; and also I do not think it will increase CPU load dramatically, because the bitmaps for the hands are quite small and slim anyway. Once I've prepared the images that way, I could for example describe the little seconds hand like this: h({image: "sec.png", z: 7, x: -7, y: 0, regX: 0, regY: 0, updateFn: secondly}),

and when I can leave out values that are 0, it looks like this: h({image: "sec.png", z: 7, x: -7, updateFn: secondly}),

plus, that value 'x: -7' is nothing that I take a lot of time in figuring out. I can read it from a movement tech drawing very quickly, plus for a lot of movements I remember it. Do you see the comfort?

Leonidas-from-XIV commented 13 years ago

How bout we create a comfort function which takes a dictionary that is like I want to write it, performs the desired calculations on it, and returns a dictionary the way the library expects it.

We can agree on that, but you have to tell me how the object you want to specify is supposed to look like. You wrote something about tuples, but never used tuples in your post.

Yeah, and preloading image sucks, that makes it impossible to write the function in a straightforward way, you have to do callbacks. But ok, that's your boilerplate then.

watchdesigner commented 13 years ago

Yes, originally I had this idea about tuples, but that was just and idea, and your previous comments brought me away from that a bit. I guess implementing those tuples will be a bit more work on your side and not so much time saving on my side.

So if you can implement it in a way that my above example lines will work, that will make me really happy. I know that the hard part is preloading the images, which makes everything asynchronous. However, this is the only way that the plugin can determin the width and height of bitmaps. And that will save me really a lot of time in preparing the watch models. Anyway I think this is a moderate challange for you as a great programmer, right? ;-) I might be able to come up with suggestions on how to implement the callback, but I guess that doesn't make a lot of sense, because you are the good programmer and not me. Anyway, one simple thought I have would be wrapping a preload around the code we currently have for initializing the plugin. So that means that the above lines of code would only be executed at a time when the images have already been preloaded. Not very elegant. You probably know a better solution.

Do you need anything more from my side in order to follow through with that?

Thanks

Leonidas-from-XIV commented 13 years ago

Ok, I think the current state should satisfy us both.