AndroidPlot multitouch zoom & scroll

I’m playing around AndroidPlot library. I’ve needed to add zomm and scroll functionality. There is one example at AndroidPlot wiki, but a bit outdated, and I don’t like the idea of messing around view events in the activiti. So I’ve created my own sample:

main.xml layout:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <pl.flex_it.androidplot.MultitouchPlot
    	android:id="@+id/multitouchPlot"
    	android:layout_width="fill_parent"
    	android:layout_height="fill_parent"
    	android:layout_marginTop="10px"
    	android:layout_marginLeft="10px"
    	android:layout_marginRight="10px"
    	title="A Simple multitouch XYPlot Example"/>

</LinearLayout>

MultitouchAndroidplotActivity.java file:

package pl.flex_it.androidplot;

import java.util.Arrays;

import com.androidplot.series.XYSeries;
import com.androidplot.xy.BoundaryMode;
import com.androidplot.xy.LineAndPointFormatter;
import com.androidplot.xy.SimpleXYSeries;

import android.app.Activity;
import android.graphics.Color;
import android.os.Bundle;

/**
*
* This example is based on:
* - multitouch example, by David Buezas (david.buezas at gmail.com) and Michael
* from http://androidplot.com/wiki/A_Simple_XYPlot_with_multi-touch_zooming_and_scrolling
* - AndroidPlot quickstart example http://androidplot.com/wiki/Quickstart
* No license was given with this samples, but I assume that use it for free on BSD-like license ;-)
*
* @author Marcin Lepicki (marcin.lepicki at flex-it.pl)
*
*/
public class MultitouchAndroidplotActivity extends Activity
{

@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);

MultitouchPlot multitouchPlot = (MultitouchPlot) findViewById(R.id.multitouchPlot);

// Create two arrays of y-values to plot:
Number[] series1Numbers = {1, 8, 5, 2, 7, 4};
Number[] series2Numbers = {4, 6, 3, 8, 2, 10};

// Turn the above arrays into XYSeries:
XYSeries series1 = new SimpleXYSeries(
Arrays.asList(series1Numbers), // SimpleXYSeries takes a List so turn our array into a List
SimpleXYSeries.ArrayFormat.Y_VALS_ONLY, // Y_VALS_ONLY means use the element index as the x value
"Obwód brzucha"); // Set the display title of the series

// Same as above, for series2
XYSeries series2 = new SimpleXYSeries(Arrays.asList(series2Numbers), SimpleXYSeries.ArrayFormat.Y_VALS_ONLY,
"Series2");

// Create a formatter to use for drawing a series using LineAndPointRenderer:
LineAndPointFormatter series1Format = new LineAndPointFormatter(
Color.rgb(0, 200, 0), // line color
Color.rgb(0, 100, 0), // point color
Color.rgb(150, 190, 150)); // fill color (optional)

// Add series1 to the xyplot:
multitouchPlot.addSeries(series1, series1Format);

// Same as above, with series2:
multitouchPlot.addSeries(series2, new LineAndPointFormatter(Color.rgb(0, 0, 200), Color.rgb(0, 0, 100),
Color.rgb(150, 150, 190)));

// Reduce the number of range labels
multitouchPlot.setTicksPerRangeLabel(3);

// By default, AndroidPlot displays developer guides to aid in laying out your plot.
// To get rid of them call disableAllMarkup():
multitouchPlot.disableAllMarkup();

multitouchPlot.setRangeBoundaries(0, 10, BoundaryMode.FIXED);
multitouchPlot.setDomainBoundaries(0, 2.2, BoundaryMode.FIXED);

}
}

MultitouchPlot.java file:

package pl.flex_it.androidplot;

import android.content.Context;
import android.graphics.PointF;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import com.androidplot.series.XYSeries;
import com.androidplot.xy.BoundaryMode;
import com.androidplot.xy.XYPlot;
import com.androidplot.xy.XYSeriesFormatter;

/**
*
* This example is based on:
* - multitouch example, by David Buezas (david.buezas at gmail.com) and Michael
* from http://androidplot.com/wiki/A_Simple_XYPlot_with_multi-touch_zooming_and_scrolling
* - AndroidPlot quickstart example http://androidplot.com/wiki/Quickstart
* No license was given with this samples, but I assume that use it for free on BSD-like license ;-)
*
* @author Marcin Lepicki (marcin.lepicki at flex-it.pl)
*
*/
public class MultitouchPlot extends XYPlot implements OnTouchListener
{

// Definition of the touch states
static final private int NONE = 0;
static final private int ONE_FINGER_DRAG = 1;
static final private int TWO_FINGERS_DRAG = 2;
private int mode = NONE;

private Number minXSeriesValue;
private Number maxXSeriesValue;
private Number minYSeriesValue;
private Number maxYSeriesValue;

private PointF firstFinger;
private float lastScrolling;
private float distBetweenFingers;

private Number newMinX;
private Number newMaxX;

public MultitouchPlot(Context context, String title)
{
super(context, title);
initTouchHandling();
}

public MultitouchPlot(Context context, AttributeSet attributes)
{
super(context, attributes);
initTouchHandling();
}

public MultitouchPlot(Context context, AttributeSet attrs, int defStyle)
{
super(context, attrs, defStyle);
initTouchHandling();
}

private void initTouchHandling()
{
this.setOnTouchListener(this);
}

public boolean addSeries(XYSeries series, XYSeriesFormatter formatter)
{
//Overriden to compute min and max series values
for(int i = 0; i &lt; series.size(); i++) { if(minXSeriesValue == null || minXSeriesValue.doubleValue() &gt; series.getX(i).doubleValue())
minXSeriesValue = series.getX(i);
if(maxXSeriesValue == null || maxXSeriesValue.doubleValue() &lt; series.getX(i).doubleValue()) maxXSeriesValue = series.getX(i); if(minYSeriesValue == null || minYSeriesValue.doubleValue() &gt; series.getY(i).doubleValue())
minYSeriesValue = series.getY(i);
if(maxYSeriesValue == null || maxYSeriesValue.doubleValue() &lt; series.getX(i).doubleValue()) maxYSeriesValue = series.getY(i); } return super.addSeries(series, formatter); } public boolean onTouch(View view, MotionEvent motionEvent) { switch(motionEvent.getAction() &amp; MotionEvent.ACTION_MASK) { case MotionEvent.ACTION_DOWN: //start gesture firstFinger = new PointF(motionEvent.getX(), motionEvent.getY()); mode = ONE_FINGER_DRAG; break; case MotionEvent.ACTION_POINTER_DOWN: //second finger { distBetweenFingers = distance(motionEvent); // the distance check is done to avoid false alarms if (distBetweenFingers &gt; 5f || distBetweenFingers &lt; -5f) mode = TWO_FINGERS_DRAG; break; } case MotionEvent.ACTION_POINTER_UP: //end zoom //should I count pointers and change mode after only one is left? mode = ONE_FINGER_DRAG; break; case MotionEvent.ACTION_MOVE: if(mode == ONE_FINGER_DRAG) { calculateMinMaxVals(); final PointF oldFirstFinger = firstFinger; firstFinger = new PointF(motionEvent.getX(), motionEvent.getY()); lastScrolling = oldFirstFinger.x - firstFinger.x; scroll(lastScrolling); fixBoundariesForScroll(); setDomainBoundaries(newMinX, newMaxX, BoundaryMode.FIXED); redraw(); } else if(mode == TWO_FINGERS_DRAG) { calculateMinMaxVals(); final float oldDist = distBetweenFingers; final float newDist = distance(motionEvent); if(oldDist &gt; 0 &amp;&amp; newDist &lt; 0 || oldDist &lt; 0 &amp;&amp; newDist &gt; 0) //sign change! Fingers have crossed ;-)
break;

distBetweenFingers = newDist;

zoom(oldDist / distBetweenFingers);

fixBoundariesForZoom();
setDomainBoundaries(newMinX, newMaxX, BoundaryMode.FIXED);
redraw();
}
break;
}

return true;
}

private void scroll(float pan)
{
float calculatedMinX = getCalculatedMinX().floatValue();
float calculatedMaxX = getCalculatedMaxX().floatValue();
final float domainSpan = calculatedMaxX - calculatedMinX;
final float step = domainSpan / getWidth();
final float offset = pan * step;

newMinX = calculatedMinX + offset;
newMaxX = calculatedMaxX + offset;
}

private void fixBoundariesForScroll()
{
float diff = newMaxX.floatValue() - newMinX.floatValue();
if(newMinX.floatValue() &lt; minXSeriesValue.floatValue()) { newMinX = minXSeriesValue; newMaxX = newMinX.floatValue() + diff; } if(newMaxX.floatValue() &gt; maxXSeriesValue.floatValue())
{
newMaxX = maxXSeriesValue;
newMinX = newMaxX.floatValue() - diff;
}
}

private float distance(MotionEvent event)
{
final float x = event.getX(0) - event.getX(1);
return x;
}

private void zoom(float scale)
{
if(Float.isInfinite(scale) || Float.isNaN(scale) || (scale &gt; -0.001 &amp;&amp; scale &lt; 0.001)) //sanity check
return;

float calculatedMinX = getCalculatedMinX().floatValue();
float calculatedMaxX = getCalculatedMaxX().floatValue();
final float domainSpan = calculatedMaxX - calculatedMinX;
final float domainMidPoint = calculatedMaxX - domainSpan / 2.0f;
final float offset = domainSpan * scale / 2.0f;
newMinX = domainMidPoint - offset;
newMaxX = domainMidPoint + offset;
}

private void fixBoundariesForZoom()
{
if(newMinX.floatValue() &lt; minXSeriesValue.floatValue()) { newMinX = minXSeriesValue; } if(newMaxX.floatValue() &gt; maxXSeriesValue.floatValue())
{
newMaxX = maxXSeriesValue;
}
}
}

If you want, you can download complete eclipse project here

 

List w sprawie ACTA

Zebrałem się dziś w sobie i napisałem list do posła Roberta Tyszkiewicza, na którego głosowałem w wyborach parlamentarnych, w sprawie ACTA. Jakby ktoś chciał wykorzystać jego treść – zachęcam, tekst przekazuje do domeny publicznej

Szanowny Panie Pośle,

Jako Pański wyborca, który dwukrotnie oddał na Pana głos w wyborach parlamentarnych, chciałbym poznać Pana opinię w sprawie Umowy handlowej dotyczącej zwalczania obrotu towarami podrobionymi, znanej szerzej jako porozumienie ACTA. Jest to zbiór przepisów, które – zgodnie z analizami organizacji pozarządowych – pod hasłami walki z naruszeniami praw autorskich wprowadzają szereg niebezpiecznych regulacji, mogących ograniczyć wolności obywatelskie. Co więcej, proces uzgadniania treści przepisów ACTA w wielu państwach, także w Polsce, był prowadzony w sposób częściowo niejawny, co stoi w sprzeczności z deklarowanymi przez państwa demokratyczne ideami społeczeństwa otwartego.

Wspomniane wyżej zagrożenia ograniczenia wolności obywatelskich wynikają z wielu przepisów wspomnianej Umowy. Dla przykładu, artykuł 27 punkt 4 ACTA nakłada obowiązek na dostawców usług internetowych ujawniania danych abonentów w momencie przedstawienia przez posiadaczy praw autorskich dowodów na ich naruszenie. Ten przepis pomija obowiązek przeprowadzenia procedury sądowej w celu udowodnienia winy osoby naruszającej prawa autorskie, przyjmując za wystarczające oświadczenie posiadaczy praw autorskich. Co więcej, podobne obowiązki na tradycyjne przesyłki zawierające towary nakłada artykuł 22, gdzie jest mowa o przekazaniu danych adresata i nadawcy stronie, której prawa autorskie możne naruszać zawartość przesyłki.

Wiele przepisów wspomnianej umowy może prowadzić do absurdalnych wręcz sytuacji. I tak, artykuł 23 punkt 3 mówi o odpowiedzialności karnej osób, które rozpowszechniają nagrania zawierające “kopie” dzieł kinematograficznych. Łatwo sobie wyobrazić sytuacje, w której takim nagraniem może być fragment bajki dla dzieci oglądanej na przyjęciu urodzinowym.

Na początku listu wspomniałem o dziwnych procedurach przyjętych przy negocjowaniu tego porozumienia handlowego. Przede wszystkim, podczas prac nad umową jej treść pozostawała tajna. Przyznaje to Ministerstwo Kultury i Dziedzictwa Narodowego w odpowiedzi na interpelację posłów Grzegorza Pisalskiego i Bożeny Kotkowskiej z dnia 17 marca br., nr SPS-023-15121/10. Oznacza to, że organizacje pozarządowe, chcące uczestniczyć w otwartej dyskusji na temat umowy nie mogły prowadzić szerokich konsultacji społecznych na temat działania tych przepisów. Rozumiejąc potrzebę zachowania informacji niejawnych i tajnych muszę stanowczo zaprotestować przeciwko utajnianiu procesów powstawania prawa – stoi to bowiem w sprzeczności z zasadami demokracji, w szczególności zaś z zasadą suwerenności ludu. Stanowi to oczywiste naruszenie prawa do informacji publicznej. Nie jest to jedyne działanie tego typu – już po “odtajnieniu” tekstu porozumienia informacje o jego dalszych losach były publikowane w przedziwnych miejscach, jak np. na 43 komunikatu prasowego na temat rolnictwa i rybołówstwa. Niestety, wygląda to na próbę ukrywania przepisów prawnych przed osobami, których będą one dotyczyć.

Umowa ACTA zostanie podpisana już 26 stycznia przez Pana Premiera Donalda Tuska oraz innych przedstawicieli rządów państw Unii Europejskiej, po czym nastąpi proces ratyfikacyjny w Parlamencie Europejskim oraz w parlamentach państw członkowskich, w tym w polskim Sejmie. W związku z tym chciałbym poznać Pana opinię o proponowanych regulacjach oraz zwrócić uwagę na niebezpieczeństwa z nimi związane. Nie ukrywam, że liczę na zaangażowanie Pana lub innych osób z Pana klubu poselskiego i wyrażenie sprzeciwu wobec zarówno treści umowy, jak i procedur podejmowanych podczas jej tworzenia.

Z wyrazami szacunku,
(imię i nazwisko)

PS Umieszczam linki do wspomnianych w treści materiałów:
i) Decyzja Rady w sprawie zawarcia umowy handlowej dotyczącej zwalczania obrotu towarami podrobionymi między Unią Europejską i jej Państwami Członkowskimi, Australią, Kanadą, Japonią, Republiką Korei, Meksykańskimi Stanami Zjednoczonymi, Królestwem Marokańskim, Nową Zelandią, Republiką Singapuru, Konfederacją Szwajcarską i Stanami Zjednoczonymi Ameryki (zawiera treść umowy): http://eur-lex.europa.eu/LexUriServ/LexUriServ.do?uri=COM%3A2011%3A0380%3AFIN%3APL%3APDF
ii) Odpowiedź na interpelację posłów Grzegorza Pisalskiego i Bożeny Kotkowskiej z dnia 17 marca br., nr SPS-023-15121/10: http://orka.sejm.gov.pl/izo6.nsf/www1/i15121o0/$File/i15121o0.pdf
iii) Uchwała Rady Ministrów w sprawie udzielenia zgody na podpisanie wspomnianej umowy:http://www.mkidn.gov.pl/media/docs/20120118-URM_ACTA.pdf
iv) Wspomniany komunikat na temat rolnictwa i rybołówstwa, z informacją o ACTA na stronie 43: http://consilium.europa.eu/uedocs/cms_data/docs/pressdata/en/agricult/127031.pdf

oraz kilka głosów na temat ACTA:
i) Głos Eurodeputowanej Lidii Geringer de Oedenberg po odtajnieniu treści porozumienia: http://2009.salon24.pl/238995,odtajnione-acta
ii) Zbiór uwag doktora Piotra Waglowskiego, członka Polskiej Izby Informatyki i Telekomunikacji na temat umowy i procesu jej uzgadniania: http://prawo.vagla.pl/node/9631

I’ve trolled myself with hostname config

Recently I’ve updated my hostname on ubuntu VPS running this website. To do so, I’ve changed /etc/hostname file – it is now containing “mlepicki.com” line only.

After that I’ve restarted my machine and forgot about it. Today, while updating my linkedin profile I’ve noticed that my site is not available, and instead of wordpress based site – it was serving Apache Default site. Why, the hell?

Quick look at Apache logs and I’ve noticed line:

apache2: Could not reliably determine the server's fully qualified domain name, using mlepicki.com for ServerName`

So, my hostname was used as default fully qualified domain name for ServerName. Before changes, it was “localhost”, and now “mlepicki.com” – that’s why default page was served.

To fix it, I’ve simply added line

ServerName localhost

to my /etc/apache2/httpd.conf file and restarted apache. Fixed!

Remote VNC login to Ubuntu 11.10

Today I’ve installed Ubuntu 11.10 Oneiric Ocelot on my ASrock 100HT nettop. I’ve wanted to remotely control this box via VNC protocol.
My solution was x11vnc server, so I could share one one session between remote and physical access. I’ve found useful thread about x11vnc on Ubuntu 11.10 – I’ve just added some upstart magic to start x11vnc after lightdm.

First of all, I’ve installed x11vnc:
apt-get install x11vnc

Then, I’ve created /etc/init/x11vnc.conf file:
start on login-session-start
script
x11vnc -xkb -noxrecord -noxfixes -noxdamage -display :0 -auth /var/run/lightdm/root/:0 -forever -bg -o /var/log/x11vnc.log
end script

After restart, x11vnc shoud listen on vnc startard port – 5900.

This script is of course based on upstart event mechanism. Lightdm emits login-session-start event (you can find it in lightdm.conf), and we start x11vnc when this event is emited – that’s first line of x11vnc.conf file.