Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Get MolDraw2DQt working again #3592

Merged
merged 14 commits into from
Dec 3, 2020

Conversation

greglandrum
Copy link
Member

The original plan was to deprecate it, but it could be useful to have a non-cairo way to create high-quality PNGs. Qt lets us do that. So this updates the class to get it working with the new font handling code.

Some caveats:

  • it's not exposed to the Python wrappers yet... still need to figure out how to do that
  • if you want to use it without FreeType you need to have a QGuiApplication running. Otherwise you can have a QCoreApplication.

needs polish and testing
non-freetype drawing doesn't work still
With the giant caveat that you need a QGuiApplication to use fonts. We try to detect that
@greglandrum
Copy link
Member Author

@d-b-w : I'd love your feedback/thoughts on this

@greglandrum greglandrum added this to the 2021_03_1 milestone Nov 27, 2020
@d-b-w
Copy link
Contributor

d-b-w commented Dec 1, 2020

@ZontaNicola -
Would you mind taking a look at this?

Copy link
Contributor

@d-b-w d-b-w left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this, @greglandrum - It looks pretty wild to try to figure out the right conversions for some of this.

My only real concern is about the non-ascii data.

void getStringSize(const std::string &label, double &label_width,
double &label_height) const override;
#endif
void drawChar(char c, const Point2D &cds) override;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens to non-ascii characters? Would they be rendered as individual utf-8 bytes?

I ask bc I know I've seen people talk in the RDK mailing list about, e.g. "±" in images.

I wonder if it would make sense to have this interface use QChar/QString.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The API for this is set at the MolDraw2D level and it is really only setup for text made up of single-byte characters.
We could think about moving to supporting wide chars, particularly now that the freetype support is there, but that's a bigger story

: DrawText(max_fnt_sz, min_fnt_sz), d_qp(qp) {
PRECONDITION(
QCoreApplication::instance(),
"need a global QGuiApplication instance to use the Qt font system");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I've usually seen "QApplication" in this error message :)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sorry, I don't follow you here.

// of the RDKit source tree.
//

#define CATCH_CONFIG_MAIN // This tells Catch to provide a main() - only do
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought that the main was in catch_qt.cpp?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

catch_main.cpp is currently used for moldraw2DTestCatch

bool no_freetype = true;
MolDraw2DQt drawer(qimg.width(), qimg.height(), qpt, -1, -1, no_freetype);
MolDraw2DUtils::prepareAndDrawMolecule(drawer, *m1);
qimg.save("qttest-1b.png");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We've used http://pdiff.sourceforge.net/ to check things like this, but it's super sensitive to, e.g., platform differences or library updates. May not be useful for the RDKit

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, I think comparing PNGs to each other byte-for-byte isn't useful

void setColour(const DrawColour &col);

void drawLine(const Point2D &cds1, const Point2D &cds2);
void drawChar(char c, const Point2D &cds);
void drawPolygon(const std::vector<Point2D> &cds);
void clearDrawing();

#if 0
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bc these aren't implemented yet?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should have removed those, they were vestigial


QPen pen(this_col);
pen.setJoinStyle(Qt::RoundJoin);
pen.setColor(this_col);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does this do something different from the QPen constructor two lines up?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nope. That looks like a mistake

font.setPixelSize(fontSize());
d_qp.setFont(font);
QPointF loc(cds.x, cds.y);
QString text;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what about:
QString text (QChar (c))

QPen pen(this_col);
pen.setJoinStyle(Qt::RoundJoin);
pen.setColor(this_col);
d_qp.setPen(pen);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is the painter used by other functions?
I like putting changes to painters between QPainter::save() and QPainter::restore() to make sure they don't bleed through, just a suggestion

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is used elsewhere, but the rest of the code should already be handling that particular problem since the drawing code runs across multiple rendering platforms, not all of which support equivalents to QPainter's save() and restore() methods

}

for (size_t i = 0; i < draw_chars.size(); ++i) {
double char_width =

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was wondering if you could use QFontMetrics::boundingRect(QChar) here

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, this is the lowest-common denominator implementation that I added to just get things working
I will go back and look at doing it more correctly

@@ -33,11 +67,11 @@ void MolDraw2DQt::setColour(const DrawColour &col) {
QPen pen(this_col);
pen.setJoinStyle(Qt::RoundJoin);
pen.setColor(this_col);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can also get rid of this line

@greglandrum
Copy link
Member Author

greglandrum commented Dec 1, 2020

@ptosco @ricrogz @bp-kelley : I'm leaning towards reclassifying this as a bug fix. It's a bit more substantial than the usual bug fix, but it takes code which doesn't work at all any more and gets it working again. It can't break existing code that uses 2020.09 since MolDraw2DQt doesn't work at all for that release.
What do you think?

@ptosco
Copy link
Contributor

ptosco commented Dec 1, 2020

@greglandrum I agree with the reclassification. Thanks for your work on this - I think this is going to be useful to many. I guess to expose it usefully to Python it needs to be interfaced with either PyQt5 or PySide2, right?

@ricrogz
Copy link
Contributor

ricrogz commented Dec 1, 2020

I agree, reclassifying as a bug fix sounds the right thing to do.

@greglandrum
Copy link
Member Author

@ZontaNicola Thanks for the review. I made your suggested changes.

@greglandrum greglandrum modified the milestones: 2021_03_1, 2020_09_3 Dec 2, 2020
@greglandrum
Copy link
Member Author

Ok, merging this as is now that I have the CI builds working on at least linux and the Mac.
We should talk about how to handle the Python wrappers for this...

@greglandrum greglandrum merged commit 938563c into rdkit:master Dec 3, 2020
@greglandrum greglandrum deleted the fix/get_qt_working_again branch December 3, 2020 16:31
greglandrum added a commit that referenced this pull request Dec 12, 2020
* Qt drawing works with freetype.
needs polish and testing
non-freetype drawing doesn't work still

* make the Qt rendering anti-aliased

* non-freetype fonts work in Qt
With the giant caveat that you need a QGuiApplication to use fonts. We try to detect that

* cleanup

* changes in response to review

* add qt support to CI builds

* fix VS build problem

* try resolving a linux link error

* Update linux_build.yml

* Update linux_build.yml

* another attempt to get the linux CI builds working

* getting closer?

* Update linux_build.yml

* disable the qt CI builds on windows
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants