Im trying to get the direction of the vector pointing out of the camera, with respect to magnetic north. I'm under the impression that I need to use the values returned from getOrientation(), but I'm not sure what they represent. The values I get from getOrientation() don't change predictably when I change the orientation of the phone (rotating 90 degrees does not change values by 90 degrees). I need to know what the values returned by getOrientation() mean. What I have so far is written below:
package com.example.orientation;
import android.app.Activity;
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.widget.Toast;
public class Orientation extends Activity{
private SensorManager mSM;
private mSensorEventListener mSEL;
float[] inR = new float[16];
float[] outR= new float[16];
float[] I = new float[16];
float[] gravity = new float[3];
float[] geomag = new float[3];
float[] orientVals = new float[3];
final float pi = (float) Math.PI;
final float rad2deg = 180/pi;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mSM = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
mSEL = new mSensorEventListener();
mSM.registerListener(mSEL,
mSM.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
SensorManager.SENSOR_DELAY_NORMAL);
mSM.registerListener(mSEL,
mSM.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD),
SensorManager.SENSOR_DELAY_NORMAL);
}
private class mSensorEventListener implements SensorEventListener{
#Override
public void onAccuracyChanged(Sensor arg0, int arg1) {}
#Override
public void onSensorChanged(SensorEvent event) {
// If the sensor data is unreliable return
if (event.accuracy == SensorManager.SENSOR_STATUS_UNRELIABLE)
return;
// Gets the value of the sensor that has been changed
switch (event.sensor.getType()){
case Sensor.TYPE_ACCELEROMETER:
gravity = event.values.clone();
break;
case Sensor.TYPE_MAGNETIC_FIELD:
geomag = event.values.clone();
break;
}
// If gravity and geomag have values then find rotation matrix
if (gravity != null && geomag != null){
// checks that the rotation matrix is found
boolean success = SensorManager.getRotationMatrix(inR, I, gravity, geomag);
if (success){
// Re-map coordinates so y-axis comes out of camera
SensorManager.remapCoordinateSystem(inR, SensorManager.AXIS_X,
SensorManager.AXIS_Z, outR);
// Finds the Azimuth and Pitch angles of the y-axis with
// magnetic north and the horizon respectively
SensorManager.getOrientation(outR, orientVals);
float azimuth = orientVals[0]*rad2deg;
float pitch = orientVals[1]*rad2deg;
float roll = orientVals[2]*rad2deg;
// Displays a pop up message with the azimuth and inclination angles
String endl = System.getProperty("line.separator");
Toast.makeText(getBaseContext(),
"Rotation:" +
outR[0] + " " + outR[1] + " " + outR[2] + endl +
outR[4] + " " + outR[5] + " " + outR[6] + endl +
outR[8] + " " + outR[9] + " " + outR[10] + endl +endl +
"Azimuth: " + azimuth + " degrees" + endl +
"Pitch: " + pitch + " degrees" + endl +
"Roll: " + roll + " degrees",
Toast.LENGTH_LONG).show();
} /*else
Toast.makeText(getBaseContext(),
"Get Rotation Matrix Failed", Toast.LENGTH_LONG).show();*/
}
}
}
}
I've looked at the documentation on the sensorManager class, but it hasn't helped solve this. If anyone could help me get meaning out of the this I would really appreciate it. I'm testing on a Nexus One running Android 2.1
Because I was new to android I was using toast to display the information on the screen. I changed it to just update text on a view and that seemed to fix it. I also figured out that what I assumed the orientVals actually were is correct. For what I need the roll is not used. Also didnt realize there was a way to convert from rad to deg built in so I just used that.
you can check out the logger application that displays raw values on the screen. In its description you'll find a link to the source code so that you can learn how it accesses the sensors.
HTH,
Daniele
You need to get the orientation of your device (Landscape/Portrait)
and make some compensation.
SensorManager.getOrientation(R, values);
mHeading = (int) Math.toDegrees(values[0]);
Display display =
((WindowManager)getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
int compensation = display.getRotation() * 90;
mHeading = mHeading+compensation;
I think you should have to use getInclination to get the direction instead of get orientation. as getRotationMatrix is calculating based on both gravity and geomagnetic feild and you will get the inlination from the magnetic field directly.
I Think you should change outR to inR in line getOrientation
boolean success = SensorManager.getRotationMatrix(inR, I, gravity, geomag);
if (success){
// Re-map coordinates so y-axis comes out of camera
SensorManager.remapCoordinateSystem(inR, SensorManager.AXIS_X,
SensorManager.AXIS_Z, outR);
// Finds the Azimuth and Pitch angles of the y-axis with
// magnetic north and the horizon respectively
**SensorManager.getOrientation(inR, orientVals);**
Related
I am working on a project with my rocketry club.
I want to have a microbit control the orientation of the fins to auto-stabilize the rocket.
But first, I tried to make a processing code to display in real-time my micro-bit's orientation using its integrated gyroscope.
Here's my processing code :
import processing.serial.*; // import the serial library
Serial myPort; // create a serial object
float xRot = 0; // variables to store the rotation angles
float yRot = 0;
float zRot = 0;
String occ[];
void setup() {
size(400, 400, P3D); // set the size of the window and enable 3D rendering
String portName = Serial.list()[0]; // get the name of the first serial port
myPort = new Serial(this, portName, 115200); // open a connection to the serial port
println((Object[]) Serial.list());
}
void draw() {
background(255); // clear the screen
translate(width/2, height/2, 0); // center the cube on the screen
rotateX(xRot); // apply the rotations
rotateZ(yRot);
rotateY(zRot);
fill(200); // set the fill color
box(100); // draw the cube
}
void serialEvent(Serial myPort) {
// this function is called whenever new data is available
// read the incoming data from the serial port
String data = myPort.readStringUntil('\n'); // read the data as a string
// print the incoming data to the console if it is not an empty string
if (data != null) {
println(data);
}
delay(10);
if (data != null) {
// split the string into separate values
String[] values = split(data, ',');
// convert the values to floats and store them in the rotation variables
xRot = radians(float(values[0]));
yRot = radians(float(values[1]));
zRot = radians(float(values[2]));
}
}
and here's the python code I have on my microbit
pitch = 0
roll = 0
x = 0
y = 0
z = 0
def on_forever():
global pitch, roll, x, y, z
pitch = input.rotation(Rotation.PITCH) + 90
roll = input.rotation(Rotation.ROLL) + 90
servos.P2.set_angle(pitch)
servos.P1.set_angle(roll)
x = input.rotation(Rotation.PITCH)
y = input.rotation(Rotation.ROLL)
z = 1
serial.set_baud_rate(BaudRate.BAUD_RATE115200)
serial.write_string(str(x) + "," + str(y) + "," + str(z) + "\n")
basic.forever(on_forever)
What happens when I run my code is that a cube appears and rotates weirdly for a short time, then, the cube stops and processing prints "Error, disabling serialEvent() for COM5 null".
Please help me out, I really need this code to be working!
Is this the documentation for the micro:bit Python API you're using ?
input.rotation (as the reference mentions), returns accelerometer data:
a number that means how much the micro:bit is tilted in the direction you ask for. This is a value in degrees between -180 to 180 in either the Rotation.Pitch or the Rotation.Roll direction of rotation.
I'd start with a try/catch block to get more details on the actual error.
e.g. is it the actual serial communication (e.g. resetting the baud rate over and over again (serial.set_baud_rate(BaudRate.BAUD_RATE115200)) instead of once) or optimistically assuming there will be 0 errors in serial communication and the string will always split to at least 3 values.
Unfortunately I won't have the resources to test with an actual device, so the following code might contain errors, but hopefully it illustrates some of the ideas.
I'd try simplifying/minimising the amount of data used on the micropython (and setting the baud rate once) and removing the need to read accelerometer data twice in the same iteration. If z is always 1 it can probably be ignored (you always rotate by 1 degree in Processing if necessary):
pitch = 0
roll = 0
x = 0
y = 0
def on_forever():
global pitch, roll, x, y
x = input.rotation(Rotation.PITCH)
y = input.rotation(Rotation.ROLL)
pitch = x + 90
roll = y + 90
servos.P2.set_angle(pitch)
servos.P1.set_angle(roll)
serial.write_string(str(x) + "," + str(y) + "\n")
serial.set_baud_rate(BaudRate.BAUD_RATE115200)
basic.forever(on_forever)
On the processing side, I'd surround serial code with try/catch just in case anything went wrong and double check every step of the string parsing process:
import processing.serial.*; // import the serial library
Serial myPort; // create a serial object
float xRot = 0; // variables to store the rotation angles
float yRot = 0;
void setup() {
size(400, 400, P3D); // set the size of the window and enable 3D rendering
String portNames = Serial.list();
println(portNames);
String portName = portNames[0]; // get the name of the first serial port
try {
myPort = new Serial(this, portName, 115200); // open a connection to the serial port
myPort.bufferUntil('\n');
} catch (Exception e){
println("error opening serial port " + portName + "\ndouble check USB is connected and the port isn't already open in another app")
e.printStackTrace();
}
}
void draw() {
background(255); // clear the screen
translate(width/2, height/2, 0); // center the cube on the screen
rotateX(xRot); // apply the rotations
rotateZ(yRot);
fill(200); // set the fill color
box(100); // draw the cube
}
void serialEvent(Serial myPort) {
try{
// this function is called whenever new data is available
// read the incoming data from the serial port
String data = myPort.readString(); // read the data as a string
// print the incoming data to the console if it is not an empty string
if (data != null) {
println(data);
// cleanup / remove whitespace
data = data.trim();
// split the string into separate values
String[] values = split(data, ',');
if (values.length >= 2){
// convert the values to floats and store them in the rotation variables
xRot = radians(float(values[0]));
yRot = radians(float(values[1]));
}else{
println("received unexpected number of values");
printArray(values);
}
}
} catch (Exception e){
println("error reading serial:");
e.printStackTrace();
}
}
(If the above still produces serial errors I'd also write a separate test that doesn't use the servos, just in case internally some servo pwm timing/interrupts alongside accelerometer data polling interferes with serial communication for some reason.)
(AFAIK there is no full IMU support on the micro::bit (e.g. accelerometer + gyroscope + magnetometer (+ ideally sensor fusion)), just accelerometer + magnetometer. If you want to get basic rotation data, but don't care for full 3D orientation of the device should suffice. Otherwise you'd need an IMU (e.g BNO055 or newer) which you can connect to the micro via I2C (but will also probably need to implement the communications protocol to the sensor if someone else hasn't done so already).(In theory I see there's Python support for the Nordic nRF52840 chipset, however microbit uses nRF51822 for v1 and nRF52833 for v2 :/). Depending on your application you might want to switch to a different microcontroller altogether. (for example the official Arduino 33 BLE has a built-in accelerometer (and Python support) (and even supports TensorFlow Lite))
Since I do not have a microbit I tested your Processing code using an Arduino UNO at 9600 baud rate. The following serialEvent() function runs without error:
void serialEvent(Serial myPort) {
String data = myPort.readStringUntil('\n');
if (data != null) {
String inStr = trim(data);
String[] values = split(inStr, ',');
printArray(values);
// convert the values to floats and store them in the rotation variables
xRot = radians(float(values[0]));
yRot = radians(float(values[1]));
zRot = radians(float(values[2]));
}
}
Arduino code:
byte val1 = 0;
byte val2 = 0;
byte val3 = 0;
void setup() {
Serial.begin(9600);
}
void loop() {
val1 += 8;
val2 += 4;
val3 += 2;
String s = String(String(val1) + "," + String(val2) + "," + String(val3));
Serial.println(s);
}
Thank you very much George Profenza, it works perfectly well now!
I just had to fix some errors in the code.
Here's the functional code if anyone has this problem later :
import processing.serial.*; // import the serial library
Serial myPort; // create a serial object
float xRot = 0; // variables to store the rotation angles
float yRot = 0;
void setup() {
size(400, 400, P3D); // set the size of the window and enable 3D rendering
String portNames[] = Serial.list();
printArray(portNames);
String portName = portNames[0]; // get the name of the first serial port
try {
myPort = new Serial(this, portName, 115200); // open a connection to the serial port
myPort.bufferUntil('\n');
}
catch (Exception e) {
println("error opening serial port " + portName + "\ndouble check USB is connected and the port isn't already open in another app");
e.printStackTrace();
}
}
void draw() {
background(255); // clear the screen
translate(width/2, height/2, 0); // center the cube on the screen
rotateX(xRot); // apply the rotations
rotateZ(yRot);
fill(200); // set the fill color
box(100); // draw the cube
}
void serialEvent(Serial myPort) {
try {
// this function is called whenever new data is available
// read the incoming data from the serial port
String data = myPort.readString(); // read the data as a string
// print the incoming data to the console if it is not an empty string
if (data != null) {
println(data);
// cleanup / remove whitespace
data = data.trim();
// split the string into separate values
String[] values = split(data, ',');
if (values.length >= 2) {
// convert the values to floats and store them in the rotation variables
xRot = radians(float(values[0]));
yRot = radians(float(values[1]));
} else {
println("received unexpected number of values");
printArray(values);
}
}
}
catch (Exception e) {
println("error reading serial:");
e.printStackTrace();
}
}
As for the Micro:Bit, I didn't have to change the code at all...
I assume their was an error with the Z axis since we basically just removed removed that...
Using Gluon Mobile 4 and Gluon Maps 1.0.1, I am displaying a map with a layer showing foot steps. When the users double clicks the mouse button, a new foot step is shown. This works great, but I currently need a workaround to convert from pointer coordinates (where the user clicked) to MapPoints (needed for the layer).
Here is how the mouse click is obtained:
public MainView(String name) {
super(name);
MapView mapView = new MapView();
mapView.setZoom(18f);
mapView.setCenter(NUREMBERG);
layer = new FootStepsLayer();
mapView.addLayer(layer);
setCenter(mapView);
layer.addPoint(NUREMBERG);
setOnMouseClicked(event -> {
if ((event.getButton() == MouseButton.PRIMARY)
&& (event.getClickCount() == 2)) {
double x = event.getX();
double y = event.getY();
layer.addPoint(x, y);
}
});
}
Currently my layer implementation looks like this:
public class FootStepsLayer extends MapLayer {
private static final Image FOOTSTEPS
= new Image(FootStepsLayer.class.getResourceAsStream("/footsteps.png"),
32, 32, true, true);
private final ObservableList<Pair<MapPoint, Node>> points
= FXCollections.observableArrayList();
public void addPoint(MapPoint mapPoint) {
Node node = new ImageView(FOOTSTEPS);
Pair<MapPoint, Node> pair = new Pair<>(mapPoint, node);
points.add(pair);
getChildren().add(node);
markDirty();
}
public void addPoint(double x, double y) {
Bounds bounds = baseMap.getParent().getLayoutBounds();
baseMap.moveX(x - bounds.getWidth() / 2);
baseMap.moveY(y - bounds.getHeight() / 2);
addPoint(new MapPoint(baseMap.centerLat().get(),
baseMap.centerLon().get()));
}
#Override
protected void layoutLayer() {
// Warning: suggested conversion to functional style crashed app on BlueStacks
for (Pair<MapPoint, Node> element : points) {
MapPoint mapPoint = element.getKey();
Node node = element.getValue();
Point2D point = baseMap.getMapPoint(mapPoint.getLatitude(), mapPoint.getLongitude());
node.setVisible(true);
node.setTranslateX(point.getX());
node.setTranslateY(point.getY());
}
}
}
My workaround is in public void addPoint(double x, double y): I am calling moveX() and moveY(), because after that I can query centerLat() and centerLong(). This is not ideal because the map moves and the new foot step becomes the center of the map. What I want is the map position to remain unchanged.
If I have not overlooked it, there seems to be no API for converting mouse coordinates to geo locations. As answered in question create a polyline in gluon mapLayer, the BaseMap class has two getMapPoint methods, but I have found none the other way round. But there must be a way to do it. ;-)
If you have a look at BaseMap, there is already one method that does precisely what you are looking for, but only for the center of the map: calculateCenterCoords.
Based on it, you could add your own method to BaseMap, where the sceneX and sceneY coordinates are taken into account instead:
public MapPoint getMapPosition(double sceneX, double sceneY) {
double x = sceneX - this.getTranslateX();
double y = sceneY - this.getTranslateY();
double z = zoom.get();
double latrad = Math.PI - (2 * Math.PI * y) / (Math.pow(2, z) * 256);
double mlat = Math.toDegrees(Math.atan(Math.sinh(latrad)));
double mlon = x / (256 * Math.pow(2, z)) * 360 - 180;
return new MapPoint(mlat, mlon);
}
Then you can expose this method in MapView:
public MapPoint getMapPosition(double sceneX, double sceneY) {
return baseMap.getMapPosition(sceneX, sceneY);
}
So you can use it on your map:
mapView.setOnMouseClicked(e -> {
MapPoint mapPosition = mapView.getMapPosition(e.getSceneX(), e.getSceneY());
System.out.println("mapPosition: " + mapPosition.getLatitude()+ ", " + mapPosition.getLongitude());
});
This method should be part of Maps, so feel free to create a feature request or even a pull request.
I am trying to build a calculator that will give me the calculation for width length and Area and perimeter. Now where I'm stuck, once I label the text box ( txtWidth) and then I click on it to bring up the code editor what do I put in under the handler. Second question how do I enter the math for them. Like I know that to get the area I just do widthlength and for perimeter it's 2*width + 2*length. And I also need to add fractional decimal entries like 10.5 and 20.65. I hope this gives more insight to what I'm trying to do.
Assuming you're using C#... add two labels (lblArea & lblPerimeter) and a button (btnCalculate), and add an event for the button (double-click on it):
Here's your homework:
private void CalculateDisplayInfo()
{
double len = 0.0;
if (!double.TryParse(txtLength.Text, out len))
{
MessageBox.Show(this, "Invalid Length Input", "ERROR", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
return;
}
double width = 0.0;
if (!double.TryParse(txtWidth.Text, out width))
{
MessageBox.Show(this, "Invalid Width Input", "ERROR", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
return;
}
lblArea.Text = (width * len).ToString();
lblPerimeter.Text = (2 * (width + len)).ToString();
}
private void btnCalculate_Click(object sender, EventArgs e)
{
CalculateDisplayInfo();
}
I have a huge (but probably simple) problem. I want to display score. I'm using GUI.Label. When I scale GUI.Label. I want to set position of text. I work on Android, so there are many resolutions and aspect ratios, and I have problem with giving it a precise position.
The "GAME OVER" text is sprite. I tried to set position as half of screen height. It works on some devices, but it doesn't work on devices with highest resolution (1280x720). When I set 400px from top it works, but it doesn't make any sense. Is there any tip for this? I want to display score like here.
My code:
private string labelText;
public Font fontxd;
public Vector2 sizexde;
/*[HideInInspector]*/public GUIStyle styl;
public int p,hp;
static GameObject g1;
static punkt playerScript;
static float virtualWidth = 640.0f;
static float virtualHeight = 400.0f;
static Rect rece;
static Vector3 v3;
public Matrix4x4 matrixs;
static float guiRatio=Screen.width/640;
static float XD=0;
void Start() //1280x720
{
if (Screen.width > Screen.height) {
XD=Screen.width/2;
}
else{//if( Screen.height>Screen.width ){
XD=Screen.height/2;
}
rece=new Rect(10,XD, Screen.width,1);
v3 = new Vector3 (Screen.width / virtualWidth, Screen.width / virtualWidth , 1.0f);
matrixs = Matrix4x4.TRS (Vector3.zero, Quaternion.identity, v3);
g1 = GameObject.Find("XDXDX2");
playerScript = g1.GetComponent<punkt>();
}
void OnGUI()
{
p = playerScript.punkty;
hp = playerScript.hpunkty;
labelText = "Height: " + Screen.height+"-"+Screen.height/2 + "\nWidth: " + Screen.width + "-"+Screen.width/2 ;
GUI.matrix = matrixs;
styl.normal.textColor = Color.black;
styl.font = fontxd;
styl.fontSize = 70;
GUI.Label (rece, labelText, styl);
}
GameObject > CreateOther > GUIText
Edit settings in inspect as shown below:
Now your label's position should be resolution independent.
I'm working on a program that reads in some images (.jpg) and text from source files and assembling them into a single PDF. I know processing probably isn't the best language to do it in, but its the only one I know how to do it in. Anyway, I am having an issue where processing calls setup two times. I've seen that this issue is resolved when size() is the first line within setup, however I can't have that happen, because I have to read in and store all my data, find the width of the widest image, then make sure its tall enough to accommodate pages with more than one image, and add text before I can decide on how wide and tall my window is. I am looking for suggestions as to how I might structure the code so that I can get all my information without having to call setup twice, because that's causing my PDF to contain two copies of all the data. I've included setup if it helps anyone. Thanks!
void setup(){
font = loadFont("TimesNewRomanPSMT-20.vlw");
File clientsFolder = new File("C:/Users/[my name]/Documents/Processing/ExerciseProgram/Clients");
clients = clientsFolder.listFiles();
for(File x : clients){
println(x.getName());
}
//test files to see if they end in .txt, and have a matching .pdf extension that is newer
String nextClient = needPdf();
File nextClientData = new File("C:/Users/[my name]/Documents/Processing/ExerciseProgram/Clients/" + nextClient);
//println(nextClientData.getName());
//open the file for reading
//setup can't throw the exception, and it needs it, so this should take care of it
try{
Scanner scan = new Scanner(nextClientData);
while(scan.hasNextLine() ){
exercises.add(scan.nextLine());
}
//println(exercises.toString());
printedData = new Exercise[exercises.size()];
println(exercises.size());
for(int i = 0; i < exercises.size(); i++){
printedData[i] = new Exercise((String)exercises.get(i));
}
//count the width and height
int w = 0, h = 0;
for(Exercise e: printedData){
if(e.getWidest() > w){
w = e.getWidest();
}
if(e.getTallest() > h){
h = e.getHeight();
}
}
//and finally we can create the freaking window
// this cuts the .txt off
size(w, h, PDF, "C:/Users/[my name]/Desktop/" + nextClient.substring(0, nextClient.length() - 4) + ".pdf");
}catch (FileNotFoundException e){
println("Unknown error in PApplet.setup(). Exiting.");
println(e.getMessage() );
exit();
}
}
How about moving all these functions to be done before setup()? Although processing usually complains that you are "mixing static and active modes", this hack seems to work at processing 2.0.1:
int i = beforeSetup();
int szX,szY;
int beforeSetup() {
println("look! I am happening before setup()!!");
szX = 800;
szY = 600;
return 0;
}
void setup() {
size(szX,szY);
println("awww");
}
You are essentially calling a function to fill int i just as a hack to run all the functions you want, thus having to compute whatever you want before having to set the window size.
perhaps you can resize your window after calcs are done? Once I made this sketch to see how resizing would work, it is expecting an image file, see if it can help you...
//no error handling for non image files!
PImage img;
int newCanvasWidth = MIN_WINDOW_WIDTH; // made global to use in draw
int newCanvasHeight = MIN_WINDOW_HEIGHT;
java.awt.Insets insets; //"An Insets object is a representation of the borders of a container"
//from http://docs.oracle.com/javase/1.4.2/docs/api/java/awt/Insets.html
void setup()
{
size(200, 200); // always first line
frame.pack(); insets = frame.getInsets();
frame.setResizable(true);
/// for debuging, system depende`nt, at least screen is...
print("MIN_WINDOW_WIDTH = " + MIN_WINDOW_WIDTH);
print(" MIN_WINDOW_HEIGHT = " + MIN_WINDOW_HEIGHT);
print(" screenWidth = " + displayWidth);
println(" screenHeight = " + displayHeight);
}
void draw()
{
if (img != null)
{
image(img, 0, 0, newCanvasWidth, newCanvasHeight);
}
}
void getImageAndResize(File selected)
{
String path = selected.getAbsolutePath();
if (path == null)
{
println ("nono :-|");
}
else
{
img = loadImage(path);
// a temp variable for readability
int widthInsets =insets.left + insets.right;
int heightInsets =insets.top + insets.bottom;
// constrain values between screen size and minimum window size
int newFrameWidth = constrain(img.width + widthInsets, MIN_WINDOW_WIDTH, displayWidth);
int newFrameHeight = constrain(img.height + heightInsets, MIN_WINDOW_HEIGHT, displayHeight -20);
// Canvas should consider insets for constraining? I think so...
newCanvasWidth = constrain(img.width, MIN_WINDOW_WIDTH - widthInsets, displayWidth - widthInsets);
newCanvasHeight = constrain(img.height, MIN_WINDOW_HEIGHT - heightInsets, displayHeight -20 - heightInsets);
// set canvas size to img size WITHOUT INSETS
setSize(newCanvasWidth, newCanvasHeight);
// set frame size to image + Insets size
frame.setSize(newFrameWidth, newFrameHeight);
//// for debuging
println(path);
println(" ");
print("imgW = " + img.width);
println(" imgH = " + img.height);
print("width+ins = " + widthInsets);
println(" height+ins = " + heightInsets);
print("nFrameW = " + newFrameWidth);
println(" nFrameH = " + newFrameHeight);
print("nCanvasw = " + newCanvasWidth);
println(" nCanvsH = " + newCanvasHeight);
println(" ------ ");
}
}
void mouseClicked()
{
img = null;
selectInput("select an image", "getImageAndResize" );
}