How to set relative position (oCoords) in FabricJs? - fabricjs

I have a Text in fabricJs. I set top and left.
This sets the aCoords properly to those values.
However the oCoords dont match. And the Text is not displayed at the right position.
I suspect that I need to set to oCoords somehow. So that the Text is displayed at the right pixel coordinates (top & left) on the canvas.

aCoords and oCoords are two different things and should not be in sync.
In your comment you speak about scaled canvas.
Top and Left are 2 absolute values that represent the position of the object on the canvas. This position match with the canvas pixels when the canvas has a identity transform matrix.
If you apply a zoom, this coordinates diverge.
To get the position of pixel 300,100 of the scaled canvas on the unscaled canvas, you need to apply some basic math.
1) get the transform applied to the canvas
canvas.viewportTransform
2) invert it
var iM = fabric.util.invertTransform(canvas.viewportTransform)
3) multiply the wanted point by this matrix
var point = new fabric.Point(myX, myY);
var transformedPoint = fabric.util.transformPoint(point, iM)
4) set the object at that point.

Related

Find original (x,y) new coordinates in fabric canvas

I am building a Warehouse map in 2D with fabricjs where I am displaying their racking systems as a series of rectangles.
As a first "layer/group", i add all bays as groups containing a rectangle and text, both positioned at the same (x,y). They also have both an angle set to fit their orientation in the space.
As a second "layer/group", i add groups containing a circle and text, representing the bay's number of issues. The (x,y) also fits the bays. This way, all my issues are always on top of the bays and the center of the group fits the rotated corner of the bay.
On the first paint, all is well aligned. Once they're shown on the page, the user can create new issues, so I am trying to position the issue group fitting the original (x,y), but since it can all be panned and zoomed, I am having a hard time positioning it where it should be.
I've been looking at their explanations about transforms, but I can't figure who the boss should be and thinking that having nested groups may also be why I am all mixed up.
By doing:
const gMatrix = matchingBay.group.calcTransformMatrix(false);
const targetToCanvas = fabric.util.transformPoint(matchingBay.aCoords.tl, gMatrix);
I am on the bay, but on the "group" corner, which is not what I am looking for. (x,y) will be one of the corners of the rectangle in the group, that may have been rotated.
By specifying the original (x,y) in this code will get me way off the actual painting zone.
So, my question is, how do I get the transformed (x,y) so I can add my issue group at those coordinates?
[EDIT]
As the suggestion of spring, it made me realize I can use the rotated rectangle's transforms to find its coordinates, so I tried:
const rect = matchingBay.getObjects()[BAY_RECTANGLE_INX];
const gMatrix = rect.calcTransformMatrix();
const targetToCanvas = fabric.util.transformPoint(rect.aCoords.bl, gMatrix);
Bottom left corner is where I wish to add the new Circle. After rotation, the bottom left is now the bottom right. But I am still off. As shown, the red circle should be on the corner. It looks like the rotation has not been applied.
qrDecompose gives me something that seems right:
{angle: -90, scaleX: 1, scaleY: -1, skewX: 0, skewY: 0, translateX: 6099.626027314769, translateY: 4785.016008065199 }
I realized that I was not thinking it the right way. Since I have the rectangle already in hands, I just had to get its own transformation and resolve the corner by my own, the following fixed my issue:
{
[...]
const rect = matchingBay.getObjects()[BAY_RECTANGLE_INX];
const gMatrix = rect.calcTransformMatrix();
const decomposed = fabric.util.qrDecompose(gMatrix);
const trans = fabric.util.transformPoint(new fabric.Point((decomposed.scaleX * -rect.width) / 2, (decomposed.scaleY * rect.height) / 2), gMatrix);
const top = trans.y;
const left = trans.x;
[...]
}
Since the matrix is bringing the center point of the rectangle, I can get the corner by substracting its width and height and then transforming the coordinates to find out where the matrix puts it.

Count non-zero pixels in area rotated rectangle

I've got a binary image with an object and a rotated rectangle over it, found with cv2.findContours and cv2.minAreaRect. The image is normalized to [0;1]
What is the most efficient way to count non-zero area within the bounding rectangle?
Create new zero values Mat that has the same size of your original image.
Draw your rotated rectangle on it in (fillConvexPoly using the RotatedRect vertices).
Bitwise_and this image with your original mask
apply findnonzero function on the result image
You may also apply the previous steps on ROI of the image since you have the bounding box of your rotated rectangle.
According to Humam Helfawi's answer I've tuned a bit suggested steps, so the following code seems doing what i need:
rectangles = [(cv2.minAreaRect(cnt)) for cnt in contours]
for rect in rectangles:
rect = cv2.boxPoints(rect)
rect = np.int0(rect)
coords = cv2.boundingRect(rect)
rect[:,0] = rect[:,0] - coords[0]
rect[:,1] = rect[:,1] - coords[1]
area = cv2.contourArea(rect)
zeros = np.zeros((coords[3], coords[2]), np.uint8)
cv2.fillConvexPoly(zeros, rect, 255)
im = greyscale[coords[1]:coords[1]+coords[3],
coords[0]:coords[0]+coords[2]]
print(np.sum(cv2.bitwise_and(zeros,im))/255)
contours is a list of points. You can fill this shape on an empty binary image with the same size using cv2.fillConvexPoly and then use cv2.countNonZero or numpy.count_nonzero to get the number of occupied pixels.

How to add centered text with gm for node (graphicsmagick/imagemagick)?

This relates to the "gm" extension for node, http://aheckmann.github.io/gm/docs.html
I need to add some text centered around a bounding box (horizontally is enough). The function drawText() requires x,y coordinates, but there is no way to draw centered text.
I would otherwise need a function which can return the width of a text string in the font/size given, so I can calculate my starting x position in javascript, before calling drawText().
You can use the region and gravity functions this way:
gm(filePath)
.region(WIDTH, HEIGHT, X, Y)
.gravity('Center')
.fill(color)
.fontSize(textFontSize)
.font(font)
.drawText(0, 0, 'This text will be centered inside the region')

How to clamp the output of CIPerspectiveTransformWithExtent filter?

I'm using a CIPerspectiveTransformWithExtent filter to apply homographies (perspective warp) to images on OS X. So far, so good, and I can get the desired warping applied to my images.
I'm still struggling however with the border behavior. I would like the output of the filter to be clipped outside the original image domain:
I managed to do it for the lower and left borders by shifting the origin of the inputExtent rectangle of the correct amount. For example, if the lower left corner is projected to x = -10 then using extent.origin.x = 10 will correctly clip the left border;
on the other hand, the upper and right borders are always shown in the output image. For example, if the rightmost corner is projected to x = width + 10, setting the extent via extent.origin.x = 0, extent.size.width = width; does not work an the rightmost corner remains visible.
Am I doing anything wrong here? or maybe I'm not trying the right way to achieve my goal?

Change the color or texture of a SCNText node object (Swift - Scenekit)

How do I set the texture of a SCNText object? This is what I have and nothing changes in the appearance:
// myNode is a working SCNText element
let mat = SCNMaterial()
met.diffuse.contents = UIImage(contentsOfFile: "texture.png")
myNode.geometry.firstMaterial = mat
A text geometry may contain one, three, or five geometry elements:
If its extrusionDepth property is 0.0, the text geometry has one element corresponding to its one visible side.
If its extrusion depth is greater than zero and its chamferRadius property is 0.0, the text geometry has three elements, corresponding to its front, back, and extruded sides.
If both extrusion depth and chamfer radius are greater than zero, the text geometry has five elements, corresponding to its front, back, extruded sides, front chamfer, and back chamfer.
Scene Kit can render each element using a different material. For details, see the description of the materials property in SCNGeometry Class Reference.
just like for any other geometry, simply set its materials property.

Resources