I have created an android application similar to Not Tetris 2 using Libgdx with Box2d.
It can successfully remove a slice from the world, which obviously involves duplicating several bodies and destroying/creating fixtures. However, seemingly at random, a body with a 2x2 fixture will appear. The body and fixture are displayed using information related to the objects around it when it is created, so I narrowed its creation down to the following function:
Body duplicateBody(Body original){
BodyDef d = new BodyDef();
d.position.set(original.getPosition());
d.angle = original.getAngle();
d.linearVelocity.set(original.getLinearVelocity());
d.angularVelocity = original.getAngularVelocity();
Body dup = world.createBody(d);
dup.setType(BodyDef.BodyType.DynamicBody);
return dup;
}
I use this function in 2 different contexts:
Making a copy of the body if a "slice" cuts one in two -- I then transfer the fixtures which are below to it.
When a fixture is below the line then it is added to a body created for ones below
Making a copy of the body when groups of fixtures are separated
I commented out the code responsible for the third instance and still had the 2x2 boxes spawning, so here are the functions relevant to the others:
...
if (below && !above) {
//copy fixture, add copy to lower body and remove original
Body top = fixture.getBody();
FixtureDef n = new FixtureDef();
PolygonShape s = new PolygonShape();
s.set(getLocalVerticesOfFixture(fixture));
n.shape = s;
n.density = fixture.getDensity();
//create lower body if a lower one doesn't already exist
if (!topBottomPairs.containsKey(top)) {
Body dup = duplicateBody(top);
topBottomPairs.put(top, dup);
}
//delete fixture
remove.add(fixture);
Fixture f = topBottomPairs.get(top).createFixture(n);
s.dispose();
}
...
if (below && above) {
//copy fixture, add copy to lower body, but keep original on upper as it needs to split
FixtureDef n = new FixtureDef();
PolygonShape s = new PolygonShape();
s.set(getLocalVerticesOfFixture(fixture));
n.shape = s;
n.density = fixture.getDensity();
Body top = fixture.getBody();
//create lower body if a lower one doesn't already exist
if (!topBottomPairs.containsKey(top)) {
Body dup = duplicateBody(top);
topBottomPairs.put(top, dup);
}
Fixture second = topBottomPairs.get(top).createFixture(n);
s.dispose();
}
....
private Vector2[] getLocalVerticesOfFixture(Fixture fixture) {
PolygonShape shape = ((PolygonShape) fixture.getShape());
Vector2[] localVertices = new Vector2[shape.getVertexCount()];
for (int i = 0; i < shape.getVertexCount(); i++) {
localVertices[i] = new Vector2();
shape.getVertex(i, localVertices[i]);
}
return localVertices;
}
I also have this remove fixture function which runs on all fixtures I want to remove:
private void smartDeleteFixture(Fixture f){
f.getBody().destroyFixture(f);
if(f.getBody().getFixtureList().size == 0){
world.destroyBody(f.getBody());
}
}
Nowhere do I create vertices, let alone a fixture of a 2x2 shape. I was wondering if this duplication function has any flaws, or if I stumbled upon some "default shape" that box2d uses.
Edit: I have removed anything not related to the manipulation of box2d bodies. Hope that helps
Deleted this question as I decided to perform a major recode and hoped that would fix my problem. It did not, but I figured out the cause.
I looked through box2d and found a couple instances of code similar to this in the polygon shape class:
if (n < 3)
{
// Polygon is degenerate.
b2Assert(false);
SetAsBox(1.0f, 1.0f);
return;
}
These instances check the number of vertices after various operations and turn the shape into a 2x2 box if there are fewer than 3. One of these operations makes the shape convex. Another checks if vertices are close together (closer than 0.0025f), deleting one if so.
In my case, the problem was simple. Some of my vertices were less than 0.0025f from each other, resulting in them being deleted, the vert count dropping below 3, an assertion being ignored, and then my shape being turned into a 2x2 box. I hope this helps someone out.
Related
For line charts I find that if I have multiple y values for a single x, it works fine as long as it isn't the final x. If it's the final x, it only displays the first entry. Is there a known workaround for this?
Example:
//firstTimestamp is earlier than secondTimestamp
data.add(new Entry(firstTimestamp, 10));
data.add(new Entry(firstTimestamp, 20)); //won't show unless you uncomment below
data.add(new Entry(firstTimestamp, 30)); //won't show unless you uncomment below
//data.add(new Entry(secondTimestamp, 40));
Graph when second timestamp commented out:
Graph with second timestamp uncommented (note that the 20 and 30 are now included, whereas they weren't before):
Edit:
I believe I've found the cause of this problem and can fix it in the following way, by changing
public abstract class BarLineScatterCandleBubbleRenderer extends DataRenderer {
// ... lines removed ... //
public void set(BarLineScatterCandleBubbleDataProvider chart, IBarLineScatterCandleBubbleDataSet dataSet) {
float phaseX = Math.max(0.f, Math.min(1.f, mAnimator.getPhaseX()));
float low = chart.getLowestVisibleX();
float high = chart.getHighestVisibleX();
Entry entryFrom = dataSet.getEntryForXValue(low, Float.NaN, DataSet.Rounding.DOWN);
Entry entryTo = dataSet.getEntryForXValue(high, Float.NaN, DataSet.Rounding.UP);
min = entryFrom == null ? 0 : dataSet.getEntryIndex(entryFrom);
max = entryTo == null ? 0 : dataSet.getEntryIndex(entryTo);
range = (int) ((max - min) * phaseX);
}
// ... lines removed ... //
}
to this, which I believe will resolve the issue:
public abstract class BarLineScatterCandleBubbleRenderer extends DataRenderer {
// ... lines removed ... //
public void set(BarLineScatterCandleBubbleDataProvider chart, IBarLineScatterCandleBubbleDataSet dataSet) {
float phaseX = Math.max(0.f, Math.min(1.f, mAnimator.getPhaseX()));
float low = chart.getLowestVisibleX();
float high = chart.getHighestVisibleX();
Entry entryFrom = dataSet.getEntryForXValue(low, Float.NaN, DataSet.Rounding.DOWN);
//my edits here
int indexTo = dataset.getEntryIndex(high, Float.NaN, DataSet.Rounding.UP);
List<Entry> values = dataset.getValues();
while (indexTo + 1 < values.size() && values.get(indexTo + 1).getX() == high) {
indexTo++;
}
Entry entryTo = values.get(indexTo);
//my edits end here
min = entryFrom == null ? 0 : dataSet.getEntryIndex(entryFrom);
max = entryTo == null ? 0 : dataSet.getEntryIndex(entryTo);
range = (int) ((max - min) * phaseX);
}
// ... lines removed ... //
}
How can I subclass this / use these edits?
Please note that the only supported use case for LineChart entries is adding them ordered ascending. This is documented in the wiki:
Please be aware that this library does not officially support drawing LineChart data from an Entry list not sorted by the x-position of the entries in ascending manner.
The reason for this is that the renderer is optimised for unique ascending order entries.
If you want to get around this, I suggest you have a look at the source for LineChartRenderer. You will have to place breakpoints and find the issue that is causing it to render in the way you have demonstrated. Then you can consider subclassing the renderer to meet your requirement. Essentially you would be removing the optimisation in order to support the extra use case (non-unique values).
EDIT: If you are unwilling to manipulate the existing object graph to obtain the behaviour you want, you might want to consider forking the library with the change. Then you can build a .jar of your fork and include it in your Android project. Refer to the instructions in the answers below for the same:
How to make a .jar from an Android Studio project
How to add a .jar as a library in Android Studio
[also posted on MPAndroidChart's Github]
I need realtime graph with a rolling windows, that's when I ran into 'problems'. Adding data is no problem, but after adding data with an Xvalue(index) that's higher than the current width of the graph the graph doesn't autoscroll because it don't seem to be able to always display [X] Xvalues.
Example of issue:
The result in graph 3 is not what I want for displaying realtime data. A scrollingwindow is much more usefull. So I tried to archieve this..
My working 'solution' was to remove the first Xvalue, add a new one and move all Xindexes of all Entries on screen one to the left. The result is some code like this:
int GRAPH_WIDTH = 10;
LineData lineData = chart.getData();
LineDataSet lineDataSet = lineData.getDataSetByIndex(0);
int count = lineDataSet.getEntryCount();
// Make rolling window
if (lineData.getXValCount() <= count) {
// Remove/Add XVal
lineData.getXVals().add("" + count);
lineData.getXVals().remove(0);
// Move all entries 1 to the left..
for (int i=0; i < count; i++) {
Entry e = lineDataSet.getEntryForXIndex(i);
if (e==null) continue;
e.setXIndex(e.getXIndex() - 1);
}
// Set correct index to add value
count = GRAPH_WIDTH;
}
// Add new value
lineData.addEntry(new Entry([random value], count), 0);
// Make sure to draw
chart.notifyDataSetChanged();
chart.invalidate();
This works quite well actually (as seen in this video here ), but I feel like there must be an easier way to do this. Maybe I overlooked some API window/scrolling..
But if this is the 'right' way to archieve this result then it would be an enhancement to add support for this kind of graphs in your library.
Thank you for the video.
I am surprised you found a workaround that is rather complicated but works quite well.
Unfortunately this is currently the only way to achieve what you want. I will work on making this easier soon probably reusing some of your code.
Also take a look at these two methods:
setScaleMinima(...)
centerViewPort(...)
I took your code and changed it a bit. It will only show up to GRAPH_WIDTH number of points at a time. Then it scrolls along deleting the older data. Useful if you're only interested in relatively recent data. Is that what you were going for?
public void addTimeEntry() {
String entry_date_time = new SimpleDateFormat("MMM d - HH:mm:ss").format(new Date());
LineData lineData = mChart.getData();
int GRAPH_WIDTH = 15;
if (lineData != null) {
LineDataSet set = lineData.getDataSetByIndex(0);
if (set == null) {
set = createSet();
lineData.addDataSet(set);
}
// Make rolling window
if (lineData.getXValCount() > GRAPH_WIDTH) {
lineData.getXVals().remove(0);
set.removeEntry(0);
lineData.getXVals().add(entry_date_time);
lineData.addEntry(new Entry((float) (Math.random() * 40) + 30f, GRAPH_WIDTH), 0);
// lineData.getXVals().add(entry_date_time);
// Move all entries 1 to the left..
for (int i=0; i < set.getEntryCount(); i++) {
Entry e = set.getEntryForXIndex(i);
if (e==null) continue;
e.setXIndex(e.getXIndex() - 1);
}
}
else{
lineData.getXVals().add(entry_date_time);
lineData.addEntry(new Entry((float) (Math.random() * 40) + 30f, lineData.getXValCount()-1), 0);
}
// let the chart know it's data has changed
mChart.notifyDataSetChanged();
mChart.invalidate();
}
}
Am using AndroidPlot on my project and it's just great so far. This is what i got.
Now am trying to remove one of the series indicators from the legend. Actually i want to keep only the first one (the blue one) cause the others are self explanatory.
Am not asking how to remove the legend it self (see https://stackoverflow.com/a/13413758/665823 for that issue).
If someone can help me i'll be great. Thanks in advance.
I finally found a tweek that allows me to do what i need. To achieve this the series that i need to be shown must be added to the plot first over the ones i need to hide :
// I add the blue serie first
LineAndPointFormatter mFormat = new LineAndPointFormatter();
mFormat.configure(context, R.xml.plot_blue);
graphView.addSeries(serieMesures, mFormat);
// I add the other colors after
for (XYSeries serie : seriesSeuils) {
LineAndPointFormatter sFormat = new LineAndPointFormatter();
if (serie.getTitle().equals("RED") {
sFormat.configure(context, R.xml.plot_red);
}
else if (serie.getTitle().equals("ORANGE")) {
sFormat.configure(context, R.xml.plot_orange);
}
else if (serie.getTitle().equals("YELLOW")) {
sFormat.configure(context, R.xml.plot_yellow);
}
graphView.addSeries(serie, sFormat);
}
Then i just created a legend where there is only enough space to show the series i need (in my case just the first one).
// This is what does the trick! A Table with 1 line and 1 column
// so the other series can't be rendered in the LegendWidget
graphView.getLegendWidget().setTableModel(new DynamicTableModel(1, 1));
// Other customizations (size and position)
graphView.getLegendWidget().setSize(new SizeMetrics(55, SizeLayoutType.ABSOLUTE, legendWith, SizeLayoutType.ABSOLUTE));
graphView.getLegendWidget().setPositionMetrics(
new PositionMetrics(20,
XLayoutStyle.ABSOLUTE_FROM_RIGHT,
20,
YLayoutStyle.ABSOLUTE_FROM_TOP,
AnchorPosition.RIGHT_TOP));
graphView.getLegendWidget().setBackgroundPaint(bgPaint);
graphView.getLegendWidget().setTextPaint(txPaint);
graphView.getLegendWidget().setBorderPaint(brPaint);
graphView.getLegendWidget().setPadding(10, 1, 10, 1);
And voila!
I wanted to create something like jetboy asteroids that I found on android samples but i'ts too complicated to get the right code and to make it work properly.
I don't want on touch simply the asteroids should begin themselves.
Can someone link me some good stuff or give me some examples?
private void doAsteroidCreation() {
// Log.d(TAG, "asteroid created");
Asteroid _as = new Asteroid();
int drawIndex = mRandom.nextInt(4);
// TODO Remove hard coded value
_as.mDrawY = mAsteroidMinY + (drawIndex * 63);
_as.mDrawX = (mCanvasWidth - mAsteroids[0].getWidth());
_as.mStartTime = System.currentTimeMillis();
mDangerWillRobinson.add(_as);
}
New to Starling-Feathers, before I start to develop my mobile app, I would like to know what are the best practice to develop the following features using Feathers:
Partial view slide - A part of the next view is shown and the user can drag to see it all. Could this be done with Feathers ScreenNavigator?
Sliding menu from the top
Dragging text elements with title pushing the last items
Since it is hard to describe I've added an animated gif to describe my goals. Thanks for all your advices
I would like to maximize the use of Feathers built in widgets and will appreciate code examples :)
I think these are not that much hard to do in core flash or you can also do it in Starling feathers too. YOu can use list item to do the third point (Dragging text elements with title pushing the last items) .
First and second you can use it with tweening effect i think.
For the third one using feathers list.
(re formated post)
private function addFeatherList():void{
Flist = new List();
Flist.width = 250;
Flist.height = 300;
Flist.x = GAME_W/2 - Flist.width/2;
Flist.y = sampText.height + 5;
this.addChild( Flist );
fontArr = Font.enumerateFonts(true);
for (var i:int=0; i<fontArr.length; i++){
ListArr[i] = { text:Font(fontArr[i]).fontName }
}
var groceryList:ListCollection = new ListCollection( ListArr );
Flist.dataProvider = groceryList;
Flist.itemRendererProperties.labelField = "text";
FeathersControl.defaultTextRendererFactory=function():ITextRenderer{
var render:TextFieldTextRenderer=new TextFieldTextRenderer();
render.textFormat = new TextFormat("Verdana",8,0xFFFFFF,false);
return render;
}
Flist.itemRendererFactory = function():IListItemRenderer //list.itemRendererProperties.accessorySourceField list.itemRendererFactory
{
var renderer:DefaultListItemRenderer = new DefaultListItemRenderer();
renderer.addEventListener(Event.TRIGGERED, onListTriggered);
return renderer;
}
}