I have a bmp with text, for ease of access the bmp rotates accordingly to the user options. Problem: the text gets inverted whenever the image rotates.
(only strict angles, 90, 180, etc)
Possible solution:
Rotate the text at 180º then use the regular rotation, so that it doesnt get mirrored?
I tried this the following way, I create a rectangle around the text and turn it.
Rectangle r1 = new Rectangle((int)(ecobdesenho / 10) / 2 + esp - 15, esp - 25, 25, 12);
using (Matrix m = new Matrix())
{
m.RotateAt(180, new PointF((int)(ecobdesenho / 10) / 2 + esp - 15 + (25 / 2),
esp - 25 + (12 / 2)));
g.Transform = m;
g.DrawRectangle(new Pen(Color.Black), r1);
g.DrawString("e/10", fnt2, new SolidBrush(Color.Black), (int)(ecobdesenho / 10) / 2 + esp - 15, esp - 25); //15 para tras, 15 para cima
g.ResetTransform();
}
Then, i provide the bmp with the rotation before its drawings:
g.TranslateTransform((float)(xWcorrigido / 2 + esp), (float)(yWcorrigido / 2 + esp));
g.RotateTransform(180);
g.TranslateTransform((float)(-xWcorrigido / 2 - esp), (float)(-yWcorrigido / 2 - esp));
However this combination doesnt affect the previous text. I tried to place it inside the using Matrix brackets, but regardless of it, it doesnt apply the whole transformation process.
I could too, first use the general translation, and then turn the text at very specific boxes, but it would give the same amount of work i'm trying to avoid.
Any hint? My brain already hurts with so many possible combinations
The solution is applying the transformation within the matrix, and for the matrix, like this:
Rectangle r1 = new Rectangle((int)(ecobdesenho / 10) / 2 + esp - 15, esp - 25, 25, 12);
using (Matrix m = new Matrix())
{
m.TranslateTransform((float)(xWcorrigido / 2 + esp), (float)(yWcorrigido / 2 + esp));
m.RotateTransform(180);
m.TranslateTransform((float)(-xWcorrigido / 2 - esp), (float)(-yWcorrigido / 2 - esp));
m.RotateAt(180, new PointF((int)(ecobdesenho / 10) / 2 + esp - 15 + (25 / 2),
esp - 25 + (12 / 2)));
g.Transform = m;
g.DrawRectangle(new Pen(Color.Black), r1);
g.DrawString("e/10", fnt2, new SolidBrush(Color.Black), (int)(ecobdesenho / 10) / 2 + esp - 15, esp - 25); //15 para tras, 15 para cima
g.ResetTransform();
}
Related
I am trying to create custom digital signatures using iText (sharp, version 5.5.13) where the user is able to set the image location from a set of four positions (top, bottom, left and right), as shown below:
Rigth:
Left:
Top:
Bottom:
So far I tried working on layer 0 of the signature but I think I doing it wrong because signature details are set in layer 2.
Nevertheless, this is just an initial sketch to set position of the images. In the following code I load the image and put it in a chunk (idea taken from this example)
PdfTemplate pdfTemplate = sap.GetLayer(0);
ColumnText c1 = new ColumnText(pdfTemplate);
Image img = Image.GetInstance(signatureImage);
Phrase elements = new Phrase();
elements.Add(new Chunk(img, 0, 0, true));
//c1.SetSimpleColumn(elements, 0, 0, rectangle.Width, rectangle.Height / 4, 0, Element.ALIGN_CENTER); // align bottom
//c1.SetSimpleColumn(elements, 0, rectangle.Height / 2, rectangle.Width, rectangle.Height, 0, Element.ALIGN_CENTER); // align top
c1.SetSimpleColumn(elements, rectangle.Width/2, 0, rectangle.Width, rectangle.Height, 0, Element.ALIGN_CENTER); // align right
//c1.SetSimpleColumn(elements, 0, 0, rectangle.Width/2, rectangle.Height, 0, Element.ALIGN_CENTER); // align left
c1.Go();
The result is more or less the expected, but there are two problems: the signature information takes over the whole rectangle (this is normal since I do not modify layer 2, and the image in layer 0 is not scaled as it should)
If I scale the image to fit the column, it goes to the top of rectangle:
Is there any way to do this "out of the box" or I need to overload the method that builds the signature appearance (like this) and how can I achieve this?
My initial concert was not to use iText (v7) because we do not have much time to migrate all the projects we have with iText (v5), but I went ahead and tried out with v7. But to be honest is does not seem to be very easy to achieve with v5.
On the other hand, in iText (v7) I was able to do this very quickly with this simple method:
private static void SetCustomSignature(PdfDocument doc, PdfSignatureAppearance sap, SignatureFormat signatureFormat, X509Certificate2 signerCertificate) {
string signatureFont = signatureFormat.Font;
float signatureFontSize = float.Parse(signatureFormat.FontSize);
Rectangle rect = new Rectangle(250, 100, 200, 80);
sap.SetPageRect(rect).SetPageNumber(1);
PdfFormXObject layer2 = sap.GetLayer2();
PdfCanvas canvas = new PdfCanvas(layer2, doc);
float MARGIN = 2;
PdfFont font = PdfFontFactory.CreateFont();
string signingText = GetSignatureInfo(signerCertificate, signatureFormat);
// Signature at left and image at right
//Rectangle dataRect = new Rectangle(rect.GetWidth() / 2 + MARGIN / 2, MARGIN, rect.GetWidth() / 2 - MARGIN, rect.GetHeight() - 2 * MARGIN);
//Rectangle signatureRect = new Rectangle(MARGIN, MARGIN, rect.GetWidth() / 2 - 2 * MARGIN, rect.GetHeight() - 2 * MARGIN);
// Signature at right and image at left
//Rectangle dataRect = new Rectangle(MARGIN, MARGIN, rect.GetWidth() / 2 - MARGIN, rect.GetHeight() - 2 * MARGIN);
//Rectangle signatureRect = new Rectangle(rect.GetWidth() / 2 + MARGIN / 2, MARGIN, rect.GetWidth() / 2 - 2 * MARGIN, rect.GetHeight() - 2 * MARGIN);
// Signature at top and image at bottom
//Rectangle dataRect = new Rectangle(MARGIN, MARGIN, rect.GetWidth() - 2 * MARGIN, rect.GetHeight() / 2 - MARGIN);
//Rectangle signatureRect = new Rectangle(MARGIN, rect.GetHeight() / 2 + MARGIN, rect.GetWidth() - 2 * MARGIN, rect.GetHeight() / 2 - MARGIN);
// Signature at bottom and image at top
Rectangle dataRect = new Rectangle(MARGIN, rect.GetHeight() / 2 + MARGIN, rect.GetWidth() - 2 * MARGIN, rect.GetHeight() / 2 - MARGIN);
Rectangle signatureRect = new Rectangle(MARGIN, MARGIN, rect.GetWidth() - 2 * MARGIN, rect.GetHeight() / 2 - MARGIN);
try {
Canvas signLayoutCanvas = new Canvas(canvas, doc, signatureRect);
Paragraph paragraph = new Paragraph(signingText).SetFont(font).SetMargin(0).SetMultipliedLeading(0.9f).SetFontSize(10);
Div div = new Div();
div.SetHeight(signatureRect.GetHeight());
div.SetWidth(signatureRect.GetWidth());
div.SetVerticalAlignment(iText.Layout.Properties.VerticalAlignment.MIDDLE);
div.SetHorizontalAlignment(iText.Layout.Properties.HorizontalAlignment.CENTER);
div.Add(paragraph);
signLayoutCanvas.Add(div);
Canvas dataLayoutCanvas = new Canvas(canvas, doc, dataRect);
Image image = new Image(ImageDataFactory.Create(signatureFormat.SignatureImage));
image.SetAutoScale(true);
Div dataDiv = new Div();
dataDiv.SetHeight(dataRect.GetHeight());
dataDiv.SetWidth(dataRect.GetWidth());
dataDiv.SetVerticalAlignment(iText.Layout.Properties.VerticalAlignment.MIDDLE);
dataDiv.SetHorizontalAlignment(iText.Layout.Properties.HorizontalAlignment.CENTER);
dataDiv.Add(image);
dataLayoutCanvas.Add(dataDiv);
}
catch {
throw;
}
}
This will result in the following signatures:
Of course, it still needs some improvements but it may serve as an example for others :-)
I have a rectangular selection made programatically on an Image.The user is provided the option to set the size of the rectangle,on doing so the rectangle size should increase but the center point of the old rectangle should be maintained,so that the contents within the rectangle is not out of focus.
Is this a correct approach
objSmall.X = CInt(objBig.X + (Math.Round(((objBig.Width / 2) - (objSmall.Width / 2)), 0)))
objSmall.Y = CInt(objBig.Y + (Math.Round(((objBig.Height / 2) - (objSmall.Height / 2)), 0)))
The new rectangle can be larger or smaller than the old one.
The calculation is correct; it can be simplified using just one integer division:
(and translated to C#, because the source code is VB.Net)
An integer division (MSDN Docs) can be used because we're dividing by 2, it's like rounding down. But you should use floating point values (float) when drawing, especially moving objects (with values expressed in both degrees and, of course, radians): your positions will be off quite a bit if you don't.
objSmall.X = objBig.X + (objBig.Width - objSmall.Width) / 2;
objSmall.Y = objBig.Y + (objBig.Height - objSmall.Height) / 2;
Or (2):
objSmall.Location = new Point(objBig.X + (objBig.Width - objSmall.Width) / 2,
objBig.Y + (objBig.Height - objSmall.Height) / 2);
Or, using the relative Centre coordinates of the larger object:
Point BigRectCenter = new Point((objBig.Width / 2) + objBig.X, (objBig.Height / 2) + objBig.Y);
objSmall.Location = new Point(BigRectCenter.X - (objSmall.Width / 2),
BigRectCenter.Y - (objSmall.Height / 2));
The (2) method can be also used when you don't know which one of the Rectangles is the largest.
Assume you know your reference Rectangle's Location and Size and you let the User specify the new Size of the selection:
Rectangle OriginalRect = new Rectangle(30, 30, 120, 90);
Rectangle ResizedRect = new Rectangle(0, 0, 140, 140);
The ResizedRect has a Size (defined by the User) but its Location is unknown at this point.
The new selection Rectangle's (ResizedRect) Location can be calculated with:
ResizedRect.Location = new Point(OriginalRect.X + (OriginalRect.Width - ResizedRect.Width) / 2,
OriginalRect.Y + (OriginalRect.Height - ResizedRect.Height) / 2);
Original Selection (Green) Original Selection (Green)
(20, 20, 120, 120) (30, 30, 120, 90)
Resized Selection (Red) Resized Selection (Red)
( 0, 0, 95, 86) ( 0, 0, 140, 140)
Calculated Selection Calculated Selection
Rectangle Rectangle
(32, 37, 95, 86) (20, 5, 140, 140)
I'm using the method posted here
Using a matrix to rotate rectangles individually
(I hope this is not a repost, if it is maybe i'm doing something wrong)
I'm using the perfectly defined RotateRectangle method as follows
public void RotateRectangle(Graphics g, Rectangle r, float angle)
{
using (Matrix m = new Matrix())
{
m.RotateAt(angle, new PointF(r.Left + (r.Width / 2),
r.Top + (r.Height / 2)));
g.Transform = m;
g.DrawRectangle(Pens.Black, r);
g.ResetTransform();
}
}
And then on my drawing i create a label, and a rectangle outside of it
g.DrawString("e/10", fnt2, new SolidBrush(Color.Black), (int)(ecobdesenho / 10) / 2 + esp - 15, esp - 25); //15 para tras, 15 para cima
Rectangle r1 = new Rectangle((int)(ecobdesenho / 10) / 2 + esp - 15, esp - 25, 25, 12);
RotateRectangle(g, r1, 40);
(Notice the rectangle in top left corner)
Am I missing something? Or should I go eat bananas?
Your RotateRectangle is not rotating a rectangle of canvas; it's drawing a rotated rectangle.
Everything that's drawn between setting the Transform and the ResetTransform will be drawn rotated.
Therefore, if you want the DrawString to be rotated, you need to put it after you set the Transform, and before you reset it.
using (Matrix m = new Matrix())
{
m.RotateAt(angle, new PointF(r.Left + (r.Width / 2),
r.Top + (r.Height / 2)));
g.Transform = m;
g.DrawString("e/10", fnt2, new SolidBrush(Color.Black), (int)(ecobdesenho / 10) / 2 + esp - 15, esp - 25); //15 para tras, 15 para cima
g.DrawRectangle(Pens.Black, r);
g.ResetTransform();
}
I have a script attached to the main camera in my Unity scene that enables me to draw an isometric grid centered on the origin point, using good old OpenGl Lines.
As indicated in Unity's documentation (there), I launch the drawing on the "OnPostRender" event ; problem is lines only get drawn in Game view, and not in Edit view (even with the [ExecuteInEditMode] instruction).
Is there a way to get them drawn there?
--
Btw, here is the code (C#) for the function :
void OnPostRender()
{
CreateLineMaterial();
// set the current material
lineMaterial.SetPass( 0 );
GL.Begin( GL.LINES );
GL.Color(mainColor);
// Draw x lines
for (int x = - gridSizeX / 2; x <= gridSizeX / 2; x++) {
GL.Vertex3 (- gridSizeX / 4 + x, - gridSizeX / 8, 0 - x * 0.5f);
GL.Vertex3 (gridSizeX / 4 + x, gridSizeX / 8, 0 - x * 0.5f);
}
// Draw y lines
for (int y = - gridSizeY / 2; y <= gridSizeY / 2; y++) {
GL.Vertex3 (- gridSizeY / 4 + y, gridSizeY / 8, 0 - y * 0.5f);
GL.Vertex3 (gridSizeY / 4 + y, - gridSizeY / 8, 0 - y * 0.5f);
}
GL.End();
}
God, I knew it would be like this. I got stuck on this the whole afternoon and when I eventually decide to submit a question here, I actually find the solution.
So I apologize for your wasted time.
Btw, solution was just to draw grid on the OnDrawGizmos event...
A couple of days ago I started looking into efficiently drawing bezier curves, and I came across a this method developed by Charles Loop and Jim Blinn that seemed very interesting. How ever, after a lot of experimenting with their algorithm, I just can't seem to get it to be able to render the cubic curves. Quadratics are fine, no problem there.
The only resources I have found so far are as follows:
GPU Gems 3 Chapter 25
Curvy Blues
Resolution Independent Curve Rendering using Programmable Graphics Hardware
To get the testing up and running quickly, I'm doing this in XNA. Basically I'm passing texture coordinates with my vertices to the GPU, apply a perspective transform and use the formula mentioned in all the articles in a pixel shader to render the final result. How ever, the problem (I think) lays in how I calculate the texture coordinates. Check this code out:
public void Update()
{
float a1 = Vector3.Dot(p1, Vector3.Cross(p4, p3));
float a2 = Vector3.Dot(p2, Vector3.Cross(p1, p4));
float a3 = Vector3.Dot(p3, Vector3.Cross(p2, p2));
float d1 = a1 - 2 * a2 + 3 * a3;
float d2 = -a2 + 3 * a3;
float d3 = 3 * a3;
float discr = d1 * d1 * (3 * d2 * d2 - 4 * d1 * d3);
if (discr > 0)
{
Type = CurveTypes.Serpentine;
float ls = 3 * d2 - (float)Math.Sqrt(9 * d2 * d2 - 12 * d1 * d3);
float lt = 6 * d1;
float ms = 3 * d2 + (float)Math.Sqrt(9 * d2 * d2 - 12 * d1 * d3);
float mt = 6 * d1;
TexCoord1 = new Vector3(ls * ms, (float)Math.Pow(ls, 3), (float)Math.Pow(ms, 3));
TexCoord2 = new Vector3((3 * ls * ms - ls * mt - lt * ms) / 3, ls * ls * (ls - lt), ms * ms * (ms - mt));
TexCoord3 = new Vector3((lt * (mt - 2 * ms) + ls * (3 * ms - 2 * mt)) / 3, (float)Math.Pow(lt - ls, 2) * ls, (float)Math.Pow(mt - ms, 2) * ms);
TexCoord4 = new Vector3((lt - ls) * (mt - ms), -(float)Math.Pow(lt - ls, 3), -(float)Math.Pow(mt - ms, 3));
}
else if (discr == 0)
{
Type = CurveTypes.Cusp;
}
else if (discr < 0)
{
Type = CurveTypes.Loop;
}
}
Excuse the mess, it's just some testing code. p1...p4 are the control points in world space, and TexCoord1...TexCoord4 are the corresponding texture coordinates. This is a replication of what is said in the GPU Gems article.
There are a few problems here, first when calculating a3, we use p2 for both parameters, which of course always results in a (0,0,0) vector, and taking the dot product of that and p3 will always give us 0. That't pretty useless, so why would they mention that in the article?
This will of course make discr incorrect, and we won't even be able to determine what type of curve it is.
After fiddling around with that code for a while, I decided to try to do it exactly the why they did in in the Loop and Blinn paper. From that I get something like this:
public void Update()
{
Matrix m1 = new Matrix(
p4.X, p4.Y, 1, 0,
p3.X, p3.Y, 1, 0,
p2.X, p2.Y, 1, 0,
0, 0, 0, 1);
Matrix m2 = new Matrix(
p4.X, p4.Y, 1, 0,
p3.X, p3.Y, 1, 0,
p1.X, p1.Y, 1, 0,
0, 0, 0, 1);
Matrix m3 = new Matrix(
p4.X, p4.Y, 1, 0,
p2.X, p2.Y, 1, 0,
p1.X, p1.Y, 1, 0,
0, 0, 0, 1);
Matrix m4 = new Matrix(
p3.X, p3.Y, 1, 0,
p2.X, p2.Y, 1, 0,
p1.X, p1.Y, 1, 0,
0, 0, 0, 1);
float det1 = m1.Determinant();
float det2 = -m2.Determinant();
float det3 = m3.Determinant();
float det4 = -m4.Determinant();
float tet1 = det1 * det3 - det2 * det2;
float tet2 = det2 * det3 - det1 * det4;
float tet3 = det2 * det4 - det3 * det3;
float discr = 4 * tet1 * tet3 - tet2 * tet2;
if (discr > 0)
{
Type = CurveTypes.Serpentine;
float ls = 2 * det2;
float lt = det3 + (float)((1 / Math.Sqrt(3)) * Math.Sqrt(3 * det3 * det3 - 4 * det2 * det4));
float ms = 2 * det2;
float mt = det3 - (float)((1 / Math.Sqrt(3)) * Math.Sqrt(3 * det3 * det3 - 4 * det2 * det4));
TexCoord1 = new Vector3(lt * mt, (float)Math.Pow(lt, 3), (float)Math.Pow(mt, 3));
TexCoord2 = new Vector3(-ms * lt - ls * mt, -3 * ls * lt * lt, -3 * ms * mt * mt);
TexCoord3 = new Vector3(ls * ms, 3 * ls * ls * lt, 3 * ms * ms * mt);
TexCoord4 = new Vector3(0, -ls * ls * ls, -ms * ms * ms);
}
else if (discr == 0)
{
Type = CurveTypes.Cusp;
}
else if (discr < 0)
{
Type = CurveTypes.Loop;
}
}
Guess what, that didn't work either. How ever, discr seem to be at least a little more correct now. At least it has the right sign, and it is zero when the control points are arranged to form a cusp. I still get the same visual result though, except the curve disappears randomly for a while (the pixel shader formula is always greater than zero) and returns after I move the control point back to more of a square shape. Here is the pixel shader code by the way:
PixelToFrame PixelShader(VertexToPixel PSIn)
{
PixelToFrame Output = (PixelToFrame)0;
if(pow(PSIn.TexCoords.x, 3) - PSIn.TexCoords.y * PSIn.TexCoords.z > 0)
{
Output.Color = float4(0,0,0,0.1);
}
else
{
Output.Color = float4(0,1,0,1);
}
return Output;
}
That is about all useful information I can think of right now. Does anyone have any idea what's going on? Because I'm running out of them.
I was looking at the paper and your code, and it seams you're missing the multiplication to the M3 matrix.
Your p1, p2, p3 and p4 coordinates should be placed in a matrix and multiplied by the M3 matrix, before using it to calculate the determinants.
eg.
Matrix M3 = Matrix(
1, 0, 0, 0,
-3, 3, 0, 0,
3, -6, 3, 0,
-1, 3, -3, 1);
Matrix B = Matrix(
p1.X, p1.Y, 0, 1,
p2.X, p2.Y, 0, 1,
p3.X, p3.Y, 0, 1,
p4.X, p4.Y, 0, 1);
Matrix C = M3*B;
Then you use each row of the C matrix as the coordinates for the m1 to m4 matrices in your code. Where the first and second values of the row are the x,y coordinates and the last is the w coordinate.
Finally the matrix of texture coordinates needs to be mutiplied by the inverse of M3
eg.
Matrix invM3 = Matrix(
1, 0, 0, 0,
1, 0.3333333, 0, 0,
1, 0.6666667, 0.333333, 0,
1, 1, 1, 1);
Matrix F = Matrix(
TexCoord1,
TexCoord2,
TexCoord3,
TexCoord4);
Matrix result = invM3*F;
Each row of the resulting matrix corresponds to the texture coordinates needed for the shader.
I haven't implemented it myself yet, so cannot guarantee that that it will solve your problem. It simply is what I noticed to be missing from your implementation after reading the paper.
I hope this helps, if I'm wrong please tell me cause I will be trying this out soon.