Как использовать холст Android для рисования прямоугольника только с верхним левым и верхним правым углами?

Я нашел функцию для прямоугольников, в которой все 4 угла закруглены, но я хочу, чтобы только 2 верхних угла были круглыми. Что я могу сделать?

canvas.drawRoundRect(new RectF(0, 100, 100, 300), 6, 6, paint);

person virsir    schedule 05.05.2011    source источник
comment
Разве вы не можете просто нарисовать один прямоугольник со скругленными углами, а затем обычный прямоугольник в нижней половине (заменив закругленные углы обычными?)   -  person interstar    schedule 05.02.2021


Ответы (15)


Вы можете нарисовать этот фрагмент за фрагментом, используя функции drawLine() и drawArc() из файла Canvas.

person Zelimir    schedule 05.05.2011
comment
Но метод drawArc() был введен в API 21, есть ли какой-то другой метод, где я могу сделать то же самое? Как нарисовать дугу? - person Giridhar Karnik; 23.06.2015
comment
Существует еще одна версия drawArc(), доступная начиная с API 1. - person JohnyTex; 21.01.2021

Используйте путь. Преимущество заключается в том, что он работает с API менее 21 (Arc также ограничен таким образом, поэтому я квад). Это проблема, потому что не у всех есть Lollipop. Однако вы можете указать RectF и установить значения с этим и использовать дугу обратно в API 1, но тогда вы не сможете использовать статику (без объявления нового объекта для создания объекта).

Рисование закругленного прямоугольника:

    path.moveTo(right, top + ry);
    path.rQuadTo(0, -ry, -rx, -ry);
    path.rLineTo(-(width - (2 * rx)), 0);
    path.rQuadTo(-rx, 0, -rx, ry);
    path.rLineTo(0, (height - (2 * ry)));
    path.rQuadTo(0, ry, rx, ry);
    path.rLineTo((width - (2 * rx)), 0);
    path.rQuadTo(rx, 0, rx, -ry);
    path.rLineTo(0, -(height - (2 * ry)));
    path.close();

Как полноценная функция:

static public Path RoundedRect(float left, float top, float right, float bottom, float rx, float ry, boolean conformToOriginalPost) {
    Path path = new Path();
    if (rx < 0) rx = 0;
    if (ry < 0) ry = 0;
    float width = right - left;
    float height = bottom - top;
    if (rx > width/2) rx = width/2;
    if (ry > height/2) ry = height/2;
    float widthMinusCorners = (width - (2 * rx));
    float heightMinusCorners = (height - (2 * ry));

    path.moveTo(right, top + ry);
    path.rQuadTo(0, -ry, -rx, -ry);//top-right corner
    path.rLineTo(-widthMinusCorners, 0);
    path.rQuadTo(-rx, 0, -rx, ry); //top-left corner
    path.rLineTo(0, heightMinusCorners);

    if (conformToOriginalPost) {
        path.rLineTo(0, ry);
        path.rLineTo(width, 0);
        path.rLineTo(0, -ry);
    }
    else {
        path.rQuadTo(0, ry, rx, ry);//bottom-left corner
        path.rLineTo(widthMinusCorners, 0);
        path.rQuadTo(rx, 0, rx, -ry); //bottom-right corner
    }

    path.rLineTo(0, -heightMinusCorners);

    path.close();//Given close, last lineto can be removed.

    return path;
}

Вы бы хотели выровнять все до этих угловых битов, а не четырехугольник через них. Это то, что делает установка true для конформтооригиналпост. Просто линия до контрольной точки там.

Если вы хотите сделать все это, но не заботитесь о вещах, предшествующих Lollipop, и настоятельно настаиваете на том, что если ваши rx и ry достаточно высоки, он должен нарисовать круг.

@TargetApi(Build.VERSION_CODES.LOLLIPOP)
static public Path RoundedRect(float left, float top, float right, float bottom, float rx, float ry, boolean conformToOriginalPost) {
    Path path = new Path();
    if (rx < 0) rx = 0;
    if (ry < 0) ry = 0;
    float width = right - left;
    float height = bottom - top;
    if (rx > width/2) rx = width/2;
    if (ry > height/2) ry = height/2;
    float widthMinusCorners = (width - (2 * rx));
    float heightMinusCorners = (height - (2 * ry));

    path.moveTo(right, top + ry);
    path.arcTo(right - 2*rx, top, right, top + 2*ry, 0, -90, false); //top-right-corner
    path.rLineTo(-widthMinusCorners, 0);
    path.arcTo(left, top, left + 2*rx, top + 2*ry, 270, -90, false);//top-left corner.
    path.rLineTo(0, heightMinusCorners);
    if (conformToOriginalPost) {
        path.rLineTo(0, ry);
        path.rLineTo(width, 0);
        path.rLineTo(0, -ry);
    }
    else {
        path.arcTo(left, bottom - 2 * ry, left + 2 * rx, bottom, 180, -90, false); //bottom-left corner
        path.rLineTo(widthMinusCorners, 0);
        path.arcTo(right - 2 * rx, bottom - 2 * ry, right, bottom, 90, -90, false); //bottom-right corner
    }

    path.rLineTo(0, -heightMinusCorners);

    path.close();//Given close, last lineto can be removed.
    return path;
}

Таким образом, конформтооригиналпост фактически рисует закругленный прямоугольник без округления двух нижних битов.

дуговое изображение

person Tatarize    schedule 22.02.2015
comment
На мой взгляд, я считаю, что функции относительного пути намного лучше, потому что вам нужно беспокоиться только об одной точке, в которой будет нарисован путь. - person TheRealChx101; 21.10.2015
comment
@ chx101 chx101 да, хорошо, переделал это как относительное и начал с кривой, чтобы close () могла покрыть линию. - person Tatarize; 22.10.2015
comment
@Tatrize Вау, ты все переписал, да? - person TheRealChx101; 23.10.2015
comment
Там есть части исходного ответа. В основном я в основном отказался от исходного кода и фактически полностью предоставил фактически запрошенный ответ. Но это было больше потому, что дуги были грубыми, и поэтому мне пришлось изменить направление, а затем переупорядочить их, поместив последние две внизу, чтобы их можно было легко удалить. Затем я проверил W3 Rect на предмет типичной стандартной реализации того, что делать для различных значений RX, RY (выбрал 0, если отрицательный, а не выдавал ошибку). w3.org/TR/SVG/shapes.html#RectElement - person Tatarize; 23.10.2015
comment
И мне приходит в голову, что даже без дуги окружности можно было бы сделать гораздо более круглую кривую с помощью квадратичного Безье, а не четырехугольника. А именно, вы должны сделать контрольные точки в 1, c и c, 1 (относительно квадранта), где C = (4/3) * tan (pi / 8), или сделать слегка улучшенное значение Спенсера Мортенсена для C. Квадрат с контрольной точкой на углу работает, но на самом деле это немного наивно. - person Tatarize; 03.01.2016
comment
Да, конечно верно.. По крайней мере, одно из этих слов должно быть кубическим. с квадроциклом Безье, а не с квадроциклом, и хотя, безусловно, есть способ сделать это с квадроциклом и все еще быть более похожим на дугу (хотя я никогда не видел попытки), лучшее кубическое решение уравнивает ошибка вида: spencermortensen.com/articles/bezier-circle - person Tatarize; 01.08.2016
comment
Я удосужился ее решить, ответ оказался c = 2*cos(pi/4)-1/2 или 0,91421356237. Таким образом, вместо четырехугольника в угол, как я делаю здесь, если мы вчетвером в точку (0,91421356237 rx, 0,91421356237 ry), а не (1 rx, 1 ry), мы получим лучшее из обоих миров. Почти минимальная ошибка на кривой и только с использованием квадроцикла. - person Tatarize; 02.08.2016
comment
Таким образом, для квадранта I наша кривая будет q(0,1, c, 1 - c, 1,0), где c = 2*cos(pi/4)-1/2 или 0,91421356237. - person Tatarize; 02.08.2016
comment
Когда я хочу нарисовать круг с помощью Quad, он не должен рисовать чистый круг см. это, поэтому я буду использовать дугу, спасибо за этот метод. - person S Kumar; 14.05.2020
comment
@SKumar на этом изображении явно видно, что квадроцикл полностью входит в угол и выезжает слишком далеко, если вы выходите только на 0,91% пути, вы получаете гораздо более круговой путь. Но да, используйте дуги, если хотите настоящий круг. Но ошибка снижается до нескольких процентов, если вы правильно подделываете ее. - person Tatarize; 15.05.2020

Я бы нарисовал два прямоугольника:

canvas.drawRect(new RectF(0, 110, 100, 290), paint);
canvas.drawRoundRect(new RectF(0, 100, 100, 200), 6, 6, paint);

Или что-то в этом роде, вы просто накладываете их друг на друга, чтобы верхние углы были круглыми. Предпочтительно, вы должны написать метод для этого

person Durza007    schedule 05.05.2011
comment
Как насчет того, что мне нужно установить альфу для всего прямоугольника, раздел перекрытия будет иметь другое значение альфы с другими - person virsir; 05.05.2011
comment
@V.Kalyuzhnyu сигнатура метода, используемая в ответе, доступна с API 1, вы должны говорить о drawRoundRect(float left, float top, float right, float bottom, float rx, float ry, Paint paint), который доступен из API 21. - person Mokkun; 01.05.2017
comment
@virsir paint.setColor(Color.argb(200, 0,0,0)); установит альфу для краски. - person niek tuytel; 28.11.2020

Для API 21 и выше в класс Path добавлен новый метод addRoundRect(), который вы можете использовать следующим образом.

corners = new float[]{
    80, 80,        // Top left radius in px
    80, 80,        // Top right radius in px
    0, 0,          // Bottom right radius in px
    0, 0           // Bottom left radius in px
};

final Path path = new Path();
path.addRoundRect(rect, corners, Path.Direction.CW);
canvas.drawPath(path, mPaint);

в Котлине

val corners = floatArrayOf(
    80f, 80f,   // Top left radius in px
    80f, 80f,   // Top right radius in px
    0f, 0f,     // Bottom right radius in px
    0f, 0f      // Bottom left radius in px
)

val path = Path()
path.addRoundRect(rect, corners, Path.Direction.CW)
canvas.drawPath(path, mPaint)
person Saran Sankaran    schedule 21.05.2019
comment
ЭТО СВЯТОЙ ГРААЛЬ, КОТОРЫЙ Я ИСКАЛА! Спасибо чувак! - person Starwave; 20.09.2020
comment
Правильное решение - person metodieva; 08.12.2020

Я изменил этот ответ, чтобы вы могли указать, какой угол вы хотите сделать круглым, а какой — острым. также работает на pre-lolipop

Usage Example:

только верхний правый и нижний правый углы закруглены

 Path path = RoundedRect(0, 0, fwidth , fheight , 5,5,
                     false, true, true, false);
 canvas.drawPath(path,myPaint);

Круглый прямоугольник:

    public static Path RoundedRect(
            float left, float top, float right, float bottom, float rx, float ry,
               boolean tl, boolean tr, boolean br, boolean bl
    ){
        Path path = new Path();
        if (rx < 0) rx = 0;
        if (ry < 0) ry = 0;
        float width = right - left;
        float height = bottom - top;
        if (rx > width / 2) rx = width / 2;
        if (ry > height / 2) ry = height / 2;
        float widthMinusCorners = (width - (2 * rx));
        float heightMinusCorners = (height - (2 * ry));

        path.moveTo(right, top + ry);
        if (tr)
            path.rQuadTo(0, -ry, -rx, -ry);//top-right corner
        else{
            path.rLineTo(0, -ry);
            path.rLineTo(-rx,0);
        }
        path.rLineTo(-widthMinusCorners, 0);
        if (tl)
            path.rQuadTo(-rx, 0, -rx, ry); //top-left corner
        else{
            path.rLineTo(-rx, 0);
            path.rLineTo(0,ry);
        }
        path.rLineTo(0, heightMinusCorners);

        if (bl)
            path.rQuadTo(0, ry, rx, ry);//bottom-left corner
        else{
            path.rLineTo(0, ry);
            path.rLineTo(rx,0);
        }

        path.rLineTo(widthMinusCorners, 0);
        if (br)
            path.rQuadTo(rx, 0, rx, -ry); //bottom-right corner
        else{
            path.rLineTo(rx,0);
            path.rLineTo(0, -ry);
        }

        path.rLineTo(0, -heightMinusCorners);

        path.close();//Given close, last lineto can be removed.

        return path;
    }
person Moh Mah    schedule 27.02.2016
comment
Вы должны исправить мой ответ там с правильной дугой Безье, приближающей углы. spencermortensen.com/articles/bezier-circle И конвертируйте, используя побитовую вещь в стиле C для углов, а не кучу логических значений. static final int SHARP_TOP_RIGHT = 0b0001, static final int SHARP_TOP_LEFT = 0b0010; -- тогда вы можете назвать это getRoundRect(0, 0, fwidth, fheight, 5, 5, SHARP_TOP_LEFT | SHARP_BOTTOM_LEFT); с ifs (if ((SHARP_TOP_LEFT & angleflag) == 0) ... ; также вспомогательная функция, которая, если она опущена, вызывает ее с 0. Таким образом, RoundRect (l, tl, r, b, rx, ry) работает нормально. Все статические финальные. - person Tatarize; 17.04.2016
comment
Идеально! Это было то, что я искал.! Спасибо дружище! - person Adnan; 09.06.2016
comment
Я не могу отблагодарить вас достаточно! Это потрясающе! Вы только что сэкономили мне много часов! СПАСИБО! - person Nick; 29.02.2020
comment
Большое спасибо, я использую это перед размытием вида следующим образом: mBottomRightCorner, mBottomLeftCorner); холст.клиппуть(клиппуть); super.onDraw (холст); DrawBlurredBitmap (холст, mBlurredBitmap, mOverlayColor); } - person Ho Luong; 13.08.2020

Простая вспомогательная функция, написанная на Kotlin.

private fun Canvas.drawTopRoundRect(rect: RectF, paint: Paint, radius: Float) {
    // Step 1. Draw rect with rounded corners.
    drawRoundRect(rect, radius, radius, paint)

    // Step 2. Draw simple rect with reduced height,
    // so it wont cover top rounded corners.
    drawRect(
            rect.left,
            rect.top + radius,
            rect.right,
            rect.bottom,
            paint
    )
}

Использование:

canvas.drawTopRoundRect(rect, paint, radius)
person Vadim Akhmerov    schedule 05.11.2017
comment
он будет перекрываться, и цвет альфа будет другим - person Jemshit Iskenderov; 10.04.2018
comment
drawRoundRect() требует уровня API 21. - person Swathi; 27.02.2020

вы можете легко добиться этого, используя Path:

val radiusArr = floatArrayOf(
    15f, 15f,
    15f, 15f,
    0f, 0f,
    0f, 0f
)
val myPath = Path()
myPath.addRoundRect(
    RectF(0f, 0f, 400f, 400f),
    radiusArr,
    Path.Direction.CW
)

canvas.drawPath(myPath, paint)
person Hashem Mousavi    schedule 16.12.2019

Я достиг этого, выполнив следующие шаги.

Это необходимые условия для того, чтобы прямоугольник со скругленными углами выглядел аккуратно.

  • Радиус краев должен быть равен (высота прямоугольника / 2). Это связано с тем, что если его значение отличается, то место, где кривая встречается с прямой линией прямоугольника, не будет

Далее идут шаги по рисованию прямоугольника со скругленными углами.

  • Сначала рисуем по 2 круга слева и справа, радиус = высота прямоугольника / 2

  • Затем мы рисуем прямоугольник между этими кругами, чтобы получить желаемый прямоугольник со скругленными углами.

Я публикую код ниже

private void drawRoundedRect(Canvas canvas, float left, float top, float right, float bottom) {
    float radius = getHeight() / 2;
    canvas.drawCircle(radius, radius, radius, mainPaint);
    canvas.drawCircle(right - radius, radius, radius, mainPaint);
    canvas.drawRect(left + radius, top, right - radius, bottom, mainPaint);
}

Теперь это приводит к действительно красивому прямоугольнику со скругленными углами, как показано нижевведите здесь описание изображения

person Bhargav    schedule 13.05.2016

Один из простых и эффективных способов нарисовать сплошную сторону — это использовать отсечение — прямоугольное отсечение практически бесплатно и требует гораздо меньше кода для написания, чем пользовательский путь.

Если мне нужен прямоугольник размером 300x300 с верхним левым и правым краями, округленными на 50 пикселей, вы можете сделать:

canvas.save();
canvas.clipRect(0, 0, 300, 300);
canvas.drawRoundRect(new RectF(0, 0, 300, 350), 50, 50, paint);
canvas.restore();

Этот подход будет работать только для скругления на 2 или 3 соседних углах, поэтому он немного менее настраиваемый, чем подход, основанный на пути, но использование скругленных прямоугольников более эффективно, поскольку drawRoundRect() полностью аппаратно ускорен (то есть тесселяция в треугольники) в то время как drawPath() всегда возвращается к программному рендерингу (программное обеспечение рисует растровое изображение пути и загружает его для кэширования на GPU).

Не большая проблема с производительностью для небольшого нечастого рисования, но если вы анимируете пути, стоимость программного отрисовки может увеличить время кадра и увеличить вероятность пропуска кадров. Маска пути также требует памяти.

Если вы хотите использовать подход на основе пути, я бы рекомендовал использовать GradientDrawable для упрощения строк кода (при условии, что вам не нужно устанавливать собственный шейдер, например, для рисования растрового изображения).

mGradient.setBounds(0, 0, 300, 300);
mGradient.setCornerRadii(new int[] {50,50, 50,50, 0,0, 0,0});

С помощью GradientDrawable#setCornerRadii() , вы можете задать любому углу любую округлость и разумно анимировать между состояниями.

person Chris Craik    schedule 22.08.2017
comment
отсечение не сглаживается; проблема с вырезанием круглого материала - person urSus; 13.05.2019

Это старый вопрос, однако я хотел добавить свое решение, потому что оно использует собственный SDK без большого количества пользовательского кода или хакерского рисования. Это решение поддерживается вплоть до API 1.

Способ сделать это правильно - создать путь (как упоминалось в других ответах), однако предыдущие ответы, похоже, упускают из виду вызов функции addRoundedRect, который принимает радиусы для каждого угла.

Переменные

private val path = Path()
private val paint = Paint()

Настройка Paint

paint.color = Color.RED
paint.style = Paint.Style.FILL

Обновить путь с изменением размера

Вызовите это где-нибудь, кроме onDraw, например, onMeasure для представления или onBoundChange для рисования. Если это не изменится (как в этом примере), вы можете поместить этот код там, где вы настраиваете свою краску.

val radii = floatArrayOf(
    25f, 25f, //Top left corner
    25f, 25f, //Top right corner
    0f, 0f,   //Bottom right corner
    0f, 0f,   //Bottom left corner
)

path.reset() //Clears the previously set path
path.addRoundedRect(0f, 0f, 100f, 100f, radii, Path.Direction.CW)

Этот код создает закругленный прямоугольник 100x100 с верхними углами, закругленными с радиусом 25.

Нарисовать путь

Вызовите это в onDraw для представления или draw для рисования.

canvas.drawPath(path, paint)
person Cassie    schedule 03.09.2019

путь Версия #arcTo() для рисования закругленной стороны, если радиус равен половине высоты.

fun getPathOfRoundedRectF(
    rect: RectF,
    topLeftRadius: Float = 0f,
    topRightRadius: Float = 0f,
    bottomRightRadius: Float = 0f,
    bottomLeftRadius: Float = 0f
): Path {
    val tlRadius = topLeftRadius.coerceAtLeast(0f)
    val trRadius = topRightRadius.coerceAtLeast(0f)
    val brRadius = bottomRightRadius.coerceAtLeast(0f)
    val blRadius = bottomLeftRadius.coerceAtLeast(0f)

    with(Path()) {
        moveTo(rect.left + tlRadius, rect.top)

        //setup top border
        lineTo(rect.right - trRadius, rect.top)

        //setup top-right corner
        arcTo(
            RectF(
                rect.right - trRadius * 2f,
                rect.top,
                rect.right,
                rect.top + trRadius * 2f
            ), -90f, 90f
        )

        //setup right border
        lineTo(rect.right, rect.bottom - trRadius)

        //setup bottom-right corner
        arcTo(
            RectF(
                rect.right - brRadius * 2f,
                rect.bottom - brRadius * 2f,
                rect.right,
                rect.bottom
            ), 0f, 90f
        )

        //setup bottom border
        lineTo(rect.left + blRadius, rect.bottom)

        //setup bottom-left corner
        arcTo(
            RectF(
                rect.left,
                rect.bottom - blRadius * 2f,
                rect.left + blRadius * 2f,
                rect.bottom
            ), 90f, 90f
        )

        //setup left border
        lineTo(rect.left, rect.top + tlRadius)

        //setup top-left corner
        arcTo(
            RectF(
                rect.left,
                rect.top,
                rect.left + tlRadius * 2f,
                rect.top + tlRadius * 2f
            ),
            180f,
            90f
        )

        close()

        return this
    }
}

Два закругленных угла Три закругленных угла Три закругленных угла

person firemaples    schedule 02.07.2020

нарисовать круглый прямоугольник с левыми закругленными углами

  private void drawRoundRect(float left, float top, float right, float bottom, Paint paint, Canvas canvas) {
        Path path = new Path();
        path.moveTo(left, top);
        path.lineTo(right, top);
        path.lineTo(right, bottom);
        path.lineTo(left + radius, bottom);
        path.quadTo(left, bottom, left, bottom - radius);
        path.lineTo(left, top + radius);
        path.quadTo(left, top, left + radius, top);
        canvas.drawPath(path, onlinePaint);
    }
person georgehardcore    schedule 20.07.2015
comment
Этот метод не обеспечивает скругление углов прямоугольника, он обеспечивает скругление некоторых углов, но не всех, форма результата искажается. Вы должны немного поработать над этим, я думаю. - person Bahadir Tasdemir; 02.09.2015
comment
вы не должны создавать новые объекты в методе onDraw - используйте предварительно выделенный путь - person Evgenii Vorobei; 20.04.2019

Лучше использовать PaintDrawable:

    val topLeftRadius = 10
    val topRightRadius = 10
    val bottomLeftRadius = 0
    val bottomRightRadius = 0
    val rect = Rect(0, 0, 100, 100)
    val paintDrawable = PaintDrawable(Color.RED)
    val outter = floatArrayOf(topLeftRadius, topLeftRadius, topRightRadius, topRightRadius,
            bottomLeftRadius, bottomLeftRadius, bottomRightRadius, bottomRightRadius)
    paintDrawable.setCornerRadii(outter)
    paintDrawable.bounds = rect
    paintDrawable.draw(canvas)
person GreatC    schedule 16.01.2019

Вот мой ответ на поставленный выше вопрос. Здесь я создал функцию расширения Kotlin, которая использует Path вместе с функцией quadTo, которую также можно использовать в API более низкого уровня.

fun Canvas.drawRoundRectPath(
rectF: RectF,
radius: Float,
roundTopLeft: Boolean,
roundTopRight: Boolean,
roundBottomLeft: Boolean,
roundBottomRight: Boolean,
paint: Paint) {

val path = Path()

//Move path cursor to start point
if (roundBottomLeft) {
    path.moveTo(rectF.left, rectF.bottom - radius)
} else {
    path.moveTo(rectF.left, rectF.bottom)
}

// drawing line and rounding top left curve
if (roundTopLeft) {
    path.lineTo(rectF.left, rectF.top + radius)
    path.quadTo(rectF.left, rectF.top, rectF.left + radius, rectF.top)
} else {
    path.lineTo(rectF.left, rectF.top)
}

// drawing line an rounding top right curve
if (roundTopRight) {
    path.lineTo(rectF.right - radius, rectF.top)
    path.quadTo(rectF.right, rectF.top, rectF.right, rectF.top + radius)
} else {
    path.lineTo(rectF.right, rectF.top)
}

// drawing line an rounding bottom right curve
if (roundBottomRight) {
    path.lineTo(rectF.right, rectF.bottom - radius)
    path.quadTo(rectF.right, rectF.bottom, rectF.right - radius, rectF.bottom)
} else {
    path.lineTo(rectF.right, rectF.bottom)
}

// drawing line an rounding bottom left curve
if (roundBottomLeft) {
    path.lineTo(rectF.left + radius, rectF.bottom)
    path.quadTo(rectF.left, rectF.bottom, rectF.left, rectF.bottom - radius)
} else {
    path.lineTo(rectF.left, rectF.bottom)
}
path.close()

drawPath(path, paint)
}

Мы можем вызвать функцию с объектом холста и передать RectF размер, к которому мы хотим применить кривую.

Кроме того, мы можем передать логическое значение для углов, которые мы хотим скруглить. Этот ответ можно дополнительно настроить, чтобы принять радиус для отдельных углов.

person Ashish M    schedule 01.10.2020

person    schedule
comment
Спасибо за код, он работал хорошо для меня. Но в коде есть небольшая ошибка: вы работаете с половиной требуемого радиуса - я полагаю, вы принимаете радиус за диаметр, но радиус уже составляет половину диаметра, поэтому вы должны отбросить все /2 в код. - person Ridcully; 10.12.2016