wxPDF: brush & pen funky with multiple rotated rectangles

Talk here about issues with one of the components hosted at wxCode, or suggest features for it.
Post Reply
mael15
Super wx Problem Solver
Super wx Problem Solver
Posts: 496
Joined: Fri May 22, 2009 8:52 am
Location: Bremen, Germany

wxPDF: brush & pen funky with multiple rotated rectangles

Post by mael15 »

this is really weird and it is very hard to produce a minimal example, so maybe someone knows a solution without having to. i attached a picture of how the pdf page is supposed to look like and the produced pdf. brushed and pens get mixed up, but only if the rectangles are rotated.
i found some hint in my code that might have something to do with it, but the problem stays if I comment this code, so maybe not?

Code: Select all

// notwendig damit im pdf die brush tatsächlich initialisiert wird
// brush problem in wxPdfDc wenn vorher ein rotiertes (!) shape gezeichnet wurde, z.b. ManwayShape und
// beide dieselbe füllfarbe haben
// wxPdfDC::SetupBrush() muss aufgerufen werden, ist aber private
// kann eventuell in zukunft weg (jetzt 19.07.20)
void slightBrushVariation(wxDC* dc) {
	wxColour colToUse = getFill().GetColour();
	if (colToUse == dc->GetBrush().GetColour())
		colToUse = wxColour(colToUse.Red() > 0 ? colToUse.Red() - 1 : colToUse.Red() + 1, colToUse.Green(), colToUse.Blue());
	dc->SetBrush(colToUse);
}
Attachments
33.jpg
33.jpg (25.81 KiB) Viewed 1482 times
Schadensbild_33.rar
(117.42 KiB) Downloaded 27 times
utelle
Moderator
Moderator
Posts: 1065
Joined: Tue Jul 05, 2005 10:00 pm
Location: Cologne, Germany
Contact:

Re: wxPDF: brush & pen funky with multiple rotated rectangles

Post by utelle »

mael15 wrote: Thu Sep 30, 2021 5:04 pm this is really weird and it is very hard to produce a minimal example, so maybe someone knows a solution without having to. i attached a picture of how the pdf page is supposed to look like and the produced pdf. brushed and pens get mixed up, but only if the rectangles are rotated.
i found some hint in my code that might have something to do with it, but the problem stays if I comment this code, so maybe not?
When a transformation matrix is applied (here for rotation) the PDF graphics state is saved and later restored. It looks a bit like that the default fill color (that is, black) is applied after drawing the first rotated rectangle, instead of restoring the correct fill color. This might be a bug in the wxPdfDC implementation, but I have to dive deeper into the code to verify this.

It would be helpful, if you could provide the code you use for drawing a single rotated rectangle with wxDC methods.

Unfortunately I'm very busy for the next couple of days, but I will try to look into this issue over the weekend or early next week.
mael15
Super wx Problem Solver
Super wx Problem Solver
Posts: 496
Joined: Fri May 22, 2009 8:52 am
Location: Bremen, Germany

Re: wxPDF: brush & pen funky with multiple rotated rectangles

Post by mael15 »

okay, it is not an urgent problem. i hope it helps when i concatenate the parts of my code that lead to drawing the rectangle:

Code: Select all

wxPdfDocument pdfDcmt;
pdfDcmt.SetCompression(false);
pdfDcmt.AddPage(orient, papSize);
tpl = pdfDcmt.BeginTemplate();
.................
dc = new wxPdfDC(&pdfDcmt, pageSzMM.x, pageSzMM.y);
dc->SetResolution(600);
dc->SetBackground(*wxWHITE_BRUSH);

if (dc->StartDoc(wxT("Printing ...")))
{
	//OutputDebugString(wxString::Format(wxT("Seite %i wird gedruckt\n"), i));
	libClientOutput::TubeDataPrintout::printToDC(*dc, i - 1);
..........................
wxPdfDocument *pDoc = static_cast<wxPdfDC*>(dc)->GetPdfDocument();
pDoc->StartTransform();

wxSize pgSzWhole = dc ? dc->GetSize() : getPageSizeWhole();
int pageMargin = ScreenPagePanel::getPaperMarginPx(pgSzWhole, getLayout());

// mittelpunkt der bitmap als rotationspunkt berechnen
wxPoint middleBtmpPx(
	pageMargin + btmpHndls->getPositionNormed().x * pgSzDrawable.GetWidth() + btmpSize.GetWidth() / 2,
	pageMargin + btmpHndls->getPositionNormed().y * pgSzDrawable.GetHeight() + btmpSize.GetHeight() / 2);
wxRealPoint middleN(middleBtmpPx.x / (double)pgSzWhole.GetWidth(), middleBtmpPx.y / (double)pgSzWhole.GetHeight());
wxPoint middleMM(middleN.x * pDoc->GetPageWidth(), middleN.y * pDoc->GetPageHeight());

// rotation onScreen ist im UZS und im pdf gegen den UZS
pDoc->Rotate(-rotation, middleMM.x, middleMM.y);
............................................
dc->SetPen(getPen(penWidthPx));
dc->SetBrush(getFill());
slightBrushVariation(dc);	// this is the function from my previous post
dc->DrawRectangle(ret.GetPosition(), sizePx);
thanx! :)
utelle
Moderator
Moderator
Posts: 1065
Joined: Tue Jul 05, 2005 10:00 pm
Location: Cologne, Germany
Contact:

Re: wxPDF: brush & pen funky with multiple rotated rectangles

Post by utelle »

mael15 wrote: Fri Oct 01, 2021 7:08 am i hope it helps when i concatenate the parts of my code that lead to drawing the rectangle:
Thanks for providing the code. I see that you apply the rotation directly to the PDF document instance, not to the drawing context. At least there is a chance that this causes the trouble. When you apply rotation for screen display, you probably use the wxDC method SetTransformMatrix. This should work for wxPdfDC, too. Maybe it's worth a try to use wxDC methods.

As said I will look into this issue in more detail within the next days. If it is a bug in wxPdfDC I will provide a fix asap.

Regards,
Ulrich
utelle
Moderator
Moderator
Posts: 1065
Joined: Tue Jul 05, 2005 10:00 pm
Location: Cologne, Germany
Contact:

Re: wxPDF: brush & pen funky with multiple rotated rectangles

Post by utelle »

utelle wrote: Fri Oct 01, 2021 2:23 pm I see that you apply the rotation directly to the PDF document instance, not to the drawing context. At least there is a chance that this causes the trouble.
That you are applying rotation directly to the PDF document is at least part of the problem. If the fill color is set after a transformation has been started (like rotation), it will be "forgotten" as soon as the transformation has been ended. This is what happens in your application: the desired fill color is set for the first rotated rectangle, but internally "forgotten" after the rotation has been ended and then reverted to the default fill color (black) for the next rotated rectangle. Since wxPdfDC does not know anything about the transformation, it thinks the fill color is still correctly set and is the same for the second rextangle, and therefore the fill color is not applied again.

Unfortunately, using the wxDC methods to apply transformations doesn't help at the moment, because the corresponding wxPdfDC methods do not remember the pen and brush settings. That is, you would experience the same problem.

I will adjust the wxPdfDC methods for applying transformations. However, this will not help to resolve the problem in your use case with transformations directly applied to the underlying PDF document.
mael15
Super wx Problem Solver
Super wx Problem Solver
Posts: 496
Joined: Fri May 22, 2009 8:52 am
Location: Bremen, Germany

Re: wxPDF: brush & pen funky with multiple rotated rectangles

Post by mael15 »

I am not sure if forgetting the settings is the problem here, because I apply the settings before each paint action?

Code: Select all

dc->SetPen(getPen(penWidthPx));
dc->SetBrush(getFill());
slightBrushVariation(dc);	// this is the function from my previous post
dc->DrawRectangle(ret.GetPosition(), sizePx);
Or would you say I have to explicitly include the color here?
utelle
Moderator
Moderator
Posts: 1065
Joined: Tue Jul 05, 2005 10:00 pm
Location: Cologne, Germany
Contact:

Re: wxPDF: brush & pen funky with multiple rotated rectangles

Post by utelle »

mael15 wrote: Mon Oct 04, 2021 2:22 pm I am not sure if forgetting the settings is the problem here, because I apply the settings before each paint action?
The problem is that wxPdfDC tries to be smart and actually only sets the brush color for the PDF document, if the brush color differs from the previous. This is not the case, therefore the color is not set, and since the previous brush color was set within a transformation operation, the PDF "remembers" the wrong fill color, namely the default color that was set on creating the PDF document.

As a workaround you could set first a dummy fill color and then immediately the fill color you really want.
mael15 wrote: Mon Oct 04, 2021 2:22 pm Or would you say I have to explicitly include the color here?
Well, that could also be an option. However, mixing wxPdfDC access with direct access can lead to unexpected results.
utelle
Moderator
Moderator
Posts: 1065
Joined: Tue Jul 05, 2005 10:00 pm
Location: Cologne, Germany
Contact:

Re: wxPDF: brush & pen funky with multiple rotated rectangles

Post by utelle »

The wxPdfDC class has been adjusted to avoid problems in handling pens and brushes when transformations have been started (see wxPdfDocument GitHub repository). However, this will work only, if the transformation was started via wxDC/wxPdfDC methods.
mael15
Super wx Problem Solver
Super wx Problem Solver
Posts: 496
Joined: Fri May 22, 2009 8:52 am
Location: Bremen, Germany

Re: wxPDF: brush & pen funky with multiple rotated rectangles

Post by mael15 »

I downloaded the latest build, unfortunately I did not see a difference.
utelle wrote: Tue Oct 05, 2021 6:13 pm However, this will work only, if the transformation was started via wxDC/wxPdfDC methods.
I do not understand what that means, sorry. :?:
utelle wrote: Mon Oct 04, 2021 3:13 pm As a workaround you could set first a dummy fill color and then immediately the fill color you really want.
dc->SetPen(wxPen(*wxRED)); and dc->SetBrush(wxBrush(*wxRED)); right before setting the wanted pen/brush and drawing did not have an effect.
Can I do something different or will this be fixed at a later time?
utelle
Moderator
Moderator
Posts: 1065
Joined: Tue Jul 05, 2005 10:00 pm
Location: Cologne, Germany
Contact:

Re: wxPDF: brush & pen funky with multiple rotated rectangles

Post by utelle »

mael15 wrote: Fri Oct 08, 2021 3:46 pm I downloaded the latest build, unfortunately I did not see a difference.
utelle wrote: Tue Oct 05, 2021 6:13 pm However, this will work only, if the transformation was started via wxDC/wxPdfDC methods.
I do not understand what that means, sorry. :?:
Well, in your posted code snippet you used

Code: Select all

pDoc->Rotate(-rotation, middleMM.x, middleMM.y);
That is, you applied a transformation of the coordinate system directly to the PDF document. Since wxPdfDC can not detect such modifications, it can not take measures to remember the graphics state. If you use the wxDC method SetTransformMatrix (as you probably do anyway for screen display), it should work. (If not, further investigation will be necessary.)
mael15 wrote: Fri Oct 08, 2021 3:46 pm
utelle wrote: Mon Oct 04, 2021 3:13 pm As a workaround you could set first a dummy fill color and then immediately the fill color you really want.
dc->SetPen(wxPen(*wxRED)); and dc->SetBrush(wxBrush(*wxRED)); right before setting the wanted pen/brush and drawing did not have an effect.
Hm, obviously wxPdfDC is still too smart and takes no action unless the pen/brush has been actually used for some drawing operation.
mael15 wrote: Fri Oct 08, 2021 3:46 pm Can I do something different or will this be fixed at a later time?
At the moment I have no alternative at hand. I will look into the issue and will try to provide a fix.
utelle
Moderator
Moderator
Posts: 1065
Joined: Tue Jul 05, 2005 10:00 pm
Location: Cologne, Germany
Contact:

Re: wxPDF: brush & pen funky with multiple rotated rectangles

Post by utelle »

utelle wrote: Sat Oct 09, 2021 2:33 pm Well, in your posted code snippet you used

Code: Select all

pDoc->Rotate(-rotation, middleMM.x, middleMM.y);
That is, you applied a transformation of the coordinate system directly to the PDF document. Since wxPdfDC can not detect such modifications, it can not take measures to remember the graphics state. If you use the wxDC method SetTransformMatrix (as you probably do anyway for screen display), it should work. (If not, further investigation will be necessary.)
In the meantime I tested the current wxPdfDC implementation more thoroughly. If you use code similar to the following for drawing a rotated rectangle:

Code: Select all

    wxAffineMatrix2D tm;
    tm.Translate(xOffset, yOffset);
    tm.Rotate(radians);
    dc.SetTransformMatrix(tm);
    dc.SetBrush(*wxGREY_BRUSH);
    dc.SetPen(*wxBLUE_PEN);
    dc.DrawRectangle(x, y, width, height);
    dc.ResetTransformMatrix();
and repeat this code for additional rectangles, it works as expected with the current master branch of wxPdfDocument, even if you do not set pen and brush for subsequent rectangles.
utelle wrote: Sat Oct 09, 2021 2:33 pm
mael15 wrote: Fri Oct 08, 2021 3:46 pm dc->SetPen(wxPen(*wxRED)); and dc->SetBrush(wxBrush(*wxRED)); right before setting the wanted pen/brush and drawing did not have an effect.
Hm, obviously wxPdfDC is still too smart and takes no action unless the pen/brush has been actually used for some drawing operation.
Unfortunately, the "workaround" with setting different pens and brushes, before setting the actually wanted pens and brushes will not work, because wxPdfDC compares only the last pen/brush set with SetPen/SetBrush with the pen/brush used in PDF operations.
utelle wrote: Sat Oct 09, 2021 2:33 pm
mael15 wrote: Fri Oct 08, 2021 3:46 pm Can I do something different or will this be fixed at a later time?
At the moment I have no alternative at hand. I will look into the issue and will try to provide a fix.
As described above using wxDC methods for applying transformations like rotations will work as expected. However, applying transformations directly to the underlying PDF document instance (that is, outside of wxPdfDC) will not apply the intended pens/brushes, because wxPdfDC has no means to detect that pens/brushes have to be applied again.
Post Reply