Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 1 year ago.
Improve this question
I want to make an app in which when i touch at a point on the screen and drag to another position,a line get drawn on ACTION_UP and then another line from the ACTION_UP position to some other point and so on.But the line we have drawn before should not disappear on drawing a new line.
public class LineDrawerView extends View
{
public LineDrawerView(Context context, AttributeSet attrs) {
super(context, attrs);
}
ArrayList<Rect> lines= new ArrayList<Rect>();
int x1, y1;
int x2, y2;
boolean drawing=false;
#Override
protected void onDraw(Canvas canvas)
{
super.onDraw(canvas);
canvas.drawColor(Color.YELLOW);
Paint p= new Paint();
p.setColor(Color.BLACK);
if (drawing)
canvas.drawLine(x1, y1, x2, y2, p);
else
for (int i=0; i<lines.size(); i++)
{
Rect currline= lines.get(i);
canvas.drawLine(currline.left, currline.top, currline.right, currline.bottom, p);
}
}
#Override
public boolean onTouchEvent(MotionEvent event)
{
boolean result=false;
switch (event.getAction())
{
case MotionEvent.ACTION_DOWN:
x1=x2= (int)event.getX();
y1=y2= (int)event.getY();
drawing=true;
result=true;
break;
case MotionEvent.ACTION_MOVE:
x2= (int)event.getX();
y2= (int)event.getY();
result=true;
break;
case MotionEvent.ACTION_UP:
x2= (int)event.getX();
y2= (int)event.getY();
lines.add(new Rect(x1, y1, x2, y2));
drawing=false;
result=true;
break;
}
if (result) invalidate();
return result;
}
}
Related
When you want to create a visible signature using PDFBox you need to create a Rectangle2D object.
Rectangle2D humanRect = new Rectangle2D.Float(100, 200, 150, 50);
I would like to know if it is possible to find all the white spaces(rectangles) in the document(or from the first/last page) of a certain size (width x height).
I would like to choose one of these positions for my signature form.
I would like to use it as in the following example:
Rectangle2D humanRect = new Rectangle2D.Float(foundX, foundY, width, height);
As already confirmed in a comment to the question, you essentially are looking for a port of the functionality of the FreeSpaceFinder and FreeSpaceFinderExt classes for iText from this answer to PDFBox. This is the focus of this answer:
If you want to determine something from the content stream instructions of a page with PDFBox, you usually will create a class based on PDFStreamEngine or one of its subclasses. For anything that's not focusing on text extraction most often the PDFGraphicsStreamEngine is the base class of choice.
Based on that we can essentially copy the functionality of the mentioned iText based classes:
public class FreeSpaceFinder extends PDFGraphicsStreamEngine {
//
// constructors
//
public FreeSpaceFinder(PDPage page, float minWidth, float minHeight) {
this(page, page.getCropBox().toGeneralPath().getBounds2D(), minWidth, minHeight);
}
public FreeSpaceFinder(PDPage page, Rectangle2D initialBox, float minWidth, float minHeight) {
this(page, Collections.singleton(initialBox), minWidth, minHeight);
}
public FreeSpaceFinder(PDPage page, Collection<Rectangle2D> initialBoxes, float minWidth, float minHeight) {
super(page);
this.minWidth = minWidth;
this.minHeight = minHeight;
this.freeSpaces = initialBoxes;
}
//
// Result
//
public Collection<Rectangle2D> getFreeSpaces() {
return freeSpaces;
}
//
// Text
//
#Override
protected void showGlyph(Matrix textRenderingMatrix, PDFont font, int code, Vector displacement)
throws IOException {
super.showGlyph(textRenderingMatrix, font, code, displacement);
Shape shape = calculateGlyphBounds(textRenderingMatrix, font, code);
if (shape != null) {
Rectangle2D rect = shape.getBounds2D();
remove(rect);
}
}
/**
* Copy of <code>org.apache.pdfbox.examples.util.DrawPrintTextLocations.calculateGlyphBounds(Matrix, PDFont, int)</code>.
*/
private Shape calculateGlyphBounds(Matrix textRenderingMatrix, PDFont font, int code) throws IOException
{
GeneralPath path = null;
AffineTransform at = textRenderingMatrix.createAffineTransform();
at.concatenate(font.getFontMatrix().createAffineTransform());
if (font instanceof PDType3Font)
{
// It is difficult to calculate the real individual glyph bounds for type 3 fonts
// because these are not vector fonts, the content stream could contain almost anything
// that is found in page content streams.
PDType3Font t3Font = (PDType3Font) font;
PDType3CharProc charProc = t3Font.getCharProc(code);
if (charProc != null)
{
BoundingBox fontBBox = t3Font.getBoundingBox();
PDRectangle glyphBBox = charProc.getGlyphBBox();
if (glyphBBox != null)
{
// PDFBOX-3850: glyph bbox could be larger than the font bbox
glyphBBox.setLowerLeftX(Math.max(fontBBox.getLowerLeftX(), glyphBBox.getLowerLeftX()));
glyphBBox.setLowerLeftY(Math.max(fontBBox.getLowerLeftY(), glyphBBox.getLowerLeftY()));
glyphBBox.setUpperRightX(Math.min(fontBBox.getUpperRightX(), glyphBBox.getUpperRightX()));
glyphBBox.setUpperRightY(Math.min(fontBBox.getUpperRightY(), glyphBBox.getUpperRightY()));
path = glyphBBox.toGeneralPath();
}
}
}
else if (font instanceof PDVectorFont)
{
PDVectorFont vectorFont = (PDVectorFont) font;
path = vectorFont.getPath(code);
if (font instanceof PDTrueTypeFont)
{
PDTrueTypeFont ttFont = (PDTrueTypeFont) font;
int unitsPerEm = ttFont.getTrueTypeFont().getHeader().getUnitsPerEm();
at.scale(1000d / unitsPerEm, 1000d / unitsPerEm);
}
if (font instanceof PDType0Font)
{
PDType0Font t0font = (PDType0Font) font;
if (t0font.getDescendantFont() instanceof PDCIDFontType2)
{
int unitsPerEm = ((PDCIDFontType2) t0font.getDescendantFont()).getTrueTypeFont().getHeader().getUnitsPerEm();
at.scale(1000d / unitsPerEm, 1000d / unitsPerEm);
}
}
}
else if (font instanceof PDSimpleFont)
{
PDSimpleFont simpleFont = (PDSimpleFont) font;
// these two lines do not always work, e.g. for the TT fonts in file 032431.pdf
// which is why PDVectorFont is tried first.
String name = simpleFont.getEncoding().getName(code);
path = simpleFont.getPath(name);
}
else
{
// shouldn't happen, please open issue in JIRA
System.out.println("Unknown font class: " + font.getClass());
}
if (path == null)
{
return null;
}
return at.createTransformedShape(path.getBounds2D());
}
//
// Bitmaps
//
#Override
public void drawImage(PDImage pdImage) throws IOException {
Matrix ctm = getGraphicsState().getCurrentTransformationMatrix();
Rectangle2D unitSquare = new Rectangle2D.Float(0, 0, 1, 1);
Path2D path = new Path2D.Float(unitSquare);
path.transform(ctm.createAffineTransform());
remove(path.getBounds2D());
}
//
// Paths
//
#Override
public void appendRectangle(Point2D p0, Point2D p1, Point2D p2, Point2D p3) throws IOException {
currentPath.moveTo(p0.getX(), p0.getY());
currentPath.lineTo(p1.getX(), p1.getY());
currentPath.lineTo(p2.getX(), p2.getY());
currentPath.lineTo(p3.getX(), p3.getY());
currentPath.closePath();
}
#Override
public void clip(int windingRule) throws IOException {
// ignore
}
#Override
public void moveTo(float x, float y) throws IOException {
currentPath.moveTo(x, y);
}
#Override
public void lineTo(float x, float y) throws IOException {
currentPath.lineTo(x, y);
}
#Override
public void curveTo(float x1, float y1, float x2, float y2, float x3, float y3) throws IOException {
currentPath.curveTo(x1, y1, x2, y2, x3, y3);
}
#Override
public Point2D getCurrentPoint() throws IOException {
// To prevent many warnings...
return new Point2D.Float();
}
#Override
public void closePath() throws IOException {
currentPath.closePath();
}
#Override
public void endPath() throws IOException {
currentPath = new Path2D.Float();
}
#Override
public void strokePath() throws IOException {
// Better only remove the bounding boxes of the constituting strokes
remove(currentPath.getBounds2D());
currentPath = new Path2D.Float();
}
#Override
public void fillPath(int windingRule) throws IOException {
// Better only remove the bounding boxes of the constituting subpaths
remove(currentPath.getBounds2D());
currentPath = new Path2D.Float();
}
#Override
public void fillAndStrokePath(int windingRule) throws IOException {
// Better only remove the bounding boxes of the constituting subpaths
remove(currentPath.getBounds2D());
currentPath = new Path2D.Float();
}
#Override
public void shadingFill(COSName shadingName) throws IOException {
// ignore
}
//
// 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);
}
//
// hidden members
//
Path2D currentPath = new Path2D.Float();
Collection<Rectangle2D> freeSpaces = null;
final float minWidth;
final float minHeight;
}
(FreeSpaceFinder)
Using this FreeSpaceFinder you can find empty areas with given minimum dimensions in a method like this:
public Collection<Rectangle2D> find(PDDocument pdDocument, PDPage pdPage, float minWidth, float minHeight) throws IOException {
FreeSpaceFinder finder = new FreeSpaceFinder(pdPage, minWidth, minHeight);
finder.processPage(pdPage);
return finder.getFreeSpaces();
}
(DetermineFreeSpaces method find)
Applied to the same PDF page as was the iText centric solution with minimum width 200 and height 50, we get:
Comparing to the analogous screen shot for the iText variant, we see that we get more possible rectangles here.
This is due to the iText solution using the font-level ascender and descender while we here use the individual glyph bounding boxes.
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 6 years ago.
Improve this question
In Objective-C it is quite common to use boolean pointers to stop an enumeration e.g.:
[myArray rh_iterate:^(id element, int index, BOOL *stop){
// Do cool stuff
*stop = YES;
}];
I've implemented this like:
// This is in a category of NSArray
- (void)rh_iterate:(void (^)(id, int, BOOL *))block
{
if (!block) { return; }
BOOL stop = NO;
for (int i = 0; i < self.count; i++) {
block(self[i], i, &stop);
if (stop) { return; }
}
}
I'm now implementing my version of this in Swift but am not relying on any Objective-C source code. I know that swift likes to restrict the access of pointers so what's the best way to go about implementing this? (Ideally completely avoiding pointers.)
EDIT:
The most direct way is:
func rh_iterate(callback: (Element, Int, UnsafeMutablePointer<Bool>) -> ()) {
var stop: Bool = false
for (index, element) in self.enumerate() {
callback(element, index, &stop)
if stop { return }
}
}
Since AMomchilov deleted his answer, I'll put it back.
The direct equivalent to the BOOL* pattern would be an inout variable
extension Array
{
func iterateWithStop(closure: (Element, inout shouldStop: Bool) -> ()) -> Bool
{
var shouldStop = false
for e in self
{
guard !shouldStop else { return false }
closure(e, shouldStop: &shouldStop)
}
return !shouldStop
}
}
The function returns true if the iteration completed without the closure trying to stop it, false if the closure did try to stop it.
You would use it like this:
let myArray = [1, 2, 3, -1, 4]
var sum = 0
let didProcessAllElements = myArray.iterateWithStop{ e, shouldStop in
if e < 0
{
shouldStop = true
}
else
{
sum += e
}
}
// sum == 6
(tested in a playground on Swift 2.2)
as basis for my GPS functionality I've taken HelloMap3D Example of Nutiteq (Thx Jaak) and I adapted to show my current GPS position light different of this example, so, no growing yelow circles but a fix blue translucent circle with a center point as my current Position and works fine except the update. It should erase the past position if location is changed, so that
this update happens as in the example in the method onLocationChanged
This is the code in my Main Activity
protected void initGps(final MyLocationCircle locationCircle) {
final Projection proj = mapView.getLayers().getBaseLayer().getProjection();
locationListener = new LocationListener() {
#Override
public void onLocationChanged(Location location) {
locationCircle.setLocation(proj, location);
locationCircle.setVisible(true);
}
// Another Methods...
}
}
I have adapted MyLocationCircle Class like this
public void update() {
//Draw center with a drawable
Bitmap bitmapPosition = BitmapFactory.decodeResource(activity.getResources(), R.drawable.ic_home);
PointStyle pointStyle = PointStyle.builder().setBitmap(bitmapPosition).setColor(Color.BLUE).build();
// Create/update Point
if ( point == null ) {
point = new Point(circlePos, null, pointStyle, null);
layer.add(point);
} else { // We just have to change the Position to actual Position
point.setMapPos(circlePos);
}
point.setVisible(visible);
// Build closed circle
circleVerts.clear();
for (float tsj = 0; tsj <= 360; tsj += 360 / NR_OF_CIRCLE_VERTS) {
MapPos mapPos = new MapPos(circleScale * Math.cos(tsj * Const.DEG_TO_RAD) + circlePos.x, circleScale * Math.sin(tsj * Const.DEG_TO_RAD) + circlePos.y);
circleVerts.add(mapPos);
}
// Create/update line
if (circle == null) {
LineStyle lineStyle = LineStyle.builder().setWidth(0.05f).setColor(Color.BLUE).build();
PolygonStyle polygonStyle = PolygonStyle.builder().setColor(Color.BLUE & 0x80FFFFFF).setLineStyle(lineStyle).build();//0xE0FFFF
circle = new Polygon(circleVerts, null, polygonStyle, circle_data);
layer.add(circle);
} else {
circle.setVertexList(circleVerts);
}
circle.setVisible(visible);
}
public void setVisible(boolean visible) {
this.visible = visible;
}
public void setLocation(Projection proj, Location location) {
circlePos = proj.fromWgs84(location.getLongitude(), location.getLatitude());
projectionScale = (float) proj.getBounds().getWidth();
circleRadius = location.getAccuracy();
// Here is the most important modification
update();
}
So, each time our Position changes is called onLocationChanged(Location location) Method and there will be called locationCircle.setLocation(location) and last there, it will be called update called.
The questions are, What am I making wrong? and How can I solve it?
Thank you in advance.
You create and add new circle with every update. You should reuse single one, just update vertexes with setVertexList(). In particular this line should be outside onLocationChanged cycle, somewhere in initGPS perhaps:
circle = new Polygon(circleVerts, null, polygonStyle, circle_data);
Hi im trying to get a sprite to fade in and scale up after fading out and scaling down. For this i used an Entitiy modifier listener but its not working? Heres my code:
public class GameScene {
Scene gameScene;
Engine engine;
Activity activity;
BitmapTextureAtlas mTextureAtlas;
ITextureRegion X;
ITextureRegion O;
ITextureRegion XO;
FadeInModifier fadeIn = new FadeInModifier(2);
FadeOutModifier fadeOut = new FadeOutModifier(2);
ScaleModifier scaleDown = new ScaleModifier(3, 1, 0);
ScaleModifier scaleUp = new ScaleModifier(2, 0, 1);
Sprite XOsprite;
Random rand = new Random();
boolean XYset = false;
public GameScene(Engine eng, Activity act) {
engine = eng;
activity = act;
}
public Scene getScene() {
gameScene = new Scene();
gameScene.setBackground(new Background(0, 256, 59));
int x = 0, y = 0;
if (rand.nextInt(2) == 0) {
XO = X;
} else {
XO = O;
}
if (!XYset) {
x = rand.nextInt(MainActivity.CAM_WIDTH);
y = rand.nextInt(MainActivity.CAM_HEIGHT);
XYset = true;
}
XOsprite = new Sprite(x, y, XO, engine.getVertexBufferObjectManager()) {
#Override
public boolean onAreaTouched(final TouchEvent te, final float xVal,
final float yVal) {
XOsprite.registerEntityModifier(fadeOut);
XOsprite.registerEntityModifier(scaleDown);
return true;
}
};
IEntityModifierListener fadeOutListener = new IEntityModifierListener() {
#Override
public void onModifierStarted(IModifier<IEntity> pModifier,
IEntity pItem) {
// TODO Auto-generated method stub
}
#Override
public void onModifierFinished(IModifier<IEntity> pModifier,
IEntity pItem) {
// TODO Auto-generated method stub
XOsprite.clearEntityModifiers();
XOsprite.setPosition(rand.nextInt(MainActivity.CAM_WIDTH), rand.nextInt(MainActivity.CAM_HEIGHT));
XOsprite.registerEntityModifier(fadeIn);
XOsprite.registerEntityModifier(scaleUp);
}
};
fadeOut.addModifierListener(fadeOutListener);
XOsprite.registerEntityModifier(scaleUp);
XOsprite.registerEntityModifier(fadeIn);
gameScene.attachChild(XOsprite);
gameScene.registerTouchArea(XOsprite);
return gameScene;
}
The sprite just fades out and nothing happens. I also want the sprite to change to a random position on the screen when it fades back in. Help?
If you want to do fade in and scale in parallel then you can use use parallelEntityModifier.
Similarly for fade out and scale out parallel then you can use use parallelEntityModifier.
To run these two in sequence use SequenceEntityModifier.
Try this it will work.
I want to implement on my project this sketch about dragging a box.
Instead of one box, I have several circles each drawn with different coordinates in the form
ellipse(lemma23.x, lemma23.y, diameterLemma23, diameterLemma23);
ellipse(law3.x, law3.y, diameterLaw3, diameterLaw3);
ellipse(law2.x, law2.y, diameterLaw2, diameterLaw2);
How do I test if the cursor is on one of the circles?
Here's a screen shot of my project:
I want to test when cursor is on (or near) a circle so that I can change its position by dragging.
The entire sketch is in pastebin.
I started with the example in your question. There are a few main differences for drawing multiple shapes:
You have to check whether the cursor is within each shape.
You have to draw each shape.
You may want to worry about overlapping, but I did not.
In the following code, I build upon the example directly although I removed the few lines which change the color of the box when clicked and I reorganized the code into the MovingEllipse class so that multiple ellipses can be drawn easily. (This code draws two ellipses.)
Note that the code in draw() checks the position of the mouse for each ellipse, however, I suppose this could be improved upon (i.e. perhaps by creating an array of ellipse positions and looping over the array). Also, for this code to work properly, mousePressed and mouseReleased methods need to be copied like the mouseDragged method. (I was trying to make my example brief.)
Anyway, this is one way to draw multiple ellipses and detect which one should be moved. Hope it helps!
int esize = 75;
MovingEllipse e1 = new MovingEllipse(0.0, 0.0, esize, 0.0, 0.0);
MovingEllipse e2 = new MovingEllipse(0.0, 0.0, esize, 0.0, 0.0);
void setup()
{
size(640, 360);
e1.eX = width/2.0; // Center of ellipse 1.
e1.eY = height/2.0;
e2.eX = width/4.0; // Center of ellipse 2.
e2.eY = height/4.0;
}
void draw()
{
background(0);
// Test if the cursor is over the ellipse.
if (mouseX > e1.eX-esize && mouseX < e1.eX+esize &&
mouseY > e1.eY-esize && mouseY < e1.eY+esize) {
e1.overBox = true;
e2.overBox = false;
} else if (mouseX > e2.eX-esize && mouseX < e2.eX+esize &&
mouseY > e2.eY-esize && mouseY < e2.eY+esize) {
e2.overBox = true;
e1.overBox = false;
} else {
e1.overBox = false;
e2.overBox = false;
}
// Draw the ellipse(s).
e1.update(e1.eX, e1.eY, e1.overBox);
e2.update(e2.eX, e2.eY, e2.overBox);
}
void mouseDragged() {
e1.mouseDragged();
e2.mouseDragged();
}
// Don't forget to repeat this for mousePressed and mouseReleased!
// ...
class MovingEllipse {
float eX, eY; // Position of ellipse.
int eSize; // Radius. For a circle use eSize for both x and y radii.
float xOffset, yOffset; // Where user clicked minus center of ellipse.
boolean locked, overBox; // Flags used for determining if the ellipse should move.
MovingEllipse (float ex, float ey, int esize, float xoff, float yoff) {
eX = ex;
eY = ey;
eSize = esize;
xOffset = xoff;
yOffset = yoff;
}
void update(float ex, float ey, boolean over) {
eX = ex;
eY = ey;
overBox = over;
// Draw the ellipse. By default, (eX, eY) represents the center of the ellipse.
ellipse(eX, eY, eSize, eSize);
}
void mousePressed() {
if(overBox) {
locked = true;
} else {
locked = false;
}
xOffset = mouseX-eX;
yOffset = mouseY-eY;
}
void mouseDragged() {
if(locked) {
eX = mouseX-xOffset;
eY = mouseY-yOffset;
}
}
void mouseReleased(){
locked = false;
}
}
Just check if the distance between the cursor and the centre of the circle is within the hit radius. The hit radius could be made larger than the radius of the circle to catch near hits.