SORU
21 EYLÜL 2013, CUMARTESİ


Kullanıcı mükemmel bir daire çizin'In touch

Onlar kendi parmakları ile dokunmatik kullanıcı ekran üzerinde çizmek için izin veren bu uygulama projem var. Geri dönüş yolu egzersiz yaptığım gibi çok basit bir Uygulama. Küçük kuzenim bu Uygulama benim iPad ile onun parmak ile çizim işleri (Çocuk çizimleri: çember, aklına gelen her satır, vb) özgürlük aldı. Daireler çizmeye başladı ve sonra bana "(anladığım kadarıyla: bildiğimiz gibi çizilmiş bir Daire mükemmel yuvarlak olun," iyi bir daire yapmak istedi nasıl kararlı ekranda bizim parmak ile bir şey çizmek için çalışsak bir daire hiç bir daire olmalı gibi gerçekten gibi yuvarlak).

Yani benim soru şu ki, orada herhangi bir şekilde kod burada ilk tespit bir çizgi çizen kullanıcı formları bir daire oluşturur ve yaklaşık olarak aynı boyutta çember yaparak mükemmel yuvarlak ekranda. Düz değil, düz bir çizgi yapmak nasıl bir şey olduğunu, ama topluluk için oldukça Kuvars veya diğer yöntemler ile yapıyor hakkında gitmek nasıl bilmiyorum.

Benim akıl yürütme, başlangıç ve bitiş noktası satırın kullanıcı parmağını aslında bir daire çizmek için çalışıyordu aslında haklı asansörleri sonra ya da birbirine çapraz gerekir.

CEVAP
28 EYLÜL 2013, CUMARTESİ


Bazen gerçekten yararlı bazı zaman tekerleği yeniden icat geçirmek. Zaten fark etmiş olabilirsiniz daha fazlası var, ama o kadar da zor tüm bu karmaşıklık tanıtmadan basit, ama daha yararlı bir çözüm uygulamak için değil. (Lütfen biraz olgun kullanmak daha iyi ve kanıtlanmış ciddi bir amaç için kararlı olmak için beni yanlış anlamayın, çerçeve).

Benim ilk sonuçları sunmak ve onların arkasında basit ve anlaşılır fikrini açıkla o zaman.

enter image description here

Her birini analiz etmek ve karmaşık hesaplamaları yapmasına gerek yok ben uygulama göreceksiniz. Bu fikir bazı değerli meta bilgileri tespit edebilmektir. Örnek olarak tangent kullanacağım:

enter image description here

Sade ve basit bir desen, seçili şekli: tipik tanımlamak mümkün

enter image description here

Zor çember algılama mekanizması bu fikre dayanarak uygulamak için değil. Çalışan demo altına (Özür dilerim, hızlı ve biraz kirli bu örnek sağlamak için en hızlı yolu olarak Java kullanıyorum)

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.HeadlessException;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;

public class CircleGestureDemo extends JFrame implements MouseListener, MouseMotionListener {

    enum Type {
        RIGHT_DOWN,
        LEFT_DOWN,
        LEFT_UP,
        RIGHT_UP,
        UNDEFINED
    }

    private static final Type[] circleShape = {
        Type.RIGHT_DOWN,
        Type.LEFT_DOWN,
        Type.LEFT_UP,
        Type.RIGHT_UP};

    private boolean editing = false;
    private Point[] bounds;
    private Point last = new Point(0, 0);
    private List<Point> points = new ArrayList<>();

    public CircleGestureDemo() throws HeadlessException {
        super("Detect Circle");

        addMouseListener(this);
        addMouseMotionListener(this);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        setPreferredSize(new Dimension(800, 600));
        pack();
    }

    @Override
    public void paint(Graphics graphics) {
        Dimension d = getSize();
        Graphics2D g = (Graphics2D) graphics;

        super.paint(g);

        RenderingHints qualityHints = new RenderingHints(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        qualityHints.put(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
        g.setRenderingHints(qualityHints);

        g.setColor(Color.RED);
        if (cD == 0) {
            Point b = null;
            for (Point e : points) {
                if (null != b) {
                    g.drawLine(b.x, b.y, e.x, e.y);
                }
                b = e;
            }
        }else if (cD > 0){
            g.setColor(Color.BLUE);
            g.setStroke(new BasicStroke(3));
            g.drawOval(cX, cY, cD, cD);
        }else{
            g.drawString("Uknown",30,50);
        }
    }


    private Type getType(int dx, int dy) {
        Type result = Type.UNDEFINED;

        if (dx > 0 && dy < 0) {
            result = Type.RIGHT_DOWN;
        } else if (dx < 0 && dy < 0) {
            result = Type.LEFT_DOWN;
        } else if (dx < 0 && dy > 0) {
            result = Type.LEFT_UP;
        } else if (dx > 0 && dy > 0) {
            result = Type.RIGHT_UP;
        }

        return result;
    }

    private boolean isCircle(List<Point> points) {
        boolean result = false;
        Type[] shape = circleShape;
        Type[] detected = new Type[shape.length];
        bounds = new Point[shape.length];

        final int STEP = 5;

        int index = 0;        
        Point current = points.get(0);
        Type type = null;

        for (int i = STEP; i < points.size(); i  = STEP) {
            Point next = points.get(i);
            int dx = next.x - current.x;
            int dy = -(next.y - current.y);

            if(dx == 0 || dy == 0) {
                continue;
            }

            Type newType = getType(dx, dy);
            if(type == null || type != newType) {
                if(newType != shape[index]) {
                    break;
                }
                bounds[index] = current;
                detected[index  ] = newType;
            }
            type = newType;            
            current = next;

            if (index >= shape.length) {
                result = true;
                break;
            }
        }

        return result;
    }

    @Override
    public void mousePressed(MouseEvent e) {
        cD = 0;
        points.clear();
        editing = true;
    }

    private int cX;
    private int cY;
    private int cD;

    @Override
    public void mouseReleased(MouseEvent e) {
        editing = false;
        if(points.size() > 0) {
            if(isCircle(points)) {
                cX = bounds[0].x   Math.abs((bounds[2].x - bounds[0].x)/2);
                cY = bounds[0].y;
                cD = bounds[2].y - bounds[0].y;
                cX = cX - cD/2;

                System.out.println("circle");
            }else{
                cD = -1;
                System.out.println("unknown");
            }
            repaint();
        }
    }

    @Override
    public void mouseDragged(MouseEvent e) {
        Point newPoint = e.getPoint();
        if (editing && !last.equals(newPoint)) {
            points.add(newPoint);
            last = newPoint;
            repaint();
        }
    }

    @Override
    public void mouseMoved(MouseEvent e) {
    }

    @Override
    public void mouseEntered(MouseEvent e) {
    }

    @Override
    public void mouseExited(MouseEvent e) {
    }

    @Override
    public void mouseClicked(MouseEvent e) {
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                CircleGestureDemo t = new CircleGestureDemo();
                t.setVisible(true);
            }
        });
    }
}

Sadece bazı olayları gerekir ve koordinatları bu yana iOS üzerinde benzer davranış uygulamak için bir sorun olmamalıdır. Aşağıdaki gibi (example):

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    UITouch* touch = [[event allTouches] anyObject];
}

- (void)handleTouch:(UIEvent *)event {
    UITouch* touch = [[event allTouches] anyObject];
    CGPoint location = [touch locationInView:self];

}

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
    [self handleTouch: event];
}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
    [self handleTouch: event];    
}

Birkaç geliştirmeleri Olası.

Herhangi bir noktada başlar

Güncel gereksinim, aşağıdaki sadeleştirme nedeniyle: üst orta noktadan sonra bir çember çizmeye başlamak için

        if(type == null || type != newType) {
            if(newType != shape[index]) {
                break;
            }
            bounds[index] = current;
            detected[index  ] = newType;
        }

Lütfen index varsayılan değer kullanılır dikkat edin. Mevcut üzerinden basit bir arama "parçalar" şeklinde bir sınırlama kaldırır. Lütfen tam bir şekil tespit etmek için dairesel bir tampon kullanmanız gerekir not:

enter image description here

Saat yönünde ve saat yönünün tersine

Her iki modları desteklemek amacıyla önceki donanımla dairesel tampon ve her iki yönde arama kullanmanız gerekir:

enter image description here

Bir elips çizin

Zaten bounds dizideki ihtiyacınız olan her şeye sahipsiniz.

enter image description here

Sadece bu verileri kullanın:

cWidth = bounds[2].y - bounds[0].y;
cHeight = bounds[3].y - bounds[1].y;

Diğer hareketleri (isteğe bağlı)

Son olarak, size sadece düzgün dx (dy) diğer hareketleri desteklemek için sıfıra eşit olduğunda bir durumun üstesinden gelmek için gereken:

enter image description here

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • funbro1

    funbro1

    11 Aralık 2007
  • kamaniusilelis

    kamaniusilel

    10 HAZİRAN 2011
  • undrmyumbrellaa

    undrmyumbrel

    25 Temmuz 2012