How to write subscript text in game maker? - game-maker

How can i type subscripts in text in game maker studio.
I want to type H2(g) where I want 2(g) be a subscript.

Create two fonts. For example, fnt_normal with size 20 and fnt_small with size 10.
Create script called draw_text_special
/// draw_text_special(x, y, font, text)
var posx = argument0;
var posy = argument1;
var font = argument2;
var text = argument3;
draw_set_font(font);
var width = string_width(text);
draw_text(posx, posy, text);
return width;
Then use like this (in Draw event):
var posx = 10;
var posy = 50;
draw_set_halign(fa_left);
draw_set_valign(fa_bottom);
posx += draw_text_special(posx, posy, fnt_normal, "H");
posx += draw_text_special(posx, posy, fnt_small, "2(g)");
posx += draw_text_special(posx, posy, fnt_normal, " Normal string");
posx += draw_text_special(posx, posy, fnt_small, "subscript string");

Related

How to convert back and forth between TextSize and FontSize with Xamarin.Android?

I'm using DisplayMetrics and FontMetrics to compute a value for TextSize so that the text inside the Button is not bigger that the button bounding box.
DisplayMetrics displayMetrics = new DisplayMetrics();
Display.GetMetrics(displayMetrics);
float scaledDensity = displayMetrics.ScaledDensity;
TextPaint paint = new TextPaint();
paint.AntiAlias = true;
Paint.FontMetrics metrics = null;
Xamarin.Forms.Button button;
MyButtonRenderer renderer = ((MyButtonRenderer)Platform.GetRenderer(button));
Android.Widget.Button control = renderer.Control;
int maxFontSize = (int)renderer.defaultFontSize;
string text = button.Text;
Rect bounds = new Rect();
while (maxFontSize >= 0)
{
paint.SetTypeface(control.Typeface);
paint.TextSize = scaledDensity * maxFontSize;
paint.GetTextBounds(text, 0, text.Length, bounds);
metrics = paint.GetFontMetrics();
if (bounds.Width() < control.MeasuredWidth && (metrics.Bottom - metrics.Top) < control.MeasuredHeight)
{
break;
}
maxFontSize--;
}
Then I thought that using maxFontSize to set the property TextSize for the button would make the text of the appropriate size:
renderer.Control.TextSize = maxFontSize * scaledDensity;
It doesn't work though, what I had to do was this instead:
float conversionScale = (float)renderer.Element.FontSize / renderer.Control.TextSize;
float maxTextSize = maxFontSize * scaledDensity;
renderer.Element.FontSize = maxTextSize * conversionScale;
Where conversionScale is what I use to covert TextSize to FontSize.
Is there a way to get this conversion factor from the API instead of inferring its value from the quotient of the two properties?
Also asked at the official forums.

How to draw a gps marker on a rotated custom image map

I need to draw a custom image map of a park in my App and add show gps markers on it.
However my problem is that the map should be drawn as a straight rectangle in my app (see below left), but in real life the park is rotated (see example below right)
I have the GPS coordinates of all the 4 corners of the real-live map together with the GPS coordinates of the markers but i'm stuck on how to calculate the (x,y) position for each marker for the map in my app where the map is displayed as a straight rectangle.
Any suggestions are welcome!
Code i have so far:
public class GeoLocation
{
public double Lattitude { get; set; }
public double Longitude { get; set; }
public GeoLocation()
{
}
public GeoLocation(double lat, double lon)
{
Lattitude = lat;
Longitude = lon;
}
public double Angle(GeoLocation point)
{
var deltaX = point.Lattitude - Lattitude;
var deltaY = point.Longitude - Longitude;
return (Math.Atan2(deltaY, deltaX));
}
public GeoLocation Rotate(GeoLocation center, double angleInRad)
{
var s = Math.Sin(angleInRad);
var c = Math.Cos(angleInRad);
// translate point back to origin:
var x = (double)(Lattitude - center.Lattitude);
var y = (double)(Longitude - center.Longitude);
// rotate point
var xnew = x * c - y * s;
var ynew = x * s + y * c;
// translate point back:
x = xnew + center.Lattitude;
y = ynew + center.Longitude;
return new GeoLocation(x, y);
}
}
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
var url = "file://c:\\db\\mapgrab.jpg";
var bitmap = new BitmapImage();
bitmap.BeginInit();
bitmap.UriSource = new Uri(url, UriKind.Absolute);
bitmap.CacheOption = BitmapCacheOption.OnLoad;
bitmap.EndInit();
mapImg.Source = bitmap;
var TopLeftGps = new GeoLocation(52.11070994543701, 4.411896866166349);
var TopRightGps = new GeoLocation(52.11475153599096, 4.415646979517055);
var BottomRightGps = new GeoLocation(52.1117075980591, 4.424232274309553);
var currentPosGps = new GeoLocation(52.11129692591393, 4.4174530542349295);
var imageWidth = 702;
var imageHeight = 924;
var angle = TopLeftGps.Angle(TopRightGps);
var topRight = TopRightGps.Rotate(TopLeftGps, -angle);
var bottomRight = BottomRightGps.Rotate(TopLeftGps, -angle);
var maxX = topRight.Lattitude - TopLeftGps.Lattitude;
var maxY = bottomRight.Longitude - topRight.Longitude;
var markerPos = new GeoLocation(currentPosGps.Lattitude, currentPosGps.Longitude).Rotate(TopLeftGps, -angle);
var diffX = markerPos.Lattitude - TopLeftGps.Lattitude;
var diffY = markerPos.Longitude - TopLeftGps.Longitude;
var percentageX = diffX / maxX;
var percentageY = diffY / maxY;
var posX = percentageX * imageWidth;
var posY = percentageY * imageHeight;
var markerImg = new Border();
markerImg.Background = new SolidColorBrush(Colors.Red);
markerImg.Width = 32;
markerImg.Height = 32;
Canvas.SetLeft(markerImg, posX);
Canvas.SetTop(markerImg, posY);
canvas.Children.Add(markerImg);
}
}
}
What you'r looking for is a 2D rotation transformation from the north aligned coordinates (x,y) to your rotated coordinates (x',y')
The rotation can be represented as a 2x2 matrix R and if we represent the coordinates as column vectors, then the computation will be:
[x',y']=R*[x,y]
Where * is matrix multiplication, R is
And the angle theta is the desired rotation angle.
Marking the corner points thus:
theta can be computed be solving (for example in wolframAlpha):
tan(theta) = (Ay-Dy) / (Ax-Dx)
I had a similar problem. Here is a javascript example how to rotate points on a map. The coordinates are measured from the center point. The angle is in radiants.
var x_new_centered = -1 * y_centered * Math.sin(a) + x_centered * Math.cos(a)
var y_new_centered = y_centered * Math.cos(a) + x_centered * Math.sin(a);
And here you find a jsfiddle where a point is drawn on a not rotated, a rotated and rotated and cropped map: https://jsfiddle.net/vienom/4ger35uq/

Paper.js animating : Movement according to a paths normal

I am trying to animate a line and its normal ( another line ). But when i change position after or before setting rotation of the normal strange animation occurs.
Is there anybody who has an idea on that?
I have this code in sketchpad:
http://sketch.paperjs.org/#S/jVJLb5tAEP4rKy7BqgvUbS+OcogstT2klaUeeohzIDA2q+AZtAyOI8v/vbM7mFDLUcqJne8xz0OE+RaiefT7CbioomlUUOnfu9wZ6hjcD3NjZll2vcIh9EdCn4fQxlHXSATh2Xz3//GkR9rGIvTIMucqPuzn2dS8zLOjp6x4xYGS5GU5YJo0/XKZ8lELeCWe0Vp29AQLqslJ4isH5VWPa0m4HNcTtIjLc9lj3YHXCeLzBj5Z5FgqzCaTC8BXRYJfmgrc2B2xz7VMHqnDsk2YmjtYc6BoQWFy3mhR2bp0gPF96GIqqgfvpYSGWsuWUNxkArIL373M/6hWqJ3VVAhBp7ABvqMi96Jbjj/NstNGkNw2r8e8XyHyyuoHMsopxvKUJnUgjjhniNUpyXFTg+p2Fp4Twm9ODkpk6w4L7xDDDpAn5rBCM/r6GXC4E4tdK5KfspNEHipJ2IrRab3KLOgfrjwvc9PULCqpDQxXYPZmaIfWIdLCZisyc+pLVf0JKdbezx607+TFfLgZUr/L3nv2GXfcw7uLGo/pP5c2JDnp3l7h2D1c6lsLFcdjdPwL
var outerH = 200;
var outerW = 300;
var group = new Group();
var spine = new Path({x:0, y:0});
spine.add({x:0, y:outerH/4});
spine.add({x:-outerW, y:outerH});
spine.strokeColor = 'red';
var nP = new Path();
nP.strokeColor = 'blue';
nP.add(new Point(0, 0))
nP.add(new Point(50, 0));
//nP.pivot = nP.bounds.topLeft;
group.addChildren([spine, nP]);
group.position = {x:200, y:300};
var loc = spine.getLocationAt(120);
var normal = spine.getNormalAt(120);
nP.position = loc.point;
nP.rotate(normal.angle);
view.onFrame = function(event) {
var sinus = Math.sin(event.time );
var cosinus = Math.cos(event.time );
// Change the x position of the segment point;
spine.segments[2].point.y += cosinus ;
spine.segments[2].point.x += sinus ;
var loc = spine.getLocationAt(120);
var normal = spine.getNormalAt(120);
nP.position = loc.point;
//nP.rotate(normal.angle);
}
If I uncomment -> nP.rotate(normal.angle); nP is not rotating with the line normal point?
Please read the following post on the mailing list that explains this behavior and offers an option to switch paper.js into a mode that simplifies this scenario:
https://groups.google.com/forum/#!searchin/paperjs/applymatrix/paperjs/4EIRSGzcaUI/seKoNT-PSpwJ
The problem is that in paper.js when you rotate an item and move it, the new rotation is accepted as 0 degree. So I am keeping an oldAngle variable outside the onFrame event. Than do the necessary math in onFrame to calculate the right rotation...
The right code:
var group = new Group();
var spine = new Path({x:0, y:0});
spine.add({x:0, y:50});
spine.add({x:-300, y:200});
spine.strokeColor = 'red';
var nP = new Path();
nP.strokeColor = 'blue';
nP.add(new Point(0, 0))
nP.add(new Point(50, 0));
group.addChildren([spine, nP]);
group.position = {x:200, y:300};
var loc = spine.getLocationAt(120);
var normal = spine.getNormalAt(120);
nP.position = loc.point;
nP.rotation = normal.angle;
var oldAngle = normal.angle; // keep the old rotation angle in this variable
view.onFrame = function(event) {
var sinus = Math.sin(event.time );
spine.segments[2].point.y += sinus ;
spine.segments[2].point.x += sinus ;
var loc = spine.getLocationAt(120);
var normal = spine.getNormalAt(120);
nP.position = loc.point;
nP.rotation += normal.angle - oldAngle; // here we do the necessary math
oldAngle = normal.angle;
}

image quantization

In Efford's cd there is a code for grayscale image quantization:
int n = 8 - numBits;//numBits will be taken as input
float scale = 255.0f / (255 >> n);
byte[] tableData = new byte[256];
for (int i = 0; i < 256; ++i)
tableData[i] = (byte) Math.round(scale*(i >> n));
LookupOp lookup =
new LookupOp(new ByteLookupTable(0, tableData), null);
BufferedImage result = lookup.filter(getSourceImage(), null);
return result;
I am trying to convert this code for 24 bit color image.
But dont know if I am correct?
my try:
int n = 24 - numBits;
float scale = 16777216.0f / (16777216 >> n);
byte[] tableData = new byte[16777216];
for (int i = 0; i < 16777216; ++i)
tableData[i] = (byte) Math.round(scale*(i >> n));
LookupOp lookup =
new LookupOp(new ByteLookupTable(0, tableData), null);
result = lookup.filter(img2, null);
//return result;
and this gives result inmage till numBits>=17, if numBits<17 then i get complete black image.
Am I doing it correctlly?
please help.
Thanks a lot. :)
That code quantizes only grayscale images, not color images. This means that it handles only one color channel at a time.
Besides, if you are doing 24bit -> 8bit, you probably want to construct a palette instead of simple quantization.

mapping rect in small image to larger image (in order to do a copyPixels operation)

this is (I think) a relatively simple math question but I've spent a day banging my head against it and have only the dents and no solution...
I'm coding in actionscript 3 - the functionality is:
large image loaded at runtime. The bitmapData is stored and a smaller version is created to display on the available screen area (I may end up just scaling the large image since it is in memory anyway).
The user can create a rectangle hotspot on the smaller image (the functionality will be more complex: multiple rects with transparency: example a donut shape with hole, etc)
3 When the user clicks on the hotspot, the rect of the hotspot is mapped to the larger image and a new bitmap "callout" is created, using the larger bitmap data. The reason for this is so the "callout" will be better quality than just scaling up the area of the hotspot.
The image below shows where I am at so far- the blue rect is the clicked hotspot. In the upper left is the "callout" - copied from the larger image. I have the aspect ratio right but I am not mapping to the larger image correctly.
Ugly code below... Sorry this post is so long - I just figured I ought to provide as much info as possible. Thanks for any tips!
--trace of my data values
*source BitmapDada 1152 864
scaled to rect 800 600
scaled BitmapData 800 600
selection BitmapData 58 56
scaled selection 83 80
ratio 1.44
before (x=544, y=237, w=58, h=56)
(x=544, y=237, w=225.04, h=217.28)
*
Image here: http://i795.photobucket.com/albums/yy237/skinnyTOD/exampleST.jpg
public function onExpandCallout(event:MouseEvent):void{
if (maskBitmapData.getPixel32(event.localX, event.localY) != 0){
var maskClone:BitmapData = maskBitmapData.clone();
//amount to scale callout - this will vary/can be changed by user
var scale:Number =150 //scale percentage
var normalizedScale :Number = scale/=100;
var w:Number = maskBitmapData.width*normalizedScale;
var h:Number = maskBitmapData.height*normalizedScale;
var ratio:Number = (sourceBD.width /targetRect.width);
//creat bmpd of the scaled size to copy source into
var scaledBitmapData:BitmapData = new BitmapData(maskBitmapData.width * ratio, maskBitmapData.height * ratio, true, 0xFFFFFFFF);
trace("source BitmapDada " + sourceBD.width, sourceBD.height);
trace("scaled to rect " + targetRect.width, targetRect.height);
trace("scaled BitmapData", bkgnImageSprite.width, bkgnImageSprite.height);
trace("selection BitmapData", maskBitmapData.width, maskBitmapData.height);
trace("scaled selection", scaledBitmapData.width, scaledBitmapData.height);
trace("ratio", ratio);
var scaledBitmap:Bitmap = new Bitmap(scaledBitmapData);
var scaleW:Number = sourceBD.width / scaledBitmapData.width;
var scaleH:Number = sourceBD.height / scaledBitmapData.height;
var scaleMatrix:Matrix = new Matrix();
scaleMatrix.scale(ratio,ratio);
var sRect:Rectangle = maskSprite.getBounds(bkgnImageSprite);
var sR:Rectangle = sRect.clone();
var ss:Sprite = new Sprite();
ss.graphics.lineStyle(8, 0x0000FF);
//ss.graphics.beginFill(0x000000, 1);
ss.graphics.drawRect(sRect.x, sRect.y, sRect.width, sRect.height);
//ss.graphics.endFill();
this.addChild(ss);
trace("before " + sRect);
w = uint(sRect.width * scaleW);
h = uint(sRect.height * scaleH);
sRect.inflate(maskBitmapData.width * ratio, maskBitmapData.height * ratio);
sRect.offset(maskBitmapData.width * ratio, maskBitmapData.height * ratio);
trace(sRect);
scaledBitmapData.copyPixels(sourceBD, sRect, new Point());
addChild(scaledBitmap);
scaledBitmap.x = offsetPt.x;
scaledBitmap.y = offsetPt.y;
}
}
Thanks!
public function onExpandCallout(event:MouseEvent):void{
// TODO: build this on startup or only on click? Speed vs memory
if (calloutState == true) return;
if (maskBitmapData.getPixel32(event.localX, event.localY) != 0){
calloutState = true;
//create bitmap from source using scaled selection rect
var ratio:Number = (sourceBMD.width /targetRect.width);
var sRect:Rectangle = hotSpotSprite.getBounds(bkgnImageSprite);
var destRect:Rectangle = new Rectangle(sRect.x * ratio, sRect.y * ratio, sRect.width * ratio, sRect.height * ratio);
calloutBitmapData = new BitmapData(destRect.width, destRect.height, true, 0xFFFFFFFF);
calloutBitmap = new Bitmap(calloutBitmapData);
//-- scale alpha mask
var scaledMaskBitmapData:BitmapData = new BitmapData(destRect.width, destRect.height, true, 0x00000000);
var maskScale:Number = scaledMaskBitmapData.width / maskBitmapData.width;
var mMatrix:Matrix = new Matrix(maskScale, 0, 0, maskScale);
scaledMaskBitmapData.draw(maskBitmapData,mMatrix,null,null,null, false);
// copy source with scaled alpha
calloutBitmapData.copyPixels(sourceBMD, destRect, new Point(), scaledMaskBitmapData, new Point());
scaledMaskBitmapData = null;
// apply filter to bitmap
var myDropShadowFilter:DropShadowFilter = new DropShadowFilter();
myDropShadowFilter.distance = 12;
myDropShadowFilter.alpha = .3
myDropShadowFilter.strength = 1;
myDropShadowFilter.blurX = 8;
myDropShadowFilter.blurY = 8;
calloutBitmap.filters = [myDropShadowFilter];
//place on screen
calloutSprite = new Sprite();
calloutSprite.addChild(calloutBitmap)
calloutSprite.x = offsetPt.x;
calloutSprite.y = offsetPt.y;
// ADD TO PARENT DisplayContainer
calloutLayer.addChild(calloutSprite);
// calloutSprite.scaleX = 2;
// calloutSprite.scaleY = 2;
calloutSprite.doubleClickEnabled = true;
calloutSprite.addEventListener(MouseEvent.DOUBLE_CLICK, onCollapseCallout);
calloutSprite.addEventListener(MouseEvent.MOUSE_DOWN, onStartDrag);
calloutSprite.addEventListener(MouseEvent.MOUSE_UP, onStopDrag);
}
}

Resources