How to scale properly world to canvas #2998
Replies: 9 comments 22 replies
-
Although I will say after reading couple of background blogs, maybe there is indeed an easier way to train the canvas as to the world coordinates, and let it handle those translations and scalings for us; which would be beneficial, because then, potentially, we could simply make the direct jump from our world coordinates straight through the canvas. POTENTIALLY... |
Beta Was this translation helpful? Give feedback.
-
I should probably also mention, unlike the academic scaling transformative examples, in which simple shapes are drawn on a blank canvas, I am loading a reference file from drive, on which I want to apply some scaled (to that bitmap resolution) area, translated then scaled from world coordinates. That's a pretty non-trivial difference, IMO, and something that should be taken into consideration. The reference file is a "hard fact" non-negotiable in that equation. Without which the properly translated and scaled layers above which are meaningless. In very high level 10K meter perspective; I am adding layers to a map; in other words, it is a cartography problem. And the map, although more or less fictional in nature, is a hard fact about that problem. Hope that helps, if any one is thinking of making any suggestions toward solving the present dilemma. Cheers, thanks... 🍻 |
Beta Was this translation helpful? Give feedback.
-
I adjusted the algo slightly, but still appears to be a // SKPointM is decimal based, we do the world-to-canvas translation shifting canvas friendly {0,0} zero.
var pointM = position.ToPointM();
var (px, py) = ((float)pointM.X, (float)pointM.Y);
// We need the precision in terms of defimal or even float at this point.
var (bwidth, bheight) = (bitmap.Width, bitmap.Height);
//(decimal bwidth, decimal bheight) = (bitmap.Width, bitmap.Height);
var (wwidth, wheight) = ((float)WorldSizeCentimeters.Width, (float)WorldSizeCentimeters.Height);
//(decimal wwidth, decimal wheight) = WorldSizeCentimeters;
// Here 'last' is not Z but rather the Y coord.
var (x, y) = (px * (bwidth / wwidth), py * (bheight / wheight));
// Best if thought of as "times 'bitmap per world'" units, cancels the world units, should be landing in bitmap units.
return new(x, y); The values in question in the debugger.
Our baseline cartography bitmap is The world coordinate system is The strategy is to apply the "bitmap per world" unit conversion, which we think should be canceling out the world, and arriving in terms of (hopefully precise) bitmap canvas positions. I've tried to calculate with I'm almost wondering is there an aspect ratio thing going on, but that does not seem quite as likely. |
Beta Was this translation helpful? Give feedback.
-
So far what I have tried...
None of which seem to be making the least bit of difference. The core issue, is that I want to cram a large world coordinate space very precisely into a smaller bitmap resolution. The next thing I will try for is to perhaps start with a larger resolution source bitmap, which I have several, one in particular extremely large, but really, for performance issues, trying to avoid that if I can help it. |
Beta Was this translation helpful? Give feedback.
-
Next tried loading from higher resolution baseline image, Will investigate the efficacy scaling the baseline image out to |
Beta Was this translation helpful? Give feedback.
-
I can't see any big problem with what you are doing. What is going wrong exactly? I wouldn't worry too much about |
Beta Was this translation helpful? Give feedback.
-
Following up, there is this reference in the SKIA docs, but I do not know what the Then there is also this GPT dialog I have been adapting, somewhat, trying to drill into potential problem areas of concern. And while I am loathe to "let" any AI direct my coding, if it can inform me the strongest, most robus algorithm, efficacy, pros cons, then why not. But still, I am not hundred percent sold I can repeatably determine the post-scaling translation consistently. The chief opportunity is, that whenever I want to jump through the world lens to canvas for any reason, there is always a progressively worser post-scaling tranlation issue. One case in view, pardoning the pun, from So, bottom line, I am after the best possible algorithm. Maybe the third exchange with my GPT session is the most promising. The poly-regression approach might be a bit overkill, I'm not sure yet. Then there is the matter of how I may facilitate such a calculation; which as I understand it Anyway 🍔 🌭 🍕 for 🧠 ... |
Beta Was this translation helpful? Give feedback.
-
Maybe I am doing too much work there as well thinking about it. If I can simple lean into the |
Beta Was this translation helpful? Give feedback.
-
Okay so this thing adapting public static void VerifyCanvasScaleDryRun(string imagePath, Guid uuid = default)
{
string fullPath;
if (uuid == default)
{
uuid = Guid.NewGuid();
}
fullPath = $"Maps\\canvas_scale_dryRun_{uuid = Guid.NewGuid()}.jpg";
using var image = SKImage.FromEncodedData(imagePath);
using var bitmap = SKBitmap.FromImage(image);
using var canvas = new SKCanvas(bitmap);
var bitmapWidthM = (decimal)bitmap.Width;
var bitmapWidthF = (float)bitmap.Width;
var bitmapWidthD = (double)bitmap.Width;
var scaleM = bitmapWidthM / WorldSizeCentimeters.Width; // 8192 / 150000 in our use case...
// TODO: this is a problem... Windows Calculator reports: 0.00546448087431693989071038251366
var scaleF = bitmapWidthF / (float)WorldSizeCentimeters.Width;
var scaleD = bitmapWidthD / (double)WorldSizeCentimeters.Width;
// TODO: but single/double are reporting something more like this: 0.0054613333333333337
canvas.Scale(scaleF);
// TODO: pg record: {"Uuid":"b8ec5136-c7e8-4e7b-bfc4-ab26d394c8c2","X":-438084.469,"Y":103356.875,"Z":38187.777}
const float radius = 10000f;
using var paint = new SKPaint { Color = SKColors.Red.WithAlpha((byte)(byte.MaxValue * 0.5f)) };
SKPoint point = new(-438084.469f, 103356.875f);
canvas.DrawCircle(point, radius, paint);
canvas.Flush();
const float inflation = radius * 10;
SKRect rect = new((point.X - radius) * scaleF, (point.Y - radius) * scaleF, (point.X + radius) * scaleF, (point.Y + radius) * scaleF);
rect.Inflate(inflation * scaleF, inflation * scaleF);
var bitmapRectI = bitmap.GetBoundsRectI();
var viewBitmap = new SKBitmap((int)rect.Size.Width, (int)rect.Size.Height);
using var viewCanvas = new SKCanvas(viewBitmap);
viewCanvas.DrawBitmap(bitmap, bitmapRectI, viewBitmap.GetBoundsRectI());
// TODO: canvas scale makes it look very grainy pixelated... not gonna work for us...
// TODO: image quality is EVERYTHING
using var data = bitmap.Encode(SKEncodedImageFormat.Jpeg, 100);
using var fs = new FileStream(fullPath, FileMode.Create, FileAccess.Write, FileShare.Read);
data.SaveTo(fs);
} Secondly, there are definitely floating point rounding issues going on. I'm not sure quite what we can do about that, which is going to make dealing with some resolutions very challenging when Just on the numbers alone, I'm not sure how they get Drawn with scaling involved, still the same sort of floating point rounding issues evidenced. The only up side is that we can more than less specify geometry in terms that are literally world scale. The following example, not rotated, but still very inaccurate, manifestation of the rounding issues. There are also issues capturing view ports when scaled, result is VERY pixelated. Maybe need to reset scale to Will experiment with higher resolution versions of the source map to see if and how it may improve. I would expect some, but kind of at a loss how to achieve accuracy at this point. |
Beta Was this translation helpful? Give feedback.
-
Hello,
I'm having what I think is an odd precision issue converting from world coords to canvas bitmap.
Assumptions. The canvas bitmap has a resolution, presumably some pixels
width
andheight
,int
. Although from a canvas perspective, these are, I think, in terms offloat
, correct? That's first.Second. world coordinates are intentionally tracked in
decimal
, because precision is critical. Measurements are to the centimeter whole number, including fractional decimal places for smaller than that. So cannot havefloat
, or especiallydouble
, floating point rounding precision errors going on.Third. World true zero is not canvas
{0,0}
presumably top left, usually. There is a simple offset{dX,dY}
getting to a zero world coordinates that is aligned with zero canvas. Neither here nor there, I think, for purposes of discussion, just an interesting translational mad fact.Anyway, at the moment, I have this translation going on from
Location
(3D, includingZ
, but we do not care about that dimension,decimal
) toSKPoint
(float
). Which I feel is scaling in correctly, which I suspect may be due to some precision issues betweendecimal
throughint
tofloat
or some parts in between.The basic algorithm is to assess the ratio of world coordinate in world dimensions, and apply that into the canvas bitmap dimension. The fun part is, the algorithms and I think scaling to SKIA points is at least consistent. But the location I can assure you, precision wise, is off.
So the algo goes something like:
position
to canvas friendly zero{0,0}
.{X,Y}
coordinates from the position.SKPoint
.I think maybe I see the issue, possibly. Perhaps I need for all the components to land in
float
, for smoothest possibly scaling into canvasSKPoint
.My next steps are to decompose the calculation a bit and better assess things. But if there are any tips how to perform this calculation more precisely, I am all ears.
Beta Was this translation helpful? Give feedback.
All reactions