Search code examples
c++mathimagemagick

how to compensate point coordinates transformation when doing a rotaion around another point in an image?


I'm generating an image with text in C++ using library called ImageMagick, and the DrawableRotation function does a rotation around the point of coordinates (0;0). (because it's an image it's top left corner )

The issue here is that I need to rotate my text label by a certain degree to put it on top of rectagle that has the same angle. ( text in box ) But the boxes are drown using the 4 points coordinates, I have their relative angle, which meens it's always positive, but some boxes are vertical, others are horizontal, and others are angled in between. here's an exemple: exemple of 3 boxes with different angles and their text

I would like to know if Image magick has an other way to rotate the text around itself or if there is a mathematical way to rotate the text so it has the good angle and then calculate the values I need to had to the coordinates to put it back at it's original coordinates.

I tried manually adding values to compensate the change in x;y but as all boxes have different angles, it's not dynamic enough, some labels get lost randomly on the image.


Solution

  • Well, I couldn't find a way to overcome this using the ImageMagick library directly, so what I do is make the rotation transformation around the origin before using the rotation formula from ImageMagick but in the opposite direction. But I also needed to map the angle (in degrees) from 90 to -90 so the text is always in the best direction to read. I'll post sample code for the rotation down below :

    std::pair<float, float> MyImage::coorRotation(float x, float y, float angle)
    {
        float x_ = x*cos(angle) - y*sin(angle);
        float y_ = x*sin(angle) + y*cos(angle);
        return (std::make_pair(x_, y_));
    }
    

    for the rotation compensation and :

    void MyImage::drawTextOnShapes()
        float degrees = std::abs((atan2(this.shape.delta y, this.shape.delta x) * 180.0) / PI); // delta y = y2 - y1 and delta x = x2 - x1
        if (degrees > 90)
            degrees -= 180; // to map between 90 and -90
        float radian = (degrees * PI) / 180;
        float x = this.shape.center.x;
        float y = this.shape.center.y;
        std::pair coords = std::make_pair(x, y);
        this->img.strokeColor("white");
        coords = this->coorRotation(x, y, radian);
        drawlist.push_back(DrawableRotation(-degrees));
        stream << std::fixed << std::setprecision(2) << wall.length; // to get a .10 precision on the float output
        drawlist.push_back(DrawableText(coords.first - textLenInPixels/2, coords.second, stream.str().append("m"))); // m for meters
        this->img.draw(drawlist);
        drawlist.clear();
        this->saveImage();
    }
    

    And here's the result:

    example of the result obtained