How to zoom in to fit the exact bounding box in Autodesk forge viewer - zooming

We want to zoom-in to a 2D sheet in forge-viewer to take screenshot and stitch multiple screenshot later to get better image quality.
We are facing issue to zoom-in to exact bounding box, it always is little less zoomed-in i.e. we can see portion of sheet which shouldn't be part of screenshot.
Take a case of dividing a 2D sheet in equal 4 quadrants to zoom-in and take screenshot (we can increase quadrants/sections as per the required image quality later), we use below code to zoom-in,
var max = viewer.model.getBoundingBox().max;
var min = viewer.model.getBoundingBox().min;
var Q1Min = new THREE.Vector3( min.x, min.y, 0 )
var Q1Max = new THREE.Vector3( (min.x)+(max.x)/2, (min.y)+(max.y)/2, 0 )
var Q1Box = new THREE.Box3(Q1Min, Q1Max);
viewer.navigation.fitBounds( immediate, Q1Box);
We also tried using below method, it also produces same result
viewer.impl.setViewFromViewBox(viewer.model, [Q1Min.x,Q1Min.y,Q1Max.x,Q1Max.y],'Q1',true)
Full sheet view as seen in browser.
Result after above code execution.
Required result, notice the difference in width of image. In some case height and width both become an issue.

Engineering came back and offered the same workaround - and see a live sample I just put together to zoom in programmatically here:
var direction = new THREE.Vector3();
camera.getWorldDirection( direction );
camera.position.add( direction.multiplyScalar(distance) ); //set distance move the camera forward to your needs
viewer.navigation.setView(camera.position,viewer.navigation.getTarget())
Also see here and here for code samples putting the above into practice.
They conceded that this could be a bug but didn't provide more details - will chase them up but guess they got other priorities for the moment like to maintain the newly released Viewer v7.

Related

Replace an image in Google Slides with Apps Script with same croping

I'm trying to replace an image in a Google Slide by a smaller version of it (in terms of bytes).
The smaller image should be displayed exactly the same way than the older.
But when my original image was croped, I cannot reproduce it with the new one.
What I'm doing is simple (I'm using this replace method)
let image = page.getImages()[0];
let newImageUrl = optimize(image.getContentUrl()); // API call to get an optimized image. newImage will have the same width and height
image.replace(newImageUrl, true);
A visual example.
Here is my slide before (pay attention to the "Quick" logo at the bottom right corner)
And here is the result after replacing it (you can see that the bounding box is the same, it takes the same space in the slide, but the image itself is lower)
How can I reproduce the croping that I've initially done in my slide with that button ?
Thanks
Issue:
As mentioned in comments, crop properties are currently read-only, so this cannot be done. Here are possible workarounds: https://stackoverflow.com/a/63256489, https://stackoverflow.com/a/64040404, https://stackoverflow.com/a/67309702.
Feature request:
There's a feature request in Issue Tracker. Anyone interested in this, consider starring it:
Why are Image Crop Properties read only

PixelCompare with right calibration

Use Case: There are several as-built plans as PDF files. The PDF files represent different planning states.
Plan A - as-built plan first floor from 1950 on paper size Letter
Plan B - as-built first floor plan from 1999 on paper size DIN A2
Both plans are scaled to maximum paper width.
Is there a possibility to calibrate the PDF files within the Autodesk Forge Viewer to overlay the files in the correct scaling?
You have access to the source code of not only the Viewer but the extensions as well:
https://developer.api.autodesk.com/modelderivative/v2/viewers/7.*/extensions/PixelCompare/PixelCompare.js
Looking in it I did not find a way to specify how the model/sheet should be transformed. However, I found that the tool it's creating is activated after the initialization is done, which includes changing the placementTransform of the secondary sheet in order to adjust the scaling. So I can listen to the Autodesk.Viewing.TOOL_CHANGE_EVENT event and adjust the scaling of the sheet:
var pcExt = await viewer.loadExtension("Autodesk.Viewing.PixelCompare");
let onToolChange = event => {
let tr = model2.getPlacementTransform();
// double scale along X axis
tr.elements[0] *= 2;
model2.setPlacementTransform(tr);
viewer.removeEventListener(Autodesk.Viewing.TOOL_CHANGE_EVENT, onToolChange);
}
viewer.addEventListener(Autodesk.Viewing.TOOL_CHANGE_EVENT, onToolChange);
pcExt.compareTwoModels(model1, model2);
This blog post might also be useful:
https://forge.autodesk.com/blog/rotate-sheets-viewer

How to change shape type in Google Slides?

I can see that Slides have getShapeType but don't have setShapeType method.
How may we udpate the shape type in Google Slides?
This is possible from the Google Slides context menu, but does not appear to be possible using Google App Script.
Any ideas? Thanks!
From Class Layout you can use getShapes to goto Class Shape where there are a lot methods for working with shapes.
Currently you cannot change the type of an existing Shape with Apps Script. This is not possible even with Slides API (you can change the shape properties in presentations.batchUpdate, but this doesn't include the shape type).
Once a Shape is created, the type is set, and if you want to have a Shape that has another type, you have to create a new one.
There are ways to achieve this, though, even if not so direct and fast:
Workaround #1 (Apps Script methods):
Using Apps Script built-in methods, you could do the following:
Get the properties of the shape you want to update (including position, rotation, scaling, color, etc.), with the corresponding methods (getRotation, getHeight, etc.).
Delete this existing shape via Shape.remove.
Create a new shape with the same properties as the old one, but with a different shape, via Slide.insertShape.
See for example, this sample, in which the position, rotation and dimensions of an existing shape is retrieved, then the shape is removed, and finally a new one is created with the same position, rotation and dimensions of the old one, and a triangular shape:
var left = shape.getLeft();
var top = shape.getTop();
var rotation = shape.getRotation();
var height = shape.getHeight();
var width = shape.getWidth();
shape.remove();
var shapeType = SlidesApp.ShapeType.TRIANGLE;
var newShape = slide.insertShape(shapeType, left, top, width, height);
newShape.setRotation(rotation);
Workaround #2 (Advanced Slides Service):
You could also activate Advanced Slides Service and use Slides API to accomplish the same process. You would have to do the following:
Retrieve the shape properties via presentations.get
Remove the old shape via presentations.batchUpdate, providing a DeleteObjectRequest.
Create a new shape with the properties of the old one and the new shape type via presentations.batchUpdate, providing a CreateShapeRequest.
Note:
I'd suggest you consider filing a Feature Request in this Issue Tracker component explaining the potential usefulness of this desired functionality.
Reference:
presentations.batchUpdate
UpdateShapePropertiesRequest
Advanced Slides Service
Slide.insertShape(shapeType, left, top, width, height)

Is there a way to have smooth/subpixel motion without turning on smoothing on graphics?

I'm creating this 2D, pixel art game. When the camera follows the player (it uses easing), on the final approach, the position gets several subpixel adjustments.
If I have smoothing ON (on my graphic assets), the graphics look good (sharp. it's pixel art) but the subpixel motion is jerky/jumpy.
If I have smoothing OFF, the subpixel motion is smooth, but the pixel art graphics look blurry.
I'm using Flash player v21. I've tried this with Starling and with Flash's display list.
You have a pixelated object that is moving in increments of less than the pixel size, but you don't want to restrict your mathematical easing to integers, or even worse, factors of 8 or what have you. The solution I am using in my project for this exact issue is posted below (I just got it working last week!)
Concept
create a driver that is controlled by the easing using floating point numbers.
Allow this driver to then control where the actual display object is rendered. We can use a constraint to only allow the display object to render on your chosen resolution.
Code Example
// you'll put these lines or equivalent in the correct spots for your particular needs.
// SCALE_UP will be your resolution control. If your pixels are 4 pixels wide, use 4.
const SCALE_UP: int = 4;
var d:CharacterDriver = new CharacterDriver();
var c:Character = new Character();
c._driver = d; // I've found it useful to be able to reference the driver
d._drives = c; // or the thing the driver drives via the linked object.
// you don't have to do this.
then when you are ready to do your easing of the driver:
function yourEase(c:Character, d:CharacterDriver):void{
c.x = Math.ceil(d.x - Math.ceil(d.x)%SCALE_UP);//this converts a floating point number into a factor of SCALE_UP
c.y = Math.ceil(d.y - Math.ceil(d.y)%SCALE_UP);
Now this will make your character move around 4 pixels at a time, but still be able to experience easing!
The bit with the modulo (%) operator is the key. For instance, 102-102%4 = 100. 103-103%4 = 100. 104-104%4 = 104.
In case anyone is confused by that, look at what 102%4 does: 4 goes into 102 25 times with a remainder of 2. so 102%4 = 2. Then 102 - 2 = 100.
In your case, since the "camera" is following the player (i.e. the background is moving, right?) then you really need to apply drivers to everything in the background instead, but it is basically the same idea.
Hope this helps.
since you specifically mentioned the "final approach" i think your problem comes from the fact that the easing equations puts your graphics at fractional coordinates, especially while getting closer to the target, but you should also notice it during the rest of the animation.
depending on the easing "engine" that you're using you should be able to set a "round values" flag, so all the coordinates set will be integer values and not fractional
if that's not possible, find a way in your display objects to round the x and y values every time they change

Windows Store App - SwapChainPanel DrawLine Performance

I am developing a Windows Store App using XAML / C#. The app also has a Windows Runtime Component, which is used for showing a Chart ouput using DirectX.
I am using SwapChainPanel approach for drawing the lines (x-axis, y-axis and waveform).
I chose this approach from the below MSDN sample (refer scenario 3 - D2DPanel)
http://code.msdn.microsoft.com/windowsapps/XAML-SwapChainPanel-00cb688b
Here is my question,
My waveform contains a huge number of data (ranging from 1,000 to 20,000 set of points). I am calling DrawLine continuously for all these points during each Render function call.
The control also provides panning and zooming but keeps the StrokeWidth constant irrespective of zoom level, hence the visible area (render target) might be much less than the lines I am drawing.
Does calling DrawLine for the area which are going to be off-screen cause performance issues?
I tried PathGeometry & GeometryRealization but I am not able to control the StrokeWidth at various zoom level.
My Render method typically resembles the below snippet. The lineThickness is controlled to be same irrespective of zoom level.
m_d2dContext->SetTransform(m_worldMatrix);
float lineThickness = 2.0f / m_zoom;
for (unsigned int i = 0; i < points->Size; i += 2)
{
double wavex1 = points->GetAt(i);
double wavey1 = points->GetAt(i + 1);
if (i != 0)
{
m_d2dContext->DrawLine(Point2F(prevX, prevY), Point2F(wavex1, wavey1), brush, lineThickness);
}
prevX = wavex1;
prevY = wavey1;
}
I'm kind of new to DirectX, but not to C++. Any thoughts?
Short answer: It probably will. It's good practice to push a clip before drawing. For instance, in your case, you'd do a call to ID2D1DeviceContext::PushAxisAlignedClip with the bounds of your drawing surface. That'll ensure no drawing calls attempt to draw outside the surface's bounds.
Long answer: Really, it depends on a handful of factors, including but not limited to what target the device context is drawing to, the display hardware, and the display driver. For instance, if you're drawing to a CPU-backed ID2D1Bitmap, it's probably fair to assume that there won't be much of a difference.
However, if you're directly drawing to some hardware-backed surface (a GPU bitmap, or a bitmap created from an IDXGISurface), it can get a little hairy. For example, consider this comment from an excellently documented MSDN sample. Here, the where the code is about to Clear an ID2D1Bitmap created from an IDXGISurface:
// The Clear call must follow and not precede the PushAxisAlignedClip call.
// Placing the Clear call before the clip is set violates the contract of the
// virtual surface image source in that the application draws outside the
// designated portion of the surface the image source hands over to it. This
// violation won't actually cause the content to spill outside the designated
// area because the image source will safeguard it. But this extra protection
// has a runtime cost associated with it, and in some drivers this cost can be
// very expensive. So the best performance strategy here is to never create a
// situation where this protection is required. Not drawing outside the appropriate
// clip does that the right way.