I am trying to fill some particular circle areas on a square grid in Proceesing. However, I am facing some weird filling after I run my code. I used the "atan2" function to get the angle of points in the grid and apply some if conditions to limit the area. But it doesn't work. Actually, it works some way but not exactly what I want.This is the result I run the code-> enter image description here, but it should be like -> enter image description here Can someone help me to solve this, please?
(Additionally, I seized this page to detect which points are in the area I specified enter link description here.
Cell [][] cells;
int res = 10;
PVector circleCenter ;
float rad=290;
void setup() {
size(1200, 800);
cells = new Cell[width/res ][height/res];
for (int i=0; i<cells.length; i++) {
for (int j = 0; j<cells[0].length; j++) {
cells[i][j] = new Cell();
}
}
}
void draw() {
background(255);
circleCenter = new PVector(mouseX, mouseY);
display();
pushStyle();
ellipse(circleCenter.x, circleCenter.y, 20, 20);
popStyle();
//println(frameRate);
}
void display() {
for (int i=0; i<cells.length; i++) {
for (int j = 0; j<cells[0].length; j++) {
if (sq(i*res-width/2) + sq(j*res-height/2) <=sq(rad/2)) {
float angleInRad = atan2(j*res-height/2, i*res-width/2);
///
if (angleInRad<radians(-10) && angleInRad>radians(-60)) {
fill(0, 255, 0); // degrees(atan2(j*res-circleCenter.y, i*res-circleCenter.x))
}
} else {
noFill();
}
rect(i*res, j*res, res, res);
}}
class Cell {
boolean blackness=false;
Cell() {
}
}
You have not specified input data for your task. I assume we have center coordinates cx, cx, radius r, starting and ending angle sa, ea of the sector (in code -10, -60).
There is an approach to check whether vector direction lies in sector, it's robust to potential troubles with periodicity, negative values etc. At first normalize range ends, then find middle angle and half-angle
half = (ea - sa) / 2
mid = (ea + sa) / 2
coshalf = Cos(half)
Now compare that difference of angle and middle one is lower then half-angle
if Cos(angle - mid) >= coshalf then
angle lies in range sa..ea
I'm trying to make a sort of Agar.io clone in Processing. I have spawned in a lot of food dots, but I wanted to also make them move about and bounce off the edges of the screen border to add some flair. However I am not too sure how to go about making the dots all move about randomly.
ArrayList<Ellipse> ellipse = new ArrayList <Ellipse>();
//Images
PImage background;
int x = 2;
//Words
PFont arial;
void setup(){
size(1920,1080);
//Background change
if (x == 1){
background = loadImage("backdrop1.jpg");
}
if (x == 2){
background = loadImage("backdrop2.jpg");
}
//Creating the font
arial = createFont ("Arial", 16, true); //the true is for antialiasing
//Load from text file
//tbd...
//Adding the food ellipses
for(int foodSpawn = 0; foodSpawn < 50; foodSpawn++){
ellipse.add(new Ellipse(random(100,1820),random(100,980), 50, 50));
}
}
void draw(){
background(background);
for(int i = 0; i<ellipse.size(); i++){
Ellipse e = ellipse.get(i);
fill(#62C3E8);
ellipse(e.xLoc,e.yLoc, e.eWidth, e.eHeight);
}
}
class Ellipse {
float xLoc;
float yLoc;
float eWidth;
float eHeight;
public Ellipse(float xLoc, float yLoc, float eWidth, float eHeight){
this.xLoc = xLoc;
this.yLoc = yLoc;
this.eWidth = eWidth;
this.eHeight = eHeight;
}
}
The ellipses already have position attributes, so simply adding a method to move them should work. If you want them to collide realistically with the walls, you'll need to give each ellipse an initial random velocity. Then, you update the position at set time intervals based on the current velocity and the interval length. E.g.:
public void move() {
// Note: these are signed, and xvel and vyel are in pixels/second
float x_move_dist = this.xvel*time_int
float y_move_dist = this.yvel*time_int
// Update xloc
// Check collision with left wall
if (this.xloc + x_move_dist - this.eWidth/2 < 0) {
// Assuming conservation of momentum, we can reflect the movement off the wall
this.xloc = -(this.xloc + x_move_dist + this.eWidth/2)
}
// Check collision with right wall
else if (this.xloc + x_move_dist + this.eWidth/2 > 1920) {
// Again, reflect off wall
this.xloc = 1920 - ((this.xloc + x_move_dist) - 1920) - this.eWidth/2
}
// Otherwise, just update normally
else {
this.xloc = this.xloc + x_move_dist
}
// Update yloc
// Check collision with bottom wall
if (this.yloc + y_move_dist - this.eHeight/2 < 0) {
// Again, reflect off wall
this.yloc = -(this.yloc + y_move_dist) + this.eHeight/2
}
// Check collision with top wall
else if (this.yloc + y_move_dist + this.eHeight/2 > 1080) {
// Again, reflect off wall
this.yloc = 1920 - ((this.yloc + y_move_dist) - 1920) - this.eHeight/2
}
// Otherwise, just update normally
else {
this.yloc = this.yloc + y_move_dist
}
}
There are balls in my app that just fly through display. They draws as I want. But now I want to draw the trail behind them.
All I could make is just drawing by canvas.drawPath something like following picture:
But it is not what I want. It should have pointed tail and gradient color like this:
I have no idea how to make it. Tried BitmapShader - couldn't make something right. Help, please.
Code:
First of all, there is Point class for position on display:
class Point {
float x, y;
...
}
And trail is stored as queue of Point:
private ConcurrentLinkedQueue<Point> trail;
It doesn't matter how it fills, just know it has size limit:
trail.add(position);
if(trail.size() > TRAIL_MAX_COUNT) {
trail.remove();
}
And drawing happened in DrawTrail method:
private void DrawTrail(Canvas canvas) {
trailPath.reset();
boolean isFirst = true;
for(Point p : trail) {
if(isFirst) {
trailPath.moveTo(p.x, p.y);
isFirst = false;
} else {
trailPath.lineTo(p.x, p.y);
}
}
canvas.drawPath(trailPath, trailPaint);
}
By the way, trailPaint is just really fat paint :)
trailPaint = new Paint();
trailPaint.setStyle(Paint.Style.STROKE);
trailPaint.setColor(color);
trailPaint.setStrokeWidth(radius * 2);
trailPaint.setAlpha(150);
I see you want to see a gradient on the ball path, you could use something like this
int x1 = 0, y1 = 0, x2 = 0, y2 = 40;
Shader shader = new LinearGradient(0, 0, 0, 40, Color.WHITE, Color.BLACK, TileMode.CLAMP);
trailPaint = new Paint();
trailPaint.setShader(shader);
This is what you should change your trailPaint to and see if it works.
provided from here.
I found solution. But still think it is not the best one.
First of all there are my class fields used for that task.
static final int TRAIL_MAX_COUNT = 50; //maximum trail array size
static final int TRAIL_DRAW_POINT = 30; //number of points to split the trail for draw
private ConcurrentLinkedQueue<Point> trail;
private Paint[] trailPaints;
private float[][] trailPoss, trailTans;
private Path trailPath;
Additionally to trailPath object I used PathMeasure object to split path to multiple equal parts.
After filling trail array object added call of trail calculating function.
lastTrailAdd = now;
trail.add(pos.Copy());
if (trail.size() > TRAIL_MAX_COUNT) {
trail.remove();
}
FillTrail();
Then my FillTrail function.
private void FillTrail() {
trailPath.reset();
boolean isFirst = true;
for(Point p : trail) {
if(isFirst) {
trailPath.moveTo(p.x, p.y);
trailPoss[0][0] = p.x;
trailPoss[0][1] = p.y;
isFirst = false;
} else {
trailPath.lineTo(p.x, p.y);
}
}
PathMeasure path = new PathMeasure(trailPath, false);
float step = path.getLength() / TRAIL_DRAW_POINT;
for(int i=0; i<TRAIL_DRAW_POINT; i++) {
path.getPosTan(step * i, trailPoss[i], trailTans[i]);
}
}
It separated from drawing thread. Next code is drawing function.
private void DrawTrail(Canvas canvas) {
if(trail.size() > 1) {
float prevWidthHalfX = 0f, prevWidthHalfY = 0f, prevX = 0f, prevY = 0f;
Path trailStepRect = new Path();
boolean isFirst = true;
for (int i = 0; i < TRAIL_DRAW_POINT; i++) {
float currWidthHalf = (float) (radius) * i / TRAIL_DRAW_POINT / 2f,
currWidthHalfX = currWidthHalf * trailTans[i][1],
currWidthHalfY = currWidthHalf * trailTans[i][0],
currX = trailPoss[i][0], currY = trailPoss[i][1];
if (!isFirst) {
trailStepRect.reset();
trailStepRect.moveTo(prevX - prevWidthHalfX, prevY + prevWidthHalfY);
trailStepRect.lineTo(prevX + prevWidthHalfX, prevY - prevWidthHalfY);
trailStepRect.lineTo(currX + currWidthHalfX, currY - currWidthHalfY);
trailStepRect.lineTo(currX - currWidthHalfX, currY + currWidthHalfY);
canvas.drawPath(trailStepRect, trailPaints[i]);
} else {
isFirst = false;
}
prevX = currX;
prevY = currY;
prevWidthHalfX = currWidthHalfX;
prevWidthHalfY = currWidthHalfY;
}
}
}
Main point of this is drawing trail by parts with different paints. Closer to ball - wider the trail. I think I will optimise it, but it is allready work.
If you want to watch how it looks just install my app from google play.
I have a pdf file where-in I am adding a stamp to all it's pages.
But, the problem is, the stamp is added to the upper-left corner of each page. If, the page has text in that part, the stamp appears on the text.
My question is, is there any method by which I can read each page and if there is no text in that part add the stamp else search for nearest available free space, just like what a density scanner does?
I am using IText and Java 1.7.
The free space fider class and the distance calculation function are the same that is there in the accepted answer.
Following is the edited code I am using:
// The resulting PDF file
String RESULT = "K:\\DCIN_TER\\DCIN_EPU2\\CIRCUIT FROM BRANCH\\RAINBOW ORDERS\\" + jtfSONo.getText().trim() + "\\PADR Release\\Final PADR Release 1.pdf";
// Create a reader
PdfReader reader = new PdfReader("K:\\DCIN_TER\\DCIN_EPU2\\CIRCUIT FROM BRANCH\\RAINBOW ORDERS\\" + jtfSONo.getText().trim() + "\\PADR Release\\Final PADR Release.pdf");
// Create a stamper
PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(RESULT));
// Loop over the pages and add a footer to each page
int n = reader.getNumberOfPages();
for(int i = 1; i <= n; i++)
{
Collection<Rectangle2D> rectangles = find(reader, 300, 100, n, stamper); // minimum width & height of a rectangle
Iterator itr = rectangles.iterator();
while(itr.hasNext())
{
System.out.println(itr.next());
}
if(!(rectangles.isEmpty()) && (rectangles.size() != 0))
{
Rectangle2D best = null;
double bestDist = Double.MAX_VALUE;
Point2D.Double point = new Point2D.Double(200, 400);
float x = 0, y = 0;
for(Rectangle2D rectangle: rectangles)
{
double distance = distance(rectangle, point);
if(distance < bestDist)
{
best = rectangle;
bestDist = distance;
x = (float) best.getX();
y = (float) best.getY();
int left = (int) best.getMinX();
int right = (int) best.getMaxX();
int top = (int) best.getMaxY();
int bottom = (int) best.getMinY();
System.out.println("x : " + x);
System.out.println("y : " + y);
System.out.println("left : " + left);
System.out.println("right : " + right);
System.out.println("top : " + top);
System.out.println("bottom : " + bottom);
}
}
getFooterTable(i, n).writeSelectedRows(0, -1, x, y, stamper.getOverContent(i)); // 0, -1 indicates 1st row, 1st column upto last row and last column
}
else
getFooterTable(i, n).writeSelectedRows(0, -1, 94, 140, stamper.getOverContent(i)); // bottom left corner
}
// Close the stamper
stamper.close();
// Close the reader
reader.close();
public Collection<Rectangle2D> find(PdfReader reader, float minWidth, float minHeight, int page, PdfStamper stamper) throws IOException
{
Rectangle cropBox = reader.getCropBox(page);
Rectangle2D crop = new Rectangle2D.Float(cropBox.getLeft(), cropBox.getBottom(), cropBox.getWidth(), cropBox.getHeight());
FreeSpaceFinder finder = new FreeSpaceFinder(crop, minWidth, minHeight);
PdfReaderContentParser parser = new PdfReaderContentParser(reader);
parser.processContent(page, finder);
System.out.println("finder.freeSpaces : " + finder.freeSpaces);
return finder.freeSpaces;
}
// Create a table with page X of Y, #param x the page number, #param y the total number of pages, #return a table that can be used as footer
public static PdfPTable getFooterTable(int x, int y)
{
java.util.Date date = new java.util.Date();
SimpleDateFormat sdf = new SimpleDateFormat("dd MMM yyyy");
String month = sdf.format(date);
System.out.println("Month : " + month);
PdfPTable table = new PdfPTable(1);
table.setTotalWidth(120);
table.setLockedWidth(true);
table.getDefaultCell().setFixedHeight(20);
table.getDefaultCell().setBorder(Rectangle.TOP);
table.getDefaultCell().setBorder(Rectangle.LEFT);
table.getDefaultCell().setBorder(Rectangle.RIGHT);
table.getDefaultCell().setBorderColorTop(BaseColor.BLUE);
table.getDefaultCell().setBorderColorLeft(BaseColor.BLUE);
table.getDefaultCell().setBorderColorRight(BaseColor.BLUE);
table.getDefaultCell().setBorderWidthTop(1f);
table.getDefaultCell().setBorderWidthLeft(1f);
table.getDefaultCell().setBorderWidthRight(1f);
table.getDefaultCell().setHorizontalAlignment(Element.ALIGN_CENTER);
Font font1 = new Font(FontFamily.HELVETICA, 10, Font.BOLD, BaseColor.BLUE);
table.addCell(new Phrase("CONTROLLED COPY", font1));
table.getDefaultCell().setFixedHeight(20);
table.getDefaultCell().setBorder(Rectangle.LEFT);
table.getDefaultCell().setBorder(Rectangle.RIGHT);
table.getDefaultCell().setBorderColorLeft(BaseColor.BLUE);
table.getDefaultCell().setBorderColorRight(BaseColor.BLUE);
table.getDefaultCell().setBorderWidthLeft(1f);
table.getDefaultCell().setBorderWidthRight(1f);
table.getDefaultCell().setHorizontalAlignment(Element.ALIGN_CENTER);
Font font = new Font(FontFamily.HELVETICA, 10, Font.BOLD, BaseColor.RED);
table.addCell(new Phrase(month, font));
table.getDefaultCell().setFixedHeight(20);
table.getDefaultCell().setBorder(Rectangle.LEFT);
table.getDefaultCell().setBorder(Rectangle.RIGHT);
table.getDefaultCell().setBorder(Rectangle.BOTTOM);
table.getDefaultCell().setBorderColorLeft(BaseColor.BLUE);
table.getDefaultCell().setBorderColorRight(BaseColor.BLUE);
table.getDefaultCell().setBorderColorBottom(BaseColor.BLUE);
table.getDefaultCell().setBorderWidthLeft(1f);
table.getDefaultCell().setBorderWidthRight(1f);
table.getDefaultCell().setBorderWidthBottom(1f);
table.getDefaultCell().setHorizontalAlignment(Element.ALIGN_CENTER);
table.addCell(new Phrase("BLR DESIGN DEPT.", font1));
return table;
}
is there any method by which I can read each page and if there is no text in that part add the stamp else search for nearest available free space, just like what a density scanner does?
iText does not offer that functionality out of the box. Depending of what kind of content you want to evade, though, you might consider either rendering the page to an image and looking for white spots in the image or doing text extraction with a strategy that tries to find locations without text.
The first alternative, analyzing a rendered version of the page, would be the focus of a separate question as an image processing library would have to be chosen first.
There are a number of situations, though, in which that first alternative is not the best way to go. E.g. if you only want to evade text but not necessarily graphics (like watermarks), or if you also want to evade invisible text (which usually can be marked in a PDF viewer and, therefore, interfere with your addition).
The second alternative (using text and image extraction abilities of iText) can be the more appropriate approach in such situations.
Here a sample RenderListener for such a task:
public class FreeSpaceFinder implements RenderListener
{
//
// constructors
//
public FreeSpaceFinder(Rectangle2D initialBox, float minWidth, float minHeight)
{
this(Collections.singleton(initialBox), minWidth, minHeight);
}
public FreeSpaceFinder(Collection<Rectangle2D> initialBoxes, float minWidth, float minHeight)
{
this.minWidth = minWidth;
this.minHeight = minHeight;
freeSpaces = initialBoxes;
}
//
// RenderListener implementation
//
#Override
public void renderText(TextRenderInfo renderInfo)
{
Rectangle2D usedSpace = renderInfo.getAscentLine().getBoundingRectange();
usedSpace.add(renderInfo.getDescentLine().getBoundingRectange());
remove(usedSpace);
}
#Override
public void renderImage(ImageRenderInfo renderInfo)
{
Matrix imageMatrix = renderInfo.getImageCTM();
Vector image00 = rect00.cross(imageMatrix);
Vector image01 = rect01.cross(imageMatrix);
Vector image10 = rect10.cross(imageMatrix);
Vector image11 = rect11.cross(imageMatrix);
Rectangle2D usedSpace = new Rectangle2D.Float(image00.get(Vector.I1), image00.get(Vector.I2), 0, 0);
usedSpace.add(image01.get(Vector.I1), image01.get(Vector.I2));
usedSpace.add(image10.get(Vector.I1), image10.get(Vector.I2));
usedSpace.add(image11.get(Vector.I1), image11.get(Vector.I2));
remove(usedSpace);
}
#Override
public void beginTextBlock() { }
#Override
public void endTextBlock() { }
//
// helpers
//
void remove(Rectangle2D usedSpace)
{
final double minX = usedSpace.getMinX();
final double maxX = usedSpace.getMaxX();
final double minY = usedSpace.getMinY();
final double maxY = usedSpace.getMaxY();
final Collection<Rectangle2D> newFreeSpaces = new ArrayList<Rectangle2D>();
for (Rectangle2D freeSpace: freeSpaces)
{
final Collection<Rectangle2D> newFragments = new ArrayList<Rectangle2D>();
if (freeSpace.intersectsLine(minX, minY, maxX, minY))
newFragments.add(new Rectangle2D.Double(freeSpace.getMinX(), freeSpace.getMinY(), freeSpace.getWidth(), minY-freeSpace.getMinY()));
if (freeSpace.intersectsLine(minX, maxY, maxX, maxY))
newFragments.add(new Rectangle2D.Double(freeSpace.getMinX(), maxY, freeSpace.getWidth(), freeSpace.getMaxY() - maxY));
if (freeSpace.intersectsLine(minX, minY, minX, maxY))
newFragments.add(new Rectangle2D.Double(freeSpace.getMinX(), freeSpace.getMinY(), minX - freeSpace.getMinX(), freeSpace.getHeight()));
if (freeSpace.intersectsLine(maxX, minY, maxX, maxY))
newFragments.add(new Rectangle2D.Double(maxX, freeSpace.getMinY(), freeSpace.getMaxX() - maxX, freeSpace.getHeight()));
if (newFragments.isEmpty())
{
add(newFreeSpaces, freeSpace);
}
else
{
for (Rectangle2D fragment: newFragments)
{
if (fragment.getHeight() >= minHeight && fragment.getWidth() >= minWidth)
{
add(newFreeSpaces, fragment);
}
}
}
}
freeSpaces = newFreeSpaces;
}
void add(Collection<Rectangle2D> rectangles, Rectangle2D addition)
{
final Collection<Rectangle2D> toRemove = new ArrayList<Rectangle2D>();
boolean isContained = false;
for (Rectangle2D rectangle: rectangles)
{
if (rectangle.contains(addition))
{
isContained = true;
break;
}
if (addition.contains(rectangle))
toRemove.add(rectangle);
}
rectangles.removeAll(toRemove);
if (!isContained)
rectangles.add(addition);
}
//
// members
//
public Collection<Rectangle2D> freeSpaces = null;
final float minWidth;
final float minHeight;
final static Vector rect00 = new Vector(0, 0, 1);
final static Vector rect01 = new Vector(0, 1, 1);
final static Vector rect10 = new Vector(1, 0, 1);
final static Vector rect11 = new Vector(1, 1, 1);
}
Using this FreeSpaceFinder you can find empty areas with given minimum dimensions in a method like this:
public Collection<Rectangle2D> find(PdfReader reader, float minWidth, float minHeight, int page) throws IOException
{
Rectangle cropBox = reader.getCropBox(page);
Rectangle2D crop = new Rectangle2D.Float(cropBox.getLeft(), cropBox.getBottom(), cropBox.getWidth(), cropBox.getHeight());
FreeSpaceFinder finder = new FreeSpaceFinder(crop, minWidth, minHeight);
PdfReaderContentParser parser = new PdfReaderContentParser(reader);
parser.processContent(page, finder);
return finder.freeSpaces;
}
For your task you now have to choose from the returned rectangles the one which suits you best.
Beware, this code still may have to be tuned to your requirements:
It ignores clip paths, rendering modes, colors, and covering objects. Thus, it considers all text and all bitmap images, whether they are actually visible or not.
It does not consider vector graphics (because the iText parser package does not consider them).
It is not very optimized.
Applied to this PDF page:
with minimum width 200 and height 50, you get these rectangles:
x y w h
000,000 000,000 595,000 056,423
000,000 074,423 595,000 168,681
000,000 267,304 314,508 088,751
000,000 503,933 351,932 068,665
164,296 583,598 430,704 082,800
220,803 583,598 374,197 096,474
220,803 583,598 234,197 107,825
000,000 700,423 455,000 102,396
000,000 700,423 267,632 141,577
361,348 782,372 233,652 059,628
or, more visually, here as rectangles on the page:
The paper plane is a vector graphic and, therefore, ignored.
Of course you could also change the PDF rendering code to not draw stuff you want to ignore and to visibly draw originally invisible stuff which you want to ignore, and then use bitmap image analysis nonetheless...
EDIT
In his comments the OP asked how to find the rectangle in the rectangle collection returned by find which is nearest to a given point.
First of all there not necessarily is the nearest rectangle, there may be multiple.
That been said, one can choose a nearest rectangle as follows:
First one needs to calculate a distance between point and rectangle, e.g.:
double distance(Rectangle2D rectangle, Point2D point)
{
double x = point.getX();
double y = point.getY();
double left = rectangle.getMinX();
double right = rectangle.getMaxX();
double top = rectangle.getMaxY();
double bottom = rectangle.getMinY();
if (x < left) // point left of rect
{
if (y < bottom) // and below
return Point2D.distance(x, y, left, bottom);
if (y > top) // and top
return Point2D.distance(x, y, left, top);
return left - x;
}
if (x > right) // point right of rect
{
if (y < bottom) // and below
return Point2D.distance(x, y, right, bottom);
if (y > top) // and top
return Point2D.distance(x, y, right, top);
return x - right;
}
if (y < bottom) // and below
return bottom - y;
if (y > top) // and top
return y - top;
return 0;
}
Using this distance measurement one can select a nearest rectangle using code like this for a Collection<Rectangle2D> rectangles and a Point2D point:
Rectangle2D best = null;
double bestDist = Double.MAX_VALUE;
for (Rectangle2D rectangle: rectangles)
{
double distance = distance(rectangle, point);
if (distance < bestDist)
{
best = rectangle;
bestDist = distance;
}
}
After this best contains a best rectangle.
For the sample document used above, this method returns the colored rectangles for the page corners and left and right centers:
EDIT TWO
Since iText 5.5.6, the RenderListener interface has been extended as ExtRenderListener to also be signaled about Path construction and path drawing operations. Thus, the FreeSpaceFinder above could also be extended to handle paths:
//
// Additional ExtRenderListener methods
//
#Override
public void modifyPath(PathConstructionRenderInfo renderInfo)
{
List<Vector> points = new ArrayList<Vector>();
if (renderInfo.getOperation() == PathConstructionRenderInfo.RECT)
{
float x = renderInfo.getSegmentData().get(0);
float y = renderInfo.getSegmentData().get(1);
float w = renderInfo.getSegmentData().get(2);
float h = renderInfo.getSegmentData().get(3);
points.add(new Vector(x, y, 1));
points.add(new Vector(x+w, y, 1));
points.add(new Vector(x, y+h, 1));
points.add(new Vector(x+w, y+h, 1));
}
else if (renderInfo.getSegmentData() != null)
{
for (int i = 0; i < renderInfo.getSegmentData().size()-1; i+=2)
{
points.add(new Vector(renderInfo.getSegmentData().get(i), renderInfo.getSegmentData().get(i+1), 1));
}
}
for (Vector point: points)
{
point = point.cross(renderInfo.getCtm());
Rectangle2D.Float pointRectangle = new Rectangle2D.Float(point.get(Vector.I1), point.get(Vector.I2), 0, 0);
if (currentPathRectangle == null)
currentPathRectangle = pointRectangle;
else
currentPathRectangle.add(pointRectangle);
}
}
#Override
public Path renderPath(PathPaintingRenderInfo renderInfo)
{
if (renderInfo.getOperation() != PathPaintingRenderInfo.NO_OP)
remove(currentPathRectangle);
currentPathRectangle = null;
return null;
}
#Override
public void clipPath(int rule)
{
// TODO Auto-generated method stub
}
Rectangle2D.Float currentPathRectangle = null;
(FreeSpaceFinderExt.java)
Using this class the result above is improved to
As you see the paper plane and the table background colorations now also are taken into account.
My other answer focuses on the original question, i.e. how to find free space with given minimum dimensions on a page.
Since that answer had been written, the OP provided code trying to make use of that original answer.
This answer deals with that code.
The code has a number of shortcoming.
The choice of free space on a page depends on the number of pages in the document.
The reason for this is to be found at the start of the loop over the pages:
for(int i = 1; i <= n; i++)
{
Collection<Rectangle2D> rectangles = find(reader, 300, 100, n, stamper);
...
The OP surely meant i, not n there. The code as is always looks for free space on the last document page.
The rectangles are lower than they should be.
The reason for this is to be found in the retrieval and use of the rectangle coordinates:
x = (float) best.getX();
y = (float) best.getY();
...
getFooterTable(i, n).writeSelectedRows(0, -1, x, y, stamper.getOverContent(i));
The Rectangle2D methods getX and getY return the coordinates of the lower left rectangle corner; the PdfPTable methods writeSelectedRows, on the other hand, require the upper left rectangle corner. Thus, getMaxY should be used instead of getY.