Инвариантная штриховая толщина Пути независимо от масштаба

Если вы делаете большое приложение с другими разработчиками в своей команде и собираетесь иметь все хорошо организованное без разброса кода или разных экземпляров SharedPreferences, вы можете сделать что-то вроде этого:

//SharedPreferences manager class
public class SharedPrefs {

    //SharedPreferences file name
    private static String SHARED_PREFS_FILE_NAME = "my_app_shared_prefs";

    //here you can centralize all your shared prefs keys
    public static String KEY_MY_SHARED_BOOLEAN = "my_shared_boolean";
    public static String KEY_MY_SHARED_FOO = "my_shared_foo";

    //get the SharedPreferences object instance
    //create SharedPreferences file if not present


    private static SharedPreferences getPrefs(Context context) {
        return context.getSharedPreferences(SHARED_PREFS_FILE_NAME, Context.MODE_PRIVATE);
    }

    //Save Booleans
    public static void savePref(Context context, String key, boolean value) {
        getPrefs(context).edit().putBoolean(key, value).commit();       
    }

    //Get Booleans
    public static boolean getBoolean(Context context, String key) {
        return getPrefs(context).getBoolean(key, false);
    }

    //Get Booleans if not found return a predefined default value
    public static boolean getBoolean(Context context, String key, boolean defaultValue) {
        return getPrefs(context).getBoolean(key, defaultValue);
    }

    //Strings
    public static void save(Context context, String key, String value) {
        getPrefs(context).edit().putString(key, value).commit();
    }

    public static String getString(Context context, String key) {
        return getPrefs(context).getString(key, "");
    }

    public static String getString(Context context, String key, String defaultValue) {
        return getPrefs(context).getString(key, defaultValue);
    }

    //Integers
    public static void save(Context context, String key, int value) {
        getPrefs(context).edit().putInt(key, value).commit();
    }

    public static int getInt(Context context, String key) {
        return getPrefs(context).getInt(key, 0);
    }

    public static int getInt(Context context, String key, int defaultValue) {
        return getPrefs(context).getInt(key, defaultValue);
    }

    //Floats
    public static void save(Context context, String key, float value) {
        getPrefs(context).edit().putFloat(key, value).commit();
    }

    public static float getFloat(Context context, String key) {
        return getPrefs(context).getFloat(key, 0);
    }

    public static float getFloat(Context context, String key, float defaultValue) {
        return getPrefs(context).getFloat(key, defaultValue);
    }

    //Longs
    public static void save(Context context, String key, long value) {
        getPrefs(context).edit().putLong(key, value).commit();
    }

    public static long getLong(Context context, String key) {
        return getPrefs(context).getLong(key, 0);
    }

    public static long getLong(Context context, String key, long defaultValue) {
        return getPrefs(context).getLong(key, defaultValue);
    }

    //StringSets
    public static void save(Context context, String key, Set<String> value) {
        getPrefs(context).edit().putStringSet(key, value).commit();
    }

    public static Set<String> getStringSet(Context context, String key) {
        return getPrefs(context).getStringSet(key, null);
    }

    public static Set<String> getStringSet(Context context, String key, Set<String> defaultValue) {
        return getPrefs(context).getStringSet(key, defaultValue);
    }
}

В вашем вы можете сохранить SharedPreferences таким образом

//saving a boolean into prefs
SharedPrefs.savePref(this, SharedPrefs.KEY_MY_SHARED_BOOLEAN, booleanVar);

, и вы можете получить свои SharedPreferences таким образом

//getting a boolean from prefs
booleanVar = SharedPrefs.getBoolean(this, SharedPrefs.KEY_MY_SHARED_BOOLEAN);
22
задан Brian Campbell 6 April 2009 в 17:31
поделиться

3 ответа

Наконец я получил обходное решение для вышеупомянутого решения. Я сделал это путем установки StrokeThickness из Path относительно масштабирования Canvas.

Как это:

// scale = scaling factor applied to the canvas
path.StrokeThickness = 1.0 / scale;

Это только работает если ScaleX и ScaleY универсальны.

7
ответ дан 29 November 2019 в 05:43
поделиться

Лучшим решением было бы использовать один или несколько объектов System.Windows.Media.Geometry для хранения ваших путей, точек и т. д.

Эту геометрию можно нарисовать пером, поэтому вы действительно можете изменить толщину обводки при масштабировании, но более гибким является использование свойства Transform.

Используя преобразование, вы можете «масштабировать» фактическое координаты геометрического представления, а не визуализации - поэтому при рисовании вам не нужно возиться с преобразованиями рендеринга.

Чтобы вычислить преобразование, я использую следующий код, например:

public static Matrix TransformShape(Rect fromPosition, Rect toPosition, bool flipVertical) {
    Matrix translateThenScale = Matrix.Identity;
    //we first translate to origin since that's just easier
    translateThenScale.Translate(-fromPosition.X, -fromPosition.Y);
    //now we scale the graph to the appropriate dimensions
    translateThenScale.Scale(toPosition.Width / fromPosition.Width, toPosition.Height / fromPosition.Height);
    //then we flip the graph vertically around the viewport middle since in our graph positive is up, not down.
    if (flipVertical)
        translateThenScale.ScaleAt(1.0, -1.0, 0.0, toPosition.Height / 2.0);
    //now we push the graph to the right spot, which will usually simply be 0,0.
    translateThenScale.Translate(toPosition.X, toPosition.Y);

    return translateThenScale;
}

где fromPosition Rect должен содержат нетрансформированные границы, а объект toPosition Rect должен содержать трансформированные границы. Это также тривиально позволяет масштабировать X и Y отдельно, что часто необходимо для построения графика.

Легко вычислить границы вашей геометрии:

Geometry graphGeom;
//[...]   
//the bounds are modified by the transform, so we want no transform!    
graphGeom.Transform = Transform.Identity; 
Rect graphBounds = graphGeom.Bounds;
//then set the transform again

//or, if the transform is axis-aligned, the following _should_ work:
Rect graphBoundsAlt = graphGeom.Transform.Inverse.TransformBounds(graphGeom.Bounds);

И, конечно, WPF может сказать вам, в какие границы вам нужно визуализировать, если это будет необходимо. Собрав все вместе, вы могли бы сделать что-то вроде

public void RecomputeTransform(Rect targetRect, bool flipVertical) {
    graphGeom.Transform = Transform.Identity; 
    Rect graphBounds = graphGeom.Bounds;
    Matrix transMat = TransformShape(graphBounds,targetRect,flipVertical);
    graphGeom.Transform = new MatrixTransform(transMat);
}

. Преимущество использования этого решения в том, что вам не нужно связываться с RenderTransforms, вы можете свободно использовать преобразования, которые срезают и / или масштабируют X и Y независимо друг от друга, не получая странных искажения в ваших линиях, и вы можете рассматривать перо как непрозрачный объект (т. е. его проще настроить из пользовательского интерфейса - если вы выберете ширину пера или что-то еще, дальнейшая коррекция не требуется).

13
ответ дан 29 November 2019 в 05:43
поделиться

Я думаю, что Вам было нужно YourPathObject.RenderedGeometry.Transform свойство

0
ответ дан 29 November 2019 в 05:43
поделиться
Другие вопросы по тегам:

Похожие вопросы: