So I started working with ARCore in Android Studio in Java, and I tested their demo HelloAR, which works.
Now I want to add simple thing such as move the object to scroll direction.
In TapHelper I need to add onScroll for GestureDetector
#Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
}
But that is where I am stuck now, the virtual object is rendered based on anchor? So do I need to update the anchor position or the position of the virtual object? And how do I do that, the anchor does not have any way of updating its position, do I destroy it and create new one, or did I miss anything?
If you just want to rotate the renderable itself you don't need to create a new anchor, but if you want to move the renderable to a new place in the 'world' then the standard approach, at this time, seems to be to delete the anchor and recreate it.
Here is an example of how you might do this:
private AnchorNode moveRenderable(AnchorNode myAnchorNodeToMove, Pose newPoseToMoveTo) {
//Move a renderable to a new pose
if (myAnchorNodeToMove != null) {
arFragment.getArSceneView().getScene().removeChild(myAnchorNodeToMove);
} else {
Log.d(TAG,"moveRenderable - myAnchorNode was null");
return null;
}
Frame frame = arFragment.getArSceneView().getArFrame();
Session session = arFragment.getArSceneView().getSession();
Anchor myAnchor = session.createAnchor(newPoseToMoveTo.extractTranslation());
AnchorNode newMyAnchorNode = new AnchorNode(myAnchor);
newMyAnchorNode.setRenderable(andyRenderable);
newMyAnchorNode.setParent(arFragment.getArSceneView().getScene());
return newMyAnchorNode;
}
The above is modified from a working example to make it more readable here - full source is here: https://github.com/mickod/LineView
Related
I'm currently developing an application on Android with AndroidPDFViewer : https://github.com/barteksc/AndroidPdfViewer
I want to create a functionality, when the user touch the screen, it put a point on the PDF at this location. After I want to measure the distance between 2 points but it's an other problem.
I don't understand how to do this functionality, put a point on PDF. I found this : https://github.com/barteksc/AndroidPdfViewer/issues/554
So it's possible but how ? I don't get it.
I suppose I need to create a bitmap, but I can't draw on the PDF, or put a marker.
Thanks for your time.
You have a sample file in his repo.
If you go to this location he has already created the method on how to load a pdf! Then if you go to this link you will see that he has created the class and has included good comments
Render page fragment on {#link Surface}
Page must be opened before rendering.
public void renderPage(PdfDocument doc, Surface surface, int pageIndex,
int startX, int startY, int drawSizeX, int drawSizeY) {
renderPage(doc, surface, pageIndex, startX, startY, drawSizeX, drawSizeY, false);
}
The one that you are searching is bookmark method
/** Get table of contents (bookmarks) for given document */
public List<PdfDocument.Bookmark> getTableOfContents(PdfDocument doc) {
synchronized (lock) {
List<PdfDocument.Bookmark> topLevel = new ArrayList<>();
Long first = nativeGetFirstChildBookmark(doc.mNativeDocPtr, null);
if (first != null) {
recursiveGetBookmark(topLevel, doc, first);
}
return topLevel;
}
}
However keep in mind that it might be necessary to use Async Tasks to download a pdf!
I'm writing an application using AndroidPlot in which the user needs to be able to touch a point on a scatter plot and bring up information about that specific point. In other words, the application needs to identify the closest point to the location touched or otherwise recognize that a point has been touched, and be able to return the specific identity of the point. All of the points in this scatter plot will always be of one series, so identifying between series isn't an issue, but I don't know how to implement finding or identifying the touched point.
I can get as far as:
plot.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View view, MotionEvent motionEvent) {
PointF click = new PointF(motionEvent.getX(), motionEvent.getY());
if(plot.getGraphWidget().containsPoint(click)) {
AlertDialog.Builder builder = new AlertDialog.Builder(GraphView.this);
builder.setTitle("Point: ");
builder.setMessage("Description: ");
AlertDialog dialog = builder.create();
dialog.show();
}
return false;
}
});
}
Which creates the AlertDialog whenever the graph is touched.
The DemoApp's BarPlotExampleActivity has this functionality implemented in it's onPlotClicked(...) method. It could certainly be improved but should give you a good starting point.
The basic steps are:
Filter for clicks within the plot's graph area. (You've got this piece already)
Convert the screen coords to domain/range values using XYPlot.getXVal(screenX) & XYPlot.getYVal(screenY).
Find the closest point(s) in your model for the above domain/range values.
I have a Activity. On this Activity I have a Relative Layout. On this layout I have placed several custom objects from a class that extends RelativeLayout.
It kind of looks like a chessboard (it isn't, but so you know what I'm talking about).
I now want to be able to touch one of this objects and drag it to one of the 4 adjacent fields, swapping it against the one there.
I thought the most simple way would be to use androids drag & drop.
I used setOnTouchListener and setOnDragListener for every object, so every object can be touched and dragged onto another object.
I used this tutorial, should be easier for you to read than just the code, but here it is:
#Override
public boolean onTouch(View v, MotionEvent e) {
if (e.getAction() == MotionEvent.ACTION_DOWN) {
DragShadowBuilder shadowBuilder = new View.DragShadowBuilder(v);
v.startDrag(null, shadowBuilder, v, 0);
return true;
} else {
return false;
}
}
#Override
public boolean onDrag(View v, DragEvent e) {
if (e.getAction()==DragEvent.ACTION_DROP) {
View view = (View) e.getLocalState();
ViewGroup from = (ViewGroup) view.getParent();
from.removeView(view);
MyCustomViewClass to = (MyCustomViewClass) v;
to.addView(view);
view.setVisibility(View.VISIBLE);
}
return true;
}
Now I am wondering how I could limit where a object could be dropped. I want it to be able to be moved just to the 4 adjacent fields (not only by limiting the draglistener, I also don't want the object to be moved beyond this objects, no matter how far the finger tries to drag it).
I hope you get what I mean, if not please ask.
So this question is all about what I can do with this drag & drop I guess. Is it possible to somehow detect where the finger is before dropping? Is it possible to limit the dragging to the straight x and y axis? Or is there a way to know the direction of that dragging movement, allowing me to 1) know the object I would swap with and 2) moving the other object before the drop, making it look like the objects are just swapping?
Edit:
I got the direction, since I can calculate it from view.getX, view.getY (coords are inside my startobject) and v.getX and v.getY (coords from the object I'm over) in onDrag when the dragEvent is ACTION_ENTERED.
Now I try to figure out either how to set the dragshadows position to the object I want it to be over, or to only allow dragging in my direction and ending the drag over the next object.
Further help or ideas still appreciated.
So, my issue is this: I'm attempting to define a custom set of nodes for a Javafx XYChart LineChart, where each node corresponds to a point that was plotted directly from the datasets. After looking around a little bit, Jewlesea actually had a solution at one point about how to add dynamic labels to nodes on a linechart graph that gave me enough of a push in the right direction to create black symbols (they are dots at the moment, but they can be many different things). Now I have a requirement that requires me to change ONE of the nodes on the XY chart into an 'X'. this could be either through loading an image in place of the 'node', or through physically manipulating the 'shape' parameter in .css.
The problem begins when I try to add this property dynamically, since which node has the 'x' will always be changing. Here are the things I've tried, and they all end up with no results whatsoever, regardless of the property used.
private XYChart.Data datum( Double x, Double y )
{
final XYChart.Data data = new XYChart.Data(x, y);
data.setNode(
new HoveredThresholdNode(x, y));
//data.getNode().setStyle("-fx-background-image: url(\"redX.png\");");
data.getNode().styleProperty().bind(
new SimpleStringProperty("-fx-background-color: #0181e2;")
.concat("-fx-font-size: 20px;")
.concat("-fx-background-radius: 0;")
.concat("-fx-background-insets: 0;")
.concat("-fx-shape: \"M2,0 L5,4 L8,0 L10,0 L10,2 L6,5 L10,8 L10,10 L8,10 L5,6 L2,10 L0,10 L0,8 L4,5 L0,2 L0,0 Z\";")
);
data.getNode().toFront();
return data;
}
So in the above, you can see that this is adding a property through the use of the 'bind' function after the dataNode has already been created. Also note above, I tried doing it through the 'setStyle' interface at this level to give it a background image, with no success. Also, no errors are being thrown, no 'invalid css' or anything of the sort, just simply no display on the graph at all when done this way.
now, in the HoveredThresholdNode (Again a big thanks to Jewelsea for being a master of Javafx and putting this bit of code online, it's where 90% of this class came from.) I tried essentially the same thing, at a different level. (actually being IN the node creation class, as opposed to a layer above it).
class HoveredThresholdNode extends StackPane {
/**
*
* #param x the x value of our node (this gets passed around a bunch)
* #param y the y value of our node (also gets passed around a bunch)
*/
HoveredThresholdNode(Double x, Double y) {
//The preferred size of each node of the graph
//getStylesheets().add(getClass().getResource("style/XYChart.css").toExternalForm());
//getStyleClass().add("xyChart-Node");
//setOpacity(.8);
styleProperty().bind(
new SimpleStringProperty("-fx-background-color: #0181e2;")
.concat("-fx-font-size: 20px;")
.concat("-fx-background-radius: 0;")
.concat("-fx-background-insets: 0;")
.concat("-fx-shape: \"M2,0 L5,4 L8,0 L10,0 L10,2 L6,5 L10,8 L10,10 L8,10 L5,6 L2,10 L0,10 L0,8 L4,5 L0,2 L0,0 Z\";")
);
//this label is the 'tooltip' label for the graph.
final Label label = createDataThresholdLabel(x, y);
final double Myx = x;
final double Myy = y;
setOnMouseEntered(new EventHandler<MouseEvent>() {
#Override public void handle(MouseEvent mouseEvent) {
if (Myx == 0) {
label.setTextFill(Color.DARKGRAY);
} else if (Myx > 0) {
label.setTextFill(Color.SPRINGGREEN);
} else {
label.setTextFill(Color.FIREBRICK);
}
label.setText("Current position: " + Myx + " , " + Myy);
//setCursor(Cursor.NONE);
toFront();
}
});
setOnMouseExited(new EventHandler<MouseEvent>() {
#Override public void handle(MouseEvent mouseEvent) {
//getChildren().clear();
//setCursor(Cursor.CROSSHAIR);
}
});
}
Now note, I also tried the setStyle(java.lang.String) method, with all of the same type of CSS, with no success. I have NO idea why this isn't styling dynamically. It's almost as if the custom nodes are simply ignoring all new .css that I define at runtime?
Any help would be greatly appreciated, please don't be shy if you need more details or explanation on any points.
So, I did finally find a good workaround to solve my problem, although not in the way I thought it would happen. The main problem I was having, was that I was extending from stackPane to create my node, which only had a very small number of graphical display options available to it, and by switching the 'prefSize()' property, I was simply changing the size of that stackPane, and then filling in the background area of that stack pane black, giving it a very deceptive shape-look to it.
So rather than use a stack pane, whenever I reached the node that I needed to place the red 'X' on, I simply called a different Datum method that returned a datum with an ImageView Attached, like so:
private XYChart.Data CoLDatum(Double x, Double y){
final XYChart.Data data = new XYChart.Data(x, y);
ImageView myImage = new ImageView(new Image(getClass().getResource("style/redX.png").toExternalForm()));
data.setNode(myImage);
data.getNode().setOnMouseEntered(new EventHandler<MouseEvent>() {
#Override public void handle(MouseEvent mouseEvent) {
main_label.setText("Some Text.");
}
});
data.getNode().setOnMouseExited(new EventHandler<MouseEvent>(){
#Override public void handle(MouseEvent mouseEvent) {
main_label.setText("");
}
});
return data;
}
and since ImageView is an implementing class of Node, this worked out just fine, and allowed me to load up an image for that one single node in the graph, while still maintaining a listener to give custom text to our information label when the red 'x' was hovered over with a mouse. Sometimes, it's the simple solutions that slip right past you.
I imagine that, had I employed stackPane properties properly with the setStyle(java.lang.String) method, they would have absolutely shown up, and I was just butchering the nature of a stack pane. Interesting.
Hopefully this helps somebody else stuck with similar problems!
I am using this method in AndEngine to determine the scene being touched by the user.
#Override
public boolean onSceneTouchEvent(Scene pScene, TouchEvent pSceneTouchEvent) {
if(pSceneTouchEvent.isActionDown()) {
Log.e("Arcade", "Scene Tapped");
//Simulate player jumping
}
return false;
}
What i want to do is when the scene is tapped, i want to allow the player to jump.
Now two things for this would it be better to use PathModifier, or MoveYModifier considering it is landscape mode?
If either please provide an example of such.
Thanks
EDIT:
ive managed to use Physics to simulate a jump using this..
#Override
public boolean onSceneTouchEvent(Scene pScene, TouchEvent pSceneTouchEvent) {
if(pSceneTouchEvent.isActionDown()) {
Log.e("Arcade", "Scene Tapped");
final Vector2 velocity = Vector2Pool.obtain(mPhysicsWorld.getGravity().x * -0.5f,mPhysicsWorld.getGravity().y * -0.5f);
body.setLinearVelocity(velocity);
Vector2Pool.recycle(velocity);
return true;
}
return false;
}
As you said in the answer by changing the gravity. The only issue is, when the user keeps touching the screen the sprites keep going up and up and up. How can i set it where the user can only click once and cant make him jump again until the sprite hits the ground, which is a rectangle?
Use the MoveYModifier. remember, you can register as many modifiers as you want. So if, for example, the game a platform game and the character always moves on the X axis, and he can jumpt if he wants (Like Gravity Guy or Yoo Ninja, although these games change the gravity which is something else).
You could do like:
Entity playerEntity = ..//It doesn't matter if the player is a sprite, animated sprite, or anything else. So I'll just use Entity here, but you can declare your player as you wish.
final float jumpDuration = 2;
final float startX = playerEntity.getX();
final float jumpHeight = 100;
final MoveYModifier moveUpModifier = new MoveYModifier(jumpDuration / 2, startX, startX + jumpHeight);
final MoveYModifier moveDownModifier = new MoveYModifier(jumpDuration / 2, startX + jumpHeight, startX);
final SequenceEntityModifier modifier = new SequenceEntityModifier(moveUpModifier, moveDownModifier);
playerEntity.registerEntityModifier(modifier);
EDIT:
For your second question:
Create a variable boolean mIsJumping in your scene; When the jump starts - set it to true. If the user taps the screen and mIsJumping == true, don't jump.
Now, register a ContactListener to your PhysicsWorld. Whenever there is contact between the player and the ground, set mIsJumping to false.
There are many samples of using ContactListeners in AndEngine forums, a quick search yields some. If you need an example, you can ask for one :)
EDIT 2: ContactListener sample:
Have 2 variables to hold IDs for the player and the ground: private static final String PLAYER_ID = "player", GROUND_ID = "ground";
When you create the ground body and the player body, set their IDs as the user data: playerBody.setUserData(PLAYER_ID); and groundBody.setUserData(GROUND_ID);
Create a ContactListener as a field in your scene:
private ContactListener mContactListener = new ContactListener() {
/**
* Called when two fixtures begin to touch.
*/
public void beginContact (Contact contact) {
final Body bodyA = contact.getFixtureA().getBody();
final Body bodyB = contact.getFixtureB().getBody();
if(bodyA.getUserData().equals(PLAYER_ID)) {
if(bodyB.getUserData().equals(GROUND_ID))
mIsJumping = false;
}
else if(bodyA.getUserData().equals(GROUND_ID)) {
if(bodyB.getUserData().equals(PLAYER_ID))
mIsJumping = false;
}
}
/**
* Called when two fixtures cease to touch.
*/
public void endContact (Contact contact) { }
/**
* This is called after a contact is updated.
*/
public void preSolve(Contact pContact) { }
/**
* This lets you inspect a contact after the solver is finished.
*/
public void postSolve(Contact pContact) { }
};
Lastly, register that contact listener: physicsWorld.setContactListener(mContactListener);
EDIT 3:
To move your sprite over the X axis, you can apply a force using Body.applyForce method, or apply an impulse using Body.applyLinearImpulse method. Play around with the arguments and find what works the next.
The vector should consist a X part only; Try Vector2 force = Vector2Pool.obtain(50, 0);. Then apply the force this way: body.applyForce(force, body.getWorldCenter());.