<commit_before>/***************************************************************
 *
 * Copyright (C) 1990-2007, Condor Team, Computer Sciences Department,
 * University of Wisconsin-Madison, WI.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you
 * may not use this file except in compliance with the License.  You may
 * obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 ***************************************************************/

#include "condor_common.h"
#include "condor_debug.h"
#include "condor_syscall_mode.h"
#include "limit.h"

extern "C" {

void
limit( int resource, rlim_t new_limit, int kind, char const *resource_str )
{
	int		scm;
	struct	rlimit current = {0,0};
	struct	rlimit desired = {0,0};
	char const *kind_str = "";

	scm = SetSyscalls( SYS_LOCAL | SYS_RECORDED );

	/* Find out current limit for this resource */
	if( getrlimit(resource, &current) < 0 ) {
		EXCEPT( "getrlimit(%d (%s)): errno: %d(%s)",
					resource, resource_str, errno, strerror(errno));
	}

	switch(kind) {
		case CONDOR_SOFT_LIMIT:
			/* Make a new rlimit structure that holds what I desire to be
				true */
			desired.rlim_cur = new_limit;
			desired.rlim_max = current.rlim_max;
			kind_str = "soft";

			/* Don't try to exceed the hard max as supplied by getrlimit() */
			if( desired.rlim_cur > desired.rlim_max ) {
				desired.rlim_cur = desired.rlim_max;
			}

			break;

		case CONDOR_HARD_LIMIT:
			desired.rlim_cur = new_limit;
			desired.rlim_max = new_limit;
			kind_str = "hard";

			if ((desired.rlim_max > current.rlim_max) && (getuid() != (pid_t)0))
			{
				/* Due to the fact that this code
					path will happen a lot as a non
					root user due to the the behavior
					in Create_Process where we always
					try to set the core hard limit to
					the maximum of size_t by default,
					we will by default ALWAYS ask
					for a limit which may be larger
					than the current hard max of
					this limit. Especially in the
					case of a personal Condor this
					will result in whatever message
					being written here being printed
					out *all the time*. So, instead
					of doing a dprintf for SNAFU
					behavior, we silently truncate
					the asked for limit the to
					current hard max if it is greater.
				*/

				desired = current;

				desired.rlim_cur = desired.rlim_max;
			}

			break;

		case CONDOR_REQUIRED_LIMIT:
			desired.rlim_cur = new_limit;
			desired.rlim_max = current.rlim_max;
			kind_str = "required";

				// only raise the hard limit if necessary
			if( desired.rlim_cur > desired.rlim_max ) {
				desired.rlim_max = desired.rlim_cur;
			}

			break;

		default:
			EXCEPT("do_limit() unknown limit enforcment policy. Programmer "
				"Error.");
			break;
	}

	/* Set the new limit */
	if( setrlimit(resource, &desired) < 0 ) {
		if (errno == EPERM && kind != CONDOR_REQUIRED_LIMIT ) {
		/* Under tru64, this setrlimit() fails oddly in that we
			are following the API restrictions exactly(not
			adjusting the maximum up as non-root, and not
			asking for more soft limit than hard limit),
			but still the kernel refuses to honor the
			change we wish to make and responds with a
			nonsensical EPERM failure. So we'll see if we
			can do something reasonable before giving up
			and not setting it at all. This code will be
			kept common for all architectures in the hopes
			that it will handle failures of this kind
			everywhere. We're going to try and bound the
			resource limit to UINT_MAX if we are able. */

		dprintf( D_ALWAYS,
			"Unexpected permissions failure in setting %s limit for %s"
			"setrlimit(%d, new = [rlim_cur = %lu, rlim_max = %lu]) : "
			"old = [rlim_cur = %lu, rlim_max = %lu], errno: %d(%s). Attempting "
			"workaround.\n",
			kind_str,
			resource_str,
			resource,
			(unsigned long)desired.rlim_cur,
			(unsigned long)desired.rlim_max,
			(unsigned long)current.rlim_cur,
			(unsigned long)current.rlim_max,
			errno,
			strerror(errno) );

			/* bound the resource limit to UINT_MAX, if I can */
			if (desired.rlim_cur > UINT_MAX &&
				current.rlim_max >= UINT_MAX)
			{
				desired.rlim_cur = UINT_MAX;
				if (setrlimit(resource, &desired) < 0) {
					dprintf( D_ALWAYS, "Workaround failed with error %d(%s). "
						"Not adjusting %s limit for %s\n",
						errno, strerror(errno), kind_str, resource_str);

				} else {
					dprintf( D_ALWAYS, "Workaround enabled. The %s limit for "
						"%s is this: "
						"new = [rlim_cur = %lu, rlim_max = %lu]\n",
						kind_str,resource_str,
						(unsigned long)desired.rlim_cur,
						(unsigned long)desired.rlim_max);
				}
			} else {
				dprintf( D_ALWAYS, "Workaround not applicable, no %s limit "
					"enforcement for %s.\n", kind_str, resource_str);
			}

		} else {
			/* if this is something other than a permission problem
				given the legal use of the setrlimit() interface */

			EXCEPT( "Failed to set %s limits for %s. "
			"setrlimit(%d, new = [rlim_cur = %lu, rlim_max = %lu]) : "
			"old = [rlim_cur = %lu, rlim_max = %lu], errno: %d(%s). \n",
			kind_str,
			resource_str,
			resource,
			(unsigned long)desired.rlim_cur,
			(unsigned long)desired.rlim_max,
			(unsigned long)current.rlim_cur,
			(unsigned long)current.rlim_max,
			errno,
			strerror(errno) );
		}
	}

	(void)SetSyscalls( scm );
}

} /* extern "C" */
<commit_msg>Make failure to setrlmit fds non-fatal #7470<commit_after>/***************************************************************
 *
 * Copyright (C) 1990-2007, Condor Team, Computer Sciences Department,
 * University of Wisconsin-Madison, WI.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you
 * may not use this file except in compliance with the License.  You may
 * obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 ***************************************************************/

#include "condor_common.h"
#include "condor_debug.h"
#include "condor_syscall_mode.h"
#include "limit.h"

extern "C" {

void
limit( int resource, rlim_t new_limit, int kind, char const *resource_str )
{
	int		scm;
	struct	rlimit current = {0,0};
	struct	rlimit desired = {0,0};
	char const *kind_str = "";

	scm = SetSyscalls( SYS_LOCAL | SYS_RECORDED );

	/* Find out current limit for this resource */
	if( getrlimit(resource, &current) < 0 ) {
		EXCEPT( "getrlimit(%d (%s)): errno: %d(%s)",
					resource, resource_str, errno, strerror(errno));
	}

	switch(kind) {
		case CONDOR_SOFT_LIMIT:
			/* Make a new rlimit structure that holds what I desire to be
				true */
			desired.rlim_cur = new_limit;
			desired.rlim_max = current.rlim_max;
			kind_str = "soft";

			/* Don't try to exceed the hard max as supplied by getrlimit() */
			if( desired.rlim_cur > desired.rlim_max ) {
				desired.rlim_cur = desired.rlim_max;
			}

			break;

		case CONDOR_HARD_LIMIT:
			desired.rlim_cur = new_limit;
			desired.rlim_max = new_limit;
			kind_str = "hard";

			if ((desired.rlim_max > current.rlim_max) && (getuid() != (pid_t)0))
			{
				/* Due to the fact that this code
					path will happen a lot as a non
					root user due to the the behavior
					in Create_Process where we always
					try to set the core hard limit to
					the maximum of size_t by default,
					we will by default ALWAYS ask
					for a limit which may be larger
					than the current hard max of
					this limit. Especially in the
					case of a personal Condor this
					will result in whatever message
					being written here being printed
					out *all the time*. So, instead
					of doing a dprintf for SNAFU
					behavior, we silently truncate
					the asked for limit the to
					current hard max if it is greater.
				*/

				desired = current;

				desired.rlim_cur = desired.rlim_max;
			}

			break;

		case CONDOR_REQUIRED_LIMIT:
			desired.rlim_cur = new_limit;
			desired.rlim_max = current.rlim_max;
			kind_str = "required";

				// only raise the hard limit if necessary
			if( desired.rlim_cur > desired.rlim_max ) {
				desired.rlim_max = desired.rlim_cur;
			}

			break;

		default:
			EXCEPT("do_limit() unknown limit enforcment policy. Programmer "
				"Error.");
			break;
	}

	/* Set the new limit */
	if( setrlimit(resource, &desired) < 0 ) {
		if (errno == EPERM && kind != CONDOR_REQUIRED_LIMIT ) {
		/* Under tru64, this setrlimit() fails oddly in that we
			are following the API restrictions exactly(not
			adjusting the maximum up as non-root, and not
			asking for more soft limit than hard limit),
			but still the kernel refuses to honor the
			change we wish to make and responds with a
			nonsensical EPERM failure. So we'll see if we
			can do something reasonable before giving up
			and not setting it at all. This code will be
			kept common for all architectures in the hopes
			that it will handle failures of this kind
			everywhere. We're going to try and bound the
			resource limit to UINT_MAX if we are able. */

		dprintf( D_ALWAYS,
			"Unexpected permissions failure in setting %s limit for %s"
			"setrlimit(%d, new = [rlim_cur = %lu, rlim_max = %lu]) : "
			"old = [rlim_cur = %lu, rlim_max = %lu], errno: %d(%s). Attempting "
			"workaround.\n",
			kind_str,
			resource_str,
			resource,
			(unsigned long)desired.rlim_cur,
			(unsigned long)desired.rlim_max,
			(unsigned long)current.rlim_cur,
			(unsigned long)current.rlim_max,
			errno,
			strerror(errno) );

			/* bound the resource limit to UINT_MAX, if I can */
			if (desired.rlim_cur > UINT_MAX &&
				current.rlim_max >= UINT_MAX)
			{
				desired.rlim_cur = UINT_MAX;
				if (setrlimit(resource, &desired) < 0) {
					dprintf( D_ALWAYS, "Workaround failed with error %d(%s). "
						"Not adjusting %s limit for %s\n",
						errno, strerror(errno), kind_str, resource_str);

				} else {
					dprintf( D_ALWAYS, "Workaround enabled. The %s limit for "
						"%s is this: "
						"new = [rlim_cur = %lu, rlim_max = %lu]\n",
						kind_str,resource_str,
						(unsigned long)desired.rlim_cur,
						(unsigned long)desired.rlim_max);
				}
			} else {
				dprintf( D_ALWAYS, "Workaround not applicable, no %s limit "
					"enforcement for %s.\n", kind_str, resource_str);
			}

		} else {
			/* if this is something other than a permission problem
				given the legal use of the setrlimit() interface */

			dprintf(D_ALWAYS, "Failed to set %s limits for %s. "
			"setrlimit(%d, new = [rlim_cur = %lu, rlim_max = %lu]) : "
			"old = [rlim_cur = %lu, rlim_max = %lu], errno: %d(%s). \n",
			kind_str,
			resource_str,
			resource,
			(unsigned long)desired.rlim_cur,
			(unsigned long)desired.rlim_max,
			(unsigned long)current.rlim_cur,
			(unsigned long)current.rlim_max,
			errno,
			strerror(errno) );
		}
	}

	(void)SetSyscalls( scm );
}

} /* extern "C" */
<|endoftext|>


<commit_before>/////////////////////////////////////////////////////////////////////////
// $Id: stack64.cc,v 1.6 2002/09/20 23:17:51 kevinlawton Exp $
/////////////////////////////////////////////////////////////////////////
//
//  Copyright (C) 2001  MandrakeSoft S.A.
//
//    MandrakeSoft S.A.
//    43, rue d'Aboukir
//    75002 Paris - France
//    http://www.linux-mandrake.com/
//    http://www.mandrakesoft.com/
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Lesser General Public
//  License as published by the Free Software Foundation; either
//  version 2 of the License, or (at your option) any later version.
//
//  This library 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
//  Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with this library; if not, write to the Free Software
//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA

#define NEED_CPU_REG_SHORTCUTS 1
#include "bochs.h"
#define LOG_THIS BX_CPU_THIS_PTR

#if BX_USE_CPU_SMF
#define this (BX_CPU(0))
#endif

  void
BX_CPU_C::POP_Eq(bxInstruction_c *i)
{
  Bit64u val64;

  pop_64(&val64);

  if (i->modC0()) {
    BX_WRITE_64BIT_REG(i->rm(), val64);
    }
  else {
    // Note: there is one little weirdism here.  When 64bit addressing
    // is used, it is possible to use RSP in the modrm addressing.
    // If used, the value of RSP after the pop is used to calculate
    // the address.
    if (i->as64L() && (!i->modC0()) && (i->rm()==4) && (i->sibBase()==4)) {
      // call method on BX_CPU_C object
      BX_CPU_CALL_METHOD (i->ResolveModrm, (i));
      }
    write_virtual_qword(i->seg(), RMAddr(i), &val64);
    }
}

  void
BX_CPU_C::PUSH_RRX(bxInstruction_c *i)
{
  push_64(BX_CPU_THIS_PTR gen_reg[i->opcodeReg()].rrx);
}

  void
BX_CPU_C::POP_RRX(bxInstruction_c *i)
{
  Bit64u rrx;

  pop_64(&rrx);
  BX_CPU_THIS_PTR gen_reg[i->opcodeReg()].rrx = rrx;
}

  void
BX_CPU_C::PUSH64_CS(bxInstruction_c *i)
{
  push_64(BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value);
}
  void
BX_CPU_C::PUSH64_DS(bxInstruction_c *i)
{
  push_64(BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].selector.value);
}
  void
BX_CPU_C::PUSH64_ES(bxInstruction_c *i)
{
  push_64(BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].selector.value);
}
  void
BX_CPU_C::PUSH64_FS(bxInstruction_c *i)
{
  push_64(BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS].selector.value);
}
  void
BX_CPU_C::PUSH64_GS(bxInstruction_c *i)
{
  push_64(BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS].selector.value);
}
  void
BX_CPU_C::PUSH64_SS(bxInstruction_c *i)
{
  push_64(BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].selector.value);
}

  void
BX_CPU_C::POP64_DS(bxInstruction_c *i)
{
  Bit64u ds;
  pop_64(&ds);
  load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS], (Bit16u) ds);
}
  void
BX_CPU_C::POP64_ES(bxInstruction_c *i)
{
  Bit64u es;
  pop_64(&es);
  load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES], (Bit16u) es);
}
  void
BX_CPU_C::POP64_FS(bxInstruction_c *i)
{
  Bit64u fs;
  pop_64(&fs);
  load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS], (Bit16u) fs);
}
  void
BX_CPU_C::POP64_GS(bxInstruction_c *i)
{
  Bit64u gs;
  pop_64(&gs);
  load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS], (Bit16u) gs);
}
  void
BX_CPU_C::POP64_SS(bxInstruction_c *i)
{
  Bit64u ss;
  pop_64(&ss);
  load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS], (Bit16u) ss);

  // POP SS inhibits interrupts, debug exceptions and single-step
  // trap exceptions until the execution boundary following the
  // next instruction is reached.
  // Same code as MOV_SwEw()
  BX_CPU_THIS_PTR inhibit_mask |=
    BX_INHIBIT_INTERRUPTS | BX_INHIBIT_DEBUG;
  BX_CPU_THIS_PTR async_event = 1;
}

  void
BX_CPU_C::PUSHAD64(bxInstruction_c *i)
{
#if BX_CPU_LEVEL < 2
  BX_PANIC(("PUSHAD: not supported on an 8086"));
#else
  Bit64u temp_RSP;
  Bit64u rsp;

  temp_RSP = RSP;
  if ( !can_push(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache, temp_RSP, 64) ) {
    BX_PANIC(("PUSHAD(): stack doesn't have enough room!"));
    exception(BX_SS_EXCEPTION, 0, 0);
    return;
    }

  rsp = RSP;

  /* ??? optimize this by using virtual write, all checks passed */
  push_64(RAX);
  push_64(RCX);
  push_64(RDX);
  push_64(RBX);
  push_64(rsp);
  push_64(RBP);
  push_64(RSI);
  push_64(RDI);
#endif
}

  void
BX_CPU_C::POPAD64(bxInstruction_c *i)
{
#if BX_CPU_LEVEL < 2
  BX_PANIC(("POPAD not supported on an 8086"));
#else /* 286+ */
    Bit64u rdi, rsi, rbp, rtmp, rbx, rdx, rcx, rax;

    if ( !can_pop(64) ) {
      BX_PANIC(("pop_ad: not enough bytes on stack"));
      exception(BX_SS_EXCEPTION, 0, 0);
      return;
      }

    /* ??? optimize this */
    pop_64(&rdi);
    pop_64(&rsi);
    pop_64(&rbp);
    pop_64(&rtmp); /* value for ESP discarded */
    pop_64(&rbx);
    pop_64(&rdx);
    pop_64(&rcx);
    pop_64(&rax);

    RDI = rdi;
    RSI = rsi;
    RBP = rbp;
    RBX = rbx;
    RDX = rdx;
    RCX = rcx;
    RAX = rax;
#endif
}

  void
BX_CPU_C::PUSH64_Id(bxInstruction_c *i)
{
#if BX_CPU_LEVEL < 2
  BX_PANIC(("PUSH_Id: not supported on 8086!"));
#else

    Bit64u imm64;

    imm64 = (Bit32s) i->Id();

    push_64(imm64);
#endif
}

  void
BX_CPU_C::PUSH_Eq(bxInstruction_c *i)
{
    Bit64u op1_64;

    /* op1_64 is a register or memory reference */
    if (i->modC0()) {
      op1_64 = BX_READ_64BIT_REG(i->rm());
      }
    else {
      /* pointer, segment address pair */
      read_virtual_qword(i->seg(), RMAddr(i), &op1_64);
      }

    push_64(op1_64);
}

  void
BX_CPU_C::ENTER64_IwIb(bxInstruction_c *i)
{
#if BX_CPU_LEVEL < 2
  BX_PANIC(("ENTER_IwIb: not supported by 8086!"));
#else
  Bit64u frame_ptr64;
  Bit16u frame_ptr16;
  Bit8u level;
  static Bit8u first_time = 1;

  level = i->Ib2();

  invalidate_prefetch_q();

  level %= 32;
/* ??? */
  if (first_time && level>0) {
    BX_ERROR(("enter() with level > 0. The emulation of this instruction may not be complete.  This warning will be printed only once per bochs run."));
    first_time = 0;
  }
//if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.d_b && i->os64L()==0) {
//  BX_INFO(("enter(): stacksize!=opsize: I'm unsure of the code for this"));
//  BX_PANIC(("         The Intel manuals are a mess on this one!"));
//  }

    {
    Bit64u bytes_to_push, temp_RSP;

    if (level == 0) {
      bytes_to_push = 8 + i->Iw();
      }
    else { /* level > 0 */
      bytes_to_push = 8 + (level-1)*8 + 8 + i->Iw();
      }
    temp_RSP = RSP;
    if ( !can_push(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache, temp_RSP, bytes_to_push) ) {
      BX_PANIC(("ENTER: not enough room on stack!"));
      exception(BX_SS_EXCEPTION, 0, 0);
      }
    }

  push_64(RBP);

  frame_ptr64 = RSP;

  if (level > 0) {
    /* do level-1 times */
    while (--level) {
      Bit64u temp64;

      RBP -= 4;
      read_virtual_qword(BX_SEG_REG_SS, RBP, &temp64);
      ESP -= 4;
      write_virtual_qword(BX_SEG_REG_SS, RSP, &temp64);
      } /* while (--level) */

    /* push(frame pointer) */
    RSP -= 4;
    write_virtual_qword(BX_SEG_REG_SS, RSP, &frame_ptr64);
    } /* if (level > 0) ... */

  RBP = frame_ptr64;

  RSP = RSP - i->Iw();
#endif
}

  void
BX_CPU_C::LEAVE64(bxInstruction_c *i)
{
#if BX_CPU_LEVEL < 2
  BX_PANIC(("LEAVE: not supported by 8086!"));
#else
  // delete frame
  RSP = RBP;

  // restore frame pointer
  {
  Bit64u temp64;

  pop_64(&temp64);
  RBP = temp64;
  }
#endif
}
<commit_msg>Removed several "#if BX_CPU_LEVEL < 2" clauses, since stack64.cc   is only compiled for x86-64.<commit_after>/////////////////////////////////////////////////////////////////////////
// $Id: stack64.cc,v 1.7 2002/10/06 21:38:02 kevinlawton Exp $
/////////////////////////////////////////////////////////////////////////
//
//  Copyright (C) 2001  MandrakeSoft S.A.
//
//    MandrakeSoft S.A.
//    43, rue d'Aboukir
//    75002 Paris - France
//    http://www.linux-mandrake.com/
//    http://www.mandrakesoft.com/
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Lesser General Public
//  License as published by the Free Software Foundation; either
//  version 2 of the License, or (at your option) any later version.
//
//  This library 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
//  Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with this library; if not, write to the Free Software
//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA

#define NEED_CPU_REG_SHORTCUTS 1
#include "bochs.h"
#define LOG_THIS BX_CPU_THIS_PTR

#if BX_USE_CPU_SMF
#define this (BX_CPU(0))
#endif

  void
BX_CPU_C::POP_Eq(bxInstruction_c *i)
{
  Bit64u val64;

  pop_64(&val64);

  if (i->modC0()) {
    BX_WRITE_64BIT_REG(i->rm(), val64);
    }
  else {
    // Note: there is one little weirdism here.  When 64bit addressing
    // is used, it is possible to use RSP in the modrm addressing.
    // If used, the value of RSP after the pop is used to calculate
    // the address.
    if (i->as64L() && (!i->modC0()) && (i->rm()==4) && (i->sibBase()==4)) {
      // call method on BX_CPU_C object
      BX_CPU_CALL_METHOD (i->ResolveModrm, (i));
      }
    write_virtual_qword(i->seg(), RMAddr(i), &val64);
    }
}

  void
BX_CPU_C::PUSH_RRX(bxInstruction_c *i)
{
  push_64(BX_CPU_THIS_PTR gen_reg[i->opcodeReg()].rrx);
}

  void
BX_CPU_C::POP_RRX(bxInstruction_c *i)
{
  Bit64u rrx;

  pop_64(&rrx);
  BX_CPU_THIS_PTR gen_reg[i->opcodeReg()].rrx = rrx;
}

  void
BX_CPU_C::PUSH64_CS(bxInstruction_c *i)
{
  push_64(BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value);
}
  void
BX_CPU_C::PUSH64_DS(bxInstruction_c *i)
{
  push_64(BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].selector.value);
}
  void
BX_CPU_C::PUSH64_ES(bxInstruction_c *i)
{
  push_64(BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].selector.value);
}
  void
BX_CPU_C::PUSH64_FS(bxInstruction_c *i)
{
  push_64(BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS].selector.value);
}
  void
BX_CPU_C::PUSH64_GS(bxInstruction_c *i)
{
  push_64(BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS].selector.value);
}
  void
BX_CPU_C::PUSH64_SS(bxInstruction_c *i)
{
  push_64(BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].selector.value);
}

  void
BX_CPU_C::POP64_DS(bxInstruction_c *i)
{
  Bit64u ds;
  pop_64(&ds);
  load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS], (Bit16u) ds);
}
  void
BX_CPU_C::POP64_ES(bxInstruction_c *i)
{
  Bit64u es;
  pop_64(&es);
  load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES], (Bit16u) es);
}
  void
BX_CPU_C::POP64_FS(bxInstruction_c *i)
{
  Bit64u fs;
  pop_64(&fs);
  load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS], (Bit16u) fs);
}
  void
BX_CPU_C::POP64_GS(bxInstruction_c *i)
{
  Bit64u gs;
  pop_64(&gs);
  load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS], (Bit16u) gs);
}
  void
BX_CPU_C::POP64_SS(bxInstruction_c *i)
{
  Bit64u ss;
  pop_64(&ss);
  load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS], (Bit16u) ss);

  // POP SS inhibits interrupts, debug exceptions and single-step
  // trap exceptions until the execution boundary following the
  // next instruction is reached.
  // Same code as MOV_SwEw()
  BX_CPU_THIS_PTR inhibit_mask |=
    BX_INHIBIT_INTERRUPTS | BX_INHIBIT_DEBUG;
  BX_CPU_THIS_PTR async_event = 1;
}

  void
BX_CPU_C::PUSHAD64(bxInstruction_c *i)
{
  Bit64u temp_RSP;
  Bit64u rsp;

  temp_RSP = RSP;
  if ( !can_push(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache, temp_RSP, 64) ) {
    BX_PANIC(("PUSHAD(): stack doesn't have enough room!"));
    exception(BX_SS_EXCEPTION, 0, 0);
    return;
    }

  rsp = RSP;

  /* ??? optimize this by using virtual write, all checks passed */
  push_64(RAX);
  push_64(RCX);
  push_64(RDX);
  push_64(RBX);
  push_64(rsp);
  push_64(RBP);
  push_64(RSI);
  push_64(RDI);
}

  void
BX_CPU_C::POPAD64(bxInstruction_c *i)
{
    Bit64u rdi, rsi, rbp, rtmp, rbx, rdx, rcx, rax;

    if ( !can_pop(64) ) {
      BX_PANIC(("pop_ad: not enough bytes on stack"));
      exception(BX_SS_EXCEPTION, 0, 0);
      return;
      }

    /* ??? optimize this */
    pop_64(&rdi);
    pop_64(&rsi);
    pop_64(&rbp);
    pop_64(&rtmp); /* value for ESP discarded */
    pop_64(&rbx);
    pop_64(&rdx);
    pop_64(&rcx);
    pop_64(&rax);

    RDI = rdi;
    RSI = rsi;
    RBP = rbp;
    RBX = rbx;
    RDX = rdx;
    RCX = rcx;
    RAX = rax;
}

  void
BX_CPU_C::PUSH64_Id(bxInstruction_c *i)
{
    Bit64u imm64;

    imm64 = (Bit32s) i->Id();

    push_64(imm64);
}

  void
BX_CPU_C::PUSH_Eq(bxInstruction_c *i)
{
    Bit64u op1_64;

    /* op1_64 is a register or memory reference */
    if (i->modC0()) {
      op1_64 = BX_READ_64BIT_REG(i->rm());
      }
    else {
      /* pointer, segment address pair */
      read_virtual_qword(i->seg(), RMAddr(i), &op1_64);
      }

    push_64(op1_64);
}

  void
BX_CPU_C::ENTER64_IwIb(bxInstruction_c *i)
{
  Bit64u frame_ptr64;
  Bit16u frame_ptr16;
  Bit8u level;
  static Bit8u first_time = 1;

  level = i->Ib2();

  invalidate_prefetch_q();

  level %= 32;
/* ??? */
  if (first_time && level>0) {
    BX_ERROR(("enter() with level > 0. The emulation of this instruction may not be complete.  This warning will be printed only once per bochs run."));
    first_time = 0;
  }
//if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.d_b && i->os64L()==0) {
//  BX_INFO(("enter(): stacksize!=opsize: I'm unsure of the code for this"));
//  BX_PANIC(("         The Intel manuals are a mess on this one!"));
//  }

    {
    Bit64u bytes_to_push, temp_RSP;

    if (level == 0) {
      bytes_to_push = 8 + i->Iw();
      }
    else { /* level > 0 */
      bytes_to_push = 8 + (level-1)*8 + 8 + i->Iw();
      }
    temp_RSP = RSP;
    if ( !can_push(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache, temp_RSP, bytes_to_push) ) {
      BX_PANIC(("ENTER: not enough room on stack!"));
      exception(BX_SS_EXCEPTION, 0, 0);
      }
    }

  push_64(RBP);

  frame_ptr64 = RSP;

  if (level > 0) {
    /* do level-1 times */
    while (--level) {
      Bit64u temp64;

      RBP -= 4;
      read_virtual_qword(BX_SEG_REG_SS, RBP, &temp64);
      ESP -= 4;
      write_virtual_qword(BX_SEG_REG_SS, RSP, &temp64);
      } /* while (--level) */

    /* push(frame pointer) */
    RSP -= 4;
    write_virtual_qword(BX_SEG_REG_SS, RSP, &frame_ptr64);
    } /* if (level > 0) ... */

  RBP = frame_ptr64;

  RSP = RSP - i->Iw();
}

  void
BX_CPU_C::LEAVE64(bxInstruction_c *i)
{
  // delete frame
  RSP = RBP;

  // restore frame pointer
  {
  Bit64u temp64;

  pop_64(&temp64);
  RBP = temp64;
  }
}
<|endoftext|>


<commit_before>/*Implement double linked list by pointer*/
#include <iostream>
using namespace std;

class Link{
public:
    string value;
    Link(const string& v, Link* p = nullptr, Link* n = nullptr)
        : value(v), prev_(p), next_(n) {}
    Link* insert(Link* n);          /*Insert n before this object*/
    Link* add(Link* n);             /*Insert n after this object*/
    Link* erase();                  /*Remove this object from list*/
    Link* find(const string& s);    /*Find s in const list*/
    const Link* find(const string& s) const;

    Link* advance(int n) const;     /*Move n position in list*/

    Link* next() const{ return next_;}
    Link* prev() const{ return prev_;}

private:
    Link* prev_;
    Link* next_;
};

/*Implement*/

Link* Link::insert(Link* n){
    if(n == nullptr) return this;
    if(this == nullptr) return n;

    n->next_ = this;
    if(prev_)
        prev_->next_ = n;
    n->prev_ = prev_;
    prev_ = n;

    return n;
}

/*Insert n after this object*/
Link* Link::add(Link* n){
    if(n == nullptr) return this;
    if(this == nullptr) return n;
    n->next_ = next_;
    if(next_)
        next_->prev_ = n;
    next_ = n;

    return n;
}
// Remove this object from list
Link* Link::erase(){
    if(this == nullptr) this;
    prev_->next_ = next_;
    if(next_)
        next_->prev_ = prev_;
    delete this;
}
/*Find s in const list*/
Link* Link::find(const string& s){
    while(this != nullptr){
        if(value == s)
            return this;
        prev_ = this;
        next_ = next_->next_;
    }
    return nullptr;
}

int main(int argc, char const *argv[])
{
    Link* norse_gods = new Link("Thor");
    norse_gods = norse_gods->insert(new Link("Odin"));
    norse_gods = norse_gods->insert(new Link("Zeus"));
    return 0;
}

<commit_msg>Add list.cpp<commit_after>/*Implement double linked list by pointer*/
#include <iostream>
using namespace std;

class Link{
public:
    string value;
    Link(const string& v, Link* p = nullptr, Link* n = nullptr)
        : value(v), prev_(p), next_(n) {}
    Link* insert(Link* n);          /*Insert n before this object*/
    Link* add(Link* n);             /*Insert n after this object*/
    Link* erase();                  /*Remove this object from list*/
    Link* find(const string& s);    /*Find s in const list*/
    const Link* find(const string& s) const;

    Link* advance(int n) const;     /*Move n position in list*/

    Link* next() const{ return next_;}
    Link* prev() const{ return prev_;}

private:
    Link* prev_;
    Link* next_;
};

/*Implement*/

Link* Link::insert(Link* n){
    if(n == nullptr) return this;
    if(this == nullptr) return n;

    n->next_ = this;
    if(prev_)
        prev_->next_ = n;
    n->prev_ = prev_;
    prev_ = n;

    return n;
}

/*Insert n after this object*/
Link* Link::add(Link* n){
    if(n == nullptr) return this;
    if(this == nullptr) return n;
    n->next_ = next_;
    if(next_)
        next_->prev_ = n;
    next_ = n;

    return n;
}
// Remove this object from list
Link* Link::erase(){
    if(this == nullptr) this;
    prev_->next_ = next_;
    if(next_)
        next_->prev_ = prev_;
    delete this;
}
/*Find s in const list*/
Link* Link::find(const string& s){
    while(this != nullptr){
        if(value == s)
            return this;
        prev_ = this;
        next_ = next_->next_;
    }
    return nullptr;
}

void print_all(Link* p){
    cout << "{" ;
    while(p){
        cout << p->value;
        if(p = p->next()) cout << ",";
    }
    cout << "}";
}

int main(int argc, char const *argv[])
{
    Link* norse_gods = new Link("Thor");
    norse_gods = norse_gods->insert(new Link("Odin"));
    norse_gods = norse_gods->insert(new Link("Zeus"));

    print_all(norse_gods);
    return 0;
}

<|endoftext|>


<commit_before>#pragma once
//=========================================================================//
/*!	@file
	@brief	FT5206 class @n
			FocalTech @n
			Capacitive Touch Panel Controller ドライバー @n
			・I2C 割り込み対応 @n
			・２点同時までのタッチ位置を補足
    @author 平松邦仁 (hira@rvf-rc45.net)
	@copyright	Copyright (C) 2018 Kunihito Hiramatsu @n
				Released under the MIT license @n
				https://github.com/hirakuni45/RX/blob/master/LICENSE
*/
//=========================================================================//
#include <cstdint>
#include "common/delay.hpp"

namespace chip {

	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	/*!
		@brief  FT5206 テンプレートクラス
		@param[in]	I2C	I2C 制御クラス
	*/
	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	template <class I2C>
	class FT5206 {
	public:
		//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
		/*!
			@brief  Touch Event Type
		*/
		//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
		enum class EVENT : uint8_t {
			DOWN,		///< Touch Down
			UP,			///< Touch Up
			CONTACT,	///< Contact
			NONE
		};

		//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
		/*!
			@brief  Touch Struct
		*/
		//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
		struct xy {
			EVENT		before;	///< Touch Event (before)
			EVENT		event;	///< Touch Event
			uint8_t		id;		///< Touch ID
			int16_t		x;		///< Touch Position X
			int16_t		y;		///< Touch Position Y
			int16_t		org_x;	///< Touch Down Position X
			int16_t		org_y;	///< Touch Down Position Y
			int16_t		end_x;	///< Touch Up Position X
			int16_t		end_y;	///< Touch Up Position Y

			//-------------------------------------------------------------//
			/*!
				@brief	コンストラクター
			 */
			//-------------------------------------------------------------//
			xy() noexcept : before(EVENT::NONE), event(EVENT::NONE), id(0), x(0), y(0),
				   org_x(0), org_y(0), end_x(0), end_y(0) { }

			//-------------------------------------------------------------//
			/*!
				@brief	ドラッグされた距離の二乗を返す
				@return ドラッグされた距離の二乗
			 */
			//-------------------------------------------------------------//
			uint32_t length_sqr() const noexcept
			{
				auto dx = end_x - org_x;
				auto dy = end_y - org_y;
				return dx * dx + dy * dy;
			}
		};

	private:

		static const uint8_t	FT5206_ADR = 0x38;

		I2C&	i2c_;

		enum class REG : uint8_t {
			DEVICE_MODE,		// R/W
			GEST_ID,			// R
			TD_STATUS,			// R
			TOUCH_XH,			// R
			TOUCH_XL,			// R
			TOUCH_YH,			// R
			TOUCH_YL,			// R

			TOUCH2_XH = 0x09,	// R
			TOUCH2_XL,			// R
			TOUCH2_YH,			// R
			TOUCH2_YL,			// R

			TOUCH3_XH = 0x0F,	// R
			TOUCH3_XL,			// R
			TOUCH3_YH,			// R
			TOUCH3_YL,			// R

			TOUCH4_XH = 0x15,	// R
			TOUCH4_XL,			// R
			TOUCH4_YH,			// R
			TOUCH4_YL,			// R

			TOUCH5_XH = 0x1B,	// R
			TOUCH5_XL,			// R
			TOUCH5_YH,			// R
			TOUCH5_YL,			// R

			ID_G_THGROUP = 0x80,		// R/W
			ID_G_THPEAK,				// R/W
			ID_G_THCAL,					// R/W
			ID_G_THWATER,				// R/W
			ID_G_THTEMP,				// R/W

			ID_G_CTRL = 0x86,			// R/W
			ID_G_TIME_ENTER_MONITOR,	// R/W
			ID_G_PERIODACTIVE,			// R/W
			ID_G_PERIODMONITOR,			// R/W

			ID_G_AUTO_CLB_MODE = 0xA0,	// R/W
			ID_G_LIB_VERSION_H,			// R
			ID_G_LIB_VERSION_L,			// R
			ID_G_CIPHER,				// R
			ID_G_MODE,					// R
			ID_G_PMODE,					// R
			ID_G_FIRMID,				// R
			ID_G_STATE,					// R
			ID_G_FT5201ID,				// R
			ID_G_ERR,					// R
			ID_G_CLB,					// R/W

			ID_G_B_AREA_TH = 0xAE,		// R/W

			LOG_MSG_CNT = 0xFE,			// R
			LOG_CUR_CHA					// R
		};

		uint8_t		touch_id_;
		uint8_t		touch_num_;
		bool		start_;
		bool		startup_;
		uint16_t	version_;
		uint8_t		chip_;
		uint8_t		touch_tmp_[12];
		xy			xy_[2];

		void write_(REG reg, uint8_t data) noexcept
		{
			uint8_t tmp[2];
			tmp[0] = static_cast<uint8_t>(reg);
			tmp[1] = data;
			i2c_.send(FT5206_ADR, tmp, sizeof(tmp));
			i2c_.sync();
		}

		uint8_t read_(REG reg) noexcept
		{
			uint8_t tmp[1];
			tmp[0] = static_cast<uint8_t>(reg);
			i2c_.send(FT5206_ADR, tmp, sizeof(tmp));
			i2c_.recv(FT5206_ADR, tmp, sizeof(tmp));
			i2c_.sync();
			return tmp[0];
		}

		void convert_touch_() noexcept
		{
			touch_id_  = touch_tmp_[0];  // GEST_ID
			touch_num_ = touch_tmp_[1] & 0x0f;  // TD_STATUS

			xy_[0].before = xy_[0].event;
			xy_[0].event = static_cast<EVENT>(touch_tmp_[2] >> 6);
			xy_[0].id = touch_tmp_[4] >> 4;
			xy_[0].x = (static_cast<int16_t>(touch_tmp_[2] & 0x0F) << 8)
				| static_cast<int16_t>(touch_tmp_[3]);
			xy_[0].y = (static_cast<int16_t>(touch_tmp_[4] & 0x0F) << 8)
				| static_cast<int16_t>(touch_tmp_[5]);

			xy_[1].before = xy_[1].event;
			xy_[1].event = static_cast<EVENT>(touch_tmp_[8] >> 6);
			xy_[1].id = touch_tmp_[10] >> 4;
			xy_[1].x = (static_cast<int16_t>(touch_tmp_[8] & 0x0F) << 8)
				| static_cast<int16_t>(touch_tmp_[9]);
			xy_[1].y = (static_cast<int16_t>(touch_tmp_[10] & 0x0F) << 8)
				| static_cast<int16_t>(touch_tmp_[11]);

			// イベントが不正なら、無効にする。
//			if(xy_[0].event == EVENT::NONE || xy_[1].event == EVENT::NONE) {
//				touch_num_ = 0;
//			}
#if 1
			if(xy_[0].event == EVENT::DOWN || xy_[1].event == EVENT::DOWN) {
				startup_ = true;
			}
			if(!startup_) {
				touch_num_ = 0;
			}
#endif
		}

		void request_touch_() noexcept
		{
			touch_tmp_[0] = static_cast<uint8_t>(REG::GEST_ID);
			i2c_.send(FT5206_ADR, touch_tmp_, 1);
			i2c_.recv(FT5206_ADR, touch_tmp_, sizeof(touch_tmp_));
		}

	public:
		//-----------------------------------------------------------------//
		/*!
			@brief	コンストラクター
			@param[in]	i2c	i2c 制御クラスを参照で渡す
		 */
		//-----------------------------------------------------------------//
		FT5206(I2C& i2c) noexcept : i2c_(i2c), touch_id_(0), touch_num_(0),
			start_(false), startup_(false),
			version_(0), chip_(0), touch_tmp_{ 0 }, xy_{ } { }

		//-----------------------------------------------------------------//
		/*!
			@brief	デバイスのバージョンを取得
			@return デバイスのバージョン
		 */
		//-----------------------------------------------------------------//
		uint16_t get_version() const noexcept { return version_; }

		//-----------------------------------------------------------------//
		/*!
			@brief	チップ・コードを取得
			@return チップ・コード
		 */
		//-----------------------------------------------------------------//
		uint8_t get_chip() const noexcept { return chip_; }

		//-----------------------------------------------------------------//
		/*!
			@brief	デバイス・リセット
			@param[in]	RES	リセット端子
		 */
		//-----------------------------------------------------------------//
		template <class RES>
		static void reset() noexcept {
			RES::DIR = 1;
			RES::P = 0;
			utils::delay::milli_second(5);
			RES::P = 1;
			utils::delay::milli_second(300);
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	開始
			@return 成功なら「true」
		 */
		//-----------------------------------------------------------------//
		bool start() noexcept
		{
			uint8_t tmp[3];
			tmp[0] = static_cast<uint8_t>(REG::ID_G_LIB_VERSION_H);
			if(!i2c_.send(FT5206_ADR, tmp, 1)) {
				utils::format("Send fail\n");
				return false;
			}
			i2c_.sync();

			tmp[0] = 0xff;
			tmp[1] = 0xff;
			tmp[2] = 0xff;
			if(!i2c_.recv(FT5206_ADR, tmp, sizeof(tmp))) {
				utils::format("Recv fail\n");
				return false;
			}
			i2c_.sync();
			version_ = (static_cast<uint16_t>(tmp[0]) << 8) | tmp[1];
			chip_ = tmp[2];

			write_(REG::DEVICE_MODE, 0x00);

			touch_num_ = 0;

			start_ = true;
			startup_ = false;

			return true;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	アップデート
		 */
		//-----------------------------------------------------------------//
		void update() noexcept
		{
			if(!start_) {
				return;
			}

			convert_touch_();
			request_touch_();

			for(uint8_t i = 0; i < 2; ++i) {
				if(xy_[i].event == EVENT::DOWN) {
					xy_[i].org_x = xy_[i].x;
					xy_[i].org_y = xy_[i].y;
				} else if(xy_[i].event == EVENT::UP) {
					xy_[i].end_x = xy_[i].x;
					xy_[i].end_y = xy_[i].y;
				}
			}
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	タッチ数を取得
			@return タッチ数
		 */
		//-----------------------------------------------------------------//
		uint8_t get_touch_num() const noexcept { return touch_num_; }

		//-----------------------------------------------------------------//
		/*!
			@brief	タッチ位置を取得
			@param[in]	idx	タッチ・インデックス（０～１）
			@return タッチ位置
		 */
		//-----------------------------------------------------------------//
		const xy& get_touch_pos(uint8_t idx) const noexcept { return xy_[idx & 1]; }
	};
}
<commit_msg>Update: for vtx::spos<commit_after>#pragma once
//=========================================================================//
/*!	@file
	@brief	FT5206 class @n
			FocalTech @n
			Capacitive Touch Panel Controller ドライバー @n
			・I2C 割り込み対応 @n
			・２点同時までのタッチ位置を補足
    @author 平松邦仁 (hira@rvf-rc45.net)
	@copyright	Copyright (C) 2018, 2019 Kunihito Hiramatsu @n
				Released under the MIT license @n
				https://github.com/hirakuni45/RX/blob/master/LICENSE
*/
//=========================================================================//
#include <cstdint>
#include "common/delay.hpp"
#include "common/vtx.hpp"

namespace chip {

	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	/*!
		@brief  FT5206 テンプレートクラス
		@param[in]	I2C	I2C 制御クラス
	*/
	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	template <class I2C>
	class FT5206 {
	public:
		//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
		/*!
			@brief  Touch Event Type
		*/
		//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
		enum class EVENT : uint8_t {
			DOWN,		///< Touch Down
			UP,			///< Touch Up
			CONTACT,	///< Contact
			NONE
		};

		//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
		/*!
			@brief  Touch Struct
		*/
		//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
		struct touch_t {
			EVENT		before;	///< Touch Event (before)
			EVENT		event;	///< Touch Event
			uint8_t		id;		///< Touch ID
			vtx::spos	pos;	///< Touch Position
			vtx::spos	org;	///< Touch Down Position
			vtx::spos	end;	///< Touch Up Position

			//-------------------------------------------------------------//
			/*!
				@brief	コンストラクター
			 */
			//-------------------------------------------------------------//
			touch_t() noexcept : before(EVENT::NONE), event(EVENT::NONE), id(0),
				pos(0), org(0), end(0) { }

			//-------------------------------------------------------------//
			/*!
				@brief	ドラッグされた距離の二乗を返す
				@return ドラッグされた距離の二乗
			 */
			//-------------------------------------------------------------//
			uint32_t length_sqr() const noexcept
			{
				auto d = end - org;
				return d.x * d.x + d.y * d.y;
			}
		};

	private:

		static const uint8_t	FT5206_ADR = 0x38;

		I2C&	i2c_;

		enum class REG : uint8_t {
			DEVICE_MODE,		// R/W
			GEST_ID,			// R
			TD_STATUS,			// R
			TOUCH_XH,			// R
			TOUCH_XL,			// R
			TOUCH_YH,			// R
			TOUCH_YL,			// R

			TOUCH2_XH = 0x09,	// R
			TOUCH2_XL,			// R
			TOUCH2_YH,			// R
			TOUCH2_YL,			// R

			TOUCH3_XH = 0x0F,	// R
			TOUCH3_XL,			// R
			TOUCH3_YH,			// R
			TOUCH3_YL,			// R

			TOUCH4_XH = 0x15,	// R
			TOUCH4_XL,			// R
			TOUCH4_YH,			// R
			TOUCH4_YL,			// R

			TOUCH5_XH = 0x1B,	// R
			TOUCH5_XL,			// R
			TOUCH5_YH,			// R
			TOUCH5_YL,			// R

			ID_G_THGROUP = 0x80,		// R/W
			ID_G_THPEAK,				// R/W
			ID_G_THCAL,					// R/W
			ID_G_THWATER,				// R/W
			ID_G_THTEMP,				// R/W

			ID_G_CTRL = 0x86,			// R/W
			ID_G_TIME_ENTER_MONITOR,	// R/W
			ID_G_PERIODACTIVE,			// R/W
			ID_G_PERIODMONITOR,			// R/W

			ID_G_AUTO_CLB_MODE = 0xA0,	// R/W
			ID_G_LIB_VERSION_H,			// R
			ID_G_LIB_VERSION_L,			// R
			ID_G_CIPHER,				// R
			ID_G_MODE,					// R
			ID_G_PMODE,					// R
			ID_G_FIRMID,				// R
			ID_G_STATE,					// R
			ID_G_FT5201ID,				// R
			ID_G_ERR,					// R
			ID_G_CLB,					// R/W

			ID_G_B_AREA_TH = 0xAE,		// R/W

			LOG_MSG_CNT = 0xFE,			// R
			LOG_CUR_CHA					// R
		};

		uint8_t		touch_id_;
		uint8_t		touch_num_;
		bool		start_;
		bool		startup_;
		uint16_t	version_;
		uint8_t		chip_;
		uint8_t		touch_tmp_[12];
		touch_t		t_[2];

		void write_(REG reg, uint8_t data) noexcept
		{
			uint8_t tmp[2];
			tmp[0] = static_cast<uint8_t>(reg);
			tmp[1] = data;
			i2c_.send(FT5206_ADR, tmp, sizeof(tmp));
			i2c_.sync();
		}

		uint8_t read_(REG reg) noexcept
		{
			uint8_t tmp[1];
			tmp[0] = static_cast<uint8_t>(reg);
			i2c_.send(FT5206_ADR, tmp, sizeof(tmp));
			i2c_.recv(FT5206_ADR, tmp, sizeof(tmp));
			i2c_.sync();
			return tmp[0];
		}

		void convert_touch_() noexcept
		{
			touch_id_  = touch_tmp_[0];  // GEST_ID
			touch_num_ = touch_tmp_[1] & 0x0f;  // TD_STATUS

			t_[0].before = t_[0].event;
			t_[0].event = static_cast<EVENT>(touch_tmp_[2] >> 6);
			t_[0].id = touch_tmp_[4] >> 4;
			t_[0].pos.x = (static_cast<int16_t>(touch_tmp_[2] & 0x0F) << 8)
				| static_cast<int16_t>(touch_tmp_[3]);
			t_[0].pos.y = (static_cast<int16_t>(touch_tmp_[4] & 0x0F) << 8)
				| static_cast<int16_t>(touch_tmp_[5]);

			t_[1].before = t_[1].event;
			t_[1].event = static_cast<EVENT>(touch_tmp_[8] >> 6);
			t_[1].id = touch_tmp_[10] >> 4;
			t_[1].pos.x = (static_cast<int16_t>(touch_tmp_[8] & 0x0F) << 8)
				| static_cast<int16_t>(touch_tmp_[9]);
			t_[1].pos.y = (static_cast<int16_t>(touch_tmp_[10] & 0x0F) << 8)
				| static_cast<int16_t>(touch_tmp_[11]);

			// イベントが不正なら、無効にする。
//			if(t_[0].event == EVENT::NONE || t_[1].event == EVENT::NONE) {
//				touch_num_ = 0;
//			}
#if 1
			if(t_[0].event == EVENT::DOWN || t_[1].event == EVENT::DOWN) {
				startup_ = true;
			}
			if(!startup_) {
				touch_num_ = 0;
			}
#endif
		}

		void request_touch_() noexcept
		{
			touch_tmp_[0] = static_cast<uint8_t>(REG::GEST_ID);
			i2c_.send(FT5206_ADR, touch_tmp_, 1);
			i2c_.recv(FT5206_ADR, touch_tmp_, sizeof(touch_tmp_));
		}

	public:
		//-----------------------------------------------------------------//
		/*!
			@brief	コンストラクター
			@param[in]	i2c	i2c 制御クラスを参照で渡す
		 */
		//-----------------------------------------------------------------//
		FT5206(I2C& i2c) noexcept : i2c_(i2c), touch_id_(0), touch_num_(0),
			start_(false), startup_(false),
			version_(0), chip_(0), touch_tmp_{ 0 }, t_{ } { }

		//-----------------------------------------------------------------//
		/*!
			@brief	デバイスのバージョンを取得
			@return デバイスのバージョン
		 */
		//-----------------------------------------------------------------//
		uint16_t get_version() const noexcept { return version_; }

		//-----------------------------------------------------------------//
		/*!
			@brief	チップ・コードを取得
			@return チップ・コード
		 */
		//-----------------------------------------------------------------//
		uint8_t get_chip() const noexcept { return chip_; }

		//-----------------------------------------------------------------//
		/*!
			@brief	デバイス・リセット
			@param[in]	RES	リセット端子
		 */
		//-----------------------------------------------------------------//
		template <class RES>
		static void reset() noexcept {
			RES::DIR = 1;
			RES::P = 0;
			utils::delay::milli_second(5);
			RES::P = 1;
			utils::delay::milli_second(300);
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	開始
			@return 成功なら「true」
		 */
		//-----------------------------------------------------------------//
		bool start() noexcept
		{
			uint8_t tmp[3];
			tmp[0] = static_cast<uint8_t>(REG::ID_G_LIB_VERSION_H);
			if(!i2c_.send(FT5206_ADR, tmp, 1)) {
				utils::format("Send fail\n");
				return false;
			}
			i2c_.sync();

			tmp[0] = 0xff;
			tmp[1] = 0xff;
			tmp[2] = 0xff;
			if(!i2c_.recv(FT5206_ADR, tmp, sizeof(tmp))) {
				utils::format("Recv fail\n");
				return false;
			}
			i2c_.sync();
			version_ = (static_cast<uint16_t>(tmp[0]) << 8) | tmp[1];
			chip_ = tmp[2];

			write_(REG::DEVICE_MODE, 0x00);

			touch_num_ = 0;

			start_ = true;
			startup_ = false;

			return true;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	アップデート
		 */
		//-----------------------------------------------------------------//
		void update() noexcept
		{
			if(!start_) {
				return;
			}

			convert_touch_();
			request_touch_();

			for(uint8_t i = 0; i < 2; ++i) {
				if(t_[i].event == EVENT::DOWN) {
					t_[i].org = t_[i].pos;
				} else if(t_[i].event == EVENT::UP) {
					t_[i].end = t_[i].pos;
				}
			}
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	タッチ数を取得
			@return タッチ数
		 */
		//-----------------------------------------------------------------//
		uint8_t get_touch_num() const noexcept { return touch_num_; }

		//-----------------------------------------------------------------//
		/*!
			@brief	タッチ位置を取得
			@param[in]	idx	タッチ・インデックス（０～１）
			@return タッチ位置
		 */
		//-----------------------------------------------------------------//
		const touch_t& get_touch_pos(uint8_t idx) const noexcept { return t_[idx & 1]; }
	};
}
<|endoftext|>


<commit_before>/*=========================================================================

  Program: Bender

  Copyright (c) Kitware Inc.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0.txt

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

=========================================================================*/

// Bender includes
#include "CreateTetrahedralMeshCLP.h"
#include "benderIOUtils.h"
#include "vtkBrokenCells.h"

// ITK includes
#include "itkBinaryThresholdImageFilter.h"
#include "itkCastImageFilter.h"
#include "itkImageFileWriter.h"
#include "itkImageRegionConstIterator.h"
#include "itkImageRegionIterator.h"
#include "itkRelabelComponentImageFilter.h"
#include "itkConstantPadImageFilter.h"

// Slicer includes
#include "itkPluginUtilities.h"

// VTK includes
#include <vtkCleanPolyData.h>
#include <vtkCellArray.h>
#include <vtkCellData.h>
#include <vtkTetra.h>
#include <vtkTransform.h>
#include <vtkTransformPolyDataFilter.h>
#include <vtkPolyData.h>
#include <vtkPolyDataWriter.h>
#include <vtkMath.h>
#include <vtkNew.h>
#include <vtkSmartPointer.h>

// Cleaver includes
#include <Cleaver/Cleaver.h>
#include <Cleaver/InverseField.h>
#include <Cleaver/PaddedVolume.h>
#include <Cleaver/ScalarField.h>
#include <Cleaver/Volume.h>
#include <LabelMapField.h>

// Use an anonymous namespace to keep class types and function names
// from colliding when module is used as shared object module.  Every
// thing should be in an anonymous namespace except for the module
// entry point, e.g. main()
//
namespace
{
template <class T> int DoIt( int argc, char * argv[] );

std::vector<Cleaver::LabelMapField::ImageType::Pointer> SplitLabelMaps(
  int    argc,
  char * argv[]);
} // end of anonymous namespace

int main( int argc, char * argv[] )
{

  PARSE_ARGS;

  itk::ImageIOBase::IOPixelType     pixelType;
  itk::ImageIOBase::IOComponentType componentType;

  try
    {
    itk::GetImageType(InputVolume, pixelType, componentType);

    switch( componentType )
      {
    case itk::ImageIOBase::UCHAR:
      return DoIt<unsigned char>( argc, argv );
      break;
    case itk::ImageIOBase::CHAR:
      return DoIt<char>( argc, argv );
      break;
    case itk::ImageIOBase::USHORT:
      return DoIt<unsigned short>( argc, argv );
      break;
    case itk::ImageIOBase::SHORT:
      return DoIt<short>( argc, argv );
      break;
    case itk::ImageIOBase::UINT:
      return DoIt<unsigned int>( argc, argv );
      break;
    case itk::ImageIOBase::INT:
      return DoIt<int>( argc, argv );
      break;
    case itk::ImageIOBase::ULONG:
      return DoIt<unsigned long>( argc, argv );
      break;
    case itk::ImageIOBase::LONG:
      return DoIt<long>( argc, argv );
      break;
    case itk::ImageIOBase::FLOAT:
      return DoIt<float>( argc, argv );
      break;
    case itk::ImageIOBase::DOUBLE:
      return DoIt<double>( argc, argv );
      break;
    case itk::ImageIOBase::UNKNOWNCOMPONENTTYPE:
    default:
      std::cerr << "Unknown component type: " << componentType << std::endl;
      break;
      }
    }

  catch( itk::ExceptionObject & excep )
    {
    std::cerr << argv[0] << ": exception caught !" << std::endl;
    std::cerr << excep << std::endl;
    return EXIT_FAILURE;
    }
  return EXIT_SUCCESS;
}

// Use an anonymous namespace to keep class types and function names
// from colliding when module is used as shared object module.  Every
// thing should be in an anonymous namespace except for the module
// entry point, e.g. main()
//
namespace
{
//----------------------------------------------------------------------------
//
//----------------------------------------------------------------------------
std::vector<Cleaver::LabelMapField::ImageType::Pointer >
SplitLabelMaps(Cleaver::LabelMapField::ImageType *image, bool verbose)
{

  typedef Cleaver::LabelMapField::ImageType LabelImageType;
  typedef itk::RelabelComponentImageFilter<LabelImageType,
                                           LabelImageType> RelabelFilterType;
  typedef itk::BinaryThresholdImageFilter<LabelImageType,
                                          LabelImageType> ThresholdFilterType;
  typedef itk::ImageFileWriter<LabelImageType> ImageWriterType;

  // Assign continuous labels to the connected components, background is
  // considered to be 0 and will be ignored in the relabeling process.
  RelabelFilterType::Pointer relabelFilter = RelabelFilterType::New();
  relabelFilter->SetInput( image );
  relabelFilter->Update();

  if (verbose)
    {
    std::cout << "Total Number of Labels: " <<
      relabelFilter->GetNumberOfObjects() << std::endl;
    }

  // Extract the labels
  typedef RelabelFilterType::LabelType LabelType;
  ThresholdFilterType::Pointer skinThresholdFilter =
    ThresholdFilterType::New();

  // Create a list of images corresponding to labels
  std::vector<LabelImageType::Pointer> labels;

  // The skin label will become background for internal (smaller) organs
  skinThresholdFilter->SetInput(relabelFilter->GetOutput());
  skinThresholdFilter->SetLowerThreshold(1);
  skinThresholdFilter->SetUpperThreshold(relabelFilter->GetNumberOfObjects()+1);
  skinThresholdFilter->SetInsideValue(-1);
  skinThresholdFilter->SetOutsideValue(0);
  skinThresholdFilter->Update();
  labels.push_back(skinThresholdFilter->GetOutput());

  for (LabelType i = 1, end = relabelFilter->GetNumberOfObjects()+1; i < end;
       ++i)
    {
    ThresholdFilterType::Pointer organThresholdFilter =
      ThresholdFilterType::New();
    organThresholdFilter->SetInput(relabelFilter->GetOutput());
    organThresholdFilter->SetLowerThreshold(i);
    organThresholdFilter->SetUpperThreshold(i);
    organThresholdFilter->SetInsideValue(i);
    organThresholdFilter->SetOutsideValue(-1);
    organThresholdFilter->Update();

    labels.push_back(organThresholdFilter->GetOutput());
    }

  return labels;
}

//----------------------------------------------------------------------------
bool IsPointInvalid(Cleaver::vec3 pos)
{
  return vtkBrokenCells::IsPointValid(pos.x, pos.y, pos.z);
}

//----------------------------------------------------------------------------
//
//----------------------------------------------------------------------------
template <class T>
int DoIt( int argc, char * argv[] )
{

  PARSE_ARGS;

  typedef Cleaver::LabelMapField::ImageType LabelImageType;
  typedef T InputPixelType;
  typedef itk::Image<InputPixelType,3> InputImageType;
  typedef itk::CastImageFilter<InputImageType,
                               LabelImageType> CastFilterType;
  typedef itk::ImageFileReader<InputImageType> ReaderType;
  typedef itk::ConstantPadImageFilter<InputImageType,
                                      InputImageType> ConstantPadType;

  typename ReaderType::Pointer reader            = ReaderType::New();
  reader->SetFileName( InputVolume );
  reader->Update();

  typename CastFilterType::Pointer castingFilter = CastFilterType::New();
  castingFilter->SetInput(reader->GetOutput());

  std::vector<Cleaver::ScalarField*> labelMaps;

  std::vector<LabelImageType::Pointer> labels =
    SplitLabelMaps(castingFilter->GetOutput(), Verbose);

  // Get a map from the original labels to the new labels
  std::map<InputPixelType, InputPixelType> originalLabels;

  for(size_t i = 0; i < labels.size(); ++i)
    {
    itk::ImageRegionConstIterator<InputImageType> imageIterator(
      reader->GetOutput(), reader->GetOutput()->GetLargestPossibleRegion());
    itk::ImageRegionConstIterator<LabelImageType> labelsIterator(
      labels[i], labels[i]->GetLargestPossibleRegion());
    bool foundCorrespondence = false;
    while(!imageIterator.IsAtEnd()
      && !labelsIterator.IsAtEnd()
      && !foundCorrespondence)
      {
      if (labelsIterator.Value() > 0)
        {
        originalLabels[labelsIterator.Value()] = imageIterator.Value();
        }

      ++imageIterator;
      ++labelsIterator;
      }
    }

  if (Verbose)
    {
    std::cout << "Total labels found:  " << labels.size() << std::endl;
    }
  for(size_t i = 0; i < labels.size(); ++i)
    {
    labelMaps.push_back(new Cleaver::LabelMapField(labels[i]));
    }

  if(labelMaps.empty())
    {
    std::cerr << "Failed to load image data. Terminating." << std::endl;
    return 0;
    }
  if(labelMaps.size() < 2)
    {
    labelMaps.push_back(new Cleaver::InverseField(labelMaps[0]));
    }

  Cleaver::AbstractVolume *volume = new Cleaver::Volume(labelMaps);
  if (Padding)
    {
    volume = new Cleaver::PaddedVolume(volume);
    }

  if (Verbose)
    {
    std::cout << "Creating Mesh with Volume Size "
      << volume->size().toString() << std::endl;
    }

  //--------------------------------
  //  Create Mesher & TetMesh
  //--------------------------------
  Cleaver::TetMesh *cleaverMesh =
    Cleaver::createMeshFromVolume(volume, Verbose);
  if (!cleaverMesh)
    {
    // Clean up
    delete volume;
    delete cleaverMesh;

    std::cerr << "Mesh computation failed !" << std::endl;
    return EXIT_FAILURE;
    }

  //------------------
  //  Compute Angles
  //------------------
  if(Verbose)
    {
    cleaverMesh->computeAngles();
    std::cout.precision(12);
    std::cout << "Worst Angles:" << std::endl;
    std::cout << "min: " << cleaverMesh->min_angle << std::endl;
    std::cout << "max: " << cleaverMesh->max_angle << std::endl;
    }

  //-----------------------
  //  Fill polydata arrays
  //-----------------------
  // Constants for undesired material
  const int airLabel = 0;
  int paddedVolumeLabel = labels.size();

  // Points and cell arrays
  vtkNew<vtkCellArray> meshTetras;
  vtkNew<vtkPoints> points;
  points->SetNumberOfPoints(cleaverMesh->tets.size() * 4);

  vtkNew<vtkIntArray> cellData;
  cellData->SetName("MaterialId");

  vtkNew<vtkBrokenCells> brokenCells;
  brokenCells->SetPoints(points.GetPointer());
  brokenCells->SetVerbose(Verbose);
  for(size_t i = 0; i < cleaverMesh->tets.size(); ++i)
    {
    int label = cleaverMesh->tets[i]->mat_label;

    if(label == airLabel || label == paddedVolumeLabel)
      {
      continue;
      }

    vtkNew<vtkTetra> meshTetra;
    for (int j = 0; j < 4; ++j)
      {
      Cleaver::vec3 &pos = cleaverMesh->tets[i]->verts[j]->pos();
      int vertexIndex = cleaverMesh->tets[i]->verts[j]->tm_v_index;

      points->SetPoint(vertexIndex, pos.x, pos.y, pos.z);
      meshTetra->GetPointIds()->SetId(j, vertexIndex);

      // If invalid, flag the cell so it can be rebuild later
      if (! IsPointInvalid(pos))
        {
        std::cerr << "Invalid point for cell " << i
          << ", this point will be patched up but something went wrong with"
          << " Cleaver !" << std::endl;
        brokenCells->AddCell(vertexIndex, meshTetra.GetPointer());
        }
      }

    meshTetras->InsertNextCell(meshTetra.GetPointer());
    cellData->InsertNextValue(originalLabels[label]);
    }

  //  Repair broken cells
  if (! brokenCells->RepairAllCells())
    {
    delete volume;
    delete cleaverMesh;
    return EXIT_FAILURE;
    }

  //-----------------------------
  //  Create and clean polydata
  //-----------------------------

  vtkSmartPointer<vtkPolyData> vtkMesh = vtkSmartPointer<vtkPolyData>::New();
  vtkMesh->SetPoints(points.GetPointer());
  vtkMesh->SetPolys(meshTetras.GetPointer());
  vtkMesh->GetCellData()->SetScalars(cellData.GetPointer());

  vtkNew<vtkCleanPolyData> cleanFilter;
  cleanFilter->PointMergingOff(); // Prevent from creating triangles or lines
  cleanFilter->SetInput(vtkMesh);

  //---------------------------------------
  //  Transform polydata to fit the image
  //---------------------------------------
  // Since cleaver does not take into account the image properties such as
  // spacing or origin, we need to transform the output points so the mesh can
  // match the original image.
  vtkNew<vtkTransform> transform;
  LabelImageType::SpacingType spacing = reader->GetOutput()->GetSpacing();
  LabelImageType::PointType origin = reader->GetOutput()->GetOrigin();
  LabelImageType::DirectionType imageDirection =
    reader->GetOutput()->GetDirection();

  // Transform points to RAS (what is concatenated first is done last !)
  vtkNew<vtkMatrix4x4> rasMatrix;
  rasMatrix->Identity();
  rasMatrix->SetElement(0, 0, -1.0);
  rasMatrix->SetElement(1, 1, -1.0);
  transform->Concatenate(rasMatrix.GetPointer());

  // Translation
  vtkNew<vtkMatrix4x4> directionMatrix;
  directionMatrix->Identity();
  for (int i = 0; i < imageDirection.RowDimensions; ++i)
    {
    for (int j = 0; j < imageDirection.ColumnDimensions; ++j)
      {
      directionMatrix->SetElement(i, j, imageDirection[i][j]);
      }
    }

  vtkNew<vtkTransform> offsetTransform;
  offsetTransform->Concatenate(directionMatrix.GetPointer());
  double offsets[3];
  if (Padding)
    {
    for (int i = 0; i < 3; ++i)
      {
      offsets[i] =
        spacing[i]*Cleaver::PaddedVolume::DefaultThickness + spacing[i]/2.0;
      }
    }
  else
    {
    for (int i = 0; i < 3; ++i)
      {
      offsets[i] = spacing[i] / 2.0;
      }
    }
  double* transformedOffsets = offsetTransform->TransformDoubleVector(offsets);
  transform->Translate(
    origin[0] - transformedOffsets[0],
    origin[1] - transformedOffsets[1],
    origin[2] - transformedOffsets[2]);

  // Scaling and rotation
  vtkNew<vtkMatrix4x4> scaleMatrix;
  scaleMatrix->DeepCopy(directionMatrix.GetPointer());
  for (int i = 0; i < spacing.GetNumberOfComponents(); ++i)
    {
    scaleMatrix->SetElement(i, i, scaleMatrix->GetElement(i, i) * spacing[i]);
    }
  transform->Concatenate(scaleMatrix.GetPointer());

  // Actual transformation
  vtkNew<vtkTransformPolyDataFilter> transformFilter;
  transformFilter->SetInput(cleanFilter->GetOutput());
  transformFilter->SetTransform(transform.GetPointer());

  bender::IOUtils::WritePolyData(transformFilter->GetOutput(), OutputMesh);

  // Clean up
  delete volume;
  delete cleaverMesh;

  return EXIT_SUCCESS;
}

} // end of anonymous namespace

<commit_msg>Release memory when no longer needed in CreateTetrahedralMesh<commit_after>/*=========================================================================

  Program: Bender

  Copyright (c) Kitware Inc.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0.txt

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

=========================================================================*/

// Bender includes
#include "CreateTetrahedralMeshCLP.h"
#include "benderIOUtils.h"
#include "vtkBrokenCells.h"

// ITK includes
#include "itkBinaryThresholdImageFilter.h"
#include "itkCastImageFilter.h"
#include "itkImageFileWriter.h"
#include "itkImageRegionConstIterator.h"
#include "itkImageRegionIterator.h"
#include "itkRelabelComponentImageFilter.h"
#include "itkConstantPadImageFilter.h"

// Slicer includes
#include "itkPluginUtilities.h"

// VTK includes
#include <vtkCleanPolyData.h>
#include <vtkCellArray.h>
#include <vtkCellData.h>
#include <vtkTetra.h>
#include <vtkTransform.h>
#include <vtkTransformPolyDataFilter.h>
#include <vtkPolyData.h>
#include <vtkPolyDataWriter.h>
#include <vtkMath.h>
#include <vtkNew.h>
#include <vtkSmartPointer.h>

// Cleaver includes
#include <Cleaver/Cleaver.h>
#include <Cleaver/InverseField.h>
#include <Cleaver/PaddedVolume.h>
#include <Cleaver/ScalarField.h>
#include <Cleaver/Volume.h>
#include <LabelMapField.h>

// Use an anonymous namespace to keep class types and function names
// from colliding when module is used as shared object module.  Every
// thing should be in an anonymous namespace except for the module
// entry point, e.g. main()
//
namespace
{
template <class T> int DoIt( int argc, char * argv[] );

std::vector<Cleaver::LabelMapField::ImageType::Pointer> SplitLabelMaps(
  int    argc,
  char * argv[]);
} // end of anonymous namespace

int main( int argc, char * argv[] )
{

  PARSE_ARGS;

  itk::ImageIOBase::IOPixelType     pixelType;
  itk::ImageIOBase::IOComponentType componentType;

  try
    {
    itk::GetImageType(InputVolume, pixelType, componentType);

    switch( componentType )
      {
    case itk::ImageIOBase::UCHAR:
      return DoIt<unsigned char>( argc, argv );
      break;
    case itk::ImageIOBase::CHAR:
      return DoIt<char>( argc, argv );
      break;
    case itk::ImageIOBase::USHORT:
      return DoIt<unsigned short>( argc, argv );
      break;
    case itk::ImageIOBase::SHORT:
      return DoIt<short>( argc, argv );
      break;
    case itk::ImageIOBase::UINT:
      return DoIt<unsigned int>( argc, argv );
      break;
    case itk::ImageIOBase::INT:
      return DoIt<int>( argc, argv );
      break;
    case itk::ImageIOBase::ULONG:
      return DoIt<unsigned long>( argc, argv );
      break;
    case itk::ImageIOBase::LONG:
      return DoIt<long>( argc, argv );
      break;
    case itk::ImageIOBase::FLOAT:
      return DoIt<float>( argc, argv );
      break;
    case itk::ImageIOBase::DOUBLE:
      return DoIt<double>( argc, argv );
      break;
    case itk::ImageIOBase::UNKNOWNCOMPONENTTYPE:
    default:
      std::cerr << "Unknown component type: " << componentType << std::endl;
      break;
      }
    }

  catch( itk::ExceptionObject & excep )
    {
    std::cerr << argv[0] << ": exception caught !" << std::endl;
    std::cerr << excep << std::endl;
    return EXIT_FAILURE;
    }
  return EXIT_SUCCESS;
}

// Use an anonymous namespace to keep class types and function names
// from colliding when module is used as shared object module.  Every
// thing should be in an anonymous namespace except for the module
// entry point, e.g. main()
//
namespace
{
//----------------------------------------------------------------------------
//
//----------------------------------------------------------------------------
std::vector<Cleaver::LabelMapField::ImageType::Pointer >
SplitLabelMaps(Cleaver::LabelMapField::ImageType *image, bool verbose)
{

  typedef Cleaver::LabelMapField::ImageType LabelImageType;
  typedef itk::RelabelComponentImageFilter<LabelImageType,
                                           LabelImageType> RelabelFilterType;
  typedef itk::BinaryThresholdImageFilter<LabelImageType,
                                          LabelImageType> ThresholdFilterType;
  typedef itk::ImageFileWriter<LabelImageType> ImageWriterType;

  // Assign continuous labels to the connected components, background is
  // considered to be 0 and will be ignored in the relabeling process.
  RelabelFilterType::Pointer relabelFilter = RelabelFilterType::New();
  relabelFilter->SetInput( image );
  relabelFilter->Update();

  if (verbose)
    {
    std::cout << "Total Number of Labels: " <<
      relabelFilter->GetNumberOfObjects() << std::endl;
    }

  // Extract the labels
  typedef RelabelFilterType::LabelType LabelType;
  ThresholdFilterType::Pointer skinThresholdFilter =
    ThresholdFilterType::New();

  // Create a list of images corresponding to labels
  std::vector<LabelImageType::Pointer> labels;

  // The skin label will become background for internal (smaller) organs
  skinThresholdFilter->SetInput(relabelFilter->GetOutput());
  skinThresholdFilter->SetLowerThreshold(1);
  skinThresholdFilter->SetUpperThreshold(relabelFilter->GetNumberOfObjects()+1);
  skinThresholdFilter->SetInsideValue(-1);
  skinThresholdFilter->SetOutsideValue(0);
  skinThresholdFilter->Update();
  labels.push_back(skinThresholdFilter->GetOutput());

  for (LabelType i = 1, end = relabelFilter->GetNumberOfObjects()+1; i < end;
       ++i)
    {
    ThresholdFilterType::Pointer organThresholdFilter =
      ThresholdFilterType::New();
    organThresholdFilter->SetInput(relabelFilter->GetOutput());
    organThresholdFilter->SetLowerThreshold(i);
    organThresholdFilter->SetUpperThreshold(i);
    organThresholdFilter->SetInsideValue(i);
    organThresholdFilter->SetOutsideValue(-1);
    organThresholdFilter->Update();

    labels.push_back(organThresholdFilter->GetOutput());
    }

  return labels;
}

//----------------------------------------------------------------------------
bool IsPointInvalid(Cleaver::vec3 pos)
{
  return vtkBrokenCells::IsPointValid(pos.x, pos.y, pos.z);
}

//----------------------------------------------------------------------------
//
//----------------------------------------------------------------------------
template <class T>
int DoIt( int argc, char * argv[] )
{

  PARSE_ARGS;

  typedef Cleaver::LabelMapField::ImageType LabelImageType;
  typedef T InputPixelType;
  typedef itk::Image<InputPixelType,3> InputImageType;
  typedef itk::CastImageFilter<InputImageType,
                               LabelImageType> CastFilterType;
  typedef itk::ImageFileReader<InputImageType> ReaderType;
  typedef itk::ConstantPadImageFilter<InputImageType,
                                      InputImageType> ConstantPadType;

  typename ReaderType::Pointer reader            = ReaderType::New();
  reader->SetFileName( InputVolume );
  reader->Update();
  LabelImageType::SpacingType spacing = reader->GetOutput()->GetSpacing();
  LabelImageType::PointType origin = reader->GetOutput()->GetOrigin();
  LabelImageType::DirectionType imageDirection =
    reader->GetOutput()->GetDirection();

  typename CastFilterType::Pointer castingFilter = CastFilterType::New();
  castingFilter->SetInput(reader->GetOutput());

  std::vector<Cleaver::ScalarField*> labelMaps;

  std::vector<LabelImageType::Pointer> labels =
    SplitLabelMaps(castingFilter->GetOutput(), Verbose);

  // Get a map from the original labels to the new labels
  std::map<InputPixelType, InputPixelType> originalLabels;

  for(size_t i = 0; i < labels.size(); ++i)
    {
    itk::ImageRegionConstIterator<InputImageType> imageIterator(
      reader->GetOutput(), reader->GetOutput()->GetLargestPossibleRegion());
    itk::ImageRegionConstIterator<LabelImageType> labelsIterator(
      labels[i], labels[i]->GetLargestPossibleRegion());
    bool foundCorrespondence = false;
    while(!imageIterator.IsAtEnd()
      && !labelsIterator.IsAtEnd()
      && !foundCorrespondence)
      {
      if (labelsIterator.Value() > 0)
        {
        originalLabels[labelsIterator.Value()] = imageIterator.Value();
        }

      ++imageIterator;
      ++labelsIterator;
      }
    }

  if (Verbose)
    {
    std::cout << "Total labels found:  " << labels.size() << std::endl;
    }
  for(size_t i = 0; i < labels.size(); ++i)
    {
    labelMaps.push_back(new Cleaver::LabelMapField(labels[i]));
    }

  if(labelMaps.empty())
    {
    std::cerr << "Failed to load image data. Terminating." << std::endl;
    return 0;
    }
  if(labelMaps.size() < 2)
    {
    labelMaps.push_back(new Cleaver::InverseField(labelMaps[0]));
    }

  Cleaver::AbstractVolume *cleaverVolume = new Cleaver::Volume(labelMaps);
  if (Padding)
    {
    cleaverVolume = new Cleaver::PaddedVolume(cleaverVolume);
    }

  if (Verbose)
    {
    std::cout << "Creating Mesh with Volume Size "
      << cleaverVolume->size().toString() << std::endl;
    }

  //--------------------------------
  //  Create Mesher & TetMesh
  //--------------------------------
  Cleaver::TetMesh *cleaverMesh =
    Cleaver::createMeshFromVolume(cleaverVolume, Verbose);

  // No need for the volume nor the labelmaps anymore therefore we can release
  // the memory.
  delete cleaverVolume;
  for(size_t i=0; i < labelMaps.size(); ++i)
    delete labelMaps[i];
  labelMaps.clear();
  labels.clear();
  castingFilter = NULL;
  reader = NULL;

  if (!cleaverMesh)
    {
    std::cerr << "Mesh computation failed !" << std::endl;
    return EXIT_FAILURE;
    }

  //------------------
  //  Compute Angles
  //------------------
  if(Verbose)
    {
    cleaverMesh->computeAngles();
    std::cout.precision(12);
    std::cout << "Worst Angles:" << std::endl;
    std::cout << "min: " << cleaverMesh->min_angle << std::endl;
    std::cout << "max: " << cleaverMesh->max_angle << std::endl;
    }

  //-----------------------
  //  Fill polydata arrays
  //-----------------------
  // Constants for undesired material
  const int airLabel = 0;
  int paddedVolumeLabel = labels.size();

  // Points and cell arrays
  vtkNew<vtkCellArray> meshTetras;
  vtkNew<vtkPoints> points;
  points->SetNumberOfPoints(cleaverMesh->tets.size() * 4);

  vtkNew<vtkIntArray> cellData;
  cellData->SetName("MaterialId");

  vtkSmartPointer<vtkBrokenCells> brokenCells =
    vtkSmartPointer<vtkBrokenCells>::New();
  brokenCells->SetPoints(points.GetPointer());
  brokenCells->SetVerbose(Verbose);
  for(size_t i = 0; i < cleaverMesh->tets.size(); ++i)
    {
    int label = cleaverMesh->tets[i]->mat_label;

    if(label == airLabel || label == paddedVolumeLabel)
      {
      continue;
      }

    vtkNew<vtkTetra> meshTetra;
    for (size_t j = 0; j < 4; ++j)
      {
      Cleaver::vec3 &pos = cleaverMesh->tets[i]->verts[j]->pos();
      int vertexIndex = cleaverMesh->tets[i]->verts[j]->tm_v_index;

      points->SetPoint(vertexIndex, pos.x, pos.y, pos.z);
      meshTetra->GetPointIds()->SetId(j, vertexIndex);

      // If invalid, flag the cell so it can be rebuild later
      if (! IsPointInvalid(pos))
        {
        std::cerr << "Invalid point for cell " << i
          << ", this point will be patched up but something went wrong with"
          << " Cleaver !" << std::endl;
        brokenCells->AddCell(vertexIndex, meshTetra.GetPointer());
        }
      }

    meshTetras->InsertNextCell(meshTetra.GetPointer());
    cellData->InsertNextValue(originalLabels[label]);
    }

  // No need for the mesh anymore, release the memory.
  delete cleaverMesh;

  //  Repair broken cells
  if (!brokenCells->RepairAllCells())
    {
    return EXIT_FAILURE;
    }
  // No need for the cell fixer anymore, release the memory.
  brokenCells = NULL;

  //-----------------------------
  //  Create and clean polydata
  //-----------------------------

  vtkSmartPointer<vtkPolyData> vtkMesh = vtkSmartPointer<vtkPolyData>::New();
  vtkMesh->SetPoints(points.GetPointer());
  vtkMesh->SetPolys(meshTetras.GetPointer());
  vtkMesh->GetCellData()->SetScalars(cellData.GetPointer());

  vtkNew<vtkCleanPolyData> cleanFilter;
  cleanFilter->PointMergingOff(); // Prevent from creating triangles or lines
  cleanFilter->SetInput(vtkMesh);

  //---------------------------------------
  //  Transform polydata to fit the image
  //---------------------------------------
  // Since cleaver does not take into account the image properties such as
  // spacing or origin, we need to transform the output points so the mesh can
  // match the original image.
  vtkNew<vtkTransform> transform;

  // Transform points to RAS (what is concatenated first is done last !)
  vtkNew<vtkMatrix4x4> rasMatrix;
  rasMatrix->Identity();
  rasMatrix->SetElement(0, 0, -1.0);
  rasMatrix->SetElement(1, 1, -1.0);
  transform->Concatenate(rasMatrix.GetPointer());

  // Translation
  vtkNew<vtkMatrix4x4> directionMatrix;
  directionMatrix->Identity();
  for (int i = 0; i < imageDirection.RowDimensions; ++i)
    {
    for (int j = 0; j < imageDirection.ColumnDimensions; ++j)
      {
      directionMatrix->SetElement(i, j, imageDirection[i][j]);
      }
    }

  vtkNew<vtkTransform> offsetTransform;
  offsetTransform->Concatenate(directionMatrix.GetPointer());
  double offsets[3];
  if (Padding)
    {
    for (int i = 0; i < 3; ++i)
      {
      offsets[i] =
        spacing[i]*Cleaver::PaddedVolume::DefaultThickness + spacing[i]/2.0;
      }
    }
  else
    {
    for (int i = 0; i < 3; ++i)
      {
      offsets[i] = spacing[i] / 2.0;
      }
    }
  double* transformedOffsets = offsetTransform->TransformDoubleVector(offsets);
  transform->Translate(
    origin[0] - transformedOffsets[0],
    origin[1] - transformedOffsets[1],
    origin[2] - transformedOffsets[2]);

  // Scaling and rotation
  vtkNew<vtkMatrix4x4> scaleMatrix;
  scaleMatrix->DeepCopy(directionMatrix.GetPointer());
  for (size_t i = 0; i < spacing.GetNumberOfComponents(); ++i)
    {
    scaleMatrix->SetElement(i, i, scaleMatrix->GetElement(i, i) * spacing[i]);
    }
  transform->Concatenate(scaleMatrix.GetPointer());

  if (Verbose)
    {
    transform->Print(std::cout);
    }
  // Actual transformation
  vtkNew<vtkTransformPolyDataFilter> transformFilter;
  transformFilter->SetInput(cleanFilter->GetOutput());
  transformFilter->SetTransform(transform.GetPointer());

  // Conserve memory
  transformFilter->GetOutput()->GlobalReleaseDataFlagOn();
  bender::IOUtils::WritePolyData(transformFilter->GetOutput(), OutputMesh);

  return EXIT_SUCCESS;
}

} // end of anonymous namespace

<|endoftext|>


<commit_before>/*=========================================================================
 *
 *  Copyright Leiden University Medical Center, Erasmus University Medical
 *  Center and contributors
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0.txt
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 *=========================================================================*/

#include "selxCropperComponent.h"
#include "selxCheckTemplateProperties.h"

#include "itkImageFileWriter.h"

namespace selx
{

template< int Dimensionality, class TPixel >
CropperComponent< Dimensionality, TPixel >::CropperComponent( const std::string & name,
                                                              LoggerImpl & logger ) : Superclass( name, logger ) {
  this->m_LabelGeometryImageFilter
    = LabelGeometryImageFilterType::New();
  this->m_LabelGeometryImageFilter->CalculateOrientedBoundingBoxOn();

  this->m_RegionOfInterestImageFilter
    = RegionOfInterestImageFilterType::New();

  this->m_Pad = 0;
}

template< int Dimensionality, class TPixel >
int
CropperComponent< Dimensionality, TPixel >::Accept( typename itkImageInterface< Dimensionality, TPixel >::Pointer component )
{
  this->m_Image = component->GetItkImage();
  this->m_RegionOfInterestImageFilter->SetInput(this->m_Image);
  return 0;
}

template< int Dimensionality, class TPixel >
int
CropperComponent< Dimensionality, TPixel >::Accept( typename itkImageMaskInterface< Dimensionality, unsigned char >::Pointer component )
{
  this->m_Mask = component->GetItkImageMask();
  return 0;
}

template< int Dimensionality, class TPixel >
typename CropperComponent< Dimensionality, TPixel >::ItkImagePointer
CropperComponent< Dimensionality, TPixel >::GetItkImage()
{
  return this->m_RegionOfInterestImageFilter->GetOutput();
}

template< int Dimensionality, class TPixel >
typename CropperComponent< Dimensionality, TPixel >::ItkImagePointer
CropperComponent< Dimensionality, TPixel >::GetItkImageFixed()
{
  return this->GetItkImage();
};

template< int Dimensionality, class TPixel >
typename CropperComponent< Dimensionality, TPixel >::ItkImagePointer
CropperComponent< Dimensionality, TPixel >::GetItkImageMoving()
{
  return this->GetItkImage();
};

template< int Dimensionality, class TPixel >
typename CropperComponent< Dimensionality, TPixel >::ItkImageDomainPointer
CropperComponent< Dimensionality, TPixel >
::GetItkImageDomainFixed()
{
  // Implicitly casted to domain (itk::ImageBase)
  return this->m_RegionOfInterestImageFilter->GetOutput();
}

template< int Dimensionality, class TPixel >
void
CropperComponent< Dimensionality, TPixel >::BeforeUpdate()
{

  this->m_Image->UpdateOutputInformation();
  this->m_Mask->UpdateOutputInformation();

  // Output information must be generated before downstream components are run
  this->m_LabelGeometryImageFilter->SetInput(this->m_Mask);
  this->m_LabelGeometryImageFilter->Update();
  auto boundingBox = this->m_LabelGeometryImageFilter->GetBoundingBox(1);

  typename itk::Index< Dimensionality > start;
  start[0] = std::max(boundingBox.GetElement(0) - this->m_Pad, long(this->m_Image->GetLargestPossibleRegion().GetIndex(0)));
  start[1] = std::max(boundingBox.GetElement(2) - this->m_Pad, long(this->m_Image->GetLargestPossibleRegion().GetIndex(1)));
  if( Dimensionality > 2 ) start[2] = std::max(boundingBox.GetElement(4) - this->m_Pad, long(this->m_Image->GetLargestPossibleRegion().GetIndex(2)));
  if( Dimensionality > 3 ) start[3] = std::max(boundingBox.GetElement(6) - this->m_Pad, long(this->m_Image->GetLargestPossibleRegion().GetIndex(3)));

  {
    std::stringstream ss;
    ss << this->m_Image->GetLargestPossibleRegion();
    this->m_Logger.Log(LogLevel::INF, "{0}: Got image with {1}", this->m_Name, ss.str());
  }

  typename itk::Size< Dimensionality > size;
  size[0] = std::min(boundingBox.GetElement(1) - start[0] + 1 + this->m_Pad, long(this->m_Image->GetLargestPossibleRegion().GetSize(0)));
  size[1] = std::min(boundingBox.GetElement(3) - start[1] + 1 + this->m_Pad, long(this->m_Image->GetLargestPossibleRegion().GetSize(1)));
  if( Dimensionality > 2 ) size[2] = std::min(boundingBox.GetElement(5) - start[2] + 1 + this->m_Pad, long(this->m_Image->GetLargestPossibleRegion().GetSize(2)));
  if( Dimensionality > 3 ) size[3] = std::min(boundingBox.GetElement(7) - start[3] + 1 + this->m_Pad, long(this->m_Image->GetLargestPossibleRegion().GetSize(3)));
  typename ItkImageType::RegionType region(start, size);

  {
    std::stringstream ss;
    ss << region;
    this->m_Logger.Log(LogLevel::INF, "{0}: Cropping image to {1}", this->m_Name, ss.str());
  }

  this->m_RegionOfInterestImageFilter->SetRegionOfInterest(region);
}

template< int Dimensionality, class TPixel >
void
CropperComponent< Dimensionality, TPixel >::Update()
{

}

template< int Dimensionality, class TPixel >
bool
CropperComponent< Dimensionality, TPixel >
::MeetsCriterion( const CriterionType & criterion )
{
  auto status = CheckTemplateProperties( this->TemplateProperties(), criterion );
  if( status == CriterionStatus::Satisfied )
  {
    return true;
  }
  else if( status == CriterionStatus::Failed )
  {
    return false;
  }

  if( criterion.first == "Pad" ) {
    this->m_Pad = std::stoi( criterion.second[0] );
    return true;
  }

  return false;
};

}
<commit_msg>BUG: Cropping would occasionally result in requested region being outside largest possible region<commit_after>/*=========================================================================
 *
 *  Copyright Leiden University Medical Center, Erasmus University Medical
 *  Center and contributors
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0.txt
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 *=========================================================================*/

#include "selxCropperComponent.h"
#include "selxCheckTemplateProperties.h"

#include "itkImageFileWriter.h"

namespace selx
{

template< int Dimensionality, class TPixel >
CropperComponent< Dimensionality, TPixel >::CropperComponent( const std::string & name,
                                                              LoggerImpl & logger ) : Superclass( name, logger ) {
  this->m_LabelGeometryImageFilter
    = LabelGeometryImageFilterType::New();
  this->m_LabelGeometryImageFilter->CalculateOrientedBoundingBoxOn();

  this->m_RegionOfInterestImageFilter
    = RegionOfInterestImageFilterType::New();

  this->m_Pad = 0;
}

template< int Dimensionality, class TPixel >
int
CropperComponent< Dimensionality, TPixel >::Accept( typename itkImageInterface< Dimensionality, TPixel >::Pointer component )
{
  this->m_Image = component->GetItkImage();
  this->m_RegionOfInterestImageFilter->SetInput(this->m_Image);
  return 0;
}

template< int Dimensionality, class TPixel >
int
CropperComponent< Dimensionality, TPixel >::Accept( typename itkImageMaskInterface< Dimensionality, unsigned char >::Pointer component )
{
  this->m_Mask = component->GetItkImageMask();
  return 0;
}

template< int Dimensionality, class TPixel >
typename CropperComponent< Dimensionality, TPixel >::ItkImagePointer
CropperComponent< Dimensionality, TPixel >::GetItkImage()
{
  return this->m_RegionOfInterestImageFilter->GetOutput();
}

template< int Dimensionality, class TPixel >
typename CropperComponent< Dimensionality, TPixel >::ItkImagePointer
CropperComponent< Dimensionality, TPixel >::GetItkImageFixed()
{
  return this->GetItkImage();
};

template< int Dimensionality, class TPixel >
typename CropperComponent< Dimensionality, TPixel >::ItkImagePointer
CropperComponent< Dimensionality, TPixel >::GetItkImageMoving()
{
  return this->GetItkImage();
};

template< int Dimensionality, class TPixel >
typename CropperComponent< Dimensionality, TPixel >::ItkImageDomainPointer
CropperComponent< Dimensionality, TPixel >
::GetItkImageDomainFixed()
{
  // Implicitly casted to domain (itk::ImageBase)
  return this->m_RegionOfInterestImageFilter->GetOutput();
}

template< int Dimensionality, class TPixel >
void
CropperComponent< Dimensionality, TPixel >::BeforeUpdate()
{

  this->m_Image->UpdateOutputInformation();
  this->m_Mask->UpdateOutputInformation();

  // Output information must be generated before downstream components are run
  this->m_LabelGeometryImageFilter->SetInput(this->m_Mask);
  this->m_LabelGeometryImageFilter->Update();
  auto boundingBox = this->m_LabelGeometryImageFilter->GetBoundingBox(1);

  typename itk::Index< Dimensionality > start;
  start[0] = std::max(boundingBox.GetElement(0) - this->m_Pad, long(this->m_Image->GetLargestPossibleRegion().GetIndex(0)));
  start[1] = std::max(boundingBox.GetElement(2) - this->m_Pad, long(this->m_Image->GetLargestPossibleRegion().GetIndex(1)));
  if( Dimensionality > 2 ) start[2] = std::max(boundingBox.GetElement(4) - this->m_Pad, long(this->m_Image->GetLargestPossibleRegion().GetIndex(2)));
  if( Dimensionality > 3 ) start[3] = std::max(boundingBox.GetElement(6) - this->m_Pad, long(this->m_Image->GetLargestPossibleRegion().GetIndex(3)));

  {
    std::stringstream ss;
    ss << this->m_Image->GetLargestPossibleRegion();
    this->m_Logger.Log(LogLevel::INF, "{0}: Got image with {1}", this->m_Name, ss.str());
  }

  typename itk::Size< Dimensionality > size;
  size[0] = std::min(boundingBox.GetElement(1) - start[0] + 1 + this->m_Pad, long(this->m_Image->GetLargestPossibleRegion().GetSize(0)) - start[0]);
  size[1] = std::min(boundingBox.GetElement(3) - start[1] + 1 + this->m_Pad, long(this->m_Image->GetLargestPossibleRegion().GetSize(1)) - start[1]);
  if( Dimensionality > 2 ) size[2] = std::min(boundingBox.GetElement(5) - start[2] + 1 + this->m_Pad, long(this->m_Image->GetLargestPossibleRegion().GetSize(2)) - start[2]);
  if( Dimensionality > 3 ) size[3] = std::min(boundingBox.GetElement(7) - start[3] + 1 + this->m_Pad, long(this->m_Image->GetLargestPossibleRegion().GetSize(3)) - start[3]);
  typename ItkImageType::RegionType region(start, size);

  {
    std::stringstream ss;
    ss << region;
    this->m_Logger.Log(LogLevel::INF, "{0}: Cropping image to {1}", this->m_Name, ss.str());
  }

  this->m_RegionOfInterestImageFilter->SetRegionOfInterest(region);
}

template< int Dimensionality, class TPixel >
void
CropperComponent< Dimensionality, TPixel >::Update()
{

}

template< int Dimensionality, class TPixel >
bool
CropperComponent< Dimensionality, TPixel >
::MeetsCriterion( const CriterionType & criterion )
{
  auto status = CheckTemplateProperties( this->TemplateProperties(), criterion );
  if( status == CriterionStatus::Satisfied )
  {
    return true;
  }
  else if( status == CriterionStatus::Failed )
  {
    return false;
  }

  if( criterion.first == "Pad" ) {
    this->m_Pad = std::stoi( criterion.second[0] );
    return true;
  }

  return false;
};

}
<|endoftext|>