대략적인 개념이기 때문에 실제 사용할 수 있는 나침반을 만들려면 다른 변수들도 반영니 되야 겠지만 가속도 센서(TYPE_ACCELEROMETER)자기장 센서(TYPE_MAGNETIC_FIELD)를 이용하여 단순한compass를 만들어보겠습니다구현 방법은 구글에서 이미 함수를 만들어서 제공을 하기 때문에 그걸 그대로 사용합니다. 사용되는 함수는 getRotationMatrix() getOrientation() 입니다.



1. 함수

 

1.1 getRotationMatrix


 public static boolean getRotationMatrix (float[] R,

                float[] I,

                float[] gravity,

                float[] geomagnetic)


Type

 Parameter

 설명

 float[9]

 R

 회전 매트릭스 (Rotation matrix)

 float[9]

 I

 경사도 매트릭스 (Inclination matrix)

 float[3]

 gravity

 장치 좌표계의 gravity vector(TYPE_ACCELEROMETER)

 float[3]

 geomagnetic

 장치 좌표계의 geomagnetic vector(TYPE_MAGNETIC_FIELD)


getRotationMatrix()는 경사도와 회전 매트릭스를 구하는 함수로 지구에 대한 세계 좌표계(World Coordinate System)를 기준으로 핸드폰 장치의 좌표계의 변화하는 값을 구합니다세계 좌표계에서 서로 직교하는 3개의 축은

x : 지표면에 접하는 동쪽 방향의 벡터

y : 지표면에 접하는 북극 방향의 벡터

z : 지표면과 직각을 이루는 상공을 향하는 벡터

으로 설명 할 수 있습니다구글에서 설명하는 그림을 참고하면 아래와 같습니다.


android_compass


나침반을 만들 때에는 경사도 매트릭스를 사용하지 않습니다.


2.2 getOrientation


getOrientation() 함수는 rotation matrix를 이용하여 장치의 방향을 구하는 함수입니다. getRotationMatrix() 함수를 통해 구한 첫 번째 값인 회전 매트릭스를 사용해서 방향을 구할 수 있습니다.


public static float[] getOrientation (float[] R,

                float[] values)


Parameter

 설명

 R

 otation matrix : getRotationMatrix(float[], float[], float[], float[])

 values

 float[3] :

values[0]: Azimuth. z축에 대한 회전 방위각으로 이게 필요하죠.

values[1]: Pitch. x축에 대한 회전 방위각

values[2]: Roll. y축에 대한 회전 방위각


설명에도 기술 하였지만 getRotationMatrix()에서 회전 매트릭스 (Rotation matrix)를 구하여 getOrientation()에 입력하면 values[0] (Azimuth : z축에 대한 회전 방위각) 구하게 됩니다 값이 바로 북을 향하는 각도가 됩니다.

 

 

2. 프로젝트 생성

 

CompassTest 라는 이름으로 프로젝트를 생성 합니다.


android_compass


Activityempty로 선택합니다.


android_compass


나머지는 그냥 기본 설정 값으로 놓고 Next 버튼을 클릭 합니다.


3. 코딩

 

3.1 layout

 

구해진 회전각을 출력 할 수 있는 TextView를 하나 생성하고 나침반 이미지를 위해서 ImageView를 추가 합니다.


<TextView
    android:id="@+id/DegreeTV"
    android:layout_width="wrap_content"
    android:layout_height="18dp"
    android:layout_marginBottom="8dp"
    android:layout_marginTop="8dp"
    android:text="Heading : 0.0"
    app:layout_constraintBottom_toTopOf="@+id/pointer"
    app:layout_constraintTop_toTopOf="parent"
    app:layout_constraintVertical_bias="0.027"
    tools:layout_editor_absoluteX="127dp" />

<ImageView
    android:id="@+id/pointer"
    android:layout_width="match_parent"
    android:layout_height="437dp"
    android:src="@drawable/compass_icon"
    tools:layout_editor_absoluteX="0dp"
    tools:layout_editor_absoluteY="56dp" />


이미지는 인터넷에서 무료 이미지를 하나 줏어왔습니다. 배경이 투명이 아니라 돌아갈때 커다란네모가 돌면서 글씨를 가리는 군요전에 작업한 투명이미지 만들기를 보면서 수정했습니다.


[Pixlr] Adobe Photoshop 없이 무료 투명 배경 이미지 만들기


android_compass


3.2 방위각 구하기


getRotationMatrix() 함수를 이용하여 회전 매트릭스(mR)를 구합니다.


SensorManager.getRotationMatrix(mR, null, mLastAccelerometer, mLastMagnetometer);


mR을 이용하여 getOrientation()에서 방위각을 구합니다.


SensorManager.getOrientation(mR, mOrientation);


3.3 이미지 회전


z 축의 회전각으로 RotateAnimation()을 이용하여 이미지를 회전 시킵니다.

RotateAnimation ra = new RotateAnimation(
mCurrentDegree,
-azimuthinDegress,
Animation.RELATIVE_TO_SELF, 0.5f,
Animation.RELATIVE_TO_SELF, 0.5f
);

이미지 회전 설명은 [Android] 안드로이드 RotateAnimation 함수 이용 이미지 회전 을 참조 하세요.



3. 결과


android_compass


 

4. 전체 소스

 

activity_main.xml


<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/DegreeTV"
        android:layout_width="wrap_content"
        android:layout_height="18dp"
        android:layout_marginBottom="8dp"
        android:layout_marginTop="8dp"
        android:text="Heading : 0.0"
        app:layout_constraintBottom_toTopOf="@+id/pointer"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.027"
        tools:layout_editor_absoluteX="127dp" />

    <ImageView
        android:id="@+id/pointer"
        android:layout_width="match_parent"
        android:layout_height="437dp"
        android:src="@drawable/compass_icon"
        tools:layout_editor_absoluteX="0dp"
        tools:layout_editor_absoluteY="56dp" />
</android.support.constraint.ConstraintLayout>


MainActivity.java


package copycoding.tistory.com.compasstest;

import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.animation.Animation;
import android.view.animation.RotateAnimation;
import android.widget.ImageView;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity implements SensorEventListener {

    private ImageView mPointer;
    private SensorManager mSensorManager;
    private Sensor mAccelerometer;
    private Sensor mMagnetometer;
    private float[] mLastAccelerometer = new float[3];
    private float[] mLastMagnetometer = new float[3];
    private boolean mLastAccelerometerSet = false;
    private boolean mLastMagnetometerSet = false;
    private float[] mR = new float[9];
    private float[] mOrientation = new float[3];
    private float mCurrentDegree = 0f;
    TextView DegreeTV;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mSensorManager = (SensorManager)getSystemService(SENSOR_SERVICE);
        mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
        mMagnetometer = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
        mPointer = (ImageView)findViewById(R.id.pointer);
        DegreeTV = (TextView)findViewById(R.id.DegreeTV);

    }

    @Override
    protected void onResume() {
        super.onResume();
        mSensorManager.registerListener(this, mAccelerometer, SensorManager.SENSOR_DELAY_GAME);
        mSensorManager.registerListener(this, mMagnetometer, SensorManager.SENSOR_DELAY_GAME);
    }

    @Override
    protected void onPause() {
        super.onPause();
        mSensorManager.unregisterListener(this, mAccelerometer);
        mSensorManager.unregisterListener(this, mMagnetometer);
    }

    @Override
    public void onSensorChanged(SensorEvent event) {
        if(event.sensor == mAccelerometer) {
            System.arraycopy(event.values, 0, mLastAccelerometer, 0, event.values.length);
            mLastAccelerometerSet = true;
        } else if(event.sensor == mMagnetometer) {
            System.arraycopy(event.values, 0, mLastMagnetometer, 0, event.values.length);
            mLastMagnetometerSet = true;
        }
        if(mLastAccelerometerSet && mLastMagnetometerSet) {
            SensorManager.getRotationMatrix(mR, null, mLastAccelerometer, mLastMagnetometer);
            float azimuthinDegress  = (int) ( Math.toDegrees( SensorManager.getOrientation( mR, mOrientation)[0] ) + 360 ) % 360;
            DegreeTV.setText("Heading : " + Float.toString(azimuthinDegress) + " degrees");
            RotateAnimation ra = new RotateAnimation(
                    mCurrentDegree,
                    -azimuthinDegress,
                    Animation.RELATIVE_TO_SELF, 0.5f,
                    Animation.RELATIVE_TO_SELF, 0.5f
            );
            ra.setDuration(250);
            ra.setFillAfter(true);
            mPointer.startAnimation(ra);
            mCurrentDegree = -azimuthinDegress;
        }
    }

    @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy) {

    }

}



버전마다 설치화면이 조금씩 변경되고 있습니다. 자신이 가지고 있는 rufus 파일의 버전을 확인하고 작업을 진행 하시기 바랍니다. 작업 방법은 거의 차이가 없습니다.

최신 버전은 rufus 사이트에 가시면 받을 수 있고 저는 무설치(Portable) 버전을 추천 합니다. 제가 작업 중에 받은 파일을 첨부 합니다이 파일은 GNU GPL v3에 준하여 배포 합니다.

 

rufus-3.4p.exe

 

사이트에서 직접 다운로드 하시려면 아래 주소로 이동하시고 그림에 나와 있는 곳에서 원하는 형태의 파일을 다운로드 받으시면 됩니다.


https://rufus.ie/


windows_install_usb_Rufus


준비물


rufus 실행 파일

 - Windows 7 또는 10 iso 파일

 - 포맷해도 되는 USB 메모리 8GB 정도 용량


준비 되었다면 설치 USB 만들기를 시작 하면 됩니다.

USB 메모리를 미리 컴퓨터에 연결 합니다.

rufus-x.x.exe 파일을 실행 합니다.


windows_install_usb_Rufus


장치에 연결한 USB가 나타나는데 만일 자료가 들어있는 다른 USB가 있다면 혼동을 일으켜 포맷될 수 있으니 제거를 하는게 좋습니다선택 버튼을 눌러 운영체제 iso 파일을 선택 합니다.


windows_install_usb_Rufus


부트선택에 iso 파일명이 나타나는걸 확인하고 USB 볼륨 레이블을 적당한 이름으로 수정 합니다.

설정이 완료 되었으니 시작 버튼을 클릭하기만 하면 됩니다.

 

모든걸 기본값으로 하는데 파티션 방식만 설명 드리면

- MBR(Master Boot Recorder) : 예전 방식. HDD 2TB 까지 인식. 4개 파티션 가능

- GPT(GUID Partition Table) : HDD 8ZB 까지 인식. 128개 파티션 가능.

 

파일 시스템은 USB에 2GB이상 되는 파일을 저장 하려면 NTFS로 변경하고 작업을 진행 합니다.


설치를 하기 전에 USB에 있는 데이터가 모두 삭제 된다는 안내를 하게 됩니다작업하려는 USB가 맞는지 다시 한번 잘 보고 진행을 합니다.


windows_install_usb_Rufus


확인 버튼을 클릭하면 작업이 시작 됩니다.


windows_install_usb_Rufus


설치 USB 생성이 완료되면 특별한 완료 메시지가 나오지 않습니다.  장치 명이 설정한 값으로 변경이 되고 프로그래스 바가 완료로 표시 되면 완료되었구나 하시면 됩니다.


windows_install_usb_Rufus


이제 USB를 사용하여 Windows 7을 설치 할 수 있습니다그런데 USB 용량이 16BG인데 윈도우즈 설치로는 4GB 정도 사용하였습니다.


windows_install_usb_Rufus


10GB정도 여유가 있으니 Win7(G) 폴더로 이동해서 디렉토리를 생성하고 자료들을 저장해서 USB 본연의 데이터 저장 기능으로도 사용 합니다


windows_install_usb_Rufus


저는 OS 설치 후 필요한 util들을 저장해놓고 설치하자 마자 바로 장치 드라이버나 필요한 프로그램들을 설치 합니다.



이미지를 회전시키기 위한 RotateAnimation() 함수 입니다.  parameter2, 4개 또는 6개를 포함한 함수를 제공 하는데 회전 중심을 어디로 어떻게 설정 하는가에 따라 선택해서 사용 합니다.  



1. RotateAnimation() 함수

 

여기서는 중앙을 중심으로 회전을 시키는 parameter 6개의 함수를 사용 합니다.

 

public RotateAnimation (float fromDegrees,

                float toDegrees,

                int pivotXType,

                float pivotXValue,

                int pivotYType,

                float pivotYValue)


Type

 Parameter

 설명

 float

 fromDegrees

 회전을 시작하는 각도

 float

 toDegrees

 회전을 종료하는 각도

 int

 pivotXType

 x축 설정

Animation.ABSOLUTE,

Animation.RELATIVE_TO_SELF,

Animation.RELATIVE_TO_PARENT

 float

 pivotXValue

 x축 위치. 0은 좌측 끝, 1.0은 우측 끝, 0.5는 중앙

 int

 pivotYType

 y축 설정.

Animation.ABSOLUTE,

Animation.RELATIVE_TO_SELF,

Animation.RELATIVE_TO_PARENT.

 float

 pivotYValue

 y축 위치. 0은 상단 끝, 1.0은 하단 끝, 0.5는 중앙



2. layout

 

회전에 사용할 이미지를 대충 잘라서 res/drawable에 추가해 줍니다.


RotateAnimation


왼쪽 회전, 오른쪽 회전을 위한 버튼 2개를 추가하고 회전시킬 이미지를 하단에 추가 합니다.

<Button
    android:id="@+id/btn_left"
    android:text="left"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_marginLeft="10dp"
    android:layout_marginTop="10dp"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintTop_toTopOf="parent" />

<Button
    android:id="@+id/btn_right"
    android:text="right"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_marginLeft="250dp"
    android:layout_marginTop="10dp"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintTop_toTopOf="parent" />

<ImageView
    android:id="@+id/rotImage"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:src="@drawable/rotateimage"
    android:layout_marginTop="100dp"
    app:layout_constraintTop_toTopOf="parent"/>

이런 모양이 되겠죠?


RotateAnimation



3. 구현

 

3.1 버튼 기능 구현


이미지 정의와 버튼 클릭 이벤트를 이용하여 기능을 구현 합니다. 버튼을 클릭 하면 10도씩 시계방향, 반시계 방향으로 회전 하도록 testRotation() 함수를 호출하여 줍니다.

Button btnLeft = (Button)findViewById(R.id.btn_left);
Button btnRight = (Button)findViewById(R.id.btn_right);

mImageView =  (ImageView)findViewById(R.id.rotImage);

btnLeft.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        testRotation(nBefore - 10);
        Toast.makeText(MainActivity.this, "Left", Toast.LENGTH_SHORT).show();
    }
});

btnRight.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        testRotation(nBefore + 10);
        Toast.makeText(MainActivity.this, "Right", Toast.LENGTH_SHORT).show();
    }
});

3.2 이미지 회전

 

받아온 값을 RotateAnimation()에 대입하여 이미지를 회전 시켜 줍니다.

public void testRotation(int i) {
    RotateAnimation ra = new RotateAnimation(
            nBefore,
            i,
            Animation.RELATIVE_TO_SELF, 0.5f,
            Animation.RELATIVE_TO_SELF, 0.5f
    );
    ra.setDuration(250);
    ra.setFillAfter(true);
    mImageView.startAnimation(ra);
    nBefore = i;
}


4. 프로젝트 생성


4.1 프로젝트 만들기

 

RotateAnimation 으로 프로젝트를 생성합니다.


RotateAnimation


Activityempty를 선택해 줍니다.


RotateAnimation

 

나머지는 그냥 Next를 눌러줍니다.

 

 

4.2 전체 소스코드

 

- activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <Button
        android:id="@+id/btn_left"
        android:text="left"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="10dp"
        android:layout_marginTop="10dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/btn_right"
        android:text="right"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="250dp"
        android:layout_marginTop="10dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <ImageView
        android:id="@+id/rotImage"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:src="@drawable/rotateimage"
        android:layout_marginTop="100dp"
        app:layout_constraintTop_toTopOf="parent"/>

</android.support.constraint.ConstraintLayout>


- MainActivity.java

package copycoding.tistory.com.rotateanimation;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.RotateAnimation;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {

    private ImageView mImageView;
    private int nBefore = 0;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Button btnLeft = (Button)findViewById(R.id.btn_left);
        Button btnRight = (Button)findViewById(R.id.btn_right);

        mImageView =  (ImageView)findViewById(R.id.rotImage);

        btnLeft.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                testRotation(nBefore - 10);
                Toast.makeText(MainActivity.this, "Left", Toast.LENGTH_SHORT).show();
            }
        });

        btnRight.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                testRotation(nBefore + 10);
                Toast.makeText(MainActivity.this, "Right", Toast.LENGTH_SHORT).show();
            }
        });

    }

    public void testRotation(int i) {
        RotateAnimation ra = new RotateAnimation(
                nBefore,
                i,
                Animation.RELATIVE_TO_SELF, 0.5f,
                Animation.RELATIVE_TO_SELF, 0.5f
        );
        ra.setDuration(250);
        ra.setFillAfter(true);
        mImageView.startAnimation(ra);
        nBefore = i;
    }
}


5. 결과

 

상단에 있는 Left, Right 버튼을 누르면 이미지가 10도씩 회전합니다.


RotateAnimation



어느날 갑자기 sch.exe의 작동이 중지되었습니다. 라는 팝업 창이 나타나기 시작했습니다.


windows_sch_exe


무엇 때문인지 찾아보기 위해 작업 관리자를 확인해 봅니다윈도우 하단 작업표시줄마우스를 대고 우측 버튼을 클릭해서 작업 관리자 시작 메뉴를 선택 합니다.


windows_sch_exe


작업 관리자에서 프로세스 탭으로 들어가 sch.exe를 찾아 봅니다.  sch.exe가 보이면 마우스를 대고 우측  버튼을 클릭하고 팝업 메뉴에서 파일 위치 열기를 선택 합니다.대부분 모르는 프로그램 위치는 이런식으로 하면 찾을 수 있습니다.


windows_sch_exe


C:\Program Files (x86)\CacaoEncoder 이곳에 있었네요.  카카오인코더(CacaoEncoder)라고 얼마전에 음성파일을 변환하기 위해 설치한 유틸인데 언어팩과 충돌을 한다는 사람도 있고 가상화폐 채굴을 하는데 사용 된다는 사람도 있고, 확인할 방법은 없고 그냥 삭제 하려고 합니다.


windows_sch_exe


안전하게 제어판에 들어가서 삭제를 시도 합니다.


windows_sch_exe


제어판에서 프로그램 제거를 선택 합니다.


windows_sch_exe


리스트에서 CacaoEncoder를 찾아 더블클릭 합니다.


windows_sch_exe


삭제를 진행하고 다시 컴퓨터를 부팅 합니다.

이게 뭔일 입니까그대로 오류가 나옵니다. 제어판에는 사라졌는데 팝업과 디렉토리는 그대로 존재 하고 있습니다.


windows_sch_exe


CacaoEncoder 디렉토리에 있는 uninstaller를 찾아서 삭제를 해봅니다.


windows_sch_exe


windows_sch_exe


windows_sch_exe


windows_sch_exe


제거가 되었습니다.

 

카카오엔코더 디렉토리로 이동해서 디렉토리에 남은 파일들도 모두 삭제를 합니다.


windows_sch_exe


다시 부팅을 하면 이제 sch.exe의 작동이 중지되었습니다. 라는 팝업 창은 나타나지 않습니다.



1···88899091929394···119

+ Recent posts