How to convert dp to px in xamarin.android? - xamarin

I want to convert dp to px in my C# code in xamarin.android, but all I could find were java codes in android studio that have some problems in xamarin. I tried to use equivalent like using Resources instead of getResources() and I could solve some little problems, but there are some problems yet that I couldn't find any equivalent for them. here are original codes, my codes, and my codes problems in xamarin:
First code
(found from Programatically set height on LayoutParams as density-independent pixels)
java code
int height = (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, < HEIGHT >, getResources().getDisplayMetrics());
C# code
int height = (int)TypedValue.ApplyDimension(TypedValue.COMPLEX_UNIT_DIP, < HEIGHT >, Resources.DisplayMetrics);
problems:
'TypedValue' does not contain a definition for 'COMPLEX_UNIT_DIP'
Invalid expression term < (The same error for >)
The name 'HEIGHT' does not exist in the current context
Second code
(found from Formula px to dp, dp to px android)
java code
DisplayMetrics displayMetrics = getContext().getResources().getDisplayMetrics();
int px = Math.round(dp * (displayMetrics.xdpi / DisplayMetrics.DENSITY_DEFAULT));
C# code
DisplayMetrics displayMetrics = Application.Context.Resources.DisplayMetrics;
int pixel = Math.Round(dp * (displayMetrics.Xdpi / DisplayMetrics.DensityDefault));
problem
Operator '/' cannot be applied to operands of type 'float' and 'DisplayMetricsDensity'
Now I have actually two questions. Which code is more proper? What's equivalent code for them in xamarin.android?
Thanks in advance.

Solution to "First code":
Xamarin tends to move constants into their own enums. COMPLEX_UNIT_DIP can be found on ComplexUnitType enum. Also you cannot have < HEIGHT > in your code you actually need to pass in dips to get the equivalent pixel value. in the example below I am getting pixels in 100 dips.
var dp = 100;
int pixel = (int)TypedValue.ApplyDimension(ComplexUnitType.Dip, dp, Context.Resources.DisplayMetrics);
Solution to "Second code":
You need to explicitly cast 'DisplayMetrics.DensityDefault' to a float and the entire round to an int:
int pixel = (int)System.Math.Round(dp * (displayMetrics.Xdpi / (float)DisplayMetrics.DensityDefault));
I prefer the first approach as the second code is specifically for calculating along the "x dimension":
Per Android docs and Xamarin.Android docs, the Xdpi property is
"The exact physical pixels per inch of the screen in the X dimension."

These are from the project that I am currently working on..
public static float pxFromDp(Context context, float dp)
{
return dp * context.Resources.DisplayMetrics.Density;
}
public static float dpFromPx(Context context, float px)
{
return px / context.Resources.DisplayMetrics.Density;
}

From android source code textview settextsize
var convertToDp = TypedValue.ApplyDimension( ComplexUnitType.Dip, size, context.Resouces.DisplayMetrics);

dp to px:
DisplayMetrics displayMetrics = Application.Context.Resources.DisplayMetrics;
double pixel = Math.Round((dp * DisplayMetrics.DensityDefault) + 0.5);
Answer taken from here : https://stackoverflow.com/a/8490361/6949388
Sorry, not enough rep to comment.

Related

How can i get device tilt in xamarin forms?

I´d like to get the tilt of the device, so i can use this to mesure the tilt os some surface, laying down the device over the surface.
Right now i am using Device Motion Plugin for xamarin forms from here https://github.com/rdelrosario/xamarin-plugins
and the code below:
CrossDeviceMotion.Current.Start(MotionSensorType.Accelerometer);
CrossDeviceMotion.Current.SensorValueChanged += (s, a) =>
{
switch (a.SensorType)
{
case MotionSensorType.Accelerometer:
{
Debug.WriteLine("A: {0},{1},{2}", ((MotionVector)a.Value).X, ((MotionVector)a.Value).Y,
((MotionVector)a.Value).Z);
Exposicao.Inclinacao = ((MotionVector)a.Value).Z;
break;
}
case MotionSensorType.Compass:
{
// Debug.WriteLine("H: {0}", a.Value);
Exposicao.Bussola = (double)a.Value.Value;
break;
}
}
};
The compass part is ok, the accelerometer part is working but there are some but´s.
If i am not wrong, i get the tilt in Z axis, so z.Value.Value.
This value is diferent for android and ios, lets focus in android.
z values are from 10 when device is laying down on flat surface, to 0 if device is stand up, lets focus only in just one quadrant.
I am doing something wrong to achieve what i explained?
How can i convert those values to a Angle between 0 and 90? It seems not linear, so the 5 does not seem 45 degrees.
Thanks
I'd probably roll out my own platform implementation for the feature you're looking for. The DeviceMotion library looks a bit simple for your purposes, as can be seen from the answer below. I'm pretty sure you can use it as a good starting point but it needs to be extended a little.
Android
On Android, you should use the Rotation Vector Sensor which uses a Kalman filter (with accelerometer, magnetometer and gyroscope) to get accurate measurements of the device's rotation:
The rotation vector represents the orientation of the device as a combination of an angle and an axis, in which the device has rotated through an angle θ around an axis (x, y, or z).
Image from the official Android documentation
iOS:
For iOS, you have to do a bit more work yourself. The key is to make use of CMAttitude, which describes the attitude of the device relative to an initial attitude. I found a snippet I've saved to my collection from an unknown source (can't credit the original author) here:
public void CalculateLeanAngle ()
{
motionManager = new CMMotionManager ();
motionManager.DeviceMotionUpdateInterval = 0.02;
if (motionManager.DeviceMotionAvailable) {
motionManager.StartDeviceMotionUpdates(CMAttitudeReferenceFrame.XArbitraryZVertical, NSOperationQueue.CurrentQueue, (data, error) => {
CMQuaternion quat = motionManager.DeviceMotion.Attitude.Quaternion;
double x = quat.x;
double y = quat.y;
double w = quat.w;
double z = quat.z;
double degrees = 0.0;
//Roll
double roll = Math.Atan2 (2 * y * w - 2 * x * z, 1 - 2 * y * y - 2 * z * z);
degrees = Math.Round (-applyKalmanFiltering (roll) * 180.0 / Constants.M_PI);
});
}
public double applyKalmanFiltering (double yaw)
{
if (motionLastYaw == 0)
motionLastYaw = yaw;
float q = 0.1f; // process noise
float r = 0.1f; // sensor noise
float p = 0.1f; // estimated error
float k = 0.5f; // kalman filter gain
double x = motionLastYaw;
p = p + q;
k = p / (p + r);
x = x + k * (yaw - x);
p = (1 - k) * p;
motionLastYaw = x;
return motionLastYaw;
}
Image from the official Xamarin documentation
I'll try to look for the original source when I have more time but I'm pretty sure this will work out of the box for your purposes.

Fast algorithm for image distortion

I am working on a tool which distorts images, the purpose of the distortion is to project images to a sphere screen. The desired output is as the following image.
The code I use is as follow - for every Point(x, y) in the destination area, I calculate the corresponding pixel (sourceX, sourceY) in the original image to retrieve from.
But this approach is awkwardly slow, in my test, processing the sunset.jpg (800*600) requires more than 1500ms, if I remove the Mathematical/Trigonometrical calculations, calling cvGet2D and cvSet2D alone require more than 1200ms.
Is there a better way to do this? I am using Emgu CV (a .NET wrapper library for OpenCV) but examples in other language is also OK.
private static void DistortSingleImage()
{
System.Diagnostics.Stopwatch stopWatch = System.Diagnostics.Stopwatch.StartNew();
using (Image<Bgr, Byte> origImage = new Image<Bgr, Byte>("sunset.jpg"))
{
int frameH = origImage.Height;
using (Image<Bgr, Byte> distortImage = new Image<Bgr, Byte>(2 * frameH, 2 * frameH))
{
MCvScalar pixel;
for (int x = 0; x < 2 * frameH; x++)
{
for (int y = 0; y < 2 * frameH; y++)
{
if (x == frameH && y == frameH) continue;
int x1 = x - frameH;
int y1 = y - frameH;
if (x1 * x1 + y1 * y1 < frameH * frameH)
{
double radius = Math.Sqrt(x1 * x1 + y1 * y1);
double theta = Math.Acos(x1 / radius);
int sourceX = (int)(theta * (origImage.Width - 1) / Math.PI);
int sourceY = (int)radius;
pixel = CvInvoke.cvGet2D(origImage.Ptr, sourceY, sourceX);
CvInvoke.cvSet2D(distortImage, y, x, pixel);
}
}
}
distortImage.Save("Distort.jpg");
}
Console.WriteLine(stopWatch.ElapsedMilliseconds);
}
}
From my personal experience, I was doing some stereoscopic vision stuff, the best way to talk to openCV is through own wrapper, you could put your method in c++ and call it from c#, that would give you 1 call to native, faster code, and because under the hood Emgu's keeping OpenCV data, it's also possible to create an image with emgu, process it natively and enjoy processed image in c# again.
The get/set methods looks like Gdi's GetPixel / SetPixel ones, and, according to documentation they are "slow but safe way".
For staying with Emgu only, documentation tells that if you want to iterate over pixels, you should access .Data property:
The safe (slow) way
Suppose you are working on an Image. You can obtain the pixel on the y-th row and x-th column by calling
Bgr color = img[y, x];
Setting the pixel on the y-th row and x-th column is also simple
img[y,x] = color;
The fast way
The Image pixels values are stored in the Data property, a 3D array. Use this property if you need to iterate through the pixel values of the image.

I want to draw a grid on the Windows Phone 7 using XNA

I am trying to draw a grid on the screen of a Windows Phone; it will help me better position my sprites on the screen rather than guessing locations on the screen.
I have found several examples of a grid (2d or 3d) using XNA 3.0, but unfortunately the architectures are different and so the code doesnt work in XNA 4.0
Does anyone have something that could work?
Thanks!
You can download a PrimitiveBatch class here http://create.msdn.com/en-US/education/catalog/sample/primitives and use the code below to generate an appropriate grid as a texture.
PrimitiveBatch primitiveBatch;
private Texture2D GenerateGrid(Rectangle destRect, int cols, int rows, Color gridColor, int cellSize)
{
int w = (int)(cols * gridCellSize);
int h = (int)(rows * gridCellSize);
float uselessWidth = destRect.Width - w;
float uselessHeigth = destRect.Height - h;
Rectangle bounds = new Rectangle((int)(uselessWidth / 2) + destRect.X, (int)(uselessHeigth / 2) + destRect.Y, w, h);
RenderTarget2D grid = new RenderTarget2D(GraphicsDevice, GraphicsDevice.Viewport.Width, GraphicsDevice.Viewport.Height);
GraphicsDevice.SetRenderTarget(grid);
GraphicsDevice.Clear(Color.Transparent);
primitiveBatch.Begin(PrimitiveType.LineList);
float x = bounds.X;
float y = bounds.Y;
for (int col = 0; col < cols + 1; col++)
{
primitiveBatch.AddVertex(new Vector2(x + (col * gridCellSize), bounds.Top), gridColor);
primitiveBatch.AddVertex(new Vector2(x + (col * gridCellSize), bounds.Bottom), gridColor);
}
for (int row = 0; row < rows + 1; row++)
{
primitiveBatch.AddVertex(new Vector2(bounds.Left, y + (row * gridCellSize)), gridColor);
primitiveBatch.AddVertex(new Vector2(bounds.Right, y + (row * gridCellSize)), gridColor);
}
primitiveBatch.End();
GraphicsDevice.SetRenderTarget(null);
return grid;
}
One quick and dirty way you can do it (as it is for debugging the quicker the better) is to simply create a texture of a grid that is of the same resolution you are running your XNA game at (if you are running it at the same resolution as the phone, this will be 480x800). Most of the texture will simply be an alpha map and with grid lines of one pixel, you could create multiple resolutions or you can repeat a small texture of a single pixel cross dividing a section of the screen that is divisible by the resolution you are running at.
The draw method will be something as below and be called everyframe.
This code can declared inside your game class
Texture2D gridTexture;
Rectangle gridRectangle;
This code should be in your LoadContent method
//Best to use something like a png file
gridTexture = content.Load<Texture2D>("pathto/mygridtexture");
gridRectangle = new Rectangle(0,0,resolutionX,resolutionY);
This method should be called from your Draw method last to ensure it is on top assuming you are just using the standard spriteBatch.Begin() to render sprites (first if you are doing FrontToBack rendering).
public void DrawGrid()
{
spriteBatch.Draw(gridTexture, gridRectangle, Color.White);
}
This grid will remain stationary throughout the running of your application and should be useful when trying to line up your UI or objects that have relative positions in your game.
HTH.
You may want to take a look at the XPF project by RedBadger. It enables you to use XAML style layout in an XNA project.

QT QImage pixel manipulation

I am building a QT GUI application and use QImage for opening images.
My problem is that I can't figure out how to use QImage's bit() and scanline()
methods to get access at per pixel level.
I've seen this post Qt QImage pixel manipulation problems
but this is only for the first pixel of each row. Is this correct or I got it all wrong?
thanks in advance
The scanlines correspond to the the height of image, the columns correspond to the width of the image.
According to the docs, the prototype looks like uchar* QImage::scanline(int i), or a similar const version.
But, as a commenter pointed out, because the data is dependent on the machine architecture and image, you should NOT use the uchar * directly. Instead, use something like the following:
QRgb *rowData = (QRgb*)img.scanLine(row);
QRgb pixelData = rowData[col];
int red = qRed(pixelData);
It may not be immediately obvious from Kaleb's post, but the following works for setting a pixel on a Format_RGB32 image.
// Get the line we want
QRgb *line = (QRgb *)image->scanLine(row_index);
// Go to the pixel we want
line += col_index;
// Actually set the pixel
*line = qRgb(qRed(color), qGreen(color), qBlue(color));
The answer did not work for me. It looks like, the data is not 32bit aligned on my system.
To get the correct data, on my system i had to do this:
for(uint32_t Y = 0; Y < mHeight; ++Y)
{
uint8_t* pPixel = Image.scanLine(Y);
for(uint32_t X = 0; X < mWidth; ++X)
{
const int Blue = *pPixel++;
const int Green = *pPixel++;
const int Red = *pPixel++;
uint8_t GrayscalePixel = (0.21f * Red) + (0.72f * Green) + (0.07 * Blue);
}
}

How do I visualize audio data?

I would like to have something that looks something like this. Two different colors are not nessesary.
(source: sourceforge.net)
I already have the audio data (one sample/millisecond) from a stereo wav in two int arrays, one each for left and right channel. I have made a few attempts but they don't look anywhere near as clear as this, my attempts get to spikey or a compact lump.
Any good suggestions? I'm working in c# but psuedocode is ok.
Assume we have
a function DrawLine(color, x1, y1, x2, y2)
two int arrays with data right[] and left[] of lenght L
data values between 32767 and -32768
If you make any other assumptions just write them down in your answer.
for(i = 0; i < L - 1; i++) {
// What magic goes here?
}
This is how it turned out when I applied the solution Han provided. (only one channel)
alt text http://www.imagechicken.com/uploads/1245877759099921200.jpg
You'll likely have more than 1 sample for each pixel. For each group of samples mapped to a single pixel, you could draw a (vertical) line segment from the minimum value in the sample group to the maximum value. If you zoom in to 1 sample per pixel or less, this doesn't work anymore, and the 'nice' solution would be to display the sinc interpolated values.
Because DrawLine cannot paint a single pixel, there is a small problem when the minimum and maximum are the same. In that case you could copy a single pixel image in the desired position, as in the code below:
double samplesPerPixel = (double)L / _width;
double firstSample = 0;
int endSample = firstSample + L - 1;
for (short pixel = 0; pixel < _width; pixel++)
{
int lastSample = __min(endSample, (int)(firstSample + samplesPerPixel));
double Y = _data[channel][(int)firstSample];
double minY = Y;
double maxY = Y;
for (int sample = (int)firstSample + 1; sample <= lastSample; sample++)
{
Y = _data[channel][sample];
minY = __min(Y, minY);
maxY = __max(Y, maxY);
}
x = pixel + _offsetx;
y1 = Value2Pixel(minY);
y2 = Value2Pixel(maxY);
if (y1 == y2)
{
g->DrawImageUnscaled(bm, x, y1);
}
else
{
g->DrawLine(pen, x, y1, x, y2);
}
firstSample += samplesPerPixel;
}
Note that Value2Pixel scales a sample value to a pixel value (in the y-direction).
You might want to look into the R language for this. I don't have very much experience with it, but it's used largely in statistical analysis/visualization scenarios. I would be surprised if they didn't have some smoothing function to get rid of the extremes like you mentioned.
And you should have no trouble importing your data into it. Not only can you read flat text files, but it's also designed to be easily extensible with C, so there is probably some kind of C# interface as well.

Resources