Freestyle: New line style options for sorting and chain selection.

The following two sort keys are added for sorting chains.

* Projected X - Sort by the projected X value in the image coordinate system.
* Projected Y - Sort by the projected Y value in the image coordinate system.

A new line style option for the selection of first N chains is also added.

Moreover, the chain sorting and chain selection operations are now executed
in this order instead of the reverse order used previously.  The UI has also
changed accordingly.  This functional change is backward compatible and
won't result in visual differences.
This commit is contained in:
Tamito Kajiyama 2014-10-01 15:42:37 +09:00
parent 55aa42ad6f
commit 2cb134be2b
7 changed files with 75 additions and 18 deletions

View File

@ -82,6 +82,8 @@ __all__ = (
"pyNatureUP1D",
"pyParameterUP0D",
"pyParameterUP0DGoodOne",
"pyProjectedXBP1D",
"pyProjectedYBP1D",
"pyShapeIdListUP1D",
"pyShapeIdUP1D",
"pyShuffleBP1D",
@ -135,6 +137,8 @@ from freestyle.functions import (
GetCurvilinearAbscissaF0D,
GetDirectionalViewMapDensityF1D,
GetOccludersF1D,
GetProjectedXF1D,
GetProjectedYF1D,
GetProjectedZF1D,
GetShapeF1D,
GetSteerableViewMapDensityF1D,
@ -596,6 +600,24 @@ class pyZBP1D(BinaryPredicate1D):
return (self.func(i1) > self.func(i2))
class pyProjectedXBP1D(BinaryPredicate1D):
def __init__(self, iType=IntegrationType.MEAN):
BinaryPredicate1D.__init__(self)
self.func = GetProjectedXF1D(iType)
def __call__(self, i1, i2):
return (self.func(i1) > self.func(i2))
class pyProjectedYBP1D(BinaryPredicate1D):
def __init__(self, iType=IntegrationType.MEAN):
BinaryPredicate1D.__init__(self)
self.func = GetProjectedYF1D(iType)
def __call__(self, i1, i2):
return (self.func(i1) > self.func(i2))
class pyZDiscontinuityBP1D(BinaryPredicate1D):
def __init__(self, iType=IntegrationType.MEAN):
BinaryPredicate1D.__init__(self)

View File

@ -62,7 +62,10 @@ from freestyle.predicates import (
TrueBP1D,
TrueUP1D,
WithinImageBoundaryUP1D,
pyNFirstUP1D,
pyNatureUP1D,
pyProjectedXBP1D,
pyProjectedYBP1D,
pyZBP1D,
)
from freestyle.shaders import (
@ -1006,11 +1009,6 @@ def process(layer_name, lineset_name):
Operators.sequential_split(SplitPatternStartingUP0D(controller),
SplitPatternStoppingUP0D(controller),
sampling)
# select chains
if linestyle.use_length_min or linestyle.use_length_max:
length_min = linestyle.length_min if linestyle.use_length_min else None
length_max = linestyle.length_max if linestyle.use_length_max else None
Operators.select(LengthThresholdUP1D(length_min, length_max))
# sort selected chains
if linestyle.use_sorting:
integration = integration_types.get(linestyle.integration_type, IntegrationType.MEAN)
@ -1018,9 +1016,20 @@ def process(layer_name, lineset_name):
bpred = pyZBP1D(integration)
elif linestyle.sort_key == '2D_LENGTH':
bpred = Length2DBP1D()
elif linestyle.sort_key == 'PROJECTED_X':
bpred = pyProjectedXBP1D(integration)
elif linestyle.sort_key == 'PROJECTED_Y':
bpred = pyProjectedYBP1D(integration)
if linestyle.sort_order == 'REVERSE':
bpred = NotBP1D(bpred)
Operators.sort(bpred)
# select chains
if linestyle.use_length_min or linestyle.use_length_max:
length_min = linestyle.length_min if linestyle.use_length_min else None
length_max = linestyle.length_max if linestyle.use_length_max else None
Operators.select(LengthThresholdUP1D(length_min, length_max))
if linestyle.use_chain_count:
Operators.select(pyNFirstUP1D(linestyle.chain_count))
# prepare a list of stroke shaders
shaders_list = []
for m in linestyle.geometry_modifiers:

View File

@ -579,6 +579,20 @@ class RENDERLAYER_PT_freestyle_linestyle(RenderLayerFreestyleEditorButtonsPanel,
sub.prop(linestyle, "split_dash3", text="D3")
sub.prop(linestyle, "split_gap3", text="G3")
## Sorting
layout.prop(linestyle, "use_sorting", text="Sorting:")
col = layout.column()
col.active = linestyle.use_sorting
row = col.row(align=True)
row.prop(linestyle, "sort_key", text="")
sub = row.row()
sub.active = linestyle.sort_key in {'DISTANCE_FROM_CAMERA',
'PROJECTED_X',
'PROJECTED_Y'}
sub.prop(linestyle, "integration_type", text="")
row = col.row(align=True)
row.prop(linestyle, "sort_order", expand=True)
## Selection
layout.label(text="Selection:")
split = layout.split(align=True)
@ -589,25 +603,18 @@ class RENDERLAYER_PT_freestyle_linestyle(RenderLayerFreestyleEditorButtonsPanel,
sub = row.row()
sub.active = linestyle.use_length_min
sub.prop(linestyle, "length_min")
# Second column
col = split.column()
row = col.row(align=True)
row.prop(linestyle, "use_length_max", text="")
sub = row.row()
sub.active = linestyle.use_length_max
sub.prop(linestyle, "length_max")
## Sorting
layout.prop(linestyle, "use_sorting", text="Sorting:")
col = layout.column()
col.active = linestyle.use_sorting
# Second column
col = split.column()
row = col.row(align=True)
row.prop(linestyle, "sort_key", text="")
row.prop(linestyle, "use_chain_count", text="")
sub = row.row()
sub.active = linestyle.sort_key in {'DISTANCE_FROM_CAMERA'}
sub.prop(linestyle, "integration_type", text="")
row = col.row(align=True)
row.prop(linestyle, "sort_order", expand=True)
sub.active = linestyle.use_chain_count
sub.prop(linestyle, "chain_count")
## Caps
layout.label(text="Caps:")

View File

@ -93,6 +93,7 @@ static void default_linestyle_settings(FreestyleLineStyle *linestyle)
linestyle->min_length = 0.0f;
linestyle->max_length = 10000.0f;
linestyle->split_length = 100;
linestyle->chain_count = 10;
linestyle->sort_key = LS_SORT_KEY_DISTANCE_FROM_CAMERA;
linestyle->integration_type = LS_INTEGRATION_MEAN;
linestyle->texstep = 1.0f;
@ -186,6 +187,7 @@ FreestyleLineStyle *BKE_linestyle_copy(FreestyleLineStyle *linestyle)
new_linestyle->max_angle = linestyle->max_angle;
new_linestyle->min_length = linestyle->min_length;
new_linestyle->max_length = linestyle->max_length;
new_linestyle->chain_count = linestyle->chain_count;
new_linestyle->split_dash1 = linestyle->split_dash1;
new_linestyle->split_gap1 = linestyle->split_gap1;
new_linestyle->split_dash2 = linestyle->split_dash2;

View File

@ -99,6 +99,7 @@ void BLO_update_defaults_startup_blend(Main *bmain)
linestyle->sort_key = LS_SORT_KEY_DISTANCE_FROM_CAMERA;
linestyle->integration_type = LS_INTEGRATION_MEAN;
linestyle->texstep = 1.0;
linestyle->chain_count = 10;
}
{

View File

@ -387,6 +387,7 @@ typedef struct LineStyleThicknessModifier_Calligraphy {
#define LS_NO_SORTING (1 << 11)
#define LS_REVERSE_ORDER (1 << 12) /* for sorting */
#define LS_TEXTURE (1 << 13)
#define LS_CHAIN_COUNT (1 << 14)
/* FreestyleLineStyle::chaining */
#define LS_CHAINING_PLAIN 1
@ -406,6 +407,8 @@ typedef struct LineStyleThicknessModifier_Calligraphy {
/* FreestyleLineStyle::sort_key */
#define LS_SORT_KEY_DISTANCE_FROM_CAMERA 1
#define LS_SORT_KEY_2D_LENGTH 2
#define LS_SORT_KEY_PROJECTED_X 3
#define LS_SORT_KEY_PROJECTED_Y 4
/* FreestyleLineStyle::integration_type */
#define LS_INTEGRATION_MEAN 1
@ -428,13 +431,14 @@ typedef struct FreestyleLineStyle {
float split_length;
float min_angle, max_angle; /* in radians, for splitting */
float min_length, max_length;
unsigned int chain_count;
unsigned short split_dash1, split_gap1;
unsigned short split_dash2, split_gap2;
unsigned short split_dash3, split_gap3;
int sort_key, integration_type;
float texstep;
short texact, pr_texture;
short use_nodes, pad;
short use_nodes, pad[3];
unsigned short dash1, gap1, dash2, gap2, dash3, gap3;
int panel; /* for UI */

View File

@ -1322,6 +1322,8 @@ static void rna_def_linestyle(BlenderRNA *brna)
static EnumPropertyItem sort_key_items[] = {
{LS_SORT_KEY_DISTANCE_FROM_CAMERA, "DISTANCE_FROM_CAMERA", 0, "Distance from Camera", "Sort by distance from camera (closer lines lie on top of further lines)"},
{LS_SORT_KEY_2D_LENGTH, "2D_LENGTH", 0, "2D Length", "Sort by curvilinear 2D length (longer lines lie on top of shorter lines)"},
{LS_SORT_KEY_PROJECTED_X, "PROJECTED_X", 0, "Projected X", "Sort by the projected X value in the image coordinate system"},
{LS_SORT_KEY_PROJECTED_Y, "PROJECTED_Y", 0, "Projected Y", "Sort by the projected Y value in the image coordinate system"},
{0, NULL, 0, NULL, NULL}
};
static EnumPropertyItem sort_order_items[] = {
@ -1488,6 +1490,16 @@ static void rna_def_linestyle(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Max 2D Length", "Maximum curvilinear 2D length for the selection of chains");
RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
prop = RNA_def_property(srna, "use_chain_count", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", LS_CHAIN_COUNT);
RNA_def_property_ui_text(prop, "Use Chain Count", "Enable the selection of first N chains");
RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
prop = RNA_def_property(srna, "chain_count", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_sdna(prop, NULL, "chain_count");
RNA_def_property_ui_text(prop, "Chain Count", "Chain count for the selection of first N chains");
RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
prop = RNA_def_property(srna, "use_split_pattern", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", LS_SPLIT_PATTERN);
RNA_def_property_ui_text(prop, "Use Split Pattern", "Enable chain splitting by dashed line patterns");