mirror of https://github.com/GNOME/gimp.git
rewrite of the GimpCage data structure as a Gegl config object
This commit is contained in:
parent
5d483a9517
commit
2abbfc9114
|
@ -23,6 +23,8 @@ libappgegl_a_SOURCES = \
|
|||
\
|
||||
gimpbrightnesscontrastconfig.c \
|
||||
gimpbrightnesscontrastconfig.h \
|
||||
gimpcageconfig.c \
|
||||
gimpcageconfig.h \
|
||||
gimpcolorbalanceconfig.c \
|
||||
gimpcolorbalanceconfig.h \
|
||||
gimpcolorizeconfig.c \
|
||||
|
@ -51,9 +53,8 @@ libappgegl_a_SOURCES = \
|
|||
gimpoperationcolorbalance.h \
|
||||
gimpoperationcolorize.c \
|
||||
gimpoperationcolorize.h \
|
||||
##right place ?
|
||||
gimpoperationcage.h \
|
||||
gimpoperationcage.c \
|
||||
gimpoperationcage.h \
|
||||
gimpoperationcurves.c \
|
||||
gimpoperationcurves.h \
|
||||
gimpoperationdesaturate.c \
|
||||
|
|
|
@ -70,6 +70,7 @@ typedef struct _GimpOperationAntiEraseMode GimpOperationAntiEraseMode;
|
|||
/* operation config objects */
|
||||
|
||||
typedef struct _GimpBrightnessContrastConfig GimpBrightnessContrastConfig;
|
||||
typedef struct _GimpCageConfig GimpCageConfig;
|
||||
typedef struct _GimpColorBalanceConfig GimpColorBalanceConfig;
|
||||
typedef struct _GimpColorizeConfig GimpColorizeConfig;
|
||||
typedef struct _GimpCurvesConfig GimpCurvesConfig;
|
||||
|
|
|
@ -0,0 +1,356 @@
|
|||
/* GIMP - The GNU Image Manipulation Program
|
||||
*
|
||||
* gimpcageconfig.c
|
||||
* Copyright (C) 2010 Michael Muré <batolettre@gmail.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gegl.h>
|
||||
#include "gimp-gegl-types.h"
|
||||
|
||||
#include "libgimpconfig/gimpconfig.h"
|
||||
#include "libgimpmodule/gimpmodule.h"
|
||||
#include "libgimpmath/gimpmath.h"
|
||||
#include "libgimpbase/gimpbase.h"
|
||||
|
||||
#include "core/core-types.h"
|
||||
#include "libgimpmath/gimpmathtypes.h"
|
||||
#include "libgimpbase/gimpbaseenums.h"
|
||||
|
||||
#include "libgimpmath/gimpvector.h"
|
||||
#include <math.h>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "gimpcageconfig.h"
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (GimpCageConfig, gimp_cage_config,
|
||||
GIMP_TYPE_IMAGE_MAP_CONFIG,
|
||||
G_IMPLEMENT_INTERFACE (GIMP_TYPE_CONFIG,
|
||||
NULL))
|
||||
|
||||
#define parent_class gimp_cage_config_parent_class
|
||||
|
||||
#define N_ITEMS_PER_ALLOC 10
|
||||
|
||||
static void gimp_cage_config_finalize (GObject *object);
|
||||
static void gimp_cage_config_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static void gimp_cage_config_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec);
|
||||
|
||||
/* FIXME: to debug only */
|
||||
static void
|
||||
print_cage (GimpCageConfig *gcc)
|
||||
{
|
||||
gint i;
|
||||
GeglRectangle bounding_box;
|
||||
g_return_if_fail (GIMP_IS_CAGE_CONFIG (gcc));
|
||||
|
||||
bounding_box = gimp_cage_config_get_bounding_box (gcc);
|
||||
|
||||
for (i = 0; i < gcc->cage_vertice_number; i++)
|
||||
{
|
||||
printf("cgx: %.0f cgy: %.0f cvdx: %.0f cvdy: %.0f\n", gcc->cage_vertices[i].x, gcc->cage_vertices[i].y, gcc->cage_vertices_d[i].x, gcc->cage_vertices_d[i].y);
|
||||
}
|
||||
printf("bounding box: x: %d y: %d width: %d height: %d\n", bounding_box.x, bounding_box.y, bounding_box.width, bounding_box.height);
|
||||
printf("done\n");
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
gimp_cage_config_class_init (GimpCageConfigClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->set_property = gimp_cage_config_set_property;
|
||||
object_class->get_property = gimp_cage_config_get_property;
|
||||
|
||||
object_class->finalize = gimp_cage_config_finalize;
|
||||
}
|
||||
|
||||
static void
|
||||
gimp_cage_config_init (GimpCageConfig *self)
|
||||
{
|
||||
self->cage_vertice_number = 0;
|
||||
self->cage_vertices_max = 50; //pre-allocation for 50 vertices for the cage.
|
||||
|
||||
self->cage_vertices = g_new(GimpVector2, self->cage_vertices_max);
|
||||
self->cage_vertices_d = g_new(GimpVector2, self->cage_vertices_max);
|
||||
}
|
||||
|
||||
static void
|
||||
gimp_cage_config_finalize (GObject *object)
|
||||
{
|
||||
GimpCageConfig *gcc = GIMP_CAGE_CONFIG (object);
|
||||
|
||||
g_free(gcc->cage_vertices);
|
||||
g_free(gcc->cage_vertices_d);
|
||||
|
||||
G_OBJECT_CLASS (parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
gimp_cage_config_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
/* GimpCageConfig *gcc = GIMP_CAGE_CONFIG (object); */
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gimp_cage_config_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
/* GimpCageConfig *gcc = GIMP_CAGE_CONFIG (object); */
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gimp_cage_config_add_cage_point (GimpCageConfig *gcc,
|
||||
gdouble x,
|
||||
gdouble y)
|
||||
{
|
||||
g_return_if_fail (GIMP_IS_CAGE_CONFIG (gcc));
|
||||
|
||||
/* reallocate memory if needed */
|
||||
if (gcc->cage_vertice_number >= gcc->cage_vertices_max)
|
||||
{
|
||||
gcc->cage_vertices_max += N_ITEMS_PER_ALLOC;
|
||||
|
||||
gcc->cage_vertices = g_renew(GimpVector2,
|
||||
gcc->cage_vertices,
|
||||
gcc->cage_vertices_max);
|
||||
|
||||
gcc->cage_vertices_d = g_renew(GimpVector2,
|
||||
gcc->cage_vertices_d,
|
||||
gcc->cage_vertices_max);
|
||||
}
|
||||
|
||||
gcc->cage_vertices[gcc->cage_vertice_number].x = x;
|
||||
gcc->cage_vertices[gcc->cage_vertice_number].y = y;
|
||||
|
||||
gcc->cage_vertices_d[gcc->cage_vertice_number].x = x;
|
||||
gcc->cage_vertices_d[gcc->cage_vertice_number].y = y;
|
||||
|
||||
gcc->cage_vertice_number++;
|
||||
}
|
||||
|
||||
void gimp_cage_config_remove_last_cage_point (GimpCageConfig *gcc)
|
||||
{
|
||||
g_return_if_fail (GIMP_IS_CAGE_CONFIG (gcc));
|
||||
|
||||
if (gcc->cage_vertice_number >= 1)
|
||||
gcc->cage_vertice_number--;
|
||||
}
|
||||
|
||||
gint gimp_cage_config_is_on_handle (GimpCageConfig *gcc,
|
||||
GimpCageMode mode,
|
||||
gdouble x,
|
||||
gdouble y,
|
||||
gint handle_size)
|
||||
{
|
||||
gint i;
|
||||
gdouble vert_x, vert_y;
|
||||
|
||||
g_return_val_if_fail (GIMP_IS_CAGE_CONFIG (gcc), -1);
|
||||
|
||||
if (gcc->cage_vertice_number == 0)
|
||||
return -1;
|
||||
|
||||
for (i = 0; i < gcc->cage_vertice_number; i++)
|
||||
{
|
||||
if (mode == GIMP_CAGE_MODE_CAGE_CHANGE)
|
||||
{
|
||||
vert_x = gcc->cage_vertices[i].x;
|
||||
vert_y = gcc->cage_vertices[i].y;
|
||||
}
|
||||
else
|
||||
{
|
||||
vert_x = gcc->cage_vertices_d[i].x;
|
||||
vert_y = gcc->cage_vertices_d[i].y;
|
||||
}
|
||||
|
||||
if (x < vert_x + handle_size / 2 && x > vert_x -handle_size / 2 &&
|
||||
y < vert_y + handle_size / 2 && y > vert_y -handle_size / 2)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void gimp_cage_config_move_cage_point (GimpCageConfig *gcc,
|
||||
GimpCageMode mode,
|
||||
gint point_number,
|
||||
gdouble x,
|
||||
gdouble y)
|
||||
{
|
||||
g_return_if_fail (GIMP_IS_CAGE_CONFIG (gcc));
|
||||
g_return_if_fail (point_number < gcc->cage_vertice_number);
|
||||
g_return_if_fail (point_number >= 0);
|
||||
|
||||
if (mode == GIMP_CAGE_MODE_CAGE_CHANGE)
|
||||
{
|
||||
gcc->cage_vertices[point_number].x = x;
|
||||
gcc->cage_vertices[point_number].y = y;
|
||||
}
|
||||
else
|
||||
{
|
||||
gcc->cage_vertices_d[point_number].x = x;
|
||||
gcc->cage_vertices_d[point_number].y = y;
|
||||
}
|
||||
}
|
||||
|
||||
GimpVector2 gimp_cage_config_get_edge_normal (GimpCageConfig *gcc,
|
||||
gint edge_index)
|
||||
{
|
||||
GimpVector2 result;
|
||||
|
||||
g_return_val_if_fail (GIMP_IS_CAGE_CONFIG (gcc), gimp_vector2_new(1,0));
|
||||
g_return_val_if_fail (edge_index >= 0, gimp_vector2_new(1,0));
|
||||
g_return_val_if_fail (edge_index < gcc->cage_vertice_number, gimp_vector2_new(1,0));
|
||||
|
||||
gimp_vector2_sub (&result,
|
||||
&gcc->cage_vertices_d[(edge_index+1) % gcc->cage_vertice_number],
|
||||
&gcc->cage_vertices_d[edge_index]);
|
||||
|
||||
return gimp_vector2_normal (&result);
|
||||
}
|
||||
|
||||
GeglRectangle gimp_cage_config_get_bounding_box (GimpCageConfig *gcc)
|
||||
{
|
||||
gint i;
|
||||
GeglRectangle bounding_box = {0, };
|
||||
|
||||
g_return_val_if_fail (GIMP_IS_CAGE_CONFIG (gcc), bounding_box);
|
||||
g_return_val_if_fail (gcc->cage_vertice_number >= 0, bounding_box);
|
||||
|
||||
bounding_box.x = gcc->cage_vertices[0].x;
|
||||
bounding_box.y = gcc->cage_vertices[0].y;
|
||||
bounding_box.height = 0;
|
||||
bounding_box.width = 0;
|
||||
|
||||
for (i = 1; i < gcc->cage_vertice_number; i++)
|
||||
{
|
||||
gdouble x,y;
|
||||
|
||||
x = gcc->cage_vertices[i].x;
|
||||
y = gcc->cage_vertices[i].y;
|
||||
|
||||
if (x < bounding_box.x)
|
||||
{
|
||||
bounding_box.width += bounding_box.x - x;
|
||||
bounding_box.x = x;
|
||||
}
|
||||
|
||||
if (y < bounding_box.y)
|
||||
{
|
||||
bounding_box.height += bounding_box.y - y;
|
||||
bounding_box.y = y;
|
||||
}
|
||||
|
||||
if (x > bounding_box.x + bounding_box.width)
|
||||
{
|
||||
bounding_box.width = x - bounding_box.x;
|
||||
}
|
||||
|
||||
if (y > bounding_box.y + bounding_box.height)
|
||||
{
|
||||
bounding_box.height = y - bounding_box.y;
|
||||
}
|
||||
}
|
||||
|
||||
return bounding_box;
|
||||
}
|
||||
|
||||
void
|
||||
gimp_cage_config_reverse_cage (GimpCageConfig *gcc)
|
||||
{
|
||||
gint i;
|
||||
GimpVector2 temp;
|
||||
|
||||
g_return_if_fail (GIMP_IS_CAGE_CONFIG (gcc));
|
||||
|
||||
for (i = 0; i < gcc->cage_vertice_number / 2; i++)
|
||||
{
|
||||
temp = gcc->cage_vertices[i];
|
||||
gcc->cage_vertices[i] = gcc->cage_vertices[gcc->cage_vertice_number - i -1];
|
||||
gcc->cage_vertices[gcc->cage_vertice_number - i -1] = temp;
|
||||
|
||||
temp = gcc->cage_vertices_d[i];
|
||||
gcc->cage_vertices_d[i] = gcc->cage_vertices_d[gcc->cage_vertice_number - i -1];
|
||||
gcc->cage_vertices_d[gcc->cage_vertice_number - i -1] = temp;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gimp_cage_config_reverse_cage_if_needed (GimpCageConfig *gcc)
|
||||
{
|
||||
gint i;
|
||||
gdouble sum;
|
||||
|
||||
g_return_if_fail (GIMP_IS_CAGE_CONFIG (gcc));
|
||||
|
||||
sum = 0.0;
|
||||
|
||||
/* this is a bit crappy, but should works most of the case */
|
||||
/* we do the sum of the projection of each point to the previous segment, and see the final sign */
|
||||
for (i = 0; i < gcc->cage_vertice_number ; i++)
|
||||
{
|
||||
GimpVector2 P1, P2, P3;
|
||||
gdouble z;
|
||||
|
||||
P1 = gcc->cage_vertices[i];
|
||||
P2 = gcc->cage_vertices[(i+1) % gcc->cage_vertice_number];
|
||||
P3 = gcc->cage_vertices[(i+2) % gcc->cage_vertice_number];
|
||||
|
||||
z = P1.x * (P2.y - P3.y) + P2.x * (P3.y - P1.y) + P3.x * (P1.y - P2.y);
|
||||
|
||||
sum += z;
|
||||
}
|
||||
|
||||
/* sum > 0 mean a cage defined clockwise, so we reverse it */
|
||||
if (sum > 0)
|
||||
{
|
||||
gimp_cage_config_reverse_cage (gcc);
|
||||
printf("reverse the cage !\n");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,149 @@
|
|||
/* GIMP - The GNU Image Manipulation Program
|
||||
*
|
||||
* gimpcageconfig.h
|
||||
* Copyright (C) 2010 Michael Muré <batolettre@gmail.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __GIMP_CAGE_CONFIG_H__
|
||||
#define __GIMP_CAGE_CONFIG_H__
|
||||
|
||||
#include "core/gimpimagemapconfig.h"
|
||||
|
||||
#define GIMP_TYPE_CAGE_CONFIG (gimp_cage_config_get_type ())
|
||||
#define GIMP_CAGE_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_CAGE_CONFIG, GimpCageConfig))
|
||||
#define GIMP_CAGE_CONFIG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_CAGE_CONFIG, GimpCageConfigClass))
|
||||
#define GIMP_IS_CAGE_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_CAGE_CONFIG))
|
||||
#define GIMP_IS_CAGE_CONFIG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_CAGE_CONFIG))
|
||||
#define GIMP_CAGE_CONFIG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_CAGE_CONFIG, GimpCageConfigClass))
|
||||
|
||||
|
||||
typedef struct _GimpCageConfigClass GimpCageConfigClass;
|
||||
|
||||
struct _GimpCageConfig
|
||||
{
|
||||
GimpImageMapConfig parent_instance;
|
||||
|
||||
gint cage_vertice_number; /* number of vertices used by the cage */
|
||||
gint cage_vertices_max; /* number of vertices allocated in memory */
|
||||
|
||||
GimpVector2 *cage_vertices; /* cage before deformation */
|
||||
GimpVector2 *cage_vertices_d; /* cage after deformation */
|
||||
};
|
||||
|
||||
|
||||
struct _GimpCageConfigClass
|
||||
{
|
||||
GimpImageMapConfigClass parent_class;
|
||||
};
|
||||
|
||||
GType gimp_cage_config_get_type (void) G_GNUC_CONST;
|
||||
|
||||
/**
|
||||
* gimp_cage_config_add_cage_point:
|
||||
* @gcc: the cage config
|
||||
* @x: x value of the new point
|
||||
* @y: y value of the new point
|
||||
*
|
||||
* Add a new point in the polygon of the cage, and make allocation if needed.
|
||||
* Point is added in both source and destination cage
|
||||
*/
|
||||
void gimp_cage_config_add_cage_point (GimpCageConfig *gcc,
|
||||
gdouble x,
|
||||
gdouble y);
|
||||
|
||||
/**
|
||||
* gimp_cage_config_remove_last_cage_point:
|
||||
* @gcc: the cage config
|
||||
*
|
||||
* Remove the last point of the cage, in both source and destination cage
|
||||
*/
|
||||
void gimp_cage_config_remove_last_cage_point (GimpCageConfig *gcc);
|
||||
|
||||
/**
|
||||
* gimp_cage_config_is_on_handle:
|
||||
* @gcc: the cage config
|
||||
* @mode: the actual mode of the cage, GIMP_CAGE_MODE_CAGE_CHANGE or GIMP_CAGE_MODE_DEFORM
|
||||
* @x: x value to check
|
||||
* @y: y value to check
|
||||
* @handle_size: size of the handle, in pixels
|
||||
*
|
||||
* Check if a given point is on a handle of the cage, and return his number if yes.
|
||||
*
|
||||
* Returns: the number of the handle if the point is on a handle, or -1 if not.
|
||||
*/
|
||||
gint gimp_cage_config_is_on_handle (GimpCageConfig *gcc,
|
||||
GimpCageMode mode,
|
||||
gdouble x,
|
||||
gdouble y,
|
||||
gint handle_size);
|
||||
|
||||
/**
|
||||
* gimp_cage_config_move_cage_point:
|
||||
* @gcc: the cage config
|
||||
* @mode: the actual mode of the cage, GIMP_CAGE_MODE_CAGE_CHANGE or GIMP_CAGE_MODE_DEFORM
|
||||
* @point_number: the point of the cage to move
|
||||
* @x: new x value
|
||||
* @y: new y value
|
||||
*
|
||||
* Move a point of the source or destination cage, according to the cage mode provided
|
||||
*/
|
||||
void gimp_cage_config_move_cage_point (GimpCageConfig *gcc,
|
||||
GimpCageMode mode,
|
||||
gint point_number,
|
||||
gdouble x,
|
||||
gdouble y);
|
||||
|
||||
/**
|
||||
* gimp_cage_config_get_edge_normal:
|
||||
* @gcc: the cage config
|
||||
* @edge_index: the index of the edge considered
|
||||
*
|
||||
* Compute the normal vector to an edge of the cage
|
||||
*
|
||||
* Returns: The normal vector to the specified edge of the cage. This vector is normalized (length = 1.0)
|
||||
*/
|
||||
GimpVector2 gimp_cage_config_get_edge_normal (GimpCageConfig *gcc,
|
||||
gint edge_index);
|
||||
|
||||
/**
|
||||
* gimp_cage_config_get_bounding_box:
|
||||
* @gcc: the cage config
|
||||
*
|
||||
* Compute the bounding box of the destination cage
|
||||
*
|
||||
* Returns: the bounding box of the destination cage, as a GeglRectangle
|
||||
*/
|
||||
GeglRectangle gimp_cage_config_get_bounding_box (GimpCageConfig *gcc);
|
||||
|
||||
/**
|
||||
* gimp_cage_config_reverse_cage_if_needed:
|
||||
* @gcc: the cage config
|
||||
*
|
||||
* Since the cage need to be defined counter-clockwise to have the topological inside in the actual 'physical' inside of the cage,
|
||||
* this function compute if the cage is clockwise or not, and reverse the cage if needed.
|
||||
*/
|
||||
void gimp_cage_config_reverse_cage_if_needed (GimpCageConfig *gcc);
|
||||
|
||||
/**
|
||||
* gimp_cage_config_reverse_cage:
|
||||
* @gcc: the cage config
|
||||
*
|
||||
* When using non-simple cage (like a cage in 8), user may want to manually inverse inside and outside of the cage.
|
||||
* This function reverse the cage
|
||||
*/
|
||||
void gimp_cage_config_reverse_cage (GimpCageConfig *gcc);
|
||||
|
||||
#endif /* __GIMP_CAGE_CONFIG_H__ */
|
|
@ -29,6 +29,7 @@ OBJECTS = \
|
|||
gimpoperationtilesink.obj \
|
||||
gimpoperationtilesource.obj \
|
||||
gimpbrightnesscontrastconfig.obj \
|
||||
gimpcageconfig.obj \
|
||||
gimpcolorbalanceconfig.obj \
|
||||
gimpcolorizeconfig.obj \
|
||||
gimpcurvesconfig.obj \
|
||||
|
|
Loading…
Reference in New Issue