I'm using PeasyCam to search around a high res image and so far I have switched the pan to the left mouse button using:
cam.setLeftDragHandler(PanDragHandler);
and I have restricted the min and max zoom so that the user can zoom right into the painting but not through it.
However the user is still free to pan outside of the painting so it would be really great if someone had a method to restrict how far left and right the user can pan with PeasyCam so something a bit like the cam.setMaximumDistance(); method but for horizontal panning.
I have a sketch that collects tweets to a hashmap using Twitter4j. At the moment I have a very simple method setup that displays the tweet fom the hasmap to the screen as a string but I have the problem that it only displays the last tweet collected. What would be really great is if I could control the hashmap iterator with keypressed commands so that I can effectively scroll through the hashmap and have the updated string displayed for the user so they can explore the collected tweets.
So the code I have so far searches for and collects tweets to a hashmap and stores the last tweet in the hashmap to a string and displays it to the screen and what would be great is a method to press < to scroll back through the hashmap (thus updating the string displayed) and accordingly to be able to press > to scroll forwards through the hash.
Here is my code in full (apologies as it is quite long) with the important bits in bold. EDIT: here is a stripped down function from my program that includes the minimum number amount of code and libraries to run, I've attempted to integrate
amnon.owed's suggestions but I'm still stuck sadly.
final int TIME_STEP = 1;
final int NUM_SEARCHES = 20;
final long DAY_DURATION = 1000*60*60*24;
Twitter twitter = new TwitterFactory().getInstance();
HashMap<Long,Tweet> tweets=new HashMap<Long,Tweet>();
public void setup(){
searchString = "News of the World";
searchTwitter(searchString);
twitter = new TwitterFactory().getOAuthAuthorizedInstance(consumerKey,consumerSecret, new AccessToken(accessToken,accessTokenSecret));
size(910,400);
}
public void searchTwitter(String searchQuery) {
twitter4j.Query query = new twitter4j.Query(searchQuery);
//twitter4j.Query.setGeoCode(new GeoLocation(52.30, 13.25), 1000.0, twitter4j.Query.KILOMETERS); // if we want to only get tweets from the region berlin
query.rpp(100);
Date referenceDate=new Date();
for(int i=0; i<NUM_SEARCHES; i++) {
QueryResult result = twitter.search(query);
for (Tweet tweet : result.getTweets()) {
// first check if ID is unique?
if (tweets.get(tweet.getId())==null) {
// filter out tweets with GPS loc
GeoLocation loc=tweet.getGeoLocation();
if (loc!=null) {
tweets.put(tweet.getId(),tweet);
twitter = new TwitterFactory().getOAuthAuthorizedInstance(consumerKey,consumerSecret, new AccessToken(accessToken,accessTokenSecret));
size(910,400,P3D);
//hint(DISABLE_OPENGL_ERROR_REPORT);
twitter4j.Query query = new twitter4j.Query(searchQuery);
//twitter4j.Query.setGeoCode(new GeoLocation(52.30, 13.25), 1000.0, twitter4j.Query.KILOMETERS); // if we want to only get tweets from the region berlin
query.rpp(100);
Date referenceDate=new Date();
for(int i=0; i<NUM_SEARCHES; i++) {
QueryResult result = twitter.search(query);
for (Tweet tweet : result.getTweets()) {
// first check if ID is unique?
if (tweets.get(tweet.getId())==null) {
// filter out tweets with GPS loc
GeoLocation loc=tweet.getGeoLocation();
if (loc!=null) {
tweets.put(tweet.getId(),tweet);
//searchTwitter(SEARCH_QUERY);
int a = thread1.getCount();
// iterate over all collected tweets
for(Tweet tweet : tweets.values()) {
GeoLocation loc=tweet.getGeoLocation();
// convert geo location into cartesian world coordinates
Vec3D p=new Vec3D(600,radians((float)loc.getLongitude())-HALF_PI,radians((float)loc.getLatitude())).toCartesian();
// create a box at the computed position
AABB box=new AABB(p,2);
noStroke();
fill(255,120,0);
// draw box at position
gfx.box(box);
// text(tweets,15,15);
fill(255);
}
textMode(SCREEN);
hud(cam);
controlP5.draw();
}
class SimpleThread extends Thread {
boolean running; // Is the thread running? Yes or no?
int wait; // How many milliseconds should we wait in between executions?
String id; // Thread name
int count; // counter
boolean doSearch = false; // search trigger
public boolean getRunning(){
return running;
}
// Constructor, create the thread
// It is not running by default
SimpleThread (int w, String s) {
wait = w;
running = false;
id = s;
count = 0;
}
public void start () {
// Set running equal to true
running = true;
// Print messages
println("Starting thread (will execute every " + wait + " milliseconds.)");
// Do whatever start does in Thread, don't forget this!
super.start();
}
// We must implement run, this gets triggered by start()
public void run () {
while (running) {
if (doSearch) {
searchTwitter(searchString);
println("Search for " + searchString + " done");
doSearch = false;
}
// println(id + ": " + count);
count++;
// Ok, let's wait for however long we should wait
// try {
// } catch (Exception e) {
// }
}
System.out.println(id + ": thread is done!"); // The thread is done when we get to the end of run()
}
public void search() {
doSearch = true;
}
public int getCount() {
return count;
}
public void quit() {
System.out.println("Quitting.");
running = false; // Setting running to false ends the loop in run()
// IUn case the thread is waiting. . .
interrupt();
}
}
public void keyPressed() {
if (key == CODED && keyCode == LEFT && iterator.hasPrevious()) {
currentTweet = iterator.previous();
}
else if (key == CODED && keyCode == RIGHT && iterator.hasNext()) {
currentTweet = iterator.next();
}
// Converts 3D cartesian coordinates to polar coordinates
//
// theVector : vector to convert
// returns : vector containing 'length', 'angleY' and 'angleZ',
// so that rotating a point (length, 0, 0) first
// around the y-axis with angleY and then around the
// z-axis with angleZ results again in point (x, y, z)
public PVector cartesianToPolar(PVector theVector) {
PVector res = new PVector();
res.x = theVector.mag();
if (res.x > 0) {
res.y = -atan2(theVector.z, theVector.x);
res.z = asin(theVector.y / res.x);
}
else {
res.y = 0;
res.z = 0;
}
return res;
}
class Satellite {
float lat, lng, x, y, z, elevation;
String[] positions;
int id;
public void display() {
lng += random(0.001f, 0.0005f);
pushMatrix();
translate(x, y, z);
fill(255, 0, 0);
noStroke();
sphere(10);
popMatrix();
update();
}
public void update() {
x = r*cos(lat)*cos(lng);
y = r*cos(lat)*sin(lng);
z = r*sin(lat);
}
}
public void initializeSphere(int res)
{
sinLUT = new float[sincos_length];
cosLUT = new float[sincos_length];
for (int i = 0; i < sincos_length; i++) {
sinLUT[i] = (float) Math.sin(i * DEG_TO_RAD * sincos_precision);
cosLUT[i] = (float) Math.cos(i * DEG_TO_RAD * sincos_precision);
}
float delta = (float)sincos_length/res;
float[] cx = new float[res];
float[] cz = new float[res];
// Calc unit circle in XZ plane
for (int i = 0; i < res; i++) {
cx[i] = -cosLUT[(int) (i*delta) % sincos_length];
cz[i] = sinLUT[(int) (i*delta) % sincos_length];
}
// Computing vertexlist vertexlist starts at south pole
int vertCount = res * (res-1) + 2;
int currVert = 0;
// Re-init arrays to store vertices
sphereX = new float[vertCount];
sphereY = new float[vertCount];
sphereZ = new float[vertCount];
float angle_step = (sincos_length*0.5f)/res;
float angle = angle_step;
public void texturedSphere(float r, PImage t)
{
int v1,v11,v2;
beginShape(TRIANGLE_STRIP);
texture(t);
float iu=(float)(t.width-1)/(sDetail);
float iv=(float)(t.height-1)/(sDetail);
float u=0,v=iv;
for (int i = 0; i < sDetail; i++) {
vertex(0, -r, 0,u,0);
vertex(sphereX[i]*r, sphereY[i]*r, sphereZ[i]*r, u, v);
u+=iu;
}
vertex(0, -r, 0,u,0);
vertex(sphereX[0]*r, sphereY[0]*r, sphereZ[0]*r, u, v);
endShape();
// Middle rings
int voff = 0;
for(int i = 2; i < sDetail; i++) {
v1=v11=voff;
voff += sDetail;
v2=voff;
u=0;
beginShape(TRIANGLE_STRIP);
texture(t);
for (int j = 0; j < sDetail; j++) {
vertex(sphereX[v1]*r, sphereY[v1]*r, sphereZ[v1++]*r, u, v);
vertex(sphereX[v2]*r, sphereY[v2]*r, sphereZ[v2++]*r, u, v+iv);
u+=iu;
}
// Close each ring
v1=v11;
v2=voff;
vertex(sphereX[v1]*r, sphereY[v1]*r, sphereZ[v1]*r, u, v);
vertex(sphereX[v2]*r, sphereY[v2]*r, sphereZ[v2]*r, u, v+iv);
endShape();
v+=iv;
}
u=0;
// Add the northern cap
beginShape(TRIANGLE_STRIP);
texture(t);
for (int i = 0; i < sDetail; i++) {
v2 = voff + i;
vertex(sphereX[v2]*r, sphereY[v2]*r, sphereZ[v2]*r, u, v);
vertex(0, r, 0,u,v+iv);
u+=iu;
}
//vertex(0, r, 0,u, v+iv);
vertex(sphereX[voff]*r, sphereY[voff]*r, sphereZ[voff]*r, u, v);
endShape();
}
Hi there, I've had some problems with a project over the past few days that collects and displays tweets to a 3D Earth using Twitter4j. I'm quite a new programmer so I'm learning as I go and this forum has become a great resource.
Essentially I have a string that is updated to be the latest tweet that is stored within a hashmap. The hashmap is updated when I run a search using Twitter4J for a particular keyword and the string is then displayed to the screen. This gives me a brief look at various tweets that are being stored in the hashmap but ultimately it displays the last one stored after about 3 seconds which is all much too fast for my user experience. So I was wondering if there was a way to slow down the Twitter4J query so that the string displays the located tweet for say 5 seconds before querying again and changing the content of the string that is displayed? I've tried adjusting the thread's wait integer but to no avail.
// r = earth radius in px. 6371 is earth radius in km.
float pxToKm = 6371.0f / r;
int inRange;
String searchString;
String searchState = "";
String consumerKey = "5cO4mwCxSzh2IDixU6rKEg";
String consumerSecret = "vL3YbYclatCdFNcDzBds8BMX87mCxSqSdn0YFh8XA";
String accessToken = "319951547-kPyfRlb9MHt2LwjEtIsR2uaqAvH49dQvj5nR4gyQ";
String accessTokenSecret = "V7juyEfTgWGbeMAaVJRbiZdwJB3bCDHHPmClKN5l0";
PeasyCam cam;
PeasyDragHandler PanDragHandler;
PFont imhelix;
ControlP5 controlP5;
PMatrix3D currCameraMatrix;
//final String SEARCH_QUERY="hello";
final int TIME_STEP = 1;
final int NUM_SEARCHES = 25;
final long DAY_DURATION = 1000*60*60*24;
Twitter twitter = new TwitterFactory().getInstance();
HashMap<Long,Tweet> tweets=new HashMap<Long,Tweet>();
Iterator i = tweets.entrySet().iterator(); // Get an iterator
ToxiclibsSupport gfx;
SimpleThread thread1;
font = createFont("ArialNarrow", 20);
textFont(font);
twitter = new TwitterFactory().getOAuthAuthorizedInstance(consumerKey,consumerSecret, new AccessToken(accessToken,accessTokenSecret));
size(864,400,P3D);
//hint(DISABLE_OPENGL_ERROR_REPORT);
public void searchTwitter(String searchQuery) {
twitter4j.Query query = new twitter4j.Query(searchQuery);
//twitter4j.Query.setGeoCode(new GeoLocation(52.30, 13.25), 1000.0, twitter4j.Query.KILOMETERS); // if we want to only get tweets from the region berlin
query.rpp(100);
Date referenceDate=new Date();
for(int i=0; i<NUM_SEARCHES; i++) {
String d=new SimpleDateFormat("yyyy-MM-dd").format(referenceDate);
//println("executing search for date: "+d);
query.until(d);
// execute search
try {
QueryResult result = twitter.search(query);
for (Tweet tweet : result.getTweets()) {
// first check if ID is unique?
if (tweets.get(tweet.getId())==null) {
// filter out tweets with GPS loc
GeoLocation loc=tweet.getGeoLocation();
if (loc!=null) {
tweets.put(tweet.getId(),tweet);
//searchTwitter(SEARCH_QUERY);
int a = thread1.getCount();
text(a,10,50);
// iterate over all collected tweets
for(Tweet tweet : tweets.values()) {
GeoLocation loc=tweet.getGeoLocation();
// convert geo location into cartesian world coordinates
Vec3D p=new Vec3D(600,radians((float)loc.getLongitude())-HALF_PI,radians((float)loc.getLatitude())).toCartesian();
// create a box at the computed position
AABB box=new AABB(p,2);
noStroke();
fill(255,120,0);
// draw box at position
gfx.box(box);
// text(tweets,15,15);
fill(255);
controlP5.draw(); }
hud(cam);
}
class SimpleThread extends Thread {
boolean running; // Is the thread running? Yes or no?
int wait; // How many milliseconds should we wait in between executions?
String id; // Thread name
int count; // counter
boolean doSearch = false; // search trigger
public boolean getRunning(){
return running;
}
// Constructor, create the thread
// It is not running by default
SimpleThread (int w, String s) {
wait = w;
running = false;
id = s;
count = 0;
}
public void start () {
// Set running equal to true
running = true;
// Print messages
println("Starting thread (will execute every " + wait + " milliseconds.)");
// Do whatever start does in Thread, don't forget this!
super.start();
}
// We must implement run, this gets triggered by start()
public void run () {
while (running) {
if (doSearch) {
searchTwitter(searchString);
println("Search for " + searchString + " done");
doSearch = false;
}
// println(id + ": " + count);
count++;
// Ok, let's wait for however long we should wait
// try {
// sleep((long)(wait));
// } catch (Exception e) {
// }
}
System.out.println(id + ": thread is done!"); // The thread is done when we get to the end of run()
}
public void search() {
doSearch = true;
}
public int getCount() {
return count;
}
public void quit() {
System.out.println("Quitting.");
running = false; // Setting running to false ends the loop in run()
// IUn case the thread is waiting. . .
interrupt();
}
}
// Converts 3D cartesian coordinates to polar coordinates
//
// theVector : vector to convert
// returns : vector containing 'length', 'angleY' and 'angleZ',
// so that rotating a point (length, 0, 0) first
// around the y-axis with angleY and then around the
// z-axis with angleZ results again in point (x, y, z)
public PVector cartesianToPolar(PVector theVector) {
PVector res = new PVector();
res.x = theVector.mag();
if (res.x > 0) {
res.y = -atan2(theVector.z, theVector.x);
res.z = asin(theVector.y / res.x);
}
else {
res.y = 0;
res.z = 0;
}
return res;
}
class Satellite {
float lat, lng, x, y, z, elevation;
String[] positions;
int id;
public void display() {
lng += random(0.001f, 0.0005f);
pushMatrix();
translate(x, y, z);
fill(255, 0, 0);
noStroke();
sphere(10);
popMatrix();
update();
}
public void update() {
x = r*cos(lat)*cos(lng);
y = r*cos(lat)*sin(lng);
z = r*sin(lat);
}
}
public void initializeSphere(int res)
{
sinLUT = new float[sincos_length];
cosLUT = new float[sincos_length];
for (int i = 0; i < sincos_length; i++) {
sinLUT[i] = (float) Math.sin(i * DEG_TO_RAD * sincos_precision);
cosLUT[i] = (float) Math.cos(i * DEG_TO_RAD * sincos_precision);
}
float delta = (float)sincos_length/res;
float[] cx = new float[res];
float[] cz = new float[res];
// Calc unit circle in XZ plane
for (int i = 0; i < res; i++) {
cx[i] = -cosLUT[(int) (i*delta) % sincos_length];
cz[i] = sinLUT[(int) (i*delta) % sincos_length];
}
// Computing vertexlist vertexlist starts at south pole
int vertCount = res * (res-1) + 2;
int currVert = 0;
// Re-init arrays to store vertices
sphereX = new float[vertCount];
sphereY = new float[vertCount];
sphereZ = new float[vertCount];
float angle_step = (sincos_length*0.5f)/res;
float angle = angle_step;
public void texturedSphere(float r, PImage t)
{
int v1,v11,v2;
beginShape(TRIANGLE_STRIP);
texture(t);
float iu=(float)(t.width-1)/(sDetail);
float iv=(float)(t.height-1)/(sDetail);
float u=0,v=iv;
for (int i = 0; i < sDetail; i++) {
vertex(0, -r, 0,u,0);
vertex(sphereX[i]*r, sphereY[i]*r, sphereZ[i]*r, u, v);
u+=iu;
}
vertex(0, -r, 0,u,0);
vertex(sphereX[0]*r, sphereY[0]*r, sphereZ[0]*r, u, v);
endShape();
// Middle rings
int voff = 0;
for(int i = 2; i < sDetail; i++) {
v1=v11=voff;
voff += sDetail;
v2=voff;
u=0;
beginShape(TRIANGLE_STRIP);
texture(t);
for (int j = 0; j < sDetail; j++) {
vertex(sphereX[v1]*r, sphereY[v1]*r, sphereZ[v1++]*r, u, v);
vertex(sphereX[v2]*r, sphereY[v2]*r, sphereZ[v2++]*r, u, v+iv);
u+=iu;
}
// Close each ring
v1=v11;
v2=voff;
vertex(sphereX[v1]*r, sphereY[v1]*r, sphereZ[v1]*r, u, v);
vertex(sphereX[v2]*r, sphereY[v2]*r, sphereZ[v2]*r, u, v+iv);
endShape();
v+=iv;
}
u=0;
// Add the northern cap
beginShape(TRIANGLE_STRIP);
texture(t);
for (int i = 0; i < sDetail; i++) {
v2 = voff + i;
vertex(sphereX[v2]*r, sphereY[v2]*r, sphereZ[v2]*r, u, v);
vertex(0, r, 0,u,v+iv);
u+=iu;
}
//vertex(0, r, 0,u, v+iv);
vertex(sphereX[voff]*r, sphereY[voff]*r, sphereZ[voff]*r, u, v);
endShape();
}
I am a fairly new programmer using processing and I was wondering if anybody knew how to print the contents of a hashmap, in this case tweets, to the screen within a loop? It seems to be no problem to print to the console but it seems a bit trickier to print to the screen. Here is an extract from the code so far with the problem area in bold:
Line 137: Twitter twitter = new TwitterFactory().getInstance();
HashMap<Long,Tweet> tweets=new HashMap<Long,Tweet>();
...
Line 233: public void searchTwitter(String searchQuery) {
twitter4j.Query query = new twitter4j.Query(searchQuery);
query.rpp(100);
Date referenceDate=new Date();
for(int i=0; i<NUM_SEARCHES; i++) {
String d=new SimpleDateFormat("yyyy-MM-dd").format(referenceDate);
query.until(d);
try {
QueryResult result = twitter.search(query);
for (Tweet tweet : result.getTweets()) {
if (tweets.get(tweet.getId())==null) {
GeoLocation loc=tweet.getGeoLocation();
if (loc!=null) {
tweets.put(tweet.getId(),tweet);
}
} else {
//println("skipping: "+tweet.getId());
}
}
}
catch(TwitterException e) {
println(e.getMessage());
}
referenceDate.setTime(referenceDate.getTime()-TIME_STEP*DAY_DURATION);
}
}
...
Line 268: public void draw() {
for(Tweet tweet : tweets.values()) {
GeoLocation loc=tweet.getGeoLocation();
Vec3D p=new
Vec3D(600,radians((float)loc.getLongitude())-HALF_PI,radians((float)loc.getLatitude())).toCartesian();
// create a box at the computed position
AABB box=new AABB(p,2);
noStroke();
fill(255,120,0);
// draw box at position
gfx.box(box);
print(tweet); - so this prints the tweets to the console in the loop but replacing print with text and an x and y
position throws an error...
fill(255);